Queries Panel: Create query from welcome view (#2780)

This commit is contained in:
Shati Patel
2023-09-05 10:34:38 +01:00
committed by GitHub
parent f6b3f28039
commit a3ce9f516a
6 changed files with 82 additions and 54 deletions

View File

@@ -1804,7 +1804,8 @@
},
{
"view": "codeQLQueries",
"contents": "Looking for queries..."
"contents": "We didn't find any CodeQL queries in this workspace. [Create one to get started](command:codeQLQueries.createQuery).",
"when": "codeQL.noQueries"
},
{
"view": "codeQLDatabases",

View File

@@ -44,7 +44,7 @@ export class QueriesModule extends DisposableObject {
this.push(queryDiscovery);
void queryDiscovery.initialRefresh();
this.queriesPanel = new QueriesPanel(queryDiscovery);
this.queriesPanel = new QueriesPanel(queryDiscovery, app);
this.push(this.queriesPanel);
}
}

View File

@@ -2,12 +2,16 @@ import { DisposableObject } from "../common/disposable-object";
import { QueryTreeDataProvider } from "./query-tree-data-provider";
import { QueryDiscovery } from "./query-discovery";
import { window } from "vscode";
import { App } from "../common/app";
export class QueriesPanel extends DisposableObject {
public constructor(queryDiscovery: QueryDiscovery) {
public constructor(
queryDiscovery: QueryDiscovery,
readonly app: App,
) {
super();
const dataProvider = new QueryTreeDataProvider(queryDiscovery);
const dataProvider = new QueryTreeDataProvider(queryDiscovery, app);
const treeView = window.createTreeView("codeQLQueries", {
treeDataProvider: dataProvider,

View File

@@ -3,10 +3,10 @@ import {
QueryTreeViewItem,
createQueryTreeFileItem,
createQueryTreeFolderItem,
createQueryTreeTextItem,
} from "./query-tree-view-item";
import { DisposableObject } from "../common/disposable-object";
import { FileTreeNode } from "../common/file-tree-nodes";
import { App } from "../common/app";
export interface QueryDiscoverer {
readonly buildQueryTree: () => Array<FileTreeNode<string>> | undefined;
@@ -23,7 +23,10 @@ export class QueryTreeDataProvider
new EventEmitter<void>(),
);
public constructor(private readonly queryDiscoverer: QueryDiscoverer) {
public constructor(
private readonly queryDiscoverer: QueryDiscoverer,
private readonly app: App,
) {
super();
queryDiscoverer.onDidChangeQueries(() => {
@@ -43,8 +46,11 @@ export class QueryTreeDataProvider
if (queryTree === undefined) {
return [];
} else if (queryTree.length === 0) {
return [this.noQueriesTreeViewItem()];
void this.app.commands.execute("setContext", "codeQL.noQueries", true);
// Returning an empty tree here will show the welcome view
return [];
} else {
void this.app.commands.execute("setContext", "codeQL.noQueries", false);
return queryTree.map(this.convertFileTreeNode.bind(this));
}
}
@@ -67,12 +73,6 @@ export class QueryTreeDataProvider
}
}
private noQueriesTreeViewItem(): QueryTreeViewItem {
return createQueryTreeTextItem(
"This workspace doesn't contain any CodeQL queries at the moment.",
);
}
/**
* Returns the UI presentation of the element that gets displayed in the view.
* @param item The item to represent.

View File

@@ -39,7 +39,3 @@ export function createQueryTreeFileItem(
};
return item;
}
export function createQueryTreeTextItem(text: string): QueryTreeViewItem {
return new QueryTreeViewItem(text, undefined, []);
}

View File

@@ -7,56 +7,71 @@ import { QueryTreeDataProvider } from "../../../../src/queries-panel/query-tree-
import {
createQueryTreeFileItem,
createQueryTreeFolderItem,
createQueryTreeTextItem,
} from "../../../../src/queries-panel/query-tree-view-item";
import { createMockApp } from "../../../__mocks__/appMock";
import { createMockCommandManager } from "../../../__mocks__/commandsMock";
describe("QueryTreeDataProvider", () => {
describe("getChildren", () => {
it("returns empty array when discovery has not yet happened", async () => {
const dataProvider = new QueryTreeDataProvider({
buildQueryTree: () => undefined,
onDidChangeQueries: jest.fn(),
});
const dataProvider = new QueryTreeDataProvider(
{
buildQueryTree: () => undefined,
onDidChangeQueries: jest.fn(),
},
createMockApp({}),
);
expect(dataProvider.getChildren()).toEqual([]);
});
it("returns an explanatory message when there are no queries", async () => {
const dataProvider = new QueryTreeDataProvider({
buildQueryTree: () => [],
onDidChangeQueries: jest.fn(),
});
it("set 'noQueries' context value when there are no queries", async () => {
const executeCommand = jest.fn();
expect(dataProvider.getChildren()).toEqual([
createQueryTreeTextItem(
"This workspace doesn't contain any CodeQL queries at the moment.",
),
]);
const dataProvider = new QueryTreeDataProvider(
{
buildQueryTree: () => [],
onDidChangeQueries: jest.fn(),
},
createMockApp({
commands: createMockCommandManager({ executeCommand }),
}),
);
expect(dataProvider.getChildren()).toEqual([]);
expect(executeCommand).toBeCalledWith(
"setContext",
"codeQL.noQueries",
true,
);
});
it("converts FileTreeNode to QueryTreeViewItem", async () => {
const dataProvider = new QueryTreeDataProvider({
buildQueryTree: () => [
new FileTreeDirectory<string>("dir1", "dir1", env, [
new FileTreeDirectory<string>("dir1/dir2", "dir2", env, [
new FileTreeLeaf<string>(
"dir1/dir2/file1",
"file1",
"javascript",
),
new FileTreeLeaf<string>(
"dir1/dir2/file2",
"file2",
"javascript",
),
const dataProvider = new QueryTreeDataProvider(
{
buildQueryTree: () => [
new FileTreeDirectory<string>("dir1", "dir1", env, [
new FileTreeDirectory<string>("dir1/dir2", "dir2", env, [
new FileTreeLeaf<string>(
"dir1/dir2/file1",
"file1",
"javascript",
),
new FileTreeLeaf<string>(
"dir1/dir2/file2",
"file2",
"javascript",
),
]),
]),
]),
new FileTreeDirectory<string>("dir3", "dir3", env, [
new FileTreeLeaf<string>("dir3/file3", "file3", "javascript"),
]),
],
onDidChangeQueries: jest.fn(),
});
new FileTreeDirectory<string>("dir3", "dir3", env, [
new FileTreeLeaf<string>("dir3/file3", "file3", "javascript"),
]),
],
onDidChangeQueries: jest.fn(),
},
createMockApp({}),
);
expect(dataProvider.getChildren()).toEqual([
createQueryTreeFolderItem("dir1", "dir1", [
@@ -85,7 +100,14 @@ describe("QueryTreeDataProvider", () => {
onDidChangeQueries: onDidChangeQueriesEmitter.event,
};
const dataProvider = new QueryTreeDataProvider(queryDiscoverer);
const executeCommand = jest.fn();
const dataProvider = new QueryTreeDataProvider(
queryDiscoverer,
createMockApp({
commands: createMockCommandManager({ executeCommand }),
}),
);
expect(dataProvider.getChildren().length).toEqual(1);
queryTree.push(
@@ -96,6 +118,11 @@ describe("QueryTreeDataProvider", () => {
onDidChangeQueriesEmitter.fire();
expect(dataProvider.getChildren().length).toEqual(2);
expect(executeCommand).toBeCalledWith(
"setContext",
"codeQL.noQueries",
false,
);
});
});
});