Skip to content

Commit 5a32486

Browse files
authored
Get highlighted item in DB panel (#1887)
1 parent 4b43b9a commit 5a32486

4 files changed

Lines changed: 110 additions & 65 deletions

File tree

extensions/ql-vscode/src/databases/db-item.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,20 @@ export enum DbItemKind {
1111
RemoteRepo = "RemoteRepo",
1212
}
1313

14+
export const remoteDbKinds = [
15+
DbItemKind.RootRemote,
16+
DbItemKind.RemoteSystemDefinedList,
17+
DbItemKind.RemoteUserDefinedList,
18+
DbItemKind.RemoteOwner,
19+
DbItemKind.RemoteRepo,
20+
];
21+
22+
export const localDbKinds = [
23+
DbItemKind.RootLocal,
24+
DbItemKind.LocalList,
25+
DbItemKind.LocalDatabase,
26+
];
27+
1428
export interface RootLocalDbItem {
1529
kind: DbItemKind.RootLocal;
1630
expanded: boolean;

extensions/ql-vscode/src/databases/db-manager.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { App } from "../common/app";
22
import { AppEvent, AppEventEmitter } from "../common/events";
33
import { ValueResult } from "../common/value-result";
44
import { DbConfigStore } from "./config/db-config-store";
5-
import { DbItem } from "./db-item";
5+
import { DbItem, DbItemKind, remoteDbKinds } from "./db-item";
66
import { calculateNewExpandedState } from "./db-item-expansion";
77
import {
88
getSelectedDbItem,
@@ -75,16 +75,19 @@ export class DbManager {
7575
await this.dbConfigStore.updateExpandedState(newExpandedItems);
7676
}
7777

78-
public async addNewRemoteList(listName: string): Promise<void> {
79-
if (listName === "") {
80-
throw Error("List name cannot be empty");
78+
public async addNewList(kind: DbItemKind, listName: string): Promise<void> {
79+
if (remoteDbKinds.includes(kind)) {
80+
if (listName === "") {
81+
throw Error("List name cannot be empty");
82+
}
83+
if (this.dbConfigStore.doesRemoteListExist(listName)) {
84+
throw Error(`A list with the name '${listName}' already exists`);
85+
}
86+
87+
await this.dbConfigStore.addRemoteList(listName);
88+
} else {
89+
throw Error("Cannot add a local list");
8190
}
82-
83-
if (this.dbConfigStore.doesRemoteListExist(listName)) {
84-
throw Error(`A list with the name '${listName}' already exists`);
85-
}
86-
87-
await this.dbConfigStore.addRemoteList(listName);
8891
}
8992

9093
public doesRemoteListExist(listName: string): boolean {

extensions/ql-vscode/src/databases/ui/db-panel.ts

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,37 @@
1-
import { TreeViewExpansionEvent, window, workspace } from "vscode";
1+
import { TreeView, TreeViewExpansionEvent, window, workspace } from "vscode";
22
import { commandRunner } from "../../commandRunner";
3-
import { showAndLogErrorMessage } from "../../helpers";
43
import { DisposableObject } from "../../pure/disposable-object";
4+
import { DbItem, DbItemKind } from "../db-item";
55
import { DbManager } from "../db-manager";
66
import { DbTreeDataProvider } from "./db-tree-data-provider";
77
import { DbTreeViewItem } from "./db-tree-view-item";
88

99
export class DbPanel extends DisposableObject {
1010
private readonly dataProvider: DbTreeDataProvider;
11+
private readonly treeView: TreeView<DbTreeViewItem>;
1112

1213
public constructor(private readonly dbManager: DbManager) {
1314
super();
1415

1516
this.dataProvider = new DbTreeDataProvider(dbManager);
1617

17-
const treeView = window.createTreeView("codeQLDatabasesExperimental", {
18+
this.treeView = window.createTreeView("codeQLDatabasesExperimental", {
1819
treeDataProvider: this.dataProvider,
1920
canSelectMany: false,
2021
});
2122

2223
this.push(
23-
treeView.onDidCollapseElement(async (e) => {
24+
this.treeView.onDidCollapseElement(async (e) => {
2425
await this.onDidCollapseElement(e);
2526
}),
2627
);
2728
this.push(
28-
treeView.onDidExpandElement(async (e) => {
29+
this.treeView.onDidExpandElement(async (e) => {
2930
await this.onDidExpandElement(e);
3031
}),
3132
);
3233

33-
this.push(treeView);
34+
this.push(this.treeView);
3435
}
3536

3637
public async initialize(): Promise<void> {
@@ -67,13 +68,15 @@ export class DbPanel extends DisposableObject {
6768
return;
6869
}
6970

70-
if (this.dbManager.doesRemoteListExist(listName)) {
71-
void showAndLogErrorMessage(
72-
`A list with the name '${listName}' already exists`,
73-
);
74-
} else {
75-
await this.dbManager.addNewRemoteList(listName);
76-
}
71+
const highlightedItem = await this.getHighlightedDbItem();
72+
73+
// For now: we only support adding remote lists, so if no item is highlighted,
74+
// we default to the "RootRemote" kind.
75+
// In future: if the highlighted item is undefined, we'll show a quick pick where
76+
// a user can select whether to add a remote or local list.
77+
const listKind = highlightedItem?.kind || DbItemKind.RootRemote;
78+
79+
await this.dbManager.addNewList(listKind, listName);
7780
}
7881

7982
private async setSelectedItem(treeViewItem: DbTreeViewItem): Promise<void> {
@@ -106,4 +109,16 @@ export class DbPanel extends DisposableObject {
106109

107110
await this.dbManager.updateDbItemExpandedState(event.element.dbItem, true);
108111
}
112+
113+
/**
114+
* Gets the currently highlighted database item in the tree view.
115+
* The VS Code API calls this the "selection", but we already have a notion of selection
116+
* (i.e. which item has a check mark next to it), so we call this "highlighted".
117+
*
118+
* @returns The highlighted database item, or `undefined` if no item is highlighted.
119+
*/
120+
private async getHighlightedDbItem(): Promise<DbItem | undefined> {
121+
// You can only select one item at a time, so selection[0] gives the selection
122+
return this.treeView.selection[0]?.dbItem;
123+
}
109124
}

extensions/ql-vscode/src/vscode-tests/minimal-workspace/databases/db-panel.test.ts

Lines changed: 55 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -443,52 +443,63 @@ describe("db panel", () => {
443443
}
444444
});
445445

446-
it("should add a new list to the remote db list", async () => {
447-
const dbConfig: DbConfig = createDbConfig({
448-
remoteLists: [
449-
{
450-
name: "my-list-1",
451-
repositories: ["owner1/repo1", "owner1/repo2"],
446+
describe("addNewList", () => {
447+
it("should add a new remote list", async () => {
448+
const dbConfig: DbConfig = createDbConfig({
449+
remoteLists: [
450+
{
451+
name: "my-list-1",
452+
repositories: ["owner1/repo1", "owner1/repo2"],
453+
},
454+
],
455+
selected: {
456+
kind: SelectedDbItemKind.RemoteUserDefinedList,
457+
listName: "my-list-1",
452458
},
453-
],
454-
selected: {
455-
kind: SelectedDbItemKind.RemoteUserDefinedList,
456-
listName: "my-list-1",
457-
},
458-
});
459+
});
459460

460-
await saveDbConfig(dbConfig);
461+
await saveDbConfig(dbConfig);
461462

462-
const dbTreeItems = await dbTreeDataProvider.getChildren();
463+
const dbTreeItems = await dbTreeDataProvider.getChildren();
463464

464-
expect(dbTreeItems).toBeTruthy();
465-
const items = dbTreeItems!;
465+
expect(dbTreeItems).toBeTruthy();
466+
const items = dbTreeItems!;
466467

467-
const remoteRootNode = items[0];
468-
const remoteUserDefinedLists = remoteRootNode.children.filter(
469-
(c) => c.dbItem?.kind === DbItemKind.RemoteUserDefinedList,
470-
);
471-
const list1 = remoteRootNode.children.find(
472-
(c) =>
473-
c.dbItem?.kind === DbItemKind.RemoteUserDefinedList &&
474-
c.dbItem?.listName === "my-list-1",
475-
);
468+
const remoteRootNode = items[0];
469+
const remoteUserDefinedLists = remoteRootNode.children.filter(
470+
(c) => c.dbItem?.kind === DbItemKind.RemoteUserDefinedList,
471+
);
472+
const list1 = remoteRootNode.children.find(
473+
(c) =>
474+
c.dbItem?.kind === DbItemKind.RemoteUserDefinedList &&
475+
c.dbItem?.listName === "my-list-1",
476+
);
476477

477-
expect(remoteUserDefinedLists.length).toBe(1);
478-
expect(remoteUserDefinedLists[0]).toBe(list1);
478+
expect(remoteUserDefinedLists.length).toBe(1);
479+
expect(remoteUserDefinedLists[0]).toBe(list1);
479480

480-
await dbManager.addNewRemoteList("my-list-2");
481+
await dbManager.addNewList(DbItemKind.RootRemote, "my-list-2");
481482

482-
// Read the workspace databases JSON file directly to check that the new list has been added.
483-
// We can't use the dbConfigStore's `read` function here because it depends on the file watcher
484-
// picking up changes, and we don't control the timing of that.
485-
const dbConfigFileContents = await readJSON(dbConfigFilePath);
486-
expect(dbConfigFileContents.databases.remote.repositoryLists.length).toBe(
487-
2,
488-
);
489-
expect(dbConfigFileContents.databases.remote.repositoryLists[1]).toEqual({
490-
name: "my-list-2",
491-
repositories: [],
483+
// Read the workspace databases JSON file directly to check that the new list has been added.
484+
// We can't use the dbConfigStore's `read` function here because it depends on the file watcher
485+
// picking up changes, and we don't control the timing of that.
486+
const dbConfigFileContents = await readJSON(dbConfigFilePath);
487+
expect(dbConfigFileContents.databases.remote.repositoryLists.length).toBe(
488+
2,
489+
);
490+
expect(dbConfigFileContents.databases.remote.repositoryLists[1]).toEqual({
491+
name: "my-list-2",
492+
repositories: [],
493+
});
494+
});
495+
496+
it("should throw error when adding a new list to a local node", async () => {
497+
const dbConfig: DbConfig = createDbConfig();
498+
await saveDbConfig(dbConfig);
499+
500+
await expect(
501+
dbManager.addNewList(DbItemKind.RootLocal, ""),
502+
).rejects.toThrow(new Error("Cannot add a local list"));
492503
});
493504
});
494505

@@ -555,9 +566,9 @@ describe("db panel", () => {
555566

556567
await saveDbConfig(dbConfig);
557568

558-
await expect(dbManager.addNewRemoteList("")).rejects.toThrow(
559-
new Error("List name cannot be empty"),
560-
);
569+
await expect(
570+
dbManager.addNewList(DbItemKind.RootRemote, ""),
571+
).rejects.toThrow(new Error("List name cannot be empty"));
561572
});
562573

563574
it("should not allow adding a list with duplicate name", async () => {
@@ -572,7 +583,9 @@ describe("db panel", () => {
572583

573584
await saveDbConfig(dbConfig);
574585

575-
await expect(dbManager.addNewRemoteList("my-list-1")).rejects.toThrow(
586+
await expect(
587+
dbManager.addNewList(DbItemKind.RootRemote, "my-list-1"),
588+
).rejects.toThrow(
576589
new Error("A list with the name 'my-list-1' already exists"),
577590
);
578591
});

0 commit comments

Comments
 (0)