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.
This commit is contained in:
Andrew Eisenberg 2020-06-16 11:06:42 -07:00
Родитель 15d65b308c
Коммит 75fe8fb040
8 изменённых файлов: 164 добавлений и 121 удалений

Просмотреть файл

@ -66,6 +66,14 @@ export class CompareInterfaceManager extends DisposableObject {
selectedResultSetName
);
if (currentResultSetName) {
let rows: QueryCompareResult | undefined;
let message: string | undefined;
try {
rows = this.compareResults(fromResultSet, toResultSet);
} catch (e) {
message = e.message;
}
await this.postMessage({
t: 'setComparisons',
stats: {
@ -81,7 +89,7 @@ export class CompareInterfaceManager extends DisposableObject {
},
toQuery: {
name: to.options.label
? to.interpolate(from.getLabel())
? to.interpolate(to.getLabel())
: to.queryName,
status: to.statusString,
time: to.time,
@ -90,7 +98,8 @@ export class CompareInterfaceManager extends DisposableObject {
columns: fromResultSet.schema.columns,
commonResultSetNames,
currentResultSetName: currentResultSetName,
rows: this.compareResults(fromResultSet, toResultSet),
rows,
message,
datebaseUri: to.database.databaseUri,
});
}

Просмотреть файл

@ -2,35 +2,33 @@ import * as React from 'react';
import { useState, useEffect } from 'react';
import * as Rdom from 'react-dom';
import RawTableHeader from '../../view/RawTableHeader';
import {
ToCompareViewMessage,
SetComparisonsMessage,
} from '../../interface-types';
import CompareSelector from './CompareSelector';
import { vscode } from '../../view/vscode-api';
import RawTableRow from '../../view/RawTableRow';
import { ResultRow } from '../../adapt';
import { className } from '../../view/result-table-utils';
import CompareTable from './CompareTable';
const emptyComparison: SetComparisonsMessage = {
t: 'setComparisons',
stats: {},
rows: {
from: [],
to: [],
},
rows: undefined,
columns: [],
commonResultSetNames: [],
currentResultSetName: '',
datebaseUri: '',
message: 'Empty comparison'
};
export function Compare(props: {}): JSX.Element {
export function Compare(_: {}): JSX.Element {
const [comparison, setComparison] = useState<SetComparisonsMessage>(
emptyComparison
);
const message = comparison.message || 'Empty comparison';
const hasRows = comparison.rows && (comparison.rows.to.length || comparison.rows.from.length);
useEffect(() => {
window.addEventListener('message', (evt: MessageEvent) => {
const msg: ToCompareViewMessage = evt.data;
@ -48,7 +46,9 @@ export function Compare(props: {}): JSX.Element {
return (
<>
<div className="vscode-codeql__compare-header">
<div>Table to compare:</div>
<div className="vscode-codeql__compare-header-item">
Table to compare:
</div>
<CompareSelector
availableResultSets={comparison.commonResultSetNames}
currentResultSetName={comparison.currentResultSetName}
@ -57,60 +57,11 @@ export function Compare(props: {}): JSX.Element {
}
/>
</div>
<table className="vscode-codeql__compare-body">
<thead>
<tr>
<td>
<a
onClick={() => openQuery('from')}
className="vscode-codeql__compare-open"
>
{comparison.stats.fromQuery?.name}
</a>
</td>
<td>
<a
onClick={() => openQuery('to')}
className="vscode-codeql__compare-open"
>
{comparison.stats.toQuery?.name}
</a>
</td>
</tr>
<tr>
<td>{comparison.stats.fromQuery?.time}</td>
<td>{comparison.stats.toQuery?.time}</td>
</tr>
<tr>
<th>{comparison.rows.from.length} rows removed</th>
<th>{comparison.rows.to.length} rows added</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<table className={className}>
<RawTableHeader
columns={comparison.columns}
schemaName={comparison.currentResultSetName}
preventSort={true}
/>
{createRows(comparison.rows.from, comparison.datebaseUri)}
</table>
</td>
<td>
<table className={className}>
<RawTableHeader
columns={comparison.columns}
schemaName={comparison.currentResultSetName}
preventSort={true}
/>
{createRows(comparison.rows.to, comparison.datebaseUri)}
</table>
</td>
</tr>
</tbody>
</table>
{hasRows ? (
<CompareTable comparison={comparison}></CompareTable>
) : (
<div className="vscode-codeql__compare-message">{message}</div>
)}
</>
);
} catch (err) {
@ -119,28 +70,6 @@ export function Compare(props: {}): JSX.Element {
}
}
async function openQuery(kind: 'from' | 'to') {
vscode.postMessage({
t: 'openQuery',
kind,
});
}
function createRows(rows: ResultRow[], databaseUri: string) {
return (
<tbody>
{rows.map((row, rowIndex) => (
<RawTableRow
key={rowIndex}
rowIndex={rowIndex}
row={row}
databaseUri={databaseUri}
/>
))}
</tbody>
);
}
Rdom.render(
<Compare />,
document.getElementById('root'),

Просмотреть файл

@ -0,0 +1,96 @@
import * as React from 'react';
import { SetComparisonsMessage } from '../../interface-types';
import RawTableHeader from '../../view/RawTableHeader';
import { className } from '../../view/result-table-utils';
import { ResultRow } from '../../adapt';
import RawTableRow from '../../view/RawTableRow';
import { vscode } from '../../view/vscode-api';
interface Props {
comparison: SetComparisonsMessage;
}
export default function CompareTable(props: Props) {
const comparison = props.comparison;
const rows = props.comparison.rows!;
async function openQuery(kind: 'from' | 'to') {
vscode.postMessage({
t: 'openQuery',
kind,
});
}
function createRows(rows: ResultRow[], databaseUri: string) {
return (
<tbody>
{rows.map((row, rowIndex) => (
<RawTableRow
key={rowIndex}
rowIndex={rowIndex}
row={row}
databaseUri={databaseUri}
/>
))}
</tbody>
);
}
return (
<table className='vscode-codeql__compare-body'>
<thead>
<tr>
<td>
<a
onClick={() => openQuery('from')}
className='vscode-codeql__compare-open'
>
{comparison.stats.fromQuery?.name}
</a>
</td>
<td>
<a
onClick={() => openQuery('to')}
className='vscode-codeql__compare-open'
>
{comparison.stats.toQuery?.name}
</a>
</td>
</tr>
<tr>
<td>{comparison.stats.fromQuery?.time}</td>
<td>{comparison.stats.toQuery?.time}</td>
</tr>
<tr>
<th>{rows.from.length} rows removed</th>
<th>{rows.to.length} rows added</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<table className={className}>
<RawTableHeader
columns={comparison.columns}
schemaName={comparison.currentResultSetName}
preventSort={true}
/>
{createRows(rows.from, comparison.datebaseUri)}
</table>
</td>
<td>
<table className={className}>
<RawTableHeader
columns={comparison.columns}
schemaName={comparison.currentResultSetName}
preventSort={true}
/>
{createRows(rows.to, comparison.datebaseUri)}
</table>
</td>
</tr>
</tbody>
</table>
);
}

Просмотреть файл

@ -234,7 +234,8 @@ export interface SetComparisonsMessage {
readonly columns: readonly ColumnSchema[];
readonly commonResultSetNames: string[];
readonly currentResultSetName: string;
readonly rows: QueryCompareResult;
readonly rows: QueryCompareResult | undefined;
readonly message: string | undefined;
readonly datebaseUri: string;
}

Просмотреть файл

@ -1,5 +1,4 @@
import { languages } from 'vscode';
import { languages, IndentAction, OnEnterRule } from 'vscode';
/**
* OnEnterRules are available in language-configurations, but you cannot specify them in the language-configuration.json.
@ -27,29 +26,32 @@ export function install() {
languages.setLanguageConfiguration('dbscheme', langConfig);
}
const onEnterRules: string[] = [
// {
// // e.g. /** | */
// beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
// afterText: /^\s*\*\/$/,
// action: { indentAction: IndentAction.IndentOutdent, appendText: ' * ' }
// }, {
// // e.g. /** ...|
// beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
// action: { indentAction: IndentAction.None, appendText: ' * ' }
// }, {
// // e.g. * ...|
// beforeText: /^(\t|[ ])*[ ]\*([ ]([^\*]|\*(?!\/))*)?$/,
// oneLineAboveText: /^(\s*(\/\*\*|\*)).*/,
// action: { indentAction: IndentAction.None, appendText: '* ' }
// }, {
// // e.g. */|
// beforeText: /^(\t|[ ])*[ ]\*\/\s*$/,
// action: { indentAction: IndentAction.None, removeText: 1 }
// },
// {
// // e.g. *-----*/|
// beforeText: /^(\t|[ ])*[ ]\*[^/]*\*\/\s*$/,
// action: { indentAction: IndentAction.None, removeText: 1 }
// }
const onEnterRules: OnEnterRule[] = [
{
// e.g. /** | */
beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
afterText: /^\s*\*\/$/,
action: { indentAction: IndentAction.IndentOutdent, appendText: ' * ' },
},
{
// e.g. /** ...|
beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
action: { indentAction: IndentAction.None, appendText: ' * ' },
},
{
// e.g. * ...|
beforeText: /^(\t|[ ])*[ ]\*([ ]([^\*]|\*(?!\/))*)?$/,
// oneLineAboveText: /^(\s*(\/\*\*|\*)).*/,
action: { indentAction: IndentAction.None, appendText: '* ' },
},
{
// e.g. */|
beforeText: /^(\t|[ ])*[ ]\*\/\s*$/,
action: { indentAction: IndentAction.None, removeText: 1 },
},
{
// e.g. *-----*/|
beforeText: /^(\t|[ ])*[ ]\*[^/]*\*\/\s*$/,
action: { indentAction: IndentAction.None, removeText: 1 },
},
];

Просмотреть файл

@ -159,7 +159,6 @@ const DOUBLE_CLICK_TIME = 500;
export class QueryHistoryManager {
treeDataProvider: HistoryTreeDataProvider;
ctx: ExtensionContext;
treeView: vscode.TreeView<CompletedQuery>;
lastItemClick: { time: Date; item: CompletedQuery } | undefined;
@ -304,7 +303,6 @@ export class QueryHistoryManager {
private selectedCallback: (item: CompletedQuery) => Promise<void>,
private doCompareCallback: (from: CompletedQuery, to: CompletedQuery) => Promise<void>,
) {
this.ctx = ctx;
const treeDataProvider = this.treeDataProvider = new HistoryTreeDataProvider(ctx);
this.treeView = Window.createTreeView('codeQLQueryHistory', { treeDataProvider });
// Lazily update the tree view selection due to limitations of TreeView API (see

Просмотреть файл

@ -72,7 +72,9 @@ export class ResultTables
private getResultSets(): ResultSet[] {
const resultSets: ResultSet[] =
this.props.rawResultSets.map(rs => ({ t: 'RawResultSet', ...rs }));
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore 2783
this.props.rawResultSets.map((rs) => ({ t: 'RawResultSet', ...rs }));
if (this.props.interpretation != undefined) {
resultSets.push({
@ -286,8 +288,6 @@ class ResultTable extends React.Component<ResultTableProps, {}> {
{...this.props} resultSet={resultSet} />;
case 'SarifResultSet': return <PathTable
{...this.props} resultSet={resultSet} />;
default:
throw new Error('Invalid type');
}
}
}

Просмотреть файл

@ -161,6 +161,14 @@ td.vscode-codeql__path-index-cell {
display: flex;
}
.vscode-codeql__compare-header-item {
margin: 0 1.5rem;
}
.vscode-codeql__compare-message {
padding: 1.5rem;
}
.vscode-codeql__compare-body {
margin: 20px 0;
width: 100%;