Skip to content

Commit 75fe8fb

Browse files
committed
Display error message when can't compare queries
* The error message will be displayed instead of the empty results tables. * Also, uncomment onEnterRules. That should never have been committed. * Also, extract CompareTable to its own component.
1 parent 15d65b3 commit 75fe8fb

File tree

8 files changed

+164
-121
lines changed

8 files changed

+164
-121
lines changed

extensions/ql-vscode/src/compare/compare-interface.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ export class CompareInterfaceManager extends DisposableObject {
6666
selectedResultSetName
6767
);
6868
if (currentResultSetName) {
69+
let rows: QueryCompareResult | undefined;
70+
let message: string | undefined;
71+
try {
72+
rows = this.compareResults(fromResultSet, toResultSet);
73+
} catch (e) {
74+
message = e.message;
75+
}
76+
6977
await this.postMessage({
7078
t: 'setComparisons',
7179
stats: {
@@ -81,7 +89,7 @@ export class CompareInterfaceManager extends DisposableObject {
8189
},
8290
toQuery: {
8391
name: to.options.label
84-
? to.interpolate(from.getLabel())
92+
? to.interpolate(to.getLabel())
8593
: to.queryName,
8694
status: to.statusString,
8795
time: to.time,
@@ -90,7 +98,8 @@ export class CompareInterfaceManager extends DisposableObject {
9098
columns: fromResultSet.schema.columns,
9199
commonResultSetNames,
92100
currentResultSetName: currentResultSetName,
93-
rows: this.compareResults(fromResultSet, toResultSet),
101+
rows,
102+
message,
94103
datebaseUri: to.database.databaseUri,
95104
});
96105
}

extensions/ql-vscode/src/compare/view/Compare.tsx

Lines changed: 15 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,33 @@ import * as React from 'react';
22
import { useState, useEffect } from 'react';
33
import * as Rdom from 'react-dom';
44

5-
import RawTableHeader from '../../view/RawTableHeader';
65
import {
76
ToCompareViewMessage,
87
SetComparisonsMessage,
98
} from '../../interface-types';
109
import CompareSelector from './CompareSelector';
1110
import { vscode } from '../../view/vscode-api';
12-
import RawTableRow from '../../view/RawTableRow';
13-
import { ResultRow } from '../../adapt';
14-
import { className } from '../../view/result-table-utils';
11+
import CompareTable from './CompareTable';
1512

1613
const emptyComparison: SetComparisonsMessage = {
1714
t: 'setComparisons',
1815
stats: {},
19-
rows: {
20-
from: [],
21-
to: [],
22-
},
16+
rows: undefined,
2317
columns: [],
2418
commonResultSetNames: [],
2519
currentResultSetName: '',
2620
datebaseUri: '',
21+
message: 'Empty comparison'
2722
};
2823

29-
export function Compare(props: {}): JSX.Element {
24+
export function Compare(_: {}): JSX.Element {
3025
const [comparison, setComparison] = useState<SetComparisonsMessage>(
3126
emptyComparison
3227
);
3328

29+
const message = comparison.message || 'Empty comparison';
30+
const hasRows = comparison.rows && (comparison.rows.to.length || comparison.rows.from.length);
31+
3432
useEffect(() => {
3533
window.addEventListener('message', (evt: MessageEvent) => {
3634
const msg: ToCompareViewMessage = evt.data;
@@ -48,7 +46,9 @@ export function Compare(props: {}): JSX.Element {
4846
return (
4947
<>
5048
<div className="vscode-codeql__compare-header">
51-
<div>Table to compare:</div>
49+
<div className="vscode-codeql__compare-header-item">
50+
Table to compare:
51+
</div>
5252
<CompareSelector
5353
availableResultSets={comparison.commonResultSetNames}
5454
currentResultSetName={comparison.currentResultSetName}
@@ -57,60 +57,11 @@ export function Compare(props: {}): JSX.Element {
5757
}
5858
/>
5959
</div>
60-
<table className="vscode-codeql__compare-body">
61-
<thead>
62-
<tr>
63-
<td>
64-
<a
65-
onClick={() => openQuery('from')}
66-
className="vscode-codeql__compare-open"
67-
>
68-
{comparison.stats.fromQuery?.name}
69-
</a>
70-
</td>
71-
<td>
72-
<a
73-
onClick={() => openQuery('to')}
74-
className="vscode-codeql__compare-open"
75-
>
76-
{comparison.stats.toQuery?.name}
77-
</a>
78-
</td>
79-
</tr>
80-
<tr>
81-
<td>{comparison.stats.fromQuery?.time}</td>
82-
<td>{comparison.stats.toQuery?.time}</td>
83-
</tr>
84-
<tr>
85-
<th>{comparison.rows.from.length} rows removed</th>
86-
<th>{comparison.rows.to.length} rows added</th>
87-
</tr>
88-
</thead>
89-
<tbody>
90-
<tr>
91-
<td>
92-
<table className={className}>
93-
<RawTableHeader
94-
columns={comparison.columns}
95-
schemaName={comparison.currentResultSetName}
96-
preventSort={true}
97-
/>
98-
{createRows(comparison.rows.from, comparison.datebaseUri)}
99-
</table>
100-
</td>
101-
<td>
102-
<table className={className}>
103-
<RawTableHeader
104-
columns={comparison.columns}
105-
schemaName={comparison.currentResultSetName}
106-
preventSort={true}
107-
/>
108-
{createRows(comparison.rows.to, comparison.datebaseUri)}
109-
</table>
110-
</td>
111-
</tr>
112-
</tbody>
113-
</table>
60+
{hasRows ? (
61+
<CompareTable comparison={comparison}></CompareTable>
62+
) : (
63+
<div className="vscode-codeql__compare-message">{message}</div>
64+
)}
11465
</>
11566
);
11667
} catch (err) {
@@ -119,28 +70,6 @@ export function Compare(props: {}): JSX.Element {
11970
}
12071
}
12172

122-
async function openQuery(kind: 'from' | 'to') {
123-
vscode.postMessage({
124-
t: 'openQuery',
125-
kind,
126-
});
127-
}
128-
129-
function createRows(rows: ResultRow[], databaseUri: string) {
130-
return (
131-
<tbody>
132-
{rows.map((row, rowIndex) => (
133-
<RawTableRow
134-
key={rowIndex}
135-
rowIndex={rowIndex}
136-
row={row}
137-
databaseUri={databaseUri}
138-
/>
139-
))}
140-
</tbody>
141-
);
142-
}
143-
14473
Rdom.render(
14574
<Compare />,
14675
document.getElementById('root'),
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import * as React from 'react';
2+
3+
import { SetComparisonsMessage } from '../../interface-types';
4+
import RawTableHeader from '../../view/RawTableHeader';
5+
import { className } from '../../view/result-table-utils';
6+
import { ResultRow } from '../../adapt';
7+
import RawTableRow from '../../view/RawTableRow';
8+
import { vscode } from '../../view/vscode-api';
9+
10+
interface Props {
11+
comparison: SetComparisonsMessage;
12+
}
13+
14+
export default function CompareTable(props: Props) {
15+
const comparison = props.comparison;
16+
const rows = props.comparison.rows!;
17+
18+
async function openQuery(kind: 'from' | 'to') {
19+
vscode.postMessage({
20+
t: 'openQuery',
21+
kind,
22+
});
23+
}
24+
25+
function createRows(rows: ResultRow[], databaseUri: string) {
26+
return (
27+
<tbody>
28+
{rows.map((row, rowIndex) => (
29+
<RawTableRow
30+
key={rowIndex}
31+
rowIndex={rowIndex}
32+
row={row}
33+
databaseUri={databaseUri}
34+
/>
35+
))}
36+
</tbody>
37+
);
38+
}
39+
40+
return (
41+
<table className='vscode-codeql__compare-body'>
42+
<thead>
43+
<tr>
44+
<td>
45+
<a
46+
onClick={() => openQuery('from')}
47+
className='vscode-codeql__compare-open'
48+
>
49+
{comparison.stats.fromQuery?.name}
50+
</a>
51+
</td>
52+
<td>
53+
<a
54+
onClick={() => openQuery('to')}
55+
className='vscode-codeql__compare-open'
56+
>
57+
{comparison.stats.toQuery?.name}
58+
</a>
59+
</td>
60+
</tr>
61+
<tr>
62+
<td>{comparison.stats.fromQuery?.time}</td>
63+
<td>{comparison.stats.toQuery?.time}</td>
64+
</tr>
65+
<tr>
66+
<th>{rows.from.length} rows removed</th>
67+
<th>{rows.to.length} rows added</th>
68+
</tr>
69+
</thead>
70+
<tbody>
71+
<tr>
72+
<td>
73+
<table className={className}>
74+
<RawTableHeader
75+
columns={comparison.columns}
76+
schemaName={comparison.currentResultSetName}
77+
preventSort={true}
78+
/>
79+
{createRows(rows.from, comparison.datebaseUri)}
80+
</table>
81+
</td>
82+
<td>
83+
<table className={className}>
84+
<RawTableHeader
85+
columns={comparison.columns}
86+
schemaName={comparison.currentResultSetName}
87+
preventSort={true}
88+
/>
89+
{createRows(rows.to, comparison.datebaseUri)}
90+
</table>
91+
</td>
92+
</tr>
93+
</tbody>
94+
</table>
95+
);
96+
}

extensions/ql-vscode/src/interface-types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,8 @@ export interface SetComparisonsMessage {
234234
readonly columns: readonly ColumnSchema[];
235235
readonly commonResultSetNames: string[];
236236
readonly currentResultSetName: string;
237-
readonly rows: QueryCompareResult;
237+
readonly rows: QueryCompareResult | undefined;
238+
readonly message: string | undefined;
238239
readonly datebaseUri: string;
239240
}
240241

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { languages } from 'vscode';
2-
1+
import { languages, IndentAction, OnEnterRule } from 'vscode';
32

43
/**
54
* OnEnterRules are available in language-configurations, but you cannot specify them in the language-configuration.json.
@@ -27,29 +26,32 @@ export function install() {
2726
languages.setLanguageConfiguration('dbscheme', langConfig);
2827
}
2928

30-
const onEnterRules: string[] = [
31-
// {
32-
// // e.g. /** | */
33-
// beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
34-
// afterText: /^\s*\*\/$/,
35-
// action: { indentAction: IndentAction.IndentOutdent, appendText: ' * ' }
36-
// }, {
37-
// // e.g. /** ...|
38-
// beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
39-
// action: { indentAction: IndentAction.None, appendText: ' * ' }
40-
// }, {
41-
// // e.g. * ...|
42-
// beforeText: /^(\t|[ ])*[ ]\*([ ]([^\*]|\*(?!\/))*)?$/,
43-
// oneLineAboveText: /^(\s*(\/\*\*|\*)).*/,
44-
// action: { indentAction: IndentAction.None, appendText: '* ' }
45-
// }, {
46-
// // e.g. */|
47-
// beforeText: /^(\t|[ ])*[ ]\*\/\s*$/,
48-
// action: { indentAction: IndentAction.None, removeText: 1 }
49-
// },
50-
// {
51-
// // e.g. *-----*/|
52-
// beforeText: /^(\t|[ ])*[ ]\*[^/]*\*\/\s*$/,
53-
// action: { indentAction: IndentAction.None, removeText: 1 }
54-
// }
29+
const onEnterRules: OnEnterRule[] = [
30+
{
31+
// e.g. /** | */
32+
beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
33+
afterText: /^\s*\*\/$/,
34+
action: { indentAction: IndentAction.IndentOutdent, appendText: ' * ' },
35+
},
36+
{
37+
// e.g. /** ...|
38+
beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
39+
action: { indentAction: IndentAction.None, appendText: ' * ' },
40+
},
41+
{
42+
// e.g. * ...|
43+
beforeText: /^(\t|[ ])*[ ]\*([ ]([^\*]|\*(?!\/))*)?$/,
44+
// oneLineAboveText: /^(\s*(\/\*\*|\*)).*/,
45+
action: { indentAction: IndentAction.None, appendText: '* ' },
46+
},
47+
{
48+
// e.g. */|
49+
beforeText: /^(\t|[ ])*[ ]\*\/\s*$/,
50+
action: { indentAction: IndentAction.None, removeText: 1 },
51+
},
52+
{
53+
// e.g. *-----*/|
54+
beforeText: /^(\t|[ ])*[ ]\*[^/]*\*\/\s*$/,
55+
action: { indentAction: IndentAction.None, removeText: 1 },
56+
},
5557
];

extensions/ql-vscode/src/query-history.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,6 @@ const DOUBLE_CLICK_TIME = 500;
159159

160160
export class QueryHistoryManager {
161161
treeDataProvider: HistoryTreeDataProvider;
162-
ctx: ExtensionContext;
163162
treeView: vscode.TreeView<CompletedQuery>;
164163
lastItemClick: { time: Date; item: CompletedQuery } | undefined;
165164

@@ -304,7 +303,6 @@ export class QueryHistoryManager {
304303
private selectedCallback: (item: CompletedQuery) => Promise<void>,
305304
private doCompareCallback: (from: CompletedQuery, to: CompletedQuery) => Promise<void>,
306305
) {
307-
this.ctx = ctx;
308306
const treeDataProvider = this.treeDataProvider = new HistoryTreeDataProvider(ctx);
309307
this.treeView = Window.createTreeView('codeQLQueryHistory', { treeDataProvider });
310308
// Lazily update the tree view selection due to limitations of TreeView API (see

extensions/ql-vscode/src/view/result-tables.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ export class ResultTables
7272

7373
private getResultSets(): ResultSet[] {
7474
const resultSets: ResultSet[] =
75-
this.props.rawResultSets.map(rs => ({ t: 'RawResultSet', ...rs }));
75+
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
76+
// @ts-ignore 2783
77+
this.props.rawResultSets.map((rs) => ({ t: 'RawResultSet', ...rs }));
7678

7779
if (this.props.interpretation != undefined) {
7880
resultSets.push({
@@ -286,8 +288,6 @@ class ResultTable extends React.Component<ResultTableProps, {}> {
286288
{...this.props} resultSet={resultSet} />;
287289
case 'SarifResultSet': return <PathTable
288290
{...this.props} resultSet={resultSet} />;
289-
default:
290-
throw new Error('Invalid type');
291291
}
292292
}
293293
}

0 commit comments

Comments
 (0)