Skip to content

Commit ed2bdd8

Browse files
authored
Merge pull request github#1925 from github/nora/add-remove-context-action
Add remove context menu action
2 parents 82ce7bc + c4df8bf commit ed2bdd8

File tree

6 files changed

+310
-3
lines changed

6 files changed

+310
-3
lines changed

extensions/ql-vscode/package.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
"onCommand:codeQLDatabasesExperimental.setSelectedItemContextMenu",
6767
"onCommand:codeQLDatabasesExperimental.renameItemContextMenu",
6868
"onCommand:codeQLDatabasesExperimental.openOnGitHubContextMenu",
69+
"onCommand:codeQLDatabasesExperimental.removeItemContextMenu",
6970
"onCommand:codeQL.quickQuery",
7071
"onCommand:codeQL.restartQueryServer",
7172
"onWebviewPanel:resultsView",
@@ -392,6 +393,10 @@
392393
"command": "codeQLDatabasesExperimental.openOnGitHubContextMenu",
393394
"title": "Open on GitHub"
394395
},
396+
{
397+
"command": "codeQLDatabasesExperimental.removeItemContextMenu",
398+
"title": "Remove"
399+
},
395400
{
396401
"command": "codeQLDatabases.chooseDatabaseFolder",
397402
"title": "Choose Database from Folder",
@@ -791,6 +796,10 @@
791796
}
792797
],
793798
"view/item/context": [
799+
{
800+
"command": "codeQLDatabasesExperimental.removeItemContextMenu",
801+
"when": "view == codeQLDatabasesExperimental && viewItem =~ /canBeRemoved/"
802+
},
794803
{
795804
"command": "codeQLDatabasesExperimental.setSelectedItemContextMenu",
796805
"when": "view == codeQLDatabasesExperimental && viewItem =~ /canBeSelected/"
@@ -1043,6 +1052,10 @@
10431052
"command": "codeQLDatabasesExperimental.openOnGitHubContextMenu",
10441053
"when": "false"
10451054
},
1055+
{
1056+
"command": "codeQLDatabasesExperimental.removeItemContextMenu",
1057+
"when": "false"
1058+
},
10461059
{
10471060
"command": "codeQLDatabases.setCurrentDatabase",
10481061
"when": "false"

extensions/ql-vscode/src/databases/config/db-config-store.ts

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
renameLocalList,
88
renameRemoteList,
99
SelectedDbItem,
10+
SelectedDbItemKind,
1011
} from "./db-config";
1112
import * as chokidar from "chokidar";
1213
import { DisposableObject, DisposeHandler } from "../../pure/disposable-object";
@@ -22,7 +23,13 @@ import {
2223
LocalDatabaseDbItem,
2324
LocalListDbItem,
2425
RemoteUserDefinedListDbItem,
26+
DbItem,
27+
DbItemKind,
2528
} from "../db-item";
29+
import {
30+
compareSelectedKindIsEqual,
31+
mapDbItemToSelectedDbItem,
32+
} from "../db-item-selection";
2633

2734
export class DbConfigStore extends DisposableObject {
2835
public readonly onDidChangeConfig: AppEvent<void>;
@@ -88,6 +95,96 @@ export class DbConfigStore extends DisposableObject {
8895
await this.writeConfig(config);
8996
}
9097

98+
public async removeDbItem(dbItem: DbItem): Promise<void> {
99+
if (!this.config) {
100+
throw Error("Cannot remove item if config is not loaded");
101+
}
102+
103+
const config = cloneDbConfig(this.config);
104+
const selectedItem: SelectedDbItem | undefined = config.selected;
105+
106+
// Remove item from databases
107+
switch (dbItem.kind) {
108+
case DbItemKind.LocalList:
109+
config.databases.local.lists = config.databases.local.lists.filter(
110+
(list) => list.name !== dbItem.listName,
111+
);
112+
break;
113+
case DbItemKind.RemoteUserDefinedList:
114+
config.databases.remote.repositoryLists =
115+
config.databases.remote.repositoryLists.filter(
116+
(list) => list.name !== dbItem.listName,
117+
);
118+
break;
119+
case DbItemKind.LocalDatabase:
120+
// When we start using local databases these need to be removed from disk as well.
121+
if (dbItem.parentListName) {
122+
const parent = config.databases.local.lists.find(
123+
(list) => list.name === dbItem.parentListName,
124+
);
125+
if (!parent) {
126+
throw Error(`Cannot find parent list '${dbItem.parentListName}'`);
127+
} else {
128+
parent.databases = parent.databases.filter(
129+
(db) => db.name !== dbItem.databaseName,
130+
);
131+
}
132+
}
133+
config.databases.local.databases =
134+
config.databases.local.databases.filter(
135+
(db) => db.name !== dbItem.databaseName,
136+
);
137+
break;
138+
case DbItemKind.RemoteRepo:
139+
if (dbItem.parentListName) {
140+
const parent = config.databases.remote.repositoryLists.find(
141+
(list) => list.name === dbItem.parentListName,
142+
);
143+
if (!parent) {
144+
throw Error(`Cannot find parent list '${dbItem.parentListName}'`);
145+
} else {
146+
parent.repositories = parent.repositories.filter(
147+
(repo) => repo !== dbItem.repoFullName,
148+
);
149+
}
150+
}
151+
config.databases.remote.repositories =
152+
config.databases.remote.repositories.filter(
153+
(repo) => repo !== dbItem.repoFullName,
154+
);
155+
break;
156+
case DbItemKind.RemoteOwner:
157+
config.databases.remote.owners = config.databases.remote.owners.filter(
158+
(owner) => owner !== dbItem.ownerName,
159+
);
160+
break;
161+
default:
162+
throw Error(`Type '${dbItem.kind}' cannot be removed`);
163+
}
164+
165+
// Remove item from selected
166+
const removedItem = mapDbItemToSelectedDbItem(dbItem);
167+
if (selectedItem && removedItem) {
168+
// if removedItem has a parentList, check if parentList is selectedItem
169+
if (
170+
removedItem.kind === SelectedDbItemKind.LocalUserDefinedList ||
171+
removedItem.kind === SelectedDbItemKind.RemoteUserDefinedList
172+
) {
173+
if (
174+
(selectedItem.kind === SelectedDbItemKind.LocalDatabase ||
175+
selectedItem.kind === SelectedDbItemKind.RemoteRepository) &&
176+
removedItem.listName === selectedItem.listName
177+
) {
178+
config.selected = undefined;
179+
}
180+
}
181+
if (compareSelectedKindIsEqual(removedItem, selectedItem)) {
182+
config.selected = undefined;
183+
}
184+
}
185+
await this.writeConfig(config);
186+
}
187+
91188
public async addRemoteRepo(
92189
repoNwo: string,
93190
parentList?: string,

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

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
import { DbItem, DbItemKind, LocalDbItem, RemoteDbItem } from "./db-item";
2-
import { SelectedDbItem, SelectedDbItemKind } from "./config/db-config";
2+
import {
3+
SelectedDbItem,
4+
SelectedDbItemKind,
5+
SelectedLocalDatabase,
6+
SelectedLocalUserDefinedList,
7+
SelectedRemoteOwner,
8+
SelectedRemoteRepository,
9+
} from "./config/db-config";
310

411
export function getSelectedDbItem(dbItems: DbItem[]): DbItem | undefined {
512
for (const dbItem of dbItems) {
@@ -80,15 +87,51 @@ export function mapDbItemToSelectedDbItem(
8087
case DbItemKind.LocalDatabase:
8188
return {
8289
kind: SelectedDbItemKind.LocalDatabase,
83-
listName: dbItem?.parentListName,
8490
databaseName: dbItem.databaseName,
91+
listName: dbItem?.parentListName,
8592
};
8693

8794
case DbItemKind.RemoteRepo:
8895
return {
8996
kind: SelectedDbItemKind.RemoteRepository,
90-
listName: dbItem?.parentListName,
9197
repositoryName: dbItem.repoFullName,
98+
listName: dbItem?.parentListName,
9299
};
93100
}
94101
}
102+
103+
export function compareSelectedKindIsEqual(
104+
item1: SelectedDbItem,
105+
item2: SelectedDbItem,
106+
): boolean {
107+
if (item1.kind === item2.kind) {
108+
switch (item1.kind) {
109+
case SelectedDbItemKind.LocalUserDefinedList:
110+
case SelectedDbItemKind.RemoteUserDefinedList:
111+
case SelectedDbItemKind.RemoteSystemDefinedList:
112+
return (
113+
item1.listName === (item2 as SelectedLocalUserDefinedList).listName
114+
);
115+
case SelectedDbItemKind.RemoteOwner:
116+
return item1.ownerName === (item2 as SelectedRemoteOwner).ownerName;
117+
case SelectedDbItemKind.LocalDatabase: {
118+
const selectedItem = item2 as SelectedLocalDatabase;
119+
return (
120+
item1.databaseName === selectedItem.databaseName &&
121+
item1.listName === selectedItem.listName
122+
);
123+
}
124+
case SelectedDbItemKind.RemoteRepository: {
125+
const selectedItem = item2 as SelectedRemoteRepository;
126+
return (
127+
item1.repositoryName === selectedItem.repositoryName &&
128+
item1.listName === selectedItem.listName
129+
);
130+
}
131+
default:
132+
return false;
133+
}
134+
} else {
135+
return false;
136+
}
137+
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,14 @@ export class DbManager {
7575
}
7676
}
7777

78+
public async removeDbItem(dbItem: DbItem): Promise<void> {
79+
await this.dbConfigStore.removeDbItem(dbItem);
80+
81+
// Updating the expanded items takes care of cleaning up
82+
// any non-existent items.
83+
await this.updateExpandedItems(this.getExpandedItems());
84+
}
85+
7886
public async updateDbItemExpandedState(
7987
dbItem: DbItem,
8088
itemExpanded: boolean,

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,12 @@ export class DbPanel extends DisposableObject {
107107
(treeViewItem: DbTreeViewItem) => this.renameItem(treeViewItem),
108108
),
109109
);
110+
this.push(
111+
commandRunner(
112+
"codeQLDatabasesExperimental.removeItemContextMenu",
113+
(treeViewItem: DbTreeViewItem) => this.removeItem(treeViewItem),
114+
),
115+
);
110116
}
111117

112118
private async openConfigFile(): Promise<void> {
@@ -363,6 +369,15 @@ export class DbPanel extends DisposableObject {
363369
await this.dbManager.renameList(dbItem, newName);
364370
}
365371

372+
private async removeItem(treeViewItem: DbTreeViewItem): Promise<void> {
373+
if (treeViewItem.dbItem === undefined) {
374+
throw new Error(
375+
"Not a removable database item. Please select a valid item.",
376+
);
377+
}
378+
await this.dbManager.removeDbItem(treeViewItem.dbItem);
379+
}
380+
366381
private async onDidCollapseElement(
367382
event: TreeViewExpansionEvent<DbTreeViewItem>,
368383
): Promise<void> {

0 commit comments

Comments
 (0)