Skip to content

Commit 55af9bc

Browse files
authored
Merge pull request #2894 from github/starcke/lang-context-history
Add support for filtering history panel.
2 parents 16af4c4 + 486180d commit 55af9bc

File tree

9 files changed

+153
-52
lines changed

9 files changed

+153
-52
lines changed

extensions/ql-vscode/src/extension.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,7 @@ async function activateWithInstalledDistribution(
871871
ctx,
872872
queryHistoryConfigurationListener,
873873
labelProvider,
874+
languageContext,
874875
async (
875876
from: CompletedLocalQueryInfo,
876877
to: CompletedLocalQueryInfo,

extensions/ql-vscode/src/query-history/history-tree-data-provider.ts

Lines changed: 55 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ import {
1010
} from "vscode";
1111
import { DisposableObject } from "../common/disposable-object";
1212
import { assertNever } from "../common/helpers-pure";
13-
import { QueryHistoryInfo } from "./query-history-info";
13+
import { getLanguage, QueryHistoryInfo } from "./query-history-info";
1414
import { QueryStatus } from "./query-status";
1515
import { HistoryItemLabelProvider } from "./history-item-label-provider";
16+
import { LanguageContextStore } from "../language-context-store";
1617

1718
export enum SortOrder {
1819
NameAsc = "NameAsc",
@@ -50,7 +51,10 @@ export class HistoryTreeDataProvider
5051

5152
private current: QueryHistoryInfo | undefined;
5253

53-
constructor(private readonly labelProvider: HistoryItemLabelProvider) {
54+
constructor(
55+
private readonly labelProvider: HistoryItemLabelProvider,
56+
private readonly languageContext: LanguageContextStore,
57+
) {
5458
super();
5559
}
5660

@@ -127,51 +131,55 @@ export class HistoryTreeDataProvider
127131
getChildren(element?: QueryHistoryInfo): ProviderResult<QueryHistoryInfo[]> {
128132
return element
129133
? []
130-
: this.history.sort((h1, h2) => {
131-
const h1Label = this.labelProvider.getLabel(h1).toLowerCase();
132-
const h2Label = this.labelProvider.getLabel(h2).toLowerCase();
133-
134-
const h1Date = this.getItemDate(h1);
135-
136-
const h2Date = this.getItemDate(h2);
137-
138-
const resultCount1 =
139-
h1.t === "local"
140-
? h1.completedQuery?.resultCount ?? -1
141-
: h1.resultCount ?? -1;
142-
const resultCount2 =
143-
h2.t === "local"
144-
? h2.completedQuery?.resultCount ?? -1
145-
: h2.resultCount ?? -1;
146-
147-
switch (this.sortOrder) {
148-
case SortOrder.NameAsc:
149-
return h1Label.localeCompare(h2Label, env.language);
150-
151-
case SortOrder.NameDesc:
152-
return h2Label.localeCompare(h1Label, env.language);
153-
154-
case SortOrder.DateAsc:
155-
return h1Date - h2Date;
156-
157-
case SortOrder.DateDesc:
158-
return h2Date - h1Date;
159-
160-
case SortOrder.CountAsc:
161-
// If the result counts are equal, sort by name.
162-
return resultCount1 - resultCount2 === 0
163-
? h1Label.localeCompare(h2Label, env.language)
164-
: resultCount1 - resultCount2;
165-
166-
case SortOrder.CountDesc:
167-
// If the result counts are equal, sort by name.
168-
return resultCount2 - resultCount1 === 0
169-
? h2Label.localeCompare(h1Label, env.language)
170-
: resultCount2 - resultCount1;
171-
default:
172-
assertNever(this.sortOrder);
173-
}
174-
});
134+
: this.history
135+
.filter((h) => {
136+
return this.languageContext.shouldInclude(getLanguage(h));
137+
})
138+
.sort((h1, h2) => {
139+
const h1Label = this.labelProvider.getLabel(h1).toLowerCase();
140+
const h2Label = this.labelProvider.getLabel(h2).toLowerCase();
141+
142+
const h1Date = this.getItemDate(h1);
143+
144+
const h2Date = this.getItemDate(h2);
145+
146+
const resultCount1 =
147+
h1.t === "local"
148+
? h1.completedQuery?.resultCount ?? -1
149+
: h1.resultCount ?? -1;
150+
const resultCount2 =
151+
h2.t === "local"
152+
? h2.completedQuery?.resultCount ?? -1
153+
: h2.resultCount ?? -1;
154+
155+
switch (this.sortOrder) {
156+
case SortOrder.NameAsc:
157+
return h1Label.localeCompare(h2Label, env.language);
158+
159+
case SortOrder.NameDesc:
160+
return h2Label.localeCompare(h1Label, env.language);
161+
162+
case SortOrder.DateAsc:
163+
return h1Date - h2Date;
164+
165+
case SortOrder.DateDesc:
166+
return h2Date - h1Date;
167+
168+
case SortOrder.CountAsc:
169+
// If the result counts are equal, sort by name.
170+
return resultCount1 - resultCount2 === 0
171+
? h1Label.localeCompare(h2Label, env.language)
172+
: resultCount1 - resultCount2;
173+
174+
case SortOrder.CountDesc:
175+
// If the result counts are equal, sort by name.
176+
return resultCount2 - resultCount1 === 0
177+
? h2Label.localeCompare(h1Label, env.language)
178+
: resultCount2 - resultCount1;
179+
default:
180+
assertNever(this.sortOrder);
181+
}
182+
});
175183
}
176184

177185
getParent(_element: QueryHistoryInfo): ProviderResult<QueryHistoryInfo> {

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ import {
6262
showAndLogInformationMessage,
6363
showAndLogWarningMessage,
6464
} from "../common/logging";
65+
import { LanguageContextStore } from "../language-context-store";
6566

6667
/**
6768
* query-history-manager.ts
@@ -141,6 +142,7 @@ export class QueryHistoryManager extends DisposableObject {
141142
ctx: ExtensionContext,
142143
private readonly queryHistoryConfigListener: QueryHistoryConfig,
143144
private readonly labelProvider: HistoryItemLabelProvider,
145+
private readonly languageContext: LanguageContextStore,
144146
private readonly doCompareCallback: (
145147
from: CompletedLocalQueryInfo,
146148
to: CompletedLocalQueryInfo,
@@ -158,7 +160,7 @@ export class QueryHistoryManager extends DisposableObject {
158160
);
159161

160162
this.treeDataProvider = this.push(
161-
new HistoryTreeDataProvider(this.labelProvider),
163+
new HistoryTreeDataProvider(this.labelProvider, this.languageContext),
162164
);
163165
this.treeView = this.push(
164166
window.createTreeView("codeQLQueryHistory", {
@@ -230,6 +232,12 @@ export class QueryHistoryManager extends DisposableObject {
230232

231233
this.registerQueryHistoryScrubber(queryHistoryConfigListener, this, ctx);
232234
this.registerToVariantAnalysisEvents();
235+
236+
this.push(
237+
this.languageContext.onLanguageContextChanged(async () => {
238+
this.treeDataProvider.refresh();
239+
}),
240+
);
233241
}
234242

235243
public getCommands(): QueryHistoryCommands {

extensions/ql-vscode/test/factories/query-history/local-query-history-item.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
import { CancellationTokenSource } from "vscode";
88
import { QueryResultType } from "../../../src/query-server/legacy-messages";
99
import { QueryMetadata } from "../../../src/common/interface-types";
10+
import { QueryLanguage } from "../../../src/common/query-language";
1011

1112
export function createMockLocalQueryInfo({
1213
startTime = new Date(),
@@ -16,6 +17,7 @@ export function createMockLocalQueryInfo({
1617
dbName = "db-name",
1718
hasMetadata = false,
1819
queryWithResults = undefined,
20+
language = undefined,
1921
}: {
2022
startTime?: Date;
2123
resultCount?: number;
@@ -24,6 +26,7 @@ export function createMockLocalQueryInfo({
2426
dbName?: string;
2527
hasMetadata?: boolean;
2628
queryWithResults?: QueryWithResults | undefined;
29+
language?: QueryLanguage;
2730
}): LocalQueryInfo {
2831
const cancellationToken = {
2932
dispose: () => {
@@ -40,6 +43,7 @@ export function createMockLocalQueryInfo({
4043
databaseInfo: {
4144
databaseUri: "databaseUri",
4245
name: dbName,
46+
language,
4347
},
4448
start: startTime,
4549
id: faker.number.int().toString(),

extensions/ql-vscode/test/factories/query-history/variant-analysis-history-item.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
VariantAnalysisStatus,
66
} from "../../../src/variant-analysis/shared/variant-analysis";
77
import { createMockVariantAnalysis } from "../variant-analysis/shared/variant-analysis";
8+
import { QueryLanguage } from "../../../src/common/query-language";
89

910
export function createMockVariantAnalysisHistoryItem({
1011
historyItemStatus = QueryStatus.InProgress,
@@ -14,6 +15,7 @@ export function createMockVariantAnalysisHistoryItem({
1415
userSpecifiedLabel = undefined,
1516
executionStartTime = undefined,
1617
variantAnalysis = undefined,
18+
language = QueryLanguage.Javascript,
1719
}: {
1820
historyItemStatus?: QueryStatus;
1921
variantAnalysisStatus?: VariantAnalysisStatus;
@@ -22,6 +24,7 @@ export function createMockVariantAnalysisHistoryItem({
2224
userSpecifiedLabel?: string;
2325
executionStartTime?: number;
2426
variantAnalysis?: VariantAnalysis;
27+
language?: QueryLanguage;
2528
}): VariantAnalysisHistoryItem {
2629
return {
2730
t: "variant-analysis",
@@ -34,6 +37,7 @@ export function createMockVariantAnalysisHistoryItem({
3437
createMockVariantAnalysis({
3538
status: variantAnalysisStatus,
3639
executionStartTime,
40+
language,
3741
}),
3842
userSpecifiedLabel,
3943
};

extensions/ql-vscode/test/factories/variant-analysis/shared/variant-analysis.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ export function createMockVariantAnalysis({
1515
scannedRepos = createMockScannedRepos(),
1616
skippedRepos = createMockSkippedRepos(),
1717
executionStartTime = faker.number.int(),
18+
language = QueryLanguage.Javascript,
1819
}: {
1920
status?: VariantAnalysisStatus;
2021
scannedRepos?: VariantAnalysisScannedRepository[];
2122
skippedRepos?: VariantAnalysisSkippedRepositories;
2223
executionStartTime?: number | undefined;
24+
language?: QueryLanguage;
2325
}): VariantAnalysis {
2426
return {
2527
id: faker.number.int(),
@@ -32,7 +34,7 @@ export function createMockVariantAnalysis({
3234
query: {
3335
name: "a-query-name",
3436
filePath: "a-query-file-path",
35-
language: QueryLanguage.Javascript,
37+
language,
3638
text: "a-query-text",
3739
},
3840
databases: {

extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/history-tree-data-provider.test.ts

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,13 @@ import {
2828
import { QueryHistoryManager } from "../../../../src/query-history/query-history-manager";
2929
import { createMockQueryHistoryDirs } from "../../../factories/query-history/query-history-dirs";
3030
import { createMockApp } from "../../../__mocks__/appMock";
31+
import { LanguageContextStore } from "../../../../src/language-context-store";
32+
import { App } from "../../../../src/common/app";
33+
import { QueryLanguage } from "../../../../src/common/query-language";
3134

3235
describe("HistoryTreeDataProvider", () => {
3336
const mockExtensionLocation = join(tmpDir.name, "mock-extension-location");
37+
let app: App;
3438
let configListener: QueryHistoryConfigListener;
3539
const doCompareCallback = jest.fn();
3640

@@ -45,10 +49,12 @@ describe("HistoryTreeDataProvider", () => {
4549

4650
let historyTreeDataProvider: HistoryTreeDataProvider;
4751
let labelProvider: HistoryItemLabelProvider;
52+
let languageContext: LanguageContextStore;
4853

4954
beforeEach(() => {
5055
jest.spyOn(extLogger, "log").mockResolvedValue(undefined);
5156

57+
app = createMockApp({});
5258
configListener = new QueryHistoryConfigListener();
5359
localQueriesResultsViewStub = {
5460
showResults: jest.fn(),
@@ -124,7 +130,11 @@ describe("HistoryTreeDataProvider", () => {
124130
ttlInMillis: 0,
125131
onDidChangeConfiguration: jest.fn(),
126132
});
127-
historyTreeDataProvider = new HistoryTreeDataProvider(labelProvider);
133+
languageContext = new LanguageContextStore(app);
134+
historyTreeDataProvider = new HistoryTreeDataProvider(
135+
labelProvider,
136+
languageContext,
137+
);
128138
});
129139

130140
afterEach(async () => {
@@ -418,11 +428,68 @@ describe("HistoryTreeDataProvider", () => {
418428
expect(children).toEqual(expected);
419429
});
420430
});
431+
432+
describe("filtering", () => {
433+
const history = [
434+
createMockLocalQueryInfo({
435+
userSpecifiedLabel: "a",
436+
// No language at all => unknown
437+
}),
438+
createMockVariantAnalysisHistoryItem({
439+
userSpecifiedLabel: "b",
440+
// No specified language => javascript
441+
}),
442+
createMockLocalQueryInfo({
443+
userSpecifiedLabel: "c",
444+
language: QueryLanguage.Python,
445+
}),
446+
createMockVariantAnalysisHistoryItem({
447+
userSpecifiedLabel: "d",
448+
language: QueryLanguage.Java,
449+
}),
450+
];
451+
452+
let treeDataProvider: HistoryTreeDataProvider;
453+
454+
beforeEach(async () => {
455+
queryHistoryManager = await createMockQueryHistory(allHistory);
456+
(queryHistoryManager.treeDataProvider as any).history = [...history];
457+
treeDataProvider = queryHistoryManager.treeDataProvider;
458+
});
459+
460+
it("should get all if no filter is provided", async () => {
461+
const expected = [history[0], history[1], history[2], history[3]];
462+
treeDataProvider.sortOrder = SortOrder.NameAsc;
463+
464+
const children = await treeDataProvider.getChildren();
465+
expect(children).toEqual(expected);
466+
});
467+
468+
it("should filter local runs by language", async () => {
469+
const expected = [history[3]];
470+
treeDataProvider.sortOrder = SortOrder.NameAsc;
471+
472+
await languageContext.setLanguageContext(QueryLanguage.Java);
473+
474+
const children = await treeDataProvider.getChildren();
475+
expect(children).toEqual(expected);
476+
});
477+
478+
it("should filter variant analysis runs by language", async () => {
479+
const expected = [history[2]];
480+
treeDataProvider.sortOrder = SortOrder.NameAsc;
481+
482+
await languageContext.setLanguageContext(QueryLanguage.Python);
483+
484+
const children = await treeDataProvider.getChildren();
485+
expect(children).toEqual(expected);
486+
});
487+
});
421488
});
422489

423490
async function createMockQueryHistory(allHistory: QueryHistoryInfo[]) {
424491
const qhm = new QueryHistoryManager(
425-
createMockApp({}),
492+
app,
426493
{} as QueryRunner,
427494
{} as DatabaseManager,
428495
localQueriesResultsViewStub,
@@ -439,6 +506,7 @@ describe("HistoryTreeDataProvider", () => {
439506
ttlInMillis: 0,
440507
onDidChangeConfiguration: jest.fn(),
441508
}),
509+
languageContext,
442510
doCompareCallback,
443511
);
444512
(qhm.treeDataProvider as any).history = [...allHistory];

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { createMockQueryHistoryDirs } from "../../../factories/query-history/que
2828
import { createMockApp } from "../../../__mocks__/appMock";
2929
import { App } from "../../../../src/common/app";
3030
import { createMockCommandManager } from "../../../__mocks__/commandsMock";
31+
import { LanguageContextStore } from "../../../../src/language-context-store";
3132

3233
describe("QueryHistoryManager", () => {
3334
const mockExtensionLocation = join(tmpDir.name, "mock-extension-location");
@@ -937,6 +938,7 @@ describe("QueryHistoryManager", () => {
937938
ttlInMillis: 0,
938939
onDidChangeConfiguration: jest.fn(),
939940
}),
941+
new LanguageContextStore(mockApp),
940942
doCompareCallback,
941943
);
942944
(qhm.treeDataProvider as any).history = [...allHistory];

0 commit comments

Comments
 (0)