@deepseek-ai/dsh-client-ui-sidebar-files 0.1.5-rc.2 → 0.1.6-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 +1 -1
- package/README.zh.md +6 -6
- package/lib/client.js +37 -3
- package/lib/types/client/store.d.ts +5 -2
- package/package.json +14 -14
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: efaf0a584e0e8617d0cb97442f9ebb5fa1fe7b59
|
|
6
|
+
README.zh.md: a0d0abffcd6e9f4e979d9a6548537745d0a74ba6
|
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ The root is the session's working directory, read from `useSessions().byId[sessi
|
|
|
43
43
|
|
|
44
44
|
A level cut by the endpoint's entry cap ends with a marker; an empty level says so; a level that failed shows one line per code — `workspace-file/not-found`, `outside-workspace`, `not-directory` — and the transport's own message otherwise. Reload drops every listed level and asks again for the expanded ones; collapsed levels are fetched again when they next open. A session without a working directory shows a single line instead of a tree.
|
|
45
45
|
|
|
46
|
-
State lives in the type's own store, bucketed by tab id: `root`, `levels` (loading / ready / failed per absolute path), and `
|
|
46
|
+
State lives in the type's own store, bucketed by tab id: `root`, `levels` (loading / ready / failed per absolute path), `expanded`, and `scrollTop`, which the body tracks locally while scrolling and commits once when it unmounts. Because the store outlives the body, switching to another sidebar tab and back remounts the tree with its levels intact and its scroll offset restored. The owner's `signal` ends a bucket: on abort the tab is forgotten, and neither a listing that settles afterwards nor the unmount's offset commit writes anything.
|
|
47
47
|
|
|
48
48
|
<a id="model-experience"></a>
|
|
49
49
|
## Model Experience
|
package/README.zh.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "dsh Web 客户端右侧 Sidebar 的文件树 tab
|
|
2
|
+
description: "dsh Web 客户端右侧 Sidebar 的文件树 tab 类型:通过网络逐层列出会话工作区根目录,按资源地址把文件打开到 Sidebar。"
|
|
3
3
|
kind: "package-reference"
|
|
4
4
|
---
|
|
5
5
|
|
|
@@ -25,25 +25,25 @@ 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`
|
|
29
|
-
- **标签页标题**:以该 id 为键的 `sidebar.right.pane.tab.title`
|
|
28
|
+
- **正文**:以该 id 为键的 `sidebar.right.pane.tab` slot:strip 下的一行标题行,然后是树。标题行与文档预览(`ui-sidebar-documentpreview`)的相同:根路径,目录部分灰色、最后一段正色,从不省略号截断(比行宽的路径保留末尾、淡出开头),右端是它唯一的控件、重新读取。这一行是复制而非共享,因为插件 bundle 只经平台模块共享运行时代码;待 artifact 与各 slot 的形态定下来后,可以在 `ui-primitives` 放一份供每个 pane 标题行使用。
|
|
29
|
+
- **标签页标题**:以该 id 为键的 `sidebar.right.pane.tab.title` slot:类型标签前的一枚 16px 共享 `FileTypeIcon` 文件夹图标。树本身的行不画这枚图标。
|
|
30
30
|
|
|
31
31
|
`src/client/` 下七个源文件:`definition.tsx`(类型是什么)、`store.ts`(它保存什么)、`face.ts`(它如何列目录,含 Remote 绑定)、`FilesBody.tsx`(它画什么,含排序与失败行两个辅助函数)、`FilesTitle.tsx`(标签页标题)、`locales.ts`(它说什么)、`index.ts`(接线)。
|
|
32
32
|
|
|
33
33
|
<a id="the-tree"></a>
|
|
34
34
|
## 树
|
|
35
35
|
|
|
36
|
-
根是会话的工作目录,读自 `useSessions().byId[sessionId].cwd`,标题行里的拆分由 `@deepseek-ai/dsh-util-workspace-path` 的 `pathPartsOf` 给出。每一层以绝对路径为键;子路径是父路径以 `/` 拼上条目名。一层在首次展开时经 `@deepseek-ai/dsh-api-workspace-files` 命名空间的 `remote.workspaceFiles.list(sessionId, absolutePath)`
|
|
36
|
+
根是会话的工作目录,读自 `useSessions().byId[sessionId].cwd`,标题行里的拆分由 `@deepseek-ai/dsh-util-workspace-path` 的 `pathPartsOf` 给出。每一层以绝对路径为键;子路径是父路径以 `/` 拼上条目名。一层在首次展开时经 `@deepseek-ai/dsh-api-workspace-files` 命名空间的 `remote.workspaceFiles.list(sessionId, absolutePath)` 列出;适配器保留列表的条目与截断标志,丢弃其工作区相对路径。行序为目录优先,其后按自然序、不分大小写的名称排列;dotfiles 与其他条目一样显示。
|
|
37
37
|
|
|
38
38
|
| 条目类型 | 行 |
|
|
39
39
|
|---|---|
|
|
40
40
|
| `directory` | 切换展开与折叠;该层在首次打开时拉取,折叠期间保留。 |
|
|
41
41
|
| `file` | 经 `useTabInfo().tab.actions.openResource` 打开 `dsh-resource://file/session/<sessionId>/<encoded path relative to the root>`,地址由 `@deepseek-ai/dsh-util-workspace-path` 的 `fileAddressFor` 从条目的绝对路径与树的根生成,落在该 tab 自己的 pane 里。 |
|
|
42
|
-
| `other` |
|
|
42
|
+
| `other` | 灰显且不可点击,从而完整呈现目录内容。 |
|
|
43
43
|
|
|
44
44
|
被端点条目上限截断的层以一条标记收尾;空层如实说明;失败的层按错误码各显示一行(`workspace-file/not-found`、`outside-workspace`、`not-directory`),其他情况显示传输层自己的消息。重新读取丢弃所有已列出的层并只对展开中的层重新请求;折叠的层在下次打开时重新拉取。没有工作目录的会话只显示一行说明,而不是树。
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
状态保存在类型自己的存储里,按 tab id 分桶:`root`、`levels`(每个绝对路径的 loading / ready / failed)、`expanded` 与 `scrollTop`——滚动期间偏移由正文自己记录,卸载时一次性写入。存储比 body 活得久,切到其他侧栏 tab 再切回来时树带着已加载的层重新挂载,滚动位置也随之恢复。owner 的 `signal` 终结一个桶:中止时忘掉该 tab,其后才结算的列表与卸载时的偏移提交都什么也不写。
|
|
47
47
|
|
|
48
48
|
<a id="model-experience"></a>
|
|
49
49
|
## 模型体验
|
package/lib/client.js
CHANGED
|
@@ -33,6 +33,7 @@ window.__ModuleLoader__.load({
|
|
|
33
33
|
priority: "builtin",
|
|
34
34
|
title: () => t("type.label"),
|
|
35
35
|
guide: [{
|
|
36
|
+
id: "workspace",
|
|
36
37
|
order: 10,
|
|
37
38
|
title: () => t("guide.title"),
|
|
38
39
|
description: () => t("guide.description"),
|
|
@@ -422,7 +423,25 @@ window.__ModuleLoader__.load({
|
|
|
422
423
|
const state = useStore((store) => store.byTab[tab.id]);
|
|
423
424
|
const pathRef = (0, react.useRef)(null);
|
|
424
425
|
const pathTextRef = (0, react.useRef)(null);
|
|
426
|
+
const bodyRef = (0, react.useRef)(null);
|
|
427
|
+
const scrollTopRef = (0, react.useRef)(0);
|
|
425
428
|
usePathClipped(pathRef, pathTextRef, state?.root);
|
|
429
|
+
const seeded = state !== void 0;
|
|
430
|
+
(0, react.useLayoutEffect)(() => {
|
|
431
|
+
const body = bodyRef.current;
|
|
432
|
+
if (seeded && body !== null) {
|
|
433
|
+
body.scrollTop = state.scrollTop;
|
|
434
|
+
scrollTopRef.current = body.scrollTop;
|
|
435
|
+
}
|
|
436
|
+
}, [seeded]);
|
|
437
|
+
(0, react.useEffect)(() => () => {
|
|
438
|
+
if (seeded && !signal.aborted) actions.scrolled(tab.id, scrollTopRef.current);
|
|
439
|
+
}, [
|
|
440
|
+
seeded,
|
|
441
|
+
signal,
|
|
442
|
+
tab.id,
|
|
443
|
+
actions
|
|
444
|
+
]);
|
|
426
445
|
(0, react.useEffect)(() => {
|
|
427
446
|
if (state !== void 0 || cwd === void 0 || signal.aborted) return;
|
|
428
447
|
start(tab.id, cwd, signal);
|
|
@@ -489,7 +508,12 @@ window.__ModuleLoader__.load({
|
|
|
489
508
|
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutline16, {})
|
|
490
509
|
})]
|
|
491
510
|
}), (0, react_jsx_runtime.jsx)("div", {
|
|
511
|
+
ref: bodyRef,
|
|
492
512
|
className: FilesBody_module_css_default.body,
|
|
513
|
+
"data-files-body": true,
|
|
514
|
+
onScroll: (event) => {
|
|
515
|
+
scrollTopRef.current = event.currentTarget.scrollTop;
|
|
516
|
+
},
|
|
493
517
|
children: (0, react_jsx_runtime.jsx)("ul", {
|
|
494
518
|
className: FilesBody_module_css_default.level,
|
|
495
519
|
children: (0, react_jsx_runtime.jsx)(Level, {
|
|
@@ -552,8 +576,8 @@ window.__ModuleLoader__.load({
|
|
|
552
576
|
//#endregion
|
|
553
577
|
//#region lib/types/client/store.js
|
|
554
578
|
/**
|
|
555
|
-
* The file tree's view state: which directories are expanded,
|
|
556
|
-
* loaded level contains.
|
|
579
|
+
* The file tree's view state: which directories are expanded, what each
|
|
580
|
+
* loaded level contains, and where the body is scrolled to.
|
|
557
581
|
*
|
|
558
582
|
* The tree is not one resource. A directory listing per level, expanded lazily,
|
|
559
583
|
* is state the type owns — so it lives in a Slot-standard exclusive store
|
|
@@ -596,7 +620,8 @@ window.__ModuleLoader__.load({
|
|
|
596
620
|
d.byTab[tabId] = {
|
|
597
621
|
root,
|
|
598
622
|
levels: {},
|
|
599
|
-
expanded: [root]
|
|
623
|
+
expanded: [root],
|
|
624
|
+
scrollTop: 0
|
|
600
625
|
};
|
|
601
626
|
},
|
|
602
627
|
/**
|
|
@@ -649,6 +674,15 @@ window.__ModuleLoader__.load({
|
|
|
649
674
|
else state.expanded.push(path);
|
|
650
675
|
},
|
|
651
676
|
/**
|
|
677
|
+
* Record where one tab's body is scrolled to.
|
|
678
|
+
* @param d - draft state.
|
|
679
|
+
* @param tabId - the tab being drawn.
|
|
680
|
+
* @param scrollTop - the body's scroll offset, in px.
|
|
681
|
+
*/
|
|
682
|
+
scrolled: (d, tabId, scrollTop) => {
|
|
683
|
+
bucket(d, tabId).scrollTop = scrollTop;
|
|
684
|
+
},
|
|
685
|
+
/**
|
|
652
686
|
* Drop every loaded level, keeping what is expanded.
|
|
653
687
|
*
|
|
654
688
|
* This is the reload gesture's first half: the expanded set says which
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The file tree's view state: which directories are expanded,
|
|
3
|
-
* loaded level contains.
|
|
2
|
+
* The file tree's view state: which directories are expanded, what each
|
|
3
|
+
* loaded level contains, and where the body is scrolled to.
|
|
4
4
|
*
|
|
5
5
|
* The tree is not one resource. A directory listing per level, expanded lazily,
|
|
6
6
|
* is state the type owns — so it lives in a Slot-standard exclusive store
|
|
@@ -49,6 +49,8 @@ export interface FilesTabState {
|
|
|
49
49
|
levels: Record<string, LevelState>;
|
|
50
50
|
/** Expanded absolute directory paths, root included. */
|
|
51
51
|
expanded: string[];
|
|
52
|
+
/** The body's scroll offset in px, so a remounted tree comes back where the reader was. */
|
|
53
|
+
scrollTop: number;
|
|
52
54
|
}
|
|
53
55
|
/** Every tab's tree, keyed by tab id. */
|
|
54
56
|
export interface FilesState {
|
|
@@ -61,6 +63,7 @@ type FilesActions = {
|
|
|
61
63
|
loaded: (draft: FilesState, tabId: TabId, path: string, level: DirLevel) => void;
|
|
62
64
|
failed: (draft: FilesState, tabId: TabId, path: string, failure: RemoteFailure) => void;
|
|
63
65
|
toggled: (draft: FilesState, tabId: TabId, path: string) => void;
|
|
66
|
+
scrolled: (draft: FilesState, tabId: TabId, scrollTop: number) => void;
|
|
64
67
|
reset: (draft: FilesState, tabId: TabId) => void;
|
|
65
68
|
forget: (draft: FilesState, tabId: TabId) => void;
|
|
66
69
|
};
|
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.
|
|
4
|
+
"version": "0.1.6-alpha.2",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -48,19 +48,19 @@
|
|
|
48
48
|
"clsx": "^2.0.0",
|
|
49
49
|
"react-dom": "^18.2.0",
|
|
50
50
|
"@deepseek-ai/cordis": "^4.0.2",
|
|
51
|
-
"@deepseek-ai/dsh-api-remotes": "^0.1.
|
|
52
|
-
"@deepseek-ai/dsh-
|
|
53
|
-
"@deepseek-ai/dsh-client-
|
|
54
|
-
"@deepseek-ai/dsh-
|
|
55
|
-
"@deepseek-ai/dsh-client-
|
|
56
|
-
"@deepseek-ai/dsh-client-ui-
|
|
57
|
-
"@deepseek-ai/dsh-client-
|
|
58
|
-
"@deepseek-ai/dsh-client-ui-renderer": "^0.1.
|
|
59
|
-
"@deepseek-ai/dsh-client-ui-
|
|
60
|
-
"@deepseek-ai/dsh-client-ui-
|
|
61
|
-
"@deepseek-ai/dsh-
|
|
62
|
-
"@deepseek-ai/dsh-
|
|
63
|
-
"@deepseek-ai/dsh-
|
|
51
|
+
"@deepseek-ai/dsh-api-remotes": "^0.1.6-alpha.2",
|
|
52
|
+
"@deepseek-ai/dsh-client-store": "^0.1.6-alpha.2",
|
|
53
|
+
"@deepseek-ai/dsh-client-test-runtime": "^0.1.6-alpha.2",
|
|
54
|
+
"@deepseek-ai/dsh-api-workspace-files": "^0.1.6-alpha.2",
|
|
55
|
+
"@deepseek-ai/dsh-client-ui-dockkit": "^0.1.6-alpha.2",
|
|
56
|
+
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.6-alpha.2",
|
|
57
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.6-alpha.2",
|
|
58
|
+
"@deepseek-ai/dsh-client-ui-renderer": "^0.1.6-alpha.2",
|
|
59
|
+
"@deepseek-ai/dsh-client-ui-session": "^0.1.6-alpha.2",
|
|
60
|
+
"@deepseek-ai/dsh-client-ui-sidebar-right": "^0.1.6-alpha.2",
|
|
61
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.6-alpha.2",
|
|
62
|
+
"@deepseek-ai/dsh-util-workspace-path": "^0.1.6-alpha.2",
|
|
63
|
+
"@deepseek-ai/dsh-session": "^0.1.6-alpha.2"
|
|
64
64
|
},
|
|
65
65
|
"files": [
|
|
66
66
|
"lib/index.js",
|