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:
Родитель
15d65b308c
Коммит
75fe8fb040
|
@ -66,6 +66,14 @@ export class CompareInterfaceManager extends DisposableObject {
|
||||||
selectedResultSetName
|
selectedResultSetName
|
||||||
);
|
);
|
||||||
if (currentResultSetName) {
|
if (currentResultSetName) {
|
||||||
|
let rows: QueryCompareResult | undefined;
|
||||||
|
let message: string | undefined;
|
||||||
|
try {
|
||||||
|
rows = this.compareResults(fromResultSet, toResultSet);
|
||||||
|
} catch (e) {
|
||||||
|
message = e.message;
|
||||||
|
}
|
||||||
|
|
||||||
await this.postMessage({
|
await this.postMessage({
|
||||||
t: 'setComparisons',
|
t: 'setComparisons',
|
||||||
stats: {
|
stats: {
|
||||||
|
@ -81,7 +89,7 @@ export class CompareInterfaceManager extends DisposableObject {
|
||||||
},
|
},
|
||||||
toQuery: {
|
toQuery: {
|
||||||
name: to.options.label
|
name: to.options.label
|
||||||
? to.interpolate(from.getLabel())
|
? to.interpolate(to.getLabel())
|
||||||
: to.queryName,
|
: to.queryName,
|
||||||
status: to.statusString,
|
status: to.statusString,
|
||||||
time: to.time,
|
time: to.time,
|
||||||
|
@ -90,7 +98,8 @@ export class CompareInterfaceManager extends DisposableObject {
|
||||||
columns: fromResultSet.schema.columns,
|
columns: fromResultSet.schema.columns,
|
||||||
commonResultSetNames,
|
commonResultSetNames,
|
||||||
currentResultSetName: currentResultSetName,
|
currentResultSetName: currentResultSetName,
|
||||||
rows: this.compareResults(fromResultSet, toResultSet),
|
rows,
|
||||||
|
message,
|
||||||
datebaseUri: to.database.databaseUri,
|
datebaseUri: to.database.databaseUri,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,35 +2,33 @@ import * as React from 'react';
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import * as Rdom from 'react-dom';
|
import * as Rdom from 'react-dom';
|
||||||
|
|
||||||
import RawTableHeader from '../../view/RawTableHeader';
|
|
||||||
import {
|
import {
|
||||||
ToCompareViewMessage,
|
ToCompareViewMessage,
|
||||||
SetComparisonsMessage,
|
SetComparisonsMessage,
|
||||||
} from '../../interface-types';
|
} from '../../interface-types';
|
||||||
import CompareSelector from './CompareSelector';
|
import CompareSelector from './CompareSelector';
|
||||||
import { vscode } from '../../view/vscode-api';
|
import { vscode } from '../../view/vscode-api';
|
||||||
import RawTableRow from '../../view/RawTableRow';
|
import CompareTable from './CompareTable';
|
||||||
import { ResultRow } from '../../adapt';
|
|
||||||
import { className } from '../../view/result-table-utils';
|
|
||||||
|
|
||||||
const emptyComparison: SetComparisonsMessage = {
|
const emptyComparison: SetComparisonsMessage = {
|
||||||
t: 'setComparisons',
|
t: 'setComparisons',
|
||||||
stats: {},
|
stats: {},
|
||||||
rows: {
|
rows: undefined,
|
||||||
from: [],
|
|
||||||
to: [],
|
|
||||||
},
|
|
||||||
columns: [],
|
columns: [],
|
||||||
commonResultSetNames: [],
|
commonResultSetNames: [],
|
||||||
currentResultSetName: '',
|
currentResultSetName: '',
|
||||||
datebaseUri: '',
|
datebaseUri: '',
|
||||||
|
message: 'Empty comparison'
|
||||||
};
|
};
|
||||||
|
|
||||||
export function Compare(props: {}): JSX.Element {
|
export function Compare(_: {}): JSX.Element {
|
||||||
const [comparison, setComparison] = useState<SetComparisonsMessage>(
|
const [comparison, setComparison] = useState<SetComparisonsMessage>(
|
||||||
emptyComparison
|
emptyComparison
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const message = comparison.message || 'Empty comparison';
|
||||||
|
const hasRows = comparison.rows && (comparison.rows.to.length || comparison.rows.from.length);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
window.addEventListener('message', (evt: MessageEvent) => {
|
window.addEventListener('message', (evt: MessageEvent) => {
|
||||||
const msg: ToCompareViewMessage = evt.data;
|
const msg: ToCompareViewMessage = evt.data;
|
||||||
|
@ -48,7 +46,9 @@ export function Compare(props: {}): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="vscode-codeql__compare-header">
|
<div className="vscode-codeql__compare-header">
|
||||||
<div>Table to compare:</div>
|
<div className="vscode-codeql__compare-header-item">
|
||||||
|
Table to compare:
|
||||||
|
</div>
|
||||||
<CompareSelector
|
<CompareSelector
|
||||||
availableResultSets={comparison.commonResultSetNames}
|
availableResultSets={comparison.commonResultSetNames}
|
||||||
currentResultSetName={comparison.currentResultSetName}
|
currentResultSetName={comparison.currentResultSetName}
|
||||||
|
@ -57,60 +57,11 @@ export function Compare(props: {}): JSX.Element {
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<table className="vscode-codeql__compare-body">
|
{hasRows ? (
|
||||||
<thead>
|
<CompareTable comparison={comparison}></CompareTable>
|
||||||
<tr>
|
) : (
|
||||||
<td>
|
<div className="vscode-codeql__compare-message">{message}</div>
|
||||||
<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>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} 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(
|
Rdom.render(
|
||||||
<Compare />,
|
<Compare />,
|
||||||
document.getElementById('root'),
|
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 columns: readonly ColumnSchema[];
|
||||||
readonly commonResultSetNames: string[];
|
readonly commonResultSetNames: string[];
|
||||||
readonly currentResultSetName: string;
|
readonly currentResultSetName: string;
|
||||||
readonly rows: QueryCompareResult;
|
readonly rows: QueryCompareResult | undefined;
|
||||||
|
readonly message: string | undefined;
|
||||||
readonly datebaseUri: string;
|
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.
|
* 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);
|
languages.setLanguageConfiguration('dbscheme', langConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
const onEnterRules: string[] = [
|
const onEnterRules: OnEnterRule[] = [
|
||||||
// {
|
{
|
||||||
// // e.g. /** | */
|
// e.g. /** | */
|
||||||
// beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
|
beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
|
||||||
// afterText: /^\s*\*\/$/,
|
afterText: /^\s*\*\/$/,
|
||||||
// action: { indentAction: IndentAction.IndentOutdent, appendText: ' * ' }
|
action: { indentAction: IndentAction.IndentOutdent, appendText: ' * ' },
|
||||||
// }, {
|
},
|
||||||
// // e.g. /** ...|
|
{
|
||||||
// beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
|
// e.g. /** ...|
|
||||||
// action: { indentAction: IndentAction.None, appendText: ' * ' }
|
beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
|
||||||
// }, {
|
action: { indentAction: IndentAction.None, appendText: ' * ' },
|
||||||
// // e.g. * ...|
|
},
|
||||||
// beforeText: /^(\t|[ ])*[ ]\*([ ]([^\*]|\*(?!\/))*)?$/,
|
{
|
||||||
// oneLineAboveText: /^(\s*(\/\*\*|\*)).*/,
|
// e.g. * ...|
|
||||||
// action: { indentAction: IndentAction.None, appendText: '* ' }
|
beforeText: /^(\t|[ ])*[ ]\*([ ]([^\*]|\*(?!\/))*)?$/,
|
||||||
// }, {
|
// oneLineAboveText: /^(\s*(\/\*\*|\*)).*/,
|
||||||
// // e.g. */|
|
action: { indentAction: IndentAction.None, appendText: '* ' },
|
||||||
// beforeText: /^(\t|[ ])*[ ]\*\/\s*$/,
|
},
|
||||||
// action: { indentAction: IndentAction.None, removeText: 1 }
|
{
|
||||||
// },
|
// e.g. */|
|
||||||
// {
|
beforeText: /^(\t|[ ])*[ ]\*\/\s*$/,
|
||||||
// // e.g. *-----*/|
|
action: { indentAction: IndentAction.None, removeText: 1 },
|
||||||
// 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 {
|
export class QueryHistoryManager {
|
||||||
treeDataProvider: HistoryTreeDataProvider;
|
treeDataProvider: HistoryTreeDataProvider;
|
||||||
ctx: ExtensionContext;
|
|
||||||
treeView: vscode.TreeView<CompletedQuery>;
|
treeView: vscode.TreeView<CompletedQuery>;
|
||||||
lastItemClick: { time: Date; item: CompletedQuery } | undefined;
|
lastItemClick: { time: Date; item: CompletedQuery } | undefined;
|
||||||
|
|
||||||
|
@ -304,7 +303,6 @@ export class QueryHistoryManager {
|
||||||
private selectedCallback: (item: CompletedQuery) => Promise<void>,
|
private selectedCallback: (item: CompletedQuery) => Promise<void>,
|
||||||
private doCompareCallback: (from: CompletedQuery, to: CompletedQuery) => Promise<void>,
|
private doCompareCallback: (from: CompletedQuery, to: CompletedQuery) => Promise<void>,
|
||||||
) {
|
) {
|
||||||
this.ctx = ctx;
|
|
||||||
const treeDataProvider = this.treeDataProvider = new HistoryTreeDataProvider(ctx);
|
const treeDataProvider = this.treeDataProvider = new HistoryTreeDataProvider(ctx);
|
||||||
this.treeView = Window.createTreeView('codeQLQueryHistory', { treeDataProvider });
|
this.treeView = Window.createTreeView('codeQLQueryHistory', { treeDataProvider });
|
||||||
// Lazily update the tree view selection due to limitations of TreeView API (see
|
// Lazily update the tree view selection due to limitations of TreeView API (see
|
||||||
|
|
|
@ -72,7 +72,9 @@ export class ResultTables
|
||||||
|
|
||||||
private getResultSets(): ResultSet[] {
|
private getResultSets(): ResultSet[] {
|
||||||
const resultSets: 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) {
|
if (this.props.interpretation != undefined) {
|
||||||
resultSets.push({
|
resultSets.push({
|
||||||
|
@ -286,8 +288,6 @@ class ResultTable extends React.Component<ResultTableProps, {}> {
|
||||||
{...this.props} resultSet={resultSet} />;
|
{...this.props} resultSet={resultSet} />;
|
||||||
case 'SarifResultSet': return <PathTable
|
case 'SarifResultSet': return <PathTable
|
||||||
{...this.props} resultSet={resultSet} />;
|
{...this.props} resultSet={resultSet} />;
|
||||||
default:
|
|
||||||
throw new Error('Invalid type');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,6 +161,14 @@ td.vscode-codeql__path-index-cell {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vscode-codeql__compare-header-item {
|
||||||
|
margin: 0 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vscode-codeql__compare-message {
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.vscode-codeql__compare-body {
|
.vscode-codeql__compare-body {
|
||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче