@michengai/dsh-codex-ui 1.1.11 → 1.1.13
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 +50 -0
- package/CHANGELOG.zh-CN.md +50 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/lib/client.js +759 -214
- package/lib/session-title-plugin.mjs +12 -0
- package/lib/usage-frame.css +1 -1
- package/lib/usage-frame.js +98 -98
- package/package.json +37 -37
package/lib/client.js
CHANGED
|
@@ -8,11 +8,167 @@ window.__ModuleLoader__.load({
|
|
|
8
8
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
9
9
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
10
10
|
let react_dom = require("react-dom");
|
|
11
|
+
//#region src/client/session-host.ts
|
|
12
|
+
var UnknownSessionError = class extends Error {
|
|
13
|
+
constructor() {
|
|
14
|
+
super("unknown session");
|
|
15
|
+
this.name = "UnknownSessionError";
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
/** 旧宿主读 list.current;alpha.2 主视图改由 retainedBy.mainView 标记。 */
|
|
19
|
+
function currentSessionId(state) {
|
|
20
|
+
if (state === void 0) return void 0;
|
|
21
|
+
if (typeof state.current === "string" && state.current !== "") return state.current;
|
|
22
|
+
const byId = state.byId ?? {};
|
|
23
|
+
const ids = Array.isArray(state.ids) && state.ids.length > 0 ? state.ids : Object.keys(byId);
|
|
24
|
+
const pick = (id, row) => {
|
|
25
|
+
if (row === void 0 || (row.retainedBy?.mainView ?? 0) <= 0) return void 0;
|
|
26
|
+
const explicit = row.id?.trim();
|
|
27
|
+
return explicit !== void 0 && explicit !== "" ? explicit : id;
|
|
28
|
+
};
|
|
29
|
+
for (const id of ids) {
|
|
30
|
+
const found = pick(id, byId[id]);
|
|
31
|
+
if (found !== void 0) return found;
|
|
32
|
+
}
|
|
33
|
+
for (const id of Object.keys(byId)) {
|
|
34
|
+
if (ids.includes(id)) continue;
|
|
35
|
+
const found = pick(id, byId[id]);
|
|
36
|
+
if (found !== void 0) return found;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** 官方树在全局面板打开时取消会话选中。 */
|
|
40
|
+
function visibleSelectedSessionId(state, panelActive = false) {
|
|
41
|
+
return panelActive ? void 0 : currentSessionId(state);
|
|
42
|
+
}
|
|
43
|
+
function sessionRowUnread(localUnread, status, selected = false) {
|
|
44
|
+
return localUnread || status?.completionUnread === true && !selected;
|
|
45
|
+
}
|
|
46
|
+
function sessionRunningFlags(byId, status) {
|
|
47
|
+
const ids = new Set(Object.keys(byId));
|
|
48
|
+
if (status !== void 0) for (const id of status.keys()) ids.add(id);
|
|
49
|
+
const next = {};
|
|
50
|
+
for (const id of ids) next[id] = sessionIsRunning(byId[id], status?.get(id));
|
|
51
|
+
return next;
|
|
52
|
+
}
|
|
53
|
+
/** 旧宿主看 current 是否空会话;alpha.2 看主视图 retain 的 blank。 */
|
|
54
|
+
function isBlankOnboardingSession(state) {
|
|
55
|
+
if (state?.phase !== "ready") return false;
|
|
56
|
+
const id = currentSessionId(state);
|
|
57
|
+
return id === void 0 || state.byId?.[id]?.blank === true;
|
|
58
|
+
}
|
|
59
|
+
function hostAccess(ctx) {
|
|
60
|
+
return ctx;
|
|
61
|
+
}
|
|
62
|
+
/** 有 reflect 时只 probe,不能硬读未注入服务,否则 Cordis 会挡住插件激活。 */
|
|
63
|
+
function probeService(ctx, name) {
|
|
64
|
+
if (ctx === void 0) return void 0;
|
|
65
|
+
const access = hostAccess(ctx);
|
|
66
|
+
const reflectGet = access.reflect?.get;
|
|
67
|
+
const hasReflect = typeof reflectGet === "function";
|
|
68
|
+
if (hasReflect) try {
|
|
69
|
+
const found = reflectGet.call(access.reflect, name);
|
|
70
|
+
if (found !== void 0) return found;
|
|
71
|
+
} catch {}
|
|
72
|
+
if (typeof access.get === "function") try {
|
|
73
|
+
const found = access.get(name);
|
|
74
|
+
if (found !== void 0) return found;
|
|
75
|
+
} catch {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (hasReflect) return void 0;
|
|
79
|
+
try {
|
|
80
|
+
return access[name];
|
|
81
|
+
} catch {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function openHostSession(ctx, id) {
|
|
86
|
+
if (id === "") return false;
|
|
87
|
+
const access = hostAccess(ctx);
|
|
88
|
+
const uiWorkspace = probeService(access, "uiWorkspace");
|
|
89
|
+
if (typeof uiWorkspace?.openSession === "function") {
|
|
90
|
+
uiWorkspace.openSession(id);
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
if (typeof access.sessions?.retain === "function") return false;
|
|
94
|
+
if (typeof access.sessions?.open === "function") {
|
|
95
|
+
access.sessions.open(id);
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
async function withSessionBinding(sessions, sessionId, operation) {
|
|
101
|
+
const host = sessions === void 0 ? void 0 : hostAccess({ sessions }).sessions;
|
|
102
|
+
if (host === void 0) throw new UnknownSessionError();
|
|
103
|
+
if (typeof host.using === "function") return host.using(sessionId, { source: "controllerOperation" }, async (reference) => {
|
|
104
|
+
if (reference.ready !== void 0) await reference.ready;
|
|
105
|
+
if (reference.binding === void 0) throw new UnknownSessionError();
|
|
106
|
+
return operation(reference.binding);
|
|
107
|
+
});
|
|
108
|
+
const existing = host.binding?.(sessionId);
|
|
109
|
+
if (existing !== void 0) return operation(existing);
|
|
110
|
+
if (typeof host.retain !== "function") throw new UnknownSessionError();
|
|
111
|
+
const reference = host.retain(sessionId, { source: "controllerOperation" });
|
|
112
|
+
try {
|
|
113
|
+
if (reference.ready !== void 0) await reference.ready;
|
|
114
|
+
if (reference.binding === void 0) throw new UnknownSessionError();
|
|
115
|
+
return await operation(reference.binding);
|
|
116
|
+
} finally {
|
|
117
|
+
reference.release?.();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
async function renameHostSession(ctx, sessionId, title) {
|
|
121
|
+
await withSessionBinding(hostAccess(ctx).sessions, sessionId, async (binding) => {
|
|
122
|
+
if (typeof binding.session?.rename !== "function") throw new UnknownSessionError();
|
|
123
|
+
const result = await binding.session.rename(title);
|
|
124
|
+
if (result.ok === false) throw result.error ?? /* @__PURE__ */ new Error("rename failed");
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
async function forkHostSession(ctx, sessionId) {
|
|
128
|
+
const access = hostAccess(ctx);
|
|
129
|
+
const uiWorkspace = probeService(access, "uiWorkspace");
|
|
130
|
+
if (typeof uiWorkspace?.forkSession === "function") {
|
|
131
|
+
await uiWorkspace.forkSession(sessionId);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const childId = await access.sessions?.fork?.({
|
|
135
|
+
sessionId,
|
|
136
|
+
increaseTitle: true
|
|
137
|
+
});
|
|
138
|
+
if (typeof childId === "string" && childId !== "") openHostSession(access, childId);
|
|
139
|
+
}
|
|
140
|
+
async function archiveHostSession(ctx, sessionId) {
|
|
141
|
+
const access = hostAccess(ctx);
|
|
142
|
+
const uiWorkspace = probeService(access, "uiWorkspace");
|
|
143
|
+
if (typeof uiWorkspace?.archiveSession === "function") {
|
|
144
|
+
await uiWorkspace.archiveSession(sessionId);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
await access.workspaces?.archiveSession?.(sessionId);
|
|
148
|
+
}
|
|
149
|
+
function mergePendingInteractions(legacy, status) {
|
|
150
|
+
const next = new Map(legacy);
|
|
151
|
+
for (const [id, row] of status) if (row?.pendingInteraction !== void 0) next.set(id, row.pendingInteraction);
|
|
152
|
+
return next;
|
|
153
|
+
}
|
|
154
|
+
function sessionIsRunning(session, status) {
|
|
155
|
+
if (status?.running !== void 0) return status.running === true;
|
|
156
|
+
return session?.running === true;
|
|
157
|
+
}
|
|
158
|
+
//#endregion
|
|
11
159
|
//#region src/client/session-navigation.ts
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
160
|
+
function openConversation(host, layout, id) {
|
|
161
|
+
const opened = openHostSession(host, id);
|
|
162
|
+
if (opened) selectGlobalPanel(layout, null);
|
|
163
|
+
return opened;
|
|
164
|
+
}
|
|
165
|
+
/** 先打开再写草稿,避免 using 释放后 composer 换新 binding。 */
|
|
166
|
+
async function openConversationWithDraft(host, layout, sessions, sessionId, writeDraft) {
|
|
167
|
+
return withSessionBinding(sessions, sessionId, (binding) => {
|
|
168
|
+
const opened = openConversation(host, layout, sessionId);
|
|
169
|
+
writeDraft(binding);
|
|
170
|
+
return opened;
|
|
171
|
+
});
|
|
16
172
|
}
|
|
17
173
|
/** 统一检测旧宿主是否提供面板切换能力,保留宿主方法的 this。 */
|
|
18
174
|
function selectGlobalPanel(layout, id) {
|
|
@@ -720,17 +876,112 @@ window.__ModuleLoader__.load({
|
|
|
720
876
|
key: "17ys0d"
|
|
721
877
|
}]]);
|
|
722
878
|
//#endregion
|
|
879
|
+
//#region src/client/settings-navigation.ts
|
|
880
|
+
/**
|
|
881
|
+
* DSH 设置壳暂未提供按 section id 打开的公开 API。该兼容层只从本插件渲染
|
|
882
|
+
* 的设置入口触发,再按壳的可访问名称选择页面;宿主升级时可集中替换。
|
|
883
|
+
*/
|
|
884
|
+
function pickSettingsSectionButton(buttons, labels) {
|
|
885
|
+
for (const label of labels) {
|
|
886
|
+
const match = buttons.find((button) => button.textContent?.trim() === label);
|
|
887
|
+
if (match !== void 0) return match;
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
/**
|
|
891
|
+
* 可选插件未注册设置入口时,直接打开兜底页,避免先展示通用设置并等待导航超时。
|
|
892
|
+
*/
|
|
893
|
+
function routeOptionalSettingsSection(available, openRequested, openFallback) {
|
|
894
|
+
if (available) {
|
|
895
|
+
openRequested();
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
openFallback();
|
|
899
|
+
}
|
|
900
|
+
/** 官方 alpha.2 插件管理页占用 sidebar.panellist / main 的同一 id。 */
|
|
901
|
+
const OFFICIAL_PLUGINS_PANEL_ID = "plugins";
|
|
902
|
+
let cancelPendingNavigation;
|
|
903
|
+
const SETTINGS_NAVIGATION_TIMEOUT_MS = 4e3;
|
|
904
|
+
const SETTINGS_TRIGGER_SELECTOR = "[data-dcu-settings-trigger],[aria-haspopup=\"dialog\"]";
|
|
905
|
+
const SETTINGS_OPEN_SECTION_EVENT = "dcu-settings-open-section";
|
|
906
|
+
/** 根入口与分区跳转使用同一触发器合约,兼容保留的宿主设置壳。 */
|
|
907
|
+
function openSettingsRoot(root) {
|
|
908
|
+
root?.querySelector(SETTINGS_TRIGGER_SELECTOR)?.click();
|
|
909
|
+
}
|
|
910
|
+
function openSettingsSection(root, label, onMissing, onSelected) {
|
|
911
|
+
const labels = typeof label === "string" ? [label] : label;
|
|
912
|
+
const trigger = root?.querySelector(SETTINGS_TRIGGER_SELECTOR);
|
|
913
|
+
if (trigger === null || trigger === void 0) {
|
|
914
|
+
onMissing?.();
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
const opening = cancelPendingNavigation !== void 0;
|
|
918
|
+
cancelPendingNavigation?.();
|
|
919
|
+
const request = new CustomEvent(SETTINGS_OPEN_SECTION_EVENT, {
|
|
920
|
+
detail: { labels },
|
|
921
|
+
cancelable: true
|
|
922
|
+
});
|
|
923
|
+
if (!trigger.dispatchEvent(request)) {
|
|
924
|
+
onSelected?.();
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
const pageSelector = trigger.hasAttribute("data-dcu-settings-trigger") ? "[data-dcu-settings-page]" : "[role=\"dialog\"]";
|
|
928
|
+
if (!opening && document.querySelector(pageSelector) === null) trigger.click();
|
|
929
|
+
let frame;
|
|
930
|
+
let finished = false;
|
|
931
|
+
const observer = new MutationObserver(() => {
|
|
932
|
+
schedule();
|
|
933
|
+
});
|
|
934
|
+
const cleanup = () => {
|
|
935
|
+
if (finished) return;
|
|
936
|
+
finished = true;
|
|
937
|
+
observer.disconnect();
|
|
938
|
+
window.clearTimeout(timeout);
|
|
939
|
+
if (frame !== void 0) window.cancelAnimationFrame(frame);
|
|
940
|
+
if (cancelPendingNavigation === cleanup) cancelPendingNavigation = void 0;
|
|
941
|
+
};
|
|
942
|
+
const select = () => {
|
|
943
|
+
const target = pickSettingsSectionButton([...document.querySelectorAll(`${pageSelector} nav button`)], labels);
|
|
944
|
+
if (target === void 0) return false;
|
|
945
|
+
cleanup();
|
|
946
|
+
target.click();
|
|
947
|
+
onSelected?.();
|
|
948
|
+
return true;
|
|
949
|
+
};
|
|
950
|
+
const schedule = () => {
|
|
951
|
+
if (finished || frame !== void 0) return;
|
|
952
|
+
frame = window.requestAnimationFrame(() => {
|
|
953
|
+
frame = void 0;
|
|
954
|
+
select();
|
|
955
|
+
});
|
|
956
|
+
};
|
|
957
|
+
const timeout = window.setTimeout(() => {
|
|
958
|
+
if (select()) return;
|
|
959
|
+
cleanup();
|
|
960
|
+
console.warn(`[michengai-codex-ui] 未找到设置分区:${labels.join(" / ")}`);
|
|
961
|
+
onMissing?.();
|
|
962
|
+
}, SETTINGS_NAVIGATION_TIMEOUT_MS);
|
|
963
|
+
observer.observe(document.body, {
|
|
964
|
+
childList: true,
|
|
965
|
+
subtree: true
|
|
966
|
+
});
|
|
967
|
+
cancelPendingNavigation = cleanup;
|
|
968
|
+
schedule();
|
|
969
|
+
}
|
|
970
|
+
//#endregion
|
|
723
971
|
//#region src/client/global-panels.tsx
|
|
724
972
|
/** 从宿主注册表读取面板元数据;缓存快照以满足 React 外部状态订阅契约。 */
|
|
725
973
|
function createGlobalPanelSource(slots, locale) {
|
|
726
974
|
let cached = [];
|
|
727
975
|
return {
|
|
728
976
|
getSnapshot() {
|
|
729
|
-
const next = slots.entriesOfSlot("sidebar.panellist").flatMap(({ options }) =>
|
|
730
|
-
id
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
977
|
+
const next = slots.entriesOfSlot("sidebar.panellist").flatMap(({ options }) => {
|
|
978
|
+
if (options.id === void 0 || options.id === "plugins") return [];
|
|
979
|
+
return [{
|
|
980
|
+
id: options.id,
|
|
981
|
+
order: options.order ?? 0,
|
|
982
|
+
label: (typeof options.label === "function" ? options.label() : options.label) ?? options.id
|
|
983
|
+
}];
|
|
984
|
+
}).sort((a, b) => a.order - b.order);
|
|
734
985
|
if (next.length !== cached.length || next.some((panel, index) => {
|
|
735
986
|
const previous = cached[index];
|
|
736
987
|
return previous === void 0 || panel.id !== previous.id || panel.label !== previous.label || panel.order !== previous.order;
|
|
@@ -907,96 +1158,6 @@ window.__ModuleLoader__.load({
|
|
|
907
1158
|
} catch {}
|
|
908
1159
|
}
|
|
909
1160
|
//#endregion
|
|
910
|
-
//#region src/client/settings-navigation.ts
|
|
911
|
-
/**
|
|
912
|
-
* DSH 设置壳暂未提供按 section id 打开的公开 API。该兼容层只从本插件渲染
|
|
913
|
-
* 的设置入口触发,再按壳的可访问名称选择页面;宿主升级时可集中替换。
|
|
914
|
-
*/
|
|
915
|
-
function pickSettingsSectionButton(buttons, labels) {
|
|
916
|
-
for (const label of labels) {
|
|
917
|
-
const match = buttons.find((button) => button.textContent?.trim() === label);
|
|
918
|
-
if (match !== void 0) return match;
|
|
919
|
-
}
|
|
920
|
-
}
|
|
921
|
-
/**
|
|
922
|
-
* 可选插件未注册设置入口时,直接打开兜底页,避免先展示通用设置并等待导航超时。
|
|
923
|
-
*/
|
|
924
|
-
function routeOptionalSettingsSection(available, openRequested, openFallback) {
|
|
925
|
-
if (available) {
|
|
926
|
-
openRequested();
|
|
927
|
-
return;
|
|
928
|
-
}
|
|
929
|
-
openFallback();
|
|
930
|
-
}
|
|
931
|
-
let cancelPendingNavigation;
|
|
932
|
-
const SETTINGS_NAVIGATION_TIMEOUT_MS = 4e3;
|
|
933
|
-
const SETTINGS_TRIGGER_SELECTOR = "[data-dcu-settings-trigger],[aria-haspopup=\"dialog\"]";
|
|
934
|
-
const SETTINGS_OPEN_SECTION_EVENT = "dcu-settings-open-section";
|
|
935
|
-
/** 根入口与分区跳转使用同一触发器合约,兼容保留的宿主设置壳。 */
|
|
936
|
-
function openSettingsRoot(root) {
|
|
937
|
-
root?.querySelector(SETTINGS_TRIGGER_SELECTOR)?.click();
|
|
938
|
-
}
|
|
939
|
-
function openSettingsSection(root, label, onMissing, onSelected) {
|
|
940
|
-
const labels = typeof label === "string" ? [label] : label;
|
|
941
|
-
const trigger = root?.querySelector(SETTINGS_TRIGGER_SELECTOR);
|
|
942
|
-
if (trigger === null || trigger === void 0) {
|
|
943
|
-
onMissing?.();
|
|
944
|
-
return;
|
|
945
|
-
}
|
|
946
|
-
const opening = cancelPendingNavigation !== void 0;
|
|
947
|
-
cancelPendingNavigation?.();
|
|
948
|
-
const request = new CustomEvent(SETTINGS_OPEN_SECTION_EVENT, {
|
|
949
|
-
detail: { labels },
|
|
950
|
-
cancelable: true
|
|
951
|
-
});
|
|
952
|
-
if (!trigger.dispatchEvent(request)) {
|
|
953
|
-
onSelected?.();
|
|
954
|
-
return;
|
|
955
|
-
}
|
|
956
|
-
const pageSelector = trigger.hasAttribute("data-dcu-settings-trigger") ? "[data-dcu-settings-page]" : "[role=\"dialog\"]";
|
|
957
|
-
if (!opening && document.querySelector(pageSelector) === null) trigger.click();
|
|
958
|
-
let frame;
|
|
959
|
-
let finished = false;
|
|
960
|
-
const observer = new MutationObserver(() => {
|
|
961
|
-
schedule();
|
|
962
|
-
});
|
|
963
|
-
const cleanup = () => {
|
|
964
|
-
if (finished) return;
|
|
965
|
-
finished = true;
|
|
966
|
-
observer.disconnect();
|
|
967
|
-
window.clearTimeout(timeout);
|
|
968
|
-
if (frame !== void 0) window.cancelAnimationFrame(frame);
|
|
969
|
-
if (cancelPendingNavigation === cleanup) cancelPendingNavigation = void 0;
|
|
970
|
-
};
|
|
971
|
-
const select = () => {
|
|
972
|
-
const target = pickSettingsSectionButton([...document.querySelectorAll(`${pageSelector} nav button`)], labels);
|
|
973
|
-
if (target === void 0) return false;
|
|
974
|
-
cleanup();
|
|
975
|
-
target.click();
|
|
976
|
-
onSelected?.();
|
|
977
|
-
return true;
|
|
978
|
-
};
|
|
979
|
-
const schedule = () => {
|
|
980
|
-
if (finished || frame !== void 0) return;
|
|
981
|
-
frame = window.requestAnimationFrame(() => {
|
|
982
|
-
frame = void 0;
|
|
983
|
-
select();
|
|
984
|
-
});
|
|
985
|
-
};
|
|
986
|
-
const timeout = window.setTimeout(() => {
|
|
987
|
-
if (select()) return;
|
|
988
|
-
cleanup();
|
|
989
|
-
console.warn(`[michengai-codex-ui] 未找到设置分区:${labels.join(" / ")}`);
|
|
990
|
-
onMissing?.();
|
|
991
|
-
}, SETTINGS_NAVIGATION_TIMEOUT_MS);
|
|
992
|
-
observer.observe(document.body, {
|
|
993
|
-
childList: true,
|
|
994
|
-
subtree: true
|
|
995
|
-
});
|
|
996
|
-
cancelPendingNavigation = cleanup;
|
|
997
|
-
schedule();
|
|
998
|
-
}
|
|
999
|
-
//#endregion
|
|
1000
1161
|
//#region src/client/sidebar-search.ts
|
|
1001
1162
|
/** 按用户可见名称和辅助关键词筛选侧栏搜索结果。 */
|
|
1002
1163
|
function filterSidebarSearchItems(items, query) {
|
|
@@ -1246,6 +1407,23 @@ window.__ModuleLoader__.load({
|
|
|
1246
1407
|
return parseChannelGroups(payload, fallbackLabel);
|
|
1247
1408
|
}
|
|
1248
1409
|
//#endregion
|
|
1410
|
+
//#region src/client/session-title-scroll.ts
|
|
1411
|
+
/** 会话行只展示标题第一行,避免换行把胶囊撑高。 */
|
|
1412
|
+
function sessionTitleLine(title) {
|
|
1413
|
+
return title.split(/\r?\n/)[0] ?? title;
|
|
1414
|
+
}
|
|
1415
|
+
/** 标题比可视槽多出来的像素;1px 内当作测量误差。 */
|
|
1416
|
+
function titleOverflowPx(scrollWidth, clientWidth) {
|
|
1417
|
+
const extra = Math.ceil(scrollWidth - clientWidth);
|
|
1418
|
+
return extra > 1 ? extra : 0;
|
|
1419
|
+
}
|
|
1420
|
+
const PX_PER_SECOND = 42;
|
|
1421
|
+
/** 按溢出长度估算单程时长,长标题更慢,避免一闪而过。 */
|
|
1422
|
+
function titleScrollDurationMs(overflowPx) {
|
|
1423
|
+
if (overflowPx <= 0) return 0;
|
|
1424
|
+
return Math.min(8e3, Math.max(1600, Math.round(overflowPx / PX_PER_SECOND * 1e3)));
|
|
1425
|
+
}
|
|
1426
|
+
//#endregion
|
|
1249
1427
|
//#region src/client/session-tree.tsx
|
|
1250
1428
|
function PinIcon() {
|
|
1251
1429
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Pin, {
|
|
@@ -1416,7 +1594,58 @@ window.__ModuleLoader__.load({
|
|
|
1416
1594
|
});
|
|
1417
1595
|
return null;
|
|
1418
1596
|
}
|
|
1419
|
-
function
|
|
1597
|
+
function SessionTime({ time }) {
|
|
1598
|
+
if (time === void 0 || time === "") return null;
|
|
1599
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1600
|
+
className: "dcu-wb-session-time",
|
|
1601
|
+
children: time
|
|
1602
|
+
});
|
|
1603
|
+
}
|
|
1604
|
+
function SessionRowTitle({ title }) {
|
|
1605
|
+
const text = sessionTitleLine(title);
|
|
1606
|
+
const wrapRef = (0, react.useRef)(null);
|
|
1607
|
+
const textRef = (0, react.useRef)(null);
|
|
1608
|
+
const [shift, setShift] = (0, react.useState)(0);
|
|
1609
|
+
(0, react.useLayoutEffect)(() => {
|
|
1610
|
+
const wrap = wrapRef.current;
|
|
1611
|
+
const inner = textRef.current;
|
|
1612
|
+
if (wrap === null || inner === null) return;
|
|
1613
|
+
const measure = () => {
|
|
1614
|
+
setShift(titleOverflowPx(inner.scrollWidth, wrap.clientWidth));
|
|
1615
|
+
};
|
|
1616
|
+
measure();
|
|
1617
|
+
let cancelled = false;
|
|
1618
|
+
const fonts = typeof document === "undefined" ? void 0 : document.fonts;
|
|
1619
|
+
if (fonts !== void 0) fonts.ready.then(() => {
|
|
1620
|
+
if (!cancelled) measure();
|
|
1621
|
+
});
|
|
1622
|
+
if (typeof ResizeObserver === "undefined") return () => {
|
|
1623
|
+
cancelled = true;
|
|
1624
|
+
};
|
|
1625
|
+
const observer = new ResizeObserver(measure);
|
|
1626
|
+
observer.observe(wrap);
|
|
1627
|
+
return () => {
|
|
1628
|
+
cancelled = true;
|
|
1629
|
+
observer.disconnect();
|
|
1630
|
+
};
|
|
1631
|
+
}, [text]);
|
|
1632
|
+
const style = shift > 0 ? {
|
|
1633
|
+
"--dcu-title-shift": `${shift}px`,
|
|
1634
|
+
"--dcu-title-duration": `${titleScrollDurationMs(shift)}ms`
|
|
1635
|
+
} : void 0;
|
|
1636
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1637
|
+
ref: wrapRef,
|
|
1638
|
+
className: "dcu-wb-session-title",
|
|
1639
|
+
"data-overflow": shift > 0 || void 0,
|
|
1640
|
+
style,
|
|
1641
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1642
|
+
ref: textRef,
|
|
1643
|
+
className: "dcu-wb-session-title-text",
|
|
1644
|
+
children: text
|
|
1645
|
+
})
|
|
1646
|
+
});
|
|
1647
|
+
}
|
|
1648
|
+
function SessionRow({ id, title, selected, menuOpen, unread, running, pendingInteraction, t, menuItems, onOpen, onMenuChange, onSelectAction, onArchive, onHover, onLeave, onContextMenu, menuPoint, subtitle, flat, draggable, dropActive, onDragStart, onDragEnd, onDragOver, onDrop, time }) {
|
|
1420
1649
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1421
1650
|
"data-dcu-session": id,
|
|
1422
1651
|
className: `dcu-wb-session${selected ? " dcu-wb-selected" : ""}${menuOpen ? " dcu-wb-menu-open" : ""}${dropActive === true ? " dcu-wb-drop" : ""}${flat === true ? " dcu-wb-session-flat" : ""}`,
|
|
@@ -1434,23 +1663,18 @@ window.__ModuleLoader__.load({
|
|
|
1434
1663
|
children: [
|
|
1435
1664
|
subtitle !== void 0 && subtitle !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1436
1665
|
className: "dcu-wb-session-copy",
|
|
1437
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1438
|
-
className: "dcu-wb-session-title",
|
|
1439
|
-
children: title.split(/\r?\n/)[0] ?? title
|
|
1440
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1666
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionRowTitle, { title }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1441
1667
|
className: "dcu-wb-session-sub",
|
|
1442
1668
|
children: subtitle
|
|
1443
1669
|
})]
|
|
1444
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
1445
|
-
className: "dcu-wb-session-title",
|
|
1446
|
-
children: title.split(/\r?\n/)[0] ?? title
|
|
1447
|
-
}),
|
|
1670
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionRowTitle, { title }),
|
|
1448
1671
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionState, {
|
|
1449
1672
|
pendingInteraction,
|
|
1450
1673
|
unread,
|
|
1451
1674
|
running,
|
|
1452
1675
|
t
|
|
1453
1676
|
}),
|
|
1677
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionTime, { time }),
|
|
1454
1678
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1455
1679
|
className: "dcu-wb-quick-actions",
|
|
1456
1680
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
@@ -1524,9 +1748,20 @@ window.__ModuleLoader__.load({
|
|
|
1524
1748
|
//#endregion
|
|
1525
1749
|
//#region src/client/session-pending.ts
|
|
1526
1750
|
const EMPTY_PENDING_INTERACTIONS = /* @__PURE__ */ new Map();
|
|
1751
|
+
const EMPTY_SESSION_STATUS = /* @__PURE__ */ new Map();
|
|
1527
1752
|
function useEmptySessionPendingInteraction(selector) {
|
|
1528
1753
|
return selector(EMPTY_PENDING_INTERACTIONS);
|
|
1529
1754
|
}
|
|
1755
|
+
function useEmptySessionStatus(selector) {
|
|
1756
|
+
return selector(EMPTY_SESSION_STATUS);
|
|
1757
|
+
}
|
|
1758
|
+
function useHostSessionStatus(useSessionStatus) {
|
|
1759
|
+
return (useSessionStatus ?? useEmptySessionStatus)((state) => state);
|
|
1760
|
+
}
|
|
1761
|
+
/** 旧宿主订阅 pending Store;alpha.2 改走 useSessionStatus。两路都要订阅,避免条件 Hook。 */
|
|
1762
|
+
function useHostPendingInteractions(useSessionPendingInteraction, useSessionStatus) {
|
|
1763
|
+
return mergePendingInteractions((useSessionPendingInteraction ?? useEmptySessionPendingInteraction)((state) => state), (useSessionStatus ?? useEmptySessionStatus)((state) => state));
|
|
1764
|
+
}
|
|
1530
1765
|
function visiblePendingKind(kind) {
|
|
1531
1766
|
switch (kind) {
|
|
1532
1767
|
case "approval":
|
|
@@ -1915,13 +2150,84 @@ window.__ModuleLoader__.load({
|
|
|
1915
2150
|
top: rect.top
|
|
1916
2151
|
};
|
|
1917
2152
|
}
|
|
1918
|
-
|
|
2153
|
+
const HOUR = 3600;
|
|
2154
|
+
const DAY = HOUR * 24;
|
|
2155
|
+
const WEEK = DAY * 7;
|
|
2156
|
+
const MONTH = DAY * 30;
|
|
2157
|
+
const YEAR = DAY * 365;
|
|
2158
|
+
function formatRelativeTime(updatedAt, t, now, justNow) {
|
|
2159
|
+
const seconds = Math.max(0, Math.floor((now - updatedAt) / 1e3));
|
|
2160
|
+
if (seconds < 60) return t(justNow);
|
|
2161
|
+
if (seconds < HOUR) return t("time.minutes", { count: Math.floor(seconds / 60) });
|
|
2162
|
+
if (seconds < DAY) return t("time.hours", { count: Math.floor(seconds / HOUR) });
|
|
2163
|
+
if (seconds < WEEK) return t("time.days", { count: Math.floor(seconds / DAY) });
|
|
2164
|
+
if (seconds < MONTH) return t("time.weeks", { count: Math.floor(seconds / WEEK) });
|
|
2165
|
+
if (seconds < YEAR) return t("time.months", { count: Math.floor(seconds / MONTH) });
|
|
2166
|
+
return t("time.years", { count: Math.floor(seconds / YEAR) });
|
|
2167
|
+
}
|
|
2168
|
+
/** 悬停卡片右上角。分档与 ChatGPT `$wa` 一致;英文刚刚用 Just now。 */
|
|
1919
2169
|
function formatHoverTime(updatedAt, t, now = Date.now()) {
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
return
|
|
2170
|
+
return formatRelativeTime(updatedAt, t, now, "time.justNow");
|
|
2171
|
+
}
|
|
2172
|
+
/** 会话行右侧。分档相同;英文刚刚用 now,避免挤占标题。 */
|
|
2173
|
+
function formatCompactTime(updatedAt, t, now = Date.now()) {
|
|
2174
|
+
return formatRelativeTime(updatedAt, t, now, "time.justNowShort");
|
|
2175
|
+
}
|
|
2176
|
+
//#endregion
|
|
2177
|
+
//#region src/client/shared-now.ts
|
|
2178
|
+
const SHARED_NOW_INTERVAL_MS = 6e4;
|
|
2179
|
+
/** 对齐到下一个整档,避免「刚刚」在整分钟边界之后还多停将近一轮。 */
|
|
2180
|
+
function msUntilNextNowTick(now, intervalMs = SHARED_NOW_INTERVAL_MS) {
|
|
2181
|
+
const remainder = now % intervalMs;
|
|
2182
|
+
return remainder === 0 ? intervalMs : intervalMs - remainder;
|
|
2183
|
+
}
|
|
2184
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
2185
|
+
let sharedNow = Date.now();
|
|
2186
|
+
let timeoutId = 0;
|
|
2187
|
+
let intervalId = 0;
|
|
2188
|
+
let cancelled = true;
|
|
2189
|
+
function publish(now) {
|
|
2190
|
+
sharedNow = now;
|
|
2191
|
+
for (const listener of listeners) listener();
|
|
2192
|
+
}
|
|
2193
|
+
function startClock() {
|
|
2194
|
+
cancelled = false;
|
|
2195
|
+
timeoutId = window.setTimeout(() => {
|
|
2196
|
+
if (cancelled) return;
|
|
2197
|
+
publish(Date.now());
|
|
2198
|
+
intervalId = window.setInterval(() => {
|
|
2199
|
+
publish(Date.now());
|
|
2200
|
+
}, SHARED_NOW_INTERVAL_MS);
|
|
2201
|
+
if (cancelled) {
|
|
2202
|
+
window.clearInterval(intervalId);
|
|
2203
|
+
intervalId = 0;
|
|
2204
|
+
}
|
|
2205
|
+
}, msUntilNextNowTick(Date.now()));
|
|
2206
|
+
}
|
|
2207
|
+
function stopClock() {
|
|
2208
|
+
cancelled = true;
|
|
2209
|
+
window.clearTimeout(timeoutId);
|
|
2210
|
+
window.clearInterval(intervalId);
|
|
2211
|
+
timeoutId = 0;
|
|
2212
|
+
intervalId = 0;
|
|
2213
|
+
}
|
|
2214
|
+
function subscribe(listener) {
|
|
2215
|
+
if (listeners.size === 0) {
|
|
2216
|
+
sharedNow = Date.now();
|
|
2217
|
+
startClock();
|
|
2218
|
+
}
|
|
2219
|
+
listeners.add(listener);
|
|
2220
|
+
return () => {
|
|
2221
|
+
listeners.delete(listener);
|
|
2222
|
+
if (listeners.size === 0) stopClock();
|
|
2223
|
+
};
|
|
2224
|
+
}
|
|
2225
|
+
function getSnapshot() {
|
|
2226
|
+
return sharedNow;
|
|
2227
|
+
}
|
|
2228
|
+
/** 模块级当前时刻。几棵树挂着都只走一套定时器,每分钟刷新一次。 */
|
|
2229
|
+
function useSharedNow() {
|
|
2230
|
+
return (0, react.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
1925
2231
|
}
|
|
1926
2232
|
//#endregion
|
|
1927
2233
|
//#region src/client/conversation-bubbles.ts
|
|
@@ -2595,6 +2901,9 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2595
2901
|
function hasConnectWorkspace(value) {
|
|
2596
2902
|
return value !== null && typeof value === "object" && "connectWorkspace" in value && typeof value.connectWorkspace === "function";
|
|
2597
2903
|
}
|
|
2904
|
+
function hasOpenWorkspace(value) {
|
|
2905
|
+
return value !== null && typeof value === "object" && "openWorkspace" in value && typeof value.openWorkspace === "function";
|
|
2906
|
+
}
|
|
2598
2907
|
/** 与 DSH 官方最近工作区策略一致;时间相同时保留 Host 工作区顺序。 */
|
|
2599
2908
|
function recentWorkspaceId(workspaces, sessions) {
|
|
2600
2909
|
let selected;
|
|
@@ -2829,10 +3138,23 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2829
3138
|
lower = after ? rows[index + 1]?.rect.top : edge.rect.top;
|
|
2830
3139
|
} else if (target.matches(".dcu-wb-pin-start,.dcu-wb-pin-end")) {
|
|
2831
3140
|
if (anchor.width <= 0 || anchor.height <= 0) return void 0;
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
3141
|
+
const itemRows = rows.filter((row) => !row.node.matches(".dcu-wb-section-head,.dcu-wb-empty,.dcu-wb-nochat"));
|
|
3142
|
+
if (target.matches(".dcu-wb-pin-end") && itemRows.length > 0) {
|
|
3143
|
+
const last = itemRows[itemRows.length - 1];
|
|
3144
|
+
anchor = last.rect;
|
|
3145
|
+
upper = last.rect.bottom;
|
|
3146
|
+
lower = rows.find((row) => row.rect.top >= last.rect.bottom - .5)?.rect.top;
|
|
3147
|
+
} else if (target.matches(".dcu-wb-pin-start") && itemRows.length > 0) {
|
|
3148
|
+
const first = itemRows[0];
|
|
3149
|
+
anchor = first.rect;
|
|
3150
|
+
lower = first.rect.top;
|
|
3151
|
+
upper = rows.filter((row) => row.rect.bottom <= first.rect.top + .5).at(-1)?.rect.bottom;
|
|
3152
|
+
} else {
|
|
3153
|
+
upper = rows.filter((row) => row.rect.bottom <= anchor.top).at(-1)?.rect.bottom;
|
|
3154
|
+
lower = rows.find((row) => row.rect.top >= anchor.bottom)?.rect.top;
|
|
3155
|
+
if (lower === void 0) lower = anchor.bottom;
|
|
3156
|
+
if (upper === void 0) upper = anchor.top;
|
|
3157
|
+
}
|
|
2836
3158
|
} else return void 0;
|
|
2837
3159
|
const center = upper === void 0 ? lower - 4 : lower === void 0 ? upper + 4 : (upper + lower) / 2;
|
|
2838
3160
|
const box = root.getBoundingClientRect();
|
|
@@ -2901,7 +3223,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2901
3223
|
}
|
|
2902
3224
|
const previewTitle = document.createElement("span");
|
|
2903
3225
|
previewTitle.className = "dcu-wb-drag-ghost-title";
|
|
2904
|
-
previewTitle.textContent = title
|
|
3226
|
+
previewTitle.textContent = sessionTitleLine(title);
|
|
2905
3227
|
preview.appendChild(previewTitle);
|
|
2906
3228
|
document.body.appendChild(preview);
|
|
2907
3229
|
preview.offsetWidth;
|
|
@@ -3011,16 +3333,16 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3011
3333
|
.dcu-wb-project-head:hover,.dcu-wb-project-head.dcu-wb-menu-open,.dcu-wb-session:hover,.dcu-wb-session.dcu-wb-selected,.dcu-wb-session.dcu-wb-menu-open{background:var(--dcu-sidebar-hover)}.dcu-wb-project.dcu-wb-session-drop>.dcu-wb-project-head{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}.dcu-wb-project.dcu-wb-session-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}.dcu-wb-project.dcu-wb-session-move-drop>.dcu-wb-project-head{background:transparent;outline:0}.dcu-wb-project-body>.dcu-wb-session:first-child,.dcu-wb-project-body>.dcu-wb-nochat:first-child{margin-top:4px}.dcu-wb-session+.dcu-wb-session{margin-top:2px}
|
|
3012
3334
|
.dcu-wb-project-head[draggable=true],.dcu-wb-session[draggable=true]{cursor:grab}
|
|
3013
3335
|
.dcu-wb-project-head[draggable=true]:active,.dcu-wb-session[draggable=true]:active{cursor:grabbing}
|
|
3014
|
-
.dcu-wb-section,.dcu-wb-section:focus,.dcu-wb-section:focus-visible,.dcu-wb-project-head:focus,.dcu-wb-session:focus{outline:0}.dcu-wb-pin-end,.dcu-wb-pin-start{position:
|
|
3336
|
+
.dcu-wb-section,.dcu-wb-section:focus,.dcu-wb-section:focus-visible,.dcu-wb-project-head:focus,.dcu-wb-session:focus{outline:0}.dcu-wb-pinned-list{position:relative}.dcu-wb-pin-end,.dcu-wb-pin-start{position:absolute;left:0;right:0;height:8px;z-index:2;pointer-events:none}.dcu-wb-pin-end.dcu-wb-drop,.dcu-wb-pin-start.dcu-wb-drop{pointer-events:auto}.dcu-wb-pin-start{top:0}.dcu-wb-pin-end{bottom:-8px}.dcu-wb-project.dcu-wb-drop::before,.dcu-wb-session.dcu-wb-drop::before,.dcu-wb-pin-end.dcu-wb-drop::before,.dcu-wb-pin-start.dcu-wb-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-pin-start.dcu-wb-drop::before{top:0}.dcu-wb-pinned-list>.dcu-wb-project:first-child.dcu-wb-drop::before{top:-4px}.dcu-wb-project.dcu-wb-drop-after::before,.dcu-wb-session.dcu-wb-drop-after::before{top:auto;bottom:-8px}.dcu-wb-dragging{opacity:.28}.dcu-wb-drag-ghost{position:fixed;top:8px;left:-9999px;z-index:10040;display:flex;align-items:center;gap:8px;max-width:220px;height:30px;padding:0 10px;border:1px solid var(--dcu-sidebar-border);border-radius:8px;background:var(--dcu-sidebar-hover);box-shadow:0 4px 12px rgba(0,0,0,.24);color:var(--dcu-sidebar-primary);font:14px/20px var(--dcu-font,inherit);white-space:nowrap;pointer-events:none}.dcu-wb-drag-ghost-icon{display:grid;place-items:center;flex:none;width:16px;height:16px;color:var(--dcu-sidebar-icon)}.dcu-wb-drag-ghost-icon svg{display:block;width:16px;height:16px}.dcu-wb-drag-ghost-title{min-width:0;overflow:hidden;text-overflow:ellipsis}
|
|
3015
3337
|
.dcu-wb-folder{display:grid;place-items:center;flex:none;width:16px;height:20px;color:var(--dcu-sidebar-icon)}.dcu-wb-folder.dcu-wb-folder-current{color:var(--dsw-alias-state-business-primary)}.dcu-wb-brand{display:block;width:16px;height:16px}
|
|
3016
3338
|
.dcu-wb-project-title,.dcu-wb-session-title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;line-height:20px}
|
|
3017
3339
|
.dcu-wb-project-title{flex:1;font-weight:400;color:var(--dcu-sidebar-primary)}
|
|
3018
3340
|
.dcu-wb-session{position:relative;min-width:0;min-height:30px;gap:0;overflow:hidden;padding-left:30px;padding-right:28px}
|
|
3019
|
-
.dcu-wb-session-title{flex:1;margin-left:0}.dcu-wb-session-copy{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center}.dcu-wb-session-sub{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dcu-sidebar-tertiary);font-size:12px;line-height:16px}.dcu-wb-session-flat,.dcu-wb-session-top{padding-left:8px}.dcu-wb-session-flat:has(.dcu-wb-running),.dcu-wb-session-top:has(.dcu-wb-running){padding-left:30px}
|
|
3341
|
+
.dcu-wb-session-title{flex:1;margin-left:0}.dcu-wb-session-title-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@media (prefers-reduced-motion:no-preference){.dcu-wb-session:hover .dcu-wb-session-title[data-overflow] .dcu-wb-session-title-text,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-session-title[data-overflow] .dcu-wb-session-title-text{display:inline-block;width:max-content;max-width:none;overflow:visible;text-overflow:clip;animation:dcu-wb-title-scroll var(--dcu-title-duration,2.4s) linear 320ms infinite alternate}}@keyframes dcu-wb-title-scroll{0%,18%{transform:translateX(0)}82%,100%{transform:translateX(calc(-1 * var(--dcu-title-shift,0px)))}}.dcu-wb-session-time{position:absolute;right:8px;top:50%;transform:translateY(-50%);color:var(--dcu-sidebar-tertiary);font-size:12px;line-height:18px;font-weight:400;font-variant-numeric:tabular-nums;white-space:nowrap;pointer-events:none}.dcu-wb-session:has(.dcu-wb-session-time){padding-right:64px}.dcu-wb-session:has(.dcu-wb-unread) .dcu-wb-session-time{right:22px}.dcu-wb-session:has(.dcu-wb-unread):has(.dcu-wb-session-time){padding-right:78px}.dcu-wb-session-copy{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center}.dcu-wb-session-sub{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dcu-sidebar-tertiary);font-size:12px;line-height:16px}.dcu-wb-session-flat,.dcu-wb-session-top{padding-left:8px}.dcu-wb-session-flat:has(.dcu-wb-running),.dcu-wb-session-top:has(.dcu-wb-running){padding-left:30px}
|
|
3020
3342
|
.dcu-wb-actions{display:none;align-items:center;gap:8px;flex:none}
|
|
3021
3343
|
.dcu-wb-quick-actions{position:absolute;right:8px;top:50%;display:flex;align-items:center;gap:2px;opacity:0;pointer-events:none;transform:translateY(-50%);background:var(--dcu-sidebar-hover);border-radius:6px}
|
|
3022
3344
|
.dcu-wb-project-head:hover .dcu-wb-actions,.dcu-wb-project-head.dcu-wb-menu-open .dcu-wb-actions,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-actions{display:flex}
|
|
3023
|
-
.dcu-wb-session:hover .dcu-wb-quick-actions,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-quick-actions{opacity:1;pointer-events:auto}.dcu-wb-session:hover .dcu-wb-pending,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-pending,.dcu-wb-session:hover .dcu-wb-unread,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-unread{visibility:hidden}
|
|
3345
|
+
.dcu-wb-session:hover .dcu-wb-quick-actions,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-quick-actions{opacity:1;pointer-events:auto}.dcu-wb-session:hover .dcu-wb-pending,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-pending,.dcu-wb-session:hover .dcu-wb-unread,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-unread,.dcu-wb-session:hover .dcu-wb-session-time,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-session-time{visibility:hidden}.dcu-wb-session:has(.dcu-wb-pending) .dcu-wb-session-time{display:none}
|
|
3024
3346
|
.dcu-wb-more{display:grid;place-items:center;width:20px;height:20px;border:0;border-radius:4px;padding:0;background:transparent;color:var(--dcu-sidebar-tertiary);cursor:pointer}
|
|
3025
3347
|
.dcu-wb-more:hover{color:var(--dcu-sidebar-primary)}
|
|
3026
3348
|
.dcu-wb-context-anchor{opacity:0;pointer-events:none}
|
|
@@ -3047,7 +3369,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3047
3369
|
.dcu-wb-drop-indicator::before{content:"";position:absolute;left:6px;right:0;top:3px;height:2px;border-radius:999px;background:currentColor}
|
|
3048
3370
|
.dcu-wb-drop-indicator::after{content:"";position:absolute;box-sizing:border-box;left:0;top:0;width:8px;height:8px;border:2px solid currentColor;border-radius:50%}
|
|
3049
3371
|
.dcu-wb-project-body:has(>.dcu-wb-session)::after{content:"";display:block;height:4px;pointer-events:none}
|
|
3050
|
-
.dcu-wb-section-body[data-open=true]:has(.dcu-wb-group-order-drop){overflow:visible}
|
|
3372
|
+
.dcu-wb-section-body[data-open=true]:has(.dcu-wb-group-order-drop),.dcu-wb-section-body[data-open=true]:has(.dcu-wb-pin-end),.dcu-wb-section-body[data-open=true]:has(.dcu-wb-pin-start){overflow:visible}
|
|
3051
3373
|
.dcu-wb-collection-body{padding-left:0}
|
|
3052
3374
|
.dcu-wb-collection-body>.dcu-wb-group-member:first-child{padding-top:4px}
|
|
3053
3375
|
.dcu-wb-collection-body .dcu-wb-project-head{padding-left:8px}
|
|
@@ -3089,9 +3411,12 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3089
3411
|
function CodexWorkspaceBrowser(props) {
|
|
3090
3412
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HoverShell, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CodexWorkspaceTree, { ...props }) });
|
|
3091
3413
|
}
|
|
3092
|
-
function CodexWorkspaceTree({ wide, useSessions, useSessionPendingInteraction, useWorkspaces, t, archiveSession, deleteSession, deleteWorkspace, forkSession, insertSessionBefore, insertWorkspaceBefore, moveSession, openPath, openSession, renameSession, renameWorkspace, startSession, canDeleteSession }) {
|
|
3414
|
+
function CodexWorkspaceTree({ wide, useSessions, useSessionPendingInteraction, useSessionStatus, useWorkspaces, t, archiveSession, deleteSession, deleteWorkspace, forkSession, insertSessionBefore, insertWorkspaceBefore, moveSession, openPath, openSession, renameSession, renameWorkspace, startSession, canDeleteSession, panelActive = false }) {
|
|
3093
3415
|
const sessions = useSessions((state) => state);
|
|
3094
|
-
const
|
|
3416
|
+
const now = useSharedNow();
|
|
3417
|
+
const pendingInteractions = useHostPendingInteractions(useSessionPendingInteraction, useSessionStatus);
|
|
3418
|
+
const sessionStatus = useHostSessionStatus(useSessionStatus);
|
|
3419
|
+
const selectedId = visibleSelectedSessionId(sessions, panelActive);
|
|
3095
3420
|
const workspaces = useWorkspaces((state) => state);
|
|
3096
3421
|
const baselinesReady = workspaceBaselinesReady(workspaces, sessions);
|
|
3097
3422
|
const [expanded, setExpanded] = (0, react.useState)(() => readTreeExpansionState(storage$1(), WORKSPACE_EXPANSION_STORAGE_KEY));
|
|
@@ -3153,6 +3478,8 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3153
3478
|
setWorkspaceGroupsState(next);
|
|
3154
3479
|
};
|
|
3155
3480
|
const [unreadSessionIds, setUnreadSessionIds] = (0, react.useState)(() => readSessionIds(storage$1(), SESSION_UNREAD_STORAGE_KEY));
|
|
3481
|
+
const rowUnread = (id) => sessionRowUnread(unreadSessionIds.includes(id), sessionStatus.get(id), selectedId === id);
|
|
3482
|
+
const rowRunning = (id, session) => sessionIsRunning(session ?? sessions.byId[id], sessionStatus.get(id));
|
|
3156
3483
|
const previousSessionRunningRef = (0, react.useRef)();
|
|
3157
3484
|
const [menu, setMenu] = (0, react.useState)();
|
|
3158
3485
|
const [renameTarget, setRenameTarget] = (0, react.useState)();
|
|
@@ -3272,17 +3599,20 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3272
3599
|
}
|
|
3273
3600
|
}, [baselinesReady, workspaces.items]);
|
|
3274
3601
|
(0, react.useEffect)(() => {
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
}, [sessions.current]);
|
|
3602
|
+
if (selectedId !== void 0) setUnreadSessionIds((ids) => ids.filter((id) => id !== selectedId));
|
|
3603
|
+
}, [selectedId]);
|
|
3278
3604
|
(0, react.useEffect)(() => {
|
|
3279
|
-
const next =
|
|
3605
|
+
const next = sessionRunningFlags(sessions.byId, sessionStatus);
|
|
3280
3606
|
const previous = previousSessionRunningRef.current;
|
|
3281
3607
|
previousSessionRunningRef.current = next;
|
|
3282
3608
|
if (previous === void 0) return;
|
|
3283
|
-
const completed = completedBackgroundSessionIds(previous, next,
|
|
3609
|
+
const completed = completedBackgroundSessionIds(previous, next, selectedId);
|
|
3284
3610
|
if (completed.length > 0) setUnreadSessionIds((ids) => [...completed, ...ids.filter((id) => !completed.includes(id))]);
|
|
3285
|
-
}, [
|
|
3611
|
+
}, [
|
|
3612
|
+
selectedId,
|
|
3613
|
+
sessionStatus,
|
|
3614
|
+
sessions.byId
|
|
3615
|
+
]);
|
|
3286
3616
|
const groups = (0, react.useMemo)(() => {
|
|
3287
3617
|
const archived = workspaces.archivedSessionIds;
|
|
3288
3618
|
const visible = (ids) => visibleSessionIds(ids, sessions.byId, archived);
|
|
@@ -3313,7 +3643,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3313
3643
|
(0, react.useEffect)(() => {
|
|
3314
3644
|
const onProject = (event) => {
|
|
3315
3645
|
const detail = event.detail;
|
|
3316
|
-
const current =
|
|
3646
|
+
const current = selectedId;
|
|
3317
3647
|
const workspace = groups.items.find((item) => current !== void 0 && item.visibleIds.includes(String(current)));
|
|
3318
3648
|
if (workspace === void 0 || detail === void 0) return;
|
|
3319
3649
|
if (detail.toggle === true && isShowing("workspace", workspace.workspaceId)) {
|
|
@@ -3326,7 +3656,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3326
3656
|
title: workspace.title,
|
|
3327
3657
|
path: workspace.path,
|
|
3328
3658
|
count: workspace.visibleIds.length,
|
|
3329
|
-
unreadCount: workspace.visibleIds.filter((id) =>
|
|
3659
|
+
unreadCount: workspace.visibleIds.filter((id) => rowUnread(String(id))).length,
|
|
3330
3660
|
pinned: pinnedWorkspaceIds.includes(String(workspace.workspaceId)),
|
|
3331
3661
|
left: detail.left,
|
|
3332
3662
|
top: detail.top
|
|
@@ -3334,7 +3664,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3334
3664
|
};
|
|
3335
3665
|
const onMenu = (event) => {
|
|
3336
3666
|
const detail = event.detail;
|
|
3337
|
-
const current =
|
|
3667
|
+
const current = selectedId;
|
|
3338
3668
|
if (current === void 0 || detail === void 0) return;
|
|
3339
3669
|
dismissTip();
|
|
3340
3670
|
if (performance.now() - headerMenuPointerAt.current < 500) {
|
|
@@ -3355,9 +3685,9 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3355
3685
|
};
|
|
3356
3686
|
}, [
|
|
3357
3687
|
groups.items,
|
|
3358
|
-
sessions.current,
|
|
3359
3688
|
menu,
|
|
3360
3689
|
pinnedWorkspaceIds,
|
|
3690
|
+
selectedId,
|
|
3361
3691
|
unreadSessionIds
|
|
3362
3692
|
]);
|
|
3363
3693
|
const projectPinned = (id) => pinnedWorkspaceIds.includes(String(id));
|
|
@@ -3586,7 +3916,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3586
3916
|
};
|
|
3587
3917
|
const canDelete = canDeleteSession?.() === true;
|
|
3588
3918
|
const sessionMenu = (sessionId, path) => sessionMenuItems(t, {
|
|
3589
|
-
unread:
|
|
3919
|
+
unread: rowUnread(sessionId),
|
|
3590
3920
|
path,
|
|
3591
3921
|
includePath: true,
|
|
3592
3922
|
moveTargets: sessionMoveTargets(groups.items, sessionId).map((target) => ({
|
|
@@ -3641,7 +3971,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3641
3971
|
const renderGroup = (workspace, zone) => {
|
|
3642
3972
|
const expandKey = zone === "pinned" ? `pin:${workspace.workspaceId}` : String(workspace.workspaceId);
|
|
3643
3973
|
const isExpanded = expanded[expandKey] ?? true;
|
|
3644
|
-
const currentSessionId =
|
|
3974
|
+
const currentSessionId = selectedId;
|
|
3645
3975
|
const folder = projectFolderPresentation(isExpanded, workspace.visibleIds.some((id) => id === currentSessionId));
|
|
3646
3976
|
const shownIds = workspace.visibleIds;
|
|
3647
3977
|
const menuOpen = menu?.type === "workspace" && menu.id === workspace.workspaceId;
|
|
@@ -3769,7 +4099,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3769
4099
|
title: workspace.title,
|
|
3770
4100
|
path: workspace.path,
|
|
3771
4101
|
count: workspace.visibleIds.length,
|
|
3772
|
-
unreadCount: workspace.visibleIds.filter((id) =>
|
|
4102
|
+
unreadCount: workspace.visibleIds.filter((id) => rowUnread(String(id))).length,
|
|
3773
4103
|
pinned: projectPinned(workspace.workspaceId),
|
|
3774
4104
|
left: box.left,
|
|
3775
4105
|
top: box.top
|
|
@@ -3798,7 +4128,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3798
4128
|
title: workspace.title,
|
|
3799
4129
|
path: workspace.path,
|
|
3800
4130
|
count: workspace.visibleIds.length,
|
|
3801
|
-
unreadCount: workspace.visibleIds.filter((id) =>
|
|
4131
|
+
unreadCount: workspace.visibleIds.filter((id) => rowUnread(String(id))).length,
|
|
3802
4132
|
pinned: projectPinned(workspace.workspaceId),
|
|
3803
4133
|
left: box.left,
|
|
3804
4134
|
top: box.top
|
|
@@ -3866,7 +4196,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3866
4196
|
if (session === void 0) return null;
|
|
3867
4197
|
const pendingInteraction = pendingInteractionForSession(id, pendingInteractions, legacyPendingInteraction(session));
|
|
3868
4198
|
const path = session.cwd ?? workspace.path;
|
|
3869
|
-
const selected =
|
|
4199
|
+
const selected = selectedId === id;
|
|
3870
4200
|
const sessionMenuOpen = menu?.type === "session" && menu.id === id;
|
|
3871
4201
|
const sessionMenuAt = sessionMenuOpen && menu.x !== void 0 && menu.y !== void 0 ? {
|
|
3872
4202
|
x: menu.x,
|
|
@@ -3951,23 +4281,21 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3951
4281
|
project: workspace.title,
|
|
3952
4282
|
path,
|
|
3953
4283
|
branch,
|
|
3954
|
-
time: formatHoverTime(session.updatedAt, t),
|
|
4284
|
+
time: formatHoverTime(session.updatedAt, t, now),
|
|
3955
4285
|
left: box.left,
|
|
3956
4286
|
top: box.top
|
|
3957
4287
|
});
|
|
3958
4288
|
},
|
|
3959
4289
|
onMouseLeave: hideTip,
|
|
3960
4290
|
children: [
|
|
3961
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
3962
|
-
className: "dcu-wb-session-title",
|
|
3963
|
-
children: session.displayTitle.split(/\r?\n/)[0] ?? session.displayTitle
|
|
3964
|
-
}),
|
|
4291
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionRowTitle, { title: session.displayTitle }),
|
|
3965
4292
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionState, {
|
|
3966
4293
|
pendingInteraction,
|
|
3967
|
-
unread:
|
|
3968
|
-
running: session
|
|
4294
|
+
unread: rowUnread(id),
|
|
4295
|
+
running: rowRunning(id, session),
|
|
3969
4296
|
t
|
|
3970
4297
|
}),
|
|
4298
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionTime, { time: formatCompactTime(session.updatedAt, t, now) }),
|
|
3971
4299
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3972
4300
|
className: "dcu-wb-quick-actions",
|
|
3973
4301
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
@@ -4423,7 +4751,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4423
4751
|
return mountWorkspaceDropIndicator(treeRef.current);
|
|
4424
4752
|
}, [wide, sorting]);
|
|
4425
4753
|
(0, react.useEffect)(() => {
|
|
4426
|
-
const current =
|
|
4754
|
+
const current = selectedId;
|
|
4427
4755
|
if (current === void 0 || lastRevealedSessionIdRef.current === current) return;
|
|
4428
4756
|
const tree = {
|
|
4429
4757
|
workspaces: workspaces.items.map((item) => ({
|
|
@@ -4444,7 +4772,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4444
4772
|
}, [
|
|
4445
4773
|
pinnedWorkspaceIds,
|
|
4446
4774
|
recentIds,
|
|
4447
|
-
|
|
4775
|
+
selectedId,
|
|
4448
4776
|
workspaceGroups,
|
|
4449
4777
|
workspaces.items
|
|
4450
4778
|
]);
|
|
@@ -4714,16 +5042,17 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4714
5042
|
const session = sessions.byId[id];
|
|
4715
5043
|
if (session === void 0) return null;
|
|
4716
5044
|
const title = session.displayTitle;
|
|
4717
|
-
const unread =
|
|
5045
|
+
const unread = rowUnread(id);
|
|
4718
5046
|
const pendingInteraction = pendingInteractionForSession(id, pendingInteractions, legacyPendingInteraction(session));
|
|
4719
5047
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionRow, {
|
|
4720
5048
|
id,
|
|
4721
5049
|
title,
|
|
4722
|
-
selected:
|
|
5050
|
+
selected: selectedId === id,
|
|
4723
5051
|
menuOpen: menu?.type === "session" && menu.id === id,
|
|
4724
5052
|
unread,
|
|
4725
|
-
running: session
|
|
5053
|
+
running: rowRunning(id, session),
|
|
4726
5054
|
pendingInteraction,
|
|
5055
|
+
time: formatCompactTime(session.updatedAt, t, now),
|
|
4727
5056
|
t,
|
|
4728
5057
|
menuItems: sessionMenu(id, session.cwd),
|
|
4729
5058
|
draggable: true,
|
|
@@ -4769,7 +5098,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
4769
5098
|
kind: "session",
|
|
4770
5099
|
id,
|
|
4771
5100
|
title,
|
|
4772
|
-
time: formatHoverTime(session.updatedAt, t),
|
|
5101
|
+
time: formatHoverTime(session.updatedAt, t, now),
|
|
4773
5102
|
left: box.left,
|
|
4774
5103
|
top: box.top
|
|
4775
5104
|
});
|
|
@@ -5416,14 +5745,17 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
5416
5745
|
})
|
|
5417
5746
|
});
|
|
5418
5747
|
}
|
|
5419
|
-
function ChannelBrowserTree({ openSession, archiveSession, deleteSession, forkSession, moveSession, renameSession, useSessions, useSessionPendingInteraction, useWorkspaces, t, canDeleteSession, menu, setMenu }) {
|
|
5748
|
+
function ChannelBrowserTree({ openSession, archiveSession, deleteSession, forkSession, moveSession, renameSession, useSessions, useSessionPendingInteraction, useSessionStatus, useWorkspaces, t, canDeleteSession, panelActive = false, menu, setMenu }) {
|
|
5420
5749
|
const sessions = useSessions((state) => state);
|
|
5750
|
+
const now = useSharedNow();
|
|
5421
5751
|
const workspaces = useWorkspaces?.((state) => state);
|
|
5422
|
-
const pendingInteractions = (useSessionPendingInteraction
|
|
5752
|
+
const pendingInteractions = useHostPendingInteractions(useSessionPendingInteraction, useSessionStatus);
|
|
5753
|
+
const sessionStatus = useHostSessionStatus(useSessionStatus);
|
|
5754
|
+
const selectedId = visibleSelectedSessionId(sessions, panelActive);
|
|
5423
5755
|
const [groups, setGroups] = (0, react.useState)([]);
|
|
5424
5756
|
const [pollError, setPollError] = (0, react.useState)();
|
|
5425
5757
|
const [expanded, setExpanded] = (0, react.useState)(() => readTreeExpansionState(browserStorage(), CHANNEL_EXPANSION_STORAGE_KEY));
|
|
5426
|
-
const flags = useSessionFlags(
|
|
5758
|
+
const flags = useSessionFlags(selectedId);
|
|
5427
5759
|
const { showTip, hideTip, dismissTip } = useHoverDispatch();
|
|
5428
5760
|
const { busy, error, setError, run } = useBusyAction(t, () => {
|
|
5429
5761
|
setMenu(void 0);
|
|
@@ -5519,10 +5851,11 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
5519
5851
|
children: group.sessions.map((session) => {
|
|
5520
5852
|
const id = session.sessionId;
|
|
5521
5853
|
const title = session.title;
|
|
5522
|
-
const selected =
|
|
5523
|
-
const
|
|
5854
|
+
const selected = selectedId === id;
|
|
5855
|
+
const status = sessionStatus.get(id);
|
|
5856
|
+
const running = sessionIsRunning({ running: session.running === true || sessions.byId[id]?.running === true }, status);
|
|
5524
5857
|
const updatedAt = session.updatedAt ?? sessions.byId[id]?.updatedAt;
|
|
5525
|
-
const unread = flags.unreadSessionIds.includes(id);
|
|
5858
|
+
const unread = sessionRowUnread(flags.unreadSessionIds.includes(id), status, selected);
|
|
5526
5859
|
const pendingInteraction = pendingInteractionForSession(id, pendingInteractions, sessions.byId[id]?.pendingInteraction);
|
|
5527
5860
|
const moveTargets = moveSession === void 0 || workspaces === void 0 ? void 0 : sessionMoveTargets(workspaces.items, id).map((target) => ({
|
|
5528
5861
|
...target,
|
|
@@ -5537,6 +5870,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
5537
5870
|
unread,
|
|
5538
5871
|
running,
|
|
5539
5872
|
pendingInteraction,
|
|
5873
|
+
time: updatedAt === void 0 ? void 0 : formatCompactTime(updatedAt, t, now),
|
|
5540
5874
|
t,
|
|
5541
5875
|
menuItems: sessionMenuItems(t, {
|
|
5542
5876
|
unread,
|
|
@@ -5562,7 +5896,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
5562
5896
|
showTip({
|
|
5563
5897
|
title,
|
|
5564
5898
|
project: label,
|
|
5565
|
-
time: updatedAt === void 0 ? void 0 : formatHoverTime(updatedAt, t),
|
|
5899
|
+
time: updatedAt === void 0 ? void 0 : formatHoverTime(updatedAt, t, now),
|
|
5566
5900
|
left: box.left,
|
|
5567
5901
|
top: box.top
|
|
5568
5902
|
});
|
|
@@ -5690,14 +6024,17 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
5690
6024
|
})]
|
|
5691
6025
|
});
|
|
5692
6026
|
}
|
|
5693
|
-
function ScheduleBrowserTree({ openSession, archiveSession, deleteSession, forkSession, moveSession, renameSession, useSessions, useSessionPendingInteraction, useWorkspaces, t, canDeleteSession, openTaskSettings, menu, setMenu }) {
|
|
6027
|
+
function ScheduleBrowserTree({ openSession, archiveSession, deleteSession, forkSession, moveSession, renameSession, useSessions, useSessionPendingInteraction, useSessionStatus, useWorkspaces, t, canDeleteSession, panelActive = false, openTaskSettings, menu, setMenu }) {
|
|
5694
6028
|
const sessions = useSessions((state) => state);
|
|
5695
|
-
const
|
|
6029
|
+
const now = useSharedNow();
|
|
6030
|
+
const pendingInteractions = useHostPendingInteractions(useSessionPendingInteraction, useSessionStatus);
|
|
6031
|
+
const sessionStatus = useHostSessionStatus(useSessionStatus);
|
|
6032
|
+
const selectedId = visibleSelectedSessionId(sessions, panelActive);
|
|
5696
6033
|
const workspaces = useWorkspaces((state) => state);
|
|
5697
6034
|
const [expanded, setExpanded] = (0, react.useState)(() => readTreeExpansionState(browserStorage(), SCHEDULE_EXPANSION_STORAGE_KEY));
|
|
5698
6035
|
const [groupMenu, setGroupMenu] = (0, react.useState)();
|
|
5699
6036
|
const [archiveGroupTarget, setArchiveGroupTarget] = (0, react.useState)();
|
|
5700
|
-
const flags = useSessionFlags(
|
|
6037
|
+
const flags = useSessionFlags(selectedId);
|
|
5701
6038
|
const { showTip, hideTip, dismissTip } = useHoverDispatch();
|
|
5702
6039
|
const { busy, error, setError, run } = useBusyAction(t, () => {
|
|
5703
6040
|
setMenu(void 0);
|
|
@@ -5826,7 +6163,9 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
5826
6163
|
children: group.sessions.map((session) => {
|
|
5827
6164
|
const id = session.id;
|
|
5828
6165
|
const title = session.title;
|
|
5829
|
-
const
|
|
6166
|
+
const selected = selectedId === id;
|
|
6167
|
+
const status = sessionStatus.get(id);
|
|
6168
|
+
const unread = sessionRowUnread(flags.unreadSessionIds.includes(id), status, selected);
|
|
5830
6169
|
const pendingInteraction = pendingInteractionForSession(id, pendingInteractions, sessions.byId[id]?.pendingInteraction);
|
|
5831
6170
|
const moveTargets = moveSession === void 0 ? void 0 : sessionMoveTargets(workspaces.items ?? [], id).map((target) => ({
|
|
5832
6171
|
...target,
|
|
@@ -5836,11 +6175,12 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
5836
6175
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionRow, {
|
|
5837
6176
|
id,
|
|
5838
6177
|
title,
|
|
5839
|
-
selected
|
|
6178
|
+
selected,
|
|
5840
6179
|
menuOpen: menu?.id === id,
|
|
5841
6180
|
unread,
|
|
5842
|
-
running:
|
|
6181
|
+
running: sessionIsRunning(sessions.byId[id], status),
|
|
5843
6182
|
pendingInteraction,
|
|
6183
|
+
time: session.updatedAt === void 0 ? void 0 : formatCompactTime(session.updatedAt, t, now),
|
|
5844
6184
|
t,
|
|
5845
6185
|
menuItems: sessionMenuItems(t, {
|
|
5846
6186
|
unread,
|
|
@@ -5866,7 +6206,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
5866
6206
|
showTip({
|
|
5867
6207
|
title,
|
|
5868
6208
|
project: group.label,
|
|
5869
|
-
time: session.updatedAt === void 0 ? void 0 : formatHoverTime(session.updatedAt, t),
|
|
6209
|
+
time: session.updatedAt === void 0 ? void 0 : formatHoverTime(session.updatedAt, t, now),
|
|
5870
6210
|
left: box.left,
|
|
5871
6211
|
top: box.top
|
|
5872
6212
|
});
|
|
@@ -6602,7 +6942,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
6602
6942
|
});
|
|
6603
6943
|
}
|
|
6604
6944
|
/** 搜索状态与大侧栏隔离:输入、悬停和开关弹窗都不能让工作区树跟着重渲染。 */
|
|
6605
|
-
const SidebarSearch = (0, react.forwardRef)(function SidebarSearch({ imSettingsAvailable, openSession, startSession, t, useSessions, useWorkspaces, settingsSeat }, ref) {
|
|
6945
|
+
const SidebarSearch = (0, react.forwardRef)(function SidebarSearch({ imSettingsAvailable, openPlugins, openSession, startSession, t, useSessions, useWorkspaces, settingsSeat }, ref) {
|
|
6606
6946
|
const [open, setOpen] = (0, react.useState)(false);
|
|
6607
6947
|
const [query, setQuery] = (0, react.useState)("");
|
|
6608
6948
|
const [activeIndex, setActiveIndex] = (0, react.useState)(0);
|
|
@@ -6620,9 +6960,6 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
6620
6960
|
const selectSection = (0, react.useCallback)((label) => {
|
|
6621
6961
|
openSettingsSection(settingsSeat.current, label);
|
|
6622
6962
|
}, [settingsSeat]);
|
|
6623
|
-
const selectPluginSection = (0, react.useCallback)(() => {
|
|
6624
|
-
openSettingsSection(settingsSeat.current, [t("sidebar.marketplace"), t("sidebar.plugins")]);
|
|
6625
|
-
}, [settingsSeat, t]);
|
|
6626
6963
|
const selectExternalSection = (0, react.useCallback)((label) => {
|
|
6627
6964
|
openSettingsSection(settingsSeat.current, label, () => {
|
|
6628
6965
|
selectSection(t("about.nav"));
|
|
@@ -6699,7 +7036,17 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
6699
7036
|
keywords: t("search.settings"),
|
|
6700
7037
|
run: () => {
|
|
6701
7038
|
close();
|
|
6702
|
-
|
|
7039
|
+
openPlugins();
|
|
7040
|
+
}
|
|
7041
|
+
},
|
|
7042
|
+
{
|
|
7043
|
+
id: "settings:plugin-config",
|
|
7044
|
+
group: "settings",
|
|
7045
|
+
label: t("settings.pluginConfig"),
|
|
7046
|
+
keywords: t("search.settings"),
|
|
7047
|
+
run: () => {
|
|
7048
|
+
close();
|
|
7049
|
+
openSettingsSection(settingsSeat.current, t("settings.pluginConfig"));
|
|
6703
7050
|
}
|
|
6704
7051
|
},
|
|
6705
7052
|
{
|
|
@@ -6760,10 +7107,10 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
6760
7107
|
}, [
|
|
6761
7108
|
close,
|
|
6762
7109
|
openImSettings,
|
|
7110
|
+
openPlugins,
|
|
6763
7111
|
openSession,
|
|
6764
7112
|
openSettings,
|
|
6765
7113
|
selectExternalSection,
|
|
6766
|
-
selectPluginSection,
|
|
6767
7114
|
selectSection,
|
|
6768
7115
|
sessions.byId,
|
|
6769
7116
|
sessions.ids,
|
|
@@ -6874,10 +7221,11 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
6874
7221
|
});
|
|
6875
7222
|
});
|
|
6876
7223
|
/** Codex 风格的 DSH 侧栏,只替换导航外观,项目浏览和设置仍由 DSH 官方组件提供。 */
|
|
6877
|
-
function CodexSidebar({ globalPanels, footerActions, selectPanel, usePanelInfo = useLegacyPanelInfo, collapsed, width, openSession, startSession, toggleSidebar, archiveSession, canDeleteSession, deleteSession, forkSession, moveSession, renameSession, openPath, companionSlots, renderSlot, t, useSessions, useSessionPendingInteraction, useWorkspaces, prefillNewConversation, newConversationDraft }) {
|
|
7224
|
+
function CodexSidebar({ globalPanels, footerActions, selectPanel, usePanelInfo = useLegacyPanelInfo, collapsed, width, openSession, startSession, toggleSidebar, archiveSession, canDeleteSession, deleteSession, forkSession, moveSession, renameSession, openPath, companionSlots, renderSlot, t, useSessions, useSessionPendingInteraction, useSessionStatus, useWorkspaces, prefillNewConversation, newConversationDraft }) {
|
|
6878
7225
|
const panels = (0, react.useSyncExternalStore)(globalPanels?.subscribe ?? subscribeEmptyCompanionTabs, globalPanels?.getSnapshot ?? getEmptyPanels, globalPanels?.getSnapshot ?? getEmptyPanels);
|
|
6879
7226
|
const visibleFooterActions = (0, react.useSyncExternalStore)(footerActions?.subscribe ?? subscribeEmptyCompanionTabs, footerActions?.getSnapshot ?? getEmptyFooterActions, footerActions?.getSnapshot ?? getEmptyFooterActions);
|
|
6880
7227
|
const activePanelId = usePanelInfo((info) => info.activePanelId);
|
|
7228
|
+
const panelActive = activePanelId !== null && activePanelId !== "";
|
|
6881
7229
|
const panelButtons = (wide) => selectPanel === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GlobalPanelButtons, {
|
|
6882
7230
|
panels,
|
|
6883
7231
|
activeId: activePanelId,
|
|
@@ -6908,8 +7256,8 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
6908
7256
|
const selectSection = (label) => {
|
|
6909
7257
|
openSettingsSection(settingsSeat.current, label);
|
|
6910
7258
|
};
|
|
6911
|
-
const
|
|
6912
|
-
openSettingsSection(settingsSeat.current, [t("sidebar.marketplace"), t("sidebar.
|
|
7259
|
+
const openPlugins = () => {
|
|
7260
|
+
openSettingsSection(settingsSeat.current, [t("sidebar.marketplace"), t("sidebar.builtinPlugins")]);
|
|
6913
7261
|
};
|
|
6914
7262
|
const selectExternalSection = (label) => {
|
|
6915
7263
|
openSettingsSection(settingsSeat.current, label, () => {
|
|
@@ -7028,10 +7376,17 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
7028
7376
|
window.clearTimeout(timer);
|
|
7029
7377
|
};
|
|
7030
7378
|
}, [compact, visualCompact]);
|
|
7031
|
-
const workspaceSlot = (0, react.useMemo)(() =>
|
|
7032
|
-
|
|
7033
|
-
|
|
7034
|
-
|
|
7379
|
+
const workspaceSlot = (0, react.useMemo)(() => {
|
|
7380
|
+
return renderSlot("sidebar.workspaces", {
|
|
7381
|
+
wide: true,
|
|
7382
|
+
expandSidebar,
|
|
7383
|
+
panelActive
|
|
7384
|
+
});
|
|
7385
|
+
}, [
|
|
7386
|
+
expandSidebar,
|
|
7387
|
+
panelActive,
|
|
7388
|
+
renderSlot
|
|
7389
|
+
]);
|
|
7035
7390
|
const scheduleOverviewSlot = (0, react.useMemo)(() => renderSlot("sidebar.schedule", {
|
|
7036
7391
|
wide: true,
|
|
7037
7392
|
expandSidebar,
|
|
@@ -7167,7 +7522,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
7167
7522
|
type: "button",
|
|
7168
7523
|
tabIndex: extensionsOpen ? 0 : -1,
|
|
7169
7524
|
onClick: () => {
|
|
7170
|
-
|
|
7525
|
+
openPlugins();
|
|
7171
7526
|
},
|
|
7172
7527
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MenuIcon, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPersonalizationOutline16, { size: 16 }) }), t("sidebar.plugins")]
|
|
7173
7528
|
}),
|
|
@@ -7243,7 +7598,9 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
7243
7598
|
renameSession,
|
|
7244
7599
|
useSessions,
|
|
7245
7600
|
useSessionPendingInteraction,
|
|
7601
|
+
useSessionStatus,
|
|
7246
7602
|
useWorkspaces,
|
|
7603
|
+
panelActive,
|
|
7247
7604
|
t
|
|
7248
7605
|
})
|
|
7249
7606
|
}) : imTab === "schedule" && showSchedule ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -7258,7 +7615,9 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
7258
7615
|
renameSession,
|
|
7259
7616
|
useSessions,
|
|
7260
7617
|
useSessionPendingInteraction,
|
|
7618
|
+
useSessionStatus,
|
|
7261
7619
|
useWorkspaces,
|
|
7620
|
+
panelActive,
|
|
7262
7621
|
t,
|
|
7263
7622
|
overviewContent: scheduleOverviewSlot,
|
|
7264
7623
|
openTaskSettings: (request) => {
|
|
@@ -7331,7 +7690,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
7331
7690
|
className: "dcu-icon",
|
|
7332
7691
|
"aria-label": t("sidebar.plugins"),
|
|
7333
7692
|
onClick: () => {
|
|
7334
|
-
|
|
7693
|
+
openPlugins();
|
|
7335
7694
|
},
|
|
7336
7695
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPersonalizationOutline16, { size: 16 })
|
|
7337
7696
|
}),
|
|
@@ -7377,6 +7736,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
7377
7736
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarSearch, {
|
|
7378
7737
|
ref: search,
|
|
7379
7738
|
imSettingsAvailable: showChannels,
|
|
7739
|
+
openPlugins,
|
|
7380
7740
|
settingsSeat,
|
|
7381
7741
|
openSession,
|
|
7382
7742
|
startSession,
|
|
@@ -7916,7 +8276,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
7916
8276
|
});
|
|
7917
8277
|
}
|
|
7918
8278
|
function NativeConnectorList({ sessionStore, t }) {
|
|
7919
|
-
const sessionId = (0, react.useSyncExternalStore)(sessionStore.subscribe, () => sessionStore.getSnapshot()
|
|
8279
|
+
const sessionId = (0, react.useSyncExternalStore)(sessionStore.subscribe, () => currentSessionId(sessionStore.getSnapshot()));
|
|
7920
8280
|
const [connectors, setConnectors] = (0, react.useState)([]);
|
|
7921
8281
|
const [state, setState] = (0, react.useState)("loading");
|
|
7922
8282
|
const [failure, setFailure] = (0, react.useState)();
|
|
@@ -8071,6 +8431,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
8071
8431
|
"settings.search": "搜索设置…",
|
|
8072
8432
|
"settings.personal": "个人",
|
|
8073
8433
|
"settings.integrations": "集成",
|
|
8434
|
+
"settings.pluginConfig": "插件配置",
|
|
8074
8435
|
"settings.records": "记录与应用",
|
|
8075
8436
|
"settings.general": "常规",
|
|
8076
8437
|
"settings.permissions": "权限",
|
|
@@ -8093,6 +8454,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
8093
8454
|
"sidebar.skills": "技能",
|
|
8094
8455
|
"sidebar.plugins": "插件",
|
|
8095
8456
|
"sidebar.marketplace": "插件市场",
|
|
8457
|
+
"sidebar.builtinPlugins": "内置插件",
|
|
8096
8458
|
"sidebar.connectors": "连接器",
|
|
8097
8459
|
"sidebar.schedule": "定时任务",
|
|
8098
8460
|
"sidebar.assistant": "IM助理",
|
|
@@ -8284,9 +8646,13 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
8284
8646
|
"turns.untitled": "未命名提问",
|
|
8285
8647
|
"turns.jump": "跳转到第 {index} 轮:{summary}",
|
|
8286
8648
|
"time.justNow": "刚刚",
|
|
8649
|
+
"time.justNowShort": "刚刚",
|
|
8287
8650
|
"time.minutes": "{count}分",
|
|
8288
8651
|
"time.hours": "{count}小时",
|
|
8289
8652
|
"time.days": "{count}天",
|
|
8653
|
+
"time.weeks": "{count}周",
|
|
8654
|
+
"time.months": "{count}个月",
|
|
8655
|
+
"time.years": "{count}年",
|
|
8290
8656
|
"errors.unauthorized": "请先登录 DSH,再重试。",
|
|
8291
8657
|
"errors.forbidden": "请求被安全检查拒绝,请从可信的 DSH 地址重试。",
|
|
8292
8658
|
"errors.serviceUnavailable": "服务暂不可用,请稍后重试。",
|
|
@@ -8355,6 +8721,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
8355
8721
|
"settings.search": "Search settings…",
|
|
8356
8722
|
"settings.personal": "Personal",
|
|
8357
8723
|
"settings.integrations": "Integrations",
|
|
8724
|
+
"settings.pluginConfig": "Plugin configuration",
|
|
8358
8725
|
"settings.records": "Records and app",
|
|
8359
8726
|
"settings.general": "General",
|
|
8360
8727
|
"settings.permissions": "Permissions",
|
|
@@ -8377,6 +8744,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
8377
8744
|
"sidebar.skills": "Skills",
|
|
8378
8745
|
"sidebar.plugins": "Plugins",
|
|
8379
8746
|
"sidebar.marketplace": "Plugin Market",
|
|
8747
|
+
"sidebar.builtinPlugins": "Built-in plugins",
|
|
8380
8748
|
"sidebar.connectors": "Connectors",
|
|
8381
8749
|
"sidebar.schedule": "Scheduled tasks",
|
|
8382
8750
|
"sidebar.assistant": "IM Assistant",
|
|
@@ -8568,9 +8936,13 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
8568
8936
|
"turns.untitled": "Untitled prompt",
|
|
8569
8937
|
"turns.jump": "Jump to turn {index}: {summary}",
|
|
8570
8938
|
"time.justNow": "Just now",
|
|
8939
|
+
"time.justNowShort": "now",
|
|
8571
8940
|
"time.minutes": "{count}m",
|
|
8572
8941
|
"time.hours": "{count}h",
|
|
8573
8942
|
"time.days": "{count}d",
|
|
8943
|
+
"time.weeks": "{count}w",
|
|
8944
|
+
"time.months": "{count}mo",
|
|
8945
|
+
"time.years": "{count}y",
|
|
8574
8946
|
"errors.unauthorized": "Sign in to DSH, then try again.",
|
|
8575
8947
|
"errors.forbidden": "The security check rejected this request. Try again from a trusted DSH address.",
|
|
8576
8948
|
"errors.serviceUnavailable": "The service is unavailable. Try again later.",
|
|
@@ -8665,6 +9037,8 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
8665
9037
|
};
|
|
8666
9038
|
const LABEL_ALIASES = [
|
|
8667
9039
|
[["插件市场", "Plugin Market"], "plugins"],
|
|
9040
|
+
[["内置插件", "Built-in plugins"], "plugins"],
|
|
9041
|
+
[["插件配置", "Plugin configuration"], "plugins"],
|
|
8668
9042
|
[["专家", "Experts"], "experts"],
|
|
8669
9043
|
[["技能", "Skills"], "skills"],
|
|
8670
9044
|
[["插件", "Plugins"], "plugins"],
|
|
@@ -8966,6 +9340,160 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
8966
9340
|
}, "michengai-codex-ui: usage navigation");
|
|
8967
9341
|
}
|
|
8968
9342
|
//#endregion
|
|
9343
|
+
//#region src/client/PluginConfigSection.tsx
|
|
9344
|
+
function bindPluginConfigLocale(bind) {
|
|
9345
|
+
const cache = /* @__PURE__ */ new Map();
|
|
9346
|
+
return (ns) => {
|
|
9347
|
+
const existing = cache.get(ns);
|
|
9348
|
+
if (existing !== void 0) return existing;
|
|
9349
|
+
const translate = bind(ns);
|
|
9350
|
+
cache.set(ns, translate);
|
|
9351
|
+
return translate;
|
|
9352
|
+
};
|
|
9353
|
+
}
|
|
9354
|
+
const FORWARDED_CONFIG_SLOTS = /* @__PURE__ */ new Set([
|
|
9355
|
+
"plugins.item",
|
|
9356
|
+
"plugins.bundle.config",
|
|
9357
|
+
"plugins.row.config"
|
|
9358
|
+
]);
|
|
9359
|
+
var SlotEntryBoundary = class extends react.Component {
|
|
9360
|
+
state = { failed: false };
|
|
9361
|
+
static getDerivedStateFromError() {
|
|
9362
|
+
return { failed: true };
|
|
9363
|
+
}
|
|
9364
|
+
render() {
|
|
9365
|
+
return this.state.failed ? this.props.fallback : this.props.children;
|
|
9366
|
+
}
|
|
9367
|
+
};
|
|
9368
|
+
function isSnapshotSource(value) {
|
|
9369
|
+
return typeof value === "object" && value !== null && typeof value.getSnapshot === "function" && typeof value.subscribe === "function";
|
|
9370
|
+
}
|
|
9371
|
+
function hookPropName(name) {
|
|
9372
|
+
return `use${name[0]?.toUpperCase() ?? ""}${name.slice(1)}`;
|
|
9373
|
+
}
|
|
9374
|
+
function bindSnapshotSelector(source) {
|
|
9375
|
+
const subscribe = (listener) => source.subscribe(listener);
|
|
9376
|
+
const getSnapshot = () => source.getSnapshot();
|
|
9377
|
+
return function useSelected(selector = (value) => value) {
|
|
9378
|
+
return (0, react.useSyncExternalStore)(subscribe, () => selector(getSnapshot()), () => selector(getSnapshot()));
|
|
9379
|
+
};
|
|
9380
|
+
}
|
|
9381
|
+
function bindHookSources(hooks, bound) {
|
|
9382
|
+
for (const [name, source] of Object.entries(hooks ?? {})) if (isSnapshotSource(source)) bound[hookPropName(name)] = bindSnapshotSelector(source);
|
|
9383
|
+
}
|
|
9384
|
+
function bindInjectFace(inject) {
|
|
9385
|
+
try {
|
|
9386
|
+
if (typeof inject !== "function") return {};
|
|
9387
|
+
const face = inject();
|
|
9388
|
+
if (typeof face !== "object" || face === null) return {};
|
|
9389
|
+
const { hooks, keyedHooks, ...rest } = face;
|
|
9390
|
+
const bound = { ...rest };
|
|
9391
|
+
if (keyedHooks !== void 0) bound.keyedHooks = keyedHooks;
|
|
9392
|
+
bindHookSources(hooks, bound);
|
|
9393
|
+
bindHookSources(keyedHooks, bound);
|
|
9394
|
+
return bound;
|
|
9395
|
+
} catch {
|
|
9396
|
+
return {};
|
|
9397
|
+
}
|
|
9398
|
+
}
|
|
9399
|
+
function DelegatedOfficialSlot({ slots, name, owner, opts, bindLocale }) {
|
|
9400
|
+
(0, react.useSyncExternalStore)((listener) => slots.subscribe(name, listener), () => slots.getVersion(name));
|
|
9401
|
+
const nodes = slots.entriesOfSlot(name).filter((entry) => opts?.entryKey !== void 0 ? entry.options.key === opts.entryKey : opts?.only === void 0 || entry.options.id === opts.only).flatMap((entry, index) => {
|
|
9402
|
+
if (typeof entry.component !== "function") return [];
|
|
9403
|
+
const t = entry.locale !== void 0 && bindLocale !== void 0 ? bindLocale(entry.locale) : void 0;
|
|
9404
|
+
return [(0, react.createElement)(SlotEntryBoundary, {
|
|
9405
|
+
key: entry.options.key ?? entry.options.id ?? String(index),
|
|
9406
|
+
fallback: opts?.fallback ?? null,
|
|
9407
|
+
children: (0, react.createElement)(entry.component, {
|
|
9408
|
+
...owner,
|
|
9409
|
+
...bindInjectFace(entry.inject),
|
|
9410
|
+
...t === void 0 ? {} : { t }
|
|
9411
|
+
})
|
|
9412
|
+
})];
|
|
9413
|
+
});
|
|
9414
|
+
return nodes.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9415
|
+
"data-slot": name,
|
|
9416
|
+
style: { display: "contents" },
|
|
9417
|
+
children: nodes
|
|
9418
|
+
}) : opts?.fallback ?? null;
|
|
9419
|
+
}
|
|
9420
|
+
function wrapRenderSlot(settingsRenderSlot, slots, bindLocale) {
|
|
9421
|
+
return (name, owner = {}, opts) => {
|
|
9422
|
+
if (slots !== void 0 && FORWARDED_CONFIG_SLOTS.has(name)) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DelegatedOfficialSlot, {
|
|
9423
|
+
slots,
|
|
9424
|
+
name,
|
|
9425
|
+
owner,
|
|
9426
|
+
opts,
|
|
9427
|
+
bindLocale
|
|
9428
|
+
});
|
|
9429
|
+
return typeof settingsRenderSlot === "function" ? settingsRenderSlot(name, owner, opts) : null;
|
|
9430
|
+
};
|
|
9431
|
+
}
|
|
9432
|
+
/** 设置里的官方插件管理页副本。官方卡片要 inject 和文案;单卡崩溃不得拆掉整页。 */
|
|
9433
|
+
function PluginConfigSection({ Official, officialLabel, slots, bindLocale, ...official }) {
|
|
9434
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
|
|
9435
|
+
className: "dcu-plugin-config",
|
|
9436
|
+
"aria-label": officialLabel,
|
|
9437
|
+
children: (0, react.createElement)(Official, {
|
|
9438
|
+
...official,
|
|
9439
|
+
renderSlot: wrapRenderSlot(official.renderSlot, slots, bindLocale)
|
|
9440
|
+
})
|
|
9441
|
+
});
|
|
9442
|
+
}
|
|
9443
|
+
function createPluginConfigSection(Official, officialLabel, slots, bindLocale) {
|
|
9444
|
+
return function PluginConfigSectionBound(props) {
|
|
9445
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PluginConfigSection, {
|
|
9446
|
+
Official,
|
|
9447
|
+
officialLabel: officialLabel(),
|
|
9448
|
+
slots,
|
|
9449
|
+
bindLocale,
|
|
9450
|
+
...props
|
|
9451
|
+
});
|
|
9452
|
+
};
|
|
9453
|
+
}
|
|
9454
|
+
//#endregion
|
|
9455
|
+
//#region src/client/plugin-config.ts
|
|
9456
|
+
const PLUGIN_CONFIG_SECTION_ID = "plugin-config";
|
|
9457
|
+
const OFFICIAL_PLUGIN_MANAGER_NS = "pluginManager";
|
|
9458
|
+
function officialPluginsPage(entry) {
|
|
9459
|
+
if (entry === void 0 || entry.options.key !== "plugins") return void 0;
|
|
9460
|
+
if (typeof entry.component !== "function" || typeof entry.inject !== "function" || entry.locale !== OFFICIAL_PLUGIN_MANAGER_NS) return void 0;
|
|
9461
|
+
return entry.component;
|
|
9462
|
+
}
|
|
9463
|
+
function registerPluginConfigSection(ctx) {
|
|
9464
|
+
const t = ctx.locale.bind(NS);
|
|
9465
|
+
ctx.slots.inject("settings.section", () => {
|
|
9466
|
+
let current;
|
|
9467
|
+
let remove;
|
|
9468
|
+
const refresh = () => {
|
|
9469
|
+
const entry = ctx.slots.entriesOfSlot("main").find((item) => item.options.key === OFFICIAL_PLUGINS_PANEL_ID);
|
|
9470
|
+
if (entry === current) return;
|
|
9471
|
+
remove?.();
|
|
9472
|
+
remove = void 0;
|
|
9473
|
+
current = entry;
|
|
9474
|
+
const Official = officialPluginsPage(entry);
|
|
9475
|
+
if (Official === void 0 || entry?.inject === void 0 || entry.locale !== OFFICIAL_PLUGIN_MANAGER_NS) return;
|
|
9476
|
+
remove = ctx.slots.register({
|
|
9477
|
+
name: "settings.section",
|
|
9478
|
+
id: PLUGIN_CONFIG_SECTION_ID,
|
|
9479
|
+
order: 16,
|
|
9480
|
+
label: () => t("settings.pluginConfig"),
|
|
9481
|
+
locale: entry.locale,
|
|
9482
|
+
inject: entry.inject
|
|
9483
|
+
}, createPluginConfigSection(Official, () => t("settings.pluginConfig"), ctx.slots, bindPluginConfigLocale((ns) => {
|
|
9484
|
+
const translate = ctx.locale.bind(ns);
|
|
9485
|
+
return (key, params) => translate(key, params);
|
|
9486
|
+
})));
|
|
9487
|
+
};
|
|
9488
|
+
const unsubscribe = ctx.slots.subscribe("main", refresh);
|
|
9489
|
+
refresh();
|
|
9490
|
+
return () => {
|
|
9491
|
+
unsubscribe();
|
|
9492
|
+
remove?.();
|
|
9493
|
+
};
|
|
9494
|
+
});
|
|
9495
|
+
}
|
|
9496
|
+
//#endregion
|
|
8969
9497
|
//#region src/client/settings-page-model.ts
|
|
8970
9498
|
function settingsGroup(id) {
|
|
8971
9499
|
if (/archive|about|^usage-statistics$/.test(id)) return "records";
|
|
@@ -9067,6 +9595,10 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
9067
9595
|
.dcu-settings-inner:has(.dcu-usage-section){height:100%;display:flex;flex-direction:column;padding-bottom:0}
|
|
9068
9596
|
.dcu-settings-inner:has(.dcu-usage-section)>.dcu-settings-heading{display:none}
|
|
9069
9597
|
.dcu-settings-inner:has(.dcu-usage-section)>[data-slot="settings.section"]{display:flex;flex:1;min-height:0;flex-direction:column}
|
|
9598
|
+
.dcu-plugin-config [data-plugin-panel]{height:auto;padding:0;overflow:visible;align-items:stretch;gap:24px}
|
|
9599
|
+
.dcu-plugin-config [data-plugin-panel]>*{max-width:none}
|
|
9600
|
+
.dcu-plugin-config [data-plugin-panel]>header :is(h1,p){display:none}
|
|
9601
|
+
.dcu-plugin-config [data-plugin-panel]>header{justify-content:flex-end}
|
|
9070
9602
|
.dcu-usage-section{display:flex;flex-direction:column;flex:1;min-height:0;gap:16px}
|
|
9071
9603
|
.dcu-usage-section h1{font-size:24px;font-weight:500;margin:0}
|
|
9072
9604
|
.dcu-usage-section p{color:var(--sp-muted)}
|
|
@@ -9127,7 +9659,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
9127
9659
|
const rows = (0, react.useSyncExternalStore)(sections.subscribe, sections.getSnapshot);
|
|
9128
9660
|
const steps = (0, react.useSyncExternalStore)(onboarding.subscribe, onboarding.getSnapshot);
|
|
9129
9661
|
const connection = (0, react.useSyncExternalStore)(connectionState.subscribe, connectionState.getSnapshot);
|
|
9130
|
-
const onboardingActive = useSessions((state) =>
|
|
9662
|
+
const onboardingActive = useSessions((state) => isBlankOnboardingSession(state));
|
|
9131
9663
|
const [completed, setCompleted] = (0, react.useState)(() => /* @__PURE__ */ new Set());
|
|
9132
9664
|
const [open, setOpen] = (0, react.useState)(false);
|
|
9133
9665
|
const [activeId, setActiveId] = (0, react.useState)("general");
|
|
@@ -9282,6 +9814,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
9282
9814
|
if (main.current !== null) main.current.scrollTop = 0;
|
|
9283
9815
|
}, [active?.id]);
|
|
9284
9816
|
const visible = filterSettingsRows(rows, query);
|
|
9817
|
+
const ownTitle = active?.id === "general" ? t("settings.general") : active?.id === "plugin-config" ? t("settings.pluginConfig") : void 0;
|
|
9285
9818
|
const connectionIndicator = connection === "disconnected" ? "disconnected" : connection === "connecting" ? "connecting" : recovered ? "recovered" : void 0;
|
|
9286
9819
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
9287
9820
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: settingsPageStyles }),
|
|
@@ -9391,8 +9924,8 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
9391
9924
|
"data-settings-section": active?.id,
|
|
9392
9925
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
|
|
9393
9926
|
className: "dcu-settings-heading",
|
|
9394
|
-
"data-own-title":
|
|
9395
|
-
children: [
|
|
9927
|
+
"data-own-title": ownTitle !== void 0,
|
|
9928
|
+
children: [ownTitle !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", { children: ownTitle }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9396
9929
|
className: "dcu-settings-actions",
|
|
9397
9930
|
children: renderSlot("settings.action", {})
|
|
9398
9931
|
})]
|
|
@@ -10324,7 +10857,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
10324
10857
|
}
|
|
10325
10858
|
/** Archive Manager replaces the official ui-workspace row with this optional service. */
|
|
10326
10859
|
function startWorkspaceSession(ctx, workspaceId) {
|
|
10327
|
-
const uiWorkspace = ctx
|
|
10860
|
+
const uiWorkspace = probeService(ctx, "uiWorkspace");
|
|
10328
10861
|
if (hasStartSession(uiWorkspace)) {
|
|
10329
10862
|
uiWorkspace.startSession(workspaceId);
|
|
10330
10863
|
return;
|
|
@@ -10337,6 +10870,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
10337
10870
|
}
|
|
10338
10871
|
/** 替换 DSH 的官方 sidebar 插槽,不修改 DSH 源码或会话数据。 */
|
|
10339
10872
|
function apply(ctx) {
|
|
10873
|
+
Object.assign(globalThis, { __dcuCurrentSessionId: currentSessionId });
|
|
10340
10874
|
const widthStorage = browserStorage();
|
|
10341
10875
|
if (widthStorage) initializeComposerWidth(widthStorage);
|
|
10342
10876
|
ctx.effect(() => ctx.locale.register(NS, {
|
|
@@ -10348,6 +10882,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
10348
10882
|
registerInputHistory(ctx);
|
|
10349
10883
|
registerSettingsPage(ctx);
|
|
10350
10884
|
registerUsageStatistics(ctx);
|
|
10885
|
+
registerPluginConfigSection(ctx);
|
|
10351
10886
|
const connection = ctx.get("connection");
|
|
10352
10887
|
const openPath = (path) => openPathInHost(connection, path);
|
|
10353
10888
|
ctx.effect(() => observeSlimSidebar(), "michengai-codex-ui: slim sidebar");
|
|
@@ -10359,7 +10894,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
10359
10894
|
ctx.effect(() => observeConversationHeader(), "michengai-codex-ui: conversation header");
|
|
10360
10895
|
ctx.effect(() => observeOfficialTurnNavigators(), "michengai-codex-ui: official turn navigator");
|
|
10361
10896
|
const newConversationDraft = createDraftPresenceSource(ctx.sessions.list, () => {
|
|
10362
|
-
const id = ctx.sessions.list.getSnapshot()
|
|
10897
|
+
const id = currentSessionId(ctx.sessions.list.getSnapshot());
|
|
10363
10898
|
const binding = id === void 0 ? void 0 : ctx.sessions.binding(id);
|
|
10364
10899
|
return binding === void 0 ? void 0 : ctx.conversation.input.for(binding.ctx).state;
|
|
10365
10900
|
});
|
|
@@ -10399,12 +10934,12 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
10399
10934
|
inject: () => ({
|
|
10400
10935
|
newConversationDraft,
|
|
10401
10936
|
prefillNewConversation: (text) => {
|
|
10402
|
-
const id = ctx.sessions.list.getSnapshot()
|
|
10937
|
+
const id = currentSessionId(ctx.sessions.list.getSnapshot());
|
|
10403
10938
|
const binding = id === void 0 ? void 0 : ctx.sessions.binding(id);
|
|
10404
10939
|
return prefillNewConversation(binding === void 0 ? void 0 : ctx.conversation.input.for(binding.ctx), text);
|
|
10405
10940
|
},
|
|
10406
10941
|
openSession: (sessionId) => {
|
|
10407
|
-
openConversation(ctx
|
|
10942
|
+
openConversation(ctx, ctx.layout, sessionId);
|
|
10408
10943
|
},
|
|
10409
10944
|
startSession: (workspaceId) => {
|
|
10410
10945
|
startWorkspaceSession(ctx, workspaceId);
|
|
@@ -10434,20 +10969,16 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
10434
10969
|
locale: NS
|
|
10435
10970
|
}, TurnNavigator));
|
|
10436
10971
|
const forkSession = async (sessionId) => {
|
|
10437
|
-
await runHostAction("fork",
|
|
10438
|
-
const childId = await ctx.sessions.fork({
|
|
10439
|
-
sessionId,
|
|
10440
|
-
increaseTitle: true
|
|
10441
|
-
});
|
|
10442
|
-
openConversation(ctx.sessions, ctx.layout, childId);
|
|
10443
|
-
});
|
|
10972
|
+
await runHostAction("fork", () => forkHostSession(ctx, sessionId));
|
|
10444
10973
|
};
|
|
10445
10974
|
const renameSession = async (sessionId, title) => {
|
|
10446
|
-
const session = ctx.sessions.binding(sessionId)?.session;
|
|
10447
|
-
if (session === void 0) throw new UserFacingError(t("sessions.unknown"));
|
|
10448
10975
|
await runHostAction("rename", async () => {
|
|
10449
|
-
|
|
10450
|
-
|
|
10976
|
+
try {
|
|
10977
|
+
await renameHostSession(ctx, sessionId, title);
|
|
10978
|
+
} catch (reason) {
|
|
10979
|
+
if (reason instanceof UnknownSessionError) throw new UserFacingError(t("sessions.unknown"));
|
|
10980
|
+
throw reason;
|
|
10981
|
+
}
|
|
10451
10982
|
});
|
|
10452
10983
|
};
|
|
10453
10984
|
const deleteSession = async (sessionId) => {
|
|
@@ -10458,7 +10989,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
10458
10989
|
if (!result.ok) throw result.error === void 0 ? new UserFacingError(t("sessions.deleteUnavailable")) : result.error;
|
|
10459
10990
|
});
|
|
10460
10991
|
};
|
|
10461
|
-
const archiveSession = (sessionId) => runHostAction("archive", () => ctx
|
|
10992
|
+
const archiveSession = (sessionId) => runHostAction("archive", () => archiveHostSession(ctx, sessionId));
|
|
10462
10993
|
const moveSession = async (sessionId, targetWorkspaceId) => {
|
|
10463
10994
|
try {
|
|
10464
10995
|
await requestSessionMove(sessionId, targetWorkspaceId);
|
|
@@ -10479,22 +11010,36 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
10479
11010
|
if (prompt === "") throw new UserFacingError(t("connectors.promptRequired"));
|
|
10480
11011
|
const workspaces = ctx.workspaces.list.getSnapshot();
|
|
10481
11012
|
const sessionSnapshot = ctx.sessions.list.getSnapshot();
|
|
10482
|
-
const
|
|
10483
|
-
const currentWorkspaceId =
|
|
11013
|
+
const selectedSessionId = currentSessionId(sessionSnapshot);
|
|
11014
|
+
const currentWorkspaceId = selectedSessionId === void 0 ? void 0 : workspaces.items.find((workspace) => workspace.sessionIds.includes(selectedSessionId))?.workspaceId;
|
|
10484
11015
|
const baselinesReady = workspaceBaselinesReady(workspaces, sessionSnapshot);
|
|
10485
11016
|
const targetWorkspaceId = currentWorkspaceId ?? (baselinesReady ? recentWorkspaceId(workspaces.items, sessionSnapshot.byId) : void 0);
|
|
10486
11017
|
if (targetWorkspaceId === void 0 && !baselinesReady) throw new UserFacingError(t("connectors.workspacesLoading"));
|
|
10487
11018
|
if (targetWorkspaceId === void 0) throw new UserFacingError(t("connectors.workspaceRequired"));
|
|
10488
|
-
const uiWorkspace = ctx
|
|
10489
|
-
const workspaceNavigation = hasConnectWorkspace(uiWorkspace) ? uiWorkspace : hasConnectWorkspace(ctx.workspaces) ? ctx.workspaces : void 0;
|
|
10490
|
-
if (workspaceNavigation === void 0) throw new UserFacingError(t("connectors.workspaceUnavailable"));
|
|
10491
|
-
const sessionId = await workspaceNavigation.connectWorkspace(targetWorkspaceId);
|
|
11019
|
+
const uiWorkspace = probeService(ctx, "uiWorkspace");
|
|
10492
11020
|
const conversation = ctx.get("conversation");
|
|
10493
11021
|
if (conversation === void 0) throw new UserFacingError(t("connectors.conversationUnavailable"));
|
|
10494
|
-
|
|
10495
|
-
|
|
10496
|
-
|
|
10497
|
-
|
|
11022
|
+
try {
|
|
11023
|
+
if (hasOpenWorkspace(uiWorkspace)) {
|
|
11024
|
+
await Promise.resolve(uiWorkspace.openWorkspace(targetWorkspaceId, (id) => {
|
|
11025
|
+
const binding = ctx.sessions.binding(id);
|
|
11026
|
+
if (binding?.ctx === void 0) throw new UnknownSessionError();
|
|
11027
|
+
conversation.input.for(binding.ctx).setDraft(prompt);
|
|
11028
|
+
}));
|
|
11029
|
+
selectGlobalPanel(ctx.layout, null);
|
|
11030
|
+
return;
|
|
11031
|
+
}
|
|
11032
|
+
const workspaceNavigation = hasConnectWorkspace(uiWorkspace) ? uiWorkspace : hasConnectWorkspace(ctx.workspaces) ? ctx.workspaces : void 0;
|
|
11033
|
+
if (workspaceNavigation === void 0) throw new UserFacingError(t("connectors.workspaceUnavailable"));
|
|
11034
|
+
const sessionId = await workspaceNavigation.connectWorkspace(targetWorkspaceId);
|
|
11035
|
+
await openConversationWithDraft(ctx, ctx.layout, ctx.sessions, sessionId, (binding) => {
|
|
11036
|
+
if (binding.ctx === void 0) throw new UnknownSessionError();
|
|
11037
|
+
conversation.input.for(binding.ctx).setDraft(prompt);
|
|
11038
|
+
});
|
|
11039
|
+
} catch (reason) {
|
|
11040
|
+
if (reason instanceof UnknownSessionError) throw new UserFacingError(t("connectors.sessionPending"));
|
|
11041
|
+
throw reason;
|
|
11042
|
+
}
|
|
10498
11043
|
};
|
|
10499
11044
|
ctx.slots.inject("sidebar.workspaces", () => ctx.slots.register({
|
|
10500
11045
|
name: "sidebar.workspaces",
|
|
@@ -10509,7 +11054,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
10509
11054
|
moveSession,
|
|
10510
11055
|
openPath,
|
|
10511
11056
|
openSession: (sessionId) => {
|
|
10512
|
-
openConversation(ctx
|
|
11057
|
+
openConversation(ctx, ctx.layout, sessionId);
|
|
10513
11058
|
},
|
|
10514
11059
|
renameSession,
|
|
10515
11060
|
renameWorkspace: (workspaceId, title) => ctx.workspaces.rename(workspaceId, title),
|
|
@@ -10528,7 +11073,7 @@ html[data-dsh-native-backdrop=mica] .dcu-settings-page,html[data-dsh-native-back
|
|
|
10528
11073
|
const openDeepLink = () => {
|
|
10529
11074
|
if (opened || ctx.sessions.list.getSnapshot().byId[sessionId] === void 0) return;
|
|
10530
11075
|
opened = true;
|
|
10531
|
-
openConversation(ctx
|
|
11076
|
+
openConversation(ctx, ctx.layout, sessionId);
|
|
10532
11077
|
};
|
|
10533
11078
|
openDeepLink();
|
|
10534
11079
|
return ctx.sessions.list.subscribe(openDeepLink);
|