dsh-continual-evolve 0.13.0 → 0.14.1
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/README.md +10 -8
- package/README.zh.md +10 -8
- package/client/client.js +656 -162
- package/lib/card-routes.d.ts +3 -2
- package/lib/card-routes.js +87 -11
- package/lib/index.d.ts +7 -6
- package/lib/index.js +41 -9
- package/lib/memory-snapshot.d.ts +28 -0
- package/lib/memory-snapshot.js +57 -3
- package/lib/workspace-catalog.d.ts +30 -0
- package/lib/workspace-catalog.js +149 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +6 -4
package/client/client.js
CHANGED
|
@@ -17,12 +17,27 @@
|
|
|
17
17
|
* call with null (the bundle list row shows the package description; the
|
|
18
18
|
* card is the page).
|
|
19
19
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
20
|
+
* Card form (v0.14): the dshmarket SettingsCard shape, one for one — a
|
|
21
|
+
* collapsed-by-default framed card whose header is the toggle button
|
|
22
|
+
* (name + one-liner + rotating chevron), body rendered only when open, hover
|
|
23
|
+
* and open states on the frame (see that bundle's "why the chrome is
|
|
24
|
+
* hand-built" note: a flat, always-expanded box next to rows that collapse
|
|
25
|
+
* reads as another product). The stylesheet is injected once, like the
|
|
26
|
+
* host's own CSS-module tags.
|
|
27
|
+
*
|
|
28
|
+
* Content (v0.14, scope selector v0.15): aligned with ZCode's Settings → Memory
|
|
29
|
+
* viewer, which the .evolve store shape was itself aligned with — one workspace
|
|
30
|
+
* selected at a time behind a dropdown scope selector (workspaces come from the
|
|
31
|
+
* host registry, so the selector lists the same workspaces the workspace picker
|
|
32
|
+
* does), a file search box, per-file relative updated times, and a
|
|
33
|
+
* click-to-preview body served by the host's content endpoint (5 MiB cap,
|
|
34
|
+
* deleted/changed guards). The drift warnings (dangling index rows / unindexed
|
|
35
|
+
* files) stay: they are this plugin's OBSERVATION surface and a deliberate
|
|
36
|
+
* superset of ZCode's viewer.
|
|
37
|
+
* Locale/theme/primitives wiring unchanged from v0.13: `ctx.locale.register`
|
|
38
|
+
* + `bind`, `var(--dsw-alias-*)` tokens, primitives with plain-element
|
|
39
|
+
* fallbacks so an old host never blanks the settings dialog. Read-only
|
|
40
|
+
* projection, fetched at render time from this plugin's host routes
|
|
26
41
|
* (same-origin). No editor, no write path, no cached state.
|
|
27
42
|
*/
|
|
28
43
|
window.__ModuleLoader__.load({
|
|
@@ -65,34 +80,63 @@ window.__ModuleLoader__.load({
|
|
|
65
80
|
var NS = "dsh-continual-evolve";
|
|
66
81
|
var SLOT = "plugins.bundle.config";
|
|
67
82
|
var API_ROOT = "/dsh-continual-evolve/api/v1";
|
|
83
|
+
var STYLE_ID = "dsh-continual-evolve-card-css";
|
|
68
84
|
|
|
69
85
|
var zh = {
|
|
70
|
-
title: "
|
|
86
|
+
title: "工作区记忆",
|
|
87
|
+
desc: "各工作区 .evolve/memory/ 的只读投影。",
|
|
71
88
|
refresh: "刷新",
|
|
72
89
|
hint: "事实源是各工作区 .evolve/memory/ 下的 markdown 文件——模型原生读写;本卡片只展示,编辑请直接改文件。",
|
|
73
90
|
loading: "读取中…",
|
|
74
91
|
loadFailed: "卡片数据加载失败:",
|
|
75
|
-
empty: "
|
|
92
|
+
empty: "还没有任何工作区有记忆库——在某个工作区开一次会话后回来刷新。",
|
|
76
93
|
absent: "该工作区尚无记忆库(开一次会话自动创建)。",
|
|
77
94
|
readFailed: "记忆库读取失败:",
|
|
78
95
|
stats: "{files} 条记忆 · 索引 {index} 行",
|
|
96
|
+
filesHeading: "文件",
|
|
97
|
+
scopeLabel: "选择工作区",
|
|
98
|
+
searchPlaceholder: "搜索记忆文件…",
|
|
99
|
+
searchEmpty: "没有匹配的记忆文件。",
|
|
79
100
|
missing: "索引失联(索引引用但文件已删):",
|
|
80
101
|
unindexed: "未入索引(文件存在但索引没有行):",
|
|
81
102
|
readError: "读取失败:",
|
|
103
|
+
previewLoading: "正在加载文件…",
|
|
104
|
+
previewTooLarge: "该记忆文件超过 5 MiB 预览上限。",
|
|
105
|
+
previewDeleted: "该记忆文件已被删除,请刷新文件列表。",
|
|
106
|
+
previewFailed: "内容读取失败:",
|
|
107
|
+
justNow: "刚刚",
|
|
108
|
+
minutesAgo: "{count} 分钟前",
|
|
109
|
+
today: "今天 {time}",
|
|
110
|
+
yesterday: "昨天 {time}",
|
|
111
|
+
localeTag: "zh-CN",
|
|
82
112
|
};
|
|
83
113
|
var en = {
|
|
84
|
-
title: "Workspace
|
|
114
|
+
title: "Workspace Memory",
|
|
115
|
+
desc: "Read-only projection of each workspace's .evolve/memory/.",
|
|
85
116
|
refresh: "Refresh",
|
|
86
117
|
hint: "The source of truth is the markdown files under each workspace's .evolve/memory/ — read and written by the model; this card only displays them, edit the files directly.",
|
|
87
118
|
loading: "Loading…",
|
|
88
119
|
loadFailed: "Failed to load card data: ",
|
|
89
|
-
empty: "
|
|
120
|
+
empty: "No workspace has a memory store yet — open a session in a workspace, then come back and refresh.",
|
|
90
121
|
absent: "No memory store in this workspace yet (one is created when you open a session).",
|
|
91
122
|
readFailed: "Failed to read the memory store: ",
|
|
92
123
|
stats: "{files} memories · {index} index rows",
|
|
124
|
+
filesHeading: "Files",
|
|
125
|
+
scopeLabel: "Choose workspace",
|
|
126
|
+
searchPlaceholder: "Search memory files…",
|
|
127
|
+
searchEmpty: "No matching memory files.",
|
|
93
128
|
missing: "Dangling index (indexed but deleted): ",
|
|
94
129
|
unindexed: "Unindexed (on disk, missing from the index): ",
|
|
95
130
|
readError: "Read failed: ",
|
|
131
|
+
previewLoading: "Loading file…",
|
|
132
|
+
previewTooLarge: "This memory file exceeds the 5 MiB preview limit.",
|
|
133
|
+
previewDeleted: "This memory file has been deleted — refresh the file list.",
|
|
134
|
+
previewFailed: "Failed to read the content: ",
|
|
135
|
+
justNow: "Just now",
|
|
136
|
+
minutesAgo: "{count} min ago",
|
|
137
|
+
today: "Today {time}",
|
|
138
|
+
yesterday: "Yesterday {time}",
|
|
139
|
+
localeTag: "en-US",
|
|
96
140
|
};
|
|
97
141
|
|
|
98
142
|
function format(template, params) {
|
|
@@ -103,7 +147,42 @@ window.__ModuleLoader__.load({
|
|
|
103
147
|
}
|
|
104
148
|
|
|
105
149
|
/**
|
|
106
|
-
*
|
|
150
|
+
* Relative updated time, ZCode viewer style: just now / N minutes ago /
|
|
151
|
+
* today / yesterday, then a calendar rendering via Intl in the active
|
|
152
|
+
* language (the `localeTag` dictionary key carries that language out).
|
|
153
|
+
*/
|
|
154
|
+
function formatRelative(updatedAt, now, t) {
|
|
155
|
+
if (typeof updatedAt !== "number" || !isFinite(updatedAt) || updatedAt <= 0) {
|
|
156
|
+
return "";
|
|
157
|
+
}
|
|
158
|
+
var minute = 60000;
|
|
159
|
+
var diff = now - updatedAt;
|
|
160
|
+
if (diff < minute) {
|
|
161
|
+
return t("justNow");
|
|
162
|
+
}
|
|
163
|
+
if (diff < 60 * minute) {
|
|
164
|
+
return t("minutesAgo", { count: Math.floor(diff / minute) });
|
|
165
|
+
}
|
|
166
|
+
var date = new Date(updatedAt);
|
|
167
|
+
var time = new Intl.DateTimeFormat(t("localeTag"), { hour: "2-digit", minute: "2-digit" }).format(date);
|
|
168
|
+
var startOfDay = new Date(now);
|
|
169
|
+
startOfDay.setHours(0, 0, 0, 0);
|
|
170
|
+
if (updatedAt >= startOfDay.getTime()) {
|
|
171
|
+
return t("today", { time: time });
|
|
172
|
+
}
|
|
173
|
+
if (updatedAt >= startOfDay.getTime() - 24 * 60 * 60 * 1000) {
|
|
174
|
+
return t("yesterday", { time: time });
|
|
175
|
+
}
|
|
176
|
+
var sameYear = date.getFullYear() === new Date(now).getFullYear();
|
|
177
|
+
return new Intl.DateTimeFormat(t("localeTag"), {
|
|
178
|
+
month: "numeric",
|
|
179
|
+
day: "numeric",
|
|
180
|
+
year: sameYear ? undefined : "numeric",
|
|
181
|
+
}).format(date);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Assemble the card's view model: the workspace catalogue, then one
|
|
107
186
|
* snapshot per workspace. Network or API failure per workspace degrades
|
|
108
187
|
* to an `error` string on that workspace's entry — one bad store never
|
|
109
188
|
* blanks the whole card.
|
|
@@ -121,17 +200,20 @@ window.__ModuleLoader__.load({
|
|
|
121
200
|
var entries = await Promise.all(
|
|
122
201
|
workspaces.map(async function (workspace) {
|
|
123
202
|
var root = typeof workspace.root === "string" ? workspace.root : "";
|
|
124
|
-
var
|
|
203
|
+
var label =
|
|
204
|
+
typeof workspace.label === "string" && workspace.label.trim().length > 0
|
|
205
|
+
? workspace.label
|
|
206
|
+
: workspaceLabel(root);
|
|
125
207
|
try {
|
|
126
208
|
var snapshotResponse = await fetchImpl(API_ROOT + "/memory?root=" + encodeURIComponent(root));
|
|
127
209
|
if (!snapshotResponse.ok) {
|
|
128
|
-
return { root: root,
|
|
210
|
+
return { root: root, label: label, snapshot: null, error: "HTTP " + snapshotResponse.status };
|
|
129
211
|
}
|
|
130
|
-
return { root: root,
|
|
212
|
+
return { root: root, label: label, snapshot: await snapshotResponse.json(), error: null };
|
|
131
213
|
} catch (error) {
|
|
132
214
|
return {
|
|
133
215
|
root: root,
|
|
134
|
-
|
|
216
|
+
label: label,
|
|
135
217
|
snapshot: null,
|
|
136
218
|
error: error instanceof Error ? error.message : String(error),
|
|
137
219
|
};
|
|
@@ -141,157 +223,493 @@ window.__ModuleLoader__.load({
|
|
|
141
223
|
return { workspaces: entries };
|
|
142
224
|
}
|
|
143
225
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
226
|
+
/**
|
|
227
|
+
* Fetch one memory file's body for the preview. Outcomes mirror the
|
|
228
|
+
* endpoint's status mapping so the card can show the ZCode viewer's
|
|
229
|
+
* deleted / too-large / failed states instead of a raw error.
|
|
230
|
+
*
|
|
231
|
+
* @param {typeof fetch} fetchImpl - injectable for tests.
|
|
232
|
+
* @param {string} root - known workspace root.
|
|
233
|
+
* @param {string} file - plain .md file name inside that memory store.
|
|
234
|
+
* @returns {Promise<{status: "ready"|"deleted"|"tooLarge"|"failed", content: string, message: string}>}
|
|
235
|
+
*/
|
|
236
|
+
async function loadFileContent(fetchImpl, root, file) {
|
|
237
|
+
var url = API_ROOT + "/memory/file?root=" + encodeURIComponent(root) + "&file=" + encodeURIComponent(file);
|
|
238
|
+
try {
|
|
239
|
+
var response = await fetchImpl(url);
|
|
240
|
+
if (response.ok) {
|
|
241
|
+
var body = await response.json();
|
|
242
|
+
return {
|
|
243
|
+
status: "ready",
|
|
244
|
+
content: typeof body.content === "string" ? body.content : "",
|
|
245
|
+
message: "",
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
if (response.status === 404) {
|
|
249
|
+
return { status: "deleted", content: "", message: "" };
|
|
250
|
+
}
|
|
251
|
+
if (response.status === 413) {
|
|
252
|
+
return { status: "tooLarge", content: "", message: "" };
|
|
253
|
+
}
|
|
254
|
+
return { status: "failed", content: "", message: "HTTP " + response.status };
|
|
255
|
+
} catch (error) {
|
|
256
|
+
return {
|
|
257
|
+
status: "failed",
|
|
258
|
+
content: "",
|
|
259
|
+
message: error instanceof Error ? error.message : String(error),
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** Display label for a workspace: its directory name (ZCode shows a project name, not a path). */
|
|
265
|
+
function workspaceLabel(root) {
|
|
266
|
+
var normalized = String(root).replace(/[\\/]+$/, "");
|
|
267
|
+
var index = Math.max(normalized.lastIndexOf("/"), normalized.lastIndexOf("\\"));
|
|
268
|
+
return index >= 0 ? normalized.slice(index + 1) : normalized;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Inject the card stylesheet once, the way the host's own CSS-module
|
|
273
|
+
* tags work. The classes are prefixed `dce-` and every value falls back
|
|
274
|
+
* to a fixed color after the token, so an old theme never blanks text.
|
|
275
|
+
*/
|
|
276
|
+
function injectCardStyle() {
|
|
277
|
+
if (typeof document === "undefined") {
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
if (document.getElementById(STYLE_ID) !== null) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
var style = document.createElement("style");
|
|
284
|
+
style.id = STYLE_ID;
|
|
285
|
+
style.dataset.plugin = NS;
|
|
286
|
+
style.textContent = [
|
|
287
|
+
".dce-card{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);background:var(--dsw-alias-bg-layer-3,#fff);border-radius:12px;transition:border-color .16s,background .16s}",
|
|
288
|
+
".dce-card:hover{border-color:var(--dsw-alias-label-dimmed,#c8ccd4)}",
|
|
289
|
+
'.dce-card[data-open="true"]{background:var(--dsw-alias-bg-layer-2,#f7f8fa);border-color:var(--dsw-alias-label-dimmed,#c8ccd4)}',
|
|
290
|
+
".dce-head{appearance:none;-webkit-appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}",
|
|
291
|
+
".dce-head:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#4f6ef7);outline-offset:-2px}",
|
|
292
|
+
".dce-head-text{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}",
|
|
293
|
+
".dce-name{color:var(--dsw-alias-label-primary,#1f2328);font-size:15px;font-weight:600;line-height:1.4}",
|
|
294
|
+
".dce-desc{color:var(--dsw-alias-label-tertiary,#8b93a1);font-size:13px;line-height:1.5}",
|
|
295
|
+
".dce-chevron{color:var(--dsw-alias-label-tertiary,#8b93a1);flex:none;transition:transform .16s;display:inline-flex}",
|
|
296
|
+
'.dce-chevron[data-open="true"]{transform:rotate(180deg)}',
|
|
297
|
+
".dce-body{border-top:1px solid var(--dsw-alias-border-l2,#e5e7eb);margin:0 16px;padding:12px 0 14px;display:flex;flex-direction:column;gap:10px}",
|
|
298
|
+
".dce-hint{color:var(--dsw-alias-label-tertiary,#8b93a1);font-size:12px;line-height:18px}",
|
|
299
|
+
".dce-empty{border:1px dashed var(--dsw-alias-border-l3,#d1d9e0);border-radius:10px;padding:16px;text-align:center;color:var(--dsw-alias-label-tertiary,#8b93a1);font-size:13px;line-height:20px}",
|
|
300
|
+
".dce-scope-wrap{position:relative;display:inline-flex;min-width:0;max-width:100%;align-self:flex-start}",
|
|
301
|
+
".dce-scope{display:inline-flex;align-items:center;gap:8px;max-width:100%;padding:4px 10px;border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:999px;background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-primary,#1f2328);font:inherit;font-size:12px;line-height:18px;cursor:pointer}",
|
|
302
|
+
".dce-scope:hover{border-color:var(--dsw-alias-label-dimmed,#c8ccd4)}",
|
|
303
|
+
".dce-scope:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#4f6ef7);outline-offset:1px}",
|
|
304
|
+
".dce-scope-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}",
|
|
305
|
+
".dce-scope-caret{display:inline-flex;color:var(--dsw-alias-label-tertiary,#8b93a1)}",
|
|
306
|
+
".dce-menu{position:absolute;top:calc(100% + 6px);left:0;z-index:20;min-width:240px;max-width:min(420px,80vw);max-height:320px;overflow:auto;padding:4px;border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:10px;background:var(--dsw-alias-bg-layer-1,#fff);box-shadow:0 8px 24px rgba(0,0,0,.12)}",
|
|
307
|
+
".dce-menu-item{display:flex;flex-direction:column;gap:2px;width:100%;padding:6px 10px;border:0;border-radius:8px;background:0 0;font:inherit;color:inherit;text-align:left;cursor:pointer}",
|
|
308
|
+
".dce-menu-item:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(0,0,0,.03))}",
|
|
309
|
+
'.dce-menu-item[data-active="true"]{background:var(--dsw-alias-bg-module-platform,#eef1f4)}',
|
|
310
|
+
".dce-menu-label{color:var(--dsw-alias-label-primary,#1f2328);font-size:13px;line-height:18px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}",
|
|
311
|
+
".dce-menu-path{color:var(--dsw-alias-label-tertiary,#8b93a1);font-size:11px;line-height:16px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}",
|
|
312
|
+
".dce-search{width:100%;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l4,#d8dee4);border-radius:var(--dsw-radius-md,8px);background:var(--dsw-alias-bg-layer-1,#fff);height:32px;color:var(--dsw-alias-label-primary,#1f2328);font:inherit;font-size:12px;padding:0 10px;outline:none}",
|
|
313
|
+
".dce-search::placeholder{color:var(--dsw-alias-label-tertiary,#8b93a1)}",
|
|
314
|
+
".dce-search:focus-visible{border-color:var(--dsw-alias-brand-primary,#4f6ef7)}",
|
|
315
|
+
".dce-files-head{display:flex;align-items:center;gap:10px;min-height:28px}",
|
|
316
|
+
".dce-files-title{color:var(--dsw-alias-label-primary,#1f2328);font-size:13px;font-weight:600;line-height:18px}",
|
|
317
|
+
".dce-files-count{color:var(--dsw-alias-label-tertiary,#8b93a1);font-size:12px;line-height:18px}",
|
|
318
|
+
".dce-spacer{flex:1}",
|
|
319
|
+
".dce-list{margin:0;padding:0;list-style:none;border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:10px;overflow:hidden;background:var(--dsw-alias-bg-layer-1,#fff)}",
|
|
320
|
+
".dce-item+.dce-item{border-top:1px solid var(--dsw-alias-border-l2,#e5e7eb)}",
|
|
321
|
+
".dce-row{display:flex;width:100%;align-items:center;gap:10px;padding:8px 12px;background:0 0;border:0;font:inherit;color:inherit;text-align:left;cursor:pointer}",
|
|
322
|
+
".dce-row:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(0,0,0,.03))}",
|
|
323
|
+
".dce-row:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#4f6ef7);outline-offset:-2px}",
|
|
324
|
+
".dce-file-name{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-primary,#1f2328);font-size:13px;font-weight:500;line-height:18px}",
|
|
325
|
+
".dce-file-time{flex:none;color:var(--dsw-alias-label-tertiary,#8b93a1);font-size:11px;line-height:16px}",
|
|
326
|
+
".dce-preview{margin:0;padding:8px 12px 10px;background:var(--dsw-alias-bg-module-platform,#eef1f4);border-top:1px solid var(--dsw-alias-border-l2,#e5e7eb)}",
|
|
327
|
+
".dce-pre{margin:0;max-height:240px;overflow:auto;font-family:var(--ds-font-family-code,ui-monospace,Menlo,monospace);font-size:11px;line-height:17px;color:var(--dsw-alias-label-primary,#1f2328);white-space:pre-wrap;word-break:break-word}",
|
|
328
|
+
".dce-workspace{display:flex;flex-direction:column;gap:10px}",
|
|
329
|
+
".dce-stats{color:var(--dsw-alias-label-secondary,#6b7280);font-size:12px;line-height:18px}",
|
|
330
|
+
".dce-warn{color:var(--dsw-alias-state-warn-primary,#b45309);font-size:12px;line-height:18px}",
|
|
331
|
+
".dce-error{color:var(--dsw-alias-state-error-primary,#dc2626);font-size:12px;line-height:18px}",
|
|
332
|
+
".dce-fallback-btn{background:var(--dsw-alias-bg-layer-2,#f3f4f6);color:var(--dsw-alias-label-primary,#1f2328);border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:6px;padding:3px 10px;font-size:12px;line-height:18px;cursor:pointer}",
|
|
333
|
+
].join("\n");
|
|
334
|
+
document.head.appendChild(style);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/** Chevron from the host primitives, or a plain glyph when they are absent. */
|
|
338
|
+
function Chevron() {
|
|
339
|
+
if (
|
|
340
|
+
primitives !== undefined &&
|
|
341
|
+
primitives !== null &&
|
|
342
|
+
typeof primitives.IconChevronDownOutlineRegular !== "undefined" &&
|
|
343
|
+
primitives.IconChevronDownOutlineRegular !== null
|
|
344
|
+
) {
|
|
345
|
+
return createElement(primitives.IconChevronDownOutlineRegular, { size: 14, "aria-hidden": "true" });
|
|
346
|
+
}
|
|
347
|
+
return createElement("span", { "aria-hidden": "true" }, "▾");
|
|
348
|
+
}
|
|
203
349
|
|
|
204
350
|
function RefreshButton(props) {
|
|
205
351
|
var UI = props.UI;
|
|
206
352
|
var t = props.t;
|
|
207
353
|
var onClick = props.onClick;
|
|
208
354
|
if (UI !== null && UI !== undefined && typeof UI.Button !== "undefined" && UI.Button !== null) {
|
|
209
|
-
return createElement(
|
|
210
|
-
UI.Button,
|
|
211
|
-
{ variant: "outline", size: "sm", onClick: onClick },
|
|
212
|
-
t("refresh"),
|
|
213
|
-
);
|
|
355
|
+
return createElement(UI.Button, { variant: "outline", size: "sm", onClick: onClick }, t("refresh"));
|
|
214
356
|
}
|
|
215
|
-
return createElement(
|
|
357
|
+
return createElement(
|
|
358
|
+
"button",
|
|
359
|
+
{ type: "button", className: "dce-fallback-btn", onClick: onClick },
|
|
360
|
+
t("refresh"),
|
|
361
|
+
);
|
|
216
362
|
}
|
|
217
363
|
|
|
218
|
-
/** One
|
|
219
|
-
function
|
|
220
|
-
var
|
|
364
|
+
/** One memory file row: name + relative updated time, click toggles the body preview. */
|
|
365
|
+
function FileRow(props) {
|
|
366
|
+
var file = props.file;
|
|
367
|
+
var now = props.now;
|
|
221
368
|
var t = props.t;
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if (snapshot === null || snapshot === undefined || !snapshot.exists) {
|
|
232
|
-
return createElement(
|
|
233
|
-
"div",
|
|
234
|
-
{ style: SECTION_STYLE },
|
|
235
|
-
createElement("div", { style: ROOT_STYLE }, entry.root),
|
|
236
|
-
createElement("div", { style: HINT_STYLE }, t("absent")),
|
|
237
|
-
);
|
|
238
|
-
}
|
|
239
|
-
if (snapshot.readError !== null && snapshot.readError !== undefined) {
|
|
240
|
-
return createElement(
|
|
241
|
-
"div",
|
|
242
|
-
{ style: SECTION_STYLE },
|
|
243
|
-
createElement("div", { style: ROOT_STYLE }, entry.root),
|
|
244
|
-
createElement("div", { style: ERROR_STYLE }, t("readFailed") + snapshot.readError),
|
|
245
|
-
);
|
|
369
|
+
var expanded = props.expanded;
|
|
370
|
+
var preview = props.preview;
|
|
371
|
+
var onToggle = props.onToggle;
|
|
372
|
+
var rowChildren = [
|
|
373
|
+
createElement("span", { key: "name", className: "dce-file-name" }, file.file),
|
|
374
|
+
];
|
|
375
|
+
var time = formatRelative(file.updatedAt, now, t);
|
|
376
|
+
if (time !== "") {
|
|
377
|
+
rowChildren.push(createElement("span", { key: "time", className: "dce-file-time" }, time));
|
|
246
378
|
}
|
|
247
379
|
var children = [
|
|
248
|
-
createElement("div", { key: "root", style: ROOT_STYLE }, entry.root),
|
|
249
380
|
createElement(
|
|
250
|
-
"
|
|
251
|
-
{
|
|
252
|
-
|
|
381
|
+
"button",
|
|
382
|
+
{
|
|
383
|
+
key: "row",
|
|
384
|
+
type: "button",
|
|
385
|
+
className: "dce-row",
|
|
386
|
+
"aria-expanded": expanded ? "true" : "false",
|
|
387
|
+
onClick: onToggle,
|
|
388
|
+
},
|
|
389
|
+
rowChildren,
|
|
253
390
|
),
|
|
254
391
|
];
|
|
255
|
-
if (
|
|
256
|
-
|
|
257
|
-
|
|
392
|
+
if (expanded) {
|
|
393
|
+
var body = null;
|
|
394
|
+
if (preview === null || preview.file !== file.file) {
|
|
395
|
+
body = createElement("div", { className: "dce-hint" }, t("previewLoading"));
|
|
396
|
+
} else if (preview.status === "loading") {
|
|
397
|
+
body = createElement("div", { className: "dce-hint" }, t("previewLoading"));
|
|
398
|
+
} else if (preview.status === "ready") {
|
|
399
|
+
body = createElement("pre", { className: "dce-pre" }, preview.content);
|
|
400
|
+
} else if (preview.status === "deleted") {
|
|
401
|
+
body = createElement("div", { className: "dce-hint" }, t("previewDeleted"));
|
|
402
|
+
} else if (preview.status === "tooLarge") {
|
|
403
|
+
body = createElement("div", { className: "dce-hint" }, t("previewTooLarge"));
|
|
404
|
+
} else {
|
|
405
|
+
body = createElement("div", { className: "dce-error" }, t("previewFailed") + preview.message);
|
|
406
|
+
}
|
|
407
|
+
children.push(createElement("div", { key: "preview", className: "dce-preview" }, body));
|
|
408
|
+
}
|
|
409
|
+
return createElement("li", { className: "dce-item" }, children);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/** Leading "switch scope" marker from the host primitives, or nothing. */
|
|
413
|
+
function ScopeMark() {
|
|
414
|
+
if (
|
|
415
|
+
primitives !== undefined &&
|
|
416
|
+
primitives !== null &&
|
|
417
|
+
typeof primitives.IconChevronsUpDownOutlineRegular !== "undefined" &&
|
|
418
|
+
primitives.IconChevronsUpDownOutlineRegular !== null
|
|
419
|
+
) {
|
|
420
|
+
return createElement(primitives.IconChevronsUpDownOutlineRegular, { size: 14, "aria-hidden": "true" });
|
|
421
|
+
}
|
|
422
|
+
return null;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* The workspace scope selector, ZCode's Settings → Memory shape: one
|
|
427
|
+
* scope at a time behind a dropdown (leading marker + current workspace
|
|
428
|
+
* label + chevron), never a row of chips. A chip row can only render
|
|
429
|
+
* when several workspaces are known, so in the common single-workspace
|
|
430
|
+
* case it renders nothing at all and the capability reads as missing.
|
|
431
|
+
* The menu closes on select, on Escape and on a click outside.
|
|
432
|
+
*/
|
|
433
|
+
function WorkspaceScopeMenu(props) {
|
|
434
|
+
var workspaces = props.workspaces;
|
|
435
|
+
var selected = props.selected;
|
|
436
|
+
var onSelect = props.onSelect;
|
|
437
|
+
var t = props.t;
|
|
438
|
+
var UI = props.UI;
|
|
439
|
+
var openState = useState(false);
|
|
440
|
+
var open = openState[0];
|
|
441
|
+
var setOpen = openState[1];
|
|
442
|
+
useEffect(
|
|
443
|
+
function () {
|
|
444
|
+
if (!open || typeof document === "undefined") {
|
|
445
|
+
return undefined;
|
|
446
|
+
}
|
|
447
|
+
var close = function () {
|
|
448
|
+
setOpen(false);
|
|
449
|
+
};
|
|
450
|
+
var onKeyDown = function (event) {
|
|
451
|
+
if (event.key === "Escape") {
|
|
452
|
+
close();
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
document.addEventListener("click", close);
|
|
456
|
+
document.addEventListener("keydown", onKeyDown);
|
|
457
|
+
return function () {
|
|
458
|
+
document.removeEventListener("click", close);
|
|
459
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
460
|
+
};
|
|
461
|
+
},
|
|
462
|
+
[open],
|
|
463
|
+
);
|
|
464
|
+
var current = null;
|
|
465
|
+
for (var index = 0; index < workspaces.length; index++) {
|
|
466
|
+
if (workspaces[index].root === selected) {
|
|
467
|
+
current = workspaces[index];
|
|
468
|
+
break;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
if (current === null && workspaces.length > 0) {
|
|
472
|
+
current = workspaces[0];
|
|
473
|
+
}
|
|
474
|
+
var label = current === null ? "" : current.label || workspaceLabel(current.root);
|
|
475
|
+
var scopeChildren = [
|
|
476
|
+
createElement(ScopeMark, { key: "mark" }),
|
|
477
|
+
createElement("span", { key: "label", className: "dce-scope-label" }, label),
|
|
478
|
+
createElement("span", { key: "caret", className: "dce-scope-caret" }, createElement(Chevron, null)),
|
|
479
|
+
];
|
|
480
|
+
var triggerProps = {
|
|
481
|
+
type: "button",
|
|
482
|
+
"aria-haspopup": "menu",
|
|
483
|
+
"aria-expanded": open ? "true" : "false",
|
|
484
|
+
"aria-label": t("scopeLabel"),
|
|
485
|
+
onClick: function () {
|
|
486
|
+
setOpen(!open);
|
|
487
|
+
},
|
|
488
|
+
};
|
|
489
|
+
var trigger = null;
|
|
490
|
+
if (UI !== null && UI !== undefined && typeof UI.Button !== "undefined" && UI.Button !== null) {
|
|
491
|
+
trigger = createElement(
|
|
492
|
+
UI.Button,
|
|
493
|
+
{
|
|
494
|
+
key: "trigger",
|
|
495
|
+
variant: "outline",
|
|
496
|
+
size: "sm",
|
|
497
|
+
type: triggerProps.type,
|
|
498
|
+
"aria-haspopup": triggerProps["aria-haspopup"],
|
|
499
|
+
"aria-expanded": triggerProps["aria-expanded"],
|
|
500
|
+
"aria-label": triggerProps["aria-label"],
|
|
501
|
+
onClick: triggerProps.onClick,
|
|
502
|
+
},
|
|
503
|
+
scopeChildren,
|
|
258
504
|
);
|
|
505
|
+
} else {
|
|
506
|
+
trigger = createElement(
|
|
507
|
+
"button",
|
|
508
|
+
{
|
|
509
|
+
key: "trigger",
|
|
510
|
+
type: triggerProps.type,
|
|
511
|
+
className: "dce-scope",
|
|
512
|
+
"aria-haspopup": triggerProps["aria-haspopup"],
|
|
513
|
+
"aria-expanded": triggerProps["aria-expanded"],
|
|
514
|
+
"aria-label": triggerProps["aria-label"],
|
|
515
|
+
onClick: triggerProps.onClick,
|
|
516
|
+
},
|
|
517
|
+
scopeChildren,
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
var menu = null;
|
|
521
|
+
if (open) {
|
|
522
|
+
menu = createElement(
|
|
523
|
+
"div",
|
|
524
|
+
{ key: "menu", className: "dce-menu", role: "menu", "aria-label": t("scopeLabel") },
|
|
525
|
+
workspaces.map(function (workspace) {
|
|
526
|
+
return createElement(
|
|
527
|
+
"button",
|
|
528
|
+
{
|
|
529
|
+
key: workspace.root,
|
|
530
|
+
type: "button",
|
|
531
|
+
role: "menuitemradio",
|
|
532
|
+
"aria-checked": workspace.root === selected ? "true" : "false",
|
|
533
|
+
className: "dce-menu-item",
|
|
534
|
+
"data-active": workspace.root === selected ? "true" : "false",
|
|
535
|
+
onClick: function () {
|
|
536
|
+
setOpen(false);
|
|
537
|
+
if (workspace.root !== selected) {
|
|
538
|
+
onSelect(workspace.root);
|
|
539
|
+
}
|
|
540
|
+
},
|
|
541
|
+
},
|
|
542
|
+
// The registry allows duplicate titles, so the root
|
|
543
|
+
// disambiguates two workspaces that read the same.
|
|
544
|
+
createElement("span", { key: "label", className: "dce-menu-label" }, workspace.label || workspaceLabel(workspace.root)),
|
|
545
|
+
createElement("span", { key: "root", className: "dce-menu-path" }, workspace.root),
|
|
546
|
+
);
|
|
547
|
+
}),
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
return createElement("div", { key: "scope", className: "dce-scope-wrap" }, trigger, menu);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/** One workspace's memory store: stats, drift warnings, searchable file list with previews. */
|
|
554
|
+
function WorkspaceBlock(props) {
|
|
555
|
+
var entry = props.entry;
|
|
556
|
+
var selected = props.selected;
|
|
557
|
+
var onSelect = props.onSelect;
|
|
558
|
+
var t = props.t;
|
|
559
|
+
var UI = props.UI;
|
|
560
|
+
var now = props.now;
|
|
561
|
+
var expandedFile = props.expandedFile;
|
|
562
|
+
var preview = props.preview;
|
|
563
|
+
var onToggleFile = props.onToggleFile;
|
|
564
|
+
var onRefresh = props.onRefresh;
|
|
565
|
+
var query = props.query;
|
|
566
|
+
var onQueryChange = props.onQueryChange;
|
|
567
|
+
var scope = createElement(WorkspaceScopeMenu, {
|
|
568
|
+
key: "scope",
|
|
569
|
+
workspaces: entry.workspaces.map(function (workspace) {
|
|
570
|
+
return { root: workspace.root, label: workspace.label };
|
|
571
|
+
}),
|
|
572
|
+
selected: selected,
|
|
573
|
+
onSelect: onSelect,
|
|
574
|
+
t: t,
|
|
575
|
+
UI: UI,
|
|
576
|
+
});
|
|
577
|
+
var active = entry.workspaces.find(function (workspace) {
|
|
578
|
+
return workspace.root === selected;
|
|
579
|
+
});
|
|
580
|
+
if (active === undefined) {
|
|
581
|
+
return createElement("div", { key: "block", className: "dce-workspace" }, scope);
|
|
259
582
|
}
|
|
260
|
-
|
|
261
|
-
|
|
583
|
+
var body = null;
|
|
584
|
+
if (active.error !== null && active.error !== undefined) {
|
|
585
|
+
body = [
|
|
586
|
+
createElement("div", { key: "root", className: "dce-stats" }, active.root),
|
|
587
|
+
createElement("div", { key: "err", className: "dce-error" }, t("readError") + active.error),
|
|
588
|
+
];
|
|
589
|
+
} else if (active.snapshot === null || active.snapshot === undefined || !active.snapshot.exists) {
|
|
590
|
+
body = createElement("div", { className: "dce-empty" }, t("absent"));
|
|
591
|
+
} else if (active.snapshot.readError !== null && active.snapshot.readError !== undefined) {
|
|
592
|
+
body = [
|
|
593
|
+
createElement("div", { key: "root", className: "dce-stats" }, active.root),
|
|
594
|
+
createElement("div", { key: "err", className: "dce-error" }, t("readFailed") + active.snapshot.readError),
|
|
595
|
+
];
|
|
596
|
+
} else {
|
|
597
|
+
var snapshot = active.snapshot;
|
|
598
|
+
var normalizedQuery = String(query).trim().toLocaleLowerCase();
|
|
599
|
+
var files = snapshot.files.filter(function (file) {
|
|
600
|
+
if (normalizedQuery.length === 0) {
|
|
601
|
+
return true;
|
|
602
|
+
}
|
|
603
|
+
return [file.file, file.name, file.description, file.type]
|
|
604
|
+
.filter(function (value) {
|
|
605
|
+
return typeof value === "string";
|
|
606
|
+
})
|
|
607
|
+
.some(function (value) {
|
|
608
|
+
return value.toLocaleLowerCase().includes(normalizedQuery);
|
|
609
|
+
});
|
|
610
|
+
});
|
|
611
|
+
var parts = [
|
|
262
612
|
createElement(
|
|
263
613
|
"div",
|
|
264
|
-
{ key: "
|
|
265
|
-
t("
|
|
614
|
+
{ key: "stats", className: "dce-stats" },
|
|
615
|
+
t("stats", { files: snapshot.fileCount, index: snapshot.indexEntryCount }),
|
|
266
616
|
),
|
|
617
|
+
];
|
|
618
|
+
if (snapshot.missingFiles.length > 0) {
|
|
619
|
+
parts.push(
|
|
620
|
+
createElement("div", { key: "missing", className: "dce-warn" }, t("missing") + snapshot.missingFiles.join("、")),
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
if (snapshot.unindexedFiles.length > 0) {
|
|
624
|
+
parts.push(
|
|
625
|
+
createElement(
|
|
626
|
+
"div",
|
|
627
|
+
{ key: "unindexed", className: "dce-warn" },
|
|
628
|
+
t("unindexed") + snapshot.unindexedFiles.join("、"),
|
|
629
|
+
),
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
parts.push(
|
|
633
|
+
createElement("input", {
|
|
634
|
+
key: "search",
|
|
635
|
+
type: "search",
|
|
636
|
+
className: "dce-search",
|
|
637
|
+
value: query,
|
|
638
|
+
placeholder: t("searchPlaceholder"),
|
|
639
|
+
"aria-label": t("searchPlaceholder"),
|
|
640
|
+
onChange: function (event) {
|
|
641
|
+
onQueryChange(event.currentTarget.value);
|
|
642
|
+
},
|
|
643
|
+
}),
|
|
267
644
|
);
|
|
645
|
+
parts.push(
|
|
646
|
+
createElement(
|
|
647
|
+
"div",
|
|
648
|
+
{ key: "head", className: "dce-files-head" },
|
|
649
|
+
createElement("span", { className: "dce-files-title" }, t("filesHeading")),
|
|
650
|
+
createElement("span", { className: "dce-files-count" }, String(files.length)),
|
|
651
|
+
createElement("span", { className: "dce-spacer" }),
|
|
652
|
+
createElement(RefreshButton, {
|
|
653
|
+
UI: UI,
|
|
654
|
+
t: t,
|
|
655
|
+
onClick: onRefresh,
|
|
656
|
+
}),
|
|
657
|
+
),
|
|
658
|
+
);
|
|
659
|
+
if (files.length === 0) {
|
|
660
|
+
parts.push(createElement("div", { key: "none", className: "dce-empty" }, t("searchEmpty")));
|
|
661
|
+
} else {
|
|
662
|
+
parts.push(
|
|
663
|
+
createElement(
|
|
664
|
+
"ul",
|
|
665
|
+
{ key: "files", className: "dce-list" },
|
|
666
|
+
files.map(function (file) {
|
|
667
|
+
return createElement(FileRow, {
|
|
668
|
+
key: file.file,
|
|
669
|
+
file: file,
|
|
670
|
+
now: now,
|
|
671
|
+
t: t,
|
|
672
|
+
expanded: expandedFile === file.file,
|
|
673
|
+
preview: preview,
|
|
674
|
+
onToggle: function () {
|
|
675
|
+
onToggleFile(file.file);
|
|
676
|
+
},
|
|
677
|
+
});
|
|
678
|
+
}),
|
|
679
|
+
),
|
|
680
|
+
);
|
|
681
|
+
}
|
|
682
|
+
body = parts;
|
|
268
683
|
}
|
|
269
|
-
|
|
270
|
-
createElement(
|
|
271
|
-
"ul",
|
|
272
|
-
{ key: "files", style: LIST_STYLE },
|
|
273
|
-
snapshot.files.map(function (file) {
|
|
274
|
-
return createElement(
|
|
275
|
-
"li",
|
|
276
|
-
{ key: file.file },
|
|
277
|
-
createElement("strong", null, file.file),
|
|
278
|
-
file.description !== "" ? " — " + file.description : "",
|
|
279
|
-
);
|
|
280
|
-
}),
|
|
281
|
-
),
|
|
282
|
-
);
|
|
283
|
-
return createElement("div", { style: SECTION_STYLE }, children);
|
|
684
|
+
return createElement("div", { key: "block", className: "dce-workspace" }, scope, body);
|
|
284
685
|
}
|
|
285
686
|
|
|
286
|
-
/**
|
|
687
|
+
/**
|
|
688
|
+
* The card: a collapsed-by-default framed disclosure (dshmarket
|
|
689
|
+
* SettingsCard shape) whose open body is the ZCode-memory-viewer-shaped
|
|
690
|
+
* read-only projection.
|
|
691
|
+
*/
|
|
287
692
|
function MemoryCard(props) {
|
|
288
693
|
var t = props.t;
|
|
289
694
|
var UI = props.UI;
|
|
695
|
+
injectCardStyle();
|
|
696
|
+
var openState = useState(false);
|
|
697
|
+
var open = openState[0];
|
|
698
|
+
var setOpen = openState[1];
|
|
290
699
|
var state = useState({ status: "loading", model: null, message: "" });
|
|
291
700
|
var model = state[0];
|
|
292
701
|
var setModel = state[1];
|
|
293
702
|
var reloadState = useState(0);
|
|
294
703
|
var reload = reloadState[1];
|
|
704
|
+
var selectionState = useState({ root: null, query: "", expandedFile: null });
|
|
705
|
+
var selection = selectionState[0];
|
|
706
|
+
var setSelection = selectionState[1];
|
|
707
|
+
var previewState = useState({ file: null, status: "loading", content: "", message: "" });
|
|
708
|
+
var preview = previewState[0];
|
|
709
|
+
var setPreview = previewState[1];
|
|
710
|
+
var nowState = useState(Date.now());
|
|
711
|
+
var now = nowState[0];
|
|
712
|
+
var setNow = nowState[1];
|
|
295
713
|
useEffect(
|
|
296
714
|
function () {
|
|
297
715
|
var alive = true;
|
|
@@ -311,42 +729,117 @@ window.__ModuleLoader__.load({
|
|
|
311
729
|
},
|
|
312
730
|
[reloadState[0]],
|
|
313
731
|
);
|
|
732
|
+
useEffect(
|
|
733
|
+
function () {
|
|
734
|
+
if (open) setNow(Date.now());
|
|
735
|
+
},
|
|
736
|
+
[open],
|
|
737
|
+
);
|
|
738
|
+
var refresh = function () {
|
|
739
|
+
setModel({ status: "loading", model: null, message: "" });
|
|
740
|
+
setSelection(function (current) {
|
|
741
|
+
return { root: current.root, query: "", expandedFile: null };
|
|
742
|
+
});
|
|
743
|
+
setPreview({ file: null, status: "loading", content: "", message: "" });
|
|
744
|
+
reload(function (n) {
|
|
745
|
+
return n + 1;
|
|
746
|
+
});
|
|
747
|
+
};
|
|
748
|
+
var header = createElement(
|
|
749
|
+
"button",
|
|
750
|
+
{
|
|
751
|
+
type: "button",
|
|
752
|
+
className: "dce-head",
|
|
753
|
+
"aria-expanded": open ? "true" : "false",
|
|
754
|
+
onClick: function () {
|
|
755
|
+
setOpen(!open);
|
|
756
|
+
},
|
|
757
|
+
},
|
|
758
|
+
createElement(
|
|
759
|
+
"div",
|
|
760
|
+
{ className: "dce-head-text" },
|
|
761
|
+
createElement("div", { className: "dce-name" }, t("title")),
|
|
762
|
+
createElement("div", { className: "dce-desc" }, t("desc")),
|
|
763
|
+
),
|
|
764
|
+
createElement(
|
|
765
|
+
"span",
|
|
766
|
+
{ className: "dce-chevron", "data-open": open ? "true" : "false" },
|
|
767
|
+
createElement(Chevron, null),
|
|
768
|
+
),
|
|
769
|
+
);
|
|
314
770
|
var body = null;
|
|
771
|
+
if (!open) {
|
|
772
|
+
return createElement("div", { className: "dce-card", "data-open": "false" }, header);
|
|
773
|
+
}
|
|
774
|
+
var inner = null;
|
|
315
775
|
if (model.status === "loading") {
|
|
316
|
-
|
|
776
|
+
inner = createElement("div", { key: "inner", className: "dce-hint" }, t("loading"));
|
|
317
777
|
} else if (model.status === "error") {
|
|
318
|
-
|
|
778
|
+
inner = createElement("div", { key: "inner", className: "dce-error" }, t("loadFailed") + model.message);
|
|
319
779
|
} else if (model.model.workspaces.length === 0) {
|
|
320
|
-
|
|
780
|
+
inner = createElement("div", { key: "inner", className: "dce-empty" }, t("empty"));
|
|
321
781
|
} else {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
model.model.workspaces.
|
|
326
|
-
return
|
|
327
|
-
})
|
|
328
|
-
)
|
|
782
|
+
var selected = selection.root;
|
|
783
|
+
if (
|
|
784
|
+
selected === null ||
|
|
785
|
+
!model.model.workspaces.some(function (workspace) {
|
|
786
|
+
return workspace.root === selected;
|
|
787
|
+
})
|
|
788
|
+
) {
|
|
789
|
+
selected = model.model.workspaces[0].root;
|
|
790
|
+
}
|
|
791
|
+
inner = createElement(WorkspaceBlock, {
|
|
792
|
+
key: "inner",
|
|
793
|
+
entry: model.model,
|
|
794
|
+
selected: selected,
|
|
795
|
+
onSelect: function (root) {
|
|
796
|
+
setSelection({ root: root, query: "", expandedFile: null });
|
|
797
|
+
setPreview({ file: null, status: "loading", content: "", message: "" });
|
|
798
|
+
},
|
|
799
|
+
onRefresh: refresh,
|
|
800
|
+
t: t,
|
|
801
|
+
UI: UI,
|
|
802
|
+
now: now,
|
|
803
|
+
expandedFile: selection.expandedFile,
|
|
804
|
+
preview: preview,
|
|
805
|
+
onToggleFile: function (file) {
|
|
806
|
+
if (selection.expandedFile === file) {
|
|
807
|
+
setSelection(function (current) {
|
|
808
|
+
return { root: current.root, query: current.query, expandedFile: null };
|
|
809
|
+
});
|
|
810
|
+
return;
|
|
811
|
+
}
|
|
812
|
+
setSelection(function (current) {
|
|
813
|
+
return { root: current.root, query: current.query, expandedFile: file };
|
|
814
|
+
});
|
|
815
|
+
setPreview({ file: file, status: "loading", content: "", message: "" });
|
|
816
|
+
loadFileContent(fetch, selected, file).then(function (result) {
|
|
817
|
+
setPreview(function (current) {
|
|
818
|
+
if (current.file !== file) {
|
|
819
|
+
return current;
|
|
820
|
+
}
|
|
821
|
+
return { file: file, status: result.status, content: result.content, message: result.message };
|
|
822
|
+
});
|
|
823
|
+
});
|
|
824
|
+
},
|
|
825
|
+
query: selection.query,
|
|
826
|
+
onQueryChange: function (value) {
|
|
827
|
+
setSelection(function (current) {
|
|
828
|
+
return { root: current.root, query: value, expandedFile: current.expandedFile };
|
|
829
|
+
});
|
|
830
|
+
},
|
|
831
|
+
});
|
|
329
832
|
}
|
|
833
|
+
body = createElement(
|
|
834
|
+
"div",
|
|
835
|
+
{ key: "body", className: "dce-body" },
|
|
836
|
+
createElement("div", { className: "dce-hint" }, t("hint")),
|
|
837
|
+
inner,
|
|
838
|
+
);
|
|
330
839
|
return createElement(
|
|
331
840
|
"div",
|
|
332
|
-
{
|
|
333
|
-
|
|
334
|
-
"div",
|
|
335
|
-
{ style: { display: "flex", alignItems: "center", gap: "12px" } },
|
|
336
|
-
createElement("div", { style: TITLE_STYLE }, t("title")),
|
|
337
|
-
createElement("span", { style: { flex: 1 } }),
|
|
338
|
-
createElement(RefreshButton, {
|
|
339
|
-
UI: UI,
|
|
340
|
-
t: t,
|
|
341
|
-
onClick: function () {
|
|
342
|
-
setModel({ status: "loading", model: null, message: "" });
|
|
343
|
-
reload(function (n) {
|
|
344
|
-
return n + 1;
|
|
345
|
-
});
|
|
346
|
-
},
|
|
347
|
-
}),
|
|
348
|
-
),
|
|
349
|
-
createElement("div", { style: HINT_STYLE }, t("hint")),
|
|
841
|
+
{ className: "dce-card", "data-open": "true" },
|
|
842
|
+
header,
|
|
350
843
|
body,
|
|
351
844
|
);
|
|
352
845
|
}
|
|
@@ -354,6 +847,7 @@ window.__ModuleLoader__.load({
|
|
|
354
847
|
exports.name = NS;
|
|
355
848
|
exports.inject = ["slots", "locale", "theme"];
|
|
356
849
|
exports.loadCardModel = loadCardModel;
|
|
850
|
+
exports.loadFileContent = loadFileContent;
|
|
357
851
|
exports.apply = function apply(ctx) {
|
|
358
852
|
var tRaw = null;
|
|
359
853
|
try {
|