diff --git a/extensions/ql-vscode/src/common/interface-types.ts b/extensions/ql-vscode/src/common/interface-types.ts index fee7e62c518..f4df0ff2d61 100644 --- a/extensions/ql-vscode/src/common/interface-types.ts +++ b/extensions/ql-vscode/src/common/interface-types.ts @@ -334,13 +334,15 @@ interface ChangeCompareMessage { newResultSetName: string; } -export type ToCompareViewMessage = SetComparisonsMessage; +export type ToCompareViewMessage = + | SetComparisonQueryInfoMessage + | SetComparisonsMessage; /** - * Message to the compare view that specifies the query results to compare. + * Message to the compare view that sets the metadata of the compared queries. */ -export interface SetComparisonsMessage { - readonly t: "setComparisons"; +export interface SetComparisonQueryInfoMessage { + readonly t: "setComparisonQueryInfo"; readonly stats: { fromQuery?: { name: string; @@ -353,11 +355,18 @@ export interface SetComparisonsMessage { time: string; }; }; + readonly databaseUri: string; readonly commonResultSetNames: string[]; +} + +/** + * Message to the compare view that specifies the query results to compare. + */ +export interface SetComparisonsMessage { + readonly t: "setComparisons"; readonly currentResultSetName: string; readonly result: QueryCompareResult | undefined; readonly message: string | undefined; - readonly databaseUri: string; } type QueryCompareResult = RawQueryCompareResult | InterpretedQueryCompareResult; diff --git a/extensions/ql-vscode/src/compare/compare-view.ts b/extensions/ql-vscode/src/compare/compare-view.ts index 971f29f005b..61c467b241e 100644 --- a/extensions/ql-vscode/src/compare/compare-view.ts +++ b/extensions/ql-vscode/src/compare/compare-view.ts @@ -22,13 +22,18 @@ import { import { telemetryListener } from "../common/vscode/telemetry"; import { redactableError } from "../common/errors"; import { App } from "../common/app"; -import { findResultSetNames } from "./result-set-names"; +import { + findCommonResultSetNames, + findResultSetNames, +} from "./result-set-names"; interface ComparePair { from: CompletedLocalQueryInfo; fromSchemas: BQRSInfo; to: CompletedLocalQueryInfo; toSchemas: BQRSInfo; + + commonResultSetNames: readonly string[]; } export class CompareView extends AbstractWebview< @@ -62,13 +67,44 @@ export class CompareView extends AbstractWebview< to.completedQuery.query.resultsPaths.resultsPath, ); + const commonResultSetNames = await findCommonResultSetNames( + fromSchemas, + toSchemas, + ); + this.comparePair = { from, fromSchemas, to, toSchemas, + commonResultSetNames, }; + const panel = await this.getPanel(); + panel.reveal(undefined, true); + await this.waitForPanelLoaded(); + + await this.postMessage({ + t: "setComparisonQueryInfo", + stats: { + fromQuery: { + // since we split the description into several rows + // only run interpolation if the label is user-defined + // otherwise we will wind up with duplicated rows + name: this.labelProvider.getShortLabel(from), + status: from.completedQuery.statusString, + time: from.startTime, + }, + toQuery: { + name: this.labelProvider.getShortLabel(to), + status: to.completedQuery.statusString, + time: to.startTime, + }, + }, + databaseUri: to.initialInfo.databaseInfo.databaseUri, + commonResultSetNames, + }); + await this.showResultsInternal(selectedResultSetName); } @@ -77,21 +113,15 @@ export class CompareView extends AbstractWebview< return; } - const { from, to } = this.comparePair; - const panel = await this.getPanel(); panel.reveal(undefined, true); await this.waitForPanelLoaded(); - const { - commonResultSetNames, - currentResultSetDisplayName, - fromResultSet, - toResultSet, - } = await this.findResultSetsToCompare( - this.comparePair, - selectedResultSetName, - ); + const { currentResultSetDisplayName, fromResultSet, toResultSet } = + await this.findResultSetsToCompare( + this.comparePair, + selectedResultSetName, + ); if (currentResultSetDisplayName) { let result: RawQueryCompareResult | undefined; let message: string | undefined; @@ -103,26 +133,9 @@ export class CompareView extends AbstractWebview< await this.postMessage({ t: "setComparisons", - stats: { - fromQuery: { - // since we split the description into several rows - // only run interpolation if the label is user-defined - // otherwise we will wind up with duplicated rows - name: this.labelProvider.getShortLabel(from), - status: from.completedQuery.statusString, - time: from.startTime, - }, - toQuery: { - name: this.labelProvider.getShortLabel(to), - status: to.completedQuery.statusString, - time: to.startTime, - }, - }, result, - commonResultSetNames, currentResultSetName: currentResultSetDisplayName, message, - databaseUri: to.initialInfo.databaseInfo.databaseUri, }); } } @@ -190,15 +203,16 @@ export class CompareView extends AbstractWebview< } private async findResultSetsToCompare( - { from, fromSchemas, to, toSchemas }: ComparePair, + { from, fromSchemas, to, toSchemas, commonResultSetNames }: ComparePair, selectedResultSetName: string | undefined, ) { - const { - commonResultSetNames, - currentResultSetDisplayName, - fromResultSetName, - toResultSetName, - } = await findResultSetNames(fromSchemas, toSchemas, selectedResultSetName); + const { currentResultSetDisplayName, fromResultSetName, toResultSetName } = + await findResultSetNames( + fromSchemas, + toSchemas, + commonResultSetNames, + selectedResultSetName, + ); const fromResultSet = await this.getResultSet( fromSchemas, @@ -211,7 +225,6 @@ export class CompareView extends AbstractWebview< to.completedQuery.query.resultsPaths.resultsPath, ); return { - commonResultSetNames, currentResultSetDisplayName, fromResultSet, toResultSet, diff --git a/extensions/ql-vscode/src/compare/result-set-names.ts b/extensions/ql-vscode/src/compare/result-set-names.ts index 5b43c0eb4a3..7df0a8a729c 100644 --- a/extensions/ql-vscode/src/compare/result-set-names.ts +++ b/extensions/ql-vscode/src/compare/result-set-names.ts @@ -1,18 +1,28 @@ import { BQRSInfo } from "../common/bqrs-cli-types"; import { getDefaultResultSetName } from "../common/interface-types"; +export async function findCommonResultSetNames( + fromSchemas: BQRSInfo, + toSchemas: BQRSInfo, +): Promise { + const fromSchemaNames = fromSchemas["result-sets"].map( + (schema) => schema.name, + ); + const toSchemaNames = toSchemas["result-sets"].map((schema) => schema.name); + + return fromSchemaNames.filter((name) => toSchemaNames.includes(name)); +} + export async function findResultSetNames( fromSchemas: BQRSInfo, toSchemas: BQRSInfo, + commonResultSetNames: readonly string[], selectedResultSetName: string | undefined, ) { const fromSchemaNames = fromSchemas["result-sets"].map( (schema) => schema.name, ); const toSchemaNames = toSchemas["result-sets"].map((schema) => schema.name); - const commonResultSetNames = fromSchemaNames.filter((name) => - toSchemaNames.includes(name), - ); // Fall back on the default result set names if there are no common ones. const defaultFromResultSetName = fromSchemaNames.find((name) => @@ -37,7 +47,6 @@ export async function findResultSetNames( const toResultSetName = currentResultSetName || defaultToResultSetName!; return { - commonResultSetNames, currentResultSetDisplayName: currentResultSetName || `${defaultFromResultSetName} <-> ${defaultToResultSetName}`, diff --git a/extensions/ql-vscode/src/stories/compare/CompareTable.stories.tsx b/extensions/ql-vscode/src/stories/compare/CompareTable.stories.tsx index d0ec928f6a9..1b5a82f4cca 100644 --- a/extensions/ql-vscode/src/stories/compare/CompareTable.stories.tsx +++ b/extensions/ql-vscode/src/stories/compare/CompareTable.stories.tsx @@ -17,8 +17,8 @@ const Template: StoryFn = (args) => ( export const CompareTable = Template.bind({}); CompareTable.args = { - comparison: { - t: "setComparisons", + queryInfo: { + t: "setComparisonQueryInfo", stats: { fromQuery: { name: "Query built from user-controlled sources", @@ -31,7 +31,11 @@ CompareTable.args = { time: "8/16/2023, 3:07:21 PM", }, }, + databaseUri: "file:///java", commonResultSetNames: ["edges", "nodes", "subpaths", "#select"], + }, + comparison: { + t: "setComparisons", currentResultSetName: "edges", result: { kind: "raw", @@ -66,6 +70,5 @@ CompareTable.args = { ], }, message: undefined, - databaseUri: "file:///java", }, }; diff --git a/extensions/ql-vscode/src/view/compare/Compare.tsx b/extensions/ql-vscode/src/view/compare/Compare.tsx index 65e0a8ef3fe..e335c966373 100644 --- a/extensions/ql-vscode/src/view/compare/Compare.tsx +++ b/extensions/ql-vscode/src/view/compare/Compare.tsx @@ -5,12 +5,14 @@ import { styled } from "styled-components"; import { ToCompareViewMessage, SetComparisonsMessage, + SetComparisonQueryInfoMessage, } from "../../common/interface-types"; import CompareSelector from "./CompareSelector"; import { vscode } from "../vscode-api"; import CompareTable from "./CompareTable"; import "../results/resultsView.css"; +import { assertNever } from "../../common/helpers-pure"; const Header = styled.div` display: flex; @@ -25,6 +27,8 @@ const Message = styled.div` `; export function Compare(_: Record): JSX.Element { + const [queryInfo, setQueryInfo] = + useState(null); const [comparison, setComparison] = useState( null, ); @@ -39,8 +43,14 @@ export function Compare(_: Record): JSX.Element { if (evt.origin === window.origin) { const msg: ToCompareViewMessage = evt.data; switch (msg.t) { + case "setComparisonQueryInfo": + setQueryInfo(msg); + break; case "setComparisons": setComparison(msg); + break; + default: + assertNever(msg); } } else { // sanitize origin @@ -55,7 +65,7 @@ export function Compare(_: Record): JSX.Element { }; }, []); - if (!comparison) { + if (!queryInfo || !comparison) { return
Waiting for results to load.
; } @@ -65,7 +75,7 @@ export function Compare(_: Record): JSX.Element {
Comparing: vscode.postMessage({ t: "changeCompare", newResultSetName }) @@ -73,7 +83,10 @@ export function Compare(_: Record): JSX.Element { />
{hasRows ? ( - + ) : ( {message} )} diff --git a/extensions/ql-vscode/src/view/compare/CompareTable.tsx b/extensions/ql-vscode/src/view/compare/CompareTable.tsx index 3384580bfd9..8645285355f 100644 --- a/extensions/ql-vscode/src/view/compare/CompareTable.tsx +++ b/extensions/ql-vscode/src/view/compare/CompareTable.tsx @@ -1,6 +1,9 @@ import * as React from "react"; -import { SetComparisonsMessage } from "../../common/interface-types"; +import { + SetComparisonQueryInfoMessage, + SetComparisonsMessage, +} from "../../common/interface-types"; import { className } from "../results/result-table-utils"; import { vscode } from "../vscode-api"; import TextButton from "../common/TextButton"; @@ -8,6 +11,7 @@ import { styled } from "styled-components"; import { RawCompareResultTable } from "./RawCompareResultTable"; interface Props { + queryInfo: SetComparisonQueryInfoMessage; comparison: SetComparisonsMessage; } @@ -26,9 +30,8 @@ const Table = styled.table` } `; -export default function CompareTable(props: Props) { - const comparison = props.comparison; - const result = props.comparison.result!; +export default function CompareTable({ queryInfo, comparison }: Props) { + const result = comparison.result!; async function openQuery(kind: "from" | "to") { vscode.postMessage({ @@ -43,18 +46,18 @@ export default function CompareTable(props: Props) { openQuery("from")}> - {comparison.stats.fromQuery?.name} + {queryInfo.stats.fromQuery?.name} openQuery("to")}> - {comparison.stats.toQuery?.name} + {queryInfo.stats.toQuery?.name} - {comparison.stats.fromQuery?.time} - {comparison.stats.toQuery?.time} + {queryInfo.stats.fromQuery?.time} + {queryInfo.stats.toQuery?.time} {result.from.length} rows removed @@ -69,7 +72,7 @@ export default function CompareTable(props: Props) { columns={result.columns} schemaName={comparison.currentResultSetName} rows={result.from} - databaseUri={comparison.databaseUri} + databaseUri={queryInfo.databaseUri} className={className} /> )} @@ -80,7 +83,7 @@ export default function CompareTable(props: Props) { columns={result.columns} schemaName={comparison.currentResultSetName} rows={result.to} - databaseUri={comparison.databaseUri} + databaseUri={queryInfo.databaseUri} className={className} /> )}