Skip to content

Commit 8e848e3

Browse files
authored
Set db tree item context value to drive actions (#1920)
1 parent ae3ed94 commit 8e848e3

5 files changed

Lines changed: 208 additions & 9 deletions

File tree

extensions/ql-vscode/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -783,7 +783,7 @@
783783
"view/item/context": [
784784
{
785785
"command": "codeQLDatabasesExperimental.setSelectedItemContextMenu",
786-
"when": "view == codeQLDatabasesExperimental && viewItem == canBeSelected"
786+
"when": "view == codeQLDatabasesExperimental && viewItem =~ /canBeSelected/"
787787
},
788788
{
789789
"command": "codeQLDatabases.setCurrentDatabase",
@@ -812,7 +812,7 @@
812812
},
813813
{
814814
"command": "codeQLDatabasesExperimental.setSelectedItem",
815-
"when": "view == codeQLDatabasesExperimental && viewItem == canBeSelected",
815+
"when": "view == codeQLDatabasesExperimental && viewItem =~ /canBeSelected/",
816816
"group": "inline"
817817
},
818818
{
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { DbItem, DbItemKind, isSelectableDbItem } from "../db-item";
2+
3+
export type DbTreeViewItemAction =
4+
| "canBeSelected"
5+
| "canBeRemoved"
6+
| "canBeRenamed"
7+
| "canBeOpenedOnGitHub";
8+
9+
export function getDbItemActions(dbItem: DbItem): DbTreeViewItemAction[] {
10+
const actions: DbTreeViewItemAction[] = [];
11+
12+
if (canBeSelected(dbItem)) {
13+
actions.push("canBeSelected");
14+
}
15+
if (canBeRemoved(dbItem)) {
16+
actions.push("canBeRemoved");
17+
}
18+
if (canBeRenamed(dbItem)) {
19+
actions.push("canBeRenamed");
20+
}
21+
if (canBeOpenedOnGitHub(dbItem)) {
22+
actions.push("canBeOpenedOnGitHub");
23+
}
24+
25+
return actions;
26+
}
27+
28+
const dbItemKindsThatCanBeRemoved = [
29+
DbItemKind.LocalList,
30+
DbItemKind.RemoteUserDefinedList,
31+
DbItemKind.LocalDatabase,
32+
DbItemKind.RemoteRepo,
33+
DbItemKind.RemoteOwner,
34+
];
35+
36+
const dbItemKindsThatCanBeRenamed = [
37+
DbItemKind.LocalList,
38+
DbItemKind.RemoteUserDefinedList,
39+
DbItemKind.LocalDatabase,
40+
];
41+
42+
const dbItemKindsThatCanBeOpenedOnGitHub = [
43+
DbItemKind.RemoteOwner,
44+
DbItemKind.RemoteRepo,
45+
];
46+
47+
function canBeSelected(dbItem: DbItem): boolean {
48+
return isSelectableDbItem(dbItem) && !dbItem.selected;
49+
}
50+
51+
function canBeRemoved(dbItem: DbItem): boolean {
52+
return dbItemKindsThatCanBeRemoved.includes(dbItem.kind);
53+
}
54+
55+
function canBeRenamed(dbItem: DbItem): boolean {
56+
return dbItemKindsThatCanBeRenamed.includes(dbItem.kind);
57+
}
58+
59+
function canBeOpenedOnGitHub(dbItem: DbItem): boolean {
60+
return dbItemKindsThatCanBeOpenedOnGitHub.includes(dbItem.kind);
61+
}

extensions/ql-vscode/src/databases/ui/db-tree-view-item.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
RootLocalDbItem,
1212
RootRemoteDbItem,
1313
} from "../db-item";
14+
import { getDbItemActions } from "./db-tree-view-item-action";
1415

1516
export const SELECTED_DB_ITEM_RESOURCE_URI = "codeql://databases?selected=true";
1617

@@ -32,18 +33,21 @@ export class DbTreeViewItem extends vscode.TreeItem {
3233
) {
3334
super(label, collapsibleState);
3435

35-
if (dbItem && isSelectableDbItem(dbItem)) {
36-
if (dbItem.selected) {
36+
if (dbItem) {
37+
this.contextValue = getContextValue(dbItem);
38+
if (isSelectableDbItem(dbItem) && dbItem.selected) {
3739
// Define the resource id to drive the UI to render this item as selected.
3840
this.resourceUri = vscode.Uri.parse(SELECTED_DB_ITEM_RESOURCE_URI);
39-
} else {
40-
// Define a context value to drive the UI to show an action to select the item.
41-
this.contextValue = "canBeSelected";
4241
}
4342
}
4443
}
4544
}
4645

46+
function getContextValue(dbItem: DbItem): string | undefined {
47+
const actions = getDbItemActions(dbItem);
48+
return actions.length > 0 ? actions.join(",") : undefined;
49+
}
50+
4751
export function createDbTreeViewItemError(
4852
label: string,
4953
tooltip: string,
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import { getDbItemActions } from "../../../../src/databases/ui/db-tree-view-item-action";
2+
import {
3+
createLocalDatabaseDbItem,
4+
createLocalListDbItem,
5+
createRemoteOwnerDbItem,
6+
createRemoteRepoDbItem,
7+
createRemoteSystemDefinedListDbItem,
8+
createRemoteUserDefinedListDbItem,
9+
createRootLocalDbItem,
10+
createRootRemoteDbItem,
11+
} from "../../../factories/db-item-factories";
12+
13+
describe("getDbItemActions", () => {
14+
it("should return an empty array for root remote node", () => {
15+
const dbItem = createRootRemoteDbItem();
16+
17+
const actions = getDbItemActions(dbItem);
18+
19+
expect(actions).toEqual([]);
20+
});
21+
22+
it("should return an empty array for root local node", () => {
23+
const dbItem = createRootLocalDbItem();
24+
25+
const actions = getDbItemActions(dbItem);
26+
27+
expect(actions).toEqual([]);
28+
});
29+
30+
it("should set canBeSelected, canBeRemoved and canBeRenamed for local user defined db list", () => {
31+
const dbItem = createLocalListDbItem();
32+
33+
const actions = getDbItemActions(dbItem);
34+
35+
expect(actions).toEqual(["canBeSelected", "canBeRemoved", "canBeRenamed"]);
36+
});
37+
38+
it("should set canBeSelected, canBeRemoved and canBeRenamed for local db", () => {
39+
const dbItem = createLocalDatabaseDbItem();
40+
41+
const actions = getDbItemActions(dbItem);
42+
43+
expect(actions).toEqual(["canBeSelected", "canBeRemoved", "canBeRenamed"]);
44+
});
45+
46+
it("should set canBeSelected for remote system defined db list", () => {
47+
const dbItem = createRemoteSystemDefinedListDbItem();
48+
49+
const actions = getDbItemActions(dbItem);
50+
51+
expect(actions).toEqual(["canBeSelected"]);
52+
});
53+
54+
it("should not set canBeSelected for remote system defined list that is already selected", () => {
55+
const dbItem = createRemoteSystemDefinedListDbItem({ selected: true });
56+
57+
const actions = getDbItemActions(dbItem);
58+
59+
expect(actions.length).toEqual(0);
60+
});
61+
62+
it("should set canBeSelected, canBeRemoved and canBeRenamed for remote user defined db list", () => {
63+
const dbItem = createRemoteUserDefinedListDbItem();
64+
65+
const actions = getDbItemActions(dbItem);
66+
67+
expect(actions).toEqual(["canBeSelected", "canBeRemoved", "canBeRenamed"]);
68+
});
69+
70+
it("should not set canBeSelected for remote user defined db list that is already selected", () => {
71+
const dbItem = createRemoteUserDefinedListDbItem({ selected: true });
72+
73+
const actions = getDbItemActions(dbItem);
74+
75+
expect(actions.includes("canBeSelected")).toBeFalsy();
76+
});
77+
78+
it("should set canBeSelected, canBeRemoved, canBeOpenedOnGitHub for remote owner", () => {
79+
const dbItem = createRemoteOwnerDbItem();
80+
81+
const actions = getDbItemActions(dbItem);
82+
83+
expect(actions).toEqual([
84+
"canBeSelected",
85+
"canBeRemoved",
86+
"canBeOpenedOnGitHub",
87+
]);
88+
});
89+
90+
it("should set canBeSelected, canBeRemoved, canBeOpenedOnGitHub for remote db", () => {
91+
const dbItem = createRemoteRepoDbItem();
92+
93+
const actions = getDbItemActions(dbItem);
94+
95+
expect(actions).toEqual([
96+
"canBeSelected",
97+
"canBeRemoved",
98+
"canBeOpenedOnGitHub",
99+
]);
100+
});
101+
102+
it("should not set canBeSelected for remote db that is already selected", () => {
103+
const dbItem = createRemoteRepoDbItem({ selected: true });
104+
105+
const actions = getDbItemActions(dbItem);
106+
107+
expect(actions.includes("canBeSelected")).toBeFalsy();
108+
});
109+
});

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

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,7 @@ describe("db panel", () => {
772772
expect(item.tooltip).toBe(`Top ${n} repositories of a language`);
773773
expect(item.iconPath).toEqual(new ThemeIcon("github"));
774774
expect(item.collapsibleState).toBe(TreeItemCollapsibleState.None);
775+
checkDbItemActions(item, ["canBeSelected"]);
775776
}
776777

777778
function checkUserDefinedListItem(
@@ -783,6 +784,7 @@ describe("db panel", () => {
783784
expect(item.tooltip).toBeUndefined();
784785
expect(item.iconPath).toBeUndefined();
785786
expect(item.collapsibleState).toBe(TreeItemCollapsibleState.Collapsed);
787+
checkDbItemActions(item, ["canBeSelected", "canBeRenamed", "canBeRemoved"]);
786788
expect(item.children).toBeTruthy();
787789
expect(item.children.length).toBe(repos.length);
788790

@@ -796,6 +798,11 @@ describe("db panel", () => {
796798
expect(item.tooltip).toBeUndefined();
797799
expect(item.iconPath).toEqual(new ThemeIcon("organization"));
798800
expect(item.collapsibleState).toBe(TreeItemCollapsibleState.None);
801+
checkDbItemActions(item, [
802+
"canBeSelected",
803+
"canBeRemoved",
804+
"canBeOpenedOnGitHub",
805+
]);
799806
expect(item.children).toBeTruthy();
800807
expect(item.children.length).toBe(0);
801808
}
@@ -805,6 +812,11 @@ describe("db panel", () => {
805812
expect(item.tooltip).toBeUndefined();
806813
expect(item.iconPath).toEqual(new ThemeIcon("database"));
807814
expect(item.collapsibleState).toBe(TreeItemCollapsibleState.None);
815+
checkDbItemActions(item, [
816+
"canBeSelected",
817+
"canBeRemoved",
818+
"canBeOpenedOnGitHub",
819+
]);
808820
}
809821

810822
function checkLocalListItem(
@@ -816,6 +828,7 @@ describe("db panel", () => {
816828
expect(item.tooltip).toBeUndefined();
817829
expect(item.iconPath).toBeUndefined();
818830
expect(item.collapsibleState).toBe(TreeItemCollapsibleState.Collapsed);
831+
checkDbItemActions(item, ["canBeSelected", "canBeRemoved", "canBeRenamed"]);
819832
expect(item.children).toBeTruthy();
820833
expect(item.children.length).toBe(databases.length);
821834

@@ -832,6 +845,16 @@ describe("db panel", () => {
832845
expect(item.tooltip).toBe(`Language: ${database.language}`);
833846
expect(item.iconPath).toEqual(new ThemeIcon("database"));
834847
expect(item.collapsibleState).toBe(TreeItemCollapsibleState.None);
848+
checkDbItemActions(item, ["canBeSelected", "canBeRemoved", "canBeRenamed"]);
849+
}
850+
851+
function checkDbItemActions(item: DbTreeViewItem, actions: string[]): void {
852+
const itemActions = item.contextValue?.split(",");
853+
expect(itemActions).toBeDefined();
854+
expect(itemActions!.length).toBe(actions.length);
855+
for (const action of actions) {
856+
expect(itemActions).toContain(action);
857+
}
835858
}
836859

837860
function checkErrorItem(
@@ -852,14 +875,16 @@ describe("db panel", () => {
852875
function isTreeViewItemSelectable(treeViewItem: DbTreeViewItem) {
853876
return (
854877
treeViewItem.resourceUri === undefined &&
855-
treeViewItem.contextValue === "canBeSelected"
878+
treeViewItem.contextValue?.includes("canBeSelected")
856879
);
857880
}
858881

859882
function isTreeViewItemSelected(treeViewItem: DbTreeViewItem) {
860883
return (
861884
treeViewItem.resourceUri?.toString(true) ===
862-
SELECTED_DB_ITEM_RESOURCE_URI && treeViewItem.contextValue === undefined
885+
SELECTED_DB_ITEM_RESOURCE_URI &&
886+
(treeViewItem.contextValue === undefined ||
887+
!treeViewItem.contextValue.includes("canBeSelected"))
863888
);
864889
}
865890

0 commit comments

Comments
 (0)