Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions extensions/ql-vscode/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- Respect the `codeQL.runningQueries.numberOfThreads` setting when creating SARIF files during result interpretation. [#771](https://github.com/github/vscode-codeql/pull/771)
- Allow using raw LGTM project slugs for fetching LGTM databases. [#769](https://github.com/github/vscode-codeql/pull/769)
- Better error messages when BQRS interpretation fails to produce SARIF. [#770](https://github.com/github/vscode-codeql/pull/770)
- Implement sorting of the query history view by name, date, and results count. [#777](https://github.com/github/vscode-codeql/pull/777)

## 1.4.3 - 22 February 2021

Expand Down
15 changes: 15 additions & 0 deletions extensions/ql-vscode/media/dark/sort-num.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions extensions/ql-vscode/media/light/sort-num.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
55 changes: 53 additions & 2 deletions extensions/ql-vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,8 @@
},
"codeQL.queryHistory.format": {
"type": "string",
"default": "[%t] %q on %d - %s",
"description": "Default string for how to label query history items. %t is the time of the query, %q is the query name, %d is the database name, and %s is a status string."
"default": "%q on %d - %s, %r result count [%t]",
"description": "Default string for how to label query history items. %t is the time of the query, %q is the query name, %d is the database name, %r is the number of results, and %s is a status string."
},
"codeQL.runningTests.numberOfThreads": {
"scope": "window",
Expand Down Expand Up @@ -357,6 +357,30 @@
"dark": "media/dark/trash.svg"
}
},
{
"command": "codeQLQueryHistory.sortByName",
"title": "Sort by Name",
"icon": {
"light": "media/light/sort-alpha.svg",
"dark": "media/dark/sort-alpha.svg"
}
},
{
"command": "codeQLQueryHistory.sortByDate",
"title": "Sort by Query Date",
"icon": {
"light": "media/light/sort-date.svg",
"dark": "media/dark/sort-date.svg"
}
},
{
"command": "codeQLQueryHistory.sortByCount",
"title": "Sort by Results Count",
"icon": {
"light": "media/light/sort-num.svg",
"dark": "media/dark/sort-num.svg"
}
},
{
"command": "codeQLQueryHistory.showQueryLog",
"title": "Show Query Log"
Expand Down Expand Up @@ -461,6 +485,21 @@
"when": "view == codeQLQueryHistory",
"group": "navigation"
},
{
"command": "codeQLQueryHistory.sortByName",
"when": "view == codeQLQueryHistory",
"group": "navigation"
},
{
"command": "codeQLQueryHistory.sortByDate",
"when": "view == codeQLQueryHistory",
"group": "navigation"
},
{
"command": "codeQLQueryHistory.sortByCount",
"when": "view == codeQLQueryHistory",
"group": "navigation"
},
{
"command": "codeQLAstViewer.clear",
"when": "view == codeQLAstViewer",
Expand Down Expand Up @@ -666,6 +705,18 @@
"command": "codeQLQueryHistory.compareWith",
"when": "false"
},
{
"command": "codeQLQueryHistory.sortByName",
"when": "false"
},
{
"command": "codeQLQueryHistory.sortByDate",
"when": "false"
},
{
"command": "codeQLQueryHistory.sortByCount",
"when": "false"
},
{
"command": "codeQLAstViewer.gotoCode",
"when": "false"
Expand Down
9 changes: 4 additions & 5 deletions extensions/ql-vscode/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -472,12 +472,11 @@ async function activateWithInstalledDistribution(
progress,
token
);
const item = qhm.addQuery(info);
const item = qhm.buildCompletedQuery(info);
await showResultsForCompletedQuery(item, WebviewReveal.NotForced);
// The call to showResults potentially creates SARIF file;
// Update the tree item context value to allow viewing that
// SARIF file from context menu.
await qhm.refreshTreeView(item);
// Note we must update the query history view after showing results as the
// display and sorting might depend on the number of results
await qhm.addCompletedQuery(item);
}
}

Expand Down
1 change: 1 addition & 0 deletions extensions/ql-vscode/src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ export class InterfaceManager extends DisposableObject {
}
);
const resultSet = transformBqrsResultSet(schema, chunk);
results.setResultCount(interpretationPage?.numTotalResults || resultSet.schema.rows);
const parsedResultSets: ParsedResultSets = {
pageNumber: 0,
pageSize,
Expand Down
98 changes: 93 additions & 5 deletions extensions/ql-vscode/src/query-history.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as path from 'path';
import * as vscode from 'vscode';
import { window as Window } from 'vscode';
import { window as Window, env } from 'vscode';
import { CompletedQuery } from './query-results';
import { QueryHistoryConfig } from './config';
import { QueryWithResults } from './run-queries';
Expand All @@ -15,6 +15,7 @@ import { URLSearchParams } from 'url';
import { QueryServerClient } from './queryserver-client';
import { DisposableObject } from './pure/disposable-object';
import { commandRunner } from './commandRunner';
import { assertNever } from './pure/helpers-pure';

/**
* query-history.ts
Expand Down Expand Up @@ -58,10 +59,21 @@ const SHOW_QUERY_TEXT_QUICK_EVAL_MSG = `\
*/
const FAILED_QUERY_HISTORY_ITEM_ICON = 'media/red-x.svg';

enum SortOrder {
NameAsc = 'NameAsc',
NameDesc = 'NameDesc',
DateAsc = 'DateAsc',
DateDesc = 'DateDesc',
CountAsc = 'CountAsc',
CountDesc = 'CountDesc',
}

/**
* Tree data provider for the query history view.
*/
export class HistoryTreeDataProvider extends DisposableObject {
private _sortOrder = SortOrder.DateAsc;

private _onDidChangeTreeData = super.push(new vscode.EventEmitter<CompletedQuery | undefined>());

readonly onDidChangeTreeData: vscode.Event<CompletedQuery | undefined> = this
Expand Down Expand Up @@ -111,7 +123,24 @@ export class HistoryTreeDataProvider extends DisposableObject {
getChildren(
element?: CompletedQuery
): vscode.ProviderResult<CompletedQuery[]> {
return element ? [] : this.history;
return element ? [] : this.history.sort((q1, q2) => {
switch (this.sortOrder) {
case SortOrder.NameAsc:
return q1.toString().localeCompare(q2.toString(), env.language);
case SortOrder.NameDesc:
return q2.toString().localeCompare(q1.toString(), env.language);
case SortOrder.DateAsc:
return q1.date.getTime() - q2.date.getTime();
case SortOrder.DateDesc:
return q2.date.getTime() - q1.date.getTime();
case SortOrder.CountAsc:
return q1.resultCount - q2.resultCount;
case SortOrder.CountDesc:
return q2.resultCount - q1.resultCount;
default:
assertNever(this.sortOrder);
}
});
}

getParent(_element: CompletedQuery): vscode.ProviderResult<CompletedQuery> {
Expand Down Expand Up @@ -157,6 +186,15 @@ export class HistoryTreeDataProvider extends DisposableObject {
find(queryId: number): CompletedQuery | undefined {
return this.allHistory.find((query) => query.query.queryID === queryId);
}

public get sortOrder() {
return this._sortOrder;
}

public set sortOrder(newSortOrder: SortOrder) {
this._sortOrder = newSortOrder;
this._onDidChangeTreeData.fire();
}
}

/**
Expand Down Expand Up @@ -224,6 +262,24 @@ export class QueryHistoryManager extends DisposableObject {
this.handleRemoveHistoryItem.bind(this)
)
);
this.push(
commandRunner(
'codeQLQueryHistory.sortByName',
this.handleSortByName.bind(this)
)
);
this.push(
commandRunner(
'codeQLQueryHistory.sortByDate',
this.handleSortByDate.bind(this)
)
);
this.push(
commandRunner(
'codeQLQueryHistory.sortByCount',
this.handleSortByCount.bind(this)
)
);
this.push(
commandRunner(
'codeQLQueryHistory.setLabel',
Expand Down Expand Up @@ -345,6 +401,30 @@ export class QueryHistoryManager extends DisposableObject {
}
}

async handleSortByName() {
if (this.treeDataProvider.sortOrder === SortOrder.NameAsc) {
this.treeDataProvider.sortOrder = SortOrder.NameDesc;
} else {
this.treeDataProvider.sortOrder = SortOrder.NameAsc;
}
}

async handleSortByDate() {
if (this.treeDataProvider.sortOrder === SortOrder.DateAsc) {
this.treeDataProvider.sortOrder = SortOrder.DateDesc;
} else {
this.treeDataProvider.sortOrder = SortOrder.DateAsc;
}
}

async handleSortByCount() {
if (this.treeDataProvider.sortOrder === SortOrder.CountAsc) {
this.treeDataProvider.sortOrder = SortOrder.CountDesc;
} else {
this.treeDataProvider.sortOrder = SortOrder.CountAsc;
}
}

async handleSetLabel(
singleItem: CompletedQuery,
multiSelect: CompletedQuery[]
Expand All @@ -362,7 +442,12 @@ export class QueryHistoryManager extends DisposableObject {
if (response !== undefined) {
// Interpret empty string response as 'go back to using default'
singleItem.options.label = response === '' ? undefined : response;
this.treeDataProvider.refresh(singleItem);
if (this.treeDataProvider.sortOrder === SortOrder.NameAsc ||
this.treeDataProvider.sortOrder === SortOrder.NameDesc) {
this.treeDataProvider.refresh();
} else {
this.treeDataProvider.refresh(singleItem);
}
}
}

Expand Down Expand Up @@ -511,11 +596,14 @@ export class QueryHistoryManager extends DisposableObject {
}
}

addQuery(info: QueryWithResults): CompletedQuery {
buildCompletedQuery(info: QueryWithResults): CompletedQuery {
const item = new CompletedQuery(info, this.queryHistoryConfigListener);
return item;
}

addCompletedQuery(item: CompletedQuery) {
this.treeDataProvider.pushQuery(item);
this.updateTreeViewSelectionIfVisible();
return item;
}

find(queryId: number): CompletedQuery | undefined {
Expand Down
13 changes: 11 additions & 2 deletions extensions/ql-vscode/src/query-results.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ import { QueryHistoryConfig } from './config';
import { QueryHistoryItemOptions } from './query-history';

export class CompletedQuery implements QueryWithResults {
readonly date: Date;
readonly time: string;
readonly query: QueryInfo;
readonly result: messages.EvaluationResult;
readonly database: DatabaseInfo;
readonly logFileLocation?: string;
options: QueryHistoryItemOptions;
resultCount: number;
dispose: () => void;

/**
Expand Down Expand Up @@ -44,8 +46,14 @@ export class CompletedQuery implements QueryWithResults {
this.options = evaluation.options;
this.dispose = evaluation.dispose;

this.time = new Date().toLocaleString(env.language);
this.date = new Date();
this.time = this.date.toLocaleString(env.language);
this.sortedResultsInfo = new Map();
this.resultCount = 0;
}

setResultCount(value: number) {
this.resultCount = value;
}

get databaseName(): string {
Expand Down Expand Up @@ -80,11 +88,12 @@ export class CompletedQuery implements QueryWithResults {
}

interpolate(template: string): string {
const { databaseName, queryName, time, statusString } = this;
const { databaseName, queryName, time, resultCount, statusString } = this;
const replacements: { [k: string]: string } = {
t: time,
q: queryName,
d: databaseName,
r: resultCount.toString(),
s: statusString,
'%': '%',
};
Expand Down