Skip to content

Commit d97eb2e

Browse files
authored
Track expanded state of db items (#1844)
1 parent 28652a2 commit d97eb2e

File tree

17 files changed

+538
-6
lines changed

17 files changed

+538
-6
lines changed

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

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { pathExists, writeJSON, readJSON, readJSONSync } from "fs-extra";
22
import { join } from "path";
3-
import { cloneDbConfig, DbConfig, SelectedDbItem } from "./db-config";
3+
import {
4+
cloneDbConfig,
5+
DbConfig,
6+
ExpandedDbItem,
7+
SelectedDbItem,
8+
} from "./db-config";
49
import * as chokidar from "chokidar";
510
import { DisposableObject, DisposeHandler } from "../../pure/disposable-object";
611
import { DbConfigValidator } from "./db-config-validator";
@@ -72,6 +77,19 @@ export class DbConfigStore extends DisposableObject {
7277
await this.writeConfig(config);
7378
}
7479

80+
public async updateExpandedState(expandedItems: ExpandedDbItem[]) {
81+
if (!this.config) {
82+
throw Error("Cannot update expansion state if config is not loaded");
83+
}
84+
85+
const config: DbConfig = {
86+
...this.config,
87+
expanded: expandedItems,
88+
};
89+
90+
await this.writeConfig(config);
91+
}
92+
7593
private async writeConfig(config: DbConfig): Promise<void> {
7694
await writeJSON(this.configPath, config, {
7795
spaces: 2,
@@ -137,6 +155,7 @@ export class DbConfigStore extends DisposableObject {
137155
databases: [],
138156
},
139157
},
158+
expanded: [],
140159
};
141160
}
142161
}

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

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
export interface DbConfig {
44
databases: DbConfigDatabases;
5+
expanded: ExpandedDbItem[];
56
selected?: SelectedDbItem;
67
}
78

@@ -87,6 +88,37 @@ export interface LocalDatabase {
8788
storagePath: string;
8889
}
8990

91+
export type ExpandedDbItem =
92+
| RootLocalExpandedDbItem
93+
| LocalUserDefinedListExpandedDbItem
94+
| RootRemoteExpandedDbItem
95+
| RemoteUserDefinedListExpandedDbItem;
96+
97+
export enum ExpandedDbItemKind {
98+
RootLocal = "rootLocal",
99+
LocalUserDefinedList = "localUserDefinedList",
100+
RootRemote = "rootRemote",
101+
RemoteUserDefinedList = "remoteUserDefinedList",
102+
}
103+
104+
export interface RootLocalExpandedDbItem {
105+
kind: ExpandedDbItemKind.RootLocal;
106+
}
107+
108+
export interface LocalUserDefinedListExpandedDbItem {
109+
kind: ExpandedDbItemKind.LocalUserDefinedList;
110+
listName: string;
111+
}
112+
113+
export interface RootRemoteExpandedDbItem {
114+
kind: ExpandedDbItemKind.RootRemote;
115+
}
116+
117+
export interface RemoteUserDefinedListExpandedDbItem {
118+
kind: ExpandedDbItemKind.RemoteUserDefinedList;
119+
listName: string;
120+
}
121+
90122
export function cloneDbConfig(config: DbConfig): DbConfig {
91123
return {
92124
databases: {
@@ -108,6 +140,7 @@ export function cloneDbConfig(config: DbConfig): DbConfig {
108140
databases: config.databases.local.databases.map((db) => ({ ...db })),
109141
},
110142
},
143+
expanded: config.expanded.map(cloneDbConfigExpandedItem),
111144
selected: config.selected
112145
? cloneDbConfigSelectedItem(config.selected)
113146
: undefined,
@@ -150,3 +183,17 @@ function cloneDbConfigSelectedItem(selected: SelectedDbItem): SelectedDbItem {
150183
};
151184
}
152185
}
186+
187+
function cloneDbConfigExpandedItem(item: ExpandedDbItem): ExpandedDbItem {
188+
switch (item.kind) {
189+
case ExpandedDbItemKind.RootLocal:
190+
case ExpandedDbItemKind.RootRemote:
191+
return { kind: item.kind };
192+
case ExpandedDbItemKind.LocalUserDefinedList:
193+
case ExpandedDbItemKind.RemoteUserDefinedList:
194+
return {
195+
kind: item.kind,
196+
listName: item.listName,
197+
};
198+
}
199+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { ExpandedDbItem, ExpandedDbItemKind } from "./config/db-config";
2+
import { DbItem, DbItemKind } from "./db-item";
3+
4+
export function calculateNewExpandedState(
5+
currentExpandedItems: ExpandedDbItem[],
6+
dbItem: DbItem,
7+
itemExpanded: boolean,
8+
): ExpandedDbItem[] {
9+
if (itemExpanded) {
10+
const expandedDbItem = mapDbItemToExpandedDbItem(dbItem);
11+
const expandedItems = [...currentExpandedItems];
12+
if (!expandedItems.some((i) => isDbItemEqualToExpandedDbItem(dbItem, i))) {
13+
expandedItems.push(expandedDbItem);
14+
}
15+
return expandedItems;
16+
} else {
17+
return currentExpandedItems.filter(
18+
(i) => !isDbItemEqualToExpandedDbItem(dbItem, i),
19+
);
20+
}
21+
}
22+
23+
function mapDbItemToExpandedDbItem(dbItem: DbItem): ExpandedDbItem {
24+
switch (dbItem.kind) {
25+
case DbItemKind.RootLocal:
26+
return { kind: ExpandedDbItemKind.RootLocal };
27+
case DbItemKind.LocalList:
28+
return {
29+
kind: ExpandedDbItemKind.LocalUserDefinedList,
30+
listName: dbItem.listName,
31+
};
32+
case DbItemKind.RootRemote:
33+
return { kind: ExpandedDbItemKind.RootRemote };
34+
case DbItemKind.RemoteUserDefinedList:
35+
return {
36+
kind: ExpandedDbItemKind.RemoteUserDefinedList,
37+
listName: dbItem.listName,
38+
};
39+
default:
40+
throw Error(`Unknown db item kind ${dbItem.kind}`);
41+
}
42+
}
43+
44+
function isDbItemEqualToExpandedDbItem(
45+
dbItem: DbItem,
46+
expandedDbItem: ExpandedDbItem,
47+
) {
48+
switch (dbItem.kind) {
49+
case DbItemKind.RootLocal:
50+
return expandedDbItem.kind === ExpandedDbItemKind.RootLocal;
51+
case DbItemKind.LocalList:
52+
return (
53+
expandedDbItem.kind === ExpandedDbItemKind.LocalUserDefinedList &&
54+
expandedDbItem.listName === dbItem.listName
55+
);
56+
case DbItemKind.RootRemote:
57+
return expandedDbItem.kind === ExpandedDbItemKind.RootRemote;
58+
case DbItemKind.RemoteUserDefinedList:
59+
return (
60+
expandedDbItem.kind === ExpandedDbItemKind.RemoteUserDefinedList &&
61+
expandedDbItem.listName === dbItem.listName
62+
);
63+
default:
64+
throw Error(`Unknown db item kind ${dbItem.kind}`);
65+
}
66+
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ export enum DbItemKind {
1313

1414
export interface RootLocalDbItem {
1515
kind: DbItemKind.RootLocal;
16+
expanded: boolean;
1617
children: LocalDbItem[];
1718
}
1819

1920
export type LocalDbItem = LocalListDbItem | LocalDatabaseDbItem;
2021

2122
export interface LocalListDbItem {
2223
kind: DbItemKind.LocalList;
24+
expanded: boolean;
2325
selected: boolean;
2426
listName: string;
2527
databases: LocalDatabaseDbItem[];
@@ -37,6 +39,7 @@ export interface LocalDatabaseDbItem {
3739

3840
export interface RootRemoteDbItem {
3941
kind: DbItemKind.RootRemote;
42+
expanded: boolean;
4043
children: RemoteDbItem[];
4144
}
4245

@@ -62,6 +65,7 @@ export interface RemoteSystemDefinedListDbItem {
6265

6366
export interface RemoteUserDefinedListDbItem {
6467
kind: DbItemKind.RemoteUserDefinedList;
68+
expanded: boolean;
6569
selected: boolean;
6670
listName: string;
6771
repos: RemoteRepoDbItem[];

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { AppEvent, AppEventEmitter } from "../common/events";
33
import { ValueResult } from "../common/value-result";
44
import { DbConfigStore } from "./config/db-config-store";
55
import { DbItem } from "./db-item";
6+
import { calculateNewExpandedState } from "./db-item-expansion";
67
import {
78
getSelectedDbItem,
89
mapDbItemToSelectedDbItem,
@@ -54,4 +55,22 @@ export class DbManager {
5455
await this.dbConfigStore.setSelectedDbItem(selectedDbItem);
5556
}
5657
}
58+
59+
public async updateDbItemExpandedState(
60+
dbItem: DbItem,
61+
itemExpanded: boolean,
62+
): Promise<void> {
63+
const configResult = this.dbConfigStore.getConfig();
64+
if (configResult.isFailure) {
65+
throw Error("Cannot update expanded state if config is not loaded");
66+
}
67+
68+
const newExpandedItems = calculateNewExpandedState(
69+
configResult.value.expanded,
70+
dbItem,
71+
itemExpanded,
72+
);
73+
74+
await this.dbConfigStore.updateExpandedState(newExpandedItems);
75+
}
5776
}

extensions/ql-vscode/src/databases/db-tree-creator.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
DbConfig,
3+
ExpandedDbItemKind,
34
LocalDatabase,
45
LocalList,
56
RemoteRepositoryList,
@@ -34,6 +35,10 @@ export function createRemoteTree(dbConfig: DbConfig): RootRemoteDbItem {
3435
createRepoItem(r, dbConfig),
3536
);
3637

38+
const expanded =
39+
dbConfig.expanded &&
40+
dbConfig.expanded.some((e) => e.kind === ExpandedDbItemKind.RootRemote);
41+
3742
return {
3843
kind: DbItemKind.RootRemote,
3944
children: [
@@ -42,6 +47,7 @@ export function createRemoteTree(dbConfig: DbConfig): RootRemoteDbItem {
4247
...userDefinedRepoLists,
4348
...repos,
4449
],
50+
expanded: !!expanded,
4551
};
4652
}
4753

@@ -53,9 +59,14 @@ export function createLocalTree(dbConfig: DbConfig): RootLocalDbItem {
5359
createLocalDb(l, dbConfig),
5460
);
5561

62+
const expanded =
63+
dbConfig.expanded &&
64+
dbConfig.expanded.some((e) => e.kind === ExpandedDbItemKind.RootLocal);
65+
5666
return {
5767
kind: DbItemKind.RootLocal,
5868
children: [...localLists, ...localDbs],
69+
expanded: !!expanded,
5970
};
6071
}
6172

@@ -88,11 +99,20 @@ function createRemoteUserDefinedList(
8899
dbConfig.selected.kind === SelectedDbItemKind.RemoteUserDefinedList &&
89100
dbConfig.selected.listName === list.name;
90101

102+
const expanded =
103+
dbConfig.expanded &&
104+
dbConfig.expanded.some(
105+
(e) =>
106+
e.kind === ExpandedDbItemKind.RemoteUserDefinedList &&
107+
e.listName === list.name,
108+
);
109+
91110
return {
92111
kind: DbItemKind.RemoteUserDefinedList,
93112
listName: list.name,
94113
repos: list.repositories.map((r) => createRepoItem(r, dbConfig, list.name)),
95114
selected: !!selected,
115+
expanded: !!expanded,
96116
};
97117
}
98118

@@ -134,11 +154,20 @@ function createLocalList(list: LocalList, dbConfig: DbConfig): LocalListDbItem {
134154
dbConfig.selected.kind === SelectedDbItemKind.LocalUserDefinedList &&
135155
dbConfig.selected.listName === list.name;
136156

157+
const expanded =
158+
dbConfig.expanded &&
159+
dbConfig.expanded.some(
160+
(e) =>
161+
e.kind === ExpandedDbItemKind.LocalUserDefinedList &&
162+
e.listName === list.name,
163+
);
164+
137165
return {
138166
kind: DbItemKind.LocalList,
139167
listName: list.name,
140168
databases: list.databases.map((d) => createLocalDb(d, dbConfig, list.name)),
141169
selected: !!selected,
170+
expanded: !!expanded,
142171
};
143172
}
144173

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

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { window, workspace } from "vscode";
1+
import { TreeViewExpansionEvent, window, workspace } from "vscode";
22
import { commandRunner } from "../../commandRunner";
33
import { DisposableObject } from "../../pure/disposable-object";
44
import { DbManager } from "../db-manager";
@@ -18,6 +18,9 @@ export class DbPanel extends DisposableObject {
1818
canSelectMany: false,
1919
});
2020

21+
treeView.onDidCollapseElement.bind(this.onDidCollapseElement);
22+
treeView.onDidExpandElement.bind(this.onDidExpandElement);
23+
2124
this.push(treeView);
2225
}
2326

@@ -49,4 +52,26 @@ export class DbPanel extends DisposableObject {
4952
}
5053
await this.dbManager.setSelectedDbItem(treeViewItem.dbItem);
5154
}
55+
56+
private async onDidCollapseElement(
57+
event: TreeViewExpansionEvent<DbTreeViewItem>,
58+
): Promise<void> {
59+
const dbItem = event.element.dbItem;
60+
if (!dbItem) {
61+
throw Error("Expected a database item.");
62+
}
63+
64+
await this.dbManager.updateDbItemExpandedState(event.element.dbItem, false);
65+
}
66+
67+
private async onDidExpandElement(
68+
event: TreeViewExpansionEvent<DbTreeViewItem>,
69+
): Promise<void> {
70+
const dbItem = event.element.dbItem;
71+
if (!dbItem) {
72+
throw Error("Expected a database item.");
73+
}
74+
75+
await this.dbManager.updateDbItemExpandedState(event.element.dbItem, true);
76+
}
5277
}

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export function createDbTreeViewItemRoot(
7070
undefined,
7171
label,
7272
tooltip,
73-
vscode.TreeItemCollapsibleState.Collapsed,
73+
getCollapsibleState(dbItem.expanded),
7474
children,
7575
);
7676
}
@@ -100,7 +100,7 @@ export function createDbTreeViewItemUserDefinedList(
100100
undefined,
101101
listName,
102102
undefined,
103-
vscode.TreeItemCollapsibleState.Collapsed,
103+
getCollapsibleState(dbItem.expanded),
104104
children,
105105
);
106106
}
@@ -147,3 +147,11 @@ export function createDbTreeViewItemLocalDatabase(
147147
[],
148148
);
149149
}
150+
151+
function getCollapsibleState(
152+
expanded: boolean,
153+
): vscode.TreeItemCollapsibleState {
154+
return expanded
155+
? vscode.TreeItemCollapsibleState.Expanded
156+
: vscode.TreeItemCollapsibleState.Collapsed;
157+
}

0 commit comments

Comments
 (0)