Skip to content

Commit 49cceff

Browse files
authored
Merge pull request #1235 from github/aeisenberg/history-sort
Add query history sorting for remote queries
2 parents 0117823 + bb6ebe5 commit 49cceff

File tree

3 files changed

+77
-44
lines changed

3 files changed

+77
-44
lines changed

extensions/ql-vscode/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
## [UNRELEASED]
44

55
- Fix a bug where the AST viewer was not synchronizing its selected node when the editor selection changes. [#1230](https://github.com/github/vscode-codeql/pull/1230)
6+
- Open the directory in the finder/explorer (instead of just highlighting it) when running the "Open query directory" command from the query history view. [#1235](https://github.com/github/vscode-codeql/pull/1235)
7+
- Ensure query label in the query history view changes are persisted across restarts. [#1235](https://github.com/github/vscode-codeql/pull/1235)
68

79
## 1.6.1 - 17 March 2022
810

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

+45-26
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as path from 'path';
2+
import * as fs from 'fs-extra';
23
import {
34
commands,
45
Disposable,
@@ -28,7 +29,7 @@ import { URLSearchParams } from 'url';
2829
import { QueryServerClient } from './queryserver-client';
2930
import { DisposableObject } from './pure/disposable-object';
3031
import { commandRunner } from './commandRunner';
31-
import { assertNever, ONE_HOUR_IN_MS, TWO_HOURS_IN_MS, getErrorMessage, getErrorStack } from './pure/helpers-pure';
32+
import { assertNever, ONE_HOUR_IN_MS, TWO_HOURS_IN_MS, getErrorMessage, getErrorStack } from './pure/helpers-pure';
3233
import { CompletedLocalQueryInfo, LocalQueryInfo as LocalQueryInfo, QueryHistoryInfo } from './query-results';
3334
import { DatabaseManager } from './databases';
3435
import { registerQueryHistoryScubber } from './query-history-scrubber';
@@ -183,38 +184,48 @@ export class HistoryTreeDataProvider extends DisposableObject {
183184
): ProviderResult<QueryHistoryInfo[]> {
184185
return element ? [] : this.history.sort((h1, h2) => {
185186

186-
// TODO remote queries are not implemented yet.
187-
if (h1.t !== 'local' && h2.t !== 'local') {
188-
return 0;
189-
}
190-
if (h1.t !== 'local') {
191-
return -1;
192-
}
193-
if (h2.t !== 'local') {
194-
return 1;
195-
}
187+
const h1Label = h1.label.toLowerCase();
188+
const h2Label = h2.label.toLowerCase();
196189

197-
const resultCount1 = h1.completedQuery?.resultCount ?? -1;
198-
const resultCount2 = h2.completedQuery?.resultCount ?? -1;
190+
const h1Date = h1.t === 'local'
191+
? h1.initialInfo.start.getTime()
192+
: h1.remoteQuery?.executionStartTime;
193+
194+
const h2Date = h2.t === 'local'
195+
? h2.initialInfo.start.getTime()
196+
: h2.remoteQuery?.executionStartTime;
197+
198+
// result count for remote queries is not available here.
199+
const resultCount1 = h1.t === 'local'
200+
? h1.completedQuery?.resultCount ?? -1
201+
: -1;
202+
const resultCount2 = h2.t === 'local'
203+
? h2.completedQuery?.resultCount ?? -1
204+
: -1;
199205

200206
switch (this.sortOrder) {
201207
case SortOrder.NameAsc:
202-
return h1.label.localeCompare(h2.label, env.language);
208+
return h1Label.localeCompare(h2Label, env.language);
209+
203210
case SortOrder.NameDesc:
204-
return h2.label.localeCompare(h1.label, env.language);
211+
return h2Label.localeCompare(h1Label, env.language);
212+
205213
case SortOrder.DateAsc:
206-
return h1.initialInfo.start.getTime() - h2.initialInfo.start.getTime();
214+
return h1Date - h2Date;
215+
207216
case SortOrder.DateDesc:
208-
return h2.initialInfo.start.getTime() - h1.initialInfo.start.getTime();
217+
return h2Date - h1Date;
218+
209219
case SortOrder.CountAsc:
210220
// If the result counts are equal, sort by name.
211221
return resultCount1 - resultCount2 === 0
212-
? h1.label.localeCompare(h2.label, env.language)
222+
? h1Label.localeCompare(h2Label, env.language)
213223
: resultCount1 - resultCount2;
224+
214225
case SortOrder.CountDesc:
215226
// If the result counts are equal, sort by name.
216227
return resultCount2 - resultCount1 === 0
217-
? h2.label.localeCompare(h1.label, env.language)
228+
? h2Label.localeCompare(h1Label, env.language)
218229
: resultCount2 - resultCount1;
219230
default:
220231
assertNever(this.sortOrder);
@@ -650,7 +661,7 @@ export class QueryHistoryManager extends DisposableObject {
650661
if (response !== undefined) {
651662
// Interpret empty string response as 'go back to using default'
652663
finalSingleItem.initialInfo.userSpecifiedLabel = response === '' ? undefined : response;
653-
this.treeDataProvider.refresh();
664+
await this.refreshTreeView();
654665
}
655666
}
656667

@@ -741,20 +752,28 @@ export class QueryHistoryManager extends DisposableObject {
741752
return;
742753
}
743754

744-
let p: string | undefined;
755+
let externalFilePath: string | undefined;
745756
if (finalSingleItem.t === 'local') {
746757
if (finalSingleItem.completedQuery) {
747-
p = finalSingleItem.completedQuery.query.querySaveDir;
758+
externalFilePath = path.join(finalSingleItem.completedQuery.query.querySaveDir, 'timestamp');
748759
}
749760
} else if (finalSingleItem.t === 'remote') {
750-
p = path.join(this.queryStorageDir, finalSingleItem.queryId);
761+
externalFilePath = path.join(this.queryStorageDir, finalSingleItem.queryId, 'timestamp');
751762
}
752763

753-
if (p) {
764+
if (externalFilePath) {
765+
if (!(await fs.pathExists(externalFilePath))) {
766+
// timestamp file is missing (manually deleted?) try selecting the parent folder.
767+
// It's less nice, but at least it will work.
768+
externalFilePath = path.dirname(externalFilePath);
769+
if (!(await fs.pathExists(externalFilePath))) {
770+
throw new Error(`Query directory does not exist: ${externalFilePath}`);
771+
}
772+
}
754773
try {
755-
await commands.executeCommand('revealFileInOS', Uri.file(p));
774+
await commands.executeCommand('revealFileInOS', Uri.file(externalFilePath));
756775
} catch (e) {
757-
throw new Error(`Failed to open ${p}: ${getErrorMessage(e)}`);
776+
throw new Error(`Failed to open ${externalFilePath}: ${getErrorMessage(e)}`);
758777
}
759778
}
760779
}

extensions/ql-vscode/src/vscode-tests/no-workspace/query-history.test.ts

+30-18
Original file line numberDiff line numberDiff line change
@@ -427,9 +427,11 @@ describe('query-history', () => {
427427

428428
describe('getChildren', () => {
429429
const history = [
430-
item('a', 10, 20),
431-
item('b', 5, 30),
432-
item('c', 1, 25),
430+
item('a', 2, 'remote'),
431+
item('b', 10, 'local', 20),
432+
item('c', 5, 'local', 30),
433+
item('d', 1, 'local', 25),
434+
item('e', 6, 'remote'),
433435
];
434436
let treeDataProvider: HistoryTreeDataProvider;
435437

@@ -456,31 +458,31 @@ describe('query-history', () => {
456458
});
457459

458460
it('should get children for date ascending', async () => {
459-
const expected = [history[2], history[1], history[0]];
461+
const expected = [history[3], history[0], history[2], history[4], history[1]];
460462
treeDataProvider.sortOrder = SortOrder.DateAsc;
461463

462464
const children = await treeDataProvider.getChildren();
463465
expect(children).to.deep.eq(expected);
464466
});
465467

466468
it('should get children for date descending', async () => {
467-
const expected = [history[0], history[1], history[2]];
469+
const expected = [history[3], history[0], history[2], history[4], history[1]].reverse();
468470
treeDataProvider.sortOrder = SortOrder.DateDesc;
469471

470472
const children = await treeDataProvider.getChildren();
471473
expect(children).to.deep.eq(expected);
472474
});
473475

474476
it('should get children for result count ascending', async () => {
475-
const expected = [history[0], history[2], history[1]];
477+
const expected = [history[0], history[4], history[1], history[3], history[2]];
476478
treeDataProvider.sortOrder = SortOrder.CountAsc;
477479

478480
const children = await treeDataProvider.getChildren();
479481
expect(children).to.deep.eq(expected);
480482
});
481483

482484
it('should get children for result count descending', async () => {
483-
const expected = [history[1], history[2], history[0]];
485+
const expected = [history[0], history[4], history[1], history[3], history[2]].reverse();
484486
treeDataProvider.sortOrder = SortOrder.CountDesc;
485487

486488
const children = await treeDataProvider.getChildren();
@@ -509,17 +511,27 @@ describe('query-history', () => {
509511
expect(children).to.deep.eq(expected);
510512
});
511513

512-
function item(label: string, start: number, resultCount?: number) {
513-
return {
514-
label,
515-
initialInfo: {
516-
start: new Date(start),
517-
},
518-
completedQuery: {
519-
resultCount,
520-
},
521-
t: 'local'
522-
};
514+
function item(label: string, start: number, t = 'local', resultCount?: number) {
515+
if (t === 'local') {
516+
return {
517+
label,
518+
initialInfo: {
519+
start: new Date(start),
520+
},
521+
completedQuery: {
522+
resultCount,
523+
},
524+
t
525+
};
526+
} else {
527+
return {
528+
label,
529+
remoteQuery: {
530+
executionStartTime: start,
531+
},
532+
t
533+
};
534+
}
523535
}
524536
});
525537

0 commit comments

Comments
 (0)