@deepseek-ai/dsh-client-ui-sidebar-files 0.1.5-alpha.1 → 0.1.5-alpha.2
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.i18n.yaml +2 -2
- package/README.md +4 -3
- package/README.zh.md +4 -3
- package/lib/client.js +129 -60
- package/lib/types/client/FilesTitle.d.ts +15 -0
- package/lib/types/client/index.d.ts +5 -4
- package/lib/types/client/locales.d.ts +0 -2
- package/package.json +17 -19
package/README.i18n.yaml
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write packages/client/ui-sidebar-files/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: cadadc03f96f39f9b48813f25179f4506b6de791
|
|
6
|
+
README.zh.md: e25d86b27556bac746c53abf016b37ce1ded81df
|
package/README.md
CHANGED
|
@@ -25,14 +25,15 @@ The right Sidebar's navigator tab type: the session's workspace root as a tree,
|
|
|
25
25
|
## What it registers
|
|
26
26
|
|
|
27
27
|
- **The type** — `ctx.sidebarRightTabs.register(...)` with kind `files`, id `@deepseek-ai/dsh-client-ui-sidebar-files`, band `builtin`, no patterns, and one guide entry (order 10, titled from the `sidebarFiles` namespace) that opens the type.
|
|
28
|
-
- **The body** — the keyed `sidebar.right.pane.tab` seat under that id: the tree,
|
|
28
|
+
- **The body** — the keyed `sidebar.right.pane.tab` seat under that id: a header row under the strip, then the tree. The header row is the document preview's (`ui-sidebar-documentpreview`): the root path, its directories greyed and its last segment in full ink, never ellipsized (a path wider than the row keeps its end and fades its start), with the one control, reload, at its right. The row is copied rather than shared because a plugin bundle shares runtime code only through the platform modules; once the artifact and slot surfaces settle, one copy in `ui-primitives` could serve every pane header.
|
|
29
|
+
- **The chip title** — the keyed `sidebar.right.pane.tab.title` seat under that id: a shared `FileTypeIcon` folder glyph at 16px before the type's label. The tree's own rows never draw this sheet.
|
|
29
30
|
|
|
30
|
-
|
|
31
|
+
Seven source files under `src/client/`: `definition.ts` (the type), `store.ts` (what it keeps), `face.ts` (how it lists, Remote binding included), `FilesBody.tsx` (what it draws, with its ordering and failure-line helpers), `FilesTitle.tsx` (the chip title), `locales.ts` (what it says), and `index.ts` (the wiring).
|
|
31
32
|
|
|
32
33
|
<a id="the-tree"></a>
|
|
33
34
|
## The tree
|
|
34
35
|
|
|
35
|
-
The root is the session's working directory, read from `useSessions().byId[sessionId].cwd`, and
|
|
36
|
+
The root is the session's working directory, read from `useSessions().byId[sessionId].cwd`, and split for the header row by `pathPartsOf` from `@deepseek-ai/dsh-util-workspace-path`. Every level is keyed by absolute path; a child's path is its parent's joined with the entry name by `/`. A level is listed when it is first expanded, through `remote.workspaceFiles.list(sessionId, absolutePath)` on the `@deepseek-ai/dsh-api-workspace-files` namespace; the adapter keeps the listing's entries and truncation flag and drops its workspace-relative path. Rows are ordered directories first, then by natural, case-insensitive name; dotfiles are shown like any other entry.
|
|
36
37
|
|
|
37
38
|
| Entry type | Row |
|
|
38
39
|
|---|---|
|
package/README.zh.md
CHANGED
|
@@ -25,14 +25,15 @@ kind: "package-reference"
|
|
|
25
25
|
## 注册了什么
|
|
26
26
|
|
|
27
27
|
- **类型**:`ctx.sidebarRightTabs.register(...)`,kind 为 `files`,id 为 `@deepseek-ai/dsh-client-ui-sidebar-files`,档位 `builtin`,没有 patterns,另有一个打开该类型的引导页入口(order 10,标题取自 `sidebarFiles` 命名空间)。
|
|
28
|
-
- **正文**:以该 id 为键的 `sidebar.right.pane.tab`
|
|
28
|
+
- **正文**:以该 id 为键的 `sidebar.right.pane.tab` 坑位:strip 下的一行标题行,然后是树。标题行与文档预览(`ui-sidebar-documentpreview`)的相同:根路径,目录部分灰色、最后一段正色,从不省略号截断(比行宽的路径保留末尾、淡出开头),右端是它唯一的控件、重新读取。这一行是复制而非共享,因为插件 bundle 只经平台模块共享运行时代码;待 artifact 与各 slot 的形态定下来后,可以在 `ui-primitives` 放一份供每个 pane 标题行使用。
|
|
29
|
+
- **标签页标题**:以该 id 为键的 `sidebar.right.pane.tab.title` 坑位:类型标签前的一枚 16px 共享 `FileTypeIcon` 文件夹图标。树本身的行不画这枚图标。
|
|
29
30
|
|
|
30
|
-
`src/client/`
|
|
31
|
+
`src/client/` 下七个源文件:`definition.ts`(类型是什么)、`store.ts`(它保存什么)、`face.ts`(它如何列目录,含 Remote 绑定)、`FilesBody.tsx`(它画什么,含排序与失败行两个辅助函数)、`FilesTitle.tsx`(标签页标题)、`locales.ts`(它说什么)、`index.ts`(接线)。
|
|
31
32
|
|
|
32
33
|
<a id="the-tree"></a>
|
|
33
34
|
## 树
|
|
34
35
|
|
|
35
|
-
根是会话的工作目录,读自 `useSessions().byId[sessionId].cwd
|
|
36
|
+
根是会话的工作目录,读自 `useSessions().byId[sessionId].cwd`,标题行里的拆分由 `@deepseek-ai/dsh-util-workspace-path` 的 `pathPartsOf` 给出。每一层以绝对路径为键;子路径是父路径以 `/` 拼上条目名。一层在首次展开时经 `@deepseek-ai/dsh-api-workspace-files` 命名空间的 `remote.workspaceFiles.list(sessionId, absolutePath)` 列出;适配层保留列表的条目与截断标志,丢弃其工作区相对路径。行序为目录优先,其后按自然序、不分大小写的名称排列;dotfiles 与其他条目一样显示。
|
|
36
37
|
|
|
37
38
|
| 条目类型 | 行 |
|
|
38
39
|
|---|---|
|
package/lib/client.js
CHANGED
|
@@ -27,7 +27,6 @@ window.__ModuleLoader__.load({
|
|
|
27
27
|
guide: [{
|
|
28
28
|
order: 10,
|
|
29
29
|
title: () => t("guide.title"),
|
|
30
|
-
description: () => t("guide.description"),
|
|
31
30
|
icon: _deepseek_ai_dsh_client_ui_primitives.IconFolderClose16
|
|
32
31
|
}]
|
|
33
32
|
};
|
|
@@ -135,26 +134,14 @@ window.__ModuleLoader__.load({
|
|
|
135
134
|
return path.split("/").map(encodeSegment).join("/");
|
|
136
135
|
}
|
|
137
136
|
/**
|
|
138
|
-
* Build the address of a file
|
|
139
|
-
* @param sessionId - the Session whose workspace
|
|
140
|
-
* @param path - workspace-relative path; backslashes are normalized to `/`, and
|
|
137
|
+
* Build the address of a file read through one Session.
|
|
138
|
+
* @param sessionId - the Session whose Host workspace resolves the path.
|
|
139
|
+
* @param path - absolute or workspace-relative path; backslashes are normalized to `/`, and leading `./` prefixes are dropped.
|
|
141
140
|
* @returns the `dsh-resource://file/session/<sessionId>/<path>` address.
|
|
142
141
|
*/
|
|
143
142
|
function sessionFileAddress(sessionId, path) {
|
|
144
|
-
const
|
|
145
|
-
return `${FILE_ADDRESS_PREFIX}session/${encodeSegment(sessionId)}/${encodePath(
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Build the address of a file by its absolute path.
|
|
149
|
-
* @param path - absolute path; backslashes are normalized to `/` and the leading `/` is dropped,
|
|
150
|
-
* except that a UNC path (`\\server\share`) keeps one empty first segment.
|
|
151
|
-
* @returns the `dsh-resource://file/absolute/<path>` address.
|
|
152
|
-
*/
|
|
153
|
-
function absoluteFileAddress(path) {
|
|
154
|
-
const normalized = path.replace(/\\/g, "/");
|
|
155
|
-
const unc = normalized.startsWith("//");
|
|
156
|
-
const absolute = normalized.replace(/^\/+/, "");
|
|
157
|
-
return `${FILE_ADDRESS_PREFIX}absolute/${unc ? "/" : ""}${encodePath(absolute)}`;
|
|
143
|
+
const normalized = path.replace(/\\/g, "/").replace(/^(?:\.\/)+/, "");
|
|
144
|
+
return `${FILE_ADDRESS_PREFIX}session/${encodeSegment(sessionId)}/${encodePath(normalized)}`;
|
|
158
145
|
}
|
|
159
146
|
//#endregion
|
|
160
147
|
//#region ../../util/workspace-path/src/index.ts
|
|
@@ -175,21 +162,31 @@ window.__ModuleLoader__.load({
|
|
|
175
162
|
return path.startsWith("/") || isWindowsStylePath(path);
|
|
176
163
|
}
|
|
177
164
|
/**
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
165
|
+
* Split a path for display: the directories through their last separator, and
|
|
166
|
+
* the final segment after it. Both `/` and `\` separate, so a Windows path
|
|
167
|
+
* splits where its own segments end; trailing separators are dropped first, so
|
|
168
|
+
* a directory path names its own last segment. A path with no separator, or a
|
|
169
|
+
* separator-only path, is all name.
|
|
170
|
+
* @param path - file or directory path using POSIX or Windows separators.
|
|
171
|
+
* @returns the directory prefix (possibly empty) and the final segment.
|
|
182
172
|
*/
|
|
183
|
-
function
|
|
173
|
+
function pathPartsOf(path) {
|
|
184
174
|
const trimmed = path.replace(/[/\\]+$/, "");
|
|
185
|
-
|
|
186
|
-
|
|
175
|
+
if (trimmed === "") return {
|
|
176
|
+
directory: "",
|
|
177
|
+
name: path
|
|
178
|
+
};
|
|
179
|
+
const cut = Math.max(trimmed.lastIndexOf("/"), trimmed.lastIndexOf("\\")) + 1;
|
|
180
|
+
return {
|
|
181
|
+
directory: trimmed.slice(0, cut),
|
|
182
|
+
name: trimmed.slice(cut)
|
|
183
|
+
};
|
|
187
184
|
}
|
|
188
185
|
/**
|
|
189
186
|
* The address for a path as a caller holds it: a relative path, or an absolute
|
|
190
187
|
* path inside the Session's workspace, becomes a `session`-scoped address; an
|
|
191
|
-
* absolute path outside it, or one whose workspace root is unknown,
|
|
192
|
-
*
|
|
188
|
+
* absolute path outside it, or one whose workspace root is unknown, keeps its
|
|
189
|
+
* absolute path in that Session's address.
|
|
193
190
|
* @param sessionId - the Session the path is read in.
|
|
194
191
|
* @param cwd - that Session's workspace root, when known.
|
|
195
192
|
* @param path - absolute or workspace-relative path, in either separator spelling.
|
|
@@ -201,11 +198,11 @@ window.__ModuleLoader__.load({
|
|
|
201
198
|
const root = cwd === void 0 ? "" : cwd.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
202
199
|
if (root !== "" && normalized === root) return sessionFileAddress(sessionId, "");
|
|
203
200
|
if (root !== "" && normalized.startsWith(`${root}/`)) return sessionFileAddress(sessionId, normalized.slice(root.length + 1));
|
|
204
|
-
return
|
|
201
|
+
return sessionFileAddress(sessionId, normalized);
|
|
205
202
|
}
|
|
206
203
|
//#endregion
|
|
207
204
|
//#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-sidebar-files/src/client/FilesBody.module.css.mjs
|
|
208
|
-
const css = ".k-1LKG_root{min-height:0;color:var(--dsw-alias-label-primary);font-size:var(--dsh-content-font-size-secondary,13px);flex-direction:column;flex:auto;
|
|
205
|
+
const css = ".k-1LKG_root{height:100%;min-height:0;color:var(--dsw-alias-label-primary);font-size:var(--dsh-content-font-size-secondary,13px);flex-direction:column;flex:auto;line-height:1.5;display:flex}.k-1LKG_header{box-sizing:border-box;border-bottom:.5px solid var(--dsw-alias-border-l3);flex:none;align-items:center;gap:4px;height:38px;padding:0 6px 0 16px;display:flex}.k-1LKG_path{white-space:nowrap;flex:auto;justify-content:flex-end;min-width:0;margin-right:12px;font-size:12px;display:flex;overflow:hidden}.k-1LKG_path[data-files-path-clipped]{mask-image:linear-gradient(90deg,#0000,#000 28px)}.k-1LKG_pathText{flex:none;margin-right:auto}.k-1LKG_pathDirectory{color:var(--dsw-alias-label-tertiary)}.k-1LKG_pathName{color:var(--dsw-alias-label-primary)}.k-1LKG_body{scrollbar-gutter:stable;flex:auto;min-height:0;margin-right:2px;padding:8px 0 8px 8px;overflow:auto}.k-1LKG_body::-webkit-scrollbar-track{margin:2px}.k-1LKG_level{margin:0;padding:0;list-style:none}.k-1LKG_level .k-1LKG_level{padding-left:18px}.k-1LKG_item{margin:0;padding:0}.k-1LKG_row{width:100%;min-width:0;color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:10px;align-items:center;gap:6px;padding:5px 10px;display:flex}.k-1LKG_row:hover{background:var(--dsw-alias-interactive-bg-hover)}.k-1LKG_icon{color:var(--dsw-alias-label-tertiary);flex:none}.k-1LKG_fileIcon{flex:none}.k-1LKG_name{white-space:nowrap;text-overflow:ellipsis;min-width:0;overflow:hidden}.k-1LKG_other{color:var(--dsw-alias-label-tertiary);cursor:default}.k-1LKG_other:hover{background:0 0}.k-1LKG_note{color:var(--dsw-alias-label-tertiary);margin:0;padding:3px 10px;font-size:12px}.k-1LKG_status{flex-direction:column;padding:12px 10px;display:flex}.k-1LKG_statusLine{color:var(--dsw-alias-label-secondary);font-size:var(--dsh-content-font-size-secondary,13px);margin:0;line-height:1.6}.k-1LKG_tool{width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:28px;flex:none;justify-content:center;align-items:center;padding:6px;line-height:1;display:inline-flex}.k-1LKG_tool svg{width:15px;height:15px}.k-1LKG_tool:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}.k-1LKG_titleIcon{flex:none}";
|
|
209
206
|
const tagId = "@deepseek-ai/dsh-client-ui-sidebar-files/FilesBody.module.css";
|
|
210
207
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
211
208
|
const tag = document.createElement("style");
|
|
@@ -215,6 +212,7 @@ window.__ModuleLoader__.load({
|
|
|
215
212
|
document.head.appendChild(tag);
|
|
216
213
|
}
|
|
217
214
|
var FilesBody_module_css_default = {
|
|
215
|
+
"body": "k-1LKG_body",
|
|
218
216
|
"fileIcon": "k-1LKG_fileIcon",
|
|
219
217
|
"header": "k-1LKG_header",
|
|
220
218
|
"icon": "k-1LKG_icon",
|
|
@@ -223,10 +221,15 @@ window.__ModuleLoader__.load({
|
|
|
223
221
|
"name": "k-1LKG_name",
|
|
224
222
|
"note": "k-1LKG_note",
|
|
225
223
|
"other": "k-1LKG_other",
|
|
224
|
+
"path": "k-1LKG_path",
|
|
225
|
+
"pathDirectory": "k-1LKG_pathDirectory",
|
|
226
|
+
"pathName": "k-1LKG_pathName",
|
|
227
|
+
"pathText": "k-1LKG_pathText",
|
|
226
228
|
"root": "k-1LKG_root",
|
|
227
229
|
"row": "k-1LKG_row",
|
|
228
230
|
"status": "k-1LKG_status",
|
|
229
231
|
"statusLine": "k-1LKG_statusLine",
|
|
232
|
+
"titleIcon": "k-1LKG_titleIcon",
|
|
230
233
|
"tool": "k-1LKG_tool"
|
|
231
234
|
};
|
|
232
235
|
//#endregion
|
|
@@ -238,9 +241,10 @@ window.__ModuleLoader__.load({
|
|
|
238
241
|
* for goes through its injected face. The component itself only decides what to
|
|
239
242
|
* draw for each absolute path and what a click means: a directory toggles, a
|
|
240
243
|
* file opens through the owner's `tabActions` for a `file:` viewer to claim, and
|
|
241
|
-
* anything else is shown but refuses to open. The header row
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
+
* anything else is shown but refuses to open. The header row is the text
|
|
245
|
+
* preview's: the root's path, directories greyed and the last segment in full
|
|
246
|
+
* ink, then the one control at its end, reload, which drops every listed level
|
|
247
|
+
* and asks again for the expanded ones.
|
|
244
248
|
*/
|
|
245
249
|
/** Natural, case-insensitive name order, so `file2` precedes `file10`. */
|
|
246
250
|
const byName = new Intl.Collator(void 0, {
|
|
@@ -274,6 +278,35 @@ window.__ModuleLoader__.load({
|
|
|
274
278
|
default: return t("error.unavailable", { message: failure.message });
|
|
275
279
|
}
|
|
276
280
|
}
|
|
281
|
+
/**
|
|
282
|
+
* Keep the path row's `data-files-path-clipped` current: set while the path's
|
|
283
|
+
* text is wider than its box, so the stylesheet fades the clipped start. Read
|
|
284
|
+
* after each commit that can change the path or mount the header, and whenever
|
|
285
|
+
* either box resizes; written to the DOM directly because it changes only how
|
|
286
|
+
* the stylesheet fades what is already rendered.
|
|
287
|
+
*/
|
|
288
|
+
function usePathClipped(box, text, path) {
|
|
289
|
+
(0, react.useLayoutEffect)(() => {
|
|
290
|
+
const outer = box.current;
|
|
291
|
+
const inner = text.current;
|
|
292
|
+
if (outer === null || inner === null) return void 0;
|
|
293
|
+
const apply = () => {
|
|
294
|
+
if (inner.offsetWidth > outer.clientWidth) outer.dataset.filesPathClipped = "";
|
|
295
|
+
else delete outer.dataset.filesPathClipped;
|
|
296
|
+
};
|
|
297
|
+
apply();
|
|
298
|
+
const observer = typeof ResizeObserver === "undefined" ? void 0 : new ResizeObserver(apply);
|
|
299
|
+
observer?.observe(outer);
|
|
300
|
+
observer?.observe(inner);
|
|
301
|
+
return () => {
|
|
302
|
+
observer?.disconnect();
|
|
303
|
+
};
|
|
304
|
+
}, [
|
|
305
|
+
box,
|
|
306
|
+
text,
|
|
307
|
+
path
|
|
308
|
+
]);
|
|
309
|
+
}
|
|
277
310
|
/** One entry's row, and its children when it is an expanded directory. */
|
|
278
311
|
function Entry({ parent, entry, tree }) {
|
|
279
312
|
const path = childPath(parent, entry.name);
|
|
@@ -313,7 +346,11 @@ window.__ModuleLoader__.load({
|
|
|
313
346
|
onClick: () => {
|
|
314
347
|
tree.onOpen(path);
|
|
315
348
|
},
|
|
316
|
-
children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
349
|
+
children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.FileTypeIcon, {
|
|
350
|
+
kind: (0, _deepseek_ai_dsh_client_ui_primitives.classifyFileType)(entry.name),
|
|
351
|
+
size: 16,
|
|
352
|
+
className: FilesBody_module_css_default.fileIcon
|
|
353
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
317
354
|
className: FilesBody_module_css_default.name,
|
|
318
355
|
children: entry.name
|
|
319
356
|
})]
|
|
@@ -374,6 +411,9 @@ window.__ModuleLoader__.load({
|
|
|
374
411
|
const { signal, actions: tabActions } = tab;
|
|
375
412
|
const cwd = useSessions((sessions) => sessions.byId[sessionId]?.cwd);
|
|
376
413
|
const state = useStore((store) => store.byTab[tab.id]);
|
|
414
|
+
const pathRef = (0, react.useRef)(null);
|
|
415
|
+
const pathTextRef = (0, react.useRef)(null);
|
|
416
|
+
usePathClipped(pathRef, pathTextRef, state?.root);
|
|
377
417
|
(0, react.useEffect)(() => {
|
|
378
418
|
if (state !== void 0 || cwd === void 0 || signal.aborted) return;
|
|
379
419
|
start(tab.id, cwd, signal);
|
|
@@ -407,45 +447,71 @@ window.__ModuleLoader__.load({
|
|
|
407
447
|
actions.reset(tab.id);
|
|
408
448
|
for (const path of state.expanded) load(tab.id, path, signal);
|
|
409
449
|
};
|
|
410
|
-
const
|
|
450
|
+
const { directory, name } = pathPartsOf(state.root);
|
|
411
451
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
412
452
|
className: FilesBody_module_css_default.root,
|
|
413
453
|
"data-files-state": "tree",
|
|
414
454
|
"data-files-root": state.root,
|
|
415
455
|
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
416
456
|
className: FilesBody_module_css_default.header,
|
|
417
|
-
children: [
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
"
|
|
429
|
-
|
|
430
|
-
|
|
457
|
+
children: [(0, react_jsx_runtime.jsx)("div", {
|
|
458
|
+
ref: pathRef,
|
|
459
|
+
className: FilesBody_module_css_default.path,
|
|
460
|
+
title: state.root,
|
|
461
|
+
"data-files-path": true,
|
|
462
|
+
children: (0, react_jsx_runtime.jsxs)("span", {
|
|
463
|
+
ref: pathTextRef,
|
|
464
|
+
className: FilesBody_module_css_default.pathText,
|
|
465
|
+
children: [directory !== "" && (0, react_jsx_runtime.jsx)("span", {
|
|
466
|
+
className: FilesBody_module_css_default.pathDirectory,
|
|
467
|
+
children: directory
|
|
468
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
469
|
+
className: FilesBody_module_css_default.pathName,
|
|
470
|
+
children: name
|
|
471
|
+
})]
|
|
472
|
+
})
|
|
473
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
474
|
+
type: "button",
|
|
475
|
+
className: FilesBody_module_css_default.tool,
|
|
476
|
+
"aria-label": t("reload"),
|
|
477
|
+
title: t("reload"),
|
|
478
|
+
"data-files-reload": true,
|
|
479
|
+
onClick: reload,
|
|
480
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutline16, {})
|
|
481
|
+
})]
|
|
482
|
+
}), (0, react_jsx_runtime.jsx)("div", {
|
|
483
|
+
className: FilesBody_module_css_default.body,
|
|
484
|
+
children: (0, react_jsx_runtime.jsx)("ul", {
|
|
485
|
+
className: FilesBody_module_css_default.level,
|
|
486
|
+
children: (0, react_jsx_runtime.jsx)(Level, {
|
|
487
|
+
path: state.root,
|
|
488
|
+
tree
|
|
431
489
|
})
|
|
432
|
-
]
|
|
433
|
-
}), (0, react_jsx_runtime.jsx)("ul", {
|
|
434
|
-
className: FilesBody_module_css_default.level,
|
|
435
|
-
children: (0, react_jsx_runtime.jsx)(Level, {
|
|
436
|
-
path: state.root,
|
|
437
|
-
tree
|
|
438
490
|
})
|
|
439
491
|
})]
|
|
440
492
|
});
|
|
441
493
|
}
|
|
442
494
|
//#endregion
|
|
495
|
+
//#region lib/types/client/FilesTitle.js
|
|
496
|
+
/**
|
|
497
|
+
* The title as the chip and a floating panel's header show it.
|
|
498
|
+
* @param props - the tab information hook.
|
|
499
|
+
* @returns the folder sheet followed by the tab's title text.
|
|
500
|
+
*/
|
|
501
|
+
function FilesTitle({ useTabInfo }) {
|
|
502
|
+
const { tab } = useTabInfo();
|
|
503
|
+
return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.FileTypeIcon, {
|
|
504
|
+
kind: "folder",
|
|
505
|
+
size: 16,
|
|
506
|
+
className: FilesBody_module_css_default.titleIcon
|
|
507
|
+
}), tab.title] });
|
|
508
|
+
}
|
|
509
|
+
//#endregion
|
|
443
510
|
//#region lib/types/client/locales.js
|
|
444
511
|
/** Simplified Chinese dictionary and key-set source of truth. */
|
|
445
512
|
const zh = {
|
|
446
513
|
"type.label": "文件",
|
|
447
|
-
"guide.title": "
|
|
448
|
-
"guide.description": "浏览这个会话工作区里的文件,点开就能查看。",
|
|
514
|
+
"guide.title": "工作区文件",
|
|
449
515
|
loading: "正在读取…",
|
|
450
516
|
empty: "空目录",
|
|
451
517
|
truncated: "条目太多,只显示了一部分。",
|
|
@@ -460,11 +526,10 @@ window.__ModuleLoader__.load({
|
|
|
460
526
|
/** English dictionary, checked against the Chinese key set. */
|
|
461
527
|
const en = {
|
|
462
528
|
"type.label": "Files",
|
|
463
|
-
"guide.title": "
|
|
464
|
-
"guide.description": "Browse the files in this session's workspace and open any of them.",
|
|
529
|
+
"guide.title": "Workspace files",
|
|
465
530
|
loading: "Reading…",
|
|
466
531
|
empty: "Empty directory",
|
|
467
|
-
truncated: "Too many entries
|
|
532
|
+
truncated: "Too many entries, showing only some of them.",
|
|
468
533
|
noWorkspace: "This session has no workspace directory.",
|
|
469
534
|
reload: "Reload",
|
|
470
535
|
"entry.other": "Not a file or a directory, so it cannot be opened.",
|
|
@@ -610,7 +675,7 @@ window.__ModuleLoader__.load({
|
|
|
610
675
|
"remote.workspaceFiles"
|
|
611
676
|
];
|
|
612
677
|
/**
|
|
613
|
-
* Client plugin body: register the type, its dictionaries,
|
|
678
|
+
* Client plugin body: register the type, its dictionaries, its body, and its chip title.
|
|
614
679
|
* @param ctx - client root context carrying the registry, the slots, and the Remote face.
|
|
615
680
|
*/
|
|
616
681
|
function apply(ctx) {
|
|
@@ -629,6 +694,10 @@ window.__ModuleLoader__.load({
|
|
|
629
694
|
store,
|
|
630
695
|
inject
|
|
631
696
|
}, FilesBody)), "ui-sidebar-files: files tab body");
|
|
697
|
+
ctx.effect(() => ctx.slots.inject("sidebar.right.pane.tab.title", () => ctx.slots.register({
|
|
698
|
+
name: "sidebar.right.pane.tab.title",
|
|
699
|
+
key: FILES_ID
|
|
700
|
+
}, FilesTitle)), "ui-sidebar-files: files tab title");
|
|
632
701
|
}
|
|
633
702
|
//#endregion
|
|
634
703
|
exports.apply = apply;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The files type's chip title: the folder sheet before the type's label.
|
|
3
|
+
* Registered under `sidebar.right.pane.tab.title`; without it the chip would
|
|
4
|
+
* show the bare label. The tree in the body draws its own row glyphs and never
|
|
5
|
+
* this one.
|
|
6
|
+
*/
|
|
7
|
+
import type { ReactNode } from 'react';
|
|
8
|
+
import type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
9
|
+
/**
|
|
10
|
+
* The title as the chip and a floating panel's header show it.
|
|
11
|
+
* @param props - the tab information hook.
|
|
12
|
+
* @returns the folder sheet followed by the tab's title text.
|
|
13
|
+
*/
|
|
14
|
+
export declare function FilesTitle({ useTabInfo }: PropsRuntime<'sidebar.right.pane.tab.title'>): ReactNode;
|
|
15
|
+
//# sourceMappingURL=FilesTitle.d.ts.map
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
* Browser half: register `files` as a right-Sidebar tab type.
|
|
3
3
|
*
|
|
4
4
|
* The public two-stage path, unmodified: the type into `ctx.sidebarRightTabs`,
|
|
5
|
-
* the body into the keyed `sidebar.right.pane.tab` seat
|
|
5
|
+
* the body into the keyed `sidebar.right.pane.tab` seat and the chip title into
|
|
6
|
+
* the keyed `sidebar.right.pane.tab.title` seat, both under the type's `id`.
|
|
6
7
|
*
|
|
7
8
|
* The file split is this package's layering: what the type IS
|
|
8
9
|
* (`definition.ts`), what it keeps (`store.ts`), how it lists (`face.ts`), what
|
|
9
|
-
* it draws (`FilesBody.tsx`), what it says (`locales.ts`),
|
|
10
|
-
* which only wires them together.
|
|
10
|
+
* it draws (`FilesBody.tsx`, `FilesTitle.tsx`), what it says (`locales.ts`),
|
|
11
|
+
* and this module, which only wires them together.
|
|
11
12
|
*/
|
|
12
13
|
import type { Context as ClientContext } from '@deepseek-ai/cordis';
|
|
13
14
|
export type { SidebarFilesKey } from './locales.ts';
|
|
@@ -20,7 +21,7 @@ export type { FilesBodyProps } from './FilesBody.tsx';
|
|
|
20
21
|
*/
|
|
21
22
|
export declare const inject: string[];
|
|
22
23
|
/**
|
|
23
|
-
* Client plugin body: register the type, its dictionaries,
|
|
24
|
+
* Client plugin body: register the type, its dictionaries, its body, and its chip title.
|
|
24
25
|
* @param ctx - client root context carrying the registry, the slots, and the Remote face.
|
|
25
26
|
*/
|
|
26
27
|
export declare function apply(ctx: ClientContext): void;
|
|
@@ -8,7 +8,6 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
|
8
8
|
export declare const zh: {
|
|
9
9
|
'type.label': string;
|
|
10
10
|
'guide.title': string;
|
|
11
|
-
'guide.description': string;
|
|
12
11
|
loading: string;
|
|
13
12
|
empty: string;
|
|
14
13
|
truncated: string;
|
|
@@ -26,7 +25,6 @@ export type SidebarFilesKey = keyof typeof zh;
|
|
|
26
25
|
export declare const en: {
|
|
27
26
|
'type.label': string;
|
|
28
27
|
'guide.title': string;
|
|
29
|
-
'guide.description': string;
|
|
30
28
|
loading: string;
|
|
31
29
|
empty: string;
|
|
32
30
|
truncated: string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-client-ui-sidebar-files",
|
|
3
3
|
"description": "Workspace file tree tab type for the right Sidebar: lazy directory listing over the workspaceFiles Remote namespace, opening files into the Sidebar",
|
|
4
|
-
"version": "0.1.5-alpha.
|
|
4
|
+
"version": "0.1.5-alpha.2",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -37,11 +37,6 @@
|
|
|
37
37
|
}
|
|
38
38
|
},
|
|
39
39
|
"license": "MIT",
|
|
40
|
-
"dependencies": {
|
|
41
|
-
"clsx": "^2.0.0",
|
|
42
|
-
"react": "^18.2.0",
|
|
43
|
-
"react-dom": "^18.2.0"
|
|
44
|
-
},
|
|
45
40
|
"peerDependencies": {
|
|
46
41
|
"@deepseek-ai/cordis": "^4.0.2"
|
|
47
42
|
},
|
|
@@ -49,20 +44,23 @@
|
|
|
49
44
|
"@testing-library/react": "^16.1.0",
|
|
50
45
|
"@types/react": "~18.3.1",
|
|
51
46
|
"@types/react-dom": "~18.3.0",
|
|
47
|
+
"react": "^18.2.0",
|
|
48
|
+
"clsx": "^2.0.0",
|
|
49
|
+
"react-dom": "^18.2.0",
|
|
50
|
+
"@deepseek-ai/dsh-api-remotes": "^0.1.5-alpha.2",
|
|
51
|
+
"@deepseek-ai/dsh-api-workspace-files": "^0.1.5-alpha.2",
|
|
52
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.5-alpha.2",
|
|
53
|
+
"@deepseek-ai/dsh-client-store": "^0.1.5-alpha.2",
|
|
52
54
|
"@deepseek-ai/cordis": "^4.0.2",
|
|
53
|
-
"@deepseek-ai/dsh-
|
|
54
|
-
"@deepseek-ai/dsh-
|
|
55
|
-
"@deepseek-ai/dsh-client-
|
|
56
|
-
"@deepseek-ai/dsh-client-
|
|
57
|
-
"@deepseek-ai/dsh-client-
|
|
58
|
-
"@deepseek-ai/dsh-client-ui-
|
|
59
|
-
"@deepseek-ai/dsh-
|
|
60
|
-
"@deepseek-ai/dsh-client-ui-
|
|
61
|
-
"@deepseek-ai/dsh-
|
|
62
|
-
"@deepseek-ai/dsh-client-ui-sidebar-right": "^0.1.5-alpha.1",
|
|
63
|
-
"@deepseek-ai/dsh-client-ui-slots": "^0.1.5-alpha.1",
|
|
64
|
-
"@deepseek-ai/dsh-session": "^0.1.5-alpha.1",
|
|
65
|
-
"@deepseek-ai/dsh-util-workspace-path": "^0.1.5-alpha.1"
|
|
55
|
+
"@deepseek-ai/dsh-client-test-runtime": "^0.1.5-alpha.2",
|
|
56
|
+
"@deepseek-ai/dsh-client-ui-dockkit": "^0.1.5-alpha.2",
|
|
57
|
+
"@deepseek-ai/dsh-client-ui-renderer": "^0.1.5-alpha.2",
|
|
58
|
+
"@deepseek-ai/dsh-client-ui-session": "^0.1.5-alpha.2",
|
|
59
|
+
"@deepseek-ai/dsh-client-ui-sidebar-right": "^0.1.5-alpha.2",
|
|
60
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.5-alpha.2",
|
|
61
|
+
"@deepseek-ai/dsh-util-workspace-path": "^0.1.5-alpha.2",
|
|
62
|
+
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.5-alpha.2",
|
|
63
|
+
"@deepseek-ai/dsh-session": "^0.1.5-alpha.2"
|
|
66
64
|
},
|
|
67
65
|
"files": [
|
|
68
66
|
"lib/index.js",
|