@michengai/dsh-codex-ui 0.2.107 → 0.2.108
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 +15 -0
- package/CHANGELOG.zh-CN.md +15 -0
- package/lib/client.js +191 -54
- package/lib/index.mjs +14 -8
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,21 @@
|
|
|
4
4
|
|
|
5
5
|
This changelog records recent releases of DSH Codex UI and its one-click installer. Earlier changes remain available in the [Git history](https://github.com/MichengAI/dsh-codex-ui/commits/main).
|
|
6
6
|
|
|
7
|
+
## suite-installer-v0.1.27 - 2026-09-07
|
|
8
|
+
|
|
9
|
+
- Updated the bundled Codex UI to `0.2.108`, including group rename/delete menus and aligned group counts; refreshed exact member versions from the official npm registry.
|
|
10
|
+
|
|
11
|
+
## 0.2.108 - 2026-09-07
|
|
12
|
+
|
|
13
|
+
- Added rename and delete actions to each custom workspace group; the Projects header now keeps only the create-group button. Renaming preserves group membership, ordering, and expansion.
|
|
14
|
+
- Aligned custom-group and Ungrouped counts, kept long names from crowding menu buttons, and improved keyboard focus recovery after renaming.
|
|
15
|
+
- Prevented IME confirmation from submitting new groups and kept rejected names from interfering with preference synchronization.
|
|
16
|
+
- Made case-insensitive name checks independent of system locale while preserving legacy stored group names and memberships.
|
|
17
|
+
|
|
18
|
+
## suite-installer-v0.1.26 - 2026-09-07
|
|
19
|
+
|
|
20
|
+
- Refreshed direct member pins from the official npm registry, including IM Connect `0.1.37`, which withdraws its unfinished proactive delivery feature.
|
|
21
|
+
|
|
7
22
|
## suite-installer-v0.1.25 - 2026-09-07
|
|
8
23
|
|
|
9
24
|
- Updated the bundled Codex UI to `0.2.107` and refreshed direct member versions from the official npm registry for reproducible installation.
|
package/CHANGELOG.zh-CN.md
CHANGED
|
@@ -4,6 +4,21 @@
|
|
|
4
4
|
|
|
5
5
|
本日志记录 DSH Codex UI 及其一键安装器的最近发布;更早的变更可查看 [Git 提交历史](https://github.com/MichengAI/dsh-codex-ui/commits/main)。
|
|
6
6
|
|
|
7
|
+
## suite-installer-v0.1.27 - 2026-09-07
|
|
8
|
+
|
|
9
|
+
- 将套件中的 Codex UI 更新至 `0.2.108`,包含分组重命名、删除菜单和数量对齐优化;从官方 npm 刷新并锁定成员版本。
|
|
10
|
+
|
|
11
|
+
## 0.2.108 - 2026-09-07
|
|
12
|
+
|
|
13
|
+
- 为每个自定义工作区分组新增重命名和删除菜单;项目标题栏仅保留新增分组按钮。重命名保留项目归属、排序和展开状态。
|
|
14
|
+
- 对齐自定义分组与“未分组”的数量,避免长名称挤出菜单按钮,并完善重命名后的键盘焦点恢复。
|
|
15
|
+
- 防止新建分组时输入法选词误触发提交,修复名称校验失败影响偏好同步的问题。
|
|
16
|
+
- 统一不依赖系统语言环境的大小写判重规则,同时兼容保留旧分组名称和成员数据。
|
|
17
|
+
|
|
18
|
+
## suite-installer-v0.1.26 - 2026-09-07
|
|
19
|
+
|
|
20
|
+
- 从官方 npm 刷新直装成员版本,包含 IM Connect `0.1.37`,该版本已撤回未完成的主动投递功能。
|
|
21
|
+
|
|
7
22
|
## suite-installer-v0.1.25 - 2026-09-07
|
|
8
23
|
|
|
9
24
|
- 将套件中的 Codex UI 更新至 `0.2.107`,并从官方 npm 刷新直装成员版本,保证安装可复现。
|
package/lib/client.js
CHANGED
|
@@ -863,8 +863,8 @@ window.__ModuleLoader__.load({
|
|
|
863
863
|
this.code = code;
|
|
864
864
|
}
|
|
865
865
|
};
|
|
866
|
-
/**
|
|
867
|
-
function
|
|
866
|
+
/** 校验结构和归属;存储兼容模式保留旧 locale 下合法的大小写变体名称。 */
|
|
867
|
+
function parseGroups(value, preserveCaseVariants) {
|
|
868
868
|
if (!Array.isArray(value) || value.length > 100) return void 0;
|
|
869
869
|
const groupIds = /* @__PURE__ */ new Set();
|
|
870
870
|
const groupTitles = /* @__PURE__ */ new Set();
|
|
@@ -876,13 +876,14 @@ window.__ModuleLoader__.load({
|
|
|
876
876
|
const id = typeof group.id === "string" ? group.id.trim() : "";
|
|
877
877
|
const title = typeof group.title === "string" ? group.title.trim() : "";
|
|
878
878
|
if (id === "" || id.length > 128 || title === "" || title.length > 80) return void 0;
|
|
879
|
-
|
|
879
|
+
const titleKey = preserveCaseVariants ? title : title.toLowerCase();
|
|
880
|
+
if (groupIds.has(id) || groupTitles.has(titleKey)) return void 0;
|
|
880
881
|
if (!Array.isArray(group.workspaceIds) || group.workspaceIds.length > 1e3) return void 0;
|
|
881
882
|
const normalizedIds = [...new Set(group.workspaceIds)];
|
|
882
883
|
if (!normalizedIds.every((workspaceId) => typeof workspaceId === "string" && workspaceId.trim() !== "" && workspaceId.length <= 256)) return void 0;
|
|
883
884
|
if (normalizedIds.some((workspaceId) => workspaceIds.has(workspaceId))) return void 0;
|
|
884
885
|
groupIds.add(id);
|
|
885
|
-
groupTitles.add(
|
|
886
|
+
groupTitles.add(titleKey);
|
|
886
887
|
normalizedIds.forEach((workspaceId) => workspaceIds.add(workspaceId));
|
|
887
888
|
groups.push({
|
|
888
889
|
id,
|
|
@@ -892,15 +893,30 @@ window.__ModuleLoader__.load({
|
|
|
892
893
|
}
|
|
893
894
|
return groups;
|
|
894
895
|
}
|
|
896
|
+
/** 旧数据可往返保存且不改名;新名称的大小写判重由创建、重命名操作执行。 */
|
|
897
|
+
function parseStoredWorkspaceGroups(value) {
|
|
898
|
+
return parseGroups(value, true);
|
|
899
|
+
}
|
|
895
900
|
/** 新建空分组;项目只有被显式移动后才会进入其中。 */
|
|
896
901
|
function createWorkspaceGroup(groups, group) {
|
|
897
|
-
|
|
902
|
+
if (groups.some((existing) => existing.title.toLowerCase() === group.title.trim().toLowerCase())) throw new WorkspaceGroupError("group-invalid");
|
|
903
|
+
const next = parseStoredWorkspaceGroups([...groups, {
|
|
898
904
|
...group,
|
|
899
905
|
workspaceIds: []
|
|
900
906
|
}]);
|
|
901
907
|
if (next === void 0) throw new WorkspaceGroupError("group-invalid");
|
|
902
908
|
return next;
|
|
903
909
|
}
|
|
910
|
+
/** 仅更改名称,保留分组标识、成员及其顺序。 */
|
|
911
|
+
function renameWorkspaceGroup(groups, groupId, title) {
|
|
912
|
+
if (!groups.some((group) => group.id === groupId)) throw new WorkspaceGroupError("group-missing");
|
|
913
|
+
const normalizedTitle = title.trim();
|
|
914
|
+
if (normalizedTitle === "" || normalizedTitle.length > 80 || groups.some((group) => group.id !== groupId && group.title.toLowerCase() === normalizedTitle.toLowerCase())) throw new WorkspaceGroupError("group-invalid");
|
|
915
|
+
return groups.map((group) => group.id === groupId ? {
|
|
916
|
+
...group,
|
|
917
|
+
title: normalizedTitle
|
|
918
|
+
} : group);
|
|
919
|
+
}
|
|
904
920
|
/** 将项目放入指定分组;未传分组时退回未分组区。 */
|
|
905
921
|
function assignWorkspaceToGroup(groups, workspaceId, groupId) {
|
|
906
922
|
if (workspaceId.trim() === "" || workspaceId.length > 256) throw new WorkspaceGroupError("workspace-invalid");
|
|
@@ -1029,7 +1045,7 @@ window.__ModuleLoader__.load({
|
|
|
1029
1045
|
if (payload === null || typeof payload !== "object") throw new Error("置顶偏好响应格式无效。");
|
|
1030
1046
|
const record = payload;
|
|
1031
1047
|
const workspaceGroupsSupported = Object.prototype.hasOwnProperty.call(record, "workspaceGroups");
|
|
1032
|
-
const workspaceGroups = workspaceGroupsSupported ?
|
|
1048
|
+
const workspaceGroups = workspaceGroupsSupported ? parseStoredWorkspaceGroups(record.workspaceGroups) : [];
|
|
1033
1049
|
if (typeof record.exists !== "boolean" || !Array.isArray(record.pinnedWorkspaceIds) || !record.pinnedWorkspaceIds.every((id) => typeof id === "string") || workspaceGroups === void 0) throw new Error("置顶偏好响应格式无效。");
|
|
1034
1050
|
return {
|
|
1035
1051
|
exists: record.exists,
|
|
@@ -1039,7 +1055,7 @@ window.__ModuleLoader__.load({
|
|
|
1039
1055
|
};
|
|
1040
1056
|
}
|
|
1041
1057
|
async function writeHostWorkspacePreferences(pinnedWorkspaceIds, workspaceGroups, fetcher = fetch) {
|
|
1042
|
-
const groups =
|
|
1058
|
+
const groups = parseStoredWorkspaceGroups([...workspaceGroups]);
|
|
1043
1059
|
if (groups === void 0) throw new Error("工作区分组数据无效。");
|
|
1044
1060
|
const response = await fetcher(WORKSPACE_PREFERENCES_ENDPOINT, {
|
|
1045
1061
|
method: "PUT",
|
|
@@ -1100,7 +1116,7 @@ window.__ModuleLoader__.load({
|
|
|
1100
1116
|
pendingHostSync: false
|
|
1101
1117
|
};
|
|
1102
1118
|
const record = value;
|
|
1103
|
-
const workspaceGroups = record.version === 1 ?
|
|
1119
|
+
const workspaceGroups = record.version === 1 ? parseStoredWorkspaceGroups(record.workspaceGroups) : void 0;
|
|
1104
1120
|
if (workspaceGroups === void 0 || typeof record.pendingHostSync !== "boolean") return {
|
|
1105
1121
|
workspaceGroups: [],
|
|
1106
1122
|
pendingHostSync: false
|
|
@@ -1118,7 +1134,7 @@ window.__ModuleLoader__.load({
|
|
|
1118
1134
|
}
|
|
1119
1135
|
function saveWorkspaceGroupsCache(storage, groups, pendingHostSync) {
|
|
1120
1136
|
if (storage === void 0) return;
|
|
1121
|
-
const workspaceGroups =
|
|
1137
|
+
const workspaceGroups = parseStoredWorkspaceGroups([...groups]);
|
|
1122
1138
|
if (workspaceGroups === void 0) return;
|
|
1123
1139
|
try {
|
|
1124
1140
|
storage.setItem(WORKSPACE_GROUPS_STORAGE_KEY, JSON.stringify({
|
|
@@ -2199,6 +2215,11 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2199
2215
|
.dcu-wb-section+.dcu-wb-section{margin-top:12px}
|
|
2200
2216
|
.dcu-wb-section-head{position:relative;display:flex;align-items:center;min-height:24px;padding:0;border-radius:6px}.dcu-wb-section-head:hover .dcu-wb-actions{display:flex}.dcu-wb-section-label{position:relative;display:flex;align-items:center;gap:4px;flex:1;min-width:0;min-height:24px;border:0;padding:2px 4px 2px 12px;background:transparent;color:var(--dcu-sidebar-tertiary);font:13px/20px var(--dcu-font,inherit);font-weight:400;letter-spacing:0;text-align:left;cursor:pointer}.dcu-wb-section-caret{display:grid;place-items:center;flex:none;width:12px;height:12px;color:currentColor;opacity:0;transform:rotate(0deg);transform-origin:50% 50%;transition:opacity 120ms ease,transform 160ms ease}.dcu-wb-section-head .dcu-wb-section-caret{position:absolute;left:0;top:6px}.dcu-wb-section-caret svg{display:block}.dcu-wb-section-head:hover .dcu-wb-section-caret,.dcu-wb-section-label:focus-visible .dcu-wb-section-caret{opacity:.78}.dcu-wb-section-label[aria-expanded=true] .dcu-wb-section-caret{transform:rotate(90deg)}.dcu-wb-section-body{display:block}.dcu-wb-section-body[data-open=false]{display:none}.dcu-wb-section-body>div{min-height:0}.dcu-wb-section-body[data-open=true]>div{animation:dcu-wb-section-in 140ms cubic-bezier(.16,1,.3,1)}@keyframes dcu-wb-section-in{from{opacity:0;transform:translateY(-3px)}to{opacity:1;transform:none}}@media (prefers-reduced-motion:reduce){.dcu-wb-section-caret{transition:none}.dcu-wb-section-body[data-open=true]>div{animation:none}}
|
|
2201
2217
|
.dcu-wb-project{position:relative;min-width:0}
|
|
2218
|
+
.dcu-wb-collection-head .dcu-wb-more{opacity:0;pointer-events:none}
|
|
2219
|
+
.dcu-wb-collection-head:hover .dcu-wb-more,.dcu-wb-collection-head:focus-within .dcu-wb-more,.dcu-wb-collection-head .dcu-wb-more[aria-expanded=true]{opacity:1;pointer-events:auto}
|
|
2220
|
+
@media (pointer:coarse){.dcu-wb-collection-head .dcu-wb-more{opacity:1;pointer-events:auto}}
|
|
2221
|
+
.dcu-wb-collection-title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
2222
|
+
.dcu-wb-collection-actions{flex-shrink:0;width:20px}
|
|
2202
2223
|
.dcu-wb-collections{display:grid;min-width:0;gap:4px}.dcu-wb-collection,.dcu-wb-ungrouped{position:relative;min-width:0;overflow:visible}.dcu-wb-collection-head{display:flex;align-items:center;min-height:28px;padding:0 4px;border-radius:6px;transition:background 120ms ease}.dcu-wb-collection-head:hover,.dcu-wb-collection-head:focus-within,.dcu-wb-collection-head.dcu-wb-group-drop{background:var(--dcu-sidebar-hover)}.dcu-wb-collection-head.dcu-wb-group-drop{outline:1px solid var(--dsw-alias-state-business-primary)}.dcu-wb-collection-head[draggable=true],.dcu-wb-collection-head[draggable=true] .dcu-wb-collection-label{cursor:grab}.dcu-wb-collection-head[draggable=true]:active,.dcu-wb-collection-head[draggable=true]:active .dcu-wb-collection-label{cursor:grabbing}.dcu-wb-collection-label{display:flex;align-items:center;gap:5px;min-width:0;flex:1;border:0;padding:4px;background:transparent;color:var(--dcu-sidebar-primary);font:13px/20px var(--dcu-font,inherit);text-align:left;cursor:pointer}.dcu-wb-collection-label .dcu-wb-section-caret{position:static;order:-1;opacity:.78}.dcu-wb-collection-label[aria-expanded=true] .dcu-wb-section-caret{transform:rotate(90deg)}.dcu-wb-collection-count{margin-left:auto;color:var(--dcu-sidebar-secondary);font-variant-numeric:tabular-nums}.dcu-wb-collection-body{position:relative;min-width:0;padding-left:12px}.dcu-wb-collection-body::before{content:"";position:absolute;left:31px;top:0;bottom:8px;width:1px;background:var(--dcu-sidebar-border)}.dcu-wb-group-member{position:relative}.dcu-wb-group-member.dcu-wb-drop::before,.dcu-wb-collection.dcu-wb-group-order-drop::before,.dcu-wb-ungrouped.dcu-wb-group-order-drop::before{content:"";position:absolute;z-index:2;left:7px;right:8px;top:-8px;height:8px;pointer-events:none;background:radial-gradient(circle at 4px 50%,transparent 1.75px,var(--dsw-alias-state-business-primary) 2px 3.75px,transparent 4px),linear-gradient(var(--dsw-alias-state-business-primary),var(--dsw-alias-state-business-primary)) 10px 50%/calc(100% - 10px) 2px no-repeat}.dcu-wb-group-member.dcu-wb-drop-after::before{top:auto;bottom:-8px}.dcu-wb-collection-body .dcu-wb-project-head{padding-left:12px}
|
|
2203
2224
|
.dcu-wb-collection.dcu-wb-workspace-move-drop,.dcu-wb-ungrouped.dcu-wb-workspace-move-drop{border-radius:8px;background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 9%,transparent);outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-2px}
|
|
2204
2225
|
.dcu-wb-project-head,.dcu-wb-session{position:relative;display:flex;align-items:center;gap:6px;width:100%;min-width:0;border-radius:10px;padding:0 8px;color:var(--dcu-sidebar-primary);cursor:pointer}
|
|
@@ -2305,10 +2326,10 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2305
2326
|
setPinnedWorkspaceIdsState(next);
|
|
2306
2327
|
};
|
|
2307
2328
|
const setWorkspaceGroups = (update) => {
|
|
2308
|
-
pinnedHostDirtyRef.current = true;
|
|
2309
|
-
workspaceGroupsPendingHostSyncRef.current = true;
|
|
2310
2329
|
const current = workspaceGroupsRef.current;
|
|
2311
2330
|
const next = typeof update === "function" ? update(current) : update;
|
|
2331
|
+
pinnedHostDirtyRef.current = true;
|
|
2332
|
+
workspaceGroupsPendingHostSyncRef.current = true;
|
|
2312
2333
|
workspaceGroupsRef.current = next;
|
|
2313
2334
|
setWorkspaceGroupsState(next);
|
|
2314
2335
|
};
|
|
@@ -2353,7 +2374,12 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2353
2374
|
const [createGroupOpen, setCreateGroupOpen] = (0, react.useState)(false);
|
|
2354
2375
|
const [groupTitleDraft, setGroupTitleDraft] = (0, react.useState)("");
|
|
2355
2376
|
const [deleteGroupId, setDeleteGroupId] = (0, react.useState)();
|
|
2356
|
-
const [
|
|
2377
|
+
const [groupMenuId, setGroupMenuId] = (0, react.useState)();
|
|
2378
|
+
const [renameGroupId, setRenameGroupId] = (0, react.useState)();
|
|
2379
|
+
const [renameGroupDraft, setRenameGroupDraft] = (0, react.useState)("");
|
|
2380
|
+
const [renameGroupError, setRenameGroupError] = (0, react.useState)();
|
|
2381
|
+
const groupActionTriggerRef = (0, react.useRef)();
|
|
2382
|
+
const projectsSectionButtonRef = (0, react.useRef)(null);
|
|
2357
2383
|
(0, react.useEffect)(() => {
|
|
2358
2384
|
writeTreeExpansionState(storage$1(), WORKSPACE_EXPANSION_STORAGE_KEY, expanded);
|
|
2359
2385
|
}, [expanded]);
|
|
@@ -2611,6 +2637,28 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2611
2637
|
setError(userErrorText(reason, t));
|
|
2612
2638
|
}
|
|
2613
2639
|
};
|
|
2640
|
+
const closeRenameGroup = () => {
|
|
2641
|
+
setRenameGroupId(void 0);
|
|
2642
|
+
setRenameGroupDraft("");
|
|
2643
|
+
setRenameGroupError(void 0);
|
|
2644
|
+
const trigger = groupActionTriggerRef.current;
|
|
2645
|
+
const focusTarget = trigger?.isConnected ? trigger : projectsSectionButtonRef.current;
|
|
2646
|
+
groupActionTriggerRef.current = void 0;
|
|
2647
|
+
focusTarget?.focus();
|
|
2648
|
+
};
|
|
2649
|
+
const submitRenameGroup = () => {
|
|
2650
|
+
if (renameGroupId === void 0 || renameGroupDraft.trim() === "") return;
|
|
2651
|
+
if (workspaceGroupsRef.current.find((group) => group.id === renameGroupId)?.title === renameGroupDraft.trim()) {
|
|
2652
|
+
closeRenameGroup();
|
|
2653
|
+
return;
|
|
2654
|
+
}
|
|
2655
|
+
try {
|
|
2656
|
+
setWorkspaceGroups((current) => renameWorkspaceGroup(current, renameGroupId, renameGroupDraft));
|
|
2657
|
+
closeRenameGroup();
|
|
2658
|
+
} catch (reason) {
|
|
2659
|
+
setRenameGroupError(userErrorText(reason, t));
|
|
2660
|
+
}
|
|
2661
|
+
};
|
|
2614
2662
|
const sectionOpen = (id) => expanded[`section:${id}`] ?? true;
|
|
2615
2663
|
const toggleSection = (id) => {
|
|
2616
2664
|
setExpanded((current) => ({
|
|
@@ -3234,7 +3282,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3234
3282
|
setWorkspaceDropTarget(void 0);
|
|
3235
3283
|
setWorkspaceGroups((current) => current.find((candidate) => candidate.workspaceIds.includes(dragged))?.id === groupId ? moveWorkspaceGroupMember(current, dragged, groupId) : assignWorkspaceToGroup(current, dragged, groupId));
|
|
3236
3284
|
},
|
|
3237
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3285
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3238
3286
|
className: `dcu-wb-collection-head${workspaceGroupDragId === groupId ? " dcu-wb-dragging" : ""}`,
|
|
3239
3287
|
draggable: true,
|
|
3240
3288
|
onDragStart: (event) => {
|
|
@@ -3252,7 +3300,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3252
3300
|
setWorkspaceGroupDragId(void 0);
|
|
3253
3301
|
setWorkspaceGroupDropTarget(void 0);
|
|
3254
3302
|
},
|
|
3255
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
3303
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
3256
3304
|
type: "button",
|
|
3257
3305
|
className: "dcu-wb-collection-label",
|
|
3258
3306
|
"aria-expanded": isExpanded,
|
|
@@ -3277,13 +3325,74 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3277
3325
|
})
|
|
3278
3326
|
})
|
|
3279
3327
|
}),
|
|
3280
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3328
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3329
|
+
className: "dcu-wb-collection-title",
|
|
3330
|
+
children: group.title
|
|
3331
|
+
}),
|
|
3281
3332
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3282
3333
|
className: "dcu-wb-collection-count",
|
|
3283
3334
|
children: members.length
|
|
3284
3335
|
})
|
|
3285
3336
|
]
|
|
3286
|
-
})
|
|
3337
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3338
|
+
className: "dcu-wb-collection-actions",
|
|
3339
|
+
onClick: (event) => {
|
|
3340
|
+
event.stopPropagation();
|
|
3341
|
+
},
|
|
3342
|
+
onDragStart: (event) => {
|
|
3343
|
+
event.preventDefault();
|
|
3344
|
+
event.stopPropagation();
|
|
3345
|
+
},
|
|
3346
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
3347
|
+
open: groupMenuId === groupId,
|
|
3348
|
+
onClose: () => {
|
|
3349
|
+
setGroupMenuId(void 0);
|
|
3350
|
+
},
|
|
3351
|
+
items: [
|
|
3352
|
+
{
|
|
3353
|
+
id: "rename",
|
|
3354
|
+
label: t("workspace.renameGroup"),
|
|
3355
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutline16, { size: 16 })
|
|
3356
|
+
},
|
|
3357
|
+
{
|
|
3358
|
+
type: "separator",
|
|
3359
|
+
id: "group-delete-separator"
|
|
3360
|
+
},
|
|
3361
|
+
{
|
|
3362
|
+
id: "delete",
|
|
3363
|
+
label: t("workspace.deleteGroupAction"),
|
|
3364
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, { size: 16 }),
|
|
3365
|
+
danger: true
|
|
3366
|
+
}
|
|
3367
|
+
],
|
|
3368
|
+
onSelect: (action) => {
|
|
3369
|
+
setGroupMenuId(void 0);
|
|
3370
|
+
if (action === "rename") {
|
|
3371
|
+
setRenameGroupId(groupId);
|
|
3372
|
+
setRenameGroupDraft(group.title);
|
|
3373
|
+
setRenameGroupError(void 0);
|
|
3374
|
+
}
|
|
3375
|
+
if (action === "delete") setDeleteGroupId(groupId);
|
|
3376
|
+
},
|
|
3377
|
+
portal: true,
|
|
3378
|
+
dense: true,
|
|
3379
|
+
compact: true,
|
|
3380
|
+
anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3381
|
+
type: "button",
|
|
3382
|
+
className: "dcu-wb-more",
|
|
3383
|
+
draggable: false,
|
|
3384
|
+
"aria-haspopup": "menu",
|
|
3385
|
+
"aria-expanded": groupMenuId === groupId,
|
|
3386
|
+
"aria-label": t("workspace.groupActions", { name: group.title }),
|
|
3387
|
+
title: t("workspace.groupActions", { name: group.title }),
|
|
3388
|
+
onClick: (event) => {
|
|
3389
|
+
groupActionTriggerRef.current = event.currentTarget;
|
|
3390
|
+
setGroupMenuId((current) => current === groupId ? void 0 : groupId);
|
|
3391
|
+
},
|
|
3392
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutline16, { size: 16 })
|
|
3393
|
+
})
|
|
3394
|
+
})
|
|
3395
|
+
})]
|
|
3287
3396
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(DisclosureBody, {
|
|
3288
3397
|
className: "dcu-wb-collection-body",
|
|
3289
3398
|
open: isExpanded,
|
|
@@ -3397,9 +3506,9 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3397
3506
|
setWorkspaceGroups((current) => assignWorkspaceToGroup(current, dragged));
|
|
3398
3507
|
run("workspace-order", () => insertWorkspaceBefore(dragged));
|
|
3399
3508
|
},
|
|
3400
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3509
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3401
3510
|
className: "dcu-wb-collection-head",
|
|
3402
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
3511
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
3403
3512
|
type: "button",
|
|
3404
3513
|
className: "dcu-wb-collection-label",
|
|
3405
3514
|
"aria-expanded": ungroupedExpanded,
|
|
@@ -3430,7 +3539,10 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3430
3539
|
children: ungroupedGroups.length
|
|
3431
3540
|
})
|
|
3432
3541
|
]
|
|
3433
|
-
})
|
|
3542
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3543
|
+
className: "dcu-wb-collection-actions",
|
|
3544
|
+
"aria-hidden": "true"
|
|
3545
|
+
})]
|
|
3434
3546
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DisclosureBody, {
|
|
3435
3547
|
className: "dcu-wb-collection-body",
|
|
3436
3548
|
open: ungroupedExpanded,
|
|
@@ -3611,6 +3723,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3611
3723
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
3612
3724
|
type: "button",
|
|
3613
3725
|
className: "dcu-wb-section-label",
|
|
3726
|
+
ref: projectsSectionButtonRef,
|
|
3614
3727
|
"aria-expanded": sectionOpen("projects"),
|
|
3615
3728
|
onClick: () => {
|
|
3616
3729
|
toggleSection("projects");
|
|
@@ -3632,9 +3745,9 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3632
3745
|
})
|
|
3633
3746
|
})
|
|
3634
3747
|
})]
|
|
3635
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.
|
|
3748
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3636
3749
|
className: "dcu-wb-actions",
|
|
3637
|
-
children:
|
|
3750
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3638
3751
|
type: "button",
|
|
3639
3752
|
className: "dcu-wb-more",
|
|
3640
3753
|
"aria-label": t("workspace.createGroup"),
|
|
@@ -3646,36 +3759,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3646
3759
|
setCreateGroupOpen(true);
|
|
3647
3760
|
},
|
|
3648
3761
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 16 })
|
|
3649
|
-
})
|
|
3650
|
-
open: groupMenuOpen,
|
|
3651
|
-
onClose: () => {
|
|
3652
|
-
setGroupMenuOpen(false);
|
|
3653
|
-
},
|
|
3654
|
-
items: workspaceGroups.map((group) => ({
|
|
3655
|
-
id: group.id,
|
|
3656
|
-
label: t("workspace.deleteGroup", { name: group.title }),
|
|
3657
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, { size: 16 }),
|
|
3658
|
-
danger: true
|
|
3659
|
-
})),
|
|
3660
|
-
onSelect: (id) => {
|
|
3661
|
-
setDeleteGroupId(id);
|
|
3662
|
-
setGroupMenuOpen(false);
|
|
3663
|
-
},
|
|
3664
|
-
portal: true,
|
|
3665
|
-
dense: true,
|
|
3666
|
-
compact: true,
|
|
3667
|
-
anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3668
|
-
type: "button",
|
|
3669
|
-
className: "dcu-wb-more",
|
|
3670
|
-
"aria-label": t("workspace.manageGroups"),
|
|
3671
|
-
title: t("workspace.manageGroups"),
|
|
3672
|
-
onClick: (event) => {
|
|
3673
|
-
event.stopPropagation();
|
|
3674
|
-
setGroupMenuOpen((current) => !current);
|
|
3675
|
-
},
|
|
3676
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutline16, { size: 16 })
|
|
3677
|
-
})
|
|
3678
|
-
})]
|
|
3762
|
+
})
|
|
3679
3763
|
})]
|
|
3680
3764
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3681
3765
|
className: "dcu-wb-section-body",
|
|
@@ -3881,6 +3965,57 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3881
3965
|
setPinnedWorkspaceIds((ids) => togglePinnedWorkspace(ids, id));
|
|
3882
3966
|
}
|
|
3883
3967
|
}),
|
|
3968
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
3969
|
+
open: renameGroupId !== void 0,
|
|
3970
|
+
onClose: closeRenameGroup,
|
|
3971
|
+
closeLabel: t("sessions.close"),
|
|
3972
|
+
title: t("workspace.renameGroup"),
|
|
3973
|
+
footer: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3974
|
+
className: "dcu-wb-rename-actions",
|
|
3975
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
3976
|
+
variant: "outline",
|
|
3977
|
+
onClick: closeRenameGroup,
|
|
3978
|
+
children: t("sessions.cancel")
|
|
3979
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
3980
|
+
variant: "primary",
|
|
3981
|
+
disabled: renameGroupDraft.trim() === "",
|
|
3982
|
+
onClick: submitRenameGroup,
|
|
3983
|
+
children: t("sessions.save")
|
|
3984
|
+
})]
|
|
3985
|
+
}),
|
|
3986
|
+
children: [
|
|
3987
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
3988
|
+
htmlFor: "dcu-workspace-group-name",
|
|
3989
|
+
children: t("workspace.groupName")
|
|
3990
|
+
}),
|
|
3991
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3992
|
+
id: "dcu-workspace-group-name",
|
|
3993
|
+
className: "dcu-wb-rename-input",
|
|
3994
|
+
"aria-label": t("workspace.groupName"),
|
|
3995
|
+
maxLength: 80,
|
|
3996
|
+
value: renameGroupDraft,
|
|
3997
|
+
autoFocus: true,
|
|
3998
|
+
onFocus: (event) => {
|
|
3999
|
+
event.target.select();
|
|
4000
|
+
},
|
|
4001
|
+
onChange: (event) => {
|
|
4002
|
+
setRenameGroupDraft(event.target.value);
|
|
4003
|
+
setRenameGroupError(void 0);
|
|
4004
|
+
},
|
|
4005
|
+
onKeyDown: (event) => {
|
|
4006
|
+
if (event.key === "Enter" && !event.nativeEvent.isComposing && event.keyCode !== 229) {
|
|
4007
|
+
event.preventDefault();
|
|
4008
|
+
submitRenameGroup();
|
|
4009
|
+
}
|
|
4010
|
+
}
|
|
4011
|
+
}),
|
|
4012
|
+
renameGroupError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4013
|
+
className: "dcu-wb-error",
|
|
4014
|
+
role: "alert",
|
|
4015
|
+
children: t("sessions.failed", { message: renameGroupError })
|
|
4016
|
+
})
|
|
4017
|
+
]
|
|
4018
|
+
}),
|
|
3884
4019
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
3885
4020
|
open: createGroupOpen,
|
|
3886
4021
|
onClose: () => {
|
|
@@ -3918,7 +4053,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3918
4053
|
setError(void 0);
|
|
3919
4054
|
},
|
|
3920
4055
|
onKeyDown: (event) => {
|
|
3921
|
-
if (event.key === "Enter") {
|
|
4056
|
+
if (event.key === "Enter" && !event.nativeEvent.isComposing && event.keyCode !== 229) {
|
|
3922
4057
|
event.preventDefault();
|
|
3923
4058
|
submitCreateGroup();
|
|
3924
4059
|
}
|
|
@@ -6580,7 +6715,8 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
6580
6715
|
"workspace.deleteGroup": "删除分组“{name}”",
|
|
6581
6716
|
"workspace.deleteGroupAction": "删除分组",
|
|
6582
6717
|
"workspace.deleteGroupDescription": "删除分组只会将其中项目移至未分组,不会删除项目或会话。",
|
|
6583
|
-
"workspace.
|
|
6718
|
+
"workspace.groupActions": "分组“{name}”的操作",
|
|
6719
|
+
"workspace.renameGroup": "重命名分组",
|
|
6584
6720
|
"workspace.recent": "最近",
|
|
6585
6721
|
"workspace.recentEmpty": "无聊天",
|
|
6586
6722
|
"workspace.noChat": "没有聊天",
|
|
@@ -6780,7 +6916,8 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
6780
6916
|
"workspace.deleteGroup": "Delete group {name}",
|
|
6781
6917
|
"workspace.deleteGroupAction": "Delete group",
|
|
6782
6918
|
"workspace.deleteGroupDescription": "Deleting this group moves its projects to Ungrouped. It does not delete projects or conversations.",
|
|
6783
|
-
"workspace.
|
|
6919
|
+
"workspace.groupActions": "Actions for group {name}",
|
|
6920
|
+
"workspace.renameGroup": "Rename group",
|
|
6784
6921
|
"workspace.recent": "Recents",
|
|
6785
6922
|
"workspace.recentEmpty": "No chats",
|
|
6786
6923
|
"workspace.noChat": "No chats",
|
package/lib/index.mjs
CHANGED
|
@@ -1446,8 +1446,8 @@ async function moveSessionToWorkspace(services, sessionId, targetWorkspaceId, op
|
|
|
1446
1446
|
movingSessions.delete(sessionId);
|
|
1447
1447
|
}
|
|
1448
1448
|
}
|
|
1449
|
-
/**
|
|
1450
|
-
function
|
|
1449
|
+
/** 校验结构和归属;存储兼容模式保留旧 locale 下合法的大小写变体名称。 */
|
|
1450
|
+
function parseGroups(value, preserveCaseVariants) {
|
|
1451
1451
|
if (!Array.isArray(value) || value.length > 100) return void 0;
|
|
1452
1452
|
const groupIds = /* @__PURE__ */ new Set();
|
|
1453
1453
|
const groupTitles = /* @__PURE__ */ new Set();
|
|
@@ -1459,13 +1459,14 @@ function parseWorkspaceGroups(value) {
|
|
|
1459
1459
|
const id = typeof group.id === "string" ? group.id.trim() : "";
|
|
1460
1460
|
const title = typeof group.title === "string" ? group.title.trim() : "";
|
|
1461
1461
|
if (id === "" || id.length > 128 || title === "" || title.length > 80) return void 0;
|
|
1462
|
-
|
|
1462
|
+
const titleKey = preserveCaseVariants ? title : title.toLowerCase();
|
|
1463
|
+
if (groupIds.has(id) || groupTitles.has(titleKey)) return void 0;
|
|
1463
1464
|
if (!Array.isArray(group.workspaceIds) || group.workspaceIds.length > 1e3) return void 0;
|
|
1464
1465
|
const normalizedIds = [...new Set(group.workspaceIds)];
|
|
1465
1466
|
if (!normalizedIds.every((workspaceId) => typeof workspaceId === "string" && workspaceId.trim() !== "" && workspaceId.length <= 256)) return void 0;
|
|
1466
1467
|
if (normalizedIds.some((workspaceId) => workspaceIds.has(workspaceId))) return void 0;
|
|
1467
1468
|
groupIds.add(id);
|
|
1468
|
-
groupTitles.add(
|
|
1469
|
+
groupTitles.add(titleKey);
|
|
1469
1470
|
normalizedIds.forEach((workspaceId) => workspaceIds.add(workspaceId));
|
|
1470
1471
|
groups.push({
|
|
1471
1472
|
id,
|
|
@@ -1475,6 +1476,10 @@ function parseWorkspaceGroups(value) {
|
|
|
1475
1476
|
}
|
|
1476
1477
|
return groups;
|
|
1477
1478
|
}
|
|
1479
|
+
/** 旧数据可往返保存且不改名;新名称的大小写判重由创建、重命名操作执行。 */
|
|
1480
|
+
function parseStoredWorkspaceGroups(value) {
|
|
1481
|
+
return parseGroups(value, true);
|
|
1482
|
+
}
|
|
1478
1483
|
//#endregion
|
|
1479
1484
|
//#region src/workspace-preferences.ts
|
|
1480
1485
|
const WORKSPACE_PREFERENCES_FILE = ".dsh-codex-ui-preferences.json";
|
|
@@ -1499,7 +1504,7 @@ function parseWorkspacePreferences(value) {
|
|
|
1499
1504
|
workspaceGroups: []
|
|
1500
1505
|
};
|
|
1501
1506
|
if (record.version !== 2) return void 0;
|
|
1502
|
-
const workspaceGroups =
|
|
1507
|
+
const workspaceGroups = parseStoredWorkspaceGroups(record.workspaceGroups);
|
|
1503
1508
|
return workspaceGroups === void 0 ? void 0 : {
|
|
1504
1509
|
version: 2,
|
|
1505
1510
|
pinnedWorkspaceIds,
|
|
@@ -1531,7 +1536,7 @@ let writeQueue = Promise.resolve();
|
|
|
1531
1536
|
/** 串行、原子保存,避免快速拖动排序产生乱序或半截 JSON。 */
|
|
1532
1537
|
function writeWorkspacePreferences(pinnedWorkspaceIds, workspaceGroups = [], path = workspacePreferencesPath()) {
|
|
1533
1538
|
const normalized = parsePinnedWorkspaceIds([...pinnedWorkspaceIds]);
|
|
1534
|
-
const normalizedGroups =
|
|
1539
|
+
const normalizedGroups = parseStoredWorkspaceGroups([...workspaceGroups]);
|
|
1535
1540
|
if (normalized === void 0 || normalizedGroups === void 0) return Promise.reject(/* @__PURE__ */ new Error("工作区偏好数据无效。"));
|
|
1536
1541
|
const task = writeQueue.catch(() => void 0).then(async () => {
|
|
1537
1542
|
await mkdir(dirname(path), { recursive: true });
|
|
@@ -1817,8 +1822,9 @@ function apply(ctx) {
|
|
|
1817
1822
|
const record = body !== null && typeof body === "object" ? body : void 0;
|
|
1818
1823
|
const pinnedWorkspaceIds = record === void 0 ? void 0 : parsePinnedWorkspaceIds(record.pinnedWorkspaceIds);
|
|
1819
1824
|
const existing = await readWorkspacePreferences();
|
|
1820
|
-
const workspaceGroups = record === void 0 ? void 0 : "workspaceGroups" in record ?
|
|
1821
|
-
|
|
1825
|
+
const workspaceGroups = record === void 0 ? void 0 : "workspaceGroups" in record ? parseStoredWorkspaceGroups(record.workspaceGroups) : existing.workspaceGroups;
|
|
1826
|
+
const introducesTitleConflict = workspaceGroups?.some((group) => !existing.workspaceGroups.some((previous) => previous.id === group.id && previous.title === group.title) && workspaceGroups.some((other) => other.id !== group.id && other.title.toLowerCase() === group.title.toLowerCase())) === true;
|
|
1827
|
+
if (pinnedWorkspaceIds === void 0 || workspaceGroups === void 0 || introducesTitleConflict) {
|
|
1822
1828
|
response.writeHead(400, {
|
|
1823
1829
|
"content-type": "application/json; charset=utf-8",
|
|
1824
1830
|
"cache-control": "no-store"
|