Skip to content

Commit a3ce9f5

Browse files
authored
Queries Panel: Create query from welcome view (#2780)
1 parent f6b3f28 commit a3ce9f5

File tree

6 files changed

+82
-54
lines changed

6 files changed

+82
-54
lines changed

extensions/ql-vscode/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1804,7 +1804,8 @@
18041804
},
18051805
{
18061806
"view": "codeQLQueries",
1807-
"contents": "Looking for queries..."
1807+
"contents": "We didn't find any CodeQL queries in this workspace. [Create one to get started](command:codeQLQueries.createQuery).",
1808+
"when": "codeQL.noQueries"
18081809
},
18091810
{
18101811
"view": "codeQLDatabases",

extensions/ql-vscode/src/queries-panel/queries-module.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export class QueriesModule extends DisposableObject {
4444
this.push(queryDiscovery);
4545
void queryDiscovery.initialRefresh();
4646

47-
this.queriesPanel = new QueriesPanel(queryDiscovery);
47+
this.queriesPanel = new QueriesPanel(queryDiscovery, app);
4848
this.push(this.queriesPanel);
4949
}
5050
}

extensions/ql-vscode/src/queries-panel/queries-panel.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@ import { DisposableObject } from "../common/disposable-object";
22
import { QueryTreeDataProvider } from "./query-tree-data-provider";
33
import { QueryDiscovery } from "./query-discovery";
44
import { window } from "vscode";
5+
import { App } from "../common/app";
56

67
export class QueriesPanel extends DisposableObject {
7-
public constructor(queryDiscovery: QueryDiscovery) {
8+
public constructor(
9+
queryDiscovery: QueryDiscovery,
10+
readonly app: App,
11+
) {
812
super();
913

10-
const dataProvider = new QueryTreeDataProvider(queryDiscovery);
14+
const dataProvider = new QueryTreeDataProvider(queryDiscovery, app);
1115

1216
const treeView = window.createTreeView("codeQLQueries", {
1317
treeDataProvider: dataProvider,

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

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ import {
33
QueryTreeViewItem,
44
createQueryTreeFileItem,
55
createQueryTreeFolderItem,
6-
createQueryTreeTextItem,
76
} from "./query-tree-view-item";
87
import { DisposableObject } from "../common/disposable-object";
98
import { FileTreeNode } from "../common/file-tree-nodes";
9+
import { App } from "../common/app";
1010

1111
export interface QueryDiscoverer {
1212
readonly buildQueryTree: () => Array<FileTreeNode<string>> | undefined;
@@ -23,7 +23,10 @@ export class QueryTreeDataProvider
2323
new EventEmitter<void>(),
2424
);
2525

26-
public constructor(private readonly queryDiscoverer: QueryDiscoverer) {
26+
public constructor(
27+
private readonly queryDiscoverer: QueryDiscoverer,
28+
private readonly app: App,
29+
) {
2730
super();
2831

2932
queryDiscoverer.onDidChangeQueries(() => {
@@ -43,8 +46,11 @@ export class QueryTreeDataProvider
4346
if (queryTree === undefined) {
4447
return [];
4548
} else if (queryTree.length === 0) {
46-
return [this.noQueriesTreeViewItem()];
49+
void this.app.commands.execute("setContext", "codeQL.noQueries", true);
50+
// Returning an empty tree here will show the welcome view
51+
return [];
4752
} else {
53+
void this.app.commands.execute("setContext", "codeQL.noQueries", false);
4854
return queryTree.map(this.convertFileTreeNode.bind(this));
4955
}
5056
}
@@ -67,12 +73,6 @@ export class QueryTreeDataProvider
6773
}
6874
}
6975

70-
private noQueriesTreeViewItem(): QueryTreeViewItem {
71-
return createQueryTreeTextItem(
72-
"This workspace doesn't contain any CodeQL queries at the moment.",
73-
);
74-
}
75-
7676
/**
7777
* Returns the UI presentation of the element that gets displayed in the view.
7878
* @param item The item to represent.

extensions/ql-vscode/src/queries-panel/query-tree-view-item.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,3 @@ export function createQueryTreeFileItem(
3939
};
4040
return item;
4141
}
42-
43-
export function createQueryTreeTextItem(text: string): QueryTreeViewItem {
44-
return new QueryTreeViewItem(text, undefined, []);
45-
}

extensions/ql-vscode/test/vscode-tests/minimal-workspace/queries-panel/query-tree-data-provider.test.ts

Lines changed: 64 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,56 +7,71 @@ import { QueryTreeDataProvider } from "../../../../src/queries-panel/query-tree-
77
import {
88
createQueryTreeFileItem,
99
createQueryTreeFolderItem,
10-
createQueryTreeTextItem,
1110
} from "../../../../src/queries-panel/query-tree-view-item";
11+
import { createMockApp } from "../../../__mocks__/appMock";
12+
import { createMockCommandManager } from "../../../__mocks__/commandsMock";
1213

1314
describe("QueryTreeDataProvider", () => {
1415
describe("getChildren", () => {
1516
it("returns empty array when discovery has not yet happened", async () => {
16-
const dataProvider = new QueryTreeDataProvider({
17-
buildQueryTree: () => undefined,
18-
onDidChangeQueries: jest.fn(),
19-
});
17+
const dataProvider = new QueryTreeDataProvider(
18+
{
19+
buildQueryTree: () => undefined,
20+
onDidChangeQueries: jest.fn(),
21+
},
22+
createMockApp({}),
23+
);
2024

2125
expect(dataProvider.getChildren()).toEqual([]);
2226
});
2327

24-
it("returns an explanatory message when there are no queries", async () => {
25-
const dataProvider = new QueryTreeDataProvider({
26-
buildQueryTree: () => [],
27-
onDidChangeQueries: jest.fn(),
28-
});
28+
it("set 'noQueries' context value when there are no queries", async () => {
29+
const executeCommand = jest.fn();
2930

30-
expect(dataProvider.getChildren()).toEqual([
31-
createQueryTreeTextItem(
32-
"This workspace doesn't contain any CodeQL queries at the moment.",
33-
),
34-
]);
31+
const dataProvider = new QueryTreeDataProvider(
32+
{
33+
buildQueryTree: () => [],
34+
onDidChangeQueries: jest.fn(),
35+
},
36+
createMockApp({
37+
commands: createMockCommandManager({ executeCommand }),
38+
}),
39+
);
40+
41+
expect(dataProvider.getChildren()).toEqual([]);
42+
expect(executeCommand).toBeCalledWith(
43+
"setContext",
44+
"codeQL.noQueries",
45+
true,
46+
);
3547
});
3648

3749
it("converts FileTreeNode to QueryTreeViewItem", async () => {
38-
const dataProvider = new QueryTreeDataProvider({
39-
buildQueryTree: () => [
40-
new FileTreeDirectory<string>("dir1", "dir1", env, [
41-
new FileTreeDirectory<string>("dir1/dir2", "dir2", env, [
42-
new FileTreeLeaf<string>(
43-
"dir1/dir2/file1",
44-
"file1",
45-
"javascript",
46-
),
47-
new FileTreeLeaf<string>(
48-
"dir1/dir2/file2",
49-
"file2",
50-
"javascript",
51-
),
50+
const dataProvider = new QueryTreeDataProvider(
51+
{
52+
buildQueryTree: () => [
53+
new FileTreeDirectory<string>("dir1", "dir1", env, [
54+
new FileTreeDirectory<string>("dir1/dir2", "dir2", env, [
55+
new FileTreeLeaf<string>(
56+
"dir1/dir2/file1",
57+
"file1",
58+
"javascript",
59+
),
60+
new FileTreeLeaf<string>(
61+
"dir1/dir2/file2",
62+
"file2",
63+
"javascript",
64+
),
65+
]),
5266
]),
53-
]),
54-
new FileTreeDirectory<string>("dir3", "dir3", env, [
55-
new FileTreeLeaf<string>("dir3/file3", "file3", "javascript"),
56-
]),
57-
],
58-
onDidChangeQueries: jest.fn(),
59-
});
67+
new FileTreeDirectory<string>("dir3", "dir3", env, [
68+
new FileTreeLeaf<string>("dir3/file3", "file3", "javascript"),
69+
]),
70+
],
71+
onDidChangeQueries: jest.fn(),
72+
},
73+
createMockApp({}),
74+
);
6075

6176
expect(dataProvider.getChildren()).toEqual([
6277
createQueryTreeFolderItem("dir1", "dir1", [
@@ -85,7 +100,14 @@ describe("QueryTreeDataProvider", () => {
85100
onDidChangeQueries: onDidChangeQueriesEmitter.event,
86101
};
87102

88-
const dataProvider = new QueryTreeDataProvider(queryDiscoverer);
103+
const executeCommand = jest.fn();
104+
105+
const dataProvider = new QueryTreeDataProvider(
106+
queryDiscoverer,
107+
createMockApp({
108+
commands: createMockCommandManager({ executeCommand }),
109+
}),
110+
);
89111
expect(dataProvider.getChildren().length).toEqual(1);
90112

91113
queryTree.push(
@@ -96,6 +118,11 @@ describe("QueryTreeDataProvider", () => {
96118
onDidChangeQueriesEmitter.fire();
97119

98120
expect(dataProvider.getChildren().length).toEqual(2);
121+
expect(executeCommand).toBeCalledWith(
122+
"setContext",
123+
"codeQL.noQueries",
124+
false,
125+
);
99126
});
100127
});
101128
});

0 commit comments

Comments
 (0)