@deepseek-ai/dsh-client-ui-workspace 0.1.2-rc.1 → 0.1.5-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +2 -2
- package/README.zh.md +2 -2
- package/lib/client.js +105 -46
- package/lib/types/client/rows/Rows.d.ts +4 -1
- package/lib/types/client/tree.d.ts +7 -0
- package/package.json +18 -18
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-workspace/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: a819b07fecb74faeb3bebb6665aaabfdc8ecfba6
|
|
6
|
+
README.zh.md: f9565b12bccd596fa61d1f1436f82b090139f506
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
|
|
|
9
9
|
|
|
10
10
|
## Summary
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
This package lets users browse grouped or flat Session lists, choose a Workspace for a new Session, and manage Workspaces and Sessions through add, rename, reorder, search, fork, archive, and Workspace deletion. Pending interactions appear as warning dots, active scheduled tasks as alarm markers, and subagent-origin Sessions remain hidden. Canonically distinct folder paths remain separate Workspaces. Adding a Workspace requires a composed directory picker; without one, the add action is unavailable.
|
|
13
13
|
|
|
14
14
|
## Table of Contents
|
|
15
15
|
|
|
@@ -33,7 +33,7 @@ View options combine grouping with one browser-persisted Session order per accou
|
|
|
33
33
|
|
|
34
34
|
### Search
|
|
35
35
|
|
|
36
|
-
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 and opens the
|
|
36
|
+
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.
|
|
37
37
|
|
|
38
38
|
### Managing sessions
|
|
39
39
|
|
package/README.zh.md
CHANGED
|
@@ -9,7 +9,7 @@ kind: "package-reference"
|
|
|
9
9
|
|
|
10
10
|
## 概述
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
本包让用户浏览分组或扁平的 Session 列表、为新 Session 选择 Workspace,并通过添加、重命名、重排序、搜索、fork、归档和删除 Workspace 来管理 Workspace 与 Session。待处理交互显示为警告点,活动定时任务显示为闹钟标识,subagent 来源的 Session 则保持隐藏。规范化后仍有差异的文件夹路径会保留为独立 Workspace。添加 Workspace 需要组合目录选择器;没有目录选择器时,添加操作不可用。
|
|
13
13
|
|
|
14
14
|
## 目录
|
|
15
15
|
|
|
@@ -33,7 +33,7 @@ kind: "package-reference"
|
|
|
33
33
|
|
|
34
34
|
### 搜索
|
|
35
35
|
|
|
36
|
-
折叠搜索是视图和添加操作旁的一枚区头按钮:激活后输入框会扩展并占据区头。非空白查询会以单一扁平结果列表替代任一浏览模式——不区分大小写的标题和 Workspace 子串匹配项会立即显示,经 250 ms 防抖的 Host 请求则会加入经过排序的当前对话内容匹配项及其摘要片段。每次新查询都会中止前一个请求;内容搜索失败时,元数据匹配项仍会显示,同时给出警告。列表最多显示 20
|
|
36
|
+
折叠搜索是视图和添加操作旁的一枚区头按钮:激活后输入框会扩展并占据区头。非空白查询会以单一扁平结果列表替代任一浏览模式——不区分大小写的标题和 Workspace 子串匹配项会立即显示,经 250 ms 防抖的 Host 请求则会加入经过排序的当前对话内容匹配项及其摘要片段。每次新查询都会中止前一个请求;内容搜索失败时,元数据匹配项仍会显示,同时给出警告。列表最多显示 20 条结果。选择结果会清空并收起搜索、打开 Session,并在当前浏览模式中将其行滚动到可见区域;分组浏览还会按需展开所属 Workspace 和完整 Session 列表。
|
|
37
37
|
|
|
38
38
|
### 管理会话
|
|
39
39
|
|
package/lib/client.js
CHANGED
|
@@ -225,10 +225,6 @@ window.__ModuleLoader__.load({
|
|
|
225
225
|
}
|
|
226
226
|
//#endregion
|
|
227
227
|
//#region ../../util/workspace-path/src/index.ts
|
|
228
|
-
/**
|
|
229
|
-
* Browser-safe Workspace path and display helpers.
|
|
230
|
-
* @module @deepseek-ai/dsh-util-workspace-path
|
|
231
|
-
*/
|
|
232
228
|
/** Whether a path uses a Windows drive or UNC prefix. */
|
|
233
229
|
function isWindowsStylePath(value) {
|
|
234
230
|
return /^[A-Za-z]:[/\\]/.test(value) || value.startsWith("\\\\");
|
|
@@ -290,6 +286,15 @@ window.__ModuleLoader__.load({
|
|
|
290
286
|
return indexed;
|
|
291
287
|
}
|
|
292
288
|
/**
|
|
289
|
+
* Resolve the Workspace browser group that owns one Session.
|
|
290
|
+
* @param workspaces - authoritative Workspace membership.
|
|
291
|
+
* @param sessionId - Session whose browser group is required.
|
|
292
|
+
* @returns owning Workspace id, or {@link UNGROUPED_KEY} when no Workspace accounts for it.
|
|
293
|
+
*/
|
|
294
|
+
function owningGroupKey(workspaces, sessionId) {
|
|
295
|
+
return workspaces.find((workspace) => workspace.sessionIds.includes(sessionId))?.workspaceId ?? "";
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
293
298
|
* Directory display label: basename of the path (both separators accepted).
|
|
294
299
|
* Ungrouped-bucket fallback for surfaces without a workspace title.
|
|
295
300
|
* @param cwd - directory path, or undefined for the ungrouped bucket.
|
|
@@ -422,7 +427,7 @@ window.__ModuleLoader__.load({
|
|
|
422
427
|
const archived = new Set(archivedSessionIds);
|
|
423
428
|
const expandedGroups = new Set(view.expandedGroups);
|
|
424
429
|
const descendants = indexSubagentDescendants(list.byId);
|
|
425
|
-
const currentGroup = list.current === void 0 ? void 0 : workspaces
|
|
430
|
+
const currentGroup = list.current === void 0 ? void 0 : owningGroupKey(workspaces, list.current);
|
|
426
431
|
const groups = [];
|
|
427
432
|
for (const g of groupByWorkspace(list, workspaces, archived, view.ungroupedOrder)) {
|
|
428
433
|
const expanded = expandedGroups.has(g.key);
|
|
@@ -902,18 +907,25 @@ window.__ModuleLoader__.load({
|
|
|
902
907
|
* @param props.onRename - open the session rename dialog (id + current title).
|
|
903
908
|
* @param props.onFork - fork a session at its last completed turn.
|
|
904
909
|
* @param props.onArchive - archive a session by id.
|
|
910
|
+
* @param props.onReveal - scroll this row into view after search navigation, then acknowledge it.
|
|
905
911
|
* @param props.drag - optional draggable-row wiring.
|
|
906
912
|
* @param props.flat - omit the empty status slot in the hierarchy-free flat list.
|
|
907
913
|
* @param props.t - the browser root's locale seat.
|
|
908
914
|
* @returns the session row.
|
|
909
915
|
*/
|
|
910
|
-
function SessionNodeItem({ node, currentId, now, onOpen, onRename, onFork, onArchive, drag, flat = false, t }) {
|
|
916
|
+
function SessionNodeItem({ node, currentId, now, onOpen, onRename, onFork, onArchive, onReveal, drag, flat = false, t }) {
|
|
911
917
|
const row = node;
|
|
912
918
|
const title = displayTitle(node, t);
|
|
913
919
|
const selected = node.id === currentId;
|
|
914
920
|
const statuses = sessionStatuses(node, t);
|
|
915
921
|
const showStatus = statuses[0].state !== "done" || row.completed;
|
|
916
922
|
const [menuOpen, setMenuOpen] = (0, react.useState)(false);
|
|
923
|
+
const rowRef = (0, react.useRef)(null);
|
|
924
|
+
(0, react.useEffect)(() => {
|
|
925
|
+
if (onReveal === void 0) return;
|
|
926
|
+
rowRef.current?.scrollIntoView({ block: "nearest" });
|
|
927
|
+
onReveal();
|
|
928
|
+
}, [onReveal]);
|
|
917
929
|
const sessionMenuItems = [
|
|
918
930
|
{
|
|
919
931
|
id: "rename",
|
|
@@ -933,6 +945,7 @@ window.__ModuleLoader__.load({
|
|
|
933
945
|
];
|
|
934
946
|
return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.HoverCard, {
|
|
935
947
|
anchor: (0, react_jsx_runtime.jsxs)("div", {
|
|
948
|
+
ref: rowRef,
|
|
936
949
|
className: clsx(Rows_module_css_default.sessionRow, selected && Rows_module_css_default.selected, menuOpen && Rows_module_css_default.menuOpen, flat && !showStatus && Rows_module_css_default.flatSessionRowWithoutStatus, drag?.marker === "before" && Rows_module_css_default.dropBefore, drag?.marker === "after" && Rows_module_css_default.dropAfter),
|
|
937
950
|
role: "treeitem",
|
|
938
951
|
"aria-selected": selected,
|
|
@@ -1429,10 +1442,11 @@ window.__ModuleLoader__.load({
|
|
|
1429
1442
|
return e.clientY < rect.top + rect.height / 2 ? "before" : "after";
|
|
1430
1443
|
}
|
|
1431
1444
|
/** The scrolling session tree; unmounting drops the sessions subscription and expand-all state. */
|
|
1432
|
-
function SessionTree({ useSessions, useSessionPendingInteraction, startSession, open, forkSession, workspaces, archivedSessionIds, onRenameRequest, onDeleteRequest, onSessionRename, onSessionArchive, insertWorkspaceBefore, insertSessionBefore, orderBy, groupExpansion, setGroupExpanded, sessionOrderByAccount, sessionUpdatedAtByAccount, syncSessionOrderAccount, setSessionOrder, home, t }) {
|
|
1445
|
+
function SessionTree({ useSessions, useSessionPendingInteraction, startSession, open, forkSession, workspaces, archivedSessionIds, workspaceReady, onRenameRequest, onDeleteRequest, onSessionRename, onSessionArchive, insertWorkspaceBefore, insertSessionBefore, orderBy, groupExpansion, setGroupExpanded, sessionOrderByAccount, sessionUpdatedAtByAccount, syncSessionOrderAccount, setSessionOrder, home, t, revealSessionId, onSessionRevealed }) {
|
|
1433
1446
|
const list = useSessions((s) => s);
|
|
1434
1447
|
const pendingInteractions = useSessionPendingInteraction((s) => s);
|
|
1435
1448
|
const current = list.current;
|
|
1449
|
+
const revealGroup = revealSessionId === void 0 || !workspaceReady ? void 0 : owningGroupKey(workspaces, revealSessionId);
|
|
1436
1450
|
const [expandedSessionGroups, setExpandedSessionGroups] = (0, react.useState)([]);
|
|
1437
1451
|
const [drag, setDrag] = (0, react.useState)(null);
|
|
1438
1452
|
const sessionDropCommitted = (0, react.useRef)(false);
|
|
@@ -1440,7 +1454,7 @@ window.__ModuleLoader__.load({
|
|
|
1440
1454
|
const workspaceDropCommitted = (0, react.useRef)(false);
|
|
1441
1455
|
const previousOrderBy = (0, react.useRef)(orderBy);
|
|
1442
1456
|
useNativeDragAcceptance(drag !== null || workspaceDrag !== null);
|
|
1443
|
-
const currentGroup = current === void 0 ? void 0 : workspaces
|
|
1457
|
+
const currentGroup = current === void 0 || !workspaceReady ? void 0 : owningGroupKey(workspaces, current);
|
|
1444
1458
|
(0, react.useEffect)(() => {
|
|
1445
1459
|
if (current === void 0 || currentGroup === void 0 || Object.hasOwn(groupExpansion, currentGroup)) return;
|
|
1446
1460
|
setGroupExpanded(currentGroup, true);
|
|
@@ -1509,6 +1523,25 @@ window.__ModuleLoader__.load({
|
|
|
1509
1523
|
expandedGroups,
|
|
1510
1524
|
sessionOrderByAccount
|
|
1511
1525
|
]);
|
|
1526
|
+
(0, react.useEffect)(() => {
|
|
1527
|
+
if (revealGroup === void 0 || groupExpansion[revealGroup] === true) return;
|
|
1528
|
+
setGroupExpanded(revealGroup, true);
|
|
1529
|
+
}, [
|
|
1530
|
+
groupExpansion,
|
|
1531
|
+
revealGroup,
|
|
1532
|
+
setGroupExpanded
|
|
1533
|
+
]);
|
|
1534
|
+
(0, react.useEffect)(() => {
|
|
1535
|
+
if (revealSessionId === void 0 || revealGroup === void 0) return;
|
|
1536
|
+
const group = groups.find((candidate) => candidate.key === revealGroup);
|
|
1537
|
+
if (group === void 0 || !group.expanded || !group.sessions.some((row) => row.id === revealSessionId)) return;
|
|
1538
|
+
if (collapsedSessionRows(group.sessions).rows.some((row) => row.id === revealSessionId)) return;
|
|
1539
|
+
setExpandedSessionGroups((keys) => keys.includes(revealGroup) ? keys : [...keys, revealGroup]);
|
|
1540
|
+
}, [
|
|
1541
|
+
groups,
|
|
1542
|
+
revealGroup,
|
|
1543
|
+
revealSessionId
|
|
1544
|
+
]);
|
|
1512
1545
|
const now = Date.now();
|
|
1513
1546
|
const commitSessionDrag = (activeDrag, over) => {
|
|
1514
1547
|
if (sessionDropCommitted.current) return;
|
|
@@ -1661,6 +1694,41 @@ window.__ModuleLoader__.load({
|
|
|
1661
1694
|
}),
|
|
1662
1695
|
(sessionsExpanded ? group.sessions : collapsed.rows).map((node) => {
|
|
1663
1696
|
const sameGroupDrag = drag !== null && drag.accountKey === group.key;
|
|
1697
|
+
const dragProps = {
|
|
1698
|
+
start: () => {
|
|
1699
|
+
sessionDropCommitted.current = false;
|
|
1700
|
+
setDrag({
|
|
1701
|
+
accountKey: group.key,
|
|
1702
|
+
sessionId: node.id,
|
|
1703
|
+
over: null
|
|
1704
|
+
});
|
|
1705
|
+
},
|
|
1706
|
+
active: sameGroupDrag,
|
|
1707
|
+
marker: sameGroupDrag && drag.over?.id === node.id ? drag.over.half : null,
|
|
1708
|
+
hover: (half) => {
|
|
1709
|
+
/* v8 ignore next -- narrowing guard: Rows gates hover on `active`, which is false while the drag state is null. */
|
|
1710
|
+
setDrag((d) => d === null ? d : {
|
|
1711
|
+
...d,
|
|
1712
|
+
over: {
|
|
1713
|
+
id: node.id,
|
|
1714
|
+
half
|
|
1715
|
+
}
|
|
1716
|
+
});
|
|
1717
|
+
},
|
|
1718
|
+
drop: (half) => {
|
|
1719
|
+
/* v8 ignore next -- narrowing guard: Rows gates drop on `active`, which is false while the drag state is null. */
|
|
1720
|
+
if (drag === null) return;
|
|
1721
|
+
commitSessionDrag(drag, {
|
|
1722
|
+
id: node.id,
|
|
1723
|
+
half
|
|
1724
|
+
});
|
|
1725
|
+
},
|
|
1726
|
+
end: () => {
|
|
1727
|
+
if (drag?.over !== null && drag?.over !== void 0) commitSessionDrag(drag, drag.over);
|
|
1728
|
+
else setDrag(null);
|
|
1729
|
+
sessionDropCommitted.current = false;
|
|
1730
|
+
}
|
|
1731
|
+
};
|
|
1664
1732
|
return (0, react_jsx_runtime.jsx)(SessionNodeItem, {
|
|
1665
1733
|
node,
|
|
1666
1734
|
currentId: current,
|
|
@@ -1669,41 +1737,10 @@ window.__ModuleLoader__.load({
|
|
|
1669
1737
|
onRename: onSessionRename,
|
|
1670
1738
|
onFork: forkSession,
|
|
1671
1739
|
onArchive: onSessionArchive,
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
accountKey: group.key,
|
|
1677
|
-
sessionId: node.id,
|
|
1678
|
-
over: null
|
|
1679
|
-
});
|
|
1680
|
-
},
|
|
1681
|
-
active: sameGroupDrag,
|
|
1682
|
-
marker: sameGroupDrag && drag.over?.id === node.id ? drag.over.half : null,
|
|
1683
|
-
hover: (half) => {
|
|
1684
|
-
/* v8 ignore next -- narrowing guard: Rows gates hover on `active`, which is false while the drag state is null. */
|
|
1685
|
-
setDrag((d) => d === null ? d : {
|
|
1686
|
-
...d,
|
|
1687
|
-
over: {
|
|
1688
|
-
id: node.id,
|
|
1689
|
-
half
|
|
1690
|
-
}
|
|
1691
|
-
});
|
|
1692
|
-
},
|
|
1693
|
-
drop: (half) => {
|
|
1694
|
-
/* v8 ignore next -- narrowing guard: Rows gates drop on `active`, which is false while the drag state is null. */
|
|
1695
|
-
if (drag === null) return;
|
|
1696
|
-
commitSessionDrag(drag, {
|
|
1697
|
-
id: node.id,
|
|
1698
|
-
half
|
|
1699
|
-
});
|
|
1700
|
-
},
|
|
1701
|
-
end: () => {
|
|
1702
|
-
if (drag?.over !== null && drag?.over !== void 0) commitSessionDrag(drag, drag.over);
|
|
1703
|
-
else setDrag(null);
|
|
1704
|
-
sessionDropCommitted.current = false;
|
|
1705
|
-
}
|
|
1706
|
-
},
|
|
1740
|
+
onReveal: node.id === revealSessionId && group.key === revealGroup ? () => {
|
|
1741
|
+
onSessionRevealed(node.id);
|
|
1742
|
+
} : void 0,
|
|
1743
|
+
drag: dragProps,
|
|
1707
1744
|
t
|
|
1708
1745
|
}, node.id);
|
|
1709
1746
|
}),
|
|
@@ -1725,7 +1762,7 @@ window.__ModuleLoader__.load({
|
|
|
1725
1762
|
});
|
|
1726
1763
|
}
|
|
1727
1764
|
/** The flat "In one list" body: every session is one draggable top-level row. */
|
|
1728
|
-
function FlatList({ useSessions, useSessionPendingInteraction, open, forkSession, onSessionRename, onSessionArchive, archivedSessionIds, orderBy, sessionOrderByAccount, sessionUpdatedAtByAccount, syncSessionOrderAccount, setSessionOrder, t }) {
|
|
1765
|
+
function FlatList({ useSessions, useSessionPendingInteraction, open, forkSession, onSessionRename, onSessionArchive, archivedSessionIds, orderBy, sessionOrderByAccount, sessionUpdatedAtByAccount, syncSessionOrderAccount, setSessionOrder, revealSessionId, onSessionRevealed, t }) {
|
|
1729
1766
|
const list = useSessions((s) => s);
|
|
1730
1767
|
const pendingInteractions = useSessionPendingInteraction((s) => s);
|
|
1731
1768
|
const baseRows = (0, react.useMemo)(() => deriveFlat(list, archivedSessionIds, pendingInteractions), [
|
|
@@ -1808,6 +1845,9 @@ window.__ModuleLoader__.load({
|
|
|
1808
1845
|
onRename: onSessionRename,
|
|
1809
1846
|
onFork: forkSession,
|
|
1810
1847
|
onArchive: onSessionArchive,
|
|
1848
|
+
onReveal: node.id === revealSessionId ? () => {
|
|
1849
|
+
onSessionRevealed(node.id);
|
|
1850
|
+
} : void 0,
|
|
1811
1851
|
flat: true,
|
|
1812
1852
|
drag: {
|
|
1813
1853
|
start: () => {
|
|
@@ -1915,6 +1955,7 @@ window.__ModuleLoader__.load({
|
|
|
1915
1955
|
const home = useHostInfo((info) => info.home);
|
|
1916
1956
|
const workspaces = useWorkspaces((state) => state.items);
|
|
1917
1957
|
const workspacePhase = useWorkspaces((state) => state.phase);
|
|
1958
|
+
const workspaceStreamState = useWorkspaces((state) => state.state);
|
|
1918
1959
|
const archivedSessionIds = useWorkspaces((state) => state.archivedSessionIds);
|
|
1919
1960
|
const directoryFlowAvailable = useDirectoryFlow((occupied) => occupied);
|
|
1920
1961
|
const groupBy = useStore((s) => s.groupBy);
|
|
@@ -1926,7 +1967,7 @@ window.__ModuleLoader__.load({
|
|
|
1926
1967
|
const current = state.current;
|
|
1927
1968
|
return current !== void 0 && state.byId[current]?.blank === true ? current : void 0;
|
|
1928
1969
|
});
|
|
1929
|
-
const currentBlankAccount = currentBlankSessionId === void 0 ? void 0 : workspaces
|
|
1970
|
+
const currentBlankAccount = currentBlankSessionId === void 0 || workspacePhase !== "ready" ? void 0 : owningGroupKey(workspaces, currentBlankSessionId);
|
|
1930
1971
|
const promotedBlank = (0, react.useRef)(void 0);
|
|
1931
1972
|
(0, react.useEffect)(() => {
|
|
1932
1973
|
if (currentBlankSessionId === void 0 || currentBlankAccount === void 0) {
|
|
@@ -1963,6 +2004,7 @@ window.__ModuleLoader__.load({
|
|
|
1963
2004
|
]);
|
|
1964
2005
|
const [query, setQuery] = (0, react.useState)("");
|
|
1965
2006
|
const [searchExpanded, setSearchExpanded] = (0, react.useState)(false);
|
|
2007
|
+
const [revealSessionId, setRevealSessionId] = (0, react.useState)(void 0);
|
|
1966
2008
|
const normalizedQuery = sanitizeSearchQuery(query).trim();
|
|
1967
2009
|
const [remoteSearch, setRemoteSearch] = (0, react.useState)({
|
|
1968
2010
|
query: "",
|
|
@@ -1975,6 +2017,18 @@ window.__ModuleLoader__.load({
|
|
|
1975
2017
|
const [wsPickerOpen, setWsPickerOpen] = (0, react.useState)(false);
|
|
1976
2018
|
const wsPlusRef = (0, react.useRef)(null);
|
|
1977
2019
|
const composingRef = (0, react.useRef)(false);
|
|
2020
|
+
const openSearchResult = (sessionId) => {
|
|
2021
|
+
setRevealSessionId(sessionId);
|
|
2022
|
+
setQuery("");
|
|
2023
|
+
setSearchExpanded(false);
|
|
2024
|
+
open(sessionId);
|
|
2025
|
+
};
|
|
2026
|
+
const acknowledgeSessionReveal = (sessionId) => {
|
|
2027
|
+
setRevealSessionId((current) => current === sessionId ? void 0 : current);
|
|
2028
|
+
};
|
|
2029
|
+
(0, react.useEffect)(() => {
|
|
2030
|
+
if (normalizedQuery !== "") setRevealSessionId(void 0);
|
|
2031
|
+
}, [normalizedQuery]);
|
|
1978
2032
|
const [searchOnExpand, setSearchOnExpand] = (0, react.useState)(false);
|
|
1979
2033
|
(0, react.useEffect)(() => {
|
|
1980
2034
|
if (wide && searchOnExpand) {
|
|
@@ -2281,7 +2335,7 @@ window.__ModuleLoader__.load({
|
|
|
2281
2335
|
children: wide && (normalizedQuery !== "" ? (0, react_jsx_runtime.jsx)(SearchResults, {
|
|
2282
2336
|
useSessions,
|
|
2283
2337
|
useSessionPendingInteraction,
|
|
2284
|
-
open,
|
|
2338
|
+
open: openSearchResult,
|
|
2285
2339
|
workspaces,
|
|
2286
2340
|
archivedSessionIds,
|
|
2287
2341
|
query: normalizedQuery,
|
|
@@ -2301,6 +2355,8 @@ window.__ModuleLoader__.load({
|
|
|
2301
2355
|
sessionUpdatedAtByAccount,
|
|
2302
2356
|
syncSessionOrderAccount: actions.syncSessionOrderAccount,
|
|
2303
2357
|
setSessionOrder: actions.setSessionOrder,
|
|
2358
|
+
revealSessionId,
|
|
2359
|
+
onSessionRevealed: acknowledgeSessionReveal,
|
|
2304
2360
|
t
|
|
2305
2361
|
}) : (0, react_jsx_runtime.jsx)(SessionTree, {
|
|
2306
2362
|
useSessions,
|
|
@@ -2309,6 +2365,7 @@ window.__ModuleLoader__.load({
|
|
|
2309
2365
|
onSessionArchive,
|
|
2310
2366
|
forkSession,
|
|
2311
2367
|
workspaces,
|
|
2368
|
+
workspaceReady: workspacePhase === "ready" && workspaceStreamState !== "loading",
|
|
2312
2369
|
groupExpansion,
|
|
2313
2370
|
setGroupExpanded: actions.setGroupExpanded,
|
|
2314
2371
|
sessionOrderByAccount,
|
|
@@ -2321,6 +2378,8 @@ window.__ModuleLoader__.load({
|
|
|
2321
2378
|
insertWorkspaceBefore,
|
|
2322
2379
|
insertSessionBefore,
|
|
2323
2380
|
orderBy,
|
|
2381
|
+
revealSessionId,
|
|
2382
|
+
onSessionRevealed: acknowledgeSessionReveal,
|
|
2324
2383
|
home,
|
|
2325
2384
|
t,
|
|
2326
2385
|
onRenameRequest: (workspaceId, currentTitle) => {
|
|
@@ -77,12 +77,13 @@ export declare function SearchResultItem({ result, currentId, onOpen, t }: {
|
|
|
77
77
|
* @param props.onRename - open the session rename dialog (id + current title).
|
|
78
78
|
* @param props.onFork - fork a session at its last completed turn.
|
|
79
79
|
* @param props.onArchive - archive a session by id.
|
|
80
|
+
* @param props.onReveal - scroll this row into view after search navigation, then acknowledge it.
|
|
80
81
|
* @param props.drag - optional draggable-row wiring.
|
|
81
82
|
* @param props.flat - omit the empty status slot in the hierarchy-free flat list.
|
|
82
83
|
* @param props.t - the browser root's locale seat.
|
|
83
84
|
* @returns the session row.
|
|
84
85
|
*/
|
|
85
|
-
export declare function SessionNodeItem({ node, currentId, now, onOpen, onRename, onFork, onArchive, drag, flat, t }: {
|
|
86
|
+
export declare function SessionNodeItem({ node, currentId, now, onOpen, onRename, onFork, onArchive, onReveal, drag, flat, t, }: {
|
|
86
87
|
node: SessionNode;
|
|
87
88
|
currentId: string | undefined;
|
|
88
89
|
now: number;
|
|
@@ -93,6 +94,8 @@ export declare function SessionNodeItem({ node, currentId, now, onOpen, onRename
|
|
|
93
94
|
onFork: (id: SessionNode['id']) => void;
|
|
94
95
|
/** Archive this session (row menu action; commits without a dialog). */
|
|
95
96
|
onArchive: (id: SessionNode['id']) => void;
|
|
97
|
+
/** Scroll this row into view after search navigation, then acknowledge it. */
|
|
98
|
+
onReveal?: (() => void) | undefined;
|
|
96
99
|
/** Present only on draggable rows (workspace-group sessions outside search). */
|
|
97
100
|
drag?: RowDragProps | undefined;
|
|
98
101
|
/** The row is rendered without a parent Workspace header. */
|
|
@@ -9,6 +9,13 @@ import type { SessionPendingInteractionBase } from '@deepseek-ai/dsh-client-ui-s
|
|
|
9
9
|
import type { SessionId } from '@deepseek-ai/dsh-session/types';
|
|
10
10
|
/** Group key for Sessions outside every Workspace. */
|
|
11
11
|
export declare const UNGROUPED_KEY = "";
|
|
12
|
+
/**
|
|
13
|
+
* Resolve the Workspace browser group that owns one Session.
|
|
14
|
+
* @param workspaces - authoritative Workspace membership.
|
|
15
|
+
* @param sessionId - Session whose browser group is required.
|
|
16
|
+
* @returns owning Workspace id, or {@link UNGROUPED_KEY} when no Workspace accounts for it.
|
|
17
|
+
*/
|
|
18
|
+
export declare function owningGroupKey(workspaces: readonly WorkspaceView[], sessionId: SessionId): string;
|
|
12
19
|
/** Pending interaction kinds with dedicated Workspace-row presentation. */
|
|
13
20
|
export type SessionPendingInteractionStatus = 'approval' | 'plan-review' | 'question';
|
|
14
21
|
type SessionPendingInteractions = ReadonlyMap<SessionId, SessionPendingInteractionBase>;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-client-ui-workspace",
|
|
3
3
|
"description": "Workspace picker plugin: one WorkspacePicker registered into the sidebar and empty-state workspace slots",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.5-alpha.1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -51,24 +51,24 @@
|
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@types/react": "~18.3.1",
|
|
53
53
|
"react": "^18.2.0",
|
|
54
|
-
"@deepseek-ai/dsh-api-session-controller": "^0.1.
|
|
55
|
-
"@deepseek-ai/dsh-api-
|
|
56
|
-
"@deepseek-ai/dsh-api-
|
|
57
|
-
"@deepseek-ai/dsh-client-connection": "^0.1.
|
|
58
|
-
"@deepseek-ai/dsh-client-locale": "^0.1.
|
|
59
|
-
"@deepseek-ai/dsh-client-store": "^0.1.
|
|
60
|
-
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.
|
|
61
|
-
"@deepseek-ai/dsh-client-ui-
|
|
62
|
-
"@deepseek-ai/dsh-client-
|
|
63
|
-
"@deepseek-ai/dsh-client-
|
|
64
|
-
"@deepseek-ai/dsh-client-ui-session": "^0.1.
|
|
65
|
-
"@deepseek-ai/dsh-client-ui-sidebar": "^0.1.
|
|
66
|
-
"@deepseek-ai/dsh-client-ui-slots": "^0.1.
|
|
67
|
-
"@deepseek-ai/dsh-schedule": "^0.1.
|
|
68
|
-
"@deepseek-ai/dsh-typert-protocol": "^0.1.
|
|
69
|
-
"@deepseek-ai/dsh-session": "^0.1.
|
|
54
|
+
"@deepseek-ai/dsh-api-session-controller": "^0.1.5-alpha.1",
|
|
55
|
+
"@deepseek-ai/dsh-api-workspace-controller": "^0.1.5-alpha.1",
|
|
56
|
+
"@deepseek-ai/dsh-api-remotes": "^0.1.5-alpha.1",
|
|
57
|
+
"@deepseek-ai/dsh-client-connection": "^0.1.5-alpha.1",
|
|
58
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.5-alpha.1",
|
|
59
|
+
"@deepseek-ai/dsh-client-store": "^0.1.5-alpha.1",
|
|
60
|
+
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.5-alpha.1",
|
|
61
|
+
"@deepseek-ai/dsh-client-ui-renderer": "^0.1.5-alpha.1",
|
|
62
|
+
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.5-alpha.1",
|
|
63
|
+
"@deepseek-ai/dsh-client-test-runtime": "^0.1.5-alpha.1",
|
|
64
|
+
"@deepseek-ai/dsh-client-ui-session": "^0.1.5-alpha.1",
|
|
65
|
+
"@deepseek-ai/dsh-client-ui-sidebar": "^0.1.5-alpha.1",
|
|
66
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.5-alpha.1",
|
|
67
|
+
"@deepseek-ai/dsh-schedule": "^0.1.5-alpha.1",
|
|
68
|
+
"@deepseek-ai/dsh-typert-protocol": "^0.1.5-alpha.1",
|
|
69
|
+
"@deepseek-ai/dsh-session": "^0.1.5-alpha.1",
|
|
70
70
|
"@deepseek-ai/cordis": "^4.0.2",
|
|
71
|
-
"@deepseek-ai/dsh-util-workspace-path": "^0.1.
|
|
71
|
+
"@deepseek-ai/dsh-util-workspace-path": "^0.1.5-alpha.1"
|
|
72
72
|
},
|
|
73
73
|
"files": [
|
|
74
74
|
"lib/index.js",
|