@eclipse-lyra/extension-settings-tree 0.7.57 → 0.7.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/i18n.de-BNVmjm3M.js +11 -0
- package/dist/i18n.de-BNVmjm3M.js.map +1 -0
- package/dist/i18n.en-4qIo7_K0.js +11 -0
- package/dist/i18n.en-4qIo7_K0.js.map +1 -0
- package/dist/index.js +14 -8
- package/dist/index.js.map +1 -1
- package/dist/settings-tree-extension-xvuT1JDl.js +792 -0
- package/dist/settings-tree-extension-xvuT1JDl.js.map +1 -0
- package/package.json +3 -3
- package/dist/i18n.de-DyWo8pOM.js +0 -12
- package/dist/i18n.de-DyWo8pOM.js.map +0 -1
- package/dist/i18n.en-BsMBVteB.js +0 -12
- package/dist/i18n.en-BsMBVteB.js.map +0 -1
- package/dist/settings-tree-extension-qqh_Ohws.js +0 -829
- package/dist/settings-tree-extension-qqh_Ohws.js.map +0 -1
|
@@ -1,829 +0,0 @@
|
|
|
1
|
-
import { css, html } from "lit";
|
|
2
|
-
import { LyraPart, subscribe, TOPIC_SETTINGS_CHANGED, appSettings, promptDialog, editorRegistry, commandRegistry, contributionRegistry, TOOLBAR_MAIN_RIGHT } from "@eclipse-lyra/core";
|
|
3
|
-
import { property, state, customElement } from "lit/decorators.js";
|
|
4
|
-
import { createRef, ref } from "lit/directives/ref.js";
|
|
5
|
-
import { repeat } from "lit/directives/repeat.js";
|
|
6
|
-
var __defProp = Object.defineProperty;
|
|
7
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
8
|
-
var __decorateClass = (decorators, target, key, kind) => {
|
|
9
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
10
|
-
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
11
|
-
if (decorator = decorators[i])
|
|
12
|
-
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
13
|
-
if (kind && result) __defProp(target, key, result);
|
|
14
|
-
return result;
|
|
15
|
-
};
|
|
16
|
-
let LyraSettingsTree = class extends LyraPart {
|
|
17
|
-
constructor() {
|
|
18
|
-
super(...arguments);
|
|
19
|
-
this.settings = {};
|
|
20
|
-
this.categoryTree = [];
|
|
21
|
-
this.selectedPath = null;
|
|
22
|
-
this.detailRows = [];
|
|
23
|
-
this.detailTitle = "";
|
|
24
|
-
this.searchQuery = "";
|
|
25
|
-
this.detailForPath = null;
|
|
26
|
-
this.treeRef = createRef();
|
|
27
|
-
}
|
|
28
|
-
async doInitUI() {
|
|
29
|
-
await this.loadSettings();
|
|
30
|
-
subscribe(TOPIC_SETTINGS_CHANGED, () => this.loadSettings());
|
|
31
|
-
}
|
|
32
|
-
async loadSettings() {
|
|
33
|
-
if (this.isDirty()) return;
|
|
34
|
-
this.settings = await appSettings.getAll() ?? {};
|
|
35
|
-
this.buildCategoryTree();
|
|
36
|
-
if (this.selectedPath) {
|
|
37
|
-
this.updateDetailForPath(this.selectedPath);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
buildCategoryTree() {
|
|
41
|
-
const categories = appSettings.getCategories();
|
|
42
|
-
const schemaIds = new Set(categories.map((c) => c.id));
|
|
43
|
-
const nodes = [];
|
|
44
|
-
for (const cat of categories) {
|
|
45
|
-
const childSchema = cat.schema?.properties;
|
|
46
|
-
const value = this.settings[cat.id];
|
|
47
|
-
const children = this.buildChildNodes(`${cat.id}`, childSchema, value);
|
|
48
|
-
const label = cat.schema?.title ?? cat.label;
|
|
49
|
-
if (this.matchesSearch(label, cat.id)) {
|
|
50
|
-
nodes.push({
|
|
51
|
-
path: cat.id,
|
|
52
|
-
label,
|
|
53
|
-
children,
|
|
54
|
-
expanded: true
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
for (const key of Object.keys(this.settings)) {
|
|
59
|
-
if (schemaIds.has(key)) continue;
|
|
60
|
-
const value = this.settings[key];
|
|
61
|
-
const children = this.buildChildNodes(key, void 0, value);
|
|
62
|
-
if (this.matchesSearch(key, key)) {
|
|
63
|
-
nodes.push({
|
|
64
|
-
path: key,
|
|
65
|
-
label: key,
|
|
66
|
-
children,
|
|
67
|
-
expanded: true
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
this.categoryTree = nodes;
|
|
72
|
-
}
|
|
73
|
-
buildChildNodes(parentPath, schemaProps, value) {
|
|
74
|
-
const children = [];
|
|
75
|
-
if (schemaProps) {
|
|
76
|
-
for (const [k, s] of Object.entries(schemaProps)) {
|
|
77
|
-
const path = `${parentPath}.${k}`;
|
|
78
|
-
const label = s?.title ?? k;
|
|
79
|
-
const subValue = LyraSettingsTree.isRecord(value) ? value[k] : void 0;
|
|
80
|
-
const subChildren = this.buildChildNodes(path, s?.properties, subValue);
|
|
81
|
-
if (this.matchesSearch(label, path)) {
|
|
82
|
-
children.push({ path, label, children: subChildren, expanded: false });
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
if (LyraSettingsTree.isRecord(value) && !schemaProps) {
|
|
87
|
-
for (const [k, v] of Object.entries(value)) {
|
|
88
|
-
const path = `${parentPath}.${k}`;
|
|
89
|
-
const subChildren = this.buildChildNodes(path, void 0, v);
|
|
90
|
-
if (this.matchesSearch(k, path)) {
|
|
91
|
-
children.push({ path, label: k, children: subChildren, expanded: false });
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
return children;
|
|
96
|
-
}
|
|
97
|
-
matchesSearch(label, path) {
|
|
98
|
-
if (!this.searchQuery.trim()) return true;
|
|
99
|
-
const q = this.searchQuery.toLowerCase();
|
|
100
|
-
return label.toLowerCase().includes(q) || path.toLowerCase().includes(q);
|
|
101
|
-
}
|
|
102
|
-
static isRecord(v) {
|
|
103
|
-
return v !== null && typeof v === "object" && !Array.isArray(v);
|
|
104
|
-
}
|
|
105
|
-
refreshAfterEdit() {
|
|
106
|
-
this.markDirty(true);
|
|
107
|
-
if (this.selectedPath) this.updateDetailForPath(this.selectedPath);
|
|
108
|
-
}
|
|
109
|
-
getValueAtPath(path) {
|
|
110
|
-
const parts = path.split(".").filter(Boolean);
|
|
111
|
-
if (parts.length === 0) return this.settings;
|
|
112
|
-
let current = this.settings;
|
|
113
|
-
for (const part of parts) {
|
|
114
|
-
if (current === null || current === void 0 || typeof current !== "object") return void 0;
|
|
115
|
-
current = current[part];
|
|
116
|
-
}
|
|
117
|
-
return current;
|
|
118
|
-
}
|
|
119
|
-
setAtInMemory(path, value) {
|
|
120
|
-
const parts = path.split(".").filter(Boolean);
|
|
121
|
-
if (parts.length === 0) return;
|
|
122
|
-
this.settings = this.deepSet(this.settings, parts, value);
|
|
123
|
-
}
|
|
124
|
-
deepSet(obj, pathParts, value) {
|
|
125
|
-
if (pathParts.length === 1) {
|
|
126
|
-
const key = pathParts[0];
|
|
127
|
-
if (Array.isArray(obj)) {
|
|
128
|
-
const idx = parseInt(key, 10);
|
|
129
|
-
if (isNaN(idx) || idx < 0) return obj;
|
|
130
|
-
const arr = [...obj];
|
|
131
|
-
arr[idx] = value;
|
|
132
|
-
return arr;
|
|
133
|
-
}
|
|
134
|
-
return { ...obj, [key]: value };
|
|
135
|
-
}
|
|
136
|
-
const [head, ...rest] = pathParts;
|
|
137
|
-
if (Array.isArray(obj)) {
|
|
138
|
-
const idx = parseInt(head, 10);
|
|
139
|
-
if (isNaN(idx) || idx < 0) return obj;
|
|
140
|
-
const arr = [...obj];
|
|
141
|
-
const current2 = arr[idx];
|
|
142
|
-
const next2 = current2 !== null && typeof current2 === "object" ? current2 : {};
|
|
143
|
-
arr[idx] = this.deepSet(next2, rest, value);
|
|
144
|
-
return arr;
|
|
145
|
-
}
|
|
146
|
-
const o = obj;
|
|
147
|
-
const current = o[head];
|
|
148
|
-
const next = current !== null && typeof current === "object" ? current : {};
|
|
149
|
-
return { ...o, [head]: this.deepSet(next, rest, value) };
|
|
150
|
-
}
|
|
151
|
-
getArrayItemLabel(item, index) {
|
|
152
|
-
if (LyraSettingsTree.isRecord(item)) {
|
|
153
|
-
if (typeof item.id === "string") return item.id;
|
|
154
|
-
if (typeof item.name === "string") return item.name;
|
|
155
|
-
}
|
|
156
|
-
return `Item ${index}`;
|
|
157
|
-
}
|
|
158
|
-
async updateDetailForPath(path) {
|
|
159
|
-
const containerSchema = appSettings.getSchemaForSettingKey(path);
|
|
160
|
-
const containerValue = this.getValueAtPath(path);
|
|
161
|
-
const valueObj = LyraSettingsTree.isRecord(containerValue) ? containerValue : null;
|
|
162
|
-
const isArray = Array.isArray(containerValue);
|
|
163
|
-
let rows;
|
|
164
|
-
if (isArray) {
|
|
165
|
-
const arr = containerValue;
|
|
166
|
-
const flat = [];
|
|
167
|
-
arr.forEach((item, index) => {
|
|
168
|
-
const subPath = `${path}.${index}`;
|
|
169
|
-
const groupLabel = this.getArrayItemLabel(item, index);
|
|
170
|
-
if (LyraSettingsTree.isRecord(item)) {
|
|
171
|
-
Object.keys(item).forEach((k) => {
|
|
172
|
-
flat.push({
|
|
173
|
-
key: k,
|
|
174
|
-
path: `${subPath}.${k}`,
|
|
175
|
-
title: k,
|
|
176
|
-
description: "",
|
|
177
|
-
schema: void 0,
|
|
178
|
-
value: item[k],
|
|
179
|
-
parentPath: subPath,
|
|
180
|
-
groupLabel
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
|
-
} else {
|
|
184
|
-
flat.push({
|
|
185
|
-
key: String(index),
|
|
186
|
-
path: subPath,
|
|
187
|
-
title: groupLabel,
|
|
188
|
-
description: `Array element ${index}.`,
|
|
189
|
-
schema: void 0,
|
|
190
|
-
value: item,
|
|
191
|
-
parentPath: path,
|
|
192
|
-
groupLabel
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
rows = flat;
|
|
197
|
-
} else if (valueObj !== null) {
|
|
198
|
-
const schemaProps = containerSchema?.properties;
|
|
199
|
-
const keys = schemaProps ? Object.keys(schemaProps) : Object.keys(valueObj);
|
|
200
|
-
rows = keys.map((key) => {
|
|
201
|
-
const subPath = `${path}.${key}`;
|
|
202
|
-
const propSchema = schemaProps?.[key];
|
|
203
|
-
const value = valueObj[key];
|
|
204
|
-
return {
|
|
205
|
-
key,
|
|
206
|
-
path: subPath,
|
|
207
|
-
title: propSchema?.title ?? key,
|
|
208
|
-
description: propSchema?.description ?? "",
|
|
209
|
-
schema: propSchema,
|
|
210
|
-
value,
|
|
211
|
-
parentPath: path
|
|
212
|
-
};
|
|
213
|
-
});
|
|
214
|
-
} else if (containerValue !== void 0 && containerValue !== null && typeof containerValue !== "object") {
|
|
215
|
-
const segment = path.split(".").pop() ?? path;
|
|
216
|
-
rows = [{
|
|
217
|
-
key: segment,
|
|
218
|
-
path,
|
|
219
|
-
title: segment,
|
|
220
|
-
description: "Edit value (no schema).",
|
|
221
|
-
schema: void 0,
|
|
222
|
-
value: containerValue
|
|
223
|
-
}];
|
|
224
|
-
} else {
|
|
225
|
-
rows = [];
|
|
226
|
-
}
|
|
227
|
-
rows.forEach((r) => {
|
|
228
|
-
if (r.title === void 0) r.title = r.key;
|
|
229
|
-
});
|
|
230
|
-
if (this.selectedPath !== path) return;
|
|
231
|
-
const category = appSettings.getCategories().find((c) => c.id === path);
|
|
232
|
-
this.detailForPath = path;
|
|
233
|
-
this.detailTitle = category?.label ?? containerSchema?.title ?? path;
|
|
234
|
-
this.detailRows = rows;
|
|
235
|
-
}
|
|
236
|
-
selectPath(path) {
|
|
237
|
-
this.selectedPath = path;
|
|
238
|
-
this.updateDetailForPath(path);
|
|
239
|
-
}
|
|
240
|
-
updated(changedProperties) {
|
|
241
|
-
super.updated?.(changedProperties);
|
|
242
|
-
if (changedProperties.has("selectedPath") && this.selectedPath !== this.detailForPath) {
|
|
243
|
-
if (this.selectedPath) this.updateDetailForPath(this.selectedPath);
|
|
244
|
-
else {
|
|
245
|
-
this.detailForPath = null;
|
|
246
|
-
this.detailRows = [];
|
|
247
|
-
this.detailTitle = "";
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
setRowValue(row, value) {
|
|
252
|
-
this.setAtInMemory(row.path, value);
|
|
253
|
-
this.refreshAfterEdit();
|
|
254
|
-
}
|
|
255
|
-
setRowValueFromJson(row, raw) {
|
|
256
|
-
try {
|
|
257
|
-
this.setRowValue(row, JSON.parse(raw));
|
|
258
|
-
} catch {
|
|
259
|
-
this.refreshAfterEdit();
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
renameKey(parentPath, oldKey, newKey) {
|
|
263
|
-
if (newKey.trim() === "" || newKey === oldKey) return;
|
|
264
|
-
const parent = this.getValueAtPath(parentPath);
|
|
265
|
-
if (!LyraSettingsTree.isRecord(parent)) return;
|
|
266
|
-
const value = parent[oldKey];
|
|
267
|
-
const updated = { ...parent };
|
|
268
|
-
delete updated[oldKey];
|
|
269
|
-
updated[newKey.trim()] = value;
|
|
270
|
-
this.setAtInMemory(parentPath, updated);
|
|
271
|
-
this.refreshAfterEdit();
|
|
272
|
-
}
|
|
273
|
-
deleteKey(parentPath, key) {
|
|
274
|
-
const parent = this.getValueAtPath(parentPath);
|
|
275
|
-
if (!LyraSettingsTree.isRecord(parent)) return;
|
|
276
|
-
const updated = { ...parent };
|
|
277
|
-
delete updated[key];
|
|
278
|
-
this.setAtInMemory(parentPath, updated);
|
|
279
|
-
this.refreshAfterEdit();
|
|
280
|
-
}
|
|
281
|
-
async addKeyToGroup(groupParentPath) {
|
|
282
|
-
const key = await promptDialog("New key name:", "");
|
|
283
|
-
if (!key?.trim()) return;
|
|
284
|
-
this.setAtInMemory(`${groupParentPath}.${key.trim()}`, null);
|
|
285
|
-
this.refreshAfterEdit();
|
|
286
|
-
}
|
|
287
|
-
deleteTopLevelKey(key) {
|
|
288
|
-
if (!(key in this.settings)) return;
|
|
289
|
-
const updated = { ...this.settings };
|
|
290
|
-
delete updated[key];
|
|
291
|
-
this.settings = updated;
|
|
292
|
-
this.markDirty(true);
|
|
293
|
-
if (this.selectedPath === key) {
|
|
294
|
-
this.selectedPath = null;
|
|
295
|
-
this.detailForPath = null;
|
|
296
|
-
this.detailRows = [];
|
|
297
|
-
this.detailTitle = "";
|
|
298
|
-
}
|
|
299
|
-
this.buildCategoryTree();
|
|
300
|
-
if (this.selectedPath) this.updateDetailForPath(this.selectedPath);
|
|
301
|
-
}
|
|
302
|
-
renderDetailControl(row) {
|
|
303
|
-
const schema = row.schema;
|
|
304
|
-
const type = schema?.type;
|
|
305
|
-
const enumValues = schema?.enum;
|
|
306
|
-
const current = row.value;
|
|
307
|
-
if (enumValues && Array.isArray(enumValues) && enumValues.length > 0) {
|
|
308
|
-
const options = enumValues.map((v) => String(v));
|
|
309
|
-
const value = current !== void 0 && current !== null ? String(current) : schema?.default !== void 0 ? String(schema.default) : options[0];
|
|
310
|
-
return html`
|
|
311
|
-
<wa-select
|
|
312
|
-
value=${value}
|
|
313
|
-
@change=${(e) => this.setRowValue(row, e.target.value)}
|
|
314
|
-
size="small">
|
|
315
|
-
${options.map((opt) => html`<wa-option value=${opt}>${opt}</wa-option>`)}
|
|
316
|
-
</wa-select>
|
|
317
|
-
`;
|
|
318
|
-
}
|
|
319
|
-
if (type === "boolean") {
|
|
320
|
-
const checked = current === true || current === void 0 && schema?.default === true;
|
|
321
|
-
return html`
|
|
322
|
-
<wa-switch
|
|
323
|
-
?checked=${checked}
|
|
324
|
-
@change=${(e) => this.setRowValue(row, e.target.checked)}
|
|
325
|
-
size="small">
|
|
326
|
-
</wa-switch>
|
|
327
|
-
`;
|
|
328
|
-
}
|
|
329
|
-
if (type === "number") {
|
|
330
|
-
const num = typeof current === "number" ? current : typeof schema?.default === "number" ? schema.default : 0;
|
|
331
|
-
return html`
|
|
332
|
-
<wa-number-input
|
|
333
|
-
.value=${String(num)}
|
|
334
|
-
@change=${(e) => this.setRowValue(row, Number(e.target.value))}
|
|
335
|
-
size="small">
|
|
336
|
-
</wa-number-input>
|
|
337
|
-
`;
|
|
338
|
-
}
|
|
339
|
-
const isObjectOrArray = current !== null && typeof current === "object";
|
|
340
|
-
if (isObjectOrArray && !schema && LyraSettingsTree.isRecord(current)) {
|
|
341
|
-
return this.renderObjectFields(row.path, current, 0);
|
|
342
|
-
}
|
|
343
|
-
if (isObjectOrArray) {
|
|
344
|
-
const str = JSON.stringify(current, null, 2);
|
|
345
|
-
return html`
|
|
346
|
-
<wa-textarea
|
|
347
|
-
.value=${str}
|
|
348
|
-
@blur=${(e) => this.setRowValueFromJson(row, e.target.value)}
|
|
349
|
-
rows="3">
|
|
350
|
-
</wa-textarea>
|
|
351
|
-
`;
|
|
352
|
-
}
|
|
353
|
-
return this.renderPrimitiveControl(row, current);
|
|
354
|
-
}
|
|
355
|
-
renderPrimitiveControl(row, current) {
|
|
356
|
-
const str = current !== void 0 && current !== null ? String(current) : "";
|
|
357
|
-
if (typeof current === "boolean") {
|
|
358
|
-
return html`
|
|
359
|
-
<wa-switch
|
|
360
|
-
?checked=${current}
|
|
361
|
-
@change=${(e) => this.setRowValue(row, e.target.checked)}
|
|
362
|
-
size="small">
|
|
363
|
-
</wa-switch>
|
|
364
|
-
`;
|
|
365
|
-
}
|
|
366
|
-
if (typeof current === "number") {
|
|
367
|
-
return html`
|
|
368
|
-
<wa-number-input
|
|
369
|
-
.value=${String(current)}
|
|
370
|
-
@change=${(e) => this.setRowValue(row, Number(e.target.value))}
|
|
371
|
-
size="small">
|
|
372
|
-
</wa-number-input>
|
|
373
|
-
`;
|
|
374
|
-
}
|
|
375
|
-
return html`
|
|
376
|
-
<wa-input
|
|
377
|
-
.value=${str}
|
|
378
|
-
@input=${(e) => this.setRowValue(row, e.target.value)}
|
|
379
|
-
size="small">
|
|
380
|
-
</wa-input>
|
|
381
|
-
`;
|
|
382
|
-
}
|
|
383
|
-
renderObjectFields(parentPath, obj, depth) {
|
|
384
|
-
const maxDepth = 2;
|
|
385
|
-
if (depth >= maxDepth) {
|
|
386
|
-
const str = JSON.stringify(obj, null, 2);
|
|
387
|
-
const row = { key: "", path: parentPath, title: "", description: "", value: obj };
|
|
388
|
-
return html`
|
|
389
|
-
<wa-textarea
|
|
390
|
-
.value=${str}
|
|
391
|
-
@blur=${(e) => this.setRowValueFromJson(row, e.target.value)}
|
|
392
|
-
rows="3">
|
|
393
|
-
</wa-textarea>
|
|
394
|
-
`;
|
|
395
|
-
}
|
|
396
|
-
const entries = Object.entries(obj);
|
|
397
|
-
return html`
|
|
398
|
-
<div class="nested-object" >
|
|
399
|
-
${entries.map(([k, v]) => {
|
|
400
|
-
const subPath = `${parentPath}.${k}`;
|
|
401
|
-
const subRow = { key: k, path: subPath, title: k, description: "", value: v, parentPath };
|
|
402
|
-
const isNestedObj = LyraSettingsTree.isRecord(v);
|
|
403
|
-
const isArray = Array.isArray(v);
|
|
404
|
-
return html`
|
|
405
|
-
<div class="nested-row">
|
|
406
|
-
<wa-input
|
|
407
|
-
.value=${k}
|
|
408
|
-
size="small"
|
|
409
|
-
style="width: 140px;"
|
|
410
|
-
@blur=${(e) => {
|
|
411
|
-
const newKey = e.target.value.trim();
|
|
412
|
-
if (newKey && newKey !== k) this.renameKey(parentPath, k, newKey);
|
|
413
|
-
}}>
|
|
414
|
-
</wa-input>
|
|
415
|
-
<span class="nested-sep">:</span>
|
|
416
|
-
${isNestedObj ? this.renderObjectFields(subPath, v, depth + 1) : isArray ? html`
|
|
417
|
-
<wa-textarea
|
|
418
|
-
.value=${JSON.stringify(v, null, 2)}
|
|
419
|
-
rows="2"
|
|
420
|
-
style="min-width: 200px;"
|
|
421
|
-
@blur=${(e) => this.setRowValueFromJson(subRow, e.target.value)}>
|
|
422
|
-
</wa-textarea>
|
|
423
|
-
` : this.renderPrimitiveControl(subRow, v)}
|
|
424
|
-
</div>
|
|
425
|
-
`;
|
|
426
|
-
})}
|
|
427
|
-
</div>
|
|
428
|
-
`;
|
|
429
|
-
}
|
|
430
|
-
renderDetailPanel() {
|
|
431
|
-
if (!this.selectedPath) {
|
|
432
|
-
return html`
|
|
433
|
-
<div class="detail-placeholder">
|
|
434
|
-
<wa-icon name="gear"></wa-icon>
|
|
435
|
-
<p>Select a category from the tree</p>
|
|
436
|
-
</div>
|
|
437
|
-
`;
|
|
438
|
-
}
|
|
439
|
-
if (this.detailForPath !== this.selectedPath) {
|
|
440
|
-
return html`
|
|
441
|
-
<div class="detail-panel">
|
|
442
|
-
<div class="detail-heading-row">
|
|
443
|
-
<h2 class="detail-heading">${this.selectedPath}</h2>
|
|
444
|
-
</div>
|
|
445
|
-
<div class="detail-placeholder">
|
|
446
|
-
<p>Loading…</p>
|
|
447
|
-
</div>
|
|
448
|
-
</div>
|
|
449
|
-
`;
|
|
450
|
-
}
|
|
451
|
-
const filteredRows = this.detailRows.filter((row) => {
|
|
452
|
-
if (!this.searchQuery.trim()) return true;
|
|
453
|
-
const q = this.searchQuery.toLowerCase();
|
|
454
|
-
return row.title.toLowerCase().includes(q) || row.description.toLowerCase().includes(q);
|
|
455
|
-
});
|
|
456
|
-
const containerValue = this.selectedPath ? this.getValueAtPath(this.selectedPath) : void 0;
|
|
457
|
-
const isObjectContainer = LyraSettingsTree.isRecord(containerValue);
|
|
458
|
-
const isTopLevel = this.selectedPath !== null && !this.selectedPath.includes(".");
|
|
459
|
-
const canAddToSelection = isObjectContainer || isTopLevel;
|
|
460
|
-
return html`
|
|
461
|
-
<div class="detail-panel">
|
|
462
|
-
<div class="detail-heading-row">
|
|
463
|
-
<h2 class="detail-heading">${this.detailTitle}</h2>
|
|
464
|
-
${canAddToSelection ? html`
|
|
465
|
-
<lyra-command size="small" icon="plus" title="Add setting" .action=${() => this.addKeyToGroup(this.selectedPath)}>Add</lyra-command>
|
|
466
|
-
` : ""}
|
|
467
|
-
${isTopLevel ? html`
|
|
468
|
-
<lyra-command size="small" icon="trash" title="Delete category" .action=${() => this.deleteTopLevelKey(this.selectedPath)}></lyra-command>
|
|
469
|
-
` : ""}
|
|
470
|
-
</div>
|
|
471
|
-
<wa-scroller class="detail-scroller" orientation="vertical">
|
|
472
|
-
${filteredRows.length === 0 ? html`
|
|
473
|
-
<div class="detail-empty">
|
|
474
|
-
${this.detailRows.length === 0 ? html`<p>No settings in this category. Add keys in the JSON file or register a JSON Schema for this path.</p>` : html`<p>No matching settings for the current search.</p>`}
|
|
475
|
-
</div>
|
|
476
|
-
` : repeat(
|
|
477
|
-
filteredRows,
|
|
478
|
-
(row) => row.path,
|
|
479
|
-
(row, index) => {
|
|
480
|
-
const prev = index > 0 ? filteredRows[index - 1] : null;
|
|
481
|
-
const showGroup = row.groupLabel && prev?.groupLabel !== row.groupLabel;
|
|
482
|
-
const inGroup = !!row.groupLabel;
|
|
483
|
-
return html`
|
|
484
|
-
${showGroup ? html`
|
|
485
|
-
<div class="detail-group-header">
|
|
486
|
-
<span>${row.groupLabel}</span>
|
|
487
|
-
<lyra-command size="small" icon="plus" title="Add setting" .action=${() => this.addKeyToGroup(row.parentPath)}>Add</lyra-command>
|
|
488
|
-
</div>
|
|
489
|
-
` : ""}
|
|
490
|
-
<div class="setting-row ${inGroup ? "setting-row-in-group" : ""}">
|
|
491
|
-
<div class="setting-meta">
|
|
492
|
-
${row.parentPath != null ? html`
|
|
493
|
-
<wa-input
|
|
494
|
-
.value=${row.key}
|
|
495
|
-
size="small"
|
|
496
|
-
class="editable-key setting-control-key"
|
|
497
|
-
@blur=${(e) => {
|
|
498
|
-
const newKey = e.target.value.trim();
|
|
499
|
-
if (newKey && newKey !== row.key) this.renameKey(row.parentPath, row.key, newKey);
|
|
500
|
-
}}>
|
|
501
|
-
</wa-input>
|
|
502
|
-
` : html`<span class="setting-title">${row.title}</span>`}
|
|
503
|
-
${row.description ? html`<p class="setting-description">${row.description}</p>` : ""}
|
|
504
|
-
</div>
|
|
505
|
-
<div class="setting-control">${this.renderDetailControl(row)}</div>
|
|
506
|
-
${row.parentPath != null ? html`
|
|
507
|
-
<lyra-command size="small" icon="trash" title="Delete setting" .action=${() => this.deleteKey(row.parentPath, row.key)}></lyra-command>
|
|
508
|
-
` : ""}
|
|
509
|
-
</div>
|
|
510
|
-
`;
|
|
511
|
-
}
|
|
512
|
-
)}
|
|
513
|
-
</wa-scroller>
|
|
514
|
-
</div>
|
|
515
|
-
`;
|
|
516
|
-
}
|
|
517
|
-
renderCategoryNode(node) {
|
|
518
|
-
const hasChildren = node.children.length > 0;
|
|
519
|
-
const isSelected = this.selectedPath === node.path;
|
|
520
|
-
return html`
|
|
521
|
-
<wa-tree-item ?expanded=${node.expanded}>
|
|
522
|
-
<div
|
|
523
|
-
class="tree-node-content ${isSelected ? "selected" : ""}"
|
|
524
|
-
@click=${() => this.selectPath(node.path)}
|
|
525
|
-
role="button"
|
|
526
|
-
tabindex="0"
|
|
527
|
-
@keydown=${(e) => e.key === "Enter" && this.selectPath(node.path)}>
|
|
528
|
-
<span class="tree-node-label">${node.label}</span>
|
|
529
|
-
</div>
|
|
530
|
-
${hasChildren ? node.children.map((child) => this.renderCategoryNode(child)) : ""}
|
|
531
|
-
</wa-tree-item>
|
|
532
|
-
`;
|
|
533
|
-
}
|
|
534
|
-
setAllExpanded(expanded) {
|
|
535
|
-
const tree = this.treeRef.value;
|
|
536
|
-
if (tree) {
|
|
537
|
-
tree.querySelectorAll("wa-tree-item").forEach((item) => {
|
|
538
|
-
item.expanded = expanded;
|
|
539
|
-
});
|
|
540
|
-
}
|
|
541
|
-
this.categoryTree = this.categoryTree.map((n) => this.setExpanded(n, expanded));
|
|
542
|
-
this.requestUpdate();
|
|
543
|
-
}
|
|
544
|
-
setExpanded(node, expanded) {
|
|
545
|
-
return {
|
|
546
|
-
...node,
|
|
547
|
-
expanded,
|
|
548
|
-
children: node.children.map((c) => this.setExpanded(c, expanded))
|
|
549
|
-
};
|
|
550
|
-
}
|
|
551
|
-
async addKey() {
|
|
552
|
-
const key = await promptDialog("Enter new top-level key name:", "");
|
|
553
|
-
if (!key?.trim()) return;
|
|
554
|
-
this.setAtInMemory(key.trim(), null);
|
|
555
|
-
this.markDirty(true);
|
|
556
|
-
this.buildCategoryTree();
|
|
557
|
-
}
|
|
558
|
-
save() {
|
|
559
|
-
appSettings.setAll(this.settings).then(() => {
|
|
560
|
-
this.markDirty(false);
|
|
561
|
-
}).catch((err) => {
|
|
562
|
-
console.error("Failed to save settings:", err);
|
|
563
|
-
});
|
|
564
|
-
}
|
|
565
|
-
renderToolbar() {
|
|
566
|
-
return html`
|
|
567
|
-
<wa-input
|
|
568
|
-
placeholder="Search settings"
|
|
569
|
-
.value=${this.searchQuery}
|
|
570
|
-
@input=${(e) => {
|
|
571
|
-
this.searchQuery = e.target.value;
|
|
572
|
-
this.buildCategoryTree();
|
|
573
|
-
}}
|
|
574
|
-
size="small"
|
|
575
|
-
class="toolbar-search">
|
|
576
|
-
</wa-input>
|
|
577
|
-
<lyra-command size="small" icon="plus" title="Add Key" .action=${() => this.addKey()}>Add Key</lyra-command>
|
|
578
|
-
<lyra-command size="small" icon="chevron-down" title="Expand All" .action=${() => this.setAllExpanded(true)}>Expand All</lyra-command>
|
|
579
|
-
<lyra-command size="small" icon="chevron-right" title="Collapse All" .action=${() => this.setAllExpanded(false)}>Collapse All</lyra-command>
|
|
580
|
-
`;
|
|
581
|
-
}
|
|
582
|
-
renderContent() {
|
|
583
|
-
return html`
|
|
584
|
-
<div class="settings-editor-container">
|
|
585
|
-
<wa-split-panel position="25" class="split-panel-fill">
|
|
586
|
-
<div slot="start" class="left-panel">
|
|
587
|
-
<wa-scroller class="tree-scroller" orientation="vertical">
|
|
588
|
-
${this.categoryTree.length === 0 ? html`
|
|
589
|
-
<div class="empty-state">
|
|
590
|
-
<wa-icon name="gear"></wa-icon>
|
|
591
|
-
<p>No settings.</p>
|
|
592
|
-
</div>
|
|
593
|
-
` : html`
|
|
594
|
-
<wa-tree ${ref(this.treeRef)}>
|
|
595
|
-
${this.categoryTree.map((node) => this.renderCategoryNode(node))}
|
|
596
|
-
</wa-tree>
|
|
597
|
-
`}
|
|
598
|
-
</wa-scroller>
|
|
599
|
-
</div>
|
|
600
|
-
<div slot="end" class="right-panel">
|
|
601
|
-
${this.renderDetailPanel()}
|
|
602
|
-
</div>
|
|
603
|
-
</wa-split-panel>
|
|
604
|
-
</div>
|
|
605
|
-
`;
|
|
606
|
-
}
|
|
607
|
-
};
|
|
608
|
-
LyraSettingsTree.styles = css`
|
|
609
|
-
:host {
|
|
610
|
-
display: flex;
|
|
611
|
-
flex-direction: column;
|
|
612
|
-
height: 100%;
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
.settings-editor-container {
|
|
616
|
-
flex: 1;
|
|
617
|
-
min-height: 0;
|
|
618
|
-
display: flex;
|
|
619
|
-
flex-direction: column;
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
.left-panel, .right-panel {
|
|
623
|
-
display: flex;
|
|
624
|
-
flex-direction: column;
|
|
625
|
-
min-height: 0;
|
|
626
|
-
overflow: hidden;
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
.tree-scroller, .detail-scroller {
|
|
630
|
-
flex: 1;
|
|
631
|
-
min-height: 0;
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
.tree-node-content {
|
|
635
|
-
cursor: pointer;
|
|
636
|
-
user-select: none;
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
.tree-node-content.selected {
|
|
640
|
-
font-weight: 600;
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
.detail-placeholder {
|
|
644
|
-
display: flex;
|
|
645
|
-
flex-direction: column;
|
|
646
|
-
align-items: center;
|
|
647
|
-
justify-content: center;
|
|
648
|
-
height: 100%;
|
|
649
|
-
text-align: center;
|
|
650
|
-
padding: 32px;
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
.detail-panel {
|
|
654
|
-
display: flex;
|
|
655
|
-
flex-direction: column;
|
|
656
|
-
height: 100%;
|
|
657
|
-
overflow: hidden;
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
.detail-heading-row {
|
|
661
|
-
display: flex;
|
|
662
|
-
align-items: center;
|
|
663
|
-
gap: 8px;
|
|
664
|
-
margin-bottom: 16px;
|
|
665
|
-
padding: 0 16px;
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
.detail-heading {
|
|
669
|
-
margin: 0;
|
|
670
|
-
flex: 1;
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
.detail-scroller {
|
|
674
|
-
padding: 0 16px 16px;
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
.detail-empty {
|
|
678
|
-
padding: 24px 0;
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
.detail-group-header {
|
|
682
|
-
display: flex;
|
|
683
|
-
align-items: center;
|
|
684
|
-
gap: 8px;
|
|
685
|
-
margin-top: 12px;
|
|
686
|
-
margin-bottom: 4px;
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
.detail-group-header:first-child {
|
|
690
|
-
margin-top: 0;
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
.nested-row {
|
|
694
|
-
display: flex;
|
|
695
|
-
align-items: center;
|
|
696
|
-
gap: 8px;
|
|
697
|
-
margin-bottom: 6px;
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
.setting-row {
|
|
701
|
-
display: flex;
|
|
702
|
-
flex-wrap: wrap;
|
|
703
|
-
gap: 12px;
|
|
704
|
-
align-items: flex-start;
|
|
705
|
-
padding: 12px 0;
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
.setting-row-in-group {
|
|
709
|
-
padding-left: 20px;
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
.setting-meta {
|
|
713
|
-
flex: 0 0 auto;
|
|
714
|
-
min-width: 140px;
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
.setting-title {
|
|
718
|
-
font-weight: 600;
|
|
719
|
-
display: block;
|
|
720
|
-
margin-bottom: 4px;
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
.setting-control {
|
|
724
|
-
flex: 1;
|
|
725
|
-
min-width: 0;
|
|
726
|
-
display: flex;
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
.setting-row command {
|
|
730
|
-
flex-shrink: 0;
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
.setting-control wa-input,
|
|
734
|
-
.setting-control wa-textarea,
|
|
735
|
-
.setting-control wa-number-input,
|
|
736
|
-
.setting-control wa-select {
|
|
737
|
-
flex: 1;
|
|
738
|
-
min-width: 0;
|
|
739
|
-
width: 100%;
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
.setting-meta .setting-control-key {
|
|
743
|
-
width: 160px;
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
.empty-state {
|
|
747
|
-
display: flex;
|
|
748
|
-
flex-direction: column;
|
|
749
|
-
align-items: center;
|
|
750
|
-
justify-content: center;
|
|
751
|
-
padding: 32px;
|
|
752
|
-
text-align: center;
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
.nested-object {
|
|
756
|
-
margin-left: 8px;
|
|
757
|
-
padding-left: 8px;
|
|
758
|
-
border-left: 2px solid var(--wa-color-neutral-85);
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
.toolbar-search {
|
|
762
|
-
width: 200px;
|
|
763
|
-
margin-right: 8px;
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
.split-panel-fill {
|
|
767
|
-
height: 100%;
|
|
768
|
-
}
|
|
769
|
-
`;
|
|
770
|
-
__decorateClass([
|
|
771
|
-
property({ attribute: false })
|
|
772
|
-
], LyraSettingsTree.prototype, "input", 2);
|
|
773
|
-
__decorateClass([
|
|
774
|
-
state()
|
|
775
|
-
], LyraSettingsTree.prototype, "settings", 2);
|
|
776
|
-
__decorateClass([
|
|
777
|
-
state()
|
|
778
|
-
], LyraSettingsTree.prototype, "categoryTree", 2);
|
|
779
|
-
__decorateClass([
|
|
780
|
-
state()
|
|
781
|
-
], LyraSettingsTree.prototype, "selectedPath", 2);
|
|
782
|
-
__decorateClass([
|
|
783
|
-
state()
|
|
784
|
-
], LyraSettingsTree.prototype, "detailRows", 2);
|
|
785
|
-
__decorateClass([
|
|
786
|
-
state()
|
|
787
|
-
], LyraSettingsTree.prototype, "detailTitle", 2);
|
|
788
|
-
__decorateClass([
|
|
789
|
-
state()
|
|
790
|
-
], LyraSettingsTree.prototype, "searchQuery", 2);
|
|
791
|
-
LyraSettingsTree = __decorateClass([
|
|
792
|
-
customElement("lyra-settings-tree")
|
|
793
|
-
], LyraSettingsTree);
|
|
794
|
-
const settingsTreeExtension = (_uiContext) => {
|
|
795
|
-
editorRegistry.registerEditorInputHandler({
|
|
796
|
-
editorId: "system.settings-tree",
|
|
797
|
-
label: "Settings",
|
|
798
|
-
ranking: 1e3,
|
|
799
|
-
canHandle: (input) => input.key === ".system.settings",
|
|
800
|
-
handle: async (input) => {
|
|
801
|
-
input.component = (id) => html`
|
|
802
|
-
<lyra-settings-tree id="${id}" .input=${input}></lyra-settings-tree>
|
|
803
|
-
`;
|
|
804
|
-
return input;
|
|
805
|
-
}
|
|
806
|
-
});
|
|
807
|
-
commandRegistry.registerHandler("open_settings", {
|
|
808
|
-
ranking: 100,
|
|
809
|
-
execute: () => {
|
|
810
|
-
const editorInput = {
|
|
811
|
-
title: "Settings",
|
|
812
|
-
data: {},
|
|
813
|
-
key: ".system.settings",
|
|
814
|
-
icon: "gear",
|
|
815
|
-
state: {}
|
|
816
|
-
};
|
|
817
|
-
editorRegistry.loadEditor(editorInput);
|
|
818
|
-
}
|
|
819
|
-
});
|
|
820
|
-
contributionRegistry.registerContribution(TOOLBAR_MAIN_RIGHT, {
|
|
821
|
-
command: "open_settings",
|
|
822
|
-
icon: "gear",
|
|
823
|
-
label: "Settings"
|
|
824
|
-
});
|
|
825
|
-
};
|
|
826
|
-
export {
|
|
827
|
-
settingsTreeExtension as default
|
|
828
|
-
};
|
|
829
|
-
//# sourceMappingURL=settings-tree-extension-qqh_Ohws.js.map
|