@michengai/dsh-archive-manager 0.1.41 → 0.1.42
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/CHANGELOG.md +6 -0
- package/CHANGELOG.zh-CN.md +6 -0
- package/README.md +9 -3
- package/README.zh-CN.md +9 -3
- package/lib/client.js +188 -27
- package/lib/workspace.js +51 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
Published release notes are retained below; new versions are added without removing earlier entries.
|
|
6
6
|
|
|
7
|
+
## 0.1.42 - 2026-09-14
|
|
8
|
+
|
|
9
|
+
- Add Archived / Unarchived tabs with Archived selected by default. Select sessions across projects for batch archiving, or archive all chats in a project or ungrouped section from its menu.
|
|
10
|
+
- Unify session action labels and make batch archive buttons and menu actions easier to identify. Keep the confirmation dialog open with an error on archive failure for direct retries, and clear stale feedback.
|
|
11
|
+
- Add the Typert `workspaceRegistry/archiveSessions` endpoint accepting `{ sessionIds: string[] }` to archive sessions across projects, with deduplication, idempotency, and whole-batch rejection for invalid sessions.
|
|
12
|
+
|
|
7
13
|
## 0.1.41 - 2026-09-14
|
|
8
14
|
|
|
9
15
|
- Improve the archived-session bulk action bar with grouped selection details and actions, fixing wrapped button labels in narrow content areas.
|
package/CHANGELOG.zh-CN.md
CHANGED
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
以下发布说明会持续保留;新增版本时不再删除较早记录。
|
|
6
6
|
|
|
7
|
+
## 0.1.42 - 2026-09-14
|
|
8
|
+
|
|
9
|
+
- 新增「已归档 / 未归档」页签,默认展示已归档;支持跨项目选择会话批量归档,也可通过项目或未分组菜单归档该组全部聊天。
|
|
10
|
+
- 统一会话操作文案,提升批量归档按钮与菜单的辨识度;归档失败时保留确认框并显示错误,可直接重试,同时清理过期提示。
|
|
11
|
+
- 新增 Typert `workspaceRegistry/archiveSessions` 接口,接受 `{ sessionIds: string[] }` 批量归档跨项目会话,支持去重与幂等,无效会话导致整批拒绝。
|
|
12
|
+
|
|
7
13
|
## 0.1.41 - 2026-09-14
|
|
8
14
|
|
|
9
15
|
- 优化归档会话的批量操作栏:选择摘要与操作分组显示,修复窄内容区内按钮文字折行的问题。
|
package/README.md
CHANGED
|
@@ -76,16 +76,22 @@ Restart DSH Web, then hard-refresh your browser with `Ctrl+Shift+R`. Open **Sett
|
|
|
76
76
|
| Archive a workspace | Open the workspace menu and choose the option to archive its chats |
|
|
77
77
|
| Find an archive | Open **Settings → Archived sessions**, then search titles or filter by project |
|
|
78
78
|
| Change the order | Sort by update time, creation time, or title |
|
|
79
|
-
| Restore one chat | Click **
|
|
79
|
+
| Restore one chat | Click **Restore** beside the session |
|
|
80
|
+
| Archive a project or ungrouped chats | On **Unarchived**, open the group’s **…** menu and confirm archiving all chats in that group, regardless of search filters |
|
|
81
|
+
| Archive across projects | Switch to **Unarchived**, select sessions across projects, then click **Archive** and confirm |
|
|
80
82
|
| Restore or delete in bulk | Select chats and use the bulk actions, or use the project menu or page-wide actions |
|
|
81
83
|
|
|
82
|
-
|
|
84
|
+
The page opens on **Archived**, with **Unarchived** on the right. Switching tabs clears selections; changing search or project filters preserves them. Check the hidden selection count before applying bulk actions, or clear your selection first.
|
|
85
|
+
|
|
86
|
+
**Restore all / Delete all** remain on the Archived tab and apply to archived sessions across all projects, regardless of filters. Unarchived excludes subagents and blank placeholders and supports sorting by update time or title.
|
|
87
|
+
|
|
88
|
+
Developer API: Typert `workspaceRegistry/archiveSessions` accepts `{ sessionIds: string[] }` and returns `{ archivedSessionIds, archivedSessionIdsAdded }`. Call `registry.archiveSessions(ids)` and check the Typert `ok` result; the method uses the existing host authentication and RPC channel. The host validates and deduplicates the batch before one state write. Already archived IDs are idempotent; unknown sessions return `UNKNOWN_SESSION` without a partial archive.
|
|
83
89
|
|
|
84
90
|
### View and continue archived conversations
|
|
85
91
|
|
|
86
92
|
Available starting with `0.1.40`:
|
|
87
93
|
|
|
88
|
-
- **
|
|
94
|
+
- **Open session**: open the native DSH session to view messages, attachments, and tool details. Continue chatting while keeping the session archived.
|
|
89
95
|
- **Restore and open**: unarchive the session and open it to resume work.
|
|
90
96
|
|
|
91
97
|
## Updates
|
package/README.zh-CN.md
CHANGED
|
@@ -76,16 +76,22 @@ dsh plugin --profile web add @michengai/dsh-archive-manager@latest --registry=ht
|
|
|
76
76
|
| 归档整个工作区 | 打开工作区菜单,选择归档该工作区的会话 |
|
|
77
77
|
| 查找归档 | 打开「设置 → 归档会话」,搜索标题或按项目筛选 |
|
|
78
78
|
| 调整排列顺序 | 按更新时间、创建时间或标题排序 |
|
|
79
|
-
| 恢复一条会话 |
|
|
79
|
+
| 恢复一条会话 | 点击会话右侧的「恢复」 |
|
|
80
|
+
| 归档某个项目或未分组 | 在「未归档」页点击分组右侧“…”菜单,确认归档该组全部聊天;不受搜索筛选影响 |
|
|
81
|
+
| 跨项目批量归档 | 切换到「未归档」,跨项目勾选会话后点击「归档」并确认 |
|
|
80
82
|
| 批量恢复或删除 | 勾选会话后使用批量操作;也可使用项目菜单或页面顶部的全部操作 |
|
|
81
83
|
|
|
82
|
-
|
|
84
|
+
页面默认打开「已归档」,右侧「未归档」用于批量归档。切换 TAB 会清空选择;切换搜索或项目筛选会保留已选会话。批量操作前留意隐藏的已选数量,或先清空选择。
|
|
85
|
+
|
|
86
|
+
「全部恢复 / 全部删除」仅在已归档页显示,作用于所有项目的归档会话,不受筛选影响。未归档页排除子代理和空白占位会话,支持按更新时间或标题排序。
|
|
87
|
+
|
|
88
|
+
开发接口:Typert `workspaceRegistry/archiveSessions` 接收 `{ sessionIds: string[] }`,返回 `{ archivedSessionIds, archivedSessionIdsAdded }`。客户端调用 `registry.archiveSessions(ids)` 并检查 Typert 的 `ok` 结果;接口复用宿主连接的认证与调用通道。宿主先校验、去重,再一次写入;已归档项幂等跳过,未知会话返回 `UNKNOWN_SESSION` 且不部分归档。
|
|
83
89
|
|
|
84
90
|
### 查看并继续归档对话
|
|
85
91
|
|
|
86
92
|
从 `0.1.40` 起支持以下操作:
|
|
87
93
|
|
|
88
|
-
-
|
|
94
|
+
- **打开会话**:打开 DSH 原生会话页,查看消息、附件和工具详情;可直接继续聊天,保持归档状态。
|
|
89
95
|
- **恢复并打开**:取消归档后进入原会话,继续工作。
|
|
90
96
|
|
|
91
97
|
## 更新
|
package/lib/client.js
CHANGED
|
@@ -505,6 +505,12 @@
|
|
|
505
505
|
return value;
|
|
506
506
|
}
|
|
507
507
|
};
|
|
508
|
+
const archiveSessionIdsSchema = {
|
|
509
|
+
parse(value) {
|
|
510
|
+
if (!Array.isArray(value)) throw new TypeError("sessionIds must be an array");
|
|
511
|
+
return [...new Set(value.map((id) => sessionIdSchema.parse(id)))];
|
|
512
|
+
}
|
|
513
|
+
};
|
|
508
514
|
const archivedWorkspaceBatchSchema = {
|
|
509
515
|
parse(value) {
|
|
510
516
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new TypeError("result must be an object");
|
|
@@ -591,6 +597,25 @@
|
|
|
591
597
|
},
|
|
592
598
|
sourceLocation: { file: "@michengai/dsh-archive-manager/lib/workspace.js", line: 1, column: 1 }
|
|
593
599
|
},
|
|
600
|
+
{
|
|
601
|
+
id: "@michengai/dsh-archive-manager#workspaceRegistry/archiveSessions",
|
|
602
|
+
service: "workspaceRegistry",
|
|
603
|
+
namespace: "workspaceRegistry",
|
|
604
|
+
method: "archiveSessions",
|
|
605
|
+
invocation: { kind: "direct" },
|
|
606
|
+
parameters: [{
|
|
607
|
+
name: "sessionIds",
|
|
608
|
+
wire: "sessionIds",
|
|
609
|
+
source: "json",
|
|
610
|
+
codec: { mode: "strict", typeSymbol: "@michengai/dsh-archive-manager/types#ArchiveSessionIds", schema: archiveSessionIdsSchema }
|
|
611
|
+
}],
|
|
612
|
+
result: {
|
|
613
|
+
mode: "strict",
|
|
614
|
+
typeSymbol: "@michengai/dsh-archive-manager/types#ArchivedWorkspaceBatch",
|
|
615
|
+
schema: archivedWorkspaceBatchSchema
|
|
616
|
+
},
|
|
617
|
+
sourceLocation: { file: "@michengai/dsh-archive-manager/lib/workspace.js", line: 1, column: 1 }
|
|
618
|
+
},
|
|
594
619
|
{
|
|
595
620
|
id: "@michengai/dsh-archive-manager#workspaceRegistry/archiveWorkspaceSessions",
|
|
596
621
|
service: "workspaceRegistry",
|
|
@@ -729,9 +754,27 @@
|
|
|
729
754
|
function GithubMark16() {
|
|
730
755
|
return (0, react_jsx_runtime.jsx)("svg", { viewBox: "0 0 16 16", width: 16, height: 16, "aria-hidden": true, focusable: "false", children: (0, react_jsx_runtime.jsx)("path", { fill: "currentColor", d: "M8 0a8 8 0 0 0-2.53 15.59c.4.074.547-.173.547-.385 0-.19-.007-.693-.01-1.36-2.226.484-2.695-1.073-2.695-1.073-.364-.924-.89-1.17-.89-1.17-.726-.496.055-.486.055-.486.803.056 1.225.824 1.225.824.714 1.223 1.872.87 2.328.665.072-.517.28-.87.508-1.07-1.777-.202-3.645-.888-3.645-3.956 0-.874.31-1.588.823-2.148-.083-.202-.357-1.017.078-2.12 0 0 .672-.215 2.2.82A7.65 7.65 0 0 1 8 4.8c.68.003 1.365.092 2.004.27 1.527-1.035 2.197-.82 2.197-.82.437 1.103.162 1.918.08 2.12.513.56.822 1.274.822 2.148 0 3.076-1.872 3.752-3.654 3.95.288.248.544.735.544 1.482 0 1.07-.01 1.932-.01 2.195 0 .214.144.463.55.384A8.001 8.001 0 0 0 8 0Z" }) });
|
|
731
756
|
}
|
|
732
|
-
function ArchivedSessionsSection({ sessionStore, workspaceStore, unarchiveSession, deleteSession, unarchiveSessions, deleteArchivedSessions, archivedSessionMetadata, openConversation, viewState, close, t }) {
|
|
757
|
+
function ArchivedSessionsSection({ archiveSessions, sessionStore, workspaceStore, unarchiveSession, deleteSession, unarchiveSessions, deleteArchivedSessions, archivedSessionMetadata, openConversation, viewState, close, t }) {
|
|
733
758
|
const sessions = (0, react.useSyncExternalStore)(sessionStore.subscribe, sessionStore.getSnapshot);
|
|
734
759
|
const workspaceState = (0, react.useSyncExternalStore)(workspaceStore.subscribe, workspaceStore.getSnapshot);
|
|
760
|
+
const [archiveTab, setArchiveTab] = (0, react.useState)("archived");
|
|
761
|
+
const isArchived = archiveTab === "archived";
|
|
762
|
+
const [archiveTarget, setArchiveTarget] = (0, react.useState)(null);
|
|
763
|
+
const [archiveGroup, setArchiveGroup] = (0, react.useState)(null);
|
|
764
|
+
const requestArchive = (ids, group = null) => {
|
|
765
|
+
setError(null);
|
|
766
|
+
setNotice(null);
|
|
767
|
+
setArchiveGroup(group);
|
|
768
|
+
setArchiveTarget(ids);
|
|
769
|
+
};
|
|
770
|
+
const closeArchive = () => {
|
|
771
|
+
if (!busy) {
|
|
772
|
+
setArchiveTarget(null);
|
|
773
|
+
setArchiveGroup(null);
|
|
774
|
+
setError(null);
|
|
775
|
+
}
|
|
776
|
+
};
|
|
777
|
+
const archiveBusy = (0, react.useRef)(false);
|
|
735
778
|
const [deleteTarget, setDeleteTarget] = (0, react.useState)(null);
|
|
736
779
|
const [busy, setBusy] = (0, react.useState)(false);
|
|
737
780
|
const [error, setError] = (0, react.useState)(null);
|
|
@@ -771,7 +814,39 @@
|
|
|
771
814
|
(0, react.useEffect)(() => {
|
|
772
815
|
if (viewState) Object.assign(viewState, { query, project, sortBy });
|
|
773
816
|
}, [query, project, sortBy, viewState]);
|
|
774
|
-
const
|
|
817
|
+
const eligibleIds = (0, react.useMemo)(() => isArchived ? workspaceState.archivedSessionIds : unarchivedSessionIds(sessions.byId, workspaceState.archivedSessionIds), [isArchived, sessions.byId, workspaceState.archivedSessionIds]);
|
|
818
|
+
const groups = (0, react.useMemo)(() => deriveArchivedGroups(sessions.byId, workspaceState.items, eligibleIds, t("group.ungrouped")), [sessions.byId, workspaceState, eligibleIds, t]);
|
|
819
|
+
const switchTab = (tab) => {
|
|
820
|
+
if (busy || unarchivingSessionIdsRef.current.size > 0) return;
|
|
821
|
+
setArchiveTab(tab);
|
|
822
|
+
setSelectedSessionIds([]);
|
|
823
|
+
setArchiveTarget(null);
|
|
824
|
+
setArchiveGroup(null);
|
|
825
|
+
setError(null);
|
|
826
|
+
setNotice(null);
|
|
827
|
+
setProject("all");
|
|
828
|
+
setQuery("");
|
|
829
|
+
if (tab === "unarchived" && sortBy === "created") setSortBy("updated");
|
|
830
|
+
};
|
|
831
|
+
const confirmArchive = async () => {
|
|
832
|
+
if (archiveBusy.current || busy || !archiveTarget?.length) return;
|
|
833
|
+
archiveBusy.current = true;
|
|
834
|
+
setBusy(true);
|
|
835
|
+
setError(null);
|
|
836
|
+
setNotice(null);
|
|
837
|
+
try {
|
|
838
|
+
const result = await archiveSessions(archiveTarget);
|
|
839
|
+
setSelectedSessionIds((ids) => ids.filter((id) => !result.archivedSessionIds.includes(id)));
|
|
840
|
+
setNotice(t("archives.archiveSuccess", { n: result.archivedSessionIdsAdded.length }));
|
|
841
|
+
setArchiveTarget(null);
|
|
842
|
+
setArchiveGroup(null);
|
|
843
|
+
} catch (reason) {
|
|
844
|
+
setError(t("archives.archiveBatchFailed", { detail: reason instanceof Error ? reason.message : String(reason) }));
|
|
845
|
+
} finally {
|
|
846
|
+
archiveBusy.current = false;
|
|
847
|
+
setBusy(false);
|
|
848
|
+
}
|
|
849
|
+
};
|
|
775
850
|
const sortedGroups = (0, react.useMemo)(() => sortArchivedGroups(groups, sortBy, createdAtById, t), [groups, sortBy, createdAtById, t]);
|
|
776
851
|
(0, react.useEffect)(() => {
|
|
777
852
|
let cancelled = false;
|
|
@@ -801,8 +876,8 @@
|
|
|
801
876
|
const allBatchTarget = { scope: "all" };
|
|
802
877
|
const allBatchSessionIds = (0, react.useMemo)(() => deriveArchivedBatchIds(workspaceState.archivedSessionIds, workspaceState.items, allBatchTarget), [workspaceState.archivedSessionIds, workspaceState.items]);
|
|
803
878
|
(0, react.useEffect)(() => {
|
|
804
|
-
setSelectedSessionIds((current) => pruneArchivedSelection(current,
|
|
805
|
-
}, [
|
|
879
|
+
setSelectedSessionIds((current) => pruneArchivedSelection(current, eligibleIds));
|
|
880
|
+
}, [eligibleIds]);
|
|
806
881
|
const toggleSessionSelection = (sessionId, checked) => {
|
|
807
882
|
setSelectedSessionIds((current) => toggleArchivedSelection(current, [sessionId], checked));
|
|
808
883
|
};
|
|
@@ -892,20 +967,45 @@
|
|
|
892
967
|
return (0, react_jsx_runtime.jsxs)("section", {
|
|
893
968
|
className: "dsham_settings",
|
|
894
969
|
"aria-label": t("archives.title"),
|
|
895
|
-
children: [(0, react_jsx_runtime.jsx)("style", { children: ARCHIVE_SETTINGS_CSS + ARCHIVE_SETTINGS_BATCH_CSS + ARCHIVE_SETTINGS_EXTERNAL_LINK_CSS + ARCHIVE_SETTINGS_SELECTION_CSS + ARCHIVE_SETTINGS_DELETE_CONFIRM_CSS }), (0, react_jsx_runtime.jsxs)("
|
|
970
|
+
children: [(0, react_jsx_runtime.jsx)("style", { children: ARCHIVE_TABS_CSS + ARCHIVE_SETTINGS_CSS + ARCHIVE_SETTINGS_BATCH_CSS + ARCHIVE_SETTINGS_EXTERNAL_LINK_CSS + ARCHIVE_SETTINGS_SELECTION_CSS + ARCHIVE_SETTINGS_DELETE_CONFIRM_CSS + ARCHIVE_WORKSPACE_CONFIRM_CSS }), (0, react_jsx_runtime.jsxs)("div", {
|
|
971
|
+
// 设置页使用独立布局容器,避免被 Codex UI 的会话 header 页签适配器识别。
|
|
896
972
|
className: "dsham_settingsHeader",
|
|
897
973
|
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
898
974
|
children: [(0, react_jsx_runtime.jsxs)("div", { className: "dsham_settingsTitleRow", children: [(0, react_jsx_runtime.jsx)("h2", { children: t("archives.title") }), (0, react_jsx_runtime.jsxs)("div", { className: "dsham_settingsLinks", children: [(0, react_jsx_runtime.jsxs)("a", { className: "dsham_settingsExternalLink", href: "https://github.com/MichengAI/dsh-archive-manager", target: "_blank", rel: "noreferrer", "aria-label": t("archives.viewProject"), children: [(0, react_jsx_runtime.jsx)(GithubMark16, {}), t("archives.viewProject")] }), (0, react_jsx_runtime.jsxs)("a", { className: "dsham_settingsExternalLink", href: "https://github.com/MichengAI/dsh-archive-manager/issues", target: "_blank", rel: "noreferrer", "aria-label": t("archives.feedback"), children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconListPenOutline16, {}), t("archives.feedback")] })] })] }), (0, react_jsx_runtime.jsx)("p", { className: "dsham_settingsIntro", children: t("archives.description") })]
|
|
899
|
-
}), (0, react_jsx_runtime.
|
|
975
|
+
}), (0, react_jsx_runtime.jsx)("div", {
|
|
976
|
+
className: "dsham_archiveTabs",
|
|
977
|
+
role: "tablist",
|
|
978
|
+
"aria-label": t("archives.title"),
|
|
979
|
+
children: ["archived", "unarchived"].map((tab) => (0, react_jsx_runtime.jsx)("button", {
|
|
980
|
+
type: "button",
|
|
981
|
+
role: "tab",
|
|
982
|
+
className: "dsham_archiveTab",
|
|
983
|
+
id: "dsham-tab-" + tab,
|
|
984
|
+
"aria-controls": "dsham-archive-panel",
|
|
985
|
+
"aria-selected": archiveTab === tab,
|
|
986
|
+
tabIndex: archiveTab === tab ? 0 : -1,
|
|
987
|
+
disabled: busy || unarchivingSessionIds.size > 0,
|
|
988
|
+
onClick: () => switchTab(tab),
|
|
989
|
+
onKeyDown: (event) => {
|
|
990
|
+
if (["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Home", "End"].includes(event.key)) {
|
|
991
|
+
event.preventDefault();
|
|
992
|
+
const next = event.key === "Home" ? "archived" : event.key === "End" ? "unarchived" : isArchived ? "unarchived" : "archived";
|
|
993
|
+
switchTab(next);
|
|
994
|
+
event.currentTarget.parentElement.querySelector("#dsham-tab-" + next)?.focus();
|
|
995
|
+
}
|
|
996
|
+
},
|
|
997
|
+
children: t("archives.tab." + tab)
|
|
998
|
+
}, tab))
|
|
999
|
+
}), isArchived && (0, react_jsx_runtime.jsxs)("div", {
|
|
900
1000
|
className: "dsham_settingsHeaderActions",
|
|
901
1001
|
children: [(0, react_jsx_runtime.jsx)("button", { type: "button", className: "dsham_settingsRestoreAll", disabled: busy || allBatchSessionIds.length === 0, onClick: () => onBatchUnarchive(allBatchTarget), children: t("archives.restoreAll") }), (0, react_jsx_runtime.jsxs)("button", { type: "button", className: "dsham_settingsDanger", disabled: busy || allBatchSessionIds.length === 0, onClick: () => setDeleteTarget({ kind: "batch", target: allBatchTarget, title: t("archives.allProjects"), count: allBatchSessionIds.length }), children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, {}), t("archives.deleteAll")] })]
|
|
902
1002
|
})]
|
|
903
|
-
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
1003
|
+
}), (0, react_jsx_runtime.jsxs)("div", { id: "dsham-archive-panel", role: "tabpanel", "aria-labelledby": "dsham-tab-" + archiveTab, children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
904
1004
|
className: "dsham_settingsToolbar",
|
|
905
1005
|
children: [(0, react_jsx_runtime.jsxs)("label", {
|
|
906
1006
|
className: "dsham_settingsSearch",
|
|
907
|
-
children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSearchOutline16, {}), (0, react_jsx_runtime.jsx)("input", { type: "search", value: query, onChange: (event) => setQuery(event.target.value), placeholder: t("archives.searchPlaceholder"), "aria-label": t("archives.searchPlaceholder") })]
|
|
908
|
-
}), (0, react_jsx_runtime.jsx)(ArchiveProjectSelect, { id: "dsham-sort-filter", value: sortBy, options: [{ value: "updated", label: t("archives.sortUpdated") }, { value: "created", label: t("archives.sortCreated") }, { value: "alphabetical", label: t("archives.sortAlphabetical") }], onChange: setSortBy, "aria-label": t("archives.sortBy") }), (0, react_jsx_runtime.jsx)(ArchiveProjectSelect, { id: "dsham-project-filter", value: project, options: [{ value: "all", label: t("archives.allProjects") }, ...sortedGroups.map((group) => ({ value: group.key, label: group.title }))], onChange: setProject, "aria-label": t("archives.projectFilter") })]
|
|
1007
|
+
children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSearchOutline16, {}), (0, react_jsx_runtime.jsx)("input", { type: "search", value: query, onChange: (event) => setQuery(event.target.value), placeholder: t(isArchived ? "archives.searchPlaceholder" : "archives.searchUnarchived"), "aria-label": t(isArchived ? "archives.searchPlaceholder" : "archives.searchUnarchived") })]
|
|
1008
|
+
}), (0, react_jsx_runtime.jsx)(ArchiveProjectSelect, { id: "dsham-sort-filter", value: sortBy, options: [{ value: "updated", label: t("archives.sortUpdated") }, ...isArchived ? [{ value: "created", label: t("archives.sortCreated") }] : [], { value: "alphabetical", label: t("archives.sortAlphabetical") }], onChange: setSortBy, "aria-label": t("archives.sortBy") }), (0, react_jsx_runtime.jsx)(ArchiveProjectSelect, { id: "dsham-project-filter", value: project, options: [{ value: "all", label: t("archives.allProjects") }, ...sortedGroups.map((group) => ({ value: group.key, label: group.title }))], onChange: setProject, "aria-label": t("archives.projectFilter") })]
|
|
909
1009
|
}), groups.length > 0 && (0, react_jsx_runtime.jsx)(ArchiveSelectionToolbar, {
|
|
910
1010
|
selectedCount: selectedSessionIds.length,
|
|
911
1011
|
hiddenCount: selectedSessionIds.length - selectedVisibleCount,
|
|
@@ -916,28 +1016,41 @@
|
|
|
916
1016
|
t,
|
|
917
1017
|
onToggle: toggleVisibleSelection,
|
|
918
1018
|
onClear: () => setSelectedSessionIds([]),
|
|
1019
|
+
onArchive: isArchived ? void 0 : () => requestArchive([...selectedSessionIds]),
|
|
919
1020
|
onRestore: onSelectedUnarchive,
|
|
920
1021
|
onDelete: () => setDeleteTarget({ kind: "batch", target: { scope: "sessions", sessionIds: selectedSessionIds }, count: selectedSessionIds.length })
|
|
921
|
-
}), groups.length === 0 ? (0, react_jsx_runtime.jsx)("div", { className: "dsham_settingsEmpty", children: t("archives.empty") }) : filteredGroups.length === 0 ? (0, react_jsx_runtime.jsx)("div", { className: "dsham_settingsEmpty", children: t("archives.emptyFiltered") }) : filteredGroups.map((group) => {
|
|
1022
|
+
}), groups.length === 0 ? (0, react_jsx_runtime.jsx)("div", { className: "dsham_settingsEmpty", children: t(isArchived ? "archives.empty" : "archives.emptyUnarchived") }) : filteredGroups.length === 0 ? (0, react_jsx_runtime.jsx)("div", { className: "dsham_settingsEmpty", children: t("archives.emptyFiltered") }) : filteredGroups.map((group) => {
|
|
922
1023
|
const target = archivedBatchTargetForGroup(group.key);
|
|
923
|
-
const
|
|
1024
|
+
const groupSessionIds = groups.find((item) => item.key === group.key)?.sessions.map((session) => session.id) ?? [];
|
|
1025
|
+
const count = isArchived ? deriveArchivedBatchIds(workspaceState.archivedSessionIds, workspaceState.items, target).length : groupSessionIds.length;
|
|
924
1026
|
return (0, react_jsx_runtime.jsxs)("section", {
|
|
925
1027
|
className: "dsham_settingsGroup",
|
|
926
1028
|
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
927
1029
|
className: "dsham_settingsGroupHeading",
|
|
928
|
-
children: [(0, react_jsx_runtime.jsxs)("h3", { className: "dsham_settingsGroupTitle", children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderOpenOutline16, {}), group.title] }), (0, react_jsx_runtime.jsxs)("div", { className: "dsham_settingsGroupMeta", children: [(0, react_jsx_runtime.jsx)("span", { className: "dsham_settingsCount", children: t("archives.sessionCount", { n: count }) }), (0, react_jsx_runtime.jsx)(ArchivedGroupActions, { group, busy, onRestore: () => onBatchUnarchive(target), onDelete: () => setDeleteTarget({ kind: "batch", target, title: group.title, count }), t })] })]
|
|
1030
|
+
children: [(0, react_jsx_runtime.jsxs)("h3", { className: "dsham_settingsGroupTitle", children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderOpenOutline16, {}), group.title] }), (0, react_jsx_runtime.jsxs)("div", { className: "dsham_settingsGroupMeta", children: [(0, react_jsx_runtime.jsx)("span", { className: "dsham_settingsCount", children: t("archives.sessionCount", { n: count }) }), (0, react_jsx_runtime.jsx)(ArchivedGroupActions, { group, busy, onArchive: isArchived ? void 0 : () => requestArchive(groupSessionIds, group), onRestore: () => onBatchUnarchive(target), onDelete: () => setDeleteTarget({ kind: "batch", target, title: group.title, count }), t })] })]
|
|
929
1031
|
}), (0, react_jsx_runtime.jsx)("div", {
|
|
930
1032
|
className: "dsham_settingsList",
|
|
931
1033
|
children: group.sessions.map((session) => (0, react_jsx_runtime.jsxs)("article", {
|
|
932
1034
|
className: "dsham_settingsRow",
|
|
933
1035
|
children: [(0, react_jsx_runtime.jsx)(ArchiveSelectionCheckbox, { checked: selectedSessionIdSet.has(session.id), disabled: busy, label: t("archives.selectSession", { name: displayTitle(session, t) }), onChange: (event) => toggleSessionSelection(session.id, event.target.checked) }), (0, react_jsx_runtime.jsxs)("div", { className: "dsham_settingsContent", children: [(0, react_jsx_runtime.jsx)("div", { className: "dsham_settingsTitle", children: displayTitle(session, t) }), (0, react_jsx_runtime.jsx)("div", { className: "dsham_settingsMeta", children: archiveTimeLabel(session.updatedAt, t) })] }), (0, react_jsx_runtime.jsxs)("div", {
|
|
934
1036
|
className: "dsham_settingsActions",
|
|
935
|
-
children: [(0, react_jsx_runtime.jsx)("button", { type: "button", className: "dsham_settingsAction", disabled: busy || unarchivingSessionIds.has(session.id), onClick: () => viewConversation(session), children: t("archives.
|
|
1037
|
+
children: !isArchived ? [(0, react_jsx_runtime.jsx)("button", { type: "button", className: "dsham_settingsAction", disabled: busy, onClick: () => viewConversation(session), children: t("archives.openSession") }), (0, react_jsx_runtime.jsx)("button", { type: "button", className: "dsham_settingsAction", disabled: busy, onClick: () => requestArchive([session.id]), children: t("archives.archiveSelected") })] : [(0, react_jsx_runtime.jsx)("button", { type: "button", className: "dsham_settingsAction", disabled: busy || unarchivingSessionIds.has(session.id), onClick: () => viewConversation(session), children: t("archives.openSession") }), (0, react_jsx_runtime.jsx)("button", { type: "button", className: "dsham_settingsAction", disabled: busy || unarchivingSessionIds.has(session.id), onClick: () => viewConversation(session, true), children: t("archives.restoreOpen") }), (0, react_jsx_runtime.jsx)("button", { type: "button", className: "dsham_settingsAction", disabled: busy || unarchivingSessionIds.has(session.id), onClick: () => onUnarchive(session.id), children: t("archives.restore") }), (0, react_jsx_runtime.jsx)("button", { type: "button", className: "dsham_settingsDelete", disabled: busy || unarchivingSessionIds.has(session.id), "aria-label": t("menu.deleteSession"), onClick: () => setDeleteTarget({ kind: "session", session }), children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, {}) })]
|
|
936
1038
|
})]
|
|
937
1039
|
}, session.id))
|
|
938
1040
|
})]
|
|
939
1041
|
}, group.key);
|
|
940
|
-
}), error !== null && (0, react_jsx_runtime.jsx)("div", { className: "dsham_settingsError", role: "alert", children: error }), notice !== null && (0, react_jsx_runtime.jsx)("div", { className: "dsham_settingsStatus", role: "status", children: notice }), (0, react_jsx_runtime.
|
|
1042
|
+
}), archiveTarget === null && error !== null && (0, react_jsx_runtime.jsx)("div", { className: "dsham_settingsError", role: "alert", children: error }), notice !== null && (0, react_jsx_runtime.jsx)("div", { className: "dsham_settingsStatus", role: "status", children: notice }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
1043
|
+
open: archiveTarget !== null,
|
|
1044
|
+
onClose: closeArchive,
|
|
1045
|
+
closeLabel: t("close"),
|
|
1046
|
+
title: t("archives.archiveTitle", { n: archiveTarget?.length ?? 0 }),
|
|
1047
|
+
description: archiveGroup === null ? t("archives.archiveSelectedDesc") : t(archiveGroup.key === ARCHIVE_UNGROUPED_KEY ? "archives.archiveUngroupedDesc" : "archives.archiveProjectDesc", { name: archiveGroup.title, n: archiveTarget?.length ?? 0 }),
|
|
1048
|
+
footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1049
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, { variant: "outline", disabled: busy, onClick: closeArchive, children: t("cancel") }),
|
|
1050
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, { variant: "outline", className: "dsham_archiveWorkspaceConfirm", disabled: busy, onClick: confirmArchive, children: t("archives.archiveSelected") })
|
|
1051
|
+
] }),
|
|
1052
|
+
children: error !== null ? (0, react_jsx_runtime.jsx)("div", { className: "dsham_settingsError", role: "alert", children: error }) : busy ? t("archiveWorkspace.pending") : null
|
|
1053
|
+
}), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
941
1054
|
open: deleteTarget !== null,
|
|
942
1055
|
onClose: closeDelete,
|
|
943
1056
|
closeLabel: t("close"),
|
|
@@ -945,7 +1058,7 @@
|
|
|
945
1058
|
...deleteDialogDescription === void 0 ? {} : { description: deleteDialogDescription },
|
|
946
1059
|
footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, { variant: "outline", disabled: busy, onClick: closeDelete, children: t("cancel") }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, { variant: "outline", className: "dsham_settingsDeleteConfirm", disabled: busy, onClick: confirmDelete, children: deleteConfirmLabel })] }),
|
|
947
1060
|
children: busy && (0, react_jsx_runtime.jsx)("div", { role: "status", children: deleteTarget?.kind === "batch" ? t("archives.deleteBatchPending") : t("deleteSession.pending") })
|
|
948
|
-
})]
|
|
1061
|
+
})] })]
|
|
949
1062
|
});
|
|
950
1063
|
}
|
|
951
1064
|
function r(e) {
|
|
@@ -3170,12 +3283,13 @@
|
|
|
3170
3283
|
]
|
|
3171
3284
|
});
|
|
3172
3285
|
}
|
|
3286
|
+
const ARCHIVE_TABS_CSS = ".dsham_archiveTabs{display:flex;gap:24px;border-bottom:1px solid var(--dsw-alias-border-l2)}.dsham_archiveTab{display:inline-flex;align-items:center;gap:6px;white-space:nowrap;padding:12px 2px;border:0;border-bottom:2px solid transparent;border-radius:0;background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-weight:600;cursor:pointer}.dsham_archiveTab[aria-selected=true]{border-bottom-color:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary)}.dsham_archiveTab:focus-visible{outline:2px solid var(--dsw-alias-state-success-primary);outline-offset:2px}.dsham_archiveTab:disabled{opacity:.5;cursor:not-allowed}@container(max-width:520px){.dsham_archiveTabs{gap:16px}}";
|
|
3173
3287
|
const ARCHIVE_SETTINGS_CSS = ".dsham_settings{container-type:inline-size;min-width:0;box-sizing:border-box;width:min(100%,760px);margin:0 auto;padding:0 0 32px;color:var(--dsw-alias-label-primary)}.dsham_settingsHeader{display:flex;flex-direction:column;align-items:stretch;gap:16px;margin-bottom:16px}.dsham_settings h2{margin:0;font-size:24px;line-height:32px;font-weight:600;letter-spacing:-.4px;white-space:nowrap}.dsham_settingsIntro{margin:12px 0 0;max-width:42em;color:var(--dsw-alias-label-tertiary);font-size:14px;line-height:22px}.dsham_settingsDanger{display:inline-flex;align-items:center;gap:6px;min-height:32px;padding:0 12px;color:var(--dsw-alias-state-error-primary);background:transparent;border:1px solid var(--dsw-alias-state-error-primary);border-radius:8px;cursor:pointer;font:inherit;font-size:13px;font-weight:500}.dsham_settingsDanger:hover{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 20%,transparent)}.dsham_settingsToolbar{display:flex;gap:8px;margin-bottom:16px}.dsham_settingsSearch{display:flex;align-items:center;gap:8px;min-width:0;flex:1;height:32px;padding:0 12px;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-3,var(--dsw-alias-button-elevated-fill));border:1px solid var(--dsw-alias-border-l2);border-radius:8px}.dsham_settingsSearch:focus-within{border-color:var(--dsw-alias-label-tertiary)}.dsham_settingsSearch input{width:100%;min-width:0;padding:0;color:var(--dsw-alias-label-primary);background:transparent;border:0;outline:0;font:inherit;font-size:12px}.dsham_settingsSearch input::placeholder{color:var(--dsw-alias-label-tertiary)}.dsham_settingsFilter{position:relative;min-width:168px;flex:none}.dsham_selectTrigger{box-sizing:border-box;display:flex;align-items:center;justify-content:space-between;gap:8px;width:100%;min-height:32px;padding:0 10px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3,var(--dsw-alias-button-elevated-fill));border:1px solid var(--dsw-alias-border-l2);border-radius:8px;cursor:pointer;font:inherit;font-size:13px;line-height:20px;text-align:left}.dsham_selectTrigger:hover{background:var(--dsw-alias-interactive-bg-hover)}.dsham_selectTrigger:focus-visible{outline:2px solid var(--dsw-alias-state-success-primary);outline-offset:2px}.dsham_selectTrigger[aria-expanded='true']{border-color:var(--dsw-alias-state-success-primary)}.dsham_selectValue{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dsham_selectCaret{flex:none;width:12px;height:12px;color:var(--dsw-alias-label-tertiary)}.dsham_selectMenu{position:absolute;top:calc(100% + 4px);left:0;right:0;z-index:30;box-sizing:border-box;min-width:100%;max-height:280px;overflow:auto;padding:4px;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-specific-menu,var(--dsw-alias-bg-layer-2));box-shadow:var(--dsw-shadow-lv3)}.dsham_selectOption{box-sizing:border-box;display:flex;align-items:center;width:100%;min-height:32px;padding:0 10px;border:0;border-radius:8px;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;line-height:20px;text-align:left;cursor:pointer}.dsham_selectOption:hover,.dsham_selectOption[data-active='true']{background:var(--dsw-alias-interactive-bg-hover)}.dsham_selectOption[aria-selected='true']{color:var(--dsw-alias-state-success-primary)}.dsham_settingsGroup{margin:0 0 20px}.dsham_settingsGroupHeading{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:0 0 14px}.dsham_settingsGroupTitle{display:flex;align-items:center;gap:8px;min-width:0;margin:0;color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600}.dsham_settingsGroupTitle svg{flex:none;color:var(--dsw-alias-label-secondary)}.dsham_settingsCount{flex:none;color:var(--dsw-alias-label-tertiary);font-size:12px}.dsham_settingsList{overflow:hidden;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-layer-2,var(--dsw-alias-button-elevated-fill))}.dsham_settingsRow{display:flex;align-items:center;gap:12px;min-height:60px;padding:10px 16px;border-bottom:1px solid var(--dsw-alias-border-l2)}.dsham_settingsRow:last-child{border-bottom:0}.dsham_settingsContent{min-width:0;flex:1}.dsham_settingsTitle{overflow:hidden;color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600;line-height:18px;text-overflow:ellipsis;white-space:nowrap}.dsham_settingsMeta{margin-top:2px;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:16px}.dsham_settingsActions{display:flex;align-items:center;gap:8px}.dsham_settingsAction{min-height:32px;padding:0 12px;color:var(--dsw-alias-label-primary);background:transparent;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;cursor:pointer;font:inherit;font-size:13px;font-weight:500}.dsham_settingsAction:hover{filter:brightness(1.12)}.dsham_settingsDelete{display:flex;align-items:center;justify-content:center;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:transparent;border:0;border-radius:8px;cursor:pointer}.dsham_settingsDelete:hover{color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-interactive-bg-hover)}.dsham_settingsEmpty{padding:28px 8px;color:var(--dsw-alias-label-secondary);text-align:center}.dsham_settingsError{margin-top:10px;color:var(--dsw-alias-state-error-primary);font-size:12px}@container(max-width:520px){.dsham_settingsHeader{margin-bottom:16px}.dsham_settingsToolbar{flex-wrap:wrap;margin-bottom:28px}.dsham_settingsSearch{flex-basis:100%}.dsham_settingsFilter{flex:1;min-width:0}.dsham_settingsGroup{margin-bottom:32px}.dsham_settingsRow{padding:10px 12px}.dsham_settingsActions{gap:4px}}";
|
|
3174
3288
|
const ARCHIVE_SETTINGS_BATCH_CSS = ".dsham_settingsHeaderActions,.dsham_settingsGroupMeta{display:flex;align-items:center;gap:8px;flex:none;flex-wrap:wrap}.dsham_settingsRestoreAll{display:inline-flex;align-items:center;min-height:32px;padding:0 12px;color:var(--dsw-alias-label-primary);background:transparent;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;cursor:pointer;font:inherit;font-size:13px;font-weight:500}.dsham_settingsRestoreAll:hover{background:var(--dsw-alias-interactive-bg-hover)}.dsham_settingsRestoreAll:disabled,.dsham_settingsDanger:disabled,.dsham_settingsGroupMenu:disabled{cursor:not-allowed;opacity:.5}.dsham_settingsGroupMenu{display:flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;color:var(--dsw-alias-label-tertiary);background:transparent;border:0;border-radius:8px;cursor:pointer}.dsham_settingsGroupMenu:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}.dsham_settingsStatus{margin-top:10px;color:var(--dsw-alias-label-secondary);font-size:12px}@media(max-width:720px){.dsham_settingsHeader{flex-direction:column}.dsham_settingsHeaderActions{align-self:flex-start}}";
|
|
3175
3289
|
const ARCHIVE_SETTINGS_EXTERNAL_LINK_CSS = ".dsham_settingsTitleRow{display:flex;align-items:center;gap:8px 12px;min-width:0;flex-wrap:wrap}.dsham_settingsLinks{display:flex;align-items:center;gap:4px;flex-wrap:wrap}.dsham_settingsExternalLink{display:inline-flex;align-items:center;gap:5px;min-height:28px;padding:0 8px;color:var(--dsw-alias-label-secondary);background:transparent;border:1px solid var(--dsw-alias-border-l2);border-radius:7px;font-size:12px;font-weight:500;line-height:18px;text-decoration:none;white-space:nowrap}.dsham_settingsExternalLink:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}.dsham_settingsExternalLink:focus-visible{outline:2px solid var(--dsw-alias-state-success-primary);outline-offset:2px}.dsham_settingsExternalLink svg{flex:none}@media(max-width:720px){.dsham_settingsTitleRow{flex-wrap:wrap}}";
|
|
3176
3290
|
const ARCHIVE_SETTINGS_DELETE_CONFIRM_CSS = ".dsham_settingsDeleteConfirm{color:var(--dsw-alias-state-error-primary)!important;background:transparent!important;border-color:var(--dsw-alias-state-error-primary)!important}.dsham_settingsDeleteConfirm:hover:not(:disabled){background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 20%,transparent)!important}.dsham_settingsDeleteConfirm:focus-visible{outline:2px solid var(--dsw-alias-state-error-secondary);outline-offset:2px}.dsham_settingsDeleteConfirm:disabled{cursor:not-allowed;opacity:.5}";
|
|
3177
3291
|
const ARCHIVE_WORKSPACE_CONFIRM_CSS = ".dsham_archiveWorkspaceConfirm{color:var(--dsw-alias-state-error-primary)!important;background:transparent!important;border-color:var(--dsw-alias-state-error-primary)!important}.dsham_archiveWorkspaceConfirm:hover:not(:disabled){background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 20%,transparent)!important}.dsham_archiveWorkspaceConfirm:focus-visible{outline:2px solid var(--dsw-alias-state-error-secondary);outline-offset:2px}.dsham_archiveWorkspaceConfirm:disabled{cursor:not-allowed;opacity:.5}";
|
|
3178
|
-
const ARCHIVE_SETTINGS_SELECTION_CSS = ".dsham_settingsSelection{margin:-8px 0 16px;padding:4px 0 12px;border-bottom:1px solid var(--dsw-alias-border-l2)}.dsham_settingsSelectionMain{display:flex;flex-wrap:wrap;align-items:center;gap:10px 16px;min-height:36px}.dsham_settingsSelectionSummary{display:flex;flex-wrap:wrap;align-items:center;gap:12px;min-width:0;max-width:100%}.dsham_settingsSelectionToggle{display:inline-flex;flex:none;white-space:nowrap;align-items:center;gap:12px;color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px;cursor:pointer}.dsham_settingsCheckbox{flex:none;width:16px;height:16px;margin:0;accent-color:var(--dsw-alias-state-business-primary,#3b82f6)}.dsham_settingsSelectionClear{flex:none;min-height:28px;padding:0 0 0 12px;border:0;border-left:1px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-state-business-primary,#3b82f6);font:inherit;font-size:13px;white-space:nowrap;cursor:pointer}.dsham_settingsSelectionClear:hover:not(:disabled){text-decoration:underline}.dsham_settingsSelectionActions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:10px;max-width:100%;margin-left:auto}.dsham_settingsSelectionAction{flex:none;white-space:nowrap;min-height:32px;padding:0 14px;color:var(--dsw-alias-label-primary);background:transparent;border:1px solid var(--dsw-alias-border-l2);border-radius:7px;cursor:pointer;font:inherit;font-size:13px;font-weight:500}.dsham_settingsSelectionAction:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.dsham_settingsSelectionDelete{color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary)}.dsham_settingsSelectionScope{margin:8px 0 0;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:20px;overflow-wrap:anywhere}.dsham_settingsSelectionAction:disabled,.dsham_settingsSelectionClear:disabled{cursor:not-allowed;opacity:.5}.dsham_settingsSelectionAction:focus-visible,.dsham_settingsSelectionClear:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#3b82f6);outline-offset:3px}";
|
|
3292
|
+
const ARCHIVE_SETTINGS_SELECTION_CSS = ".dsham_settingsSelection{margin:-8px 0 16px;padding:4px 0 12px;border-bottom:1px solid var(--dsw-alias-border-l2)}.dsham_settingsSelectionMain{display:flex;flex-wrap:wrap;align-items:center;gap:10px 16px;min-height:36px}.dsham_settingsSelectionSummary{display:flex;flex-wrap:wrap;align-items:center;gap:12px;min-width:0;max-width:100%}.dsham_settingsSelectionToggle{display:inline-flex;flex:none;white-space:nowrap;align-items:center;gap:12px;color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px;cursor:pointer}.dsham_settingsCheckbox{flex:none;width:16px;height:16px;margin:0;accent-color:var(--dsw-alias-state-business-primary,#3b82f6)}.dsham_settingsSelectionClear{flex:none;min-height:28px;padding:0 0 0 12px;border:0;border-left:1px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-state-business-primary,#3b82f6);font:inherit;font-size:13px;white-space:nowrap;cursor:pointer}.dsham_settingsSelectionClear:hover:not(:disabled){text-decoration:underline}.dsham_settingsSelectionActions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:10px;max-width:100%;margin-left:auto}.dsham_settingsSelectionAction{flex:none;white-space:nowrap;min-height:32px;padding:0 14px;color:var(--dsw-alias-label-primary);background:transparent;border:1px solid var(--dsw-alias-border-l2);border-radius:7px;cursor:pointer;font:inherit;font-size:13px;font-weight:500}.dsham_settingsSelectionAction:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.dsham_settingsSelectionArchive,.dsham_settingsSelectionDelete{color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary)}.dsham_settingsSelectionScope{margin:8px 0 0;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:20px;overflow-wrap:anywhere}.dsham_settingsSelectionAction:disabled,.dsham_settingsSelectionClear:disabled{cursor:not-allowed;opacity:.5}.dsham_settingsSelectionAction:focus-visible,.dsham_settingsSelectionClear:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#3b82f6);outline-offset:3px}";
|
|
3179
3293
|
const ARCHIVE_SETTINGS_LAYOUT_OVERRIDE = ".dsham_settings{margin:0 auto!important}@media(max-width:720px){.dsham_settings{margin:0 auto!important}}";
|
|
3180
3294
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify("dsh-archive-manager/ArchiveSettings.layout.css") + "]") === null) {
|
|
3181
3295
|
const tag = document.createElement("style");
|
|
@@ -3315,7 +3429,7 @@
|
|
|
3315
3429
|
}) : null]
|
|
3316
3430
|
});
|
|
3317
3431
|
}
|
|
3318
|
-
function ArchiveSelectionToolbar({ selectedCount, hiddenCount, allVisibleSelected, selectedVisibleCount, visibleCount, busy, t, onToggle, onClear, onRestore, onDelete }) {
|
|
3432
|
+
function ArchiveSelectionToolbar({ selectedCount, hiddenCount, allVisibleSelected, selectedVisibleCount, visibleCount, busy, t, onToggle, onClear, onRestore, onDelete, onArchive }) {
|
|
3319
3433
|
const hasSelection = selectedCount > 0;
|
|
3320
3434
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
3321
3435
|
className: "dsham_settingsSelection",
|
|
@@ -3336,7 +3450,7 @@
|
|
|
3336
3450
|
}), hasSelection && (0, react_jsx_runtime.jsx)("button", { type: "button", className: "dsham_settingsSelectionClear", disabled: busy, "aria-label": t("archives.clearSelection"), onClick: onClear, children: t("archives.clearSelectionShort") })]
|
|
3337
3451
|
}), hasSelection && (0, react_jsx_runtime.jsxs)("div", {
|
|
3338
3452
|
className: "dsham_settingsSelectionActions",
|
|
3339
|
-
children: [(0, react_jsx_runtime.jsx)("button", { type: "button", className: "dsham_settingsSelectionAction", disabled: busy, "aria-label": t("archives.restoreSelected"), onClick: onRestore, children: t("archives.
|
|
3453
|
+
children: onArchive ? [(0, react_jsx_runtime.jsx)("button", { type: "button", className: "dsham_settingsSelectionAction dsham_settingsSelectionArchive", disabled: busy, onClick: onArchive, children: t("archives.archiveSelected") })] : [(0, react_jsx_runtime.jsx)("button", { type: "button", className: "dsham_settingsSelectionAction", disabled: busy, "aria-label": t("archives.restoreSelected"), onClick: onRestore, children: t("archives.restore") }), (0, react_jsx_runtime.jsx)("button", { type: "button", className: "dsham_settingsSelectionAction dsham_settingsSelectionDelete", disabled: busy, "aria-label": t("archives.deleteSelected"), onClick: onDelete, children: t("archives.deleteSelectionShort") })]
|
|
3340
3454
|
})]
|
|
3341
3455
|
}), hiddenCount > 0 && (0, react_jsx_runtime.jsx)("p", { className: "dsham_settingsSelectionScope", role: "status", children: t("archives.selectionHiddenHint", { hidden: hiddenCount }) })]
|
|
3342
3456
|
});
|
|
@@ -3356,10 +3470,15 @@
|
|
|
3356
3470
|
onChange
|
|
3357
3471
|
});
|
|
3358
3472
|
}
|
|
3359
|
-
function ArchivedGroupActions({ group, busy, onRestore, onDelete, t }) {
|
|
3473
|
+
function ArchivedGroupActions({ group, busy, onArchive, onRestore, onDelete, t }) {
|
|
3360
3474
|
const [open, setOpen] = (0, react.useState)(false);
|
|
3361
3475
|
const ungrouped = group.key === ARCHIVE_UNGROUPED_KEY;
|
|
3362
|
-
const items = [{
|
|
3476
|
+
const items = onArchive ? [{
|
|
3477
|
+
id: "archive",
|
|
3478
|
+
label: t(ungrouped ? "archives.archiveUngrouped" : "archives.archiveProject"),
|
|
3479
|
+
icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconArchiveOutline20, { size: 16 }),
|
|
3480
|
+
danger: true
|
|
3481
|
+
}] : [{
|
|
3363
3482
|
id: "restore",
|
|
3364
3483
|
label: t(ungrouped ? "archives.restoreUngrouped" : "archives.restoreProject"),
|
|
3365
3484
|
icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutline16, {})
|
|
@@ -3375,7 +3494,9 @@
|
|
|
3375
3494
|
items,
|
|
3376
3495
|
onSelect: (id) => {
|
|
3377
3496
|
setOpen(false);
|
|
3378
|
-
if (
|
|
3497
|
+
if (busy) return;
|
|
3498
|
+
if (id === "archive") onArchive?.();
|
|
3499
|
+
else if (id === "restore") onRestore();
|
|
3379
3500
|
else if (id === "delete") onDelete();
|
|
3380
3501
|
},
|
|
3381
3502
|
portal: true,
|
|
@@ -3439,6 +3560,10 @@
|
|
|
3439
3560
|
};
|
|
3440
3561
|
return { kind: "notice", message: t("archives.deleteSuccess", { n: deleted }) };
|
|
3441
3562
|
}
|
|
3563
|
+
function unarchivedSessionIds(byId, archivedSessionIds) {
|
|
3564
|
+
const archived = new Set(archivedSessionIds);
|
|
3565
|
+
return Object.values(byId).filter((session) => session.origin !== "subagent" && !session.blank && !archived.has(session.id)).map((session) => session.id);
|
|
3566
|
+
}
|
|
3442
3567
|
function deriveArchivedGroups(byId, items, archivedSessionIds, ungroupedLabel) {
|
|
3443
3568
|
const byWorkspace = items.map((workspace) => ({
|
|
3444
3569
|
key: workspace.workspaceId,
|
|
@@ -3480,14 +3605,27 @@
|
|
|
3480
3605
|
});
|
|
3481
3606
|
}
|
|
3482
3607
|
const zh = {
|
|
3483
|
-
"archives.
|
|
3608
|
+
"archives.archiveProject": "\u5F52\u6863\u8BE5\u9879\u76EE\u7684\u5168\u90E8\u804A\u5929",
|
|
3609
|
+
"archives.archiveUngrouped": "\u5F52\u6863\u5168\u90E8\u672A\u5206\u7EC4\u804A\u5929",
|
|
3610
|
+
"archives.archiveProjectDesc": "\u5C06\u201C{name}\u201D\u4E2D\u5168\u90E8 {n} \u6761\u672A\u5F52\u6863\u4F1A\u8BDD\u5F52\u6863\uFF0C\u4E0D\u53D7\u5F53\u524D\u641C\u7D22\u7B5B\u9009\u5F71\u54CD\u3002\u4E4B\u540E\u53EF\u5728\u201C\u5DF2\u5F52\u6863\u201D\u4E2D\u6062\u590D\u3002",
|
|
3611
|
+
"archives.archiveUngroupedDesc": "\u5C06\u5168\u90E8 {n} \u6761\u672A\u5206\u7EC4\u7684\u672A\u5F52\u6863\u4F1A\u8BDD\u5F52\u6863\uFF0C\u4E0D\u53D7\u5F53\u524D\u641C\u7D22\u7B5B\u9009\u5F71\u54CD\u3002\u4E4B\u540E\u53EF\u5728\u201C\u5DF2\u5F52\u6863\u201D\u4E2D\u6062\u590D\u3002",
|
|
3612
|
+
"archives.tab.archived": "\u5DF2\u5F52\u6863",
|
|
3613
|
+
"archives.tab.unarchived": "\u672A\u5F52\u6863",
|
|
3614
|
+
"archives.searchUnarchived": "\u641C\u7D22\u672A\u5F52\u6863\u804A\u5929",
|
|
3615
|
+
"archives.emptyUnarchived": "\u6682\u65E0\u672A\u5F52\u6863\u4F1A\u8BDD\u3002",
|
|
3616
|
+
"archives.archiveSelected": "\u5F52\u6863",
|
|
3617
|
+
"archives.openSession": "\u6253\u5F00\u4F1A\u8BDD",
|
|
3618
|
+
"archives.archiveSelectedDesc": "\u5C06\u9009\u4E2D\u7684\u4F1A\u8BDD\u5F52\u6863\uFF0C\u5305\u542B\u5F53\u524D\u7B5B\u9009\u9690\u85CF\u7684\u5DF2\u9009\u9879\u3002\u4E4B\u540E\u53EF\u5728\u201C\u5DF2\u5F52\u6863\u201D\u4E2D\u67E5\u770B\u548C\u6062\u590D\u3002",
|
|
3619
|
+
"archives.archiveSuccess": "\u5DF2\u5F52\u6863 {n} \u6761\u4F1A\u8BDD\u3002",
|
|
3620
|
+
"archives.archiveBatchFailed": "\u6279\u91CF\u5F52\u6863\u5931\u8D25\uFF1A{detail}",
|
|
3484
3621
|
"archives.navigationUnavailable": "\u5F53\u524D\u5BBF\u4E3B\u65E0\u6CD5\u4FDD\u6301\u5F52\u6863\u5BF9\u8BDD\uFF0C\u8BF7\u4F7F\u7528\u201C\u6062\u590D\u5E76\u6253\u5F00\u201D\u3002",
|
|
3485
3622
|
"archives.sessionNotRetained": "\u5BBF\u4E3B\u672A\u4FDD\u7559\u76EE\u6807\u4F1A\u8BDD\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u6216\u6062\u590D\u540E\u518D\u8BD5\u3002",
|
|
3486
3623
|
"archives.restoreOpen": "\u6062\u590D\u5E76\u6253\u5F00",
|
|
3487
3624
|
"archives.selectedCount": "\u5DF2\u9009 {n} \u6761",
|
|
3488
3625
|
"archives.selectionHiddenHint": "\u542B\u5F53\u524D\u672A\u663E\u793A\u7684 {hidden} \u6761\uFF0C\u4E5F\u5C06\u53C2\u4E0E\u64CD\u4F5C",
|
|
3489
3626
|
"archives.clearSelectionShort": "\u6E05\u7A7A",
|
|
3490
|
-
"archives.
|
|
3627
|
+
"archives.restore": "\u6062\u590D",
|
|
3628
|
+
"archives.archiveTitle": "\u5F52\u6863 {n} \u4E2A\u804A\u5929\uFF1F",
|
|
3491
3629
|
"archives.deleteSelectionShort": "\u5220\u9664",
|
|
3492
3630
|
"archives.clearSelection": "\u6E05\u7A7A\u9009\u62E9",
|
|
3493
3631
|
"group.ungrouped": "\u672A\u5206\u7EC4",
|
|
@@ -3519,7 +3657,7 @@
|
|
|
3519
3657
|
"archived.badge": "\u5F52\u6863\u4F1A\u8BDD",
|
|
3520
3658
|
"archived.notOpenable": "\u5DF2\u5F52\u6863\uFF0C\u53D6\u6D88\u5F52\u6863\u540E\u53EF\u7EE7\u7EED\u5BF9\u8BDD",
|
|
3521
3659
|
"archives.title": "\u5F52\u6863\u4F1A\u8BDD",
|
|
3522
|
-
"archives.description": "\u7BA1\u7406\u5DF2\u5F52\u6863\
|
|
3660
|
+
"archives.description": "\u7BA1\u7406\u5DF2\u5F52\u6863\u4F1A\u8BDD\uFF0C\u6216\u9009\u62E9\u672A\u5F52\u6863\u4F1A\u8BDD\u8FDB\u884C\u6279\u91CF\u5F52\u6863\u3002",
|
|
3523
3661
|
"archives.viewProject": "GitHub",
|
|
3524
3662
|
"archives.feedback": "\u95EE\u9898\u53CD\u9988",
|
|
3525
3663
|
"archives.empty": "\u6682\u65E0\u5DF2\u5F52\u6863\u4F1A\u8BDD",
|
|
@@ -3615,14 +3753,27 @@
|
|
|
3615
3753
|
"time.ago": "{t}\u524D"
|
|
3616
3754
|
};
|
|
3617
3755
|
const en = {
|
|
3618
|
-
"archives.
|
|
3756
|
+
"archives.archiveProject": "Archive all chats in this project",
|
|
3757
|
+
"archives.archiveUngrouped": "Archive all ungrouped chats",
|
|
3758
|
+
"archives.archiveProjectDesc": "Archive all {n} unarchived sessions in \u201C{name}\u201D, regardless of the current search filter. You can restore them in Archived.",
|
|
3759
|
+
"archives.archiveUngroupedDesc": "Archive all {n} ungrouped, unarchived sessions, regardless of the current search filter. You can restore them in Archived.",
|
|
3760
|
+
"archives.tab.archived": "Archived",
|
|
3761
|
+
"archives.tab.unarchived": "Unarchived",
|
|
3762
|
+
"archives.searchUnarchived": "Search unarchived chats",
|
|
3763
|
+
"archives.emptyUnarchived": "No unarchived sessions.",
|
|
3764
|
+
"archives.archiveSelected": "Archive",
|
|
3765
|
+
"archives.openSession": "Open session",
|
|
3766
|
+
"archives.archiveSelectedDesc": "Archive the selected sessions, including selections hidden by the current filter. You can view and restore them in Archived.",
|
|
3767
|
+
"archives.archiveSuccess": "Archived {n} sessions.",
|
|
3768
|
+
"archives.archiveBatchFailed": "Batch archive failed: {detail}",
|
|
3619
3769
|
"archives.navigationUnavailable": "This host cannot keep the conversation archived while opening it. Use \u201CRestore and open\u201D instead.",
|
|
3620
3770
|
"archives.sessionNotRetained": "The host did not keep the requested conversation open. Try again, or restore it before opening.",
|
|
3621
3771
|
"archives.restoreOpen": "Restore and open",
|
|
3622
3772
|
"archives.selectedCount": "{n} selected",
|
|
3623
3773
|
"archives.selectionHiddenHint": "Includes {hidden} hidden by the current filter; actions apply to them too.",
|
|
3624
3774
|
"archives.clearSelectionShort": "Clear",
|
|
3625
|
-
"archives.
|
|
3775
|
+
"archives.restore": "Restore",
|
|
3776
|
+
"archives.archiveTitle": "Archive {n} chats?",
|
|
3626
3777
|
"archives.deleteSelectionShort": "Delete",
|
|
3627
3778
|
"archives.clearSelection": "Clear selection",
|
|
3628
3779
|
"group.ungrouped": "Ungrouped",
|
|
@@ -3654,7 +3805,7 @@
|
|
|
3654
3805
|
"archived.badge": "Archived sessions",
|
|
3655
3806
|
"archived.notOpenable": "This session is archived. Unarchive it to continue the conversation.",
|
|
3656
3807
|
"archives.title": "Archived sessions",
|
|
3657
|
-
"archives.description": "Manage archived sessions.",
|
|
3808
|
+
"archives.description": "Manage archived sessions or select unarchived sessions to archive in bulk.",
|
|
3658
3809
|
"archives.viewProject": "GitHub",
|
|
3659
3810
|
"archives.feedback": "Issues",
|
|
3660
3811
|
"archives.empty": "No archived sessions.",
|
|
@@ -3843,6 +3994,14 @@
|
|
|
3843
3994
|
if (!result.ok) throw new Error(result.error.message);
|
|
3844
3995
|
await refreshSessionList();
|
|
3845
3996
|
};
|
|
3997
|
+
const archiveSessions = async (sessionIds) => {
|
|
3998
|
+
const registry = ctx.get("remote.workspaceRegistry");
|
|
3999
|
+
if (registry === void 0) throw new Error("archive-manager remote service is unavailable");
|
|
4000
|
+
const result = await registry.archiveSessions(sessionIds);
|
|
4001
|
+
if (!result.ok) throw new Error(result.error.message);
|
|
4002
|
+
await refreshSessionList();
|
|
4003
|
+
return result.value;
|
|
4004
|
+
};
|
|
3846
4005
|
const unarchiveSessions = async (target) => {
|
|
3847
4006
|
const registry = ctx.get("remote.workspaceRegistry");
|
|
3848
4007
|
if (registry === void 0) throw new Error("archive-manager remote service is unavailable");
|
|
@@ -3941,6 +4100,7 @@
|
|
|
3941
4100
|
icon: "archive",
|
|
3942
4101
|
locale: NS,
|
|
3943
4102
|
inject: () => ({
|
|
4103
|
+
archiveSessions,
|
|
3944
4104
|
sessionStore: bindObservable(ctx.sessions.list),
|
|
3945
4105
|
workspaceStore: bindObservable(ctx.workspaces.list),
|
|
3946
4106
|
unarchiveSession,
|
|
@@ -3955,6 +4115,7 @@
|
|
|
3955
4115
|
}, ArchivedSessionsSection));
|
|
3956
4116
|
}
|
|
3957
4117
|
exports.__test = {
|
|
4118
|
+
unarchivedSessionIds,
|
|
3958
4119
|
ArchiveSelectionToolbar,
|
|
3959
4120
|
ArchivedSessionsSection,
|
|
3960
4121
|
zh,
|
package/lib/workspace.js
CHANGED
|
@@ -118,6 +118,12 @@ const unarchivedBatchSchema = {
|
|
|
118
118
|
return value;
|
|
119
119
|
}
|
|
120
120
|
};
|
|
121
|
+
const archiveSessionIdsSchema = {
|
|
122
|
+
parse(value) {
|
|
123
|
+
if (!Array.isArray(value)) throw new TypeError("sessionIds must be an array");
|
|
124
|
+
return [...new Set(value.map((id) => sessionIdSchema.parse(id)))];
|
|
125
|
+
}
|
|
126
|
+
};
|
|
121
127
|
const archivedWorkspaceBatchSchema = {
|
|
122
128
|
parse(value) {
|
|
123
129
|
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
@@ -249,6 +255,35 @@ const ARCHIVE_MANAGER_INVOCATIONS = [
|
|
|
249
255
|
column: 1
|
|
250
256
|
}
|
|
251
257
|
},
|
|
258
|
+
{
|
|
259
|
+
id: "@michengai/dsh-archive-manager#workspaceRegistry/archiveSessions",
|
|
260
|
+
service: "workspaceRegistry",
|
|
261
|
+
namespace: "workspaceRegistry",
|
|
262
|
+
method: "archiveSessions",
|
|
263
|
+
invocation: { kind: "direct" },
|
|
264
|
+
parameters: [
|
|
265
|
+
{
|
|
266
|
+
name: "sessionIds",
|
|
267
|
+
wire: "sessionIds",
|
|
268
|
+
source: "json",
|
|
269
|
+
codec: {
|
|
270
|
+
mode: "strict",
|
|
271
|
+
typeSymbol: "@michengai/dsh-archive-manager/types#ArchiveSessionIds",
|
|
272
|
+
schema: archiveSessionIdsSchema
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
],
|
|
276
|
+
result: {
|
|
277
|
+
mode: "strict",
|
|
278
|
+
typeSymbol: "@michengai/dsh-archive-manager/types#ArchivedWorkspaceBatch",
|
|
279
|
+
schema: archivedWorkspaceBatchSchema
|
|
280
|
+
},
|
|
281
|
+
sourceLocation: {
|
|
282
|
+
file: "@michengai/dsh-archive-manager/lib/workspace.js",
|
|
283
|
+
line: 1,
|
|
284
|
+
column: 1
|
|
285
|
+
}
|
|
286
|
+
},
|
|
252
287
|
{
|
|
253
288
|
id: "@michengai/dsh-archive-manager#workspaceRegistry/archiveWorkspaceSessions",
|
|
254
289
|
service: "workspaceRegistry",
|
|
@@ -365,6 +400,7 @@ var ArchiveWorkspaceRegistry = class extends WorkspaceRegistry {
|
|
|
365
400
|
markRemoteMethod(this, "deleteSession");
|
|
366
401
|
markRemoteMethod(this, "unarchiveSessions");
|
|
367
402
|
markRemoteMethod(this, "archiveWorkspaceSessions");
|
|
403
|
+
markRemoteMethod(this, "archiveSessions");
|
|
368
404
|
markRemoteMethod(this, "deleteArchivedSessions");
|
|
369
405
|
markRemoteMethod(this, "archivedSessionMetadata");
|
|
370
406
|
registerHostRemote(this.ctx);
|
|
@@ -494,6 +530,21 @@ var ArchiveWorkspaceRegistry = class extends WorkspaceRegistry {
|
|
|
494
530
|
return { archivedSessionIds: [...next.archivedSessionIds] };
|
|
495
531
|
});
|
|
496
532
|
}
|
|
533
|
+
/** 按明确 ID 跨工作区归档;先校验整批,单次写入,重复归档不新增标记。 */
|
|
534
|
+
async archiveSessions(sessionIds) {
|
|
535
|
+
return this.enqueueOperation(async () => {
|
|
536
|
+
const ids = archiveSessionIdsSchema.parse(sessionIds);
|
|
537
|
+
const state = this.requireState();
|
|
538
|
+
const archived = new Set(state.archivedSessionIds);
|
|
539
|
+
const archivedSessionIdsAdded = ids.filter((id) => !archived.has(id));
|
|
540
|
+
for (const id of archivedSessionIdsAdded) {
|
|
541
|
+
if (!await this.sessionKnown(id)) throw new ArchiveUnknownSessionError(id);
|
|
542
|
+
}
|
|
543
|
+
const next = { ...state, archivedSessionIds: [...state.archivedSessionIds, ...archivedSessionIdsAdded] };
|
|
544
|
+
if (archivedSessionIdsAdded.length > 0) await this.setState(next);
|
|
545
|
+
return { archivedSessionIds: [...next.archivedSessionIds], archivedSessionIdsAdded };
|
|
546
|
+
});
|
|
547
|
+
}
|
|
497
548
|
/**
|
|
498
549
|
* 将一个工作区内所有会话加入归档集合。先确认所有待归档会话仍存在,
|
|
499
550
|
* 再执行单次状态写入,因此未知会话不会导致项目只归档一部分。
|