@qilin-agent/client-ui-workspace 3.1.6 → 3.1.8
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 +4 -4
- package/README.md +5 -1
- package/README.zh.md +5 -1
- package/lib/client.js +330 -53
- package/lib/types/client/context-menus.d.ts +28 -0
- package/lib/types/client/contract/slots.d.ts +29 -0
- package/lib/types/client/navigation.d.ts +13 -7
- package/lib/types/client/rows/Rows.d.ts +18 -2
- package/lib/types/client/rows/WorkspaceBrowser.d.ts +1 -1
- package/package.json +26 -24
package/README.i18n.yaml
CHANGED
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
en: 5e049b90c55eddb3
|
|
28
28
|
zh: e06dc8d0d25c013f
|
|
29
29
|
/qilin-agent-client-ui-workspace/use-this-package/search:
|
|
30
|
-
en:
|
|
31
|
-
zh:
|
|
30
|
+
en: 77fd4ac670f676cf
|
|
31
|
+
zh: 89277e09cafa0af4
|
|
32
32
|
/qilin-agent-client-ui-workspace/use-this-package/managing-sessions:
|
|
33
33
|
en: 36a910e6ad337e1c
|
|
34
34
|
zh: 9607173765bac0c7
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
en: 745e917ae00da6ab
|
|
49
49
|
zh: 32c745f9078829b8
|
|
50
50
|
/qilin-agent-client-ui-workspace/understand-the-implementation/view-state:
|
|
51
|
-
en:
|
|
52
|
-
zh:
|
|
51
|
+
en: 4b7f2f65d6259d33
|
|
52
|
+
zh: 7bbccd66050725f4
|
|
53
53
|
/qilin-agent-client-ui-workspace/understand-the-implementation/hover-cards:
|
|
54
54
|
en: f236cadca4c98088
|
|
55
55
|
zh: 8b36850c1d5f73d2
|
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ Hierarchy uses registered canonical paths only. It does not scan for projects or
|
|
|
43
43
|
|
|
44
44
|
### Search
|
|
45
45
|
|
|
46
|
-
Collapsed search is one header action beside the view and add actions: activating it expands the field across the header. A non-blank query replaces either browsing mode with one flat result list — case-insensitive title and Workspace substring matches appear immediately, while a 250 ms debounced Host request adds ranked current-conversation content matches and snippets. Each new query aborts the preceding request; a failed content search leaves metadata matches visible with a warning. The list is capped at 20. Choosing a result clears and collapses search, opens the Session, and scrolls its row into view in the configured browsing mode; grouped browsing also expands its Workspace and the full Session list when required.
|
|
46
|
+
Collapsed search is one header action beside the view and add actions: activating it expands the field across the header. A non-blank query replaces either browsing mode with one flat result list — case-insensitive title and Workspace substring matches appear immediately, while a 250 ms debounced Host request adds ranked current-conversation content matches and snippets. Each new query aborts the preceding request; a failed content search leaves metadata matches visible with a warning. The list is capped at 20. Choosing a result clears and collapses search, opens the Session, and scrolls its row into view in the configured browsing mode; grouped browsing also expands its Workspace and the full Session list when required. Opening or closing search in the expanded sidebar animates the header's trailing inset, inline padding, and gap together with the field over 180 ms, and a reduced-motion preference settles them at once.
|
|
47
47
|
|
|
48
48
|
### Managing sessions
|
|
49
49
|
|
|
@@ -89,8 +89,12 @@ The chip occupies the conversation hero's `conversation.hero.agentPreset` hole a
|
|
|
89
89
|
|
|
90
90
|
### View state
|
|
91
91
|
|
|
92
|
+
Workspace and Session rows take their metrics from the properties the sidebar root inherits to this region. The expanded-row padding minus the paint inset sets the leading cell, the label gap spaces the cells, and the inset itself rides a transparent border so the hover fill stays inset without moving content; a Session row shows the same gap on its title margin instead of the row. Trailing actions sit 13 px apart on 16 px control cells, and each button carries a 24 px click target centred by a -4 px margin. The time label pulls 1 px so its edge matches the action strip, the section label keeps a 1 px left offset, and Session insertion markers compensate the row's transparent border. On a coarse pointer the hover-only verb strip is always drawn, the archive verb yields its cell to the menu and pin verbs (it stays in the row menu), a tapped row keeps no hover fill, and a Workspace row toggles from Enter or Space.
|
|
93
|
+
|
|
92
94
|
Once the Workspace list baseline is ready, browser-persisted expansion and manual Session-order records retain only current Workspace ids plus Ungrouped and the flat-list account. `WorkspaceView.sessionIds` supplies real-Workspace membership, not Session display order. View actions require the current account orders explicitly. Flat-list membership and ordering use Session ids; row rendering adds status indicators once. Entering Manual snapshots every active account from the current display; reconciliation retains saved members that still belong to the account, removes departed members, and appends newly known members by recency. A new membership entry without a Session summary is omitted until that summary arrives, while an already saved slot survives a temporarily missing summary. During Workspace reconnection, Manual records an observed blank Session at the front of its saved flat and known group orders without removing other saved members; full membership reconciliation waits for the Workspace baseline. This reconciliation remains mounted while the sidebar is a rail or search replaces its body. Last updated derives directly from each current list snapshot without reading or writing saved positions; equal timestamps use Session ids as a stable tie-break. The shared sidebar projection hides rows whose durable Session summary has `origin: 'subagent'`, and each visible ordinary row inherits the blue activity indicator while any descendant reached through uninterrupted subagent-origin lineage is running. The same pure derivation reads the Schedule key from list projection values for grouped, flat, and search nodes; the package uses only the type-only `@qilin-agent/schedule/client` dependency and does not import the Schedule runtime or `ui-schedule`.
|
|
93
95
|
|
|
96
|
+
Row motion belongs to [AnimatedRows](../ui-primitives/src/AnimatedRows.tsx). The grouped tree and the flat list render through it and key every row with `data-row-key` (`workspace:<key>`, `session:<id>`, `overflow:<group>`, `empty`); it measures keyed rows before and after commits that change membership or order, glides and fades them with native animations, and paints removed rows as inert copies outside the scrolling list. Initial loading, drag commits, overflow expansion, and view-option changes settle immediately, and a reduced-motion preference skips the animation.
|
|
97
|
+
|
|
94
98
|
### Hover cards
|
|
95
99
|
|
|
96
100
|
Workspace and Session hover cards copy the value their row clips: activating a Workspace card writes its full directory path, while activating a non-blank Session card writes its full display title. A provisional blank New Session card remains read-only because its localized label is a placeholder rather than session content.
|
package/README.zh.md
CHANGED
|
@@ -43,7 +43,7 @@ kind: "package-reference"
|
|
|
43
43
|
|
|
44
44
|
### 搜索
|
|
45
45
|
|
|
46
|
-
折叠搜索是视图和添加操作旁的一枚区头按钮:激活后输入框会扩展并占据区头。非空白查询会以单一扁平结果列表替代任一浏览模式——不区分大小写的标题和 Workspace 子串匹配项会立即显示,经 250 ms 防抖的 Host 请求则会加入经过排序的当前对话内容匹配项及其摘要片段。每次新查询都会中止前一个请求;内容搜索失败时,元数据匹配项仍会显示,同时给出警告。列表最多显示 20 条结果。选择结果会清空并收起搜索、打开 Session,并在当前浏览模式中将其行滚动到可见区域;分组浏览还会按需展开所属 Workspace 和完整 Session
|
|
46
|
+
折叠搜索是视图和添加操作旁的一枚区头按钮:激活后输入框会扩展并占据区头。非空白查询会以单一扁平结果列表替代任一浏览模式——不区分大小写的标题和 Workspace 子串匹配项会立即显示,经 250 ms 防抖的 Host 请求则会加入经过排序的当前对话内容匹配项及其摘要片段。每次新查询都会中止前一个请求;内容搜索失败时,元数据匹配项仍会显示,同时给出警告。列表最多显示 20 条结果。选择结果会清空并收起搜索、打开 Session,并在当前浏览模式中将其行滚动到可见区域;分组浏览还会按需展开所属 Workspace 和完整 Session 列表。在展开的侧边栏中,打开或收起搜索会以 180 ms 动画一并改变区头的尾部内缩、行内内边距和间距,开启减少动态效果时则立即落位。
|
|
47
47
|
|
|
48
48
|
### 管理会话
|
|
49
49
|
|
|
@@ -89,8 +89,12 @@ chip 占据会话英雄区的 `conversation.hero.agentPreset` 槽位,把工作
|
|
|
89
89
|
|
|
90
90
|
### 视图状态
|
|
91
91
|
|
|
92
|
+
Workspace 与 Session 行采用侧边栏根节点继承给本区域的属性:展开态行内边距减去底色内缩决定前置单元格,标签间距决定单元格间隔,内缩本身由一条透明边框承载,因此悬停底色保持内缩而内容不移动;Session 行不在行上留该间距,而是在标题外边距上留同样的值。行尾操作按钮以 13 px 间隔排在 16 px 控制格上,每个按钮以 -4 px 补偿外边距承载居中的 24 px 点击热区。时间标签左收 1 px 以与操作条边缘对齐,区头标签保留 1 px 左偏移,Session 插入标记补偿该透明边框。粗指针(触屏)上仅悬停可见的操作条始终显示,归档动词把位置让给菜单与置顶动词(仍保留在行菜单里),被点按的行不会残留悬停底色,Workspace 行可用 Enter 或空格切换折叠。
|
|
93
|
+
|
|
92
94
|
Workspace 列表基线就绪后,浏览器持久化的展开状态和手动 Session 顺序记录只保留当前 Workspace id、Ungrouped 和单列表记账。`WorkspaceView.sessionIds` 提供真实 Workspace 的成员关系,而不提供 Session 显示顺序。视图操作要求显式传入当前各记账的顺序。单列表的成员筛选和排序使用 Session id,行渲染只计算一次状态指示。进入手动排序会从当前显示结果一次性记录每个有效记账;对账会保留仍属于该记账的已保存成员、移除已经离开的成员,并按最近更新时间追加新发现的成员。尚无 Session 摘要的新成员会等摘要到达后再加入,而已经保存的位置在摘要暂时缺失时仍会保留。Workspace 重连期间,手动排序会将已观察到的空白 Session 记录到已保存的单列表及已知分组顺序首位,不移除其他已保存成员;完整成员对账等待 Workspace 基线到齐。即使侧边栏收成窄栏或搜索替代列表主体,这项对账也保持挂载。最近更新直接从每份当前列表快照派生,不读取或写入已保存位置;时间相同时按 Session id 稳定排序。共享侧边栏投影会隐藏持久化 Session 摘要中带有 `origin: 'subagent'` 的行;每个可见普通行都会在经不间断的 subagent 谱系可达的任一后代运行时继承蓝色活动指示器。同一项纯派生逻辑还会为分组、平铺与搜索节点读取列表 projection value 中的 Schedule key;本包只使用纯类型依赖 `@qilin-agent/schedule/client`,不会导入 Schedule 运行时或 `ui-schedule`。
|
|
93
95
|
|
|
96
|
+
行动效由 [AnimatedRows](../ui-primitives/src/AnimatedRows.tsx) 负责。分组树与平铺列表都经它渲染,并为每一行写上 `data-row-key`(`workspace:<key>`、`session:<id>`、`overflow:<group>`、`empty`);它在改变成员关系或顺序的提交前后测量带键行,以原生动画平移与渐隐,并把离场行作为惰性副本绘制在滚动列表之外。首次加载、拖拽提交、展开溢出和视图选项切换都立即落位,开启减少动态效果时完全跳过动画。
|
|
97
|
+
|
|
94
98
|
### 悬浮卡片
|
|
95
99
|
|
|
96
100
|
Workspace 与 Session 悬浮卡片会复制对应行被截断的值:激活 Workspace 卡片会写入其完整目录路径,激活非空白 Session 卡片则会写入其完整显示标题。临时的空白「新会话」卡片保持只读,因为其本地化标签是占位文案,并非会话内容。
|
package/lib/client.js
CHANGED
|
@@ -9,6 +9,120 @@ window.__ModuleLoader__.load({
|
|
|
9
9
|
let _qilin_agent_kylin = require("@qilin-agent/kylin");
|
|
10
10
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
11
11
|
let react = require("react");
|
|
12
|
+
//#region lib/types/client/context-menus.js
|
|
13
|
+
/**
|
|
14
|
+
* Register the built-in Session and Workspace actions on the shared menu.
|
|
15
|
+
* @param ctx - workspace plugin context owning menus, membership, and locale.
|
|
16
|
+
* @param actions - shared row callbacks; execution always uses the captured object.
|
|
17
|
+
*/
|
|
18
|
+
function registerWorkspaceMenus(ctx, actions) {
|
|
19
|
+
const t = ctx.locale.bind("workspace");
|
|
20
|
+
const state = () => ctx.workspaces.list.getSnapshot();
|
|
21
|
+
ctx.effect(() => ctx.contextMenus.register({
|
|
22
|
+
id: "workspace.session.pin",
|
|
23
|
+
target: "session",
|
|
24
|
+
order: 100,
|
|
25
|
+
observe: () => [ctx.workspaces.list, ctx.locale],
|
|
26
|
+
resolve: ({ sessionId }) => {
|
|
27
|
+
const pinned = state().pinnedSessionIds.includes(sessionId);
|
|
28
|
+
return [{
|
|
29
|
+
id: "pin",
|
|
30
|
+
label: t(pinned ? "menu.unpinSession" : "menu.pinSession"),
|
|
31
|
+
icon: { key: pinned ? "workspace.unpin" : "workspace.pin" },
|
|
32
|
+
run: () => {
|
|
33
|
+
(pinned ? actions.unpin : actions.pin)(sessionId);
|
|
34
|
+
}
|
|
35
|
+
}];
|
|
36
|
+
}
|
|
37
|
+
}), "ui-workspace: pin menu");
|
|
38
|
+
ctx.effect(() => ctx.contextMenus.register({
|
|
39
|
+
id: "workspace.session.rename",
|
|
40
|
+
target: "session",
|
|
41
|
+
order: 200,
|
|
42
|
+
resolve: ({ sessionId, displayTitle }) => [{
|
|
43
|
+
id: "rename",
|
|
44
|
+
label: t("rename"),
|
|
45
|
+
icon: { key: "workspace.rename" },
|
|
46
|
+
commandId: "session.rename",
|
|
47
|
+
run: () => {
|
|
48
|
+
actions.requestSessionRename(sessionId, displayTitle);
|
|
49
|
+
}
|
|
50
|
+
}]
|
|
51
|
+
}), "ui-workspace: rename menu");
|
|
52
|
+
ctx.effect(() => ctx.contextMenus.register({
|
|
53
|
+
id: "workspace.session.fork",
|
|
54
|
+
target: "session",
|
|
55
|
+
order: 300,
|
|
56
|
+
resolve: ({ sessionId }) => [{
|
|
57
|
+
id: "fork",
|
|
58
|
+
label: t("menu.fork"),
|
|
59
|
+
icon: { key: "workspace.fork" },
|
|
60
|
+
commandId: "session.fork",
|
|
61
|
+
run: () => {
|
|
62
|
+
actions.fork(sessionId);
|
|
63
|
+
}
|
|
64
|
+
}]
|
|
65
|
+
}), "ui-workspace: fork menu");
|
|
66
|
+
ctx.effect(() => ctx.contextMenus.register({
|
|
67
|
+
id: "workspace.session.id",
|
|
68
|
+
target: "session",
|
|
69
|
+
order: 450,
|
|
70
|
+
resolve: ({ sessionId }) => [{
|
|
71
|
+
id: "copy",
|
|
72
|
+
label: t("menu.sessionId"),
|
|
73
|
+
icon: { key: "workspace.copy" },
|
|
74
|
+
separatorBefore: true,
|
|
75
|
+
run: () => {
|
|
76
|
+
actions.copySessionId(sessionId);
|
|
77
|
+
}
|
|
78
|
+
}]
|
|
79
|
+
}), "ui-workspace: Session id menu");
|
|
80
|
+
ctx.effect(() => ctx.contextMenus.register({
|
|
81
|
+
id: "workspace.session.archive",
|
|
82
|
+
target: "session",
|
|
83
|
+
order: 600,
|
|
84
|
+
resolve: ({ sessionId }) => [{
|
|
85
|
+
id: "archive",
|
|
86
|
+
label: t("menu.archiveSession"),
|
|
87
|
+
icon: { key: "workspace.archive" },
|
|
88
|
+
separatorBefore: true,
|
|
89
|
+
afterContent: true,
|
|
90
|
+
commandId: "session.archive",
|
|
91
|
+
run: () => {
|
|
92
|
+
actions.archive(sessionId);
|
|
93
|
+
}
|
|
94
|
+
}]
|
|
95
|
+
}), "ui-workspace: archive menu");
|
|
96
|
+
ctx.effect(() => ctx.contextMenus.register({
|
|
97
|
+
id: "workspace.header.rename",
|
|
98
|
+
target: "workspace",
|
|
99
|
+
order: 100,
|
|
100
|
+
resolve: ({ workspaceId, displayTitle }) => [{
|
|
101
|
+
id: "rename",
|
|
102
|
+
label: t("rename"),
|
|
103
|
+
icon: { key: "workspace.rename" },
|
|
104
|
+
run: () => {
|
|
105
|
+
actions.requestWorkspaceAction(workspaceId, displayTitle, "rename");
|
|
106
|
+
}
|
|
107
|
+
}]
|
|
108
|
+
}), "ui-workspace: Workspace rename menu");
|
|
109
|
+
ctx.effect(() => ctx.contextMenus.register({
|
|
110
|
+
id: "workspace.header.delete",
|
|
111
|
+
target: "workspace",
|
|
112
|
+
order: 300,
|
|
113
|
+
resolve: ({ workspaceId, displayTitle }) => [{
|
|
114
|
+
id: "delete",
|
|
115
|
+
label: t("delete.workspace"),
|
|
116
|
+
icon: { key: "workspace.delete" },
|
|
117
|
+
danger: true,
|
|
118
|
+
separatorBefore: true,
|
|
119
|
+
run: () => {
|
|
120
|
+
actions.requestWorkspaceAction(workspaceId, displayTitle, "delete");
|
|
121
|
+
}
|
|
122
|
+
}]
|
|
123
|
+
}), "ui-workspace: Workspace delete menu");
|
|
124
|
+
}
|
|
125
|
+
//#endregion
|
|
12
126
|
//#region lib/types/client/shortcuts.js
|
|
13
127
|
/**
|
|
14
128
|
* Create the private browser request source shared by commands and controls.
|
|
@@ -724,29 +838,49 @@ window.__ModuleLoader__.load({
|
|
|
724
838
|
};
|
|
725
839
|
}, "ui-workspace: Workspace navigation policy");
|
|
726
840
|
}
|
|
727
|
-
async connectWorkspace(workspaceId) {
|
|
841
|
+
async connectWorkspace(workspaceId, options) {
|
|
728
842
|
const workspace = this.workspaces.list.getSnapshot().items.find((item) => item.workspaceId === workspaceId);
|
|
729
843
|
if (workspace === void 0) throw new Error(`uiWorkspace.connectWorkspace: unknown workspace ${workspaceId}`);
|
|
730
844
|
const inflight = this.connecting.get(workspaceId);
|
|
731
|
-
if (inflight !== void 0) return inflight;
|
|
845
|
+
if (inflight !== void 0 && inflight.agentPreset === options?.agentPreset) return inflight.attempt;
|
|
732
846
|
const archived = this.workspaces.list.getSnapshot().archivedSessionIds;
|
|
733
847
|
const sessions = this.sessions.list.getSnapshot();
|
|
734
848
|
for (const id of sessions.ids) {
|
|
735
849
|
const summary = sessions.byId[id];
|
|
736
|
-
|
|
850
|
+
const listed = summary?.projectionValues?.agentPreset;
|
|
851
|
+
if (summary !== void 0 && summary.blank && summary.cwd === workspace.path && workspace.sessionIds.includes(summary.id) && !archived.includes(summary.id) && (options?.agentPreset === void 0 || typeof listed !== "string" || listed === options.agentPreset)) {
|
|
852
|
+
const reuse = this.sessions.create({
|
|
853
|
+
workspaceId,
|
|
854
|
+
sessionId: summary.id,
|
|
855
|
+
...options?.agentPreset === void 0 ? {} : { agentPreset: options.agentPreset }
|
|
856
|
+
}).finally(() => {
|
|
857
|
+
this.connecting.delete(workspaceId);
|
|
858
|
+
});
|
|
859
|
+
this.connecting.set(workspaceId, {
|
|
860
|
+
agentPreset: options?.agentPreset,
|
|
861
|
+
attempt: reuse
|
|
862
|
+
});
|
|
863
|
+
return reuse;
|
|
864
|
+
}
|
|
737
865
|
}
|
|
738
|
-
const attempt = this.sessions.create({
|
|
866
|
+
const attempt = this.sessions.create({
|
|
867
|
+
workspaceId,
|
|
868
|
+
...options?.agentPreset === void 0 ? {} : { agentPreset: options.agentPreset }
|
|
869
|
+
}).finally(() => {
|
|
739
870
|
this.connecting.delete(workspaceId);
|
|
740
871
|
});
|
|
741
|
-
this.connecting.set(workspaceId,
|
|
872
|
+
this.connecting.set(workspaceId, {
|
|
873
|
+
agentPreset: options?.agentPreset,
|
|
874
|
+
attempt
|
|
875
|
+
});
|
|
742
876
|
return attempt;
|
|
743
877
|
}
|
|
744
878
|
openSession(target) {
|
|
745
879
|
this.replaceMain(target, this.lifetime.signal);
|
|
746
880
|
}
|
|
747
|
-
async openWorkspace(workspaceId, beforeOpen) {
|
|
881
|
+
async openWorkspace(workspaceId, beforeOpen, options) {
|
|
748
882
|
const navigation = AbortSignal.any([this.ctx.layout.beginNavigation(), this.lifetime.signal]);
|
|
749
|
-
const sessionId = await this.connectWorkspace(workspaceId);
|
|
883
|
+
const sessionId = await this.connectWorkspace(workspaceId, options);
|
|
750
884
|
if (navigation.aborted) return;
|
|
751
885
|
this.replaceMain(sessionId, navigation, beforeOpen);
|
|
752
886
|
}
|
|
@@ -759,8 +893,9 @@ window.__ModuleLoader__.load({
|
|
|
759
893
|
if (!navigation.aborted) this.replaceMain(childId, navigation);
|
|
760
894
|
}
|
|
761
895
|
startSession(workspaceId, options) {
|
|
762
|
-
const
|
|
763
|
-
const
|
|
896
|
+
const { agentPreset, ...draft } = options ?? {};
|
|
897
|
+
const draftOptions = options === void 0 ? void 0 : structuredClone(draft);
|
|
898
|
+
const initializeDraft = draftOptions !== void 0 && (draftOptions.prompt !== void 0 || (draftOptions.whenDraftExists ?? (draftOptions.clearPreviousDraft === true ? "replace" : "keep")) === "replace");
|
|
764
899
|
const workspace = this.workspaces.list.getSnapshot();
|
|
765
900
|
const sessions = this.sessions.list.getSnapshot();
|
|
766
901
|
const current = this.mainReference?.sessionId;
|
|
@@ -782,7 +917,7 @@ window.__ModuleLoader__.load({
|
|
|
782
917
|
const binding = this.sessions.binding(id);
|
|
783
918
|
if (binding === void 0) this.draftPreparationFailed();
|
|
784
919
|
this.prepareDraft(binding, draftOptions);
|
|
785
|
-
} : void 0).catch((reason) => {
|
|
920
|
+
} : void 0, agentPreset === void 0 ? void 0 : { agentPreset }).catch((reason) => {
|
|
786
921
|
console.warn("new session failed:", reason);
|
|
787
922
|
});
|
|
788
923
|
}
|
|
@@ -956,7 +1091,7 @@ window.__ModuleLoader__.load({
|
|
|
956
1091
|
}
|
|
957
1092
|
//#endregion
|
|
958
1093
|
//#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-workspace/src/client/rows/Rows.module.css.mjs
|
|
959
|
-
const css$2 = ".RrwzeW_projectRow,.RrwzeW_sessionRow{padding:0 8px;cursor:pointer;user-select:none;color:var(--qilin-alias-label-primary);border-radius:8px;
|
|
1094
|
+
const css$2 = ".RrwzeW_projectRow,.RrwzeW_sessionRow{align-items:center;gap:var(--qilin-sidebar-label-gap);border-inline:var(--qilin-sidebar-paint-inset) solid transparent;box-sizing:border-box;padding:0 8px;cursor:pointer;user-select:none;color:var(--qilin-alias-label-primary);background-clip:padding-box;border-radius:8px;padding-inline-start:calc(var(--qilin-sidebar-row-padding) - var(--qilin-sidebar-paint-inset) + var(--dsh-workspace-indent,0px));display:flex}@media (hover:hover){.RrwzeW_projectRow:hover,.RrwzeW_sessionRow:hover{background-color:var(--qilin-alias-interactive-bg-hover)}}.RrwzeW_sessionRow.RrwzeW_selected{background-color:var(--qilin-alias-interactive-bg-hover)}.RrwzeW_searchResultRow{box-sizing:border-box;width:100%;min-height:48px;padding:4px calc(var(--qilin-sidebar-row-padding) - var(--qilin-sidebar-paint-inset));border:none;border-inline:var(--qilin-sidebar-paint-inset) solid transparent;cursor:pointer;text-align:left;color:var(--qilin-alias-label-primary);background:padding-box padding-box;border-radius:8px;flex-direction:column;align-items:stretch;display:flex}@media (hover:hover){.RrwzeW_searchResultRow:hover{background-color:var(--qilin-alias-interactive-bg-hover)}}.RrwzeW_searchResultRow.RrwzeW_selected{background-color:var(--qilin-alias-interactive-bg-hover)}.RrwzeW_searchResultHeading{align-items:center;min-width:0;display:flex}.RrwzeW_searchResultTitle{min-width:0;margin:0 var(--qilin-sidebar-label-gap);text-overflow:ellipsis;white-space:nowrap;flex:0 auto;font-size:14px;line-height:20px;overflow:hidden}.RrwzeW_searchResultMeta{min-width:0;margin-left:calc(16px + var(--qilin-sidebar-label-gap));align-items:center;gap:6px;display:flex}.RrwzeW_searchResultWorkspace,.RrwzeW_searchResultSnippet{text-overflow:ellipsis;white-space:nowrap;font-size:12px;line-height:17px;overflow:hidden}.RrwzeW_searchResultWorkspace{max-width:40%;color:var(--qilin-alias-label-tertiary);flex:none}.RrwzeW_searchResultSnippet{min-width:0;color:var(--qilin-alias-label-secondary);flex:1}.RrwzeW_projectRow{box-sizing:border-box;align-items:center;height:34px}.RrwzeW_projectRow .RrwzeW_rowActions{height:20px}.RrwzeW_sessionRow{gap:0;height:32px}.RrwzeW_sessionRow .RrwzeW_title{margin:0 6px 0 var(--qilin-sidebar-label-gap)}.RrwzeW_slot{width:16px;height:20px;color:var(--qilin-alias-label-tertiary);flex:none;justify-content:center;align-items:center;display:inline-flex}.RrwzeW_visuallyHidden{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.RrwzeW_folderActive{color:var(--qilin-alias-state-business-primary)}.RrwzeW_projectRow .RrwzeW_chevron{display:none}@media (hover:hover){.RrwzeW_projectRow:hover .RrwzeW_chevron{display:inline-flex}.RrwzeW_projectRow:hover .RrwzeW_folder{display:none}}.RrwzeW_arrow{transition:transform .15s var(--ds-ease-in-out)}.RrwzeW_arrowOpen{transform:rotate(90deg)}.RrwzeW_projectText{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.RrwzeW_title{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:14px;line-height:20px;overflow:hidden}.RrwzeW_renameInput{border:1px solid var(--qilin-alias-border-l4);background:var(--qilin-alias-button-elevated-fill);min-width:0;color:inherit;border-radius:4px;outline:none;padding:0 2px;font-size:14px;line-height:20px}.RrwzeW_sessionRow .RrwzeW_title{flex:1}.RrwzeW_sessionRow .RrwzeW_title[data-scrolled]{mask-image:linear-gradient(90deg,#0000,#000 12px)}.RrwzeW_sessionRow .RrwzeW_title[data-clipped]{mask-image:linear-gradient(270deg,#0000,#000 12px)}.RrwzeW_sessionRow .RrwzeW_title[data-scrolled][data-clipped]{mask-image:linear-gradient(90deg,#0000,#000 12px calc(100% - 12px),#0000)}@media (hover:hover){.RrwzeW_sessionRow:hover .RrwzeW_title,.RrwzeW_sessionRow.RrwzeW_menuOpen .RrwzeW_title{text-overflow:clip}}.RrwzeW_meta{text-overflow:ellipsis;white-space:nowrap;color:var(--qilin-alias-label-tertiary);font-size:12px;line-height:20px;overflow:hidden}.RrwzeW_time{color:var(--qilin-alias-label-tertiary);flex:none;margin-inline-end:-1px;font-size:12px;line-height:20px}.RrwzeW_dot{flex:none}.RrwzeW_pinIndicator{width:16px;height:20px;color:var(--qilin-alias-label-caption);flex:none;justify-content:center;align-items:center;margin-left:6px;display:inline-flex}.RrwzeW_sessionRow.RrwzeW_menuOpen .RrwzeW_pinIndicator{display:none}@media (hover:hover){.RrwzeW_sessionRow:hover .RrwzeW_pinIndicator{display:none}}@media (hover:none){.RrwzeW_sessionRow .RrwzeW_pinIndicator{display:none}}.RrwzeW_rowActions{flex:none;align-items:center;gap:13px;display:none}.RrwzeW_projectRow.RrwzeW_menuOpen .RrwzeW_rowActions,.RrwzeW_sessionRow.RrwzeW_menuOpen .RrwzeW_rowActions,.RrwzeW_projectRow:focus-within .RrwzeW_rowActions,.RrwzeW_sessionRow:focus-within .RrwzeW_rowActions{display:inline-flex}.RrwzeW_sessionRow.RrwzeW_menuOpen .RrwzeW_time{display:none}@media (hover:hover){.RrwzeW_projectRow:hover .RrwzeW_rowActions,.RrwzeW_sessionRow:hover .RrwzeW_rowActions{display:inline-flex}.RrwzeW_sessionRow:hover .RrwzeW_time{display:none}}@media (hover:none){.RrwzeW_projectRow .RrwzeW_rowActions,.RrwzeW_sessionRow .RrwzeW_rowActions{display:inline-flex}.RrwzeW_projectRow[aria-expanded=false] .RrwzeW_rowActions,.RrwzeW_sessionRow .RrwzeW_time,.RrwzeW_secondaryAction{display:none}}.RrwzeW_projectRow.RrwzeW_menuOpen,.RrwzeW_sessionRow.RrwzeW_menuOpen{background-color:var(--qilin-alias-interactive-bg-hover)}.RrwzeW_sessionRow.RrwzeW_dropBefore,.RrwzeW_sessionRow.RrwzeW_dropAfter{position:relative}.RrwzeW_sessionRow.RrwzeW_dropBefore:before,.RrwzeW_sessionRow.RrwzeW_dropAfter:after{content:\"\";z-index:1;left:calc(-1 * var(--qilin-sidebar-paint-inset));right:calc(4px - var(--qilin-sidebar-paint-inset));background:linear-gradient(55deg, transparent calc(50% - 1px), var(--qilin-alias-state-business-primary) calc(50% - 1px) calc(50% + 1px), transparent calc(50% + 1px)) 0 0 / 5px 7px no-repeat, linear-gradient(125deg, transparent calc(50% - 1px), var(--qilin-alias-state-business-primary) calc(50% - 1px) calc(50% + 1px), transparent calc(50% + 1px)) 0 5px / 5px 7px no-repeat, linear-gradient(var(--qilin-alias-state-business-primary) 0 0) 4px 5px / calc(100% - 4px) 2px no-repeat;pointer-events:none;height:12px;position:absolute}.RrwzeW_sessionRow.RrwzeW_dropBefore:before{top:-7px}.RrwzeW_sessionRow.RrwzeW_dropAfter:after{bottom:-7px}.RrwzeW_hoverContent{flex-direction:column;gap:8px;display:flex}.RrwzeW_hoverTitle{color:#fff;overflow-wrap:break-word;font-size:14px;line-height:20px}.RrwzeW_hoverPath{color:#cfd3d6;word-break:break-all;font-size:12px;line-height:16px}.RrwzeW_hoverTime{color:#cfd3d6;font-size:12px;line-height:16px}.RrwzeW_hoverStatus{color:#adb2b8;align-items:center;gap:8px;font-size:12px;line-height:20px;display:flex}.RrwzeW_iconButton{cursor:pointer;width:24px;height:24px;color:var(--qilin-alias-label-tertiary);background:0 0;border:none;border-radius:4px;flex:none;justify-content:center;align-items:center;margin:-4px;padding:0;display:inline-flex}.RrwzeW_iconButton:focus-visible{outline-offset:-2px}.RrwzeW_iconButton:hover{color:var(--qilin-alias-label-primary)}.RrwzeW_chevron{color:var(--qilin-alias-label-caption)}@media (prefers-reduced-motion:reduce){.RrwzeW_arrow{transition:none;animation:none}}";
|
|
960
1095
|
const tagId$2 = "@qilin-agent/client-ui-workspace/Rows.module.css";
|
|
961
1096
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
|
|
962
1097
|
const tag = document.createElement("style");
|
|
@@ -986,7 +1121,6 @@ window.__ModuleLoader__.load({
|
|
|
986
1121
|
"projectRow": "RrwzeW_projectRow",
|
|
987
1122
|
"projectText": "RrwzeW_projectText",
|
|
988
1123
|
"renameInput": "RrwzeW_renameInput",
|
|
989
|
-
"row-in": "RrwzeW_row-in",
|
|
990
1124
|
"rowActions": "RrwzeW_rowActions",
|
|
991
1125
|
"searchResultHeading": "RrwzeW_searchResultHeading",
|
|
992
1126
|
"searchResultMeta": "RrwzeW_searchResultMeta",
|
|
@@ -994,6 +1128,7 @@ window.__ModuleLoader__.load({
|
|
|
994
1128
|
"searchResultSnippet": "RrwzeW_searchResultSnippet",
|
|
995
1129
|
"searchResultTitle": "RrwzeW_searchResultTitle",
|
|
996
1130
|
"searchResultWorkspace": "RrwzeW_searchResultWorkspace",
|
|
1131
|
+
"secondaryAction": "RrwzeW_secondaryAction",
|
|
997
1132
|
"selected": "RrwzeW_selected",
|
|
998
1133
|
"sessionRow": "RrwzeW_sessionRow",
|
|
999
1134
|
"slot": "RrwzeW_slot",
|
|
@@ -1008,9 +1143,10 @@ window.__ModuleLoader__.load({
|
|
|
1008
1143
|
* all data and callbacks arrive via props. Hover swaps (folder->chevron,
|
|
1009
1144
|
* time->ellipsis, action buttons) are CSS-only, and a session row's clipped
|
|
1010
1145
|
* title marquees programmatically while the row is hovered, fading both
|
|
1011
|
-
* clipping edges from the depth of its travel. Row ... menus
|
|
1012
|
-
*
|
|
1013
|
-
*
|
|
1146
|
+
* clipping edges from the depth of its travel. Row ... menus cover workspace
|
|
1147
|
+
* Rename/Delete and session Rename/Fork/Archive; a right-click on the row
|
|
1148
|
+
* captures the same object for the shared context menu. The session and
|
|
1149
|
+
* workspace hover cards are suppressed while a menu is open.
|
|
1014
1150
|
*/
|
|
1015
1151
|
/** Row display title: blank rows show the localized New Session label. */
|
|
1016
1152
|
function displayTitle(node, t) {
|
|
@@ -1018,10 +1154,6 @@ window.__ModuleLoader__.load({
|
|
|
1018
1154
|
}
|
|
1019
1155
|
const MIN_TITLE_REVEAL_PX = 8;
|
|
1020
1156
|
const TITLE_MARQUEE_PX_PER_MS = .03;
|
|
1021
|
-
/** Whether the platform asked for reduced motion; jsdom implements no matchMedia. */
|
|
1022
|
-
function prefersReducedMotion() {
|
|
1023
|
-
return typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
1024
|
-
}
|
|
1025
1157
|
/**
|
|
1026
1158
|
* Place the title's scroll position and publish the stylesheet's fade-mask
|
|
1027
1159
|
* hooks: `data-scrolled` while the title has left its start (left fade) and
|
|
@@ -1073,13 +1205,14 @@ window.__ModuleLoader__.load({
|
|
|
1073
1205
|
cancelAnimationFrame(frame.current);
|
|
1074
1206
|
}, []);
|
|
1075
1207
|
return (0, react.useMemo)(() => ({
|
|
1076
|
-
enter: () => {
|
|
1208
|
+
enter: (event) => {
|
|
1209
|
+
if (event.pointerType === "touch") return;
|
|
1077
1210
|
/* v8 ignore next -- defensive: the title span renders unconditionally. */
|
|
1078
1211
|
if (title.current === null) return;
|
|
1079
1212
|
const element = title.current;
|
|
1080
1213
|
const range = element.scrollWidth - element.clientWidth;
|
|
1081
1214
|
if (range <= MIN_TITLE_REVEAL_PX) return;
|
|
1082
|
-
if (prefersReducedMotion()) {
|
|
1215
|
+
if ((0, _qilin_agent_client_ui_primitives.prefersReducedMotion)()) {
|
|
1083
1216
|
placeTitle(element, range, range);
|
|
1084
1217
|
return;
|
|
1085
1218
|
}
|
|
@@ -1165,7 +1298,7 @@ window.__ModuleLoader__.load({
|
|
|
1165
1298
|
* @param props.t - the browser root's locale seat.
|
|
1166
1299
|
* @returns the row element.
|
|
1167
1300
|
*/
|
|
1168
|
-
function ProjectRowItem({ group, containsCurrentDescendant = false, onToggle, onCreate, actions, drag, home, t }) {
|
|
1301
|
+
function ProjectRowItem({ group, containsCurrentDescendant = false, onToggle, onCreate, actions, drag, home, menu, t }) {
|
|
1169
1302
|
const row = group;
|
|
1170
1303
|
const label = row.workspaceId === void 0 ? t("group.ungrouped") : row.label;
|
|
1171
1304
|
const active = containsCurrentDescendant || group.expanded && group.containsCurrent;
|
|
@@ -1173,18 +1306,29 @@ window.__ModuleLoader__.load({
|
|
|
1173
1306
|
const workspaceMenuItems = [{
|
|
1174
1307
|
id: "rename",
|
|
1175
1308
|
label: t("rename"),
|
|
1176
|
-
icon: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.
|
|
1309
|
+
icon: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconEditOutlineRegular, {})
|
|
1177
1310
|
}, {
|
|
1178
1311
|
id: "delete",
|
|
1179
1312
|
label: t("delete.workspace"),
|
|
1180
|
-
icon: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.
|
|
1313
|
+
icon: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconTrashOutlineRegular, {}),
|
|
1181
1314
|
danger: true
|
|
1182
1315
|
}];
|
|
1316
|
+
const menuProps = row.workspaceId === void 0 ? void 0 : menu?.(row.workspaceId, row.cwd, label);
|
|
1183
1317
|
const ownRow = (0, react_jsx_runtime.jsxs)("div", {
|
|
1184
1318
|
className: clsx(Rows_module_css_default.projectRow, menuOpen && Rows_module_css_default.menuOpen),
|
|
1185
1319
|
role: "treeitem",
|
|
1320
|
+
"data-row-key": `workspace:${row.key}`,
|
|
1186
1321
|
"aria-expanded": row.expanded,
|
|
1322
|
+
tabIndex: 0,
|
|
1323
|
+
...menuProps,
|
|
1187
1324
|
onClick: onToggle,
|
|
1325
|
+
onKeyDown: (event) => {
|
|
1326
|
+
menuProps?.onKeyDown?.(event);
|
|
1327
|
+
if (event.defaultPrevented) return;
|
|
1328
|
+
if (event.target !== event.currentTarget || !["Enter", " "].includes(event.key)) return;
|
|
1329
|
+
event.preventDefault();
|
|
1330
|
+
onToggle();
|
|
1331
|
+
},
|
|
1188
1332
|
draggable: drag !== void 0,
|
|
1189
1333
|
onDragStart: drag === void 0 ? void 0 : (e) => {
|
|
1190
1334
|
e.dataTransfer.effectAllowed = "move";
|
|
@@ -1195,11 +1339,11 @@ window.__ModuleLoader__.load({
|
|
|
1195
1339
|
children: [
|
|
1196
1340
|
(0, react_jsx_runtime.jsx)("span", {
|
|
1197
1341
|
className: clsx(Rows_module_css_default.slot, Rows_module_css_default.folder, active && Rows_module_css_default.folderActive),
|
|
1198
|
-
children: row.expanded ? (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.
|
|
1342
|
+
children: row.expanded ? (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconFolderOpenRegular, {}) : (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconFolderCloseRegular, {})
|
|
1199
1343
|
}),
|
|
1200
1344
|
(0, react_jsx_runtime.jsx)("span", {
|
|
1201
1345
|
className: clsx(Rows_module_css_default.slot, Rows_module_css_default.chevron),
|
|
1202
|
-
children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.
|
|
1346
|
+
children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconTriangleRightFillRegular, { className: clsx(Rows_module_css_default.arrow, row.expanded && Rows_module_css_default.arrowOpen) })
|
|
1203
1347
|
}),
|
|
1204
1348
|
(0, react_jsx_runtime.jsx)("span", {
|
|
1205
1349
|
className: Rows_module_css_default.projectText,
|
|
@@ -1233,7 +1377,7 @@ window.__ModuleLoader__.load({
|
|
|
1233
1377
|
e.stopPropagation();
|
|
1234
1378
|
setMenuOpen((v) => !v);
|
|
1235
1379
|
},
|
|
1236
|
-
children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.
|
|
1380
|
+
children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconEllipsisOutlineRegular, {})
|
|
1237
1381
|
})
|
|
1238
1382
|
}), (0, react_jsx_runtime.jsx)("button", {
|
|
1239
1383
|
type: "button",
|
|
@@ -1243,7 +1387,7 @@ window.__ModuleLoader__.load({
|
|
|
1243
1387
|
e.stopPropagation();
|
|
1244
1388
|
onCreate();
|
|
1245
1389
|
},
|
|
1246
|
-
children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.
|
|
1390
|
+
children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconPlusOutlineRegular, { size: 14 })
|
|
1247
1391
|
})]
|
|
1248
1392
|
})
|
|
1249
1393
|
]
|
|
@@ -1424,8 +1568,9 @@ window.__ModuleLoader__.load({
|
|
|
1424
1568
|
* @param props.t - the browser root's locale seat.
|
|
1425
1569
|
* @returns the session row.
|
|
1426
1570
|
*/
|
|
1427
|
-
function SessionNodeItem({ node, currentId, now, onOpen, onRename, onFork, onArchive, onCopyId, onPin, onUnpin, onReveal, drag, renderSlot, t }) {
|
|
1571
|
+
function SessionNodeItem({ node, currentId, now, onOpen, onRename, onFork, onArchive, onCopyId, onPin, onUnpin, onReveal, drag, renderSlot, menu, t }) {
|
|
1428
1572
|
const row = node;
|
|
1573
|
+
const menuProps = row.blank ? void 0 : menu?.(node.id, row.title);
|
|
1429
1574
|
const title = displayTitle(node, t);
|
|
1430
1575
|
const selected = node.id === currentId;
|
|
1431
1576
|
const statuses = sessionStatuses(node, t);
|
|
@@ -1449,17 +1594,17 @@ window.__ModuleLoader__.load({
|
|
|
1449
1594
|
{
|
|
1450
1595
|
id: "rename",
|
|
1451
1596
|
label: t("rename"),
|
|
1452
|
-
icon: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.
|
|
1597
|
+
icon: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconEditOutlineRegular, {})
|
|
1453
1598
|
},
|
|
1454
1599
|
{
|
|
1455
1600
|
id: "fork",
|
|
1456
1601
|
label: t("menu.fork"),
|
|
1457
|
-
icon: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.
|
|
1602
|
+
icon: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconBranchOutlineRegular, {})
|
|
1458
1603
|
},
|
|
1459
1604
|
{
|
|
1460
1605
|
id: "archive",
|
|
1461
1606
|
label: t("menu.archiveSession"),
|
|
1462
|
-
icon: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.
|
|
1607
|
+
icon: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconArchiveOutlineRegular, { size: 16 })
|
|
1463
1608
|
},
|
|
1464
1609
|
{
|
|
1465
1610
|
id: "copyId",
|
|
@@ -1472,7 +1617,9 @@ window.__ModuleLoader__.load({
|
|
|
1472
1617
|
ref: rowRef,
|
|
1473
1618
|
className: clsx(Rows_module_css_default.sessionRow, selected && Rows_module_css_default.selected, menuOpen && Rows_module_css_default.menuOpen, drag?.marker === "before" && Rows_module_css_default.dropBefore, drag?.marker === "after" && Rows_module_css_default.dropAfter),
|
|
1474
1619
|
role: "treeitem",
|
|
1620
|
+
"data-row-key": `session:${node.id}`,
|
|
1475
1621
|
"aria-selected": selected,
|
|
1622
|
+
...menuProps,
|
|
1476
1623
|
onClick: () => {
|
|
1477
1624
|
onOpen(node.id);
|
|
1478
1625
|
},
|
|
@@ -1538,7 +1685,7 @@ window.__ModuleLoader__.load({
|
|
|
1538
1685
|
e.stopPropagation();
|
|
1539
1686
|
setMenuOpen((v) => !v);
|
|
1540
1687
|
},
|
|
1541
|
-
children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.
|
|
1688
|
+
children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconEllipsisOutlineRegular, {})
|
|
1542
1689
|
})
|
|
1543
1690
|
}),
|
|
1544
1691
|
(0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.Tooltip, {
|
|
@@ -1548,13 +1695,13 @@ window.__ModuleLoader__.load({
|
|
|
1548
1695
|
portal: true,
|
|
1549
1696
|
children: (0, react_jsx_runtime.jsx)("button", {
|
|
1550
1697
|
type: "button",
|
|
1551
|
-
className: Rows_module_css_default.iconButton,
|
|
1698
|
+
className: clsx(Rows_module_css_default.iconButton, Rows_module_css_default.secondaryAction),
|
|
1552
1699
|
"aria-label": t("menu.archiveSession"),
|
|
1553
1700
|
onClick: (e) => {
|
|
1554
1701
|
e.stopPropagation();
|
|
1555
1702
|
onArchive(node.id);
|
|
1556
1703
|
},
|
|
1557
|
-
children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.
|
|
1704
|
+
children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconArchiveOutlineRegular, { size: 16 })
|
|
1558
1705
|
})
|
|
1559
1706
|
}),
|
|
1560
1707
|
(0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.Tooltip, {
|
|
@@ -1629,14 +1776,14 @@ window.__ModuleLoader__.load({
|
|
|
1629
1776
|
const addEntries = flowAvailable ? [{
|
|
1630
1777
|
id: ADD_WORKSPACE,
|
|
1631
1778
|
label: t("menu.addWorkspace"),
|
|
1632
|
-
icon: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.
|
|
1779
|
+
icon: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconPlusOutlineRegular, { size: 16 }),
|
|
1633
1780
|
disabled: flowBusy
|
|
1634
1781
|
}] : [];
|
|
1635
1782
|
const pinAdd = !addOnly && workspaces.length > 0;
|
|
1636
1783
|
const items = pinAdd ? workspaces.map((workspace) => ({
|
|
1637
1784
|
id: workspace.workspaceId,
|
|
1638
1785
|
label: workspace.title,
|
|
1639
|
-
icon: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.
|
|
1786
|
+
icon: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconFolderCloseRegular, { size: 16 }),
|
|
1640
1787
|
disabled: flowBusy
|
|
1641
1788
|
})) : addEntries;
|
|
1642
1789
|
const menuIsEmpty = items.length === 0;
|
|
@@ -1761,7 +1908,7 @@ window.__ModuleLoader__.load({
|
|
|
1761
1908
|
}
|
|
1762
1909
|
//#endregion
|
|
1763
1910
|
//#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-workspace/src/client/rows/WorkspaceBrowser.module.css.mjs
|
|
1764
|
-
const css = ".CO5s3G_root{--qilin-session-list-edge-inset:var(--qilin-sidebar-inline-padding);--qilin-session-list-scrollbar-width:8px;--qilin-session-list-scrollbar-offset:2px;box-sizing:border-box;min-height:0;padding-right:var(--qilin-session-list-edge-inset);flex-direction:column;flex:1;display:flex}.CO5s3G_root.CO5s3G_rail{padding-right:0}.CO5s3G_iconButton{corner-shape:round;cursor:pointer;width:28px;height:28px;color:var(--qilin-alias-label-secondary);background:0 0;border:none;border-radius:50%;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.CO5s3G_iconButton:focus-visible,.CO5s3G_searchButton:focus-visible,.CO5s3G_clearButton:focus-visible{outline:var(--qilin-focus-ring-width) solid var(--qilin-focus-ring-color,var(--qilin-alias-state-business-primary));outline-offset:-2px}.CO5s3G_iconButton:hover{background:var(--qilin-alias-interactive-bg-hover)}.CO5s3G_sectionHeader{box-sizing:border-box;
|
|
1911
|
+
const css = ".CO5s3G_root{--qilin-session-list-edge-inset:var(--qilin-sidebar-inline-padding);--qilin-session-list-scrollbar-width:8px;--qilin-session-list-scrollbar-offset:2px;box-sizing:border-box;min-height:0;padding-right:var(--qilin-session-list-edge-inset);flex-direction:column;flex:1;display:flex}.CO5s3G_root.CO5s3G_rail{padding-right:0}.CO5s3G_iconButton{corner-shape:round;cursor:pointer;width:28px;height:28px;color:var(--qilin-alias-label-secondary);background:0 0;border:none;border-radius:50%;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.CO5s3G_iconButton:focus-visible,.CO5s3G_searchButton:focus-visible,.CO5s3G_clearButton:focus-visible{outline:var(--qilin-focus-ring-width) solid var(--qilin-focus-ring-color,var(--qilin-alias-state-business-primary));outline-offset:-2px}.CO5s3G_iconButton:hover{background:var(--qilin-alias-interactive-bg-hover)}.CO5s3G_sectionHeader{height:36px;padding-left:var(--qilin-sidebar-row-padding);box-sizing:border-box;color:var(--qilin-alias-label-tertiary);border-radius:12px;flex:none;justify-content:flex-end;align-items:center;gap:4px;margin-bottom:4px;display:flex;overflow:hidden}.CO5s3G_root:not(.CO5s3G_rail) .CO5s3G_sectionHeader{transition:margin-right .18s var(--ds-ease-in-out), padding-inline .18s var(--ds-ease-in-out), gap .18s var(--ds-ease-in-out);margin-top:2px;margin-right:-4px}.CO5s3G_root:not(.CO5s3G_rail) .CO5s3G_sectionHeader:has(.CO5s3G_searchExpanded){padding-inline:calc(var(--qilin-sidebar-paint-inset) + 1px);gap:0;margin-right:0}.CO5s3G_sectionHeader:has(.CO5s3G_searchExpanded) .CO5s3G_sectionLabelHidden{margin-right:0}.CO5s3G_sectionLabel{white-space:nowrap;opacity:1;visibility:visible;min-width:0;max-width:45%;transition:max-width .18s var(--ds-ease-in-out), margin-right .18s var(--ds-ease-in-out), opacity .12s var(--ds-ease-in-out), transform .18s var(--ds-ease-in-out), visibility 0s linear;flex:none;line-height:20px;position:relative;left:-1px;overflow:hidden}.CO5s3G_sectionLabelHidden{opacity:0;visibility:hidden;max-width:0;margin-right:-4px;transition-delay:0s,0s,0s,0s,.18s;transform:translate(-4px)}.CO5s3G_searchSlot{box-sizing:border-box;min-width:0;max-width:28px;transition:max-width .18s var(--ds-ease-in-out), padding-left .18s var(--ds-ease-in-out);flex:1;align-items:center;margin-left:auto;padding-left:0;display:flex}.CO5s3G_searchSlotExpanded{max-width:100%;padding-left:0}.CO5s3G_headerActions{opacity:1;visibility:visible;max-width:60px;transition:max-width .18s var(--ds-ease-in-out), opacity .12s var(--ds-ease-in-out), transform .18s var(--ds-ease-in-out), visibility 0s linear;flex:none;align-items:center;gap:4px;display:flex;overflow:hidden}.CO5s3G_headerActionsHidden{opacity:0;visibility:hidden;pointer-events:none;max-width:0;transition-delay:0s,0s,0s,.18s;transform:translate(4px)}.CO5s3G_search{box-sizing:border-box;corner-shape:round;cursor:text;width:100%;height:28px;color:var(--qilin-alias-label-secondary);transition:width .18s var(--ds-ease-in-out), padding .18s var(--ds-ease-in-out), border-color .18s var(--ds-ease-in-out), background-color .18s var(--ds-ease-in-out);background:0 0;border:none;border-radius:50%;flex:none;align-items:center;gap:0;margin:0;padding:0;display:flex;overflow:hidden}.CO5s3G_searchExpanded{border:1px solid var(--qilin-alias-border-l4);width:100%;height:32px;color:var(--qilin-alias-label-caption);background:0 0;border-radius:10px;margin-inline:0;padding:0 4px 0 0}.CO5s3G_searchButton{corner-shape:round;cursor:pointer;width:28px;height:28px;color:inherit;background:0 0;border:none;border-radius:50%;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.CO5s3G_searchExpanded .CO5s3G_searchButton{width:28px;height:32px}.CO5s3G_searchButton:hover{background:var(--qilin-alias-interactive-bg-hover)}.CO5s3G_searchExpanded .CO5s3G_searchButton:hover{background:0 0}.CO5s3G_searchInput{opacity:0;pointer-events:none;width:0;min-width:0;color:var(--qilin-alias-label-primary);transition:opacity .12s var(--ds-ease-in-out);background:0 0;border:none;outline:none;flex:1;font-size:13px;line-height:18px}.CO5s3G_searchExpanded .CO5s3G_searchInput{opacity:1;pointer-events:auto;margin-left:-2px}.CO5s3G_searchInput::placeholder{color:var(--qilin-alias-label-tertiary)}.CO5s3G_clearButton{corner-shape:round;cursor:pointer;width:24px;height:24px;color:var(--qilin-alias-label-secondary);background:0 0;border:none;border-radius:50%;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.CO5s3G_clearButton:hover{background:var(--qilin-alias-interactive-bg-hover)}.CO5s3G_rail .CO5s3G_sectionHeader{justify-content:flex-start;gap:0;margin-bottom:12px;padding-left:0}.CO5s3G_listArea{min-height:0;margin-left:-4px;margin-right:calc(-1 * var(--qilin-session-list-edge-inset));flex-direction:column;flex:1;padding-left:4px;display:flex;overflow:visible}.CO5s3G_rail .CO5s3G_listArea{margin-left:0;margin-right:0;padding-left:0}.CO5s3G_treeBody{flex-direction:column;flex:1;min-height:0;display:flex;position:relative}.CO5s3G_fade{left:0;right:var(--qilin-session-list-edge-inset);background:linear-gradient(to bottom, transparent, var(--qilin-specific-sidebar-fill));pointer-events:none;height:24px;position:absolute;bottom:0}[data-platform=darwin] .CO5s3G_fade{display:none}.CO5s3G_wide{animation:CO5s3G_wide-in .2s var(--ds-ease-in-out)}@keyframes CO5s3G_wide-in{0%{opacity:0}}.CO5s3G_list{min-height:0;margin-left:-4px;margin-right:var(--qilin-session-list-scrollbar-offset);padding-left:4px;padding-right:calc(var(--qilin-session-list-edge-inset) - var(--qilin-session-list-scrollbar-width) - var(--qilin-session-list-scrollbar-offset));scrollbar-gutter:stable;flex:1;padding-bottom:16px;overflow-y:auto}.CO5s3G_flatList>*+*,.CO5s3G_searchTree>[role=treeitem]+[role=treeitem],.CO5s3G_groupSection>*+*{margin-top:2px}.CO5s3G_searchStatus,.CO5s3G_searchWarning{color:var(--qilin-alias-label-tertiary);padding:10px 12px;font-size:12px;line-height:18px}.CO5s3G_searchWarning{color:var(--qilin-alias-label-secondary)}.CO5s3G_groupSection{position:relative}.CO5s3G_groupSection+.CO5s3G_groupSection{margin-top:4px}.CO5s3G_listTopDropIndicator,.CO5s3G_workspaceDropBefore:before,.CO5s3G_workspaceDropAfter:after{content:\"\";z-index:1;background:linear-gradient(55deg, transparent calc(50% - 1px), var(--qilin-alias-state-business-primary) calc(50% - 1px) calc(50% + 1px), transparent calc(50% + 1px)) 0 0 / 5px 7px no-repeat, linear-gradient(125deg, transparent calc(50% - 1px), var(--qilin-alias-state-business-primary) calc(50% - 1px) calc(50% + 1px), transparent calc(50% + 1px)) 0 5px / 5px 7px no-repeat, linear-gradient(var(--qilin-alias-state-business-primary) 0 0) 4px 5px / calc(100% - 4px) 2px no-repeat;pointer-events:none;height:12px;position:absolute;left:0;right:0}.CO5s3G_listTopDropIndicator{top:-8px;left:0;right:var(--qilin-session-list-edge-inset)}.CO5s3G_listTopDropActive>.CO5s3G_workspaceDropBefore:first-child:before{display:none}.CO5s3G_workspaceDropBefore:before{top:-8px}.CO5s3G_workspaceDropAfter:after{bottom:-8px}.CO5s3G_sessionOverflowButton{width:100%;height:28px;padding:0 var(--qilin-sidebar-row-padding) 0 calc(var(--qilin-sidebar-row-padding) + 16px + var(--qilin-sidebar-label-gap) + var(--dsh-workspace-indent,0px));cursor:pointer;text-align:left;color:var(--qilin-alias-label-tertiary);background:0 0;border:none;border-radius:8px;font-size:12px}.CO5s3G_groupSection>.CO5s3G_sessionOverflowButton{margin-top:0}.CO5s3G_sessionOverflowButton:hover{color:var(--qilin-alias-label-secondary);background:0 0}.CO5s3G_empty{color:var(--qilin-alias-label-tertiary);padding:16px 12px;font-size:13px}.CO5s3G_renameInput{box-sizing:border-box;border:1px solid var(--qilin-alias-border-l4);width:100%;height:44px;color:var(--qilin-alias-label-primary);background:0 0;border-radius:22px;outline:none;padding:7px 14px;font-size:14px;font-weight:400;line-height:22px}.CO5s3G_renameInput:disabled{color:var(--qilin-alias-label-dimmed)}.CO5s3G_renameError{color:var(--qilin-alias-state-error-primary);margin-top:8px;font-size:12px;line-height:18px}.CO5s3G_deleteAction:not(:disabled){color:var(--qilin-alias-state-error-primary)}.CO5s3G_deleteStatus{color:var(--qilin-alias-label-secondary);font-size:12px;line-height:18px}@media (prefers-reduced-motion:reduce){.CO5s3G_wide{animation:none}.CO5s3G_root:not(.CO5s3G_rail) .CO5s3G_sectionHeader,.CO5s3G_search,.CO5s3G_sectionLabel,.CO5s3G_searchSlot,.CO5s3G_searchInput,.CO5s3G_headerActions{transition:none}}";
|
|
1765
1912
|
const tagId = "@qilin-agent/client-ui-workspace/WorkspaceBrowser.module.css";
|
|
1766
1913
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
1767
1914
|
const tag = document.createElement("style");
|
|
@@ -1969,7 +2116,7 @@ window.__ModuleLoader__.load({
|
|
|
1969
2116
|
onClick: () => {
|
|
1970
2117
|
setOpen((v) => !v);
|
|
1971
2118
|
},
|
|
1972
|
-
children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.
|
|
2119
|
+
children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconPersonalizationOutlineRegular, {})
|
|
1973
2120
|
})
|
|
1974
2121
|
})
|
|
1975
2122
|
});
|
|
@@ -1980,17 +2127,19 @@ window.__ModuleLoader__.load({
|
|
|
1980
2127
|
return e.clientY < rect.top + rect.height / 2 ? "before" : "after";
|
|
1981
2128
|
}
|
|
1982
2129
|
/** The scrolling session tree; unmounting drops the sessions subscription and expand-all state. */
|
|
1983
|
-
function SessionTree({ list, useSessionStatus, startSession, open, forkSession, copySessionId, workspaces, ungroupedSessionIds, archivedSessionIds, pinnedSessionIds, onSessionPin, onSessionUnpin, workspaceReady, usePanelInfo, onRenameRequest, onDeleteRequest, onSessionRename, onSessionArchive, insertWorkspaceBefore, nestWorkspaces, groupExpansion, setGroupExpanded, setSessionOrder, home, t, renderSlot, revealSessionId, onSessionRevealed }) {
|
|
2130
|
+
function SessionTree({ list, useSessionStatus, startSession, open, forkSession, copySessionId, workspaces, ungroupedSessionIds, archivedSessionIds, pinnedSessionIds, onSessionPin, onSessionUnpin, workspaceReady, usePanelInfo, onRenameRequest, onDeleteRequest, onSessionRename, onSessionArchive, insertWorkspaceBefore, nestWorkspaces, groupExpansion, setGroupExpanded, setSessionOrder, home, t, renderSlot, menu, revealSessionId, onSessionRevealed, animationResetKey }) {
|
|
1984
2131
|
const panelActive = usePanelInfo((info) => info.activePanelId !== null);
|
|
1985
2132
|
const statuses = useSessionStatus((s) => s);
|
|
1986
2133
|
const current = panelActive ? void 0 : Object.values(list.byId).find((session) => (session.retainedBy.mainView ?? 0) > 0)?.id;
|
|
1987
2134
|
const revealGroup = revealSessionId === void 0 || !workspaceReady ? void 0 : owningGroupKey(workspaces, revealSessionId);
|
|
1988
2135
|
const [storedWatermarks, setStoredWatermarks] = (0, react.useState)({});
|
|
2136
|
+
const [watermarkMotionKey, setWatermarkMotionKey] = (0, react.useState)(0);
|
|
1989
2137
|
const [drag, setDrag] = (0, react.useState)(null);
|
|
1990
2138
|
const sessionDropCommitted = (0, react.useRef)(false);
|
|
1991
2139
|
const [workspaceDrag, setWorkspaceDrag] = (0, react.useState)(null);
|
|
1992
2140
|
const workspaceDropCommitted = (0, react.useRef)(false);
|
|
1993
|
-
|
|
2141
|
+
const nativeDragActive = drag !== null || workspaceDrag !== null;
|
|
2142
|
+
useNativeDragAcceptance(nativeDragActive);
|
|
1994
2143
|
const currentGroup = current === void 0 || !workspaceReady ? void 0 : owningGroupKey(workspaces, current);
|
|
1995
2144
|
(0, react.useEffect)(() => {
|
|
1996
2145
|
if (current === void 0 || currentGroup === void 0 || Object.hasOwn(groupExpansion, currentGroup)) return;
|
|
@@ -2138,6 +2287,7 @@ window.__ModuleLoader__.load({
|
|
|
2138
2287
|
}, [groups, parents]);
|
|
2139
2288
|
const rootGroups = childrenByParent.get(void 0) ?? [];
|
|
2140
2289
|
const workspaceDropAtListStart = rootGroups[0]?.workspaceId !== void 0 && workspaceDrag?.over?.id === rootGroups[0].workspaceId && workspaceDrag.over.half === "before";
|
|
2290
|
+
const rowKeys = groups.length === 0 ? ["empty"] : [];
|
|
2141
2291
|
const renderGroup = (group, depth) => {
|
|
2142
2292
|
const workspaceId = group.workspaceId;
|
|
2143
2293
|
const children = childrenByParent.get(group.key) ?? [];
|
|
@@ -2146,6 +2296,10 @@ window.__ModuleLoader__.load({
|
|
|
2146
2296
|
const collapsed = watermarkRows(group.sessions, baselines.get(group.key) ?? SESSION_WATERMARK_BASE);
|
|
2147
2297
|
const visible = watermarkRows(group.sessions, watermark);
|
|
2148
2298
|
const sessionsExpanded = visible.hiddenCount === 0;
|
|
2299
|
+
rowKeys.push(`workspace:${group.key}`);
|
|
2300
|
+
const childRows = group.expanded ? children.map((child) => renderGroup(child, depth + 1)) : [];
|
|
2301
|
+
for (const node of visible.rows) rowKeys.push(`session:${node.id}`);
|
|
2302
|
+
if (collapsed.hiddenCount > 0) rowKeys.push(`overflow:${group.key}`);
|
|
2149
2303
|
const workspaceMarker = workspaceId !== void 0 && workspaceDrag?.over?.id === workspaceId ? workspaceDrag.over.half : null;
|
|
2150
2304
|
const workspaceDragProps = workspaceId === void 0 ? void 0 : {
|
|
2151
2305
|
start: () => {
|
|
@@ -2220,6 +2374,7 @@ window.__ModuleLoader__.load({
|
|
|
2220
2374
|
}
|
|
2221
2375
|
},
|
|
2222
2376
|
drag: workspaceDragProps,
|
|
2377
|
+
menu: menu.workspace,
|
|
2223
2378
|
actions: group.workspaceId === void 0 ? void 0 : {
|
|
2224
2379
|
rename: () => {
|
|
2225
2380
|
/* v8 ignore next -- narrowing guard: the actions object exists only for real-workspace groups. */
|
|
@@ -2233,7 +2388,7 @@ window.__ModuleLoader__.load({
|
|
|
2233
2388
|
}),
|
|
2234
2389
|
group.expanded && children.length > 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
2235
2390
|
role: "group",
|
|
2236
|
-
children:
|
|
2391
|
+
children: childRows
|
|
2237
2392
|
}),
|
|
2238
2393
|
visible.rows.map((node) => {
|
|
2239
2394
|
const sameGroupDrag = drag !== null && drag.accountKey === group.key;
|
|
@@ -2291,12 +2446,14 @@ window.__ModuleLoader__.load({
|
|
|
2291
2446
|
} : void 0,
|
|
2292
2447
|
drag: dragProps,
|
|
2293
2448
|
renderSlot,
|
|
2449
|
+
menu: menu.session,
|
|
2294
2450
|
t
|
|
2295
2451
|
}, node.id);
|
|
2296
2452
|
}),
|
|
2297
2453
|
collapsed.hiddenCount > 0 && (0, react_jsx_runtime.jsx)("button", {
|
|
2298
2454
|
type: "button",
|
|
2299
2455
|
className: WorkspaceBrowser_module_css_default.sessionOverflowButton,
|
|
2456
|
+
"data-row-key": `overflow:${group.key}`,
|
|
2300
2457
|
"aria-expanded": sessionsExpanded,
|
|
2301
2458
|
onClick: () => {
|
|
2302
2459
|
if (sessionsExpanded) {
|
|
@@ -2307,12 +2464,14 @@ window.__ModuleLoader__.load({
|
|
|
2307
2464
|
...marks,
|
|
2308
2465
|
[group.key]: visible.hiddenCount <= SESSION_WATERMARK_BASE ? Infinity : watermark + SESSION_WATERMARK_BASE
|
|
2309
2466
|
}));
|
|
2467
|
+
setWatermarkMotionKey((key) => key + 1);
|
|
2310
2468
|
},
|
|
2311
2469
|
children: sessionsExpanded ? t("sessions.collapse") : t("sessions.expand", { n: visible.hiddenCount })
|
|
2312
2470
|
})
|
|
2313
2471
|
]
|
|
2314
2472
|
}, group.key);
|
|
2315
2473
|
};
|
|
2474
|
+
const groupRows = rootGroups.map((group) => renderGroup(group, 0));
|
|
2316
2475
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
2317
2476
|
className: clsx(WorkspaceBrowser_module_css_default.treeBody, WorkspaceBrowser_module_css_default.wide),
|
|
2318
2477
|
children: [
|
|
@@ -2320,21 +2479,25 @@ window.__ModuleLoader__.load({
|
|
|
2320
2479
|
className: WorkspaceBrowser_module_css_default.listTopDropIndicator,
|
|
2321
2480
|
"aria-hidden": "true"
|
|
2322
2481
|
}),
|
|
2323
|
-
(0, react_jsx_runtime.jsxs)(
|
|
2482
|
+
(0, react_jsx_runtime.jsxs)(_qilin_agent_client_ui_primitives.AnimatedRows, {
|
|
2324
2483
|
className: clsx(WorkspaceBrowser_module_css_default.list, workspaceDropAtListStart && WorkspaceBrowser_module_css_default.listTopDropActive),
|
|
2325
2484
|
role: "tree",
|
|
2326
|
-
|
|
2485
|
+
label: t("section.sessions"),
|
|
2486
|
+
rowKeys,
|
|
2487
|
+
ready: list.phase === "ready" && workspaceReady && !nativeDragActive,
|
|
2488
|
+
resetKey: JSON.stringify([animationResetKey, watermarkMotionKey]),
|
|
2327
2489
|
children: [groups.length === 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
2328
2490
|
className: WorkspaceBrowser_module_css_default.empty,
|
|
2491
|
+
"data-row-key": "empty",
|
|
2329
2492
|
children: t("empty.none")
|
|
2330
|
-
}),
|
|
2493
|
+
}), groupRows]
|
|
2331
2494
|
}),
|
|
2332
2495
|
(0, react_jsx_runtime.jsx)("span", { className: WorkspaceBrowser_module_css_default.fade })
|
|
2333
2496
|
]
|
|
2334
2497
|
});
|
|
2335
2498
|
}
|
|
2336
2499
|
/** The flat "In one list" body: every session is one draggable top-level row. */
|
|
2337
|
-
function FlatList({ list, sessionIds, pinnedSessionIds, useSessionStatus, open, forkSession, copySessionId, onSessionRename, onSessionArchive, onSessionPin, onSessionUnpin, usePanelInfo, setSessionOrder, revealSessionId, onSessionRevealed, t, renderSlot }) {
|
|
2500
|
+
function FlatList({ list, sessionIds, pinnedSessionIds, useSessionStatus, open, forkSession, copySessionId, onSessionRename, onSessionArchive, onSessionPin, onSessionUnpin, usePanelInfo, setSessionOrder, workspaceReady, animationResetKey, revealSessionId, onSessionRevealed, t, renderSlot, menu }) {
|
|
2338
2501
|
const panelActive = usePanelInfo((info) => info.activePanelId !== null);
|
|
2339
2502
|
const statuses = useSessionStatus((s) => s);
|
|
2340
2503
|
const rows = (0, react.useMemo)(() => deriveFlat(list, sessionIds, pinnedSessionIds, statuses), [
|
|
@@ -2367,12 +2530,16 @@ window.__ModuleLoader__.load({
|
|
|
2367
2530
|
const now = Date.now();
|
|
2368
2531
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
2369
2532
|
className: clsx(WorkspaceBrowser_module_css_default.treeBody, WorkspaceBrowser_module_css_default.wide),
|
|
2370
|
-
children: [(0, react_jsx_runtime.jsxs)(
|
|
2533
|
+
children: [(0, react_jsx_runtime.jsxs)(_qilin_agent_client_ui_primitives.AnimatedRows, {
|
|
2371
2534
|
className: clsx(WorkspaceBrowser_module_css_default.list, WorkspaceBrowser_module_css_default.flatList),
|
|
2372
2535
|
role: "tree",
|
|
2373
|
-
|
|
2536
|
+
label: t("section.sessions"),
|
|
2537
|
+
rowKeys: rows.length === 0 ? ["empty"] : rows.map((row) => `session:${row.id}`),
|
|
2538
|
+
ready: list.phase === "ready" && workspaceReady && drag === null,
|
|
2539
|
+
resetKey: animationResetKey,
|
|
2374
2540
|
children: [rows.length === 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
2375
2541
|
className: WorkspaceBrowser_module_css_default.empty,
|
|
2542
|
+
"data-row-key": "empty",
|
|
2376
2543
|
children: t("empty.none")
|
|
2377
2544
|
}), rows.map((node) => {
|
|
2378
2545
|
const active = drag !== null;
|
|
@@ -2426,6 +2593,7 @@ window.__ModuleLoader__.load({
|
|
|
2426
2593
|
dropCommitted.current = false;
|
|
2427
2594
|
}
|
|
2428
2595
|
},
|
|
2596
|
+
menu: menu.session,
|
|
2429
2597
|
t
|
|
2430
2598
|
}, node.id);
|
|
2431
2599
|
})]
|
|
@@ -2498,7 +2666,7 @@ window.__ModuleLoader__.load({
|
|
|
2498
2666
|
* @param props - composed slot props (shell owner share + store + injected actions).
|
|
2499
2667
|
* @returns the region element tree.
|
|
2500
2668
|
*/
|
|
2501
|
-
function WorkspaceBrowser({ wide, usePanelInfo, expandSidebar, useSessions, useSessionStatus, useWorkspaces, useStore, actions, startSession, open, renameSession, forkSession, renameWorkspace, deleteWorkspace, insertWorkspaceBefore, archiveSession, copySessionId, pinSession, unpinSession, createWorkspace, searchSessions, searchResultLimit, requestSearch, requestAddWorkspace, closeAddWorkspace, closeRenameRequest, setDirectoryBusy, useDirectoryFlow, useHostInfo, useWorkspaceShortcuts, useShortcuts, renderSlot, t }) {
|
|
2669
|
+
function WorkspaceBrowser({ wide, usePanelInfo, expandSidebar, useSessions, useSessionStatus, useWorkspaces, useStore, actions, startSession, open, renameSession, forkSession, renameWorkspace, deleteWorkspace, insertWorkspaceBefore, archiveSession, copySessionId, pinSession, unpinSession, createWorkspace, searchSessions, searchResultLimit, requestSearch, requestAddWorkspace, closeAddWorkspace, closeRenameRequest, setDirectoryBusy, useDirectoryFlow, useHostInfo, useWorkspaceShortcuts, useShortcuts, useContextMenu, useSessionRenameRequest, useWorkspaceActionRequest, settleSessionRename, settleWorkspaceAction, renderSlot, t }) {
|
|
2502
2670
|
const home = useHostInfo((info) => info.home);
|
|
2503
2671
|
const list = useSessions((state) => state);
|
|
2504
2672
|
const workspaces = useWorkspaces((state) => state.items);
|
|
@@ -2861,6 +3029,54 @@ window.__ModuleLoader__.load({
|
|
|
2861
3029
|
setDeleteError(reason instanceof Error ? reason.message : String(reason));
|
|
2862
3030
|
});
|
|
2863
3031
|
};
|
|
3032
|
+
const { getTriggerProps } = useContextMenu();
|
|
3033
|
+
const menus = {
|
|
3034
|
+
session: (sessionId, displayTitle) => getTriggerProps({
|
|
3035
|
+
kind: "session",
|
|
3036
|
+
value: {
|
|
3037
|
+
sessionId,
|
|
3038
|
+
displayTitle
|
|
3039
|
+
}
|
|
3040
|
+
}),
|
|
3041
|
+
workspace: (workspaceId, path, displayTitle) => getTriggerProps({
|
|
3042
|
+
kind: "workspace",
|
|
3043
|
+
value: {
|
|
3044
|
+
workspaceId,
|
|
3045
|
+
path: path ?? "",
|
|
3046
|
+
displayTitle
|
|
3047
|
+
}
|
|
3048
|
+
})
|
|
3049
|
+
};
|
|
3050
|
+
const pendingSessionRename = useSessionRenameRequest((request) => request);
|
|
3051
|
+
(0, react.useEffect)(() => {
|
|
3052
|
+
if (pendingSessionRename === null) return;
|
|
3053
|
+
setSessionRenameTarget({
|
|
3054
|
+
sessionId: pendingSessionRename.sessionId,
|
|
3055
|
+
currentTitle: pendingSessionRename.currentTitle
|
|
3056
|
+
});
|
|
3057
|
+
setSessionRenameDraft(pendingSessionRename.currentTitle);
|
|
3058
|
+
setSessionRenameError(null);
|
|
3059
|
+
settleSessionRename();
|
|
3060
|
+
}, [pendingSessionRename, settleSessionRename]);
|
|
3061
|
+
const pendingWorkspaceAction = useWorkspaceActionRequest((request) => request);
|
|
3062
|
+
(0, react.useEffect)(() => {
|
|
3063
|
+
if (pendingWorkspaceAction === null) return;
|
|
3064
|
+
if (pendingWorkspaceAction.action === "rename") {
|
|
3065
|
+
setRenameTarget({
|
|
3066
|
+
workspaceId: pendingWorkspaceAction.workspaceId,
|
|
3067
|
+
currentTitle: pendingWorkspaceAction.currentTitle
|
|
3068
|
+
});
|
|
3069
|
+
setRenameDraft(pendingWorkspaceAction.currentTitle);
|
|
3070
|
+
setRenameError(null);
|
|
3071
|
+
} else {
|
|
3072
|
+
setDeleteTarget({
|
|
3073
|
+
workspaceId: pendingWorkspaceAction.workspaceId,
|
|
3074
|
+
title: pendingWorkspaceAction.currentTitle
|
|
3075
|
+
});
|
|
3076
|
+
setDeleteError(null);
|
|
3077
|
+
}
|
|
3078
|
+
settleWorkspaceAction();
|
|
3079
|
+
}, [pendingWorkspaceAction, settleWorkspaceAction]);
|
|
2864
3080
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
2865
3081
|
className: clsx(WorkspaceBrowser_module_css_default.root, !wide && WorkspaceBrowser_module_css_default.rail),
|
|
2866
3082
|
children: [
|
|
@@ -2900,7 +3116,7 @@ window.__ModuleLoader__.load({
|
|
|
2900
3116
|
setSearchExpanded(true);
|
|
2901
3117
|
requestSearch();
|
|
2902
3118
|
},
|
|
2903
|
-
children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.
|
|
3119
|
+
children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconSearchOutlineRegular, { size: searchExpanded ? 11 : 14 })
|
|
2904
3120
|
})
|
|
2905
3121
|
}),
|
|
2906
3122
|
(0, react_jsx_runtime.jsx)("input", {
|
|
@@ -2929,7 +3145,7 @@ window.__ModuleLoader__.load({
|
|
|
2929
3145
|
setQuery("");
|
|
2930
3146
|
setSearchExpanded(false);
|
|
2931
3147
|
},
|
|
2932
|
-
children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.
|
|
3148
|
+
children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconCloseFillRegular, {})
|
|
2933
3149
|
})
|
|
2934
3150
|
]
|
|
2935
3151
|
})
|
|
@@ -2960,7 +3176,7 @@ window.__ModuleLoader__.load({
|
|
|
2960
3176
|
onClick: () => {
|
|
2961
3177
|
requestAddWorkspace();
|
|
2962
3178
|
},
|
|
2963
|
-
children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.
|
|
3179
|
+
children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconProjectAddOutlineRegular, { size: 16 })
|
|
2964
3180
|
})
|
|
2965
3181
|
})]
|
|
2966
3182
|
}),
|
|
@@ -3001,6 +3217,8 @@ window.__ModuleLoader__.load({
|
|
|
3001
3217
|
usePanelInfo,
|
|
3002
3218
|
list,
|
|
3003
3219
|
sessionIds: orderedFlatSessionIds,
|
|
3220
|
+
workspaceReady,
|
|
3221
|
+
animationResetKey: `${groupBy}/${orderBy}`,
|
|
3004
3222
|
useSessionStatus,
|
|
3005
3223
|
open,
|
|
3006
3224
|
forkSession,
|
|
@@ -3014,13 +3232,16 @@ window.__ModuleLoader__.load({
|
|
|
3014
3232
|
revealSessionId,
|
|
3015
3233
|
onSessionRevealed: acknowledgeSessionReveal,
|
|
3016
3234
|
renderSlot,
|
|
3235
|
+
menu: menus,
|
|
3017
3236
|
t
|
|
3018
3237
|
}) : (0, react_jsx_runtime.jsx)(SessionTree, {
|
|
3019
3238
|
usePanelInfo,
|
|
3020
3239
|
list,
|
|
3240
|
+
animationResetKey: `${groupBy}/${orderBy}`,
|
|
3021
3241
|
useSessionStatus,
|
|
3022
3242
|
copySessionId,
|
|
3023
3243
|
renderSlot,
|
|
3244
|
+
menu: menus,
|
|
3024
3245
|
onSessionRename,
|
|
3025
3246
|
onSessionArchive,
|
|
3026
3247
|
onSessionPin,
|
|
@@ -3461,6 +3682,7 @@ window.__ModuleLoader__.load({
|
|
|
3461
3682
|
* declaration through `slots.inject()` instead of assuming order.
|
|
3462
3683
|
*/
|
|
3463
3684
|
const inject = [
|
|
3685
|
+
"contextMenus",
|
|
3464
3686
|
"slots",
|
|
3465
3687
|
"sessions",
|
|
3466
3688
|
"workspaces",
|
|
@@ -3486,6 +3708,8 @@ window.__ModuleLoader__.load({
|
|
|
3486
3708
|
create: () => viewInstance
|
|
3487
3709
|
};
|
|
3488
3710
|
const rowToast = (0, _qilin_agent_client_store.createSnapshotStore)(null);
|
|
3711
|
+
const sessionRenameRequest = (0, _qilin_agent_client_store.createSnapshotStore)(null);
|
|
3712
|
+
const workspaceActionRequest = (0, _qilin_agent_client_store.createSnapshotStore)(null);
|
|
3489
3713
|
let toastSeq = 0;
|
|
3490
3714
|
const notify = (toast) => {
|
|
3491
3715
|
rowToast.set({
|
|
@@ -3555,16 +3779,69 @@ window.__ModuleLoader__.load({
|
|
|
3555
3779
|
copySessionId: async (sessionId) => {
|
|
3556
3780
|
notify({ kind: await (0, _qilin_agent_client_ui_primitives.writeClipboard)(sessionId) ? "sessionIdCopied" : "sessionIdCopyFailed" });
|
|
3557
3781
|
},
|
|
3782
|
+
settleSessionRename: () => {
|
|
3783
|
+
sessionRenameRequest.set(null);
|
|
3784
|
+
},
|
|
3785
|
+
settleWorkspaceAction: () => {
|
|
3786
|
+
workspaceActionRequest.set(null);
|
|
3787
|
+
},
|
|
3558
3788
|
hooks: {
|
|
3559
3789
|
directoryFlow: browserFlowSource,
|
|
3560
3790
|
hostInfo,
|
|
3561
3791
|
workspaceShortcuts: shortcutControls.state,
|
|
3562
|
-
shortcuts: ctx.shortcuts.catalog
|
|
3792
|
+
shortcuts: ctx.shortcuts.catalog,
|
|
3793
|
+
sessionRenameRequest,
|
|
3794
|
+
workspaceActionRequest
|
|
3563
3795
|
}
|
|
3564
3796
|
});
|
|
3565
3797
|
installWorkspaceShortcuts(ctx, uiWorkspace, shortcutControls, (sessionId) => {
|
|
3566
3798
|
uiWorkspace.archiveSession(sessionId);
|
|
3567
3799
|
});
|
|
3800
|
+
ctx.slots.inject("contextMenu.icon", function* () {
|
|
3801
|
+
for (const [key, Icon] of Object.entries({
|
|
3802
|
+
"workspace.rename": _qilin_agent_client_ui_primitives.IconEditOutlineRegular,
|
|
3803
|
+
"workspace.delete": _qilin_agent_client_ui_primitives.IconTrashOutlineRegular,
|
|
3804
|
+
"workspace.pin": _qilin_agent_client_ui_primitives.IconPinOutlineRegular,
|
|
3805
|
+
"workspace.unpin": _qilin_agent_client_ui_primitives.IconPinFillRegular,
|
|
3806
|
+
"workspace.archive": _qilin_agent_client_ui_primitives.IconArchiveOutlineRegular,
|
|
3807
|
+
"workspace.fork": _qilin_agent_client_ui_primitives.IconBranchOutlineRegular,
|
|
3808
|
+
"workspace.copy": _qilin_agent_client_ui_primitives.IconCopyOutlineRegular
|
|
3809
|
+
})) yield ctx.slots.register({
|
|
3810
|
+
name: "contextMenu.icon",
|
|
3811
|
+
key
|
|
3812
|
+
}, Icon);
|
|
3813
|
+
});
|
|
3814
|
+
registerWorkspaceMenus(ctx, {
|
|
3815
|
+
pin: (sessionId) => {
|
|
3816
|
+
uiWorkspace.pinSession(sessionId);
|
|
3817
|
+
},
|
|
3818
|
+
unpin: (sessionId) => {
|
|
3819
|
+
uiWorkspace.unpinSession(sessionId);
|
|
3820
|
+
},
|
|
3821
|
+
requestSessionRename: (sessionId, currentTitle) => {
|
|
3822
|
+
sessionRenameRequest.set({
|
|
3823
|
+
sessionId,
|
|
3824
|
+
currentTitle
|
|
3825
|
+
});
|
|
3826
|
+
},
|
|
3827
|
+
fork: (sessionId) => {
|
|
3828
|
+
browserInjected().forkSession(sessionId);
|
|
3829
|
+
},
|
|
3830
|
+
copySessionId: (sessionId) => {
|
|
3831
|
+
browserInjected().copySessionId(sessionId);
|
|
3832
|
+
},
|
|
3833
|
+
archive: (sessionId) => {
|
|
3834
|
+
browserInjected().archiveSession(sessionId);
|
|
3835
|
+
},
|
|
3836
|
+
requestWorkspaceAction: (workspaceId, displayTitle, action) => {
|
|
3837
|
+
if (workspaces.list.getSnapshot().items.find((row) => row.workspaceId === workspaceId) === void 0) return;
|
|
3838
|
+
workspaceActionRequest.set({
|
|
3839
|
+
action,
|
|
3840
|
+
workspaceId,
|
|
3841
|
+
currentTitle: displayTitle
|
|
3842
|
+
});
|
|
3843
|
+
}
|
|
3844
|
+
});
|
|
3568
3845
|
registerToasts(ctx);
|
|
3569
3846
|
const rowToastInjected = () => ({
|
|
3570
3847
|
hooks: { toast: rowToast },
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Structured Session and Workspace actions over the workspace owner's existing callbacks. */
|
|
2
|
+
import type { Context } from '@qilin-agent/kylin';
|
|
3
|
+
import type { WorkspaceId } from '@qilin-agent/api-workspace-controller/client';
|
|
4
|
+
import type { SessionId } from '@qilin-agent/session/types';
|
|
5
|
+
/** The callbacks the browser already runs for its own row menus. */
|
|
6
|
+
export interface WorkspaceMenuActions {
|
|
7
|
+
/** Pin a Session ahead of unpinned rows. */
|
|
8
|
+
pin: (sessionId: SessionId) => void;
|
|
9
|
+
/** Drop one Session's pin. */
|
|
10
|
+
unpin: (sessionId: SessionId) => void;
|
|
11
|
+
/** Open the browser-owned Session rename dialog. */
|
|
12
|
+
requestSessionRename: (sessionId: SessionId, currentTitle: string) => void;
|
|
13
|
+
/** Fork a Session at its last completed turn. */
|
|
14
|
+
fork: (sessionId: SessionId) => void;
|
|
15
|
+
/** Copy a Session's complete id and report the outcome. */
|
|
16
|
+
copySessionId: (sessionId: SessionId) => void;
|
|
17
|
+
/** Archive a Session into the registry-global set. */
|
|
18
|
+
archive: (sessionId: SessionId) => void;
|
|
19
|
+
/** Open the browser-owned Workspace rename or delete dialog. */
|
|
20
|
+
requestWorkspaceAction: (workspaceId: WorkspaceId, currentTitle: string, action: 'rename' | 'delete') => void;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Register the built-in Session and Workspace actions on the shared menu.
|
|
24
|
+
* @param ctx - workspace plugin context owning menus, membership, and locale.
|
|
25
|
+
* @param actions - shared row callbacks; execution always uses the captured object.
|
|
26
|
+
*/
|
|
27
|
+
export declare function registerWorkspaceMenus(ctx: Context, actions: WorkspaceMenuActions): void;
|
|
28
|
+
//# sourceMappingURL=context-menus.d.ts.map
|
|
@@ -30,6 +30,27 @@ import type { SessionId } from '@qilin-agent/session/types';
|
|
|
30
30
|
import type { createWorkspaceViewStore } from '../stores.ts';
|
|
31
31
|
import type { ShortcutCatalogEntry } from '@qilin-agent/client-shortcuts/client';
|
|
32
32
|
import type { WorkspaceShortcutState } from '../shortcuts.ts';
|
|
33
|
+
declare module '@qilin-agent/client-ui-context-menu/client' {
|
|
34
|
+
interface ContextMenuTargetMap {
|
|
35
|
+
/** Registered Workspace header; path and title belong to the clicked row. */
|
|
36
|
+
workspace: {
|
|
37
|
+
readonly workspaceId: WorkspaceId;
|
|
38
|
+
readonly path: string;
|
|
39
|
+
readonly displayTitle: string;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** One menu request for the browser-owned Session rename dialog. */
|
|
44
|
+
export type SessionRenameRequest = {
|
|
45
|
+
readonly sessionId: SessionId;
|
|
46
|
+
readonly currentTitle: string;
|
|
47
|
+
};
|
|
48
|
+
/** One menu request for the browser-owned Workspace rename or delete dialog. */
|
|
49
|
+
export type WorkspaceActionRequest = {
|
|
50
|
+
readonly action: 'rename' | 'delete';
|
|
51
|
+
readonly workspaceId: WorkspaceId;
|
|
52
|
+
readonly currentTitle: string;
|
|
53
|
+
};
|
|
33
54
|
/**
|
|
34
55
|
* Owner share of the directory-flow holes: the complete conversation between
|
|
35
56
|
* the trigger surface and the picking interaction. The occupant reads `open`
|
|
@@ -130,6 +151,10 @@ export type WorkspaceBrowserInjected = {
|
|
|
130
151
|
workspaceShortcuts: HostObservable<WorkspaceShortcutState>;
|
|
131
152
|
/** Effective command catalog for row shortcut hints. */
|
|
132
153
|
shortcuts: HostObservable<readonly ShortcutCatalogEntry[]>;
|
|
154
|
+
/** Session rename requested by the shared context menu. */
|
|
155
|
+
sessionRenameRequest: HostObservable<SessionRenameRequest | null>;
|
|
156
|
+
/** Workspace rename or delete requested by the shared context menu. */
|
|
157
|
+
workspaceActionRequest: HostObservable<WorkspaceActionRequest | null>;
|
|
133
158
|
};
|
|
134
159
|
/** Open the browser search and focus its input. */
|
|
135
160
|
requestSearch: () => void;
|
|
@@ -192,6 +217,10 @@ export type WorkspaceBrowserInjected = {
|
|
|
192
217
|
}) => Promise<WorkspaceView>;
|
|
193
218
|
/** Copy the complete Session id and report acceptance or failure through the keyed notice. */
|
|
194
219
|
copySessionId: (sessionId: SessionId) => Promise<void>;
|
|
220
|
+
/** Consume a menu-originated Session rename request once its dialog is open. */
|
|
221
|
+
settleSessionRename: () => void;
|
|
222
|
+
/** Consume a menu-originated Workspace action request once its dialog is open. */
|
|
223
|
+
settleWorkspaceAction: () => void;
|
|
195
224
|
};
|
|
196
225
|
/** One transient Workspace notice rendered by the overlay toast entry. */
|
|
197
226
|
export type RowToast = {
|
|
@@ -14,8 +14,11 @@ export interface MainSelection {
|
|
|
14
14
|
readonly sessionId?: SessionId;
|
|
15
15
|
readonly subagentAddress?: SubagentAddress;
|
|
16
16
|
}
|
|
17
|
-
/**
|
|
18
|
-
export
|
|
17
|
+
/** Content preparation and Agent preset for the Session a Workspace flow opens. */
|
|
18
|
+
export interface StartSessionOptions extends DraftInitializationOptions {
|
|
19
|
+
/** Agent preset the Session runs; the Host default when omitted. */
|
|
20
|
+
readonly agentPreset?: string;
|
|
21
|
+
}
|
|
19
22
|
/** Workspace archive and directory operations consumed by Client UI domains. */
|
|
20
23
|
export interface UiWorkspace {
|
|
21
24
|
/**
|
|
@@ -34,9 +37,10 @@ export interface UiWorkspace {
|
|
|
34
37
|
* @param workspaceId - target Workspace.
|
|
35
38
|
* @param beforeOpen - optional synchronous preparation for the selected Session,
|
|
36
39
|
* skipped after supersession; a throw aborts the open and releases the retained reference.
|
|
40
|
+
* @param options - choices for the Session the connection creates or reuses.
|
|
37
41
|
* @returns completion; a superseded request may create a Session but does not open it.
|
|
38
42
|
*/
|
|
39
|
-
openWorkspace(workspaceId: WorkspaceId, beforeOpen?: (sessionId: SessionId) => void): Promise<void>;
|
|
43
|
+
openWorkspace(workspaceId: WorkspaceId, beforeOpen?: (sessionId: SessionId) => void, options?: Pick<StartSessionOptions, 'agentPreset'>): Promise<void>;
|
|
40
44
|
/**
|
|
41
45
|
* Fork a Session and open the child unless a later navigation supersedes it.
|
|
42
46
|
* @param sessionId - source Session.
|
|
@@ -46,13 +50,15 @@ export interface UiWorkspace {
|
|
|
46
50
|
/**
|
|
47
51
|
* Resolve the reusable or newly created blank Session for a Workspace.
|
|
48
52
|
* @param workspaceId - target Workspace.
|
|
53
|
+
* @param options - choices for the created or reused Session, including the Agent preset.
|
|
49
54
|
* @returns a Session already addressable through the Session Controller.
|
|
50
55
|
*/
|
|
51
|
-
connectWorkspace(workspaceId: WorkspaceId): Promise<SessionId>;
|
|
56
|
+
connectWorkspace(workspaceId: WorkspaceId, options?: Pick<StartSessionOptions, 'agentPreset'>): Promise<SessionId>;
|
|
52
57
|
/**
|
|
53
58
|
* Start a New Session flow and navigate to its Session.
|
|
54
59
|
* @param workspaceId - explicit target; absent inherits the current or most recent Workspace.
|
|
55
|
-
* @param options - initial content
|
|
60
|
+
* @param options - initial content, the Agent preset, and `whenDraftExists`;
|
|
61
|
+
* existing text or attachments are preserved unless that handling replaces them.
|
|
56
62
|
*/
|
|
57
63
|
startSession(workspaceId?: WorkspaceId, options?: StartSessionOptions): void;
|
|
58
64
|
/**
|
|
@@ -133,9 +139,9 @@ declare class UiWorkspaceService extends Service implements UiWorkspace {
|
|
|
133
139
|
* @param notify - show one notice through the Workspace notice channel.
|
|
134
140
|
*/
|
|
135
141
|
constructor(ctx: Context, directoryPicker: ClientRemote['directoryPicker'], workspaces: IWorkspaces, sessions: ISessions, view: Pick<WorkspaceViewStoreActions, 'pinSessionOrder'>, notify: (toast: RowToast) => void);
|
|
136
|
-
connectWorkspace(workspaceId: WorkspaceId): Promise<SessionId>;
|
|
142
|
+
connectWorkspace(workspaceId: WorkspaceId, options?: Pick<StartSessionOptions, 'agentPreset'>): Promise<SessionId>;
|
|
137
143
|
openSession(target: SessionTarget): void;
|
|
138
|
-
openWorkspace(workspaceId: WorkspaceId, beforeOpen?: (sessionId: SessionId) => void): Promise<void>;
|
|
144
|
+
openWorkspace(workspaceId: WorkspaceId, beforeOpen?: (sessionId: SessionId) => void, options?: Pick<StartSessionOptions, 'agentPreset'>): Promise<void>;
|
|
139
145
|
forkSession(sessionId: SessionId): Promise<void>;
|
|
140
146
|
startSession(workspaceId?: WorkspaceId, options?: StartSessionOptions): void;
|
|
141
147
|
private prepareDraft;
|
|
@@ -1,8 +1,20 @@
|
|
|
1
|
+
import type { ContextMenuTriggerProps } from '@qilin-agent/client-ui-context-menu/client';
|
|
1
2
|
import type { PropsRenderSlots } from '@qilin-agent/client-ui-slots';
|
|
3
|
+
import type { WorkspaceId } from '@qilin-agent/api-workspace-controller/client';
|
|
2
4
|
import type { WorkspaceBrowserProps } from '../contract/slots.ts';
|
|
3
5
|
import type { GroupNode, SearchResultNode, SessionNode } from '../tree.ts';
|
|
4
6
|
/** The standard locale seat, prop-passed from the browser root. */
|
|
5
7
|
type RowTranslate = WorkspaceBrowserProps['t'];
|
|
8
|
+
/**
|
|
9
|
+
* Shared-menu gesture bindings the browser resolves for one row. The rows own
|
|
10
|
+
* no menu state: the menu plugin captures the target and renders the actions.
|
|
11
|
+
*/
|
|
12
|
+
export interface RowMenus {
|
|
13
|
+
/** Bind one Session row's captured identity. */
|
|
14
|
+
session: (sessionId: SessionNode['id'], displayTitle: string) => ContextMenuTriggerProps;
|
|
15
|
+
/** Bind one Workspace header's captured identity and directory. */
|
|
16
|
+
workspace: (workspaceId: WorkspaceId, path: string | undefined, displayTitle: string) => ContextMenuTriggerProps;
|
|
17
|
+
}
|
|
6
18
|
/**
|
|
7
19
|
* Row drag wiring supplied by the tree owner. `drop` reports the half of the
|
|
8
20
|
* row where the pointer released so the owner can resolve an insert anchor.
|
|
@@ -38,7 +50,7 @@ interface WorkspaceRowDragProps {
|
|
|
38
50
|
* @param props.t - the browser root's locale seat.
|
|
39
51
|
* @returns the row element.
|
|
40
52
|
*/
|
|
41
|
-
export declare function ProjectRowItem({ group, containsCurrentDescendant, onToggle, onCreate, actions, drag, home, t }: {
|
|
53
|
+
export declare function ProjectRowItem({ group, containsCurrentDescendant, onToggle, onCreate, actions, drag, home, menu, t }: {
|
|
42
54
|
group: GroupNode;
|
|
43
55
|
containsCurrentDescendant?: boolean;
|
|
44
56
|
onToggle: () => void;
|
|
@@ -48,6 +60,8 @@ export declare function ProjectRowItem({ group, containsCurrentDescendant, onTog
|
|
|
48
60
|
rename: () => void;
|
|
49
61
|
delete: () => void;
|
|
50
62
|
} | undefined;
|
|
63
|
+
/** Shared-menu gesture bindings for a real Workspace header. */
|
|
64
|
+
menu?: RowMenus['workspace'] | undefined;
|
|
51
65
|
/** Present only for real Workspace rows in the grouped view. */
|
|
52
66
|
drag?: WorkspaceRowDragProps | undefined;
|
|
53
67
|
/** Host account home; POSIX home-rooted hover paths display as `~`. */
|
|
@@ -91,7 +105,7 @@ export declare function SearchResultItem({ result, currentId, onOpen, t }: {
|
|
|
91
105
|
* @param props.t - the browser root's locale seat.
|
|
92
106
|
* @returns the session row.
|
|
93
107
|
*/
|
|
94
|
-
export declare function SessionNodeItem({ node, currentId, now, onOpen, onRename, onFork, onArchive, onCopyId, onPin, onUnpin, onReveal, drag, renderSlot, t, }: {
|
|
108
|
+
export declare function SessionNodeItem({ node, currentId, now, onOpen, onRename, onFork, onArchive, onCopyId, onPin, onUnpin, onReveal, drag, renderSlot, menu, t, }: {
|
|
95
109
|
node: SessionNode;
|
|
96
110
|
currentId: string | undefined;
|
|
97
111
|
now: number;
|
|
@@ -114,6 +128,8 @@ export declare function SessionNodeItem({ node, currentId, now, onOpen, onRename
|
|
|
114
128
|
drag?: RowDragProps | undefined;
|
|
115
129
|
/** Child-seat renderer for the row's leading decoration and hover-card section. */
|
|
116
130
|
renderSlot: SessionRowRenderSlots;
|
|
131
|
+
/** Shared-menu gesture bindings; blank rows capture nothing. */
|
|
132
|
+
menu?: RowMenus['session'] | undefined;
|
|
117
133
|
t: RowTranslate;
|
|
118
134
|
}): import("react").JSX.Element;
|
|
119
135
|
export {};
|
|
@@ -4,5 +4,5 @@ import type { WorkspaceBrowserProps } from '../contract/slots.ts';
|
|
|
4
4
|
* @param props - composed slot props (shell owner share + store + injected actions).
|
|
5
5
|
* @returns the region element tree.
|
|
6
6
|
*/
|
|
7
|
-
export declare function WorkspaceBrowser({ wide, usePanelInfo, expandSidebar, useSessions, useSessionStatus, useWorkspaces, useStore, actions, startSession, open, renameSession, forkSession, renameWorkspace, deleteWorkspace, insertWorkspaceBefore, archiveSession, copySessionId, pinSession, unpinSession, createWorkspace, searchSessions, searchResultLimit, requestSearch, requestAddWorkspace, closeAddWorkspace, closeRenameRequest, setDirectoryBusy, useDirectoryFlow, useHostInfo, useWorkspaceShortcuts, useShortcuts, renderSlot, t, }: WorkspaceBrowserProps): import("react").JSX.Element;
|
|
7
|
+
export declare function WorkspaceBrowser({ wide, usePanelInfo, expandSidebar, useSessions, useSessionStatus, useWorkspaces, useStore, actions, startSession, open, renameSession, forkSession, renameWorkspace, deleteWorkspace, insertWorkspaceBefore, archiveSession, copySessionId, pinSession, unpinSession, createWorkspace, searchSessions, searchResultLimit, requestSearch, requestAddWorkspace, closeAddWorkspace, closeRenameRequest, setDirectoryBusy, useDirectoryFlow, useHostInfo, useWorkspaceShortcuts, useShortcuts, useContextMenu, useSessionRenameRequest, useWorkspaceActionRequest, settleSessionRename, settleWorkspaceAction, renderSlot, t, }: WorkspaceBrowserProps): import("react").JSX.Element;
|
|
8
8
|
//# sourceMappingURL=WorkspaceBrowser.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qilin-agent/client-ui-workspace",
|
|
3
3
|
"description": "Workspace picker plugin: one WorkspacePicker registered into the sidebar and empty-state workspace slots",
|
|
4
|
-
"version": "3.1.
|
|
4
|
+
"version": "3.1.8",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"@qilin-agent/client-connection",
|
|
38
38
|
"@qilin-agent/client-locale",
|
|
39
39
|
"@qilin-agent/client-shortcuts",
|
|
40
|
+
"@qilin-agent/client-ui-context-menu",
|
|
40
41
|
"@qilin-agent/client-ui-conversation",
|
|
41
42
|
"@qilin-agent/client-ui-layout",
|
|
42
43
|
"@qilin-agent/client-ui-renderer",
|
|
@@ -48,33 +49,34 @@
|
|
|
48
49
|
},
|
|
49
50
|
"license": "MIT",
|
|
50
51
|
"peerDependencies": {
|
|
51
|
-
"@qilin-agent/kylin": "~4.0.
|
|
52
|
+
"@qilin-agent/kylin": "~4.0.6-alpha.2"
|
|
52
53
|
},
|
|
53
54
|
"devDependencies": {
|
|
55
|
+
"@qilin-agent/api-remotes": "3.1.8",
|
|
56
|
+
"@qilin-agent/api-session-controller": "3.1.8",
|
|
57
|
+
"@qilin-agent/api-workspace-controller": "3.1.8",
|
|
58
|
+
"@qilin-agent/client-connection": "3.1.8",
|
|
59
|
+
"@qilin-agent/client-locale": "3.1.8",
|
|
60
|
+
"@qilin-agent/client-shortcuts": "3.1.8",
|
|
61
|
+
"@qilin-agent/client-store": "3.1.8",
|
|
62
|
+
"@qilin-agent/client-test-runtime": "3.1.8",
|
|
63
|
+
"@qilin-agent/client-ui-context-menu": "3.1.8",
|
|
64
|
+
"@qilin-agent/client-ui-conversation": "3.1.8",
|
|
65
|
+
"@qilin-agent/client-ui-layout": "3.1.8",
|
|
66
|
+
"@qilin-agent/client-ui-primitives": "3.1.8",
|
|
67
|
+
"@qilin-agent/client-ui-renderer": "3.1.8",
|
|
68
|
+
"@qilin-agent/client-ui-session": "3.1.8",
|
|
69
|
+
"@qilin-agent/client-ui-sidebar": "3.1.8",
|
|
70
|
+
"@qilin-agent/client-ui-slots": "3.1.8",
|
|
71
|
+
"@qilin-agent/kylin": "~4.0.6-alpha.2",
|
|
72
|
+
"@qilin-agent/schedule": "3.1.8",
|
|
73
|
+
"@qilin-agent/session": "3.1.8",
|
|
74
|
+
"@qilin-agent/subagent": "3.1.8",
|
|
75
|
+
"@qilin-agent/typert-protocol": "3.1.8",
|
|
76
|
+
"@qilin-agent/util-workspace-path": "3.1.8",
|
|
54
77
|
"@types/react": "~18.3.1",
|
|
55
78
|
"clsx": "^2.0.0",
|
|
56
|
-
"react": "^18.2.0"
|
|
57
|
-
"@qilin-agent/api-remotes": "3.1.6",
|
|
58
|
-
"@qilin-agent/api-session-controller": "3.1.6",
|
|
59
|
-
"@qilin-agent/api-workspace-controller": "3.1.6",
|
|
60
|
-
"@qilin-agent/client-locale": "3.1.6",
|
|
61
|
-
"@qilin-agent/client-shortcuts": "3.1.6",
|
|
62
|
-
"@qilin-agent/client-connection": "3.1.6",
|
|
63
|
-
"@qilin-agent/client-test-runtime": "3.1.6",
|
|
64
|
-
"@qilin-agent/client-ui-conversation": "3.1.6",
|
|
65
|
-
"@qilin-agent/client-store": "3.1.6",
|
|
66
|
-
"@qilin-agent/client-ui-layout": "3.1.6",
|
|
67
|
-
"@qilin-agent/client-ui-primitives": "3.1.6",
|
|
68
|
-
"@qilin-agent/client-ui-renderer": "3.1.6",
|
|
69
|
-
"@qilin-agent/client-ui-session": "3.1.6",
|
|
70
|
-
"@qilin-agent/client-ui-sidebar": "3.1.6",
|
|
71
|
-
"@qilin-agent/client-ui-slots": "3.1.6",
|
|
72
|
-
"@qilin-agent/schedule": "3.1.6",
|
|
73
|
-
"@qilin-agent/session": "3.1.6",
|
|
74
|
-
"@qilin-agent/subagent": "3.1.6",
|
|
75
|
-
"@qilin-agent/typert-protocol": "3.1.6",
|
|
76
|
-
"@qilin-agent/util-workspace-path": "3.1.6",
|
|
77
|
-
"@qilin-agent/kylin": "~4.0.5"
|
|
79
|
+
"react": "^18.2.0"
|
|
78
80
|
},
|
|
79
81
|
"files": [
|
|
80
82
|
"lib/index.js",
|