Use new raw result types in result and compare views
This commit is contained in:
@@ -1,9 +1,6 @@
|
||||
import * as sarif from "sarif";
|
||||
import {
|
||||
RawResultSet,
|
||||
ResultRow,
|
||||
ResultSetSchema,
|
||||
Column,
|
||||
ResolvableLocationValue,
|
||||
} from "../common/bqrs-cli-types";
|
||||
import {
|
||||
@@ -25,7 +22,12 @@ import {
|
||||
} from "../model-editor/shared/view-state";
|
||||
import { Mode } from "../model-editor/shared/mode";
|
||||
import { QueryLanguage } from "./query-language";
|
||||
import { UrlValueResolvable } from "./raw-result-types";
|
||||
import {
|
||||
Column,
|
||||
RawResultSet,
|
||||
Row,
|
||||
UrlValueResolvable,
|
||||
} from "./raw-result-types";
|
||||
|
||||
/**
|
||||
* This module contains types and code that are shared between
|
||||
@@ -36,7 +38,11 @@ export const SELECT_TABLE_NAME = "#select";
|
||||
export const ALERTS_TABLE_NAME = "alerts";
|
||||
export const GRAPH_TABLE_NAME = "graph";
|
||||
|
||||
export type RawTableResultSet = { t: "RawResultSet" } & RawResultSet;
|
||||
export type RawTableResultSet = {
|
||||
t: "RawResultSet";
|
||||
resultSet: RawResultSet;
|
||||
};
|
||||
|
||||
export type InterpretedResultSet<T> = {
|
||||
t: "InterpretedResultSet";
|
||||
readonly schema: ResultSetSchema;
|
||||
@@ -372,8 +378,8 @@ export interface SetComparisonsMessage {
|
||||
* (or added) in the comparison.
|
||||
*/
|
||||
export type QueryCompareResult = {
|
||||
from: ResultRow[];
|
||||
to: ResultRow[];
|
||||
from: Row[];
|
||||
to: Row[];
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as Sarif from "sarif";
|
||||
import type { HighlightedRegion } from "../variant-analysis/shared/analysis-result";
|
||||
import { ResolvableLocationValue } from "../common/bqrs-cli-types";
|
||||
import { UrlValueResolvable } from "./raw-result-types";
|
||||
import { isEmptyPath } from "./bqrs-utils";
|
||||
|
||||
export interface SarifLink {
|
||||
@@ -16,7 +16,7 @@ interface NoLocation {
|
||||
}
|
||||
|
||||
type ParsedSarifLocation =
|
||||
| (ResolvableLocationValue & {
|
||||
| (UrlValueResolvable & {
|
||||
userVisibleFile: string;
|
||||
})
|
||||
// Resolvable locations have a `uri` field, but it will sometimes include
|
||||
@@ -137,6 +137,7 @@ export function parseSarifLocation(
|
||||
// If the region property is absent, the physicalLocation object refers to the entire file.
|
||||
// Source: https://docs.oasis-open.org/sarif/sarif/v2.1.0/cs01/sarif-v2.1.0-cs01.html#_Toc16012638.
|
||||
return {
|
||||
type: "wholeFileLocation",
|
||||
uri: effectiveLocation,
|
||||
userVisibleFile,
|
||||
} as ParsedSarifLocation;
|
||||
@@ -144,6 +145,7 @@ export function parseSarifLocation(
|
||||
const region = parseSarifRegion(physicalLocation.region);
|
||||
|
||||
return {
|
||||
type: "lineColumnLocation",
|
||||
uri: effectiveLocation,
|
||||
userVisibleFile,
|
||||
...region,
|
||||
|
||||
@@ -10,11 +10,7 @@ import { extLogger } from "../common/logging/vscode";
|
||||
import { CodeQLCliServer } from "../codeql-cli/cli";
|
||||
import { DatabaseManager } from "../databases/local-databases";
|
||||
import { jumpToLocation } from "../databases/local-databases/locations";
|
||||
import {
|
||||
transformBqrsResultSet,
|
||||
RawResultSet,
|
||||
BQRSInfo,
|
||||
} from "../common/bqrs-cli-types";
|
||||
import { BQRSInfo } from "../common/bqrs-cli-types";
|
||||
import resultsDiff from "./resultsDiff";
|
||||
import { CompletedLocalQueryInfo } from "../query-results";
|
||||
import { assertNever, getErrorMessage } from "../common/helpers-pure";
|
||||
@@ -26,6 +22,8 @@ import {
|
||||
import { telemetryListener } from "../common/vscode/telemetry";
|
||||
import { redactableError } from "../common/errors";
|
||||
import { App } from "../common/app";
|
||||
import { bqrsToResultSet } from "../common/bqrs-result";
|
||||
import { RawResultSet } from "../common/raw-result-types";
|
||||
|
||||
interface ComparePair {
|
||||
from: CompletedLocalQueryInfo;
|
||||
@@ -93,7 +91,7 @@ export class CompareView extends AbstractWebview<
|
||||
time: to.startTime,
|
||||
},
|
||||
},
|
||||
columns: fromResultSet.schema.columns,
|
||||
columns: fromResultSet.columns,
|
||||
commonResultSetNames,
|
||||
currentResultSetName,
|
||||
rows,
|
||||
@@ -245,7 +243,7 @@ export class CompareView extends AbstractWebview<
|
||||
throw new Error(`Schema ${resultSetName} not found.`);
|
||||
}
|
||||
const chunk = await this.cliServer.bqrsDecode(resultsPath, resultSetName);
|
||||
return transformBqrsResultSet(schema, chunk);
|
||||
return bqrsToResultSet(schema, chunk);
|
||||
}
|
||||
|
||||
private compareResults(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { RawResultSet } from "../common/bqrs-cli-types";
|
||||
import { QueryCompareResult } from "../common/interface-types";
|
||||
import { RawResultSet } from "../common/raw-result-types";
|
||||
|
||||
/**
|
||||
* Compare the rows of two queries. Use deep equality to determine if
|
||||
@@ -23,7 +23,7 @@ export default function resultsDiff(
|
||||
fromResults: RawResultSet,
|
||||
toResults: RawResultSet,
|
||||
): QueryCompareResult {
|
||||
if (fromResults.schema.columns.length !== toResults.schema.columns.length) {
|
||||
if (fromResults.columns.length !== toResults.columns.length) {
|
||||
throw new Error("CodeQL Compare: Columns do not match.");
|
||||
}
|
||||
|
||||
|
||||
@@ -60,11 +60,7 @@ import {
|
||||
shownLocationLineDecoration,
|
||||
jumpToLocation,
|
||||
} from "../databases/local-databases/locations";
|
||||
import {
|
||||
RawResultSet,
|
||||
transformBqrsResultSet,
|
||||
ResultSetSchema,
|
||||
} from "../common/bqrs-cli-types";
|
||||
import { bqrsToResultSet } from "../common/bqrs-result";
|
||||
import {
|
||||
AbstractWebview,
|
||||
WebviewPanelConfig,
|
||||
@@ -76,6 +72,8 @@ import { redactableError } from "../common/errors";
|
||||
import { ResultsViewCommands } from "../common/commands";
|
||||
import { App } from "../common/app";
|
||||
import { Disposable } from "../common/disposable-object";
|
||||
import { RawResultSet } from "../common/raw-result-types";
|
||||
import { ResultSetSchema } from "../common/bqrs-cli-types";
|
||||
|
||||
/**
|
||||
* results-view.ts
|
||||
@@ -136,7 +134,7 @@ function numPagesOfResultSet(
|
||||
const n =
|
||||
interpretation?.data.t === "GraphInterpretationData"
|
||||
? interpretation.data.dot.length
|
||||
: resultSet.schema.rows;
|
||||
: resultSet.totalRowCount;
|
||||
|
||||
return Math.ceil(n / pageSize);
|
||||
}
|
||||
@@ -524,16 +522,16 @@ export class ResultsView extends AbstractWebview<
|
||||
offset: schema.pagination?.offsets[0],
|
||||
pageSize,
|
||||
});
|
||||
const resultSet = transformBqrsResultSet(schema, chunk);
|
||||
const resultSet = bqrsToResultSet(schema, chunk);
|
||||
fullQuery.completedQuery.setResultCount(
|
||||
interpretationPage?.numTotalResults || resultSet.schema.rows,
|
||||
interpretationPage?.numTotalResults || resultSet.totalRowCount,
|
||||
);
|
||||
const parsedResultSets: ParsedResultSets = {
|
||||
pageNumber: 0,
|
||||
pageSize,
|
||||
numPages: numPagesOfResultSet(resultSet, this._interpretation),
|
||||
numInterpretedPages: numInterpretedPages(this._interpretation),
|
||||
resultSet: { ...resultSet, t: "RawResultSet" },
|
||||
resultSet: { t: "RawResultSet", resultSet },
|
||||
selectedTable: undefined,
|
||||
resultSetNames,
|
||||
};
|
||||
@@ -668,12 +666,12 @@ export class ResultsView extends AbstractWebview<
|
||||
pageSize,
|
||||
},
|
||||
);
|
||||
const resultSet = transformBqrsResultSet(schema, chunk);
|
||||
const resultSet = bqrsToResultSet(schema, chunk);
|
||||
|
||||
const parsedResultSets: ParsedResultSets = {
|
||||
pageNumber,
|
||||
pageSize,
|
||||
resultSet: { t: "RawResultSet", ...resultSet },
|
||||
resultSet: { t: "RawResultSet", resultSet },
|
||||
numPages: numPagesOfResultSet(resultSet),
|
||||
numInterpretedPages: numInterpretedPages(this._interpretation),
|
||||
selectedTable,
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Meta, StoryFn } from "@storybook/react";
|
||||
import CompareTableComponent from "../../view/compare/CompareTable";
|
||||
|
||||
import "../../view/results/resultsView.css";
|
||||
import { ColumnKind } from "../../common/raw-result-types";
|
||||
|
||||
export default {
|
||||
title: "Compare/Compare Table",
|
||||
@@ -32,8 +33,8 @@ CompareTable.args = {
|
||||
},
|
||||
},
|
||||
columns: [
|
||||
{ name: "a", kind: "e" },
|
||||
{ name: "b", kind: "e" },
|
||||
{ name: "a", kind: ColumnKind.Entity },
|
||||
{ name: "b", kind: ColumnKind.Entity },
|
||||
],
|
||||
commonResultSetNames: ["edges", "nodes", "subpaths", "#select"],
|
||||
currentResultSetName: "edges",
|
||||
@@ -42,23 +43,31 @@ CompareTable.args = {
|
||||
to: [
|
||||
[
|
||||
{
|
||||
label: "url : String",
|
||||
url: {
|
||||
uri: "file:/home/runner/work/sql2o-example/sql2o-example/src/main/java/org/example/HelloController.java",
|
||||
startLine: 22,
|
||||
startColumn: 27,
|
||||
endLine: 22,
|
||||
endColumn: 57,
|
||||
type: "entity",
|
||||
value: {
|
||||
label: "url : String",
|
||||
url: {
|
||||
type: "lineColumnLocation",
|
||||
uri: "file:/home/runner/work/sql2o-example/sql2o-example/src/main/java/org/example/HelloController.java",
|
||||
startLine: 22,
|
||||
startColumn: 27,
|
||||
endLine: 22,
|
||||
endColumn: 57,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "url",
|
||||
url: {
|
||||
uri: "file:/home/runner/work/sql2o-example/sql2o-example/src/main/java/org/example/HelloController.java",
|
||||
startLine: 23,
|
||||
startColumn: 33,
|
||||
endLine: 23,
|
||||
endColumn: 35,
|
||||
type: "entity",
|
||||
value: {
|
||||
label: "url",
|
||||
url: {
|
||||
type: "lineColumnLocation",
|
||||
uri: "file:/home/runner/work/sql2o-example/sql2o-example/src/main/java/org/example/HelloController.java",
|
||||
startLine: 23,
|
||||
startColumn: 33,
|
||||
endLine: 23,
|
||||
endColumn: 35,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -3,12 +3,12 @@ import * as React from "react";
|
||||
import { SetComparisonsMessage } from "../../common/interface-types";
|
||||
import RawTableHeader from "../results/RawTableHeader";
|
||||
import { className } from "../results/result-table-utils";
|
||||
import { ResultRow } from "../../common/bqrs-cli-types";
|
||||
import RawTableRow from "../results/RawTableRow";
|
||||
import { vscode } from "../vscode-api";
|
||||
import { sendTelemetry } from "../common/telemetry";
|
||||
import TextButton from "../common/TextButton";
|
||||
import { styled } from "styled-components";
|
||||
import { Row } from "../../common/raw-result-types";
|
||||
|
||||
interface Props {
|
||||
comparison: SetComparisonsMessage;
|
||||
@@ -31,7 +31,7 @@ export default function CompareTable(props: Props) {
|
||||
});
|
||||
}
|
||||
|
||||
function createRows(rows: ResultRow[], databaseUri: string) {
|
||||
function createRows(rows: Row[], databaseUri: string) {
|
||||
return (
|
||||
<tbody>
|
||||
{rows.map((row, rowIndex) => (
|
||||
|
||||
@@ -6,21 +6,22 @@ import {
|
||||
RawResultsSortState,
|
||||
NavigateMsg,
|
||||
NavigationDirection,
|
||||
RawTableResultSet,
|
||||
} from "../../common/interface-types";
|
||||
import RawTableHeader from "./RawTableHeader";
|
||||
import RawTableRow from "./RawTableRow";
|
||||
import { ResultRow } from "../../common/bqrs-cli-types";
|
||||
import { onNavigation } from "./ResultsApp";
|
||||
import { tryGetResolvableLocation } from "../../common/bqrs-utils";
|
||||
import { sendTelemetry } from "../common/telemetry";
|
||||
import { assertNever } from "../../common/helpers-pure";
|
||||
import { EmptyQueryResultsMessage } from "./EmptyQueryResultsMessage";
|
||||
import { useScrollIntoView } from "./useScrollIntoView";
|
||||
import {
|
||||
isUrlValueResolvable,
|
||||
RawResultSet,
|
||||
} from "../../common/raw-result-types";
|
||||
|
||||
type RawTableProps = {
|
||||
databaseUri: string;
|
||||
resultSet: RawTableResultSet;
|
||||
resultSet: RawResultSet;
|
||||
sortState?: RawResultsSortState;
|
||||
offset: number;
|
||||
};
|
||||
@@ -67,11 +68,12 @@ export function RawTable({
|
||||
return prevSelectedItem;
|
||||
}
|
||||
const cellData = rowData[nextColumn];
|
||||
if (cellData != null && typeof cellData === "object") {
|
||||
const location = tryGetResolvableLocation(cellData.url);
|
||||
if (location !== undefined) {
|
||||
jumpToLocation(location, databaseUri);
|
||||
}
|
||||
if (
|
||||
cellData?.type === "entity" &&
|
||||
cellData.value.url &&
|
||||
isUrlValueResolvable(cellData.value.url)
|
||||
) {
|
||||
jumpToLocation(cellData.value.url, databaseUri);
|
||||
}
|
||||
return { row: nextRow, column: nextColumn };
|
||||
});
|
||||
@@ -126,7 +128,7 @@ export function RawTable({
|
||||
return <EmptyQueryResultsMessage />;
|
||||
}
|
||||
|
||||
const tableRows = dataRows.map((row: ResultRow, rowIndex: number) => (
|
||||
const tableRows = dataRows.map((row, rowIndex) => (
|
||||
<RawTableRow
|
||||
key={rowIndex}
|
||||
rowIndex={rowIndex + offset}
|
||||
@@ -159,8 +161,8 @@ export function RawTable({
|
||||
return (
|
||||
<table className={className}>
|
||||
<RawTableHeader
|
||||
columns={resultSet.schema.columns}
|
||||
schemaName={resultSet.schema.name}
|
||||
columns={resultSet.columns}
|
||||
schemaName={resultSet.name}
|
||||
sortState={sortState}
|
||||
/>
|
||||
<tbody>{tableRows}</tbody>
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
SortDirection,
|
||||
} from "../../common/interface-types";
|
||||
import { nextSortDirection } from "./result-table-utils";
|
||||
import { Column } from "../../common/bqrs-cli-types";
|
||||
import { Column } from "../../common/raw-result-types";
|
||||
|
||||
interface Props {
|
||||
readonly columns: readonly Column[];
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import * as React from "react";
|
||||
import { ResultRow } from "../../common/bqrs-cli-types";
|
||||
import { selectedRowClassName, zebraStripe } from "./result-table-utils";
|
||||
import RawTableValue from "./RawTableValue";
|
||||
import { Row } from "../../common/raw-result-types";
|
||||
|
||||
interface Props {
|
||||
rowIndex: number;
|
||||
row: ResultRow;
|
||||
row: Row;
|
||||
databaseUri: string;
|
||||
className?: string;
|
||||
selectedColumn?: number;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import * as React from "react";
|
||||
|
||||
import { Location } from "./locations/Location";
|
||||
import { CellValue } from "../../common/bqrs-cli-types";
|
||||
import { RawNumberValue } from "../common/RawNumberValue";
|
||||
import { CellValue } from "../../common/raw-result-types";
|
||||
import { assertNever } from "../../common/helpers-pure";
|
||||
|
||||
interface Props {
|
||||
value: CellValue;
|
||||
@@ -15,21 +16,23 @@ export default function RawTableValue({
|
||||
databaseUri,
|
||||
onSelected,
|
||||
}: Props): JSX.Element {
|
||||
switch (typeof value) {
|
||||
switch (value.type) {
|
||||
case "boolean":
|
||||
return <span>{value.toString()}</span>;
|
||||
return <span>{value.value.toString()}</span>;
|
||||
case "number":
|
||||
return <RawNumberValue value={value} />;
|
||||
return <RawNumberValue value={value.value} />;
|
||||
case "string":
|
||||
return <Location label={value.toString()} />;
|
||||
default:
|
||||
return <Location label={value.value} />;
|
||||
case "entity":
|
||||
return (
|
||||
<Location
|
||||
loc={value.url}
|
||||
label={value.label}
|
||||
loc={value.value.url}
|
||||
label={value.value.label}
|
||||
databaseUri={databaseUri}
|
||||
onClick={onSelected}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
assertNever(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ interface Props {
|
||||
function getResultCount(resultSet: ResultSet): number {
|
||||
switch (resultSet.t) {
|
||||
case "RawResultSet":
|
||||
return resultSet.schema.rows;
|
||||
return resultSet.resultSet.totalRowCount;
|
||||
case "InterpretedResultSet":
|
||||
return resultSet.interpretation.numTotalResults;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ export function ResultTable(props: ResultTableProps) {
|
||||
const { resultSet } = props;
|
||||
switch (resultSet.t) {
|
||||
case "RawResultSet":
|
||||
return <RawTable {...props} resultSet={resultSet} />;
|
||||
return <RawTable {...props} resultSet={resultSet.resultSet} />;
|
||||
case "InterpretedResultSet": {
|
||||
const data = resultSet.interpretation.data;
|
||||
switch (data.t) {
|
||||
|
||||
@@ -22,6 +22,7 @@ import { ResultTablesHeader } from "./ResultTablesHeader";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { ResultCount } from "./ResultCount";
|
||||
import { ProblemsViewCheckbox } from "./ProblemsViewCheckbox";
|
||||
import { assertNever } from "../../common/helpers-pure";
|
||||
|
||||
/**
|
||||
* Properties for the `ResultTables` component.
|
||||
@@ -149,7 +150,7 @@ export function ResultTables(props: ResultTablesProps) {
|
||||
const resultSetExists =
|
||||
parsedResultSets.resultSetNames.some((v) => selectedTable === v) ||
|
||||
getResultSets(rawResultSets, interpretation).some(
|
||||
(v) => selectedTable === v.schema.name,
|
||||
(v) => selectedTable === getResultSetName(v),
|
||||
);
|
||||
|
||||
// If the selected result set does not exist, select the default result set.
|
||||
@@ -207,11 +208,14 @@ export function ResultTables(props: ResultTablesProps) {
|
||||
|
||||
const resultSet = useMemo(
|
||||
() =>
|
||||
resultSets.find((resultSet) => resultSet.schema.name === selectedTable),
|
||||
resultSets.find(
|
||||
(resultSet) => selectedTable === getResultSetName(resultSet),
|
||||
),
|
||||
[resultSets, selectedTable],
|
||||
);
|
||||
const nonemptyRawResults = resultSets.some(
|
||||
(resultSet) => resultSet.t === "RawResultSet" && resultSet.rows.length > 0,
|
||||
(resultSet) =>
|
||||
resultSet.t === "RawResultSet" && resultSet.resultSet.rows.length > 0,
|
||||
);
|
||||
|
||||
const resultSetOptions = resultSetNames.map((name) => (
|
||||
@@ -219,6 +223,9 @@ export function ResultTables(props: ResultTablesProps) {
|
||||
{name}
|
||||
</option>
|
||||
));
|
||||
|
||||
const resultSetName = resultSet ? getResultSetName(resultSet) : undefined;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ResultTablesHeader {...props} selectedTable={selectedTable} />
|
||||
@@ -239,13 +246,13 @@ export function ResultTables(props: ResultTablesProps) {
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
{resultSet && (
|
||||
{resultSet && resultSetName && (
|
||||
<ResultTable
|
||||
key={resultSet.schema.name}
|
||||
key={resultSetName}
|
||||
resultSet={resultSet}
|
||||
databaseUri={database.databaseUri}
|
||||
resultsPath={resultsPath}
|
||||
sortState={sortStates.get(resultSet.schema.name)}
|
||||
sortState={sortStates.get(resultSetName)}
|
||||
nonemptyRawResults={nonemptyRawResults}
|
||||
showRawResults={() => {
|
||||
setSelectedTable(SELECT_TABLE_NAME);
|
||||
@@ -260,6 +267,17 @@ export function ResultTables(props: ResultTablesProps) {
|
||||
|
||||
function getDefaultResultSet(resultSets: readonly ResultSet[]): string {
|
||||
return getDefaultResultSetName(
|
||||
resultSets.map((resultSet) => resultSet.schema.name),
|
||||
resultSets.map((resultSet) => getResultSetName(resultSet)),
|
||||
);
|
||||
}
|
||||
|
||||
function getResultSetName(resultSet: ResultSet): string {
|
||||
switch (resultSet.t) {
|
||||
case "RawResultSet":
|
||||
return resultSet.resultSet.name;
|
||||
case "InterpretedResultSet":
|
||||
return resultSet.schema.name;
|
||||
default:
|
||||
assertNever(resultSet);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import * as fs from "fs-extra";
|
||||
import { resolve } from "path";
|
||||
import { ColumnKindCode } from "../../../common/bqrs-cli-types";
|
||||
import { postMessage } from "../../common/post-message";
|
||||
import { ColumnKind } from "../../../common/raw-result-types";
|
||||
|
||||
const exampleSarif = fs.readJSONSync(
|
||||
resolve(__dirname, "../../../../test/data/sarif/validSarif.sarif"),
|
||||
@@ -120,13 +121,19 @@ describe(ResultsApp.name, () => {
|
||||
numPages: 1,
|
||||
numInterpretedPages: 0,
|
||||
resultSet: {
|
||||
schema: {
|
||||
resultSet: {
|
||||
name: "#select",
|
||||
rows: 1,
|
||||
columns: [{ kind: "s" }],
|
||||
pagination: { "step-size": 200, offsets: [13] },
|
||||
totalRowCount: 1,
|
||||
columns: [{ kind: ColumnKind.String }],
|
||||
rows: [
|
||||
[
|
||||
{
|
||||
type: "string",
|
||||
value: "foobar1",
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
rows: [["foobar1"]],
|
||||
t: "RawResultSet",
|
||||
},
|
||||
resultSetNames: ["#select"],
|
||||
@@ -158,13 +165,19 @@ describe(ResultsApp.name, () => {
|
||||
numPages: 1,
|
||||
numInterpretedPages: 0,
|
||||
resultSet: {
|
||||
schema: {
|
||||
resultSet: {
|
||||
name: "#Quick_evaluation_of_expression",
|
||||
rows: 1,
|
||||
columns: [{ name: "#expr_result", kind: "s" }],
|
||||
pagination: { "step-size": 200, offsets: [49] },
|
||||
totalRowCount: 1,
|
||||
columns: [{ name: "#expr_result", kind: ColumnKind.String }],
|
||||
rows: [
|
||||
[
|
||||
{
|
||||
type: "string",
|
||||
value: "foobar2",
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
rows: [["foobar2"]],
|
||||
t: "RawResultSet",
|
||||
},
|
||||
resultSetNames: ["#Quick_evaluation_of_expression"],
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import * as React from "react";
|
||||
import { useMemo } from "react";
|
||||
|
||||
import { UrlValue } from "../../../common/bqrs-cli-types";
|
||||
import {
|
||||
isStringLoc,
|
||||
tryGetResolvableLocation,
|
||||
} from "../../../common/bqrs-utils";
|
||||
import { UrlValue } from "../../../common/raw-result-types";
|
||||
import { convertNonPrintableChars } from "../../../common/text-utils";
|
||||
import { NonClickableLocation } from "./NonClickableLocation";
|
||||
import { ClickableLocation } from "./ClickableLocation";
|
||||
@@ -28,24 +24,23 @@ export function Location({
|
||||
title,
|
||||
onClick,
|
||||
}: Props): JSX.Element {
|
||||
const resolvableLoc = useMemo(() => tryGetResolvableLocation(loc), [loc]);
|
||||
const displayLabel = useMemo(() => convertNonPrintableChars(label), [label]);
|
||||
|
||||
if (loc === undefined) {
|
||||
return <NonClickableLocation msg={displayLabel} />;
|
||||
}
|
||||
|
||||
if (isStringLoc(loc)) {
|
||||
return <a href={loc}>{loc}</a>;
|
||||
if (loc.type === "string") {
|
||||
return <a href={loc.value}>{loc.value}</a>;
|
||||
}
|
||||
|
||||
if (databaseUri === undefined || resolvableLoc === undefined) {
|
||||
if (databaseUri === undefined) {
|
||||
return <NonClickableLocation msg={displayLabel} locationHint={title} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<ClickableLocation
|
||||
loc={resolvableLoc}
|
||||
loc={loc}
|
||||
label={displayLabel}
|
||||
databaseUri={databaseUri}
|
||||
onClick={onClick}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import * as React from "react";
|
||||
import * as Sarif from "sarif";
|
||||
import { isLineColumnLoc, isWholeFileLoc } from "../../../common/bqrs-utils";
|
||||
import { parseSarifLocation } from "../../../common/sarif-utils";
|
||||
import { basename } from "../../../common/path";
|
||||
import { useMemo } from "react";
|
||||
@@ -35,7 +34,7 @@ export function SarifLocation({
|
||||
return <Location label={text || "[no location]"} title={parsedLoc?.hint} />;
|
||||
}
|
||||
|
||||
if (isWholeFileLoc(parsedLoc)) {
|
||||
if (parsedLoc.type === "wholeFileLocation") {
|
||||
return (
|
||||
<Location
|
||||
loc={parsedLoc}
|
||||
@@ -47,7 +46,7 @@ export function SarifLocation({
|
||||
);
|
||||
}
|
||||
|
||||
if (isLineColumnLoc(parsedLoc)) {
|
||||
if (parsedLoc.type === "lineColumnLocation") {
|
||||
return (
|
||||
<Location
|
||||
loc={parsedLoc}
|
||||
|
||||
Reference in New Issue
Block a user