Move components for rendering locations to a separate file
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
|
||||||
import { renderLocation } from "./result-table-utils";
|
import { Location } from "./locations";
|
||||||
import { CellValue } from "../../common/bqrs-cli-types";
|
import { CellValue } from "../../common/bqrs-cli-types";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -16,14 +16,15 @@ export default function RawTableValue(props: Props): JSX.Element {
|
|||||||
typeof rawValue === "number" ||
|
typeof rawValue === "number" ||
|
||||||
typeof rawValue === "boolean"
|
typeof rawValue === "boolean"
|
||||||
) {
|
) {
|
||||||
return <span>{renderLocation(undefined, rawValue.toString())}</span>;
|
return <Location label={rawValue.toString()} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return renderLocation(
|
return (
|
||||||
rawValue.url,
|
<Location
|
||||||
rawValue.label,
|
loc={rawValue.url}
|
||||||
props.databaseUri,
|
label={rawValue.label}
|
||||||
undefined,
|
databaseUri={props.databaseUri}
|
||||||
props.onSelected,
|
jumpToLocationCallback={props.onSelected}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import { basename } from "path";
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as Sarif from "sarif";
|
import * as Sarif from "sarif";
|
||||||
import * as Keys from "./result-keys";
|
import * as Keys from "./result-keys";
|
||||||
import { chevronDown, chevronRight, info, listUnordered } from "./octicons";
|
import { chevronDown, chevronRight, info, listUnordered } from "./octicons";
|
||||||
import {
|
import {
|
||||||
className,
|
className,
|
||||||
renderLocation,
|
|
||||||
ResultTableProps,
|
ResultTableProps,
|
||||||
selectableZebraStripe,
|
selectableZebraStripe,
|
||||||
jumpToLocation,
|
jumpToLocation,
|
||||||
@@ -18,15 +16,11 @@ import {
|
|||||||
NavigationDirection,
|
NavigationDirection,
|
||||||
SarifInterpretationData,
|
SarifInterpretationData,
|
||||||
} from "../../common/interface-types";
|
} from "../../common/interface-types";
|
||||||
import {
|
import { parseSarifLocation, isNoLocation } from "../../common/sarif-utils";
|
||||||
parseSarifPlainTextMessage,
|
|
||||||
parseSarifLocation,
|
|
||||||
isNoLocation,
|
|
||||||
} from "../../common/sarif-utils";
|
|
||||||
import { isWholeFileLoc, isLineColumnLoc } from "../../common/bqrs-utils";
|
|
||||||
import { ScrollIntoViewHelper } from "./scroll-into-view-helper";
|
import { ScrollIntoViewHelper } from "./scroll-into-view-helper";
|
||||||
import { sendTelemetry } from "../common/telemetry";
|
import { sendTelemetry } from "../common/telemetry";
|
||||||
import { AlertTableHeader } from "./alert-table-header";
|
import { AlertTableHeader } from "./alert-table-header";
|
||||||
|
import { SarifLocation, SarifMessageWithLocations } from "./locations";
|
||||||
|
|
||||||
export type AlertTableProps = ResultTableProps & {
|
export type AlertTableProps = ResultTableProps & {
|
||||||
resultSet: InterpretedResultSet<SarifInterpretationData>;
|
resultSet: InterpretedResultSet<SarifInterpretationData>;
|
||||||
@@ -100,41 +94,6 @@ export class AlertTable extends React.Component<
|
|||||||
const { numTruncatedResults, sourceLocationPrefix } =
|
const { numTruncatedResults, sourceLocationPrefix } =
|
||||||
resultSet.interpretation;
|
resultSet.interpretation;
|
||||||
|
|
||||||
function renderRelatedLocations(
|
|
||||||
msg: string,
|
|
||||||
relatedLocations: Sarif.Location[],
|
|
||||||
resultKey: Keys.PathNode | Keys.Result | undefined,
|
|
||||||
): JSX.Element[] {
|
|
||||||
const relatedLocationsById: { [k: string]: Sarif.Location } = {};
|
|
||||||
for (const loc of relatedLocations) {
|
|
||||||
relatedLocationsById[loc.id!] = loc;
|
|
||||||
}
|
|
||||||
|
|
||||||
// match things like `[link-text](related-location-id)`
|
|
||||||
const parts = parseSarifPlainTextMessage(msg);
|
|
||||||
|
|
||||||
return parts.map((part, i) => {
|
|
||||||
if (typeof part === "string") {
|
|
||||||
return <span key={i}>{part}</span>;
|
|
||||||
} else {
|
|
||||||
const renderedLocation = renderSarifLocationWithText(
|
|
||||||
part.text,
|
|
||||||
relatedLocationsById[part.dest],
|
|
||||||
resultKey,
|
|
||||||
);
|
|
||||||
return <span key={i}>{renderedLocation}</span>;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderNonLocation(
|
|
||||||
msg: string | undefined,
|
|
||||||
locationHint: string,
|
|
||||||
): JSX.Element | undefined {
|
|
||||||
if (msg === undefined) return undefined;
|
|
||||||
return <span title={locationHint}>{msg}</span>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateSelectionCallback = (
|
const updateSelectionCallback = (
|
||||||
resultKey: Keys.PathNode | Keys.Result | undefined,
|
resultKey: Keys.PathNode | Keys.Result | undefined,
|
||||||
) => {
|
) => {
|
||||||
@@ -147,65 +106,6 @@ export class AlertTable extends React.Component<
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
function renderSarifLocationWithText(
|
|
||||||
text: string | undefined,
|
|
||||||
loc: Sarif.Location,
|
|
||||||
resultKey: Keys.PathNode | Keys.Result | undefined,
|
|
||||||
): JSX.Element | undefined {
|
|
||||||
const parsedLoc = parseSarifLocation(loc, sourceLocationPrefix);
|
|
||||||
if ("hint" in parsedLoc) {
|
|
||||||
return renderNonLocation(text, parsedLoc.hint);
|
|
||||||
} else if (isWholeFileLoc(parsedLoc) || isLineColumnLoc(parsedLoc)) {
|
|
||||||
return renderLocation(
|
|
||||||
parsedLoc,
|
|
||||||
text,
|
|
||||||
databaseUri,
|
|
||||||
undefined,
|
|
||||||
updateSelectionCallback(resultKey),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render sarif location as a link with the text being simply a
|
|
||||||
* human-readable form of the location itself.
|
|
||||||
*/
|
|
||||||
function renderSarifLocation(
|
|
||||||
loc: Sarif.Location,
|
|
||||||
pathNodeKey: Keys.PathNode | Keys.Result | undefined,
|
|
||||||
): JSX.Element | undefined {
|
|
||||||
const parsedLoc = parseSarifLocation(loc, sourceLocationPrefix);
|
|
||||||
if ("hint" in parsedLoc) {
|
|
||||||
return renderNonLocation("[no location]", parsedLoc.hint);
|
|
||||||
} else if (isWholeFileLoc(parsedLoc)) {
|
|
||||||
const shortLocation = `${basename(parsedLoc.userVisibleFile)}`;
|
|
||||||
const longLocation = `${parsedLoc.userVisibleFile}`;
|
|
||||||
return renderLocation(
|
|
||||||
parsedLoc,
|
|
||||||
shortLocation,
|
|
||||||
databaseUri,
|
|
||||||
longLocation,
|
|
||||||
updateSelectionCallback(pathNodeKey),
|
|
||||||
);
|
|
||||||
} else if (isLineColumnLoc(parsedLoc)) {
|
|
||||||
const shortLocation = `${basename(parsedLoc.userVisibleFile)}:${
|
|
||||||
parsedLoc.startLine
|
|
||||||
}:${parsedLoc.startColumn}`;
|
|
||||||
const longLocation = `${parsedLoc.userVisibleFile}`;
|
|
||||||
return renderLocation(
|
|
||||||
parsedLoc,
|
|
||||||
shortLocation,
|
|
||||||
databaseUri,
|
|
||||||
longLocation,
|
|
||||||
updateSelectionCallback(pathNodeKey),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const toggler: (keys: Keys.ResultKey[]) => (e: React.MouseEvent) => void = (
|
const toggler: (keys: Keys.ResultKey[]) => (e: React.MouseEvent) => void = (
|
||||||
indices,
|
indices,
|
||||||
) => {
|
) => {
|
||||||
@@ -220,19 +120,32 @@ export class AlertTable extends React.Component<
|
|||||||
(result, resultIndex) => {
|
(result, resultIndex) => {
|
||||||
const resultKey: Keys.Result = { resultIndex };
|
const resultKey: Keys.Result = { resultIndex };
|
||||||
const text = result.message.text || "[no text]";
|
const text = result.message.text || "[no text]";
|
||||||
const msg: JSX.Element[] =
|
const msg =
|
||||||
result.relatedLocations === undefined
|
result.relatedLocations === undefined ? (
|
||||||
? [<span key="0">{text}</span>]
|
<span key="0">{text}</span>
|
||||||
: renderRelatedLocations(text, result.relatedLocations, resultKey);
|
) : (
|
||||||
|
<SarifMessageWithLocations
|
||||||
|
msg={text}
|
||||||
|
relatedLocations={result.relatedLocations}
|
||||||
|
sourceLocationPrefix={sourceLocationPrefix}
|
||||||
|
databaseUri={databaseUri}
|
||||||
|
jumpToLocationCallback={updateSelectionCallback(resultKey)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
const currentResultExpanded = this.state.expanded.has(
|
const currentResultExpanded = this.state.expanded.has(
|
||||||
Keys.keyToString(resultKey),
|
Keys.keyToString(resultKey),
|
||||||
);
|
);
|
||||||
const indicator = currentResultExpanded ? chevronDown : chevronRight;
|
const indicator = currentResultExpanded ? chevronDown : chevronRight;
|
||||||
const location =
|
const location = result.locations !== undefined &&
|
||||||
result.locations !== undefined &&
|
result.locations.length > 0 && (
|
||||||
result.locations.length > 0 &&
|
<SarifLocation
|
||||||
renderSarifLocation(result.locations[0], resultKey);
|
loc={result.locations[0]}
|
||||||
|
sourceLocationPrefix={sourceLocationPrefix}
|
||||||
|
databaseUri={databaseUri}
|
||||||
|
jumpToLocationCallback={updateSelectionCallback(resultKey)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
const locationCells = (
|
const locationCells = (
|
||||||
<td className="vscode-codeql__location-cell">{location}</td>
|
<td className="vscode-codeql__location-cell">{location}</td>
|
||||||
);
|
);
|
||||||
@@ -342,17 +255,32 @@ export class AlertTable extends React.Component<
|
|||||||
const step = pathNodes[pathNodeIndex];
|
const step = pathNodes[pathNodeIndex];
|
||||||
const msg =
|
const msg =
|
||||||
step.location !== undefined &&
|
step.location !== undefined &&
|
||||||
step.location.message !== undefined
|
step.location.message !== undefined ? (
|
||||||
? renderSarifLocationWithText(
|
<SarifLocation
|
||||||
step.location.message.text,
|
text={step.location.message.text}
|
||||||
step.location,
|
loc={step.location}
|
||||||
|
sourceLocationPrefix={sourceLocationPrefix}
|
||||||
|
databaseUri={databaseUri}
|
||||||
|
jumpToLocationCallback={updateSelectionCallback(
|
||||||
pathNodeKey,
|
pathNodeKey,
|
||||||
)
|
)}
|
||||||
: "[no location]";
|
/>
|
||||||
|
) : (
|
||||||
|
"[no location]"
|
||||||
|
);
|
||||||
const additionalMsg =
|
const additionalMsg =
|
||||||
step.location !== undefined
|
step.location !== undefined ? (
|
||||||
? renderSarifLocation(step.location, pathNodeKey)
|
<SarifLocation
|
||||||
: "";
|
loc={step.location}
|
||||||
|
sourceLocationPrefix={sourceLocationPrefix}
|
||||||
|
databaseUri={databaseUri}
|
||||||
|
jumpToLocationCallback={updateSelectionCallback(
|
||||||
|
pathNodeKey,
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
);
|
||||||
const isSelected = Keys.equalsNotUndefined(
|
const isSelected = Keys.equalsNotUndefined(
|
||||||
this.state.selectedItem,
|
this.state.selectedItem,
|
||||||
pathNodeKey,
|
pathNodeKey,
|
||||||
|
|||||||
213
extensions/ql-vscode/src/view/results/locations.tsx
Normal file
213
extensions/ql-vscode/src/view/results/locations.tsx
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
import * as Sarif from "sarif";
|
||||||
|
import { ResolvableLocationValue, UrlValue } from "../../common/bqrs-cli-types";
|
||||||
|
import { convertNonPrintableChars } from "../../common/text-utils";
|
||||||
|
import {
|
||||||
|
isLineColumnLoc,
|
||||||
|
isStringLoc,
|
||||||
|
isWholeFileLoc,
|
||||||
|
tryGetResolvableLocation,
|
||||||
|
} from "../../common/bqrs-utils";
|
||||||
|
import {
|
||||||
|
parseSarifLocation,
|
||||||
|
parseSarifPlainTextMessage,
|
||||||
|
} from "../../common/sarif-utils";
|
||||||
|
import { basename } from "path";
|
||||||
|
import { jumpToLocation } from "./result-table-utils";
|
||||||
|
import { useCallback, useMemo } from "react";
|
||||||
|
|
||||||
|
function NonLocation({
|
||||||
|
msg,
|
||||||
|
locationHint,
|
||||||
|
}: {
|
||||||
|
msg?: string;
|
||||||
|
locationHint?: string;
|
||||||
|
}) {
|
||||||
|
if (msg === undefined) return null;
|
||||||
|
return <span title={locationHint}>{msg}</span>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ClickableLocation({
|
||||||
|
loc,
|
||||||
|
label,
|
||||||
|
databaseUri,
|
||||||
|
title,
|
||||||
|
jumpToLocationCallback,
|
||||||
|
}: {
|
||||||
|
loc: ResolvableLocationValue;
|
||||||
|
label: string;
|
||||||
|
databaseUri: string;
|
||||||
|
title?: string;
|
||||||
|
jumpToLocationCallback?: () => void;
|
||||||
|
}): JSX.Element {
|
||||||
|
const jumpToLocationHandler = useCallback(
|
||||||
|
(e: React.MouseEvent) => {
|
||||||
|
jumpToLocation(loc, databaseUri);
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
if (jumpToLocationCallback) {
|
||||||
|
jumpToLocationCallback();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[loc, databaseUri, jumpToLocationCallback],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/*
|
||||||
|
eslint-disable-next-line
|
||||||
|
jsx-a11y/anchor-is-valid,
|
||||||
|
*/}
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
className="vscode-codeql__result-table-location-link"
|
||||||
|
title={title}
|
||||||
|
onClick={jumpToLocationHandler}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</a>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A clickable location link.
|
||||||
|
*/
|
||||||
|
export function Location({
|
||||||
|
loc,
|
||||||
|
label,
|
||||||
|
databaseUri,
|
||||||
|
title,
|
||||||
|
jumpToLocationCallback,
|
||||||
|
}: {
|
||||||
|
loc?: UrlValue;
|
||||||
|
label?: string;
|
||||||
|
databaseUri?: string;
|
||||||
|
title?: string;
|
||||||
|
jumpToLocationCallback?: () => void;
|
||||||
|
}): JSX.Element {
|
||||||
|
const resolvableLoc = useMemo(() => tryGetResolvableLocation(loc), [loc]);
|
||||||
|
const displayLabel = useMemo(() => convertNonPrintableChars(label!), [label]);
|
||||||
|
if (loc === undefined) {
|
||||||
|
return <NonLocation msg={displayLabel} />;
|
||||||
|
} else if (isStringLoc(loc)) {
|
||||||
|
return <a href={loc}>{loc}</a>;
|
||||||
|
} else if (databaseUri === undefined || resolvableLoc === undefined) {
|
||||||
|
return <NonLocation msg={displayLabel} locationHint={title} />;
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<ClickableLocation
|
||||||
|
loc={resolvableLoc}
|
||||||
|
label={displayLabel}
|
||||||
|
databaseUri={databaseUri}
|
||||||
|
title={title}
|
||||||
|
jumpToLocationCallback={jumpToLocationCallback}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A clickable SARIF location link.
|
||||||
|
*
|
||||||
|
* Custom text can be provided, but otherwise the text will be
|
||||||
|
* a human-readable form of the location itself.
|
||||||
|
*/
|
||||||
|
export function SarifLocation({
|
||||||
|
text,
|
||||||
|
loc,
|
||||||
|
sourceLocationPrefix,
|
||||||
|
databaseUri,
|
||||||
|
jumpToLocationCallback,
|
||||||
|
}: {
|
||||||
|
text?: string;
|
||||||
|
loc?: Sarif.Location;
|
||||||
|
sourceLocationPrefix: string;
|
||||||
|
databaseUri: string;
|
||||||
|
jumpToLocationCallback: () => void;
|
||||||
|
}) {
|
||||||
|
const parsedLoc = useMemo(
|
||||||
|
() => loc && parseSarifLocation(loc, sourceLocationPrefix),
|
||||||
|
[loc, sourceLocationPrefix],
|
||||||
|
);
|
||||||
|
if (parsedLoc === undefined || "hint" in parsedLoc) {
|
||||||
|
return (
|
||||||
|
<NonLocation
|
||||||
|
msg={text || "[no location]"}
|
||||||
|
locationHint={parsedLoc?.hint}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else if (isWholeFileLoc(parsedLoc)) {
|
||||||
|
return (
|
||||||
|
<Location
|
||||||
|
loc={parsedLoc}
|
||||||
|
label={text || `${basename(parsedLoc.userVisibleFile)}`}
|
||||||
|
databaseUri={databaseUri}
|
||||||
|
title={text ? undefined : `${parsedLoc.userVisibleFile}`}
|
||||||
|
jumpToLocationCallback={jumpToLocationCallback}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else if (isLineColumnLoc(parsedLoc)) {
|
||||||
|
return (
|
||||||
|
<Location
|
||||||
|
loc={parsedLoc}
|
||||||
|
label={
|
||||||
|
text ||
|
||||||
|
`${basename(parsedLoc.userVisibleFile)}:${parsedLoc.startLine}:${
|
||||||
|
parsedLoc.startColumn
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
databaseUri={databaseUri}
|
||||||
|
title={text ? undefined : `${parsedLoc.userVisibleFile}`}
|
||||||
|
jumpToLocationCallback={jumpToLocationCallback}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a SARIF message and populates clickable locations.
|
||||||
|
*/
|
||||||
|
export function SarifMessageWithLocations({
|
||||||
|
msg,
|
||||||
|
relatedLocations,
|
||||||
|
sourceLocationPrefix,
|
||||||
|
databaseUri,
|
||||||
|
jumpToLocationCallback,
|
||||||
|
}: {
|
||||||
|
msg: string;
|
||||||
|
relatedLocations: Sarif.Location[];
|
||||||
|
sourceLocationPrefix: string;
|
||||||
|
databaseUri: string;
|
||||||
|
jumpToLocationCallback: () => void;
|
||||||
|
}) {
|
||||||
|
const relatedLocationsById: Map<number, Sarif.Location> = new Map();
|
||||||
|
for (const loc of relatedLocations) {
|
||||||
|
if (loc.id !== undefined) {
|
||||||
|
relatedLocationsById.set(loc.id, loc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{parseSarifPlainTextMessage(msg).map((part, i) => {
|
||||||
|
if (typeof part === "string") {
|
||||||
|
return <span key={i}>{part}</span>;
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<SarifLocation
|
||||||
|
key={i}
|
||||||
|
text={part.text}
|
||||||
|
loc={relatedLocationsById.get(part.dest)}
|
||||||
|
sourceLocationPrefix={sourceLocationPrefix}
|
||||||
|
databaseUri={databaseUri}
|
||||||
|
jumpToLocationCallback={jumpToLocationCallback}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { UrlValue, ResolvableLocationValue } from "../../common/bqrs-cli-types";
|
import { ResolvableLocationValue } from "../../common/bqrs-cli-types";
|
||||||
import { isStringLoc, tryGetResolvableLocation } from "../../common/bqrs-utils";
|
|
||||||
import {
|
import {
|
||||||
RawResultsSortState,
|
RawResultsSortState,
|
||||||
QueryMetadata,
|
QueryMetadata,
|
||||||
@@ -9,7 +8,6 @@ import {
|
|||||||
} from "../../common/interface-types";
|
} from "../../common/interface-types";
|
||||||
import { assertNever } from "../../common/helpers-pure";
|
import { assertNever } from "../../common/helpers-pure";
|
||||||
import { vscode } from "../vscode-api";
|
import { vscode } from "../vscode-api";
|
||||||
import { convertNonPrintableChars } from "../../common/text-utils";
|
|
||||||
import { sendTelemetry } from "../common/telemetry";
|
import { sendTelemetry } from "../common/telemetry";
|
||||||
|
|
||||||
export interface ResultTableProps {
|
export interface ResultTableProps {
|
||||||
@@ -44,21 +42,6 @@ export const oddRowClassName = "vscode-codeql__result-table-row--odd";
|
|||||||
export const pathRowClassName = "vscode-codeql__result-table-row--path";
|
export const pathRowClassName = "vscode-codeql__result-table-row--path";
|
||||||
export const selectedRowClassName = "vscode-codeql__result-table-row--selected";
|
export const selectedRowClassName = "vscode-codeql__result-table-row--selected";
|
||||||
|
|
||||||
export function jumpToLocationHandler(
|
|
||||||
loc: ResolvableLocationValue,
|
|
||||||
databaseUri: string,
|
|
||||||
callback?: () => void,
|
|
||||||
): (e: React.MouseEvent) => void {
|
|
||||||
return (e) => {
|
|
||||||
jumpToLocation(loc, databaseUri);
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
if (callback) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function jumpToLocation(
|
export function jumpToLocation(
|
||||||
loc: ResolvableLocationValue,
|
loc: ResolvableLocationValue,
|
||||||
databaseUri: string,
|
databaseUri: string,
|
||||||
@@ -77,47 +60,6 @@ export function openFile(filePath: string): void {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Render a location as a link which when clicked displays the original location.
|
|
||||||
*/
|
|
||||||
export function renderLocation(
|
|
||||||
loc?: UrlValue,
|
|
||||||
label?: string,
|
|
||||||
databaseUri?: string,
|
|
||||||
title?: string,
|
|
||||||
callback?: () => void,
|
|
||||||
): JSX.Element {
|
|
||||||
const displayLabel = convertNonPrintableChars(label!);
|
|
||||||
|
|
||||||
if (loc === undefined) {
|
|
||||||
return <span>{displayLabel}</span>;
|
|
||||||
} else if (isStringLoc(loc)) {
|
|
||||||
return <a href={loc}>{loc}</a>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const resolvableLoc = tryGetResolvableLocation(loc);
|
|
||||||
if (databaseUri !== undefined && resolvableLoc !== undefined) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{/*
|
|
||||||
eslint-disable-next-line
|
|
||||||
jsx-a11y/anchor-is-valid,
|
|
||||||
*/}
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
className="vscode-codeql__result-table-location-link"
|
|
||||||
title={title}
|
|
||||||
onClick={jumpToLocationHandler(resolvableLoc, databaseUri, callback)}
|
|
||||||
>
|
|
||||||
{displayLabel}
|
|
||||||
</a>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return <span title={title}>{displayLabel}</span>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the attributes for a zebra-striped table row at position `index`.
|
* Returns the attributes for a zebra-striped table row at position `index`.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user