dsh-session-manager 0.5.4 → 0.6.3
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 +81 -0
- package/README.md +16 -2
- package/README.zh.md +16 -4
- package/lib/annotation-store.js +1 -1
- package/lib/client.js +1768 -213
- package/lib/compat/dsh-adapter.js +55 -0
- package/lib/index.js +83 -2
- package/package.json +2 -2
package/lib/client.js
CHANGED
|
@@ -21,7 +21,17 @@ window.__ModuleLoader__.load({
|
|
|
21
21
|
const P = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
22
22
|
if (typeof window !== "undefined") {
|
|
23
23
|
window.__smReact = React;
|
|
24
|
-
|
|
24
|
+
let rdomModule = null;
|
|
25
|
+
try { rdomModule = require("react-dom"); } catch (_) {}
|
|
26
|
+
if (!rdomModule) {
|
|
27
|
+
try { rdomModule = require("react-dom/client"); } catch (_) {}
|
|
28
|
+
}
|
|
29
|
+
if (!rdomModule && typeof window.ReactDOM !== "undefined") {
|
|
30
|
+
rdomModule = window.ReactDOM;
|
|
31
|
+
}
|
|
32
|
+
window.__smReactDOM = (rdomModule && typeof rdomModule.createPortal === "function")
|
|
33
|
+
? rdomModule
|
|
34
|
+
: (typeof React.createPortal === "function" ? React : null);
|
|
25
35
|
// Tiny imperative portal helper: takes a React element + a host
|
|
26
36
|
// DOM node, creates a React root on the host (lazily), and re-renders
|
|
27
37
|
// the element into it on each call. Used by ConfirmDialog to escape
|
|
@@ -41,16 +51,36 @@ window.__ModuleLoader__.load({
|
|
|
41
51
|
}
|
|
42
52
|
// Monotonically-increasing z-index for popup dialogs so the most-recently
|
|
43
53
|
// opened popup always sits on top of any previously opened popup. The
|
|
44
|
-
// CSS-defined z-index values (
|
|
54
|
+
// CSS-defined z-index values (confirm 10000 / migrate 10001 / annotation +
|
|
45
55
|
// bulk 10002) are static; without a counter the user can open an
|
|
46
56
|
// annotation popup (10002) after a confirm popup (10000) and the older
|
|
47
57
|
// confirm stays below. Each dialog component claims a fresh slot from
|
|
48
58
|
// this counter on mount, writes it to inline style.zIndex, and never
|
|
49
59
|
// recycles within a session, so the most-recently opened popup is
|
|
50
60
|
// always the topmost one.
|
|
51
|
-
|
|
61
|
+
// These values are all resolved INSIDE the #dsh-session-manager-overlay-root
|
|
62
|
+
// stacking context (see the layering contract in the stylesheet): the root
|
|
63
|
+
// itself sits at 1050, below DSH's 1100 floating tier, so the absolute size of
|
|
64
|
+
// the numbers here never competes with DSH's own tooltips and menus.
|
|
65
|
+
let dialogZStackCounter = 100000;
|
|
52
66
|
function nextDialogZ() { return ++dialogZStackCounter; }
|
|
53
67
|
|
|
68
|
+
// Wrap an anchor in DSH's own Tooltip primitive (falls back to the bare
|
|
69
|
+
// node when the primitive is unavailable).
|
|
70
|
+
//
|
|
71
|
+
// `portal: true` renders the bubble under document.body, which escapes the
|
|
72
|
+
// plugin dialog's own overflow clipping -- but DSH's bubble paints at a
|
|
73
|
+
// hard-coded z-index 1100 and exposes no class hook, so it can only stay
|
|
74
|
+
// visible while every plugin surface stays BELOW 1100. Keep the panel
|
|
75
|
+
// (1020) and the overlay root (1050) inside that gap; see the layering
|
|
76
|
+
// contract in the stylesheet.
|
|
77
|
+
function renderTip(label, node, side = "bottom", portal = true) {
|
|
78
|
+
if (!label || !node) return node;
|
|
79
|
+
if (P && typeof P.Tooltip === "function") {
|
|
80
|
+
return h(P.Tooltip, { label, side, portal, align: "center" }, node);
|
|
81
|
+
}
|
|
82
|
+
return node;
|
|
83
|
+
}
|
|
54
84
|
|
|
55
85
|
const NS = "session-manager";
|
|
56
86
|
const API = "/session-manager/api";
|
|
@@ -119,6 +149,7 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
119
149
|
"marks.tags.clear": "清空标签",
|
|
120
150
|
"marks.note.clear": "清空备注",
|
|
121
151
|
"header.aria": "会话操作",
|
|
152
|
+
"header.more": "更多操作",
|
|
122
153
|
"menu.open": "打开",
|
|
123
154
|
"menu.archive": "归档会话",
|
|
124
155
|
"menu.unarchive": "移出归档",
|
|
@@ -129,6 +160,42 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
129
160
|
"footer.label": "会话管理",
|
|
130
161
|
"panel.title": "会话管理",
|
|
131
162
|
"panel.github.title": "欢迎Star和提交Issue",
|
|
163
|
+
"panel.update.title": "检查更新",
|
|
164
|
+
"panel.update.badge": "有新版本可用",
|
|
165
|
+
"update.title": "检查更新",
|
|
166
|
+
"update.newVersion": "发现新版本",
|
|
167
|
+
"update.currentVersion": "当前版本",
|
|
168
|
+
"update.latestVersion": "最新版本",
|
|
169
|
+
"update.isLatest": "当前已是最新版本",
|
|
170
|
+
"update.checking": "正在检查更新…",
|
|
171
|
+
"update.installing": "正在通过插件管理器安装新版本…",
|
|
172
|
+
"update.btn.check": "检查更新",
|
|
173
|
+
"update.btn.update": "更新到 v{version}",
|
|
174
|
+
"update.btn.updating": "更新中…",
|
|
175
|
+
"update.btn.later": "稍后",
|
|
176
|
+
"update.btn.done": "好的",
|
|
177
|
+
"update.btn.retry": "重试",
|
|
178
|
+
"update.btn.close": "关闭",
|
|
179
|
+
"update.done.restart": "更新已安装(v{from} → v{to}),重启 DSH 后生效。",
|
|
180
|
+
"update.done.applied": "更新已应用!",
|
|
181
|
+
"update.error": "更新遇到问题",
|
|
182
|
+
"update.autoCheck": "自动检查更新",
|
|
183
|
+
"update.autoCheck.enable": "开启",
|
|
184
|
+
"settings.registry": "安装源",
|
|
185
|
+
"settings.registry.npm": "npm 官方源 registry.npmjs.org",
|
|
186
|
+
"settings.registry.china": "中国大陆镜像源 registry.npmmirror.com",
|
|
187
|
+
"settings.title": "会话管理",
|
|
188
|
+
"settings.pluginName": "dsh-session-manager",
|
|
189
|
+
"settings.versionSection": "插件版本",
|
|
190
|
+
"settings.prefSection": "偏好设置",
|
|
191
|
+
"settings.dialogOpacity": "弹窗透明度",
|
|
192
|
+
"settings.dialogOpacity.hint": "仅调整插件弹窗的背景透明度;文字、按钮、输入框和边框保持不透明。",
|
|
193
|
+
"settings.dialogOpacity.value": "{value}%",
|
|
194
|
+
"settings.dialogOpacity.reset": "恢复默认",
|
|
195
|
+
"settings.projectSection": "项目",
|
|
196
|
+
"settings.github": "GitHub 仓库",
|
|
197
|
+
"settings.star": "感谢Star",
|
|
198
|
+
"settings.feedback": "欢迎反馈",
|
|
132
199
|
"panel.search": "搜索标题、ID、标签或备注",
|
|
133
200
|
"panel.workspace": "工作区",
|
|
134
201
|
"panel.workspace.all": "全部工作区",
|
|
@@ -303,6 +370,7 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
303
370
|
"marks.tags.clear": "Clear tags",
|
|
304
371
|
"marks.note.clear": "Clear note",
|
|
305
372
|
"header.aria": "Session actions",
|
|
373
|
+
"header.more": "More actions",
|
|
306
374
|
"menu.open": "Open",
|
|
307
375
|
"menu.archive": "Archive session",
|
|
308
376
|
"menu.unarchive": "Unarchive session",
|
|
@@ -313,6 +381,42 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
313
381
|
"footer.label": "Sessions",
|
|
314
382
|
"panel.title": "Session manager",
|
|
315
383
|
"panel.github.title": "Star the project or open an issue",
|
|
384
|
+
"panel.update.title": "Check for updates",
|
|
385
|
+
"panel.update.badge": "New version available",
|
|
386
|
+
"update.title": "Check for Updates",
|
|
387
|
+
"update.newVersion": "New Version Available",
|
|
388
|
+
"update.currentVersion": "Current Version",
|
|
389
|
+
"update.latestVersion": "Latest Version",
|
|
390
|
+
"update.isLatest": "Up to date",
|
|
391
|
+
"update.checking": "Checking for updates…",
|
|
392
|
+
"update.installing": "Installing update via plugin manager…",
|
|
393
|
+
"update.btn.check": "Check for Updates",
|
|
394
|
+
"update.btn.update": "Update to v{version}",
|
|
395
|
+
"update.btn.updating": "Updating…",
|
|
396
|
+
"update.btn.later": "Later",
|
|
397
|
+
"update.btn.done": "OK",
|
|
398
|
+
"update.btn.retry": "Retry",
|
|
399
|
+
"update.btn.close": "Close",
|
|
400
|
+
"update.done.restart": "Update installed (v{from} → v{to}). Please restart DSH.",
|
|
401
|
+
"update.done.applied": "Update applied successfully!",
|
|
402
|
+
"update.error": "Update Error",
|
|
403
|
+
"update.autoCheck": "Automatically check for updates",
|
|
404
|
+
"update.autoCheck.enable": "Enable",
|
|
405
|
+
"settings.registry": "Install Source",
|
|
406
|
+
"settings.registry.npm": "npm official registry.npmjs.org",
|
|
407
|
+
"settings.registry.china": "China mainland mirror registry.npmmirror.com",
|
|
408
|
+
"settings.title": "Session Manager",
|
|
409
|
+
"settings.pluginName": "dsh-session-manager",
|
|
410
|
+
"settings.versionSection": "Plugin Version",
|
|
411
|
+
"settings.prefSection": "Preferences",
|
|
412
|
+
"settings.dialogOpacity": "Dialog opacity",
|
|
413
|
+
"settings.dialogOpacity.hint": "Adjusts the plugin dialog background only; text, buttons, inputs and borders stay opaque.",
|
|
414
|
+
"settings.dialogOpacity.value": "{value}%",
|
|
415
|
+
"settings.dialogOpacity.reset": "Reset to default",
|
|
416
|
+
"settings.projectSection": "Project",
|
|
417
|
+
"settings.github": "GitHub Repository",
|
|
418
|
+
"settings.star": "Star on GitHub",
|
|
419
|
+
"settings.feedback": "Feedback / Issues",
|
|
316
420
|
"panel.search": "Search title, ID, tags or notes",
|
|
317
421
|
"panel.workspace": "Workspace",
|
|
318
422
|
"panel.workspace.all": "All workspaces",
|
|
@@ -440,23 +544,26 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
440
544
|
".sm-filter{display:flex;gap:4px;flex-wrap:wrap}",
|
|
441
545
|
".sm-filterBtn{cursor:pointer;display:inline-flex;align-items:center;color:var(--dsw-alias-label-secondary);background:0 0;border:1px solid var(--dsw-alias-border-l2);border-radius:999px;height:28px;padding:3px 10px;font-size:12px;line-height:18px;white-space:nowrap;box-sizing:border-box}",
|
|
442
546
|
".sm-filterBtn:hover{background:var(--dsw-alias-interactive-bg-hover)}",
|
|
443
|
-
".sm-filterBtn.sm-on{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-
|
|
547
|
+
".sm-filterBtn.sm-on{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-module-platform);border-color:transparent}",
|
|
444
548
|
".sm-list{display:flex;flex-direction:column;gap:4px;min-height:0;overflow:auto;flex:1}",
|
|
445
549
|
".sm-row{box-sizing:border-box;display:flex;align-items:center;gap:10px;padding:8px 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:10px}",
|
|
446
550
|
".sm-row:hover{background:var(--dsw-alias-interactive-bg-hover)}",
|
|
447
|
-
".sm-rowCurrent{border-color:var(--dsw-alias-
|
|
551
|
+
".sm-rowCurrent{border-color:var(--dsw-alias-state-business-primary,var(--dsw-alias-label-secondary))}",
|
|
448
552
|
".sm-rowMain{min-width:0;display:flex;flex-direction:column;gap:2px;flex:1 1 280px}",
|
|
449
553
|
".sm-rowTitle{color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px;display:flex;align-items:center;gap:6px;min-width:0}",
|
|
450
554
|
".sm-rowTitle>span:first-child{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}",
|
|
451
555
|
".sm-rowMeta{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}",
|
|
452
556
|
".sm-rowActions{display:flex;gap:4px;flex:none;flex-wrap:wrap;justify-content:flex-end}",
|
|
453
557
|
".sm-badge{flex:none;border-radius:999px;padding:0 6px;font-size:10px;line-height:16px}",
|
|
454
|
-
".sm-badgeArchived{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-
|
|
455
|
-
".sm-badgeRunning{color:var(--dsw-alias-state-
|
|
456
|
-
".sm-badgeCurrent{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
558
|
+
".sm-badgeArchived{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-markdown-tag)}",
|
|
559
|
+
".sm-badgeRunning{color:var(--dsw-alias-state-warn-label,#dd8629);background:var(--dsw-alias-state-warn-tertiary,#fef5e7)}",
|
|
560
|
+
".sm-badgeCurrent{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-markdown-tag)}",
|
|
561
|
+
// The former .sm-danger / .sm-dangerText rules were removed: no element
|
|
562
|
+
// ever carried those classes (dead CSS) and they were the only colour
|
|
563
|
+
// !important declarations that could have fought a theme. Danger-coloured
|
|
564
|
+
// affordances use .sm-headerBtnDanger / .sm-rowBtnDanger /
|
|
565
|
+
// .sm-nativeDialogDanger / .sm-bulkBtnDanger, all plain DSH tokens.
|
|
566
|
+
".sm-warn{display:flex;align-items:flex-start;gap:8px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-state-warn-tertiary,#fef5e7);border:1px solid color-mix(in srgb,var(--dsw-alias-state-warn-primary,#f59e0b) 30%,transparent);border-radius:8px;padding:8px 10px;margin-top:4px}",
|
|
460
567
|
".sm-warn svg{flex:none;margin-top:1px}",
|
|
461
568
|
".sm-error{color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px;min-height:0;margin-top:4px}",
|
|
462
569
|
".sm-foot{display:flex;justify-content:flex-end;align-items:center;gap:8px;width:100%}",
|
|
@@ -467,56 +574,136 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
467
574
|
".sm-moveList{display:flex;flex-direction:column;gap:4px;max-height:200px;overflow:auto}",
|
|
468
575
|
".sm-moveItem{box-sizing:border-box;display:flex;align-items:center;justify-content:space-between;padding:8px 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;cursor:pointer;transition:all .15s}",
|
|
469
576
|
".sm-moveItem:hover{background:var(--dsw-alias-interactive-bg-hover)}",
|
|
470
|
-
".sm-moveItemSelected{border-color:var(--dsw-alias-
|
|
577
|
+
".sm-moveItemSelected{border-color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-state-business-tertiary)}",
|
|
471
578
|
".sm-moveItemName{color:var(--dsw-alias-label-primary);font-size:13px;line-height:18px}",
|
|
472
|
-
".sm-moveItemMeta{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}.sm-panelModal{width:760px;max-width:92vw}.sm-panelModal .sm-rowActions{flex-wrap:wrap;justify-content:flex-end}.sm-headerMenu{position:absolute;right:0;top:100%;z-index:50;display:flex;flex-direction:column;min-width:
|
|
473
|
-
".sm-panelDialog{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);width:600px;max-width:calc(100vw - 32px);max-height:560px;height:auto;box-sizing:border-box;display:flex;flex-direction:column;gap:0;background:var(--dsw-alias-surface-l1,#fff);color:var(--dsw-alias-label-primary,#111);border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:12px;box-shadow:0 16px 48px rgba(0,0,0,.25);overflow:hidden;z-index:9999;opacity:1}.sm-panelDialog .sm-nativeDialogHeader{display:flex;align-items:center;gap:8px;padding:10px 16px;border-bottom:1px solid var(--dsw-alias-border-l2,#eee);flex:none}.sm-panelDialog .sm-nativeDialogTitle{margin:0;font-size:14px;line-height:20px;font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:center;flex:1 1 auto}.sm-panelDialog .sm-nativeDialogHeaderActions{display:flex;align-items:center;gap:6px;flex:none}.sm-panelDialog .sm-nativeDialogTitle{margin:0;font-size:14px;line-height:20px;font-weight:600;text-align:center;flex:1 1 auto}.sm-nativeDialogFooter,.sm-bulkDialog .sm-nativeDialogFooter,.sm-confirmDialog .sm-nativeDialogFooter,.sm-migrateDialog .sm-nativeDialogFooter{display:flex;padding:10px 16px;border-top:1px solid var(--dsw-alias-border-l2,#eee);flex:none;flex-wrap:wrap;justify-content:space-between;gap:6px;margin-top:0}.sm-panelDialog .sm-panel{display:flex;flex-direction:column;gap:6px;min-height:0;flex:1 1 auto;overflow:auto;padding:8px 12px}.sm-panelDialog .sm-list{display:flex;flex-direction:column;gap:2px;flex:1 1 auto;min-height:0;overflow:auto}.sm-panelDialog .sm-row{display:flex;align-items:center;gap:8px;padding:6px 10px;min-height:36px;border:1px solid transparent;border-radius:8px;background:transparent;flex-shrink:0}.sm-panelDialog .sm-row:hover{background:var(--dsw-alias-interactive-bg-hover)}.sm-panelDialog .sm-rowCurrent{background:var(--dsw-alias-fill-l2);border-color:var(--dsw-alias-accent-primary,#356ae6)}.sm-panelDialog .sm-rowMain{display:flex;align-items:stretch!important;gap:8px;min-width:0;flex:1 1 auto;overflow:visible;text-align:left!important}.sm-panelDialog .sm-rowTitle{min-width:0;flex:1 1 0%;width:100%;align-self:stretch;display:flex;align-items:center;justify-content:flex-start;gap:6px;font-size:12px;line-height:16px;overflow:hidden;text-align:left!important;direction:ltr!important}.sm-confirmDialog{z-index:10000}.sm-confirmDialog.sm-nativeDialogLayer{position:fixed;left:calc(50vw + 184px);top:calc(50vh - 90px);width:360px;max-width:calc(100vw - 32px);max-height:none;display:block;align-items:initial;justify-content:initial;box-sizing:border-box;background:transparent;border:0;box-shadow:none;padding:0;inset:calc(50vh - 90px) auto auto calc(50vw + 308px)}.sm-confirmDialog.sm-nativeDialogLayer .sm-nativeDialogBackdrop{display:none}.sm-confirmDialog.sm-nativeDialogLayer .sm-nativeDialog{position:relative;left:auto;top:auto;transform:none;width:auto;box-sizing:border-box;background:var(--dsw-alias-surface-l1,#fff);color:var(--dsw-alias-label-primary,#111);border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:12px;box-shadow:0 16px 48px rgba(0,0,0,.25);padding:0;overflow:hidden;animation:sm-confirmPop .14s ease-out}.sm-confirmDialog .sm-nativeDialogHeader{padding:12px 16px;border-bottom:1px solid var(--dsw-alias-border-l2,#eee)}.sm-confirmDialog .sm-nativeDialogTitle{margin:0;font-size:14px;line-height:20px;font-weight:600;text-align:center;width:100%}.sm-confirmDialog .sm-nativeDialogBody{padding:10px 16px;display:flex;flex-direction:column;gap:8px;min-height:0}.sm-confirmDialog .sm-nativeDialogDescription{font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary);white-space:pre-wrap}.sm-confirmDialog .sm-warn{padding:6px 10px;font-size:12px;line-height:16px;margin-top:0}.sm-confirmDialog .sm-nativeDialogFooter{padding:10px 16px;border-top:1px solid var(--dsw-alias-border-l2,#eee);flex-wrap:wrap;justify-content:space-between;gap:6px;margin-top:0}.sm-confirmDialog .sm-nativeDialogButton{min-height:28px;padding:3px 14px;font-size:12px;line-height:20px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;cursor:pointer;background:transparent;color:var(--dsw-alias-label-primary);text-align:center}.sm-confirmDialog .sm-nativeDialogCancel:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.sm-confirmDialog .sm-nativeDialogConfirm{background:var(--dsw-alias-accent-primary,#356ae6);color:#fff;border-color:var(--dsw-alias-accent-primary,#356ae6)}.sm-confirmDialog .sm-nativeDialogConfirm:hover:not(:disabled){filter:brightness(.94)}@keyframes sm-confirmPop{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.sm-confirmDialog.sm-nativeDialog{padding:0;width:auto;max-width:none}.sm-panelDialog .sm-rowTitle>span:first-child{display:block;min-width:0;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;flex:1 1 auto;width:auto;text-align:left!important;direction:ltr!important;unicode-bidi:plaintext}.sm-panelDialog .sm-rowMeta{display:none}.sm-panelDialog .sm-rowActions{display:flex;gap:2px;flex:none;justify-content:flex-end}.sm-panelDialog .sm-rowActions .sm-rowBtn{min-height:22px;padding:0 7px;font-size:11px;line-height:18px;border-radius:6px;border:1px solid transparent;background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap}.sm-rowBtn.sm-markIcon{padding:0 6px;font-size:13px;line-height:18px}.sm-panelDialog .sm-rowActions .sm-rowBtn:hover{background:var(--dsw-alias-fill-l2);color:var(--dsw-alias-label-primary)}.sm-panelDialog .sm-rowActions .sm-rowBtnDanger{color:var(--dsw-alias-state-error-primary)}.sm-panelDialog .sm-filter{flex:none;padding:6px 12px 4px;gap:4px;display:flex;flex-wrap:wrap}.sm-panelDialog .sm-filterBtn{min-height:24px;padding:2px 10px;font-size:11px;line-height:16px;border-radius:4px;border:1px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer}.sm-panelDialog .sm-filterBtn.sm-on{background:var(--dsw-alias-fill-l2);color:var(--dsw-alias-label-primary)}.sm-panelDialog .sm-badge{font-size:10px;line-height:14px;padding:0 5px;border-radius:6px;flex:none}.sm-panelDialog .sm-error{padding:6px 10px;margin:0;font-size:12px;line-height:16px}.sm-panelDialog .sm-nativeDialogButton{min-height:28px;padding:3px 12px;font-size:12px;line-height:18px;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;background:transparent;color:var(--dsw-alias-label-primary);cursor:pointer}.sm-panelDialog .sm-nativeDialogCancel{background:transparent}.sm-panelDialog .sm-nativeDialogGhost{background:transparent;border-color:var(--dsw-alias-border-l2)}.sm-panelDialog .sm-nativeDialogConfirm{background:var(--dsw-alias-accent-primary,#356ae6);color:#fff;border-color:var(--dsw-alias-accent-primary,#356ae6)}.sm-nativeDialogDanger{background:var(--dsw-alias-state-error-primary,#d92d20);color:#fff;border-color:var(--dsw-alias-state-error-primary,#d92d20)}.sm-nativeDialogDanger:hover:not(:disabled){filter:brightness(.92)}.sm-confirmDialog .sm-nativeDialogDanger,.sm-migrateDialog .sm-nativeDialogDanger,.sm-bulkDialog .sm-nativeDialogDanger{background:var(--dsw-alias-state-error-primary,#d92d20);color:#fff;border-color:var(--dsw-alias-state-error-primary,#d92d20)}.sm-confirmDialog .sm-nativeDialogDanger:hover:not(:disabled),.sm-migrateDialog .sm-nativeDialogDanger:hover:not(:disabled),.sm-bulkDialog .sm-nativeDialogDanger:hover:not(:disabled){filter:brightness(.92)}.sm-panelDialog .sm-empty{padding:18px 0;font-size:12px;color:var(--dsw-alias-label-tertiary);text-align:center}.sm-panelDialog .sm-footError{font-size:11px;color:var(--dsw-alias-state-error-primary);margin-right:auto;line-height:20px}.sm-panelDialog .sm-moveLabel{font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary)}.sm-migrateDialog .sm-nativeDialogFooter{flex-wrap:wrap;justify-content:space-between;gap:6px;margin-top:0}.sm-migrateDialog .sm-migrateChip{cursor:pointer;pointer-events:auto;position:relative;z-index:1}.sm-migrateDialog .sm-migrateChip[disabled]{opacity:.5;cursor:not-allowed}.sm-migrateDialog.sm-nativeDialogLayer{position:fixed;left:50vw;top:auto;bottom:48px;transform:translateX(-50%);width:min(560px,calc(100vw - 32px));max-height:none;display:block;align-items:initial;justify-content:initial;box-sizing:border-box;background:transparent;border:0;box-shadow:none;padding:0;inset:auto;z-index:10001}.sm-migrateDialog.sm-nativeDialogLayer .sm-nativeDialogBackdrop{display:none}.sm-migrateDialog.sm-nativeDialogLayer .sm-nativeDialog{position:relative;left:auto;top:auto;transform:none;width:360px;max-width:calc(100vw - 32px);max-height:min(70vh,520px);box-sizing:border-box;background-color:#ffffff;background-color:var(--dsw-alias-surface-l1,#fff);color:var(--dsw-alias-label-primary,#111);border:1px solid #d4d4d8;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:12px;box-shadow:0 16px 48px rgba(0,0,0,.45);overflow:hidden;padding:0;display:flex;flex-direction:column;gap:0;opacity:1}.sm-migrateDialog{position:fixed;left:50vw;top:auto;bottom:48px;transform:translateX(-50%);width:min(560px,calc(100vw - 32px));max-height:min(70vh,520px);box-sizing:border-box;display:flex;flex-direction:column;gap:0;background-color:#ffffff;background-color:var(--dsw-alias-surface-l1,#fff);color:var(--dsw-alias-label-primary,#111);border:1px solid #d4d4d8;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:12px;box-shadow:0 16px 48px rgba(0,0,0,.45);overflow:hidden;opacity:1;z-index:10001;backdrop-filter:none;-webkit-backdrop-filter:none}.sm-migrateDialog .sm-nativeDialogHeader{padding:12px 18px;border-bottom:1px solid #eee;border-bottom:1px solid var(--dsw-alias-border-l2,#eee);flex:none;background-color:#fff;background-color:var(--dsw-alias-surface-l1,#fff)}.sm-migrateDialog .sm-nativeDialogTitle{margin:0;font-size:14px;line-height:20px;font-weight:600;color:#111;color:var(--dsw-alias-label-primary,#111);text-align:center;width:100%}.sm-migrateDialog .sm-migratePanel{padding:12px 18px;display:flex;flex-direction:column;gap:14px;background-color:#fff;background-color:var(--dsw-alias-surface-l1,#fff)}.sm-migrateDialog .sm-nativeDialogBody{padding:0;background-color:#fff;background-color:var(--dsw-alias-surface-l1,#fff)}.sm-migrateDialog .sm-nativeDialogFooter{padding:10px 16px;border-top:1px solid var(--dsw-alias-border-l2,#eee);flex:none;flex-wrap:wrap;justify-content:space-between;gap:6px;margin-top:0;gap:8px;background-color:#fff;background-color:var(--dsw-alias-surface-l1,#fff)}.sm-migrateDialog .sm-migrateRow>label{color:#444;color:var(--dsw-alias-label-secondary,#444)}.sm-migrateDialog .sm-migrateChip{padding:6px 12px;border-radius:999px;border:1px solid #d4d4d8;border:1px solid var(--dsw-alias-border-l2,#ddd);background-color:#f5f5f5;background-color:var(--dsw-alias-fill-l2,#f5f5f5);color:#111;color:var(--dsw-alias-label-primary,#111);font-size:13px;line-height:18px;cursor:pointer;pointer-events:auto;position:relative;z-index:1;white-space:nowrap}.sm-migrateDialog .sm-migrateChip:hover:not(:disabled){background-color:#e8e8e8;background-color:var(--dsw-alias-interactive-bg-hover,#e8e8e8)}.sm-migrateDialog .sm-migrateChipOn{background-color:#356ae6;background-color:var(--dsw-alias-accent-primary,#356ae6);color:#fff;border-color:#356ae6;border-color:var(--dsw-alias-accent-primary,#356ae6)}.sm-migrateDialog .sm-migrateChip.sm-migrateChipOn:hover:not(:disabled){background-color:#4576f0;background-color:var(--dsw-alias-accent-primary-hover,#4576f0);color:#fff;border-color:#4576f0;border-color:var(--dsw-alias-accent-primary-hover,#4576f0);filter:none}.sm-migrateDialog .sm-migrateChipOn:hover:not(:disabled){filter:brightness(.92)}.sm-migrateDialog .sm-migrateChip[disabled]{opacity:.5;cursor:not-allowed}.sm-migrateDialog .sm-migrateEmpty{color:#888;color:var(--dsw-alias-label-tertiary,#888)}.sm-migrateDialog .sm-migratePreview{padding:10px 12px;border:1px solid #d4d4d8;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;background-color:#f5f5f5;background-color:var(--dsw-alias-fill-l2,#f5f5f5);color:#111;color:var(--dsw-alias-label-primary,#111);font-size:13px;line-height:18px}.sm-migrateDialog .sm-migrateWarn{padding:10px 12px;border:1px solid rgba(217,119,6,.25);border-radius:8px;background-color:rgba(217,119,6,.08);color:#444;color:var(--dsw-alias-label-secondary,#444);font-size:13px;line-height:18px}.sm-migrateDialog .sm-nativeDialogButton{min-height:28px;padding:3px 14px;font-size:12px;line-height:20px;border:1px solid #d4d4d8;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;cursor:pointer;background-color:#fff;background-color:var(--dsw-alias-fill-l2,#fff);color:#111;color:var(--dsw-alias-label-primary,#111);text-align:center}.sm-migrateDialog .sm-nativeDialogButton:hover:not(:disabled){background-color:#e8e8e8;background-color:var(--dsw-alias-interactive-bg-hover,#e8e8e8)}.sm-migrateDialog .sm-nativeDialogConfirm{background-color:#356ae6;background-color:var(--dsw-alias-accent-primary,#356ae6);color:#fff;border-color:#356ae6;border-color:var(--dsw-alias-accent-primary,#356ae6)}.sm-migrateDialog .sm-nativeDialogConfirm:hover:not(:disabled){filter:brightness(.94)}",
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
//
|
|
477
|
-
//
|
|
478
|
-
//
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
579
|
+
".sm-moveItemMeta{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}.sm-panelModal{width:760px;max-width:92vw}.sm-panelModal .sm-rowActions{flex-wrap:wrap;justify-content:flex-end}.sm-headerMenu{position:absolute;right:0;top:100%;margin-top:4px;z-index:50;display:flex;flex-direction:column;min-width:140px;padding:4px;background:var(--dsw-alias-bg-layer-2,#fff);border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;box-shadow:0 4px 16px rgba(0,0,0,.15)}.sm-headerMenuItem{display:flex;align-items:center;gap:8px;width:100%;text-align:left;background:0 0;border:0;border-radius:6px;color:var(--dsw-alias-label-primary,#111);cursor:pointer;padding:6px 10px;font-size:13px;line-height:18px;white-space:nowrap}.sm-headerMenuItem:hover{background:var(--dsw-alias-interactive-bg-hover)}.sm-headerMenuItem .sm-headerBtnIcon{width:20px;min-width:20px;text-align:center;flex-shrink:0}.sm-headerMenuItemDanger{color:var(--dsw-alias-state-error-primary,#d92d20)}.sm-headerMenuItemDanger:hover{background:var(--dsw-alias-interactive-bg-hover-danger)}.sm-headerBtn{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:32px;height:32px;box-sizing:border-box;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-button-floating-fill,#fff);border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;cursor:pointer;padding:0 10px;font-size:13px;line-height:1;white-space:nowrap;transition:background .15s,color .15s,border-color .15s;flex-shrink:0}.sm-headerBtn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l1)}.sm-headerBtn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}.sm-headerBtn svg{width:16px;height:16px;display:block;margin:auto;flex-shrink:0}.sm-migratePanel{display:flex;flex-direction:column;gap:14px;min-width:480px}.sm-migrateRow{display:flex;flex-direction:column;gap:8px}.sm-migrateRow>label{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:16px;font-weight:500}.sm-migrateChips{display:flex;flex-wrap:wrap;gap:6px}.sm-migrateChip{padding:6px 12px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);background:transparent;cursor:pointer;font-size:13px;line-height:18px;color:var(--dsw-alias-label-primary);white-space:nowrap}.sm-migrateChip:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.sm-migrateChip:disabled{opacity:.5;cursor:not-allowed}.sm-migrateChipOn{background:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-label-primary-foreground,#fff);border-color:var(--dsw-alias-state-business-primary)}.sm-migrateEmpty{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.sm-migratePreview{padding:10px 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);font-size:13px;line-height:18px}.sm-migrateWarn{padding:10px 12px;border:1px solid color-mix(in srgb,var(--dsw-alias-state-warn-primary,#f59e0b) 30%,transparent);border-radius:8px;background:var(--dsw-alias-state-warn-tertiary,#fef5e7);color:var(--dsw-alias-label-secondary);font-size:13px;line-height:18px}.sm-migrateList{max-height:200px;overflow:auto;border:1px solid var(--dsw-alias-border-l2);border-radius:8px}.sm-headerBtnDanger{background:var(--dsw-alias-button-floating-fill,#fff);color:var(--dsw-alias-state-error-primary,#d92d20);border-color:var(--dsw-alias-state-error-primary,#d92d20);font-weight:500}.sm-headerBtnDanger:hover:not(:disabled){background:var(--dsw-alias-state-error-primary,#d92d20);color:var(--dsw-alias-label-primary-foreground,#fff);border-color:var(--dsw-alias-state-error-primary,#d92d20)}.sm-header{display:inline-flex;align-items:center;gap:6px;flex-wrap:nowrap}.sm-headerSecondaryActions{display:inline-flex;align-items:center;gap:6px;flex-wrap:nowrap}.sm-headerCompactMenu{display:none;position:relative}.sm-headerCompactMenuBtn{width:32px;min-width:32px;height:32px;padding:0;justify-content:center;font-size:16px;line-height:1}.sm-headerBtnIcon{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;font-size:14px;line-height:1;vertical-align:middle;flex-shrink:0}.sm-headerBtn.sm-markIcon{width:32px;min-width:32px;height:32px;padding:0;justify-content:center}.sm-headerBtn.sm-markIcon .sm-headerBtnIcon{width:16px;height:16px;font-size:15px;line-height:1}.sm-headerCompactMenuBtn .sm-headerBtnIcon{width:16px;height:16px;font-size:16px;line-height:1}.sm-annotationToggleOpen{position:relative;z-index:100004}.sm-headerBtnActive{background:var(--dsw-alias-button-ghost-active-fill);color:var(--dsw-alias-label-primary)}@container (max-width:720px){.sm-headerBtn{width:32px;min-width:32px;height:32px;padding:0;justify-content:center}.sm-headerBtnLabel,.sm-priorityText,.sm-priorityBadge{display:none}.sm-headerBtn.sm-headerBtn-withBadge{width:auto;min-width:32px;padding:0 6px}}@container (max-width:520px){.sm-headerSecondaryActions,.sm-headerSecondaryAction{display:none!important}.sm-headerCompactMenu{display:inline-flex}}",
|
|
580
|
+
".sm-panelDialog{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);width:600px;max-width:calc(100vw - 32px);max-height:560px;height:auto;box-sizing:border-box;display:flex;flex-direction:column;gap:0;background:var(--sm-dialog-fill);color:var(--dsw-alias-label-primary,#111);border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:12px;box-shadow:0 16px 48px rgba(0,0,0,.25);overflow:hidden;z-index:1020}.sm-panelDialog .sm-nativeDialogHeader{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:10px 16px;border-bottom:1px solid var(--dsw-alias-border-l2,#eee);flex:none;position:relative;min-height:46px;box-sizing:border-box}.sm-panelDialog .sm-nativeDialogTitle{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);margin:0;font-size:14px;line-height:20px;font-weight:600;min-width:0;max-width:calc(100% - 140px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:center;pointer-events:auto;z-index:0}.sm-panelDialog .sm-nativeDialogHeaderActions{display:flex;align-items:center;gap:6px;flex:none;position:relative;z-index:1;margin-left:auto}.sm-nativeDialogFooter,.sm-bulkDialog .sm-nativeDialogFooter,.sm-confirmDialog .sm-nativeDialogFooter,.sm-migrateDialog .sm-nativeDialogFooter{display:flex;padding:10px 16px;border-top:1px solid var(--dsw-alias-border-l2,#eee);flex:none;flex-wrap:wrap;justify-content:space-between;gap:6px;margin-top:0}.sm-panelDialog .sm-panel{display:flex;flex-direction:column;gap:6px;min-height:0;flex:1 1 auto;overflow:auto;padding:8px 12px}.sm-panelDialog .sm-list{display:flex;flex-direction:column;gap:2px;flex:1 1 auto;min-height:0;overflow:auto}.sm-panelDialog .sm-row{display:flex;align-items:center;gap:8px;padding:6px 10px;min-height:36px;border:1px solid transparent;border-radius:8px;background:transparent;flex-shrink:0}.sm-panelDialog .sm-row:hover{background:var(--dsw-alias-interactive-bg-hover)}.sm-panelDialog .sm-rowCurrent{background:var(--dsw-alias-bg-module-platform);border-color:var(--dsw-alias-state-business-primary,#356ae6)}.sm-panelDialog .sm-rowMain{display:flex;align-items:stretch!important;gap:8px;min-width:0;flex:1 1 auto;overflow:visible;text-align:left!important}.sm-panelDialog .sm-rowTitle{min-width:0;flex:1 1 0%;width:100%;align-self:stretch;display:flex;align-items:center;justify-content:flex-start;gap:6px;font-size:12px;line-height:16px;overflow:hidden;text-align:left!important;direction:ltr!important}.sm-confirmDialog{z-index:10000}.sm-confirmDialog.sm-nativeDialogLayer{position:fixed;left:calc(50vw + 184px);top:calc(50vh - 90px);width:360px;max-width:calc(100vw - 32px);max-height:none;display:block;align-items:initial;justify-content:initial;box-sizing:border-box;background:transparent;border:0;box-shadow:none;padding:0;inset:calc(50vh - 90px) auto auto calc(50vw + 308px)}.sm-confirmDialog.sm-nativeDialogLayer .sm-nativeDialogBackdrop{display:none}.sm-confirmDialog.sm-nativeDialogLayer .sm-nativeDialog{position:relative;left:auto;top:auto;transform:none;width:auto;box-sizing:border-box;background:var(--sm-dialog-fill);color:var(--dsw-alias-label-primary,#111);border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:12px;box-shadow:0 16px 48px rgba(0,0,0,.25);padding:0;overflow:hidden;animation:sm-confirmPop .14s ease-out}.sm-confirmDialog .sm-nativeDialogHeader{position:relative;padding:12px 16px;border-bottom:1px solid var(--dsw-alias-border-l2,#eee);display:flex;align-items:center;justify-content:center;min-height:44px;box-sizing:border-box}.sm-confirmDialog .sm-nativeDialogTitle{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);margin:0;font-size:14px;line-height:20px;font-weight:600;text-align:center;width:auto;max-width:calc(100% - 32px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sm-confirmDialog .sm-nativeDialogBody{padding:10px 16px;display:flex;flex-direction:column;gap:8px;min-height:0}.sm-confirmDialog .sm-nativeDialogDescription{font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary);white-space:pre-wrap}.sm-confirmDialog .sm-warn{padding:6px 10px;font-size:12px;line-height:16px;margin-top:0}.sm-confirmDialog .sm-nativeDialogFooter{padding:10px 16px;border-top:1px solid var(--dsw-alias-border-l2,#eee);flex-wrap:wrap;justify-content:space-between;gap:6px;margin-top:0}.sm-confirmDialog .sm-nativeDialogButton{min-height:28px;padding:3px 14px;font-size:12px;line-height:20px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;cursor:pointer;background:transparent;color:var(--dsw-alias-label-primary);text-align:center}.sm-confirmDialog .sm-nativeDialogCancel:hover:not(:disabled),.sm-migrateDialog .sm-nativeDialogCancel:hover:not(:disabled),.sm-updateDialog .sm-nativeDialogCancel:hover:not(:disabled),.sm-bulkDialog .sm-nativeDialogCancel:hover:not(:disabled),.sm-panelDialog .sm-nativeDialogCancel:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.sm-confirmDialog .sm-nativeDialogConfirm{background:var(--dsw-alias-state-business-primary,#356ae6);color:var(--dsw-alias-label-primary-foreground,#fff);border-color:var(--dsw-alias-state-business-primary,#356ae6)}.sm-confirmDialog .sm-nativeDialogConfirm:hover:not(:disabled){filter:brightness(.94)}@keyframes sm-confirmPop{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.sm-confirmDialog.sm-nativeDialog{padding:0;width:auto;max-width:none}.sm-panelDialog .sm-rowTitle>span:first-child{display:block;min-width:0;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;flex:1 1 auto;width:auto;text-align:left!important;direction:ltr!important;unicode-bidi:plaintext}.sm-panelDialog .sm-rowMeta{display:none}.sm-panelDialog .sm-rowActions{display:flex;gap:2px;flex:none;justify-content:flex-end}.sm-panelDialog .sm-rowActions .sm-rowBtn{min-height:22px;padding:0 7px;font-size:11px;line-height:18px;border-radius:6px;border:1px solid transparent;background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap}.sm-rowBtn.sm-markIcon{padding:0 6px;font-size:13px;line-height:18px}.sm-panelDialog .sm-rowActions .sm-rowBtn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.sm-panelDialog .sm-rowActions .sm-rowBtnDanger{color:var(--dsw-alias-state-error-primary)}.sm-panelDialog .sm-rowActions .sm-rowBtnDanger:hover{background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary)}.sm-panelDialog .sm-filter{flex:none;padding:6px 12px 4px;gap:4px;display:flex;flex-wrap:wrap}.sm-panelDialog .sm-filterBtn{min-height:24px;padding:2px 10px;font-size:11px;line-height:16px;border-radius:4px;border:1px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer}.sm-panelDialog .sm-filterBtn.sm-on{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary)}.sm-panelDialog .sm-badge{font-size:10px;line-height:14px;padding:0 5px;border-radius:6px;flex:none}.sm-panelDialog .sm-error{padding:6px 10px;margin:0;font-size:12px;line-height:16px}.sm-panelDialog .sm-nativeDialogButton{min-height:28px;padding:3px 14px;font-size:12px;line-height:20px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:transparent;color:var(--dsw-alias-label-primary);cursor:pointer;text-align:center}.sm-panelDialog .sm-nativeDialogCancel{background:transparent}.sm-panelDialog .sm-panelDialog .sm-nativeDialogConfirm{background:var(--dsw-alias-state-business-primary,#356ae6);color:var(--dsw-alias-label-primary-foreground,#fff);border-color:var(--dsw-alias-state-business-primary,#356ae6)}.sm-nativeDialogDanger{background:var(--dsw-alias-state-error-primary,#d92d20);color:var(--dsw-alias-label-primary-foreground,#fff);border-color:var(--dsw-alias-state-error-primary,#d92d20)}.sm-nativeDialogDanger:hover:not(:disabled){filter:brightness(.92)}.sm-confirmDialog .sm-nativeDialogDanger,.sm-migrateDialog .sm-nativeDialogDanger,.sm-bulkDialog .sm-nativeDialogDanger{background:var(--dsw-alias-state-error-primary,#d92d20);color:var(--dsw-alias-label-primary-foreground,#fff);border-color:var(--dsw-alias-state-error-primary,#d92d20)}.sm-confirmDialog .sm-nativeDialogDanger:hover:not(:disabled),.sm-migrateDialog .sm-nativeDialogDanger:hover:not(:disabled),.sm-bulkDialog .sm-nativeDialogDanger:hover:not(:disabled){filter:brightness(.92)}.sm-panelDialog .sm-empty{padding:18px 0;font-size:12px;color:var(--dsw-alias-label-tertiary);text-align:center}.sm-panelDialog .sm-footError{font-size:11px;color:var(--dsw-alias-state-error-primary);margin-right:auto;line-height:20px}.sm-panelDialog .sm-moveLabel{font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary)}.sm-migrateDialog .sm-nativeDialogFooter{flex-wrap:wrap;justify-content:space-between;gap:6px;margin-top:0}.sm-migrateDialog .sm-migrateChip{cursor:pointer;pointer-events:auto;position:relative;z-index:1}.sm-migrateDialog .sm-migrateChip[disabled]{opacity:.5;cursor:not-allowed}.sm-migrateDialog.sm-nativeDialogLayer{position:fixed;left:50vw;top:auto;bottom:48px;transform:translateX(-50%);width:min(560px,calc(100vw - 32px));max-height:none;display:block;align-items:initial;justify-content:initial;box-sizing:border-box;background:transparent;border:0;box-shadow:none;padding:0;inset:auto;z-index:10001}.sm-migrateDialog.sm-nativeDialogLayer .sm-nativeDialogBackdrop{display:none}.sm-migrateDialog.sm-nativeDialogLayer .sm-nativeDialog{position:relative;left:auto;top:auto;transform:none;width:360px;max-width:calc(100vw - 32px);max-height:min(70vh,520px);box-sizing:border-box;background-color:var(--sm-dialog-fill);color:var(--dsw-alias-label-primary,#111);border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:12px;box-shadow:0 16px 48px rgba(0,0,0,.45);overflow:hidden;padding:0;display:flex;flex-direction:column;gap:0}.sm-migrateDialog{position:fixed;left:50vw;top:auto;bottom:48px;transform:translateX(-50%);width:min(560px,calc(100vw - 32px));max-height:min(70vh,520px);box-sizing:border-box;display:flex;flex-direction:column;gap:0;background-color:var(--sm-dialog-fill);color:var(--dsw-alias-label-primary,#111);border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:12px;box-shadow:0 16px 48px rgba(0,0,0,.45);overflow:hidden;z-index:10001}.sm-migrateDialog .sm-nativeDialogHeader{padding:12px 18px;border-bottom:1px solid var(--dsw-alias-border-l2,#eee);flex:none;position:relative;display:flex;align-items:center;justify-content:center;min-height:44px;box-sizing:border-box}.sm-migrateDialog .sm-nativeDialogTitle{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);margin:0;font-size:14px;line-height:20px;font-weight:600;color:var(--dsw-alias-label-primary,#111);text-align:center;width:auto;max-width:calc(100% - 36px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sm-migrateDialog .sm-migratePanel{padding:12px 18px;display:flex;flex-direction:column;gap:14px}.sm-migrateDialog .sm-nativeDialogBody{padding:0}.sm-migrateDialog .sm-nativeDialogFooter{padding:10px 16px;border-top:1px solid var(--dsw-alias-border-l2,#eee);flex:none;flex-wrap:wrap;justify-content:space-between;gap:6px;margin-top:0;gap:8px}.sm-migrateDialog .sm-migrateRow>label{color:var(--dsw-alias-label-secondary,#444)}.sm-migrateDialog .sm-migrateChip{padding:6px 12px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2,#ddd);background-color:var(--dsw-alias-markdown-tag,#f1f3f5);color:var(--dsw-alias-label-primary,#111);font-size:13px;line-height:18px;cursor:pointer;pointer-events:auto;position:relative;z-index:1;white-space:nowrap}.sm-migrateDialog .sm-migrateChip:hover:not(:disabled){background-color:var(--dsw-alias-interactive-bg-hover,#e8e8e8)}.sm-migrateDialog .sm-migrateChipOn{background-color:var(--dsw-alias-state-business-primary,#356ae6);color:var(--dsw-alias-label-primary-foreground,#fff);border-color:var(--dsw-alias-state-business-primary,#356ae6)}.sm-migrateDialog .sm-migrateChip.sm-migrateChipOn:hover:not(:disabled){background-color:var(--dsw-alias-button-info-hover,#4576f0);color:var(--dsw-alias-label-primary-foreground,#fff);border-color:var(--dsw-alias-button-info-hover,#4576f0);filter:none}.sm-migrateDialog .sm-migrateChipOn:hover:not(:disabled){filter:brightness(.92)}.sm-migrateDialog .sm-migrateChip[disabled]{opacity:.5;cursor:not-allowed}.sm-migrateDialog .sm-migrateEmpty{color:var(--dsw-alias-label-tertiary,#888)}.sm-migrateDialog .sm-migratePreview{padding:10px 12px;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;background-color:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#111);font-size:13px;line-height:18px}.sm-migrateDialog .sm-migrateWarn{padding:10px 12px;border:1px solid color-mix(in srgb,var(--dsw-alias-state-warn-primary,#f59e0b) 30%,transparent);border-radius:8px;background-color:var(--dsw-alias-state-warn-tertiary,#fef5e7);color:var(--dsw-alias-label-secondary,#444);font-size:13px;line-height:18px}.sm-migrateDialog .sm-nativeDialogButton{min-height:28px;padding:3px 14px;font-size:12px;line-height:20px;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;cursor:pointer;background-color:transparent;color:var(--dsw-alias-label-primary,#111);text-align:center}.sm-migrateDialog .sm-nativeDialogButton:hover:not(:disabled){background-color:var(--dsw-alias-interactive-bg-hover,#e8e8e8)}.sm-migrateDialog .sm-nativeDialogConfirm{background-color:var(--dsw-alias-state-business-primary,#356ae6);color:var(--dsw-alias-label-primary-foreground,#fff);border-color:var(--dsw-alias-state-business-primary,#356ae6)}.sm-migrateDialog .sm-nativeDialogConfirm:hover:not(:disabled){filter:brightness(.94)}",
|
|
581
|
+
// The .sm-tooltip rule below deliberately keeps !important: it targets
|
|
582
|
+
// DSH's Tooltip primitive (used through renderTip), which ships its own
|
|
583
|
+
// inline styles, so a plugin rule cannot win on specificity alone
|
|
584
|
+
// (Issue #21 regression guard). It overrides DSH's primitive rather than
|
|
585
|
+
// DSH's theme tokens -- and it only sets a token-based border plus
|
|
586
|
+
// z-index/shadow -- so it does not block theming.
|
|
587
|
+
// NOTE: DSH's bubble uses a hard-coded hashed class and forwards no
|
|
588
|
+
// className, so this rule matches nothing today (the class is never
|
|
589
|
+
// applied). Tooltip visibility is governed by the layering contract
|
|
590
|
+
// above, not by this rule; it is kept as the scoped replacement for the
|
|
591
|
+
// unscoped selector Issue #21 removed.
|
|
592
|
+
".sm-panelHeaderClose{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;min-height:26px;padding:0;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:7px;background:transparent;color:var(--dsw-alias-label-secondary,#555);cursor:pointer;flex:none;box-sizing:border-box;outline:none}.sm-panelHeaderClose:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#eee);color:var(--dsw-alias-label-primary,#111)}.sm-panelHeaderClose svg{display:block;width:14px;height:14px;margin:auto}.sm-panelHeaderGithub{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;border-radius:6px;color:var(--dsw-alias-label-secondary,#555);text-decoration:none;flex:none;transition:background .15s,color .15s;cursor:pointer}.sm-panelHeaderGithub:hover{background:var(--dsw-alias-interactive-bg-hover,#eee);color:var(--dsw-alias-label-primary,#111)}.sm-panelHeaderGithub svg{display:block;width:16px;height:16px;fill:currentColor}.sm-panelHeaderLeft{display:flex;align-items:center;gap:4px;flex:none;position:relative;z-index:1}.sm-panelHeaderWhale{display:inline-flex;align-items:center;justify-content:center;position:relative;width:26px;height:26px;border-radius:6px;color:var(--dsw-alias-label-secondary,#555);text-decoration:none;flex:none;transition:background .15s,color .15s;cursor:pointer}.sm-panelHeaderWhale:hover{background:var(--dsw-alias-interactive-bg-hover,#eee);color:var(--dsw-alias-label-primary,#111)}.sm-panelHeaderWhale svg{display:block;width:16px;height:16px;margin:auto}.sm-panelHeaderWhale .sm-updateDot{position:absolute;top:2px;right:2px;width:7px;height:7px;border-radius:50%;background:var(--dsw-alias-state-error-primary,#e53e3e);border:1.5px solid var(--dsw-alias-bg-layer-1,#fff)}.sm-panelHeaderWhale .sm-updateSpinner{position:absolute;inset:2px;border:2px solid transparent;border-top-color:var(--dsw-alias-state-business-primary,#356ae6);border-radius:50%;animation:sm-spin .8s linear infinite}@keyframes sm-spin{to{transform:rotate(360deg)}}.sm-updateDialogLayer{display:flex!important;align-items:center!important;justify-content:center!important;position:fixed;inset:0;padding:16px;box-sizing:border-box;background:transparent;border:0;box-shadow:none;z-index:10010;pointer-events:none}.sm-updateDialogLayer .sm-nativeDialog{position:relative;width:380px;max-width:calc(100vw - 32px);box-sizing:border-box;background:var(--sm-dialog-fill);color:var(--dsw-alias-label-primary,#111);border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:12px;box-shadow:0 16px 48px rgba(0,0,0,.25);overflow:hidden;animation:sm-confirmPop .14s ease-out;pointer-events:auto}.sm-updateDialog .sm-nativeDialogHeader{position:relative;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:12px 16px;border-bottom:1px solid var(--dsw-alias-border-l2,#eee);flex:none;min-height:46px;box-sizing:border-box}.sm-updateDialog .sm-nativeDialogTitle{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);margin:0;font-size:15px;line-height:20px;font-weight:600;text-align:center;width:auto;max-width:calc(100% - 80px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;z-index:0}.sm-updateDialog .sm-nativeDialogHeader .sm-panelHeaderClose{position:relative;z-index:1;margin-left:auto}.sm-updateDialog .sm-nativeDialogBody{padding:14px 16px;display:flex;flex-direction:column;gap:10px;font-size:13px;line-height:20px;color:var(--dsw-alias-label-primary,#111)}.sm-updateDialog .sm-nativeDialogFooter{display:flex;padding:10px 16px;border-top:1px solid var(--dsw-alias-border-l2,#eee);flex:none;flex-wrap:wrap;justify-content:space-between;gap:8px;margin-top:0}.sm-updateDialog .sm-nativeDialogFooter .sm-nativeDialogConfirm:only-child{margin-left:auto}.sm-updateDialog .sm-nativeDialogButton{min-height:28px;padding:3px 14px;font-size:12px;line-height:20px;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;cursor:pointer;background:transparent;color:var(--dsw-alias-label-primary,#111);text-align:center}.sm-updateDialog .sm-nativeDialogButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.sm-updateDialog .sm-nativeDialogConfirm{background:var(--dsw-alias-state-business-primary,#356ae6);color:var(--dsw-alias-label-primary-foreground,#fff);border-color:var(--dsw-alias-state-business-primary,#356ae6)}.sm-updateDialog .sm-nativeDialogConfirm:hover:not(:disabled){filter:brightness(.94)}.sm-updateVersionGrid{display:grid;grid-template-columns:auto 1fr;gap:6px 12px;padding:12px;background:var(--dsw-alias-bg-layer-2,#fff);border:1px solid var(--dsw-alias-border-l2,#eee);border-radius:8px;font-size:13px;line-height:20px}.sm-updateVersionLabel{color:var(--dsw-alias-label-secondary,#666);font-weight:500}.sm-updateVersionValue{color:var(--dsw-alias-label-primary,#111);font-family:monospace;font-size:13px}.sm-updateStatusBox{margin-top:10px;font-size:13px;line-height:20px;color:var(--dsw-alias-label-primary,#111)}.sm-updateStatusBox.sm-warn{color:var(--dsw-alias-state-warn-label,#dd8629);background:var(--dsw-alias-state-warn-tertiary,#fef5e7);padding:8px 10px;border-radius:6px;border:1px solid color-mix(in srgb,var(--dsw-alias-state-warn-primary,#f59e0b) 25%,transparent)}.sm-updateStatusBox.sm-error{color:var(--dsw-alias-state-error-primary,#ec1313);background:color-mix(in srgb,var(--dsw-alias-state-error-primary,#ec1313) 8%,transparent);padding:8px 10px;border-radius:6px;border:1px solid color-mix(in srgb,var(--dsw-alias-state-error-primary,#ec1313) 22%,transparent)}.sm-updateStatusBox.sm-success{color:var(--dsw-alias-state-success-primary,#22c55e);background:var(--dsw-alias-state-success-tertiary,#e6faed);padding:8px 10px;border-radius:6px;border:1px solid color-mix(in srgb,var(--dsw-alias-state-success-primary,#22c55e) 25%,transparent)}.sm-settingsCard{background:var(--sm-dialog-surface);border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:12px;padding:16px 20px;font-size:13px;line-height:20px;color:var(--dsw-alias-label-primary,#111);box-sizing:border-box;width:100%}.sm-settingsHeader{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;padding-bottom:10px;border-bottom:1px solid var(--dsw-alias-border-l2,#eee)}.sm-settingsTitle{margin:0;font-size:16px;line-height:22px;font-weight:600;display:flex;align-items:center;gap:8px}.sm-settingsTag{font-size:12px;padding:2px 8px;border-radius:999px;background:var(--dsw-alias-markdown-tag,#f1f3f5);color:var(--dsw-alias-label-secondary,#666);font-family:monospace}.sm-settingsSection{margin-top:14px;padding-top:12px;border-top:1px solid var(--dsw-alias-border-l2,#eee)}.sm-settingsSectionTitle{font-size:13px;font-weight:600;color:var(--dsw-alias-label-secondary,#666);margin-bottom:8px;text-transform:uppercase;letter-spacing:.5px}.sm-settingsRow{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:32px}.sm-settingsActions{display:flex;align-items:center;gap:8px;margin-top:10px}.sm-settingsLink{color:var(--dsw-alias-state-business-primary,#356ae6);text-decoration:none}.sm-settingsLink:hover{text-decoration:underline}.sm-settingsCheckbox{display:inline-flex;align-items:center;gap:6px;cursor:pointer}.sm-settingsSelect{min-height:28px;padding:3px 8px;font-size:12px;line-height:20px;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:6px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#111);cursor:pointer;outline:none}.sm-panelHeaderClose:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#eee);color:var(--dsw-alias-label-primary,#111)}.sm-panelHeaderClose:disabled{opacity:.5;cursor:not-allowed}.sm-migrateCurrent{padding:8px 10px;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;background:var(--dsw-alias-bg-layer-2,#fff);font-size:13px;line-height:18px;color:var(--dsw-alias-label-primary,#111)}.sm-migrateConfirmLayer.sm-confirmDialog.sm-nativeDialogLayer{width:360px;inset:calc(50vh - 90px) auto auto calc(50vw + 308px)}.sm-migrateConfirmLayer.sm-confirmDialog.sm-nativeDialogLayer .sm-migrateDialog{position:relative;left:auto;top:auto;bottom:auto;transform:none;width:100%;max-width:none;max-height:min(70vh,520px);z-index:auto}.sm-migrateConfirmLayer .sm-migratePanel{min-width:0}.sm-migrateConfirmLayer .sm-nativeDialogButton.sm-nativeDialogConfirm:hover:not(:disabled){background-color:var(--dsw-alias-button-info-hover,#4576f0);color:var(--dsw-alias-label-primary-foreground,#fff);border-color:var(--dsw-alias-button-info-hover,#4576f0);filter:none}.sm-settingsSectionHeader{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px}.sm-settingsSectionHeader .sm-settingsSectionTitle{margin-bottom:0}.sm-settingsVersionActions{display:flex;align-items:center;gap:8px}.sm-settingsCheckBtn{min-height:26px;padding:2px 12px;font-size:12px;line-height:18px;border-radius:6px;border:1px solid var(--dsw-alias-border-l2,#ddd);background:transparent;color:var(--dsw-alias-label-primary,#111);cursor:pointer;white-space:nowrap}.sm-settingsCheckBtn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.sm-settingsRowInline{justify-content:flex-start;flex-wrap:wrap;gap:8px;align-items:center}.sm-settingsBadgeLink{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:6px;border:1px solid var(--dsw-alias-border-l2,#ddd);background:var(--dsw-alias-markdown-tag,#f1f3f5);color:var(--dsw-alias-label-secondary,#555);font-size:12px;line-height:18px;text-decoration:none;cursor:pointer;transition:all .15s}.sm-settingsBadgeLink:hover{background:var(--dsw-alias-interactive-bg-hover,#eee);color:var(--dsw-alias-state-business-primary,#356ae6);border-color:var(--dsw-alias-state-business-primary,#356ae6)}.sm-settingsBadgeLink svg{flex:none}.sm-tooltip{z-index:1100!important;box-shadow:none!important;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.15))!important;filter:none!important}",
|
|
593
|
+
|
|
594
|
+
// Issue #23 — dialog opacity.
|
|
595
|
+
//
|
|
596
|
+
// The fill is the DSH surface token itself, with the user's opacity used
|
|
597
|
+
// only as that token's weight inside color-mix(). At the default 100%
|
|
598
|
+
// the mix is `color-mix(in srgb, <token> 100%, transparent)`, which
|
|
599
|
+
// reproduces the token VERBATIM -- including whatever alpha the token (or
|
|
600
|
+
// a theme that republished it) already carries. The plugin therefore
|
|
601
|
+
// never forces an originally translucent DSH surface opaque, and only
|
|
602
|
+
// adds translucency when the user lowers the slider.
|
|
603
|
+
//
|
|
604
|
+
// Only the dialog *fill* is affected, so text, buttons, icons, borders
|
|
605
|
+
// and hover states stay fully opaque, and inside controls read their own
|
|
606
|
+
// DSH tokens rather than inheriting this setting. The static --sm-dialog-
|
|
607
|
+
// surface-fallback below is used only when the DSH token is missing; the
|
|
608
|
+
// plugin detects and names no theme plugin at all.
|
|
609
|
+
":root{--sm-dialog-opacity:100%}",
|
|
610
|
+
"html[data-sm-theme=light]{--sm-dialog-surface-fallback:#fff}",
|
|
611
|
+
"html[data-sm-theme=dark]{--sm-dialog-surface-fallback:#1f1f23}",
|
|
612
|
+
// Native UA chrome (a <select> dropdown list, scrollbars, checkbox
|
|
613
|
+
// internals) is painted by the browser, not by DSH tokens. DSH owns the
|
|
614
|
+
// palette for it: ui-layout's ThemePresenter subscribes to the official
|
|
615
|
+
// `theme/change` event and writes `documentElement.style.colorScheme`
|
|
616
|
+
// ("html { color-scheme } for native UA chrome"), which every plugin
|
|
617
|
+
// surface inherits. The plugin must NOT override it -- an earlier revision
|
|
618
|
+
// forced `color-scheme` from this plugin's own theme mirror and could then
|
|
619
|
+
// pin the native chrome to the opposite scheme (dark dropdown lists in
|
|
620
|
+
// light mode) while the tokens had already moved on. DSH stays the single
|
|
621
|
+
// authority; the plugin only themes the list *items*, which is something
|
|
622
|
+
// color-scheme alone does not cover.
|
|
623
|
+
// The items use the *layer-3* surface, not the control's layer-2: a
|
|
624
|
+
// floating list must stay opaque, and a theme may give layer-2 an alpha,
|
|
625
|
+
// which composites over the UA's default popup backdrop and still reads as
|
|
626
|
+
// white. layer-3 is opaque in DSH's palette (#fff light / #353638 dark)
|
|
627
|
+
// and sits above the dialog (layer-1) and the control (layer-2). The
|
|
628
|
+
// checked row is marked with the accent text colour instead of a fill so
|
|
629
|
+
// no translucent token can wash it out either.
|
|
630
|
+
".sm-panelDialog option,.sm-nativeDialog option,.sm-settingsCard option,.sm-headerMenu option{background-color:var(--dsw-alias-bg-layer-3,#fff);color:var(--dsw-alias-label-primary,#111)}",
|
|
631
|
+
".sm-panelDialog option:checked,.sm-nativeDialog option:checked,.sm-settingsCard option:checked,.sm-headerMenu option:checked{background-color:var(--dsw-alias-bg-layer-3,#fff);color:var(--dsw-alias-state-business-primary,#356ae6)}",
|
|
632
|
+
".sm-panelDialog option:disabled,.sm-nativeDialog option:disabled,.sm-settingsCard option:disabled,.sm-headerMenu option:disabled{color:var(--dsw-alias-label-tertiary,#888)}",
|
|
633
|
+
".sm-nativeDialog,.sm-panelDialog,.sm-migrateDialog,.sm-settingsCard{--sm-dialog-surface:var(--dsw-alias-bg-layer-1,var(--sm-dialog-surface-fallback,#fff));--sm-dialog-fill:color-mix(in srgb,var(--sm-dialog-surface) var(--sm-dialog-opacity,100%),transparent)}",
|
|
634
|
+
".sm-settingsSlider{display:flex;align-items:center;gap:8px;flex:1 1 auto;justify-content:flex-end;min-width:0}",
|
|
635
|
+
".sm-settingsRange{flex:1 1 120px;min-width:96px;max-width:220px;margin:0;cursor:pointer;accent-color:var(--dsw-alias-state-business-primary,#356ae6)}",
|
|
636
|
+
".sm-settingsRange:disabled{cursor:not-allowed}",
|
|
637
|
+
".sm-settingsRangeValue{min-width:38px;text-align:right;font-size:12px;line-height:18px;font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-secondary,#666)}",
|
|
638
|
+
".sm-settingsResetBtn{min-height:26px;padding:2px 10px;font-size:12px;line-height:18px;border-radius:6px;border:1px solid var(--dsw-alias-border-l2,#ddd);background:transparent;color:var(--dsw-alias-label-secondary,#666);cursor:pointer;white-space:nowrap}",
|
|
639
|
+
".sm-settingsResetBtn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary,#111)}",
|
|
640
|
+
".sm-settingsResetBtn:disabled{opacity:.5;cursor:not-allowed}",
|
|
641
|
+
".sm-settingsHint{margin-top:4px;font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary,#888)}",
|
|
642
|
+
|
|
643
|
+
// DSH's own theme is the single source of colour. Every rule above reads
|
|
644
|
+
// --dsw-alias-* tokens directly and none of them is redefined here: the
|
|
645
|
+
// plugin only *reads* DSH's theme, so a theme (or a third-party theme
|
|
646
|
+
// plugin) that republishes those tokens is picked up automatically.
|
|
647
|
+
// The only thing these two rules still provide is the token-less
|
|
648
|
+
// fallback surface colour required by the dialog-opacity fill. The
|
|
649
|
+
// light/dark state itself is mirrored onto <html data-sm-theme> by
|
|
650
|
+
// smApplyTheme(), which reads body[data-ds-dark-theme].
|
|
651
|
+
"[data-sm-theme=light] .sm-nativeDialog,[data-sm-theme=light] .sm-panelDialog,[data-sm-theme=light] .sm-migrateDialog,[data-sm-theme=light] .sm-settingsCard{--sm-dialog-surface-fallback:#fff}",
|
|
652
|
+
"[data-sm-theme=dark] .sm-nativeDialog,[data-sm-theme=dark] .sm-panelDialog,[data-sm-theme=dark] .sm-migrateDialog,[data-sm-theme=dark] .sm-settingsCard{--sm-dialog-surface-fallback:#1f1f23}",
|
|
483
653
|
".sm-panelDialog{max-height:min(640px,calc(100vh - 32px))}.sm-panelDialog .sm-panel{min-width:0;overflow:hidden}",
|
|
484
654
|
".sm-panelTools{display:flex;flex-direction:column;gap:8px;flex:none;padding:2px 0 6px}",
|
|
485
|
-
".sm-queryInput,.sm-viewSelect{box-sizing:border-box;width:100%;min-width:0;height:32px;padding:5px 9px;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:7px;background:var(--dsw-alias-
|
|
486
|
-
".sm-queryInput::placeholder{color:var(--dsw-alias-label-tertiary,#888)}.sm-queryInput:focus-visible,.sm-viewSelect:focus-visible,.sm-resetFilters:focus-visible{outline:2px solid var(--dsw-alias-
|
|
655
|
+
".sm-queryInput,.sm-viewSelect{box-sizing:border-box;width:100%;min-width:0;height:32px;padding:5px 9px;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:7px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#111);font:inherit;font-size:12px;line-height:20px}",
|
|
656
|
+
".sm-queryInput::placeholder{color:var(--dsw-alias-label-tertiary,#888)}.sm-queryInput:focus-visible,.sm-viewSelect:focus-visible,.sm-resetFilters:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#356ae6);outline-offset:2px}.sm-viewSelect:disabled{opacity:.6;cursor:wait}",
|
|
487
657
|
".sm-panelSelects{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px}.sm-panelSelects .sm-viewField>span{display:none}.sm-panelSelects .sm-viewField .sm-viewSelect{font-size:11px;padding:4px 7px;height:28px;line-height:18px}.sm-viewField{display:flex;flex-direction:column;gap:3px;min-width:0;color:var(--dsw-alias-label-secondary,#666);font-size:11px;line-height:16px}",
|
|
488
|
-
".sm-filterBar{display:flex;align-items:center;justify-content:space-between;gap:6px;flex-wrap:wrap}.sm-resultSummary{display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:11px;color:var(--dsw-alias-label-tertiary,#888)}.sm-resetFilters{padding:2px 0;border:0;background:none;color:var(--dsw-alias-
|
|
658
|
+
".sm-filterBar{display:flex;align-items:center;justify-content:space-between;gap:6px;flex-wrap:wrap}.sm-resultSummary{display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:11px;color:var(--dsw-alias-label-tertiary,#888)}.sm-resetFilters{padding:2px 0;border:0;background:none;color:var(--dsw-alias-state-business-primary,#356ae6);font:inherit;cursor:pointer}.sm-resetFilters:hover{text-decoration:underline}.sm-workspaceNotice{display:flex;gap:8px;align-items:center;font-size:12px;color:var(--dsw-alias-label-secondary,#666)}",
|
|
489
659
|
"@media(max-width:540px){.sm-panelSelects{grid-template-columns:minmax(0,1fr)}.sm-panelDialog .sm-row{height:auto;min-height:36px;flex-shrink:0;flex-wrap:wrap;padding:6px 8px}.sm-panelDialog .sm-rowMain{flex-basis:100%}.sm-panelDialog .sm-rowActions{width:100%;min-width:0;flex:1 1 100%;justify-content:flex-start}}",
|
|
490
660
|
".sm-panelDialog:not(.sm-annotationSurface){width:680px}.sm-panelDialog .sm-row{flex-shrink:0;padding:5px 8px}.sm-panelDialog .sm-rowMain{flex:1 1 200px;flex-direction:column;gap:4px}.sm-panelDialog .sm-rowActions{max-width:100%}.sm-rowSecondary{display:flex;flex-wrap:nowrap;align-items:center;gap:6px;min-width:0;line-height:18px}.sm-rowBadges{display:flex;align-items:center;gap:5px;min-width:0;flex:1 1 auto;flex-wrap:wrap;font-size:11px;line-height:18px}.sm-rowMeta{color:var(--dsw-alias-label-tertiary,#888);font-size:11px;line-height:18px;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;flex:none}.sm-rowAnnotations{display:flex;align-items:center;gap:5px;min-width:0;font-size:10px;line-height:16px}",
|
|
491
|
-
|
|
661
|
+
// .sm-markIcon.sm-markOn keeps !important because the generic
|
|
662
|
+
// `.sm-panelDialog .sm-rowActions .sm-rowBtn` colour rule (3 classes)
|
|
663
|
+
// outranks this 2-class selector; it overrides the plugin's own rule,
|
|
664
|
+
// not DSH's theme. The .sm-priority-1/2 colours below are plugin
|
|
665
|
+
// semantics (priority levels have no DSH token); they and their dark
|
|
666
|
+
// branch are the only intentional data-driven theme branch left.
|
|
667
|
+
".sm-markIcon{min-width:25px;padding-left:5px;padding-right:5px;font-size:15px}.sm-markIcon.sm-markOn{color:var(--dsw-alias-state-business-primary,#356ae6)!important;background:var(--dsw-alias-bg-module-platform,#f5f6f7)}.sm-priorityBadge{padding:0 5px;border-radius:4px;background:var(--dsw-alias-markdown-tag,#f1f3f5);color:var(--dsw-alias-label-secondary,#666)}.sm-priority-1{color:#c2410c;background:rgba(234,88,12,.12)}.sm-priority-2{color:#a16207;background:rgba(202,138,4,.12)}",
|
|
492
668
|
"[data-sm-theme=dark] .sm-priority-1{color:#fdba74}[data-sm-theme=dark] .sm-priority-2{color:#fde68a}",
|
|
493
|
-
".sm-tagChip,.sm-noteBadge{max-width:88px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;border:0;border-radius:4px;background:var(--dsw-alias-
|
|
494
|
-
".sm-markFilters{display:flex;flex-wrap:wrap;align-items:center;gap:8px}.sm-markFiltersGroup{display:flex;flex-wrap:wrap;align-items:center;gap:6px}.sm-markFiltersSpacer{flex:1 1 auto;min-width:12px}.sm-markFilterToggle{height:28px;padding:3px 10px;white-space:nowrap}.sm-markFilterToggle:disabled{opacity:.5;cursor:not-allowed}.sm-bulkSelectBtn{height:28px;padding:3px 10px;white-space:nowrap}.sm-bulkSelectBtn:disabled{opacity:.5;cursor:not-allowed}
|
|
495
|
-
|
|
669
|
+
".sm-tagChip,.sm-noteBadge{max-width:88px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;border:0;border-radius:4px;background:var(--dsw-alias-markdown-tag,#f1f3f5);color:var(--dsw-alias-label-secondary,#666);font:inherit;line-height:16px;padding:0 5px;cursor:pointer}.sm-noteBadge{background:transparent}.sm-tagChip:hover,.sm-noteBadge:hover{color:var(--dsw-alias-state-business-primary,#356ae6)}",
|
|
670
|
+
".sm-markFilters{display:flex;flex-wrap:wrap;align-items:center;gap:8px}.sm-markFiltersGroup{display:flex;flex-wrap:wrap;align-items:center;gap:6px}.sm-markFiltersSpacer{flex:1 1 auto;min-width:12px}.sm-markFilterToggle{height:28px;padding:3px 10px;white-space:nowrap}.sm-markFilterToggle:disabled{opacity:.5;cursor:not-allowed}.sm-bulkSelectBtn{height:28px;padding:3px 10px;white-space:nowrap}.sm-bulkSelectBtn:disabled{opacity:.5;cursor:not-allowed}",
|
|
671
|
+
// Layering contract (do not raise these above 1100).
|
|
672
|
+
// DSH's own scale is: 1000 = modal backdrop / full-viewport overlay,
|
|
673
|
+
// 1100 = floating tier shared by menus, popovers, dialogs AND the
|
|
674
|
+
// Tooltip bubble this plugin renders through renderTip(). DSH's Tooltip
|
|
675
|
+
// bubble has a hard-coded z-index (100 inline, 1100 when portaled) and
|
|
676
|
+
// exposes no class hook, so a plugin surface stacked above 1100 always
|
|
677
|
+
// hides its own tooltips.
|
|
678
|
+
// The plugin therefore keeps its two document-level layers inside the
|
|
679
|
+
// 1000..1100 gap -- the panel at 1020 and this overlay root at 1050 --
|
|
680
|
+
// and everything portaled into this root is relative to its context.
|
|
681
|
+
"#dsh-session-manager-overlay-root{position:fixed!important;inset:0!important;width:100%!important;height:100%!important;z-index:1050!important;pointer-events:none!important;overflow:visible!important}.sm-annotationDialog.sm-nativeDialogLayer{position:fixed;display:block;pointer-events:none;z-index:100002;background:transparent}.sm-annotationDialog .sm-nativeDialogBackdrop{display:none}.sm-annotationDialog.sm-annotationDialog-anchored.sm-nativeDialogLayer,.sm-confirmDialog.sm-confirmDialog-anchored.sm-nativeDialogLayer{inset:auto;background:transparent}.sm-annotationDialog.sm-confirmDialog.sm-nativeDialogLayer:not(.sm-annotationDialog-anchored){inset:50% auto auto calc(50vw + 308px);transform:translateY(-50%);max-height:calc(100vh - 32px)}.sm-panelDialog.sm-annotationSurface{position:absolute;width:360px;max-height:min(680px,calc(100vh - 32px));pointer-events:auto;z-index:100003;box-shadow:0 16px 48px rgba(0,0,0,.25)}.sm-panelDialog.sm-annotationSurface.sm-annotationSurface-anchored{position:relative;transform:none;left:auto;top:auto;margin:0}.sm-annotationCloseHint{margin:0 16px 8px;font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary)}",
|
|
496
682
|
".sm-annotationBody{padding:14px 16px;display:flex;flex-direction:column;gap:12px;min-height:0;overflow:auto;flex:1 1 auto}.sm-annotationTarget{font-size:12px;line-height:18px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-secondary,#666)}.sm-annotationChecks{display:grid;grid-template-columns:auto 1fr;column-gap:14px;row-gap:4px;align-items:center;font-size:13px}.sm-annotationChecks>label{display:flex;gap:6px;align-items:center;cursor:pointer}.sm-annotationChecks .sm-annotationPriority{display:inline-flex;align-items:center;gap:6px;font-size:13px;line-height:18px;color:inherit}.sm-annotationChecks .sm-prioritySelectInline{height:24px;padding:2px 6px;font-size:12px;line-height:18px;min-width:104px;width:auto;border-radius:6px;color:var(--dsw-alias-label-primary,#111)}.sm-annotationChecks>small{font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary,#888);justify-self:start}.sm-annotationHint,.sm-annotationBody small{font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary,#888)}",
|
|
497
|
-
".sm-noteInput{box-sizing:border-box;width:100%;min-height:60px;resize:vertical;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:7px;padding:8px;background:var(--dsw-alias-
|
|
498
|
-
".sm-bulkBar{box-sizing:border-box;display:grid;grid-template-columns:repeat(6,minmax(0,1fr));align-items:stretch;gap:6px;padding:8px 10px;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:10px;background:var(--dsw-alias-
|
|
683
|
+
".sm-noteInput{box-sizing:border-box;width:100%;min-height:60px;resize:vertical;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:7px;padding:8px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#111);font:inherit;font-size:13px;line-height:19px}.sm-noteInput:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#356ae6);outline-offset:2px}.sm-markConflict{display:flex;flex-direction:column;gap:5px;font-size:12px;padding:8px;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:6px}.sm-fieldWithClear .sm-fieldRow{position:relative;display:flex;align-items:flex-start;gap:4px}.sm-fieldRow .sm-queryInput{flex:1 1 auto;min-width:0}.sm-fieldRowNote{align-items:stretch}.sm-fieldClear{position:absolute;top:5px;right:6px;width:22px;height:22px;border:0;background:transparent;color:var(--dsw-alias-label-tertiary);cursor:pointer;border-radius:4px;font-size:14px;line-height:18px;display:inline-flex;align-items:center;justify-content:center;padding:0}.sm-fieldClear:hover,.sm-fieldClear:focus-visible{color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-interactive-bg-hover);outline:none}.sm-fieldClearNote{top:6px}.sm-importGroup{display:flex;flex-direction:column;gap:8px;padding:12px 16px;border-top:1px solid var(--dsw-alias-border-l2,#eee)}.sm-importGroupHeader{display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:20px}.sm-importLabel{color:var(--dsw-alias-label-secondary,#666);font-size:11px;line-height:16px}.sm-importGroupButtons{display:flex;align-items:center;gap:6px;flex:none}.sm-importBtn{cursor:pointer;color:var(--dsw-alias-label-primary,#111);background:transparent;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;min-height:28px;padding:3px 14px;font-size:12px;line-height:20px;text-align:center}.sm-importBtn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.sm-importBtn:disabled{opacity:.5;cursor:not-allowed}.sm-importStatus{margin:0;padding:8px 10px;font-size:12px;line-height:18px;background:var(--dsw-alias-state-business-tertiary,rgba(53,106,230,.08));color:var(--dsw-alias-label-secondary);border-radius:6px;white-space:pre-wrap;word-break:break-word}",
|
|
684
|
+
".sm-bulkBar{box-sizing:border-box;display:grid;grid-template-columns:repeat(6,minmax(0,1fr));align-items:stretch;gap:6px;padding:8px 10px;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:10px;background:var(--dsw-alias-bg-layer-2,#fff)}.sm-bulkBar .sm-bulkSummary{grid-column:1/-1;color:var(--dsw-alias-label-primary,#111);font-size:12px;line-height:18px;font-weight:500;margin:0 0 2px}",
|
|
499
685
|
".sm-bulkSummary{color:var(--dsw-alias-label-primary,#111);font-size:12px;line-height:18px;font-weight:500}",
|
|
500
686
|
"",
|
|
501
|
-
".sm-
|
|
687
|
+
".sm-panelDialog button,.sm-panelDialog a,.sm-panelHeaderGithub,.sm-panelHeaderWhale,.sm-panelHeaderClose,.sm-headerBtn,.sm-headerMenuItem,.sm-updateDialog button,.sm-settingsCard button,.sm-settingsCard a,.sm-rowBtn,.sm-bulkBtn{outline:none;box-shadow:none;-webkit-appearance:none;-moz-appearance:none;appearance:none}.sm-panelDialog button:hover,.sm-panelDialog a:hover,.sm-panelHeaderGithub:hover,.sm-panelHeaderWhale:hover,.sm-panelHeaderClose:hover,.sm-headerBtn:hover,.sm-headerMenuItem:hover,.sm-updateDialog button:hover,.sm-settingsCard button:hover,.sm-rowBtn:hover,.sm-bulkBtn:hover{outline:none;box-shadow:none}",
|
|
688
|
+
".sm-bulkBar .sm-bulkBtn{cursor:pointer;color:var(--dsw-alias-label-secondary,#666);background:transparent;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;padding:4px 10px;font-size:12px;line-height:18px;display:inline-flex;align-items:center;justify-content:center;gap:4px;white-space:nowrap;text-align:center}",
|
|
502
689
|
".sm-bulkBar .sm-bulkBtn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary,#111)}",
|
|
503
690
|
".sm-bulkBar .sm-bulkBtn:disabled{opacity:.5;cursor:not-allowed}",
|
|
504
|
-
".sm-bulkBar .sm-bulkBtnDanger{color:var(--dsw-alias-state-error-primary);border-color:
|
|
505
|
-
".sm-bulkBar .sm-bulkBtnDanger:hover:not(:disabled){color
|
|
691
|
+
".sm-bulkBar .sm-bulkBtnDanger{color:var(--dsw-alias-state-error-primary);border-color:color-mix(in srgb,var(--dsw-alias-state-error-primary,#ec1313) 45%,transparent)}",
|
|
692
|
+
".sm-bulkBar .sm-bulkBtnDanger:hover:not(:disabled){color:var(--dsw-alias-label-primary-foreground,#fff);background:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary)}",
|
|
506
693
|
"",
|
|
507
694
|
".sm-bulkRowCheckbox{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;flex:none}",
|
|
508
695
|
".sm-bulkRowCheckbox input{width:14px;height:14px;cursor:pointer;margin:0}",
|
|
509
696
|
".sm-bulkRowCheckbox input:disabled{cursor:not-allowed}",
|
|
510
|
-
".sm-rowBulkSelected{border-color:var(--dsw-alias-
|
|
511
|
-
".sm-bulkDialog.sm-nativeDialogLayer{position:fixed;left:calc(50vw + 184px);top:calc(50vh - 90px);width:360px;max-width:calc(100vw - 32px);max-height:none;display:block;align-items:initial;justify-content:initial;box-sizing:border-box;background:transparent;border:0;box-shadow:none;padding:0;inset:calc(50vh - 90px) auto auto calc(50vw + 308px);z-index:10002}.sm-bulkDialog.sm-nativeDialogLayer .sm-nativeDialogBackdrop{display:none}.sm-bulkDialog.sm-nativeDialogLayer .sm-nativeDialog{position:relative;left:auto;top:auto;transform:none;width:auto;box-sizing:border-box;background:var(--
|
|
697
|
+
".sm-rowBulkSelected{border-color:var(--dsw-alias-state-business-primary,#356ae6);background:var(--dsw-alias-state-business-tertiary,rgba(53,106,230,.06))}",
|
|
698
|
+
".sm-bulkDialog.sm-nativeDialogLayer{position:fixed;left:calc(50vw + 184px);top:calc(50vh - 90px);width:360px;max-width:calc(100vw - 32px);max-height:none;display:block;align-items:initial;justify-content:initial;box-sizing:border-box;background:transparent;border:0;box-shadow:none;padding:0;inset:calc(50vh - 90px) auto auto calc(50vw + 308px);z-index:10002}.sm-bulkDialog.sm-nativeDialogLayer .sm-nativeDialogBackdrop{display:none}.sm-bulkDialog.sm-nativeDialogLayer .sm-nativeDialog{position:relative;left:auto;top:auto;transform:none;width:auto;box-sizing:border-box;background:var(--sm-dialog-fill);color:var(--dsw-alias-label-primary,#111);border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:12px;box-shadow:0 16px 48px rgba(0,0,0,.25);padding:0;overflow:hidden;animation:sm-confirmPop .14s ease-out}.sm-bulkDialog .sm-nativeDialogHeader{padding:10px 16px;border-bottom:1px solid var(--dsw-alias-border-l2,#eee);flex:none;position:relative;display:flex;align-items:center;justify-content:center;min-height:44px;box-sizing:border-box}.sm-bulkDialog .sm-nativeDialogTitle{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);margin:0;font-size:14px;line-height:20px;font-weight:600;text-align:center;width:auto;max-width:calc(100% - 32px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sm-bulkDialog .sm-nativeDialogBody{padding:12px 16px;display:flex;flex-direction:column;gap:10px;font-size:13px;line-height:20px;color:var(--dsw-alias-label-primary,#111)}.sm-bulkDialog .sm-nativeDialogFooter{padding:10px 16px;display:flex;flex-wrap:wrap;justify-content:space-between;gap:6px}.sm-bulkDialog .sm-nativeDialogButton{min-height:28px;padding:3px 14px;font-size:12px;line-height:20px;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;cursor:pointer;background:transparent;color:var(--dsw-alias-label-primary,#111);text-align:center}.sm-bulkDialog .sm-nativeDialogConfirm{background:var(--dsw-alias-state-business-primary,#356ae6);color:var(--dsw-alias-label-primary-foreground,#fff);border-color:var(--dsw-alias-state-business-primary,#356ae6)}.sm-bulkDialog .sm-nativeDialogConfirm:hover:not(:disabled){filter:brightness(.94)}.sm-bulkDialog .sm-nativeDialogDanger{background:var(--dsw-alias-state-error-primary,#d92d20);color:var(--dsw-alias-label-primary-foreground,#fff);border-color:var(--dsw-alias-state-error-primary,#d92d20)}.sm-bulkDialog .sm-nativeDialogDanger:hover:not(:disabled){filter:brightness(.92)}.sm-bulkDialog .sm-nativeDialog select.sm-viewSelect{font-size:13px;line-height:20px;height:32px;padding:5px 9px}",
|
|
512
699
|
".sm-bulkDialog .sm-nativeDialog{width:100%;max-height:min(640px,calc(100vh - 32px))}",
|
|
513
700
|
".sm-bulkDialogBody{display:flex;flex-direction:column;gap:12px;min-height:0}",
|
|
514
701
|
".sm-bulkDialogSummary{font-size:13px;line-height:20px;color:var(--dsw-alias-label-primary,#111)}",
|
|
515
|
-
".sm-bulkDialogWarn{display:flex;align-items:flex-start;gap:8px;color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px;background:
|
|
702
|
+
".sm-bulkDialogWarn{display:flex;align-items:flex-start;gap:8px;color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px;background:color-mix(in srgb,var(--dsw-alias-state-error-primary,#ec1313) 8%,transparent);border:1px solid color-mix(in srgb,var(--dsw-alias-state-error-primary,#ec1313) 25%,transparent);border-radius:8px;padding:8px 10px}",
|
|
516
703
|
".sm-bulkSessionList{display:flex;flex-direction:column;gap:4px;max-height:200px;overflow:auto;border:1px solid var(--dsw-alias-border-l2,#eee);border-radius:8px;padding:6px}",
|
|
517
704
|
".sm-bulkSessionItem{font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary,#666);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}",
|
|
518
|
-
".sm-bulkProgressBar{position:relative;height:8px;background:var(--dsw-alias-
|
|
519
|
-
".sm-bulkProgressFill{position:absolute;top:0;left:0;bottom:0;background:var(--dsw-alias-
|
|
705
|
+
".sm-bulkProgressBar{position:relative;height:8px;background:var(--dsw-alias-bg-skeleton,#0000000a);border-radius:4px;overflow:hidden}",
|
|
706
|
+
".sm-bulkProgressFill{position:absolute;top:0;left:0;bottom:0;background:var(--dsw-alias-state-business-primary,#356ae6);transition:width .2s ease}",
|
|
520
707
|
".sm-bulkResultGroup{display:flex;flex-direction:column;gap:6px}",
|
|
521
708
|
".sm-bulkResultHeader{font-size:12px;line-height:18px;font-weight:500;color:var(--dsw-alias-label-secondary,#666)}",
|
|
522
709
|
".sm-bulkResultList{display:flex;flex-direction:column;gap:2px;max-height:160px;overflow:auto;border:1px solid var(--dsw-alias-border-l2,#eee);border-radius:8px;padding:6px}",
|
|
@@ -526,22 +713,25 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
526
713
|
".sm-bulkResultItemReason{color:var(--dsw-alias-state-error-primary);font-size:11px;line-height:16px;word-break:break-word}",
|
|
527
714
|
".sm-bulkResultItemReasonSkip{color:var(--dsw-alias-label-tertiary,#888)}",
|
|
528
715
|
".sm-bulkResultFooter{display:flex;justify-content:space-between;align-items:center;gap:8px;flex-wrap:wrap}",
|
|
529
|
-
".sm-footerBtn-wide{flex:
|
|
716
|
+
".sm-footerBtn-wide{flex:none;display:flex;align-items:center;gap:8px;width:calc(100% + 8px);height:34px;margin:4px -4px 4px;padding:6px 2px 6px 10px;box-sizing:border-box;border:none;border-radius:12px;cursor:pointer;overflow:hidden;font-size:14px;line-height:22px}",
|
|
530
717
|
".sm-footerBtn-wide:hover,.sm-footerBtn-wide:focus-visible{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}",
|
|
531
|
-
".sm-footerBtn-rail{width:36px;height:36px;padding:0;justify-content:center;border-radius:12px;color:var(--dsw-alias-label-secondary)}",
|
|
718
|
+
".sm-footerBtn-rail{width:36px;height:36px;padding:0;justify-content:center;border-radius:12px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;display:inline-flex;align-items:center}",
|
|
532
719
|
".sm-footerBtn-rail:hover,.sm-footerBtn-rail:focus-visible{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}",
|
|
533
720
|
".sm-footerBtn-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;max-width:100%}",
|
|
534
|
-
".sm-
|
|
535
|
-
".sm-
|
|
721
|
+
".sm-overlayLayer{position:fixed;inset:0;pointer-events:none}",
|
|
722
|
+
".sm-overlayLayer>*{pointer-events:auto}",
|
|
723
|
+
".sm-overlayBackdrop{position:fixed;inset:0;background:transparent;pointer-events:auto}",
|
|
536
724
|
"@media(max-width:720px){.sm-panelSelects{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}.sm-panelDialog .sm-row{flex-wrap:wrap}.sm-panelDialog .sm-rowMain{flex-basis:100%}.sm-panelDialog .sm-rowActions{width:100%;min-width:0;flex:1 1 100%;justify-content:flex-start}}@media(max-width:540px){.sm-panelSelects{grid-template-columns:minmax(0,1fr)}}",
|
|
537
725
|
].join("");
|
|
538
726
|
|
|
539
727
|
// Auto-follow DSH's theme. We detect DSH's current theme from
|
|
540
|
-
// body[data-ds-dark-theme] / color-scheme / data-theme / class tokens
|
|
541
|
-
// mirror it onto <html data-sm-theme
|
|
542
|
-
//
|
|
543
|
-
// inline
|
|
544
|
-
//
|
|
728
|
+
// body[data-ds-dark-theme] / color-scheme / data-theme / class tokens and
|
|
729
|
+
// mirror it onto <html data-sm-theme>. The scoped CSS rules above consume
|
|
730
|
+
// that attribute (light/dark fallback surface colour, local alias tokens).
|
|
731
|
+
// Deliberately no inline colour is written onto the dialogs any more:
|
|
732
|
+
// inline `!important` backgrounds/colors used to hard-code white / #1f1f23
|
|
733
|
+
// onto the dialog roots, which overrode any theme — including third-party
|
|
734
|
+
// themes that only publish --dsw-alias-* tokens.
|
|
545
735
|
const SM_THEME_ATTR = "data-sm-theme";
|
|
546
736
|
function smReadDshTheme() {
|
|
547
737
|
try {
|
|
@@ -572,29 +762,10 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
572
762
|
} catch (_) { /* ignore */ }
|
|
573
763
|
return "light";
|
|
574
764
|
}
|
|
575
|
-
function smApplyInlineTheme(theme) {
|
|
576
|
-
try {
|
|
577
|
-
const values = theme === "dark"
|
|
578
|
-
? { background: "#1f1f23", color: "#ececec", border: "#3a3a40" }
|
|
579
|
-
: { background: "#fff", color: "#1f1f1f", border: "#e5e5e5" };
|
|
580
|
-
const roots = document.querySelectorAll(
|
|
581
|
-
".sm-panelDialog," +
|
|
582
|
-
".sm-confirmDialog.sm-nativeDialogLayer .sm-nativeDialog," +
|
|
583
|
-
".sm-migrateDialog.sm-nativeDialogLayer .sm-nativeDialog"
|
|
584
|
-
);
|
|
585
|
-
for (const el of roots) {
|
|
586
|
-
el.style.setProperty("background", values.background, "important");
|
|
587
|
-
el.style.setProperty("background-color", values.background, "important");
|
|
588
|
-
el.style.setProperty("color", values.color, "important");
|
|
589
|
-
el.style.setProperty("border-color", values.border, "important");
|
|
590
|
-
}
|
|
591
|
-
} catch (_) { /* ignore */ }
|
|
592
|
-
}
|
|
593
765
|
function smApplyTheme() {
|
|
594
766
|
try {
|
|
595
767
|
const theme = smReadDshTheme();
|
|
596
768
|
document.documentElement.setAttribute(SM_THEME_ATTR, theme);
|
|
597
|
-
smApplyInlineTheme(theme);
|
|
598
769
|
} catch (_) { /* ignore */ }
|
|
599
770
|
}
|
|
600
771
|
smApplyTheme();
|
|
@@ -608,13 +779,66 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
608
779
|
} catch (_) { /* ignore */ }
|
|
609
780
|
}
|
|
610
781
|
|
|
782
|
+
// "Dialog opacity" preference (Issue #23).
|
|
783
|
+
//
|
|
784
|
+
// Generic, theme-agnostic escape hatch for third-party themes whose
|
|
785
|
+
// dialog surface does not match the plugin's own fill: the user tunes how
|
|
786
|
+
// much of *this plugin's* dialog background is painted, and whatever sits
|
|
787
|
+
// behind it (the theme's own surface) shows through. No theme plugin is
|
|
788
|
+
// detected or named, and no third-party CSS variable is read.
|
|
789
|
+
//
|
|
790
|
+
// The value is stored as a percentage in the plugin's own CSS variable on
|
|
791
|
+
// <html>; the CSS rules above turn it into the alpha channel of the dialog
|
|
792
|
+
// fill only, leaving text, buttons, inputs, borders and hover states
|
|
793
|
+
// opaque.
|
|
794
|
+
const SM_DIALOG_OPACITY = { min: 50, max: 100, step: 5, default: 100 };
|
|
795
|
+
const SM_DIALOG_OPACITY_KEY = "dsh-session-manager-dialog-opacity";
|
|
796
|
+
const SM_DIALOG_OPACITY_VAR = "--sm-dialog-opacity";
|
|
797
|
+
function smNormalizeDialogOpacity(value) {
|
|
798
|
+
const numeric = Number(value);
|
|
799
|
+
if (!Number.isFinite(numeric)) return SM_DIALOG_OPACITY.default;
|
|
800
|
+
const { min, max, step } = SM_DIALOG_OPACITY;
|
|
801
|
+
if (numeric <= min) return min;
|
|
802
|
+
if (numeric >= max) return max;
|
|
803
|
+
const snapped = min + Math.round((numeric - min) / step) * step;
|
|
804
|
+
return Math.min(max, Math.max(min, snapped));
|
|
805
|
+
}
|
|
806
|
+
function smReadDialogOpacity() {
|
|
807
|
+
try {
|
|
808
|
+
if (typeof localStorage !== "undefined") {
|
|
809
|
+
const raw = localStorage.getItem(SM_DIALOG_OPACITY_KEY);
|
|
810
|
+
if (raw !== null && raw !== "") return smNormalizeDialogOpacity(raw);
|
|
811
|
+
}
|
|
812
|
+
} catch (_) { /* storage unavailable: fall back to the default */ }
|
|
813
|
+
return SM_DIALOG_OPACITY.default;
|
|
814
|
+
}
|
|
815
|
+
function applyDialogOpacity(value) {
|
|
816
|
+
const percent = smNormalizeDialogOpacity(value);
|
|
817
|
+
try {
|
|
818
|
+
if (typeof document !== "undefined" && document.documentElement && document.documentElement.style) {
|
|
819
|
+
document.documentElement.style.setProperty(SM_DIALOG_OPACITY_VAR, percent + "%");
|
|
820
|
+
}
|
|
821
|
+
} catch (_) { /* ignore */ }
|
|
822
|
+
return percent;
|
|
823
|
+
}
|
|
824
|
+
applyDialogOpacity(smReadDialogOpacity());
|
|
825
|
+
|
|
611
826
|
const CSS_ID = "dsh-session-manager/session-manager";
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
827
|
+
const SM_CSS_SELECTOR = "style[data-plugin-css=" + JSON.stringify(CSS_ID) + "]";
|
|
828
|
+
if (typeof document !== "undefined" && typeof document.createElement === "function") {
|
|
829
|
+
let styleTag = typeof document.querySelector === "function" ? document.querySelector(SM_CSS_SELECTOR) : null;
|
|
830
|
+
if (!styleTag) {
|
|
831
|
+
styleTag = document.createElement("style");
|
|
832
|
+
styleTag.dataset.plugin = "dsh-session-manager";
|
|
833
|
+
styleTag.dataset.pluginCss = CSS_ID;
|
|
834
|
+
if (document.head && typeof document.head.appendChild === "function") document.head.appendChild(styleTag);
|
|
835
|
+
}
|
|
836
|
+
// Always rewrite the contents. A client-plugin hot reload re-executes the
|
|
837
|
+
// bundle inside the same page but leaves the <style> tag it created
|
|
838
|
+
// earlier in place; skipping the write there would silently keep the
|
|
839
|
+
// previous version's rules while the new JS (e.g. a new setting) is
|
|
840
|
+
// already live -- exactly the "setting present but has no effect" bug.
|
|
841
|
+
styleTag.textContent = css;
|
|
618
842
|
}
|
|
619
843
|
|
|
620
844
|
|
|
@@ -656,6 +880,275 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
656
880
|
try { installAnchor(); } catch (_) {}
|
|
657
881
|
|
|
658
882
|
const h = (type, props, ...children) => React.createElement(type, props, ...children);
|
|
883
|
+
|
|
884
|
+
let overlayRootElement = null;
|
|
885
|
+
function getOverlayRoot() {
|
|
886
|
+
if (typeof document === "undefined" || !document.body) return null;
|
|
887
|
+
if (typeof document.createElement !== "function") return null;
|
|
888
|
+
const contains = typeof document.body.contains === "function" ? (el) => document.body.contains(el) : () => true;
|
|
889
|
+
if (!overlayRootElement || !contains(overlayRootElement)) {
|
|
890
|
+
let el = typeof document.getElementById === "function"
|
|
891
|
+
? document.getElementById("dsh-session-manager-overlay-root")
|
|
892
|
+
: (typeof document.querySelector === "function" ? document.querySelector("#dsh-session-manager-overlay-root") : null);
|
|
893
|
+
if (!el) {
|
|
894
|
+
el = document.createElement("div");
|
|
895
|
+
el.id = "dsh-session-manager-overlay-root";
|
|
896
|
+
el.style.position = "fixed";
|
|
897
|
+
el.style.top = "0";
|
|
898
|
+
el.style.left = "0";
|
|
899
|
+
el.style.width = "100%";
|
|
900
|
+
el.style.height = "100%";
|
|
901
|
+
el.style.zIndex = "1050";
|
|
902
|
+
el.style.overflow = "visible";
|
|
903
|
+
el.style.pointerEvents = "none";
|
|
904
|
+
if (typeof document.body.appendChild === "function") {
|
|
905
|
+
document.body.appendChild(el);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
// Re-assert the z-index on an element created by an earlier version
|
|
909
|
+
// (a client-plugin hot reload re-executes this module in the same page
|
|
910
|
+
// and reuses the existing node, whose inline style would otherwise keep
|
|
911
|
+
// the old value). Must stay below DSH's 1100 floating/tooltip tier and
|
|
912
|
+
// above its 1000 backdrop tier -- see the layering contract in the
|
|
913
|
+
// stylesheet.
|
|
914
|
+
if (el.style && el.style.zIndex !== "1050") el.style.zIndex = "1050";
|
|
915
|
+
overlayRootElement = el;
|
|
916
|
+
}
|
|
917
|
+
try {
|
|
918
|
+
if (document.documentElement && typeof document.documentElement.getAttribute === "function") {
|
|
919
|
+
const currentTheme = document.documentElement.getAttribute(SM_THEME_ATTR);
|
|
920
|
+
if (currentTheme && overlayRootElement && typeof overlayRootElement.setAttribute === "function") {
|
|
921
|
+
if (overlayRootElement.getAttribute(SM_THEME_ATTR) !== currentTheme) {
|
|
922
|
+
overlayRootElement.setAttribute(SM_THEME_ATTR, currentTheme);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
} catch (_) {}
|
|
927
|
+
return overlayRootElement;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
function getPortalFn() {
|
|
931
|
+
if (typeof React.createPortal === "function") return React.createPortal;
|
|
932
|
+
if (typeof window !== "undefined") {
|
|
933
|
+
if (window.__smReactDOM && typeof window.__smReactDOM.createPortal === "function") return window.__smReactDOM.createPortal;
|
|
934
|
+
if (window.ReactDOM && typeof window.ReactDOM.createPortal === "function") return window.ReactDOM.createPortal;
|
|
935
|
+
if (window.React && typeof window.React.createPortal === "function") return window.React.createPortal;
|
|
936
|
+
}
|
|
937
|
+
try {
|
|
938
|
+
const RDOM = require("react-dom");
|
|
939
|
+
if (RDOM && typeof RDOM.createPortal === "function") return RDOM.createPortal;
|
|
940
|
+
} catch (_) {}
|
|
941
|
+
try {
|
|
942
|
+
const RDOMC = require("react-dom/client");
|
|
943
|
+
if (RDOMC && typeof RDOMC.createPortal === "function") return RDOMC.createPortal;
|
|
944
|
+
} catch (_) {}
|
|
945
|
+
return null;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
function renderInOverlay(vnode) {
|
|
949
|
+
if (!vnode) return null;
|
|
950
|
+
const root = getOverlayRoot();
|
|
951
|
+
const portal = getPortalFn();
|
|
952
|
+
if (portal && root) {
|
|
953
|
+
return portal(vnode, root);
|
|
954
|
+
}
|
|
955
|
+
return vnode;
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
function OverlayLayer({ children, className, style, onBackdropClick, role = "presentation", onKeyDown }) {
|
|
959
|
+
const zRef = useRef(null);
|
|
960
|
+
if (zRef.current === null) {
|
|
961
|
+
zRef.current = nextDialogZ();
|
|
962
|
+
}
|
|
963
|
+
const root = getOverlayRoot();
|
|
964
|
+
const portal = getPortalFn();
|
|
965
|
+
|
|
966
|
+
const layerStyle = {
|
|
967
|
+
position: "fixed",
|
|
968
|
+
inset: "0",
|
|
969
|
+
zIndex: zRef.current,
|
|
970
|
+
pointerEvents: "none",
|
|
971
|
+
...(style || {})
|
|
972
|
+
};
|
|
973
|
+
|
|
974
|
+
const content = h("div", {
|
|
975
|
+
className: "sm-overlayLayer " + (className || ""),
|
|
976
|
+
style: layerStyle,
|
|
977
|
+
role: role,
|
|
978
|
+
onKeyDown: onKeyDown
|
|
979
|
+
},
|
|
980
|
+
onBackdropClick ? h("div", {
|
|
981
|
+
className: "sm-nativeDialogBackdrop sm-overlayBackdrop",
|
|
982
|
+
style: {
|
|
983
|
+
position: "fixed",
|
|
984
|
+
inset: "0",
|
|
985
|
+
background: "transparent",
|
|
986
|
+
pointerEvents: "auto",
|
|
987
|
+
zIndex: -1
|
|
988
|
+
},
|
|
989
|
+
onClick: (e) => {
|
|
990
|
+
if (e.target === e.currentTarget && onBackdropClick) {
|
|
991
|
+
onBackdropClick(e);
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
}) : null,
|
|
995
|
+
children
|
|
996
|
+
);
|
|
997
|
+
|
|
998
|
+
if (portal && root) {
|
|
999
|
+
return portal(content, root);
|
|
1000
|
+
}
|
|
1001
|
+
return content;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
const raf = typeof requestAnimationFrame === "function" ? requestAnimationFrame : (fn) => setTimeout(fn, 16);
|
|
1005
|
+
const caf = typeof cancelAnimationFrame === "function" ? cancelAnimationFrame : (id) => clearTimeout(id);
|
|
1006
|
+
|
|
1007
|
+
function useFloatingPosition(anchor, open, options = {}) {
|
|
1008
|
+
const {
|
|
1009
|
+
placement = "bottom-end",
|
|
1010
|
+
dialogWidth = 360,
|
|
1011
|
+
dialogHeight = 220,
|
|
1012
|
+
gap = 8,
|
|
1013
|
+
margin = 16
|
|
1014
|
+
} = options;
|
|
1015
|
+
|
|
1016
|
+
const [coords, setCoords] = useState(() => {
|
|
1017
|
+
if (anchor && typeof anchor.top === "number" && typeof anchor.left === "number") {
|
|
1018
|
+
return { top: anchor.top, left: anchor.left };
|
|
1019
|
+
}
|
|
1020
|
+
return null;
|
|
1021
|
+
});
|
|
1022
|
+
|
|
1023
|
+
const anchorRef = useRef(anchor);
|
|
1024
|
+
anchorRef.current = anchor;
|
|
1025
|
+
|
|
1026
|
+
useEffect(() => {
|
|
1027
|
+
if (!open) return;
|
|
1028
|
+
const currentAnchor = anchorRef.current;
|
|
1029
|
+
if (!currentAnchor) return;
|
|
1030
|
+
|
|
1031
|
+
if (typeof currentAnchor.top === "number" && typeof currentAnchor.getBoundingClientRect !== "function") {
|
|
1032
|
+
setCoords({ top: currentAnchor.top, left: currentAnchor.left });
|
|
1033
|
+
return;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
const getEl = () => {
|
|
1037
|
+
const a = anchorRef.current;
|
|
1038
|
+
if (!a) return null;
|
|
1039
|
+
if (typeof a.getBoundingClientRect === "function") return a;
|
|
1040
|
+
if (a.current && typeof a.current.getBoundingClientRect === "function") return a.current;
|
|
1041
|
+
if (a.nodeType === 1) return a;
|
|
1042
|
+
return null;
|
|
1043
|
+
};
|
|
1044
|
+
|
|
1045
|
+
const targetEl = getEl();
|
|
1046
|
+
if (!targetEl) return;
|
|
1047
|
+
|
|
1048
|
+
let frameId = 0;
|
|
1049
|
+
const update = () => {
|
|
1050
|
+
caf(frameId);
|
|
1051
|
+
frameId = raf(() => {
|
|
1052
|
+
const el = getEl();
|
|
1053
|
+
if (!el) return;
|
|
1054
|
+
const r = el.getBoundingClientRect();
|
|
1055
|
+
if (!r || (r.width === 0 && r.height === 0 && r.top === 0 && r.bottom === 0)) {
|
|
1056
|
+
return;
|
|
1057
|
+
}
|
|
1058
|
+
const winW = typeof window !== "undefined" && window.innerWidth ? window.innerWidth : 1024;
|
|
1059
|
+
const winH = typeof window !== "undefined" && window.innerHeight ? window.innerHeight : 768;
|
|
1060
|
+
|
|
1061
|
+
let left;
|
|
1062
|
+
if (placement.endsWith("-end")) {
|
|
1063
|
+
left = r.right - dialogWidth;
|
|
1064
|
+
} else if (placement.endsWith("-start")) {
|
|
1065
|
+
left = r.left;
|
|
1066
|
+
} else {
|
|
1067
|
+
left = r.left + (r.width - dialogWidth) / 2;
|
|
1068
|
+
}
|
|
1069
|
+
left = Math.max(margin, Math.min(left, winW - dialogWidth - margin));
|
|
1070
|
+
|
|
1071
|
+
let top;
|
|
1072
|
+
const fitsBelow = (r.bottom + gap + dialogHeight) <= (winH - margin);
|
|
1073
|
+
const fitsAbove = (r.top - gap - dialogHeight) >= margin;
|
|
1074
|
+
|
|
1075
|
+
if (placement.startsWith("top")) {
|
|
1076
|
+
if (fitsAbove || !fitsBelow) {
|
|
1077
|
+
top = r.top - dialogHeight - gap;
|
|
1078
|
+
} else {
|
|
1079
|
+
top = r.bottom + gap;
|
|
1080
|
+
}
|
|
1081
|
+
top = Math.max(margin, Math.min(top, winH - dialogHeight - margin));
|
|
1082
|
+
} else {
|
|
1083
|
+
// For anchors near viewport top (like title bar actions), default to below.
|
|
1084
|
+
// Never jump upward over the header when there is insufficient space above.
|
|
1085
|
+
if (!fitsBelow && fitsAbove && r.top > dialogHeight + gap + margin) {
|
|
1086
|
+
top = r.top - dialogHeight - gap;
|
|
1087
|
+
} else {
|
|
1088
|
+
top = r.bottom + gap;
|
|
1089
|
+
}
|
|
1090
|
+
top = Math.max(margin, top);
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
setCoords({ top: Math.round(top), left: Math.round(left) });
|
|
1094
|
+
});
|
|
1095
|
+
};
|
|
1096
|
+
|
|
1097
|
+
update();
|
|
1098
|
+
|
|
1099
|
+
if (typeof window !== "undefined") {
|
|
1100
|
+
window.addEventListener("resize", update);
|
|
1101
|
+
window.addEventListener("scroll", update, true);
|
|
1102
|
+
if (window.visualViewport) {
|
|
1103
|
+
window.visualViewport.addEventListener("resize", update);
|
|
1104
|
+
window.visualViewport.addEventListener("scroll", update);
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
const pollTimer = setInterval(update, 100);
|
|
1109
|
+
|
|
1110
|
+
let ro = null;
|
|
1111
|
+
const getRealEl = (target) => {
|
|
1112
|
+
if (!target) return null;
|
|
1113
|
+
if (typeof Element !== "undefined" && target instanceof Element) return target;
|
|
1114
|
+
if (target.current && typeof Element !== "undefined" && target.current instanceof Element) return target.current;
|
|
1115
|
+
if (typeof target.resolveActiveEl === "function") {
|
|
1116
|
+
const resolved = target.resolveActiveEl();
|
|
1117
|
+
if (resolved && typeof Element !== "undefined" && resolved instanceof Element) return resolved;
|
|
1118
|
+
}
|
|
1119
|
+
if (target.nodeType === 1 && typeof target.addEventListener === "function") return target;
|
|
1120
|
+
return null;
|
|
1121
|
+
};
|
|
1122
|
+
const domEl = getRealEl(targetEl);
|
|
1123
|
+
if (typeof ResizeObserver === "function" && domEl) {
|
|
1124
|
+
try {
|
|
1125
|
+
ro = new ResizeObserver(update);
|
|
1126
|
+
ro.observe(domEl);
|
|
1127
|
+
if (domEl.parentElement) ro.observe(domEl.parentElement);
|
|
1128
|
+
const headerAncestor = typeof domEl.closest === "function" ? domEl.closest(".sm-header") : null;
|
|
1129
|
+
if (headerAncestor) ro.observe(headerAncestor);
|
|
1130
|
+
if (document.body) ro.observe(document.body);
|
|
1131
|
+
} catch (_) {}
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
return () => {
|
|
1135
|
+
caf(frameId);
|
|
1136
|
+
clearInterval(pollTimer);
|
|
1137
|
+
if (typeof window !== "undefined") {
|
|
1138
|
+
window.removeEventListener("resize", update);
|
|
1139
|
+
window.removeEventListener("scroll", update, true);
|
|
1140
|
+
if (window.visualViewport) {
|
|
1141
|
+
window.visualViewport.removeEventListener("resize", update);
|
|
1142
|
+
window.visualViewport.removeEventListener("scroll", update);
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
if (ro) ro.disconnect();
|
|
1146
|
+
};
|
|
1147
|
+
}, [open, placement, dialogWidth, dialogHeight, gap, margin]);
|
|
1148
|
+
|
|
1149
|
+
return coords;
|
|
1150
|
+
}
|
|
1151
|
+
|
|
659
1152
|
const callApi = (path, payload) => fetch(API + path, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(payload || {}) }).then((r) => r.json());
|
|
660
1153
|
const fetchApi = (path, options) => fetch(API + path, options).then((r) => r.json());
|
|
661
1154
|
// Run a bulk action across many sessionIds. /batch already does per-id
|
|
@@ -743,12 +1236,30 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
743
1236
|
const annotationButtons = (id, title, t, state, className, onToggle, onEdit, disabled = false, editorOpen = false) => {
|
|
744
1237
|
const value = annotationOf(state, id);
|
|
745
1238
|
const busy = disabled || !state.loaded || !!state.error || state.pending.has(id);
|
|
746
|
-
const
|
|
747
|
-
const
|
|
1239
|
+
const favoriteDesc = t(value.favorite ? "marks.favorite.remove" : "marks.favorite.add");
|
|
1240
|
+
const reviewDesc = t(value.reviewLater ? "marks.review.remove" : "marks.review.add");
|
|
1241
|
+
const favoriteLabel = favoriteDesc + ": " + title;
|
|
1242
|
+
const reviewLabel = reviewDesc + ": " + title;
|
|
1243
|
+
const isHeader = className === "sm-headerBtn";
|
|
748
1244
|
return h(React.Fragment, null,
|
|
749
|
-
h("button", { type: "button", className: className + " sm-markIcon" + (value.favorite ? " sm-markOn" : ""), disabled: busy, "aria-label": favoriteLabel,
|
|
750
|
-
|
|
751
|
-
|
|
1245
|
+
renderTip(favoriteDesc, h("button", { type: "button", className: className + " sm-markIcon" + (value.favorite ? " sm-markOn" : ""), disabled: busy, "aria-label": favoriteLabel, "aria-pressed": value.favorite, onClick: () => onToggle({ favorite: !value.favorite }) },
|
|
1246
|
+
h("span", { className: "sm-headerBtnIcon" }, value.favorite ? "★" : "☆")
|
|
1247
|
+
)),
|
|
1248
|
+
renderTip(reviewDesc, h("button", { type: "button", className: className + " sm-markIcon" + (value.reviewLater ? " sm-markOn" : ""), disabled: busy, "aria-label": reviewLabel, "aria-pressed": value.reviewLater, onClick: () => onToggle({ reviewLater: !value.reviewLater }) },
|
|
1249
|
+
h("span", { className: "sm-headerBtnIcon" }, "◷")
|
|
1250
|
+
)),
|
|
1251
|
+
renderTip(t("marks.edit.aria"), h("button", {
|
|
1252
|
+
type: "button",
|
|
1253
|
+
className: className + (isHeader ? " sm-headerSecondaryAction" : "") + (editorOpen ? " sm-annotationToggleOpen sm-headerBtnActive" : ""),
|
|
1254
|
+
disabled: busy,
|
|
1255
|
+
"aria-label": t("marks.edit.aria") + ": " + title,
|
|
1256
|
+
...(isHeader ? { "aria-expanded": editorOpen } : {}),
|
|
1257
|
+
onClick: e => onEdit(e)
|
|
1258
|
+
},
|
|
1259
|
+
isHeader ? h("span", { className: "sm-headerBtnIcon" }, "🏷") : null,
|
|
1260
|
+
isHeader ? h("span", { className: "sm-headerBtnLabel" }, t("marks.header.edit")) : t("marks.edit"),
|
|
1261
|
+
isHeader ? h("span", { className: "sm-priorityBadge sm-priority-" + (value.priority ?? 3) }, "P" + (value.priority ?? 3)) : null
|
|
1262
|
+
))
|
|
752
1263
|
);
|
|
753
1264
|
};
|
|
754
1265
|
|
|
@@ -1239,17 +1750,19 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
1239
1750
|
return "zh";
|
|
1240
1751
|
};
|
|
1241
1752
|
const activeLanguage = detectLanguage(t);
|
|
1242
|
-
const
|
|
1243
|
-
const
|
|
1244
|
-
const
|
|
1245
|
-
|
|
1246
|
-
|
|
1753
|
+
const floatingCoords = useFloatingPosition(anchor, true, { placement: "bottom-end", dialogWidth: 360, dialogHeight: 460 });
|
|
1754
|
+
const hasCoords = floatingCoords !== null || (anchor && typeof anchor.top === "number" && typeof anchor.left === "number");
|
|
1755
|
+
const computedTop = floatingCoords ? floatingCoords.top : (anchor && typeof anchor.top === "number" ? anchor.top : null);
|
|
1756
|
+
const computedLeft = floatingCoords ? floatingCoords.left : (anchor && typeof anchor.left === "number" ? anchor.left : null);
|
|
1757
|
+
const layerClass = "sm-nativeDialogLayer sm-annotationDialog sm-confirmDialog" + (hasCoords ? " sm-annotationDialog-anchored" : "");
|
|
1758
|
+
const surfaceClass = "sm-nativeDialog sm-panelDialog sm-annotationSurface" + (hasCoords ? " sm-annotationSurface-anchored" : "");
|
|
1247
1759
|
const layerStyle = {
|
|
1248
1760
|
zIndex: zIndex || undefined,
|
|
1249
|
-
...(
|
|
1761
|
+
...(hasCoords ? { position: "fixed", top: computedTop + "px", left: computedLeft + "px", right: "auto", bottom: "auto", inset: `${computedTop}px auto auto ${computedLeft}px` } : {})
|
|
1250
1762
|
};
|
|
1251
|
-
return
|
|
1252
|
-
h("
|
|
1763
|
+
return renderInOverlay(
|
|
1764
|
+
h("div", { className: layerClass, style: layerStyle, role: "presentation" },
|
|
1765
|
+
h("section", { className: surfaceClass, style: { pointerEvents: "auto" }, role: "dialog", "aria-labelledby": "sm-annotation-title", ref: dialogRef, onKeyDown },
|
|
1253
1766
|
h("div", { className: "sm-nativeDialogHeader" }, h("h2", { id: "sm-annotation-title", className: "sm-nativeDialogTitle" }, t("marks.title"))),
|
|
1254
1767
|
h("div", { className: "sm-annotationBody" },
|
|
1255
1768
|
h("div", { className: "sm-annotationTarget", title: displayTitle || sessionId }, displayTitle || sessionId),
|
|
@@ -1271,20 +1784,22 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
1271
1784
|
error ? h("div", { className: "sm-error", role: "alert" }, error) : null
|
|
1272
1785
|
),
|
|
1273
1786
|
h("div", { className: "sm-importGroup" },
|
|
1274
|
-
h("div", { className: "sm-
|
|
1275
|
-
h("
|
|
1276
|
-
h("
|
|
1787
|
+
h("div", { className: "sm-importGroupHeader" },
|
|
1788
|
+
h("span", { className: "sm-importLabel" }, t("marks.import.paste.label")),
|
|
1789
|
+
h("div", { className: "sm-importGroupButtons" },
|
|
1790
|
+
h("button", { type: "button", className: "sm-importBtn", disabled: busy || !importText.trim(), onClick: pasteFromInput }, t("marks.import.paste")),
|
|
1791
|
+
h("button", { type: "button", className: "sm-importBtn", disabled: busy, onClick: copyPrompt }, t("marks.import.copy")))),
|
|
1277
1792
|
h("div", { className: "sm-fieldWithClear" },
|
|
1278
1793
|
h("div", { className: "sm-fieldRow sm-fieldRowNote" },
|
|
1279
1794
|
h("textarea", { className: "sm-noteInput", "aria-label": t("marks.import.paste.aria"), value: importText, placeholder: t("marks.import.paste.placeholder"), disabled: busy, rows: 3, onChange: e => setImportText(e.target.value) }),
|
|
1280
1795
|
importText && !busy ? h("button", { type: "button", className: "sm-fieldClear sm-fieldClearNote", "aria-label": t("marks.import.paste.clear"), title: t("marks.import.paste.clear"), onClick: () => setImportText("") }, String.fromCharCode(10005)) : null))),
|
|
1281
1796
|
importStatus ? h("div", { className: "sm-importStatus", role: "status" }, importStatus) : null,
|
|
1282
1797
|
h("div", { className: "sm-nativeDialogFooter" },
|
|
1283
|
-
h("button", { type: "button", className: "sm-nativeDialogButton", disabled: busy, onClick: cancel }, t("marks.cancel")),
|
|
1798
|
+
h("button", { type: "button", className: "sm-nativeDialogButton sm-nativeDialogCancel", disabled: busy, onClick: cancel }, t("marks.cancel")),
|
|
1284
1799
|
h("button", { type: "button", className: "sm-nativeDialogButton sm-nativeDialogConfirm", disabled: busy || !annotations.loaded || !!annotations.error || latest.revision !== base.revision, onClick: save }, t(busy ? "marks.saving" : "marks.save"))
|
|
1285
1800
|
)
|
|
1286
1801
|
)
|
|
1287
|
-
);
|
|
1802
|
+
));
|
|
1288
1803
|
}
|
|
1289
1804
|
|
|
1290
1805
|
|
|
@@ -1351,24 +1866,31 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
1351
1866
|
window.addEventListener("keydown", handler);
|
|
1352
1867
|
return () => window.removeEventListener("keydown", handler);
|
|
1353
1868
|
}, [open]);
|
|
1354
|
-
// Render inline as a sibling of the panel; createPortal to document.body broke under some hosts. Migrate and AnnotationDialog render inline; do the same here.
|
|
1355
1869
|
|
|
1870
|
+
const floatingCoords = useFloatingPosition(props.anchor, open, { placement: "bottom-end", dialogWidth: 360, dialogHeight: 180 });
|
|
1356
1871
|
|
|
1357
1872
|
if (!open) return null;
|
|
1358
1873
|
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
zIndex: zIndex || undefined,
|
|
1363
|
-
...(props.anchor && typeof props.anchor.top === "number"
|
|
1364
|
-
? { position: "fixed", top: props.anchor.top + "px", left: props.anchor.left + "px" }
|
|
1365
|
-
: {})
|
|
1366
|
-
},
|
|
1367
|
-
role: "presentation"
|
|
1368
|
-
},
|
|
1874
|
+
const topPx = floatingCoords ? floatingCoords.top : (props.anchor && typeof props.anchor.top === "number" ? props.anchor.top : null);
|
|
1875
|
+
const leftPx = floatingCoords ? floatingCoords.left : (props.anchor && typeof props.anchor.left === "number" ? props.anchor.left : null);
|
|
1876
|
+
const hasCoords = topPx !== null && leftPx !== null;
|
|
1369
1877
|
|
|
1370
|
-
|
|
1371
|
-
|
|
1878
|
+
const layerStyle = {
|
|
1879
|
+
zIndex: zIndex || undefined,
|
|
1880
|
+
...(hasCoords
|
|
1881
|
+
? { position: "fixed", top: topPx + "px", left: leftPx + "px", right: "auto", bottom: "auto", inset: `${topPx}px auto auto ${leftPx}px` }
|
|
1882
|
+
: {})
|
|
1883
|
+
};
|
|
1884
|
+
|
|
1885
|
+
return renderInOverlay(
|
|
1886
|
+
h("div", {
|
|
1887
|
+
className: "sm-nativeDialogLayer sm-confirmDialog" + (hasCoords ? " sm-confirmDialog-anchored" : ""),
|
|
1888
|
+
style: layerStyle,
|
|
1889
|
+
role: "presentation"
|
|
1890
|
+
},
|
|
1891
|
+
h("section", {
|
|
1892
|
+
className: "sm-nativeDialog",
|
|
1893
|
+
style: { pointerEvents: "auto" },
|
|
1372
1894
|
role: "dialog",
|
|
1373
1895
|
"aria-modal": "true",
|
|
1374
1896
|
"aria-labelledby": "sm-confirm-dialog-title"
|
|
@@ -1395,7 +1917,7 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
1395
1917
|
}, confirmLabel)
|
|
1396
1918
|
)
|
|
1397
1919
|
)
|
|
1398
|
-
);
|
|
1920
|
+
));
|
|
1399
1921
|
}
|
|
1400
1922
|
|
|
1401
1923
|
function MoveDialog(props) {
|
|
@@ -1476,20 +1998,27 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
1476
1998
|
onConfirm(selectedWorkspaceId);
|
|
1477
1999
|
}
|
|
1478
2000
|
};
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
...(props.anchor && typeof props.anchor.top === "number"
|
|
1484
|
-
? { position: "fixed", top: props.anchor.top + "px", left: props.anchor.left + "px" }
|
|
1485
|
-
: {})
|
|
1486
|
-
},
|
|
1487
|
-
role: "presentation",
|
|
1488
|
-
onKeyDown
|
|
1489
|
-
},
|
|
2001
|
+
const floatingCoords = useFloatingPosition(props.anchor, open, { placement: "bottom-end", dialogWidth: 360, dialogHeight: 320 });
|
|
2002
|
+
const topPx = floatingCoords ? floatingCoords.top : (props.anchor && typeof props.anchor.top === "number" ? props.anchor.top : null);
|
|
2003
|
+
const leftPx = floatingCoords ? floatingCoords.left : (props.anchor && typeof props.anchor.left === "number" ? props.anchor.left : null);
|
|
2004
|
+
const hasCoords = topPx !== null && leftPx !== null;
|
|
1490
2005
|
|
|
1491
|
-
|
|
1492
|
-
|
|
2006
|
+
const layerStyle = {
|
|
2007
|
+
zIndex: zIndex || undefined,
|
|
2008
|
+
...(hasCoords
|
|
2009
|
+
? { position: "fixed", top: topPx + "px", left: leftPx + "px", right: "auto", bottom: "auto", inset: `${topPx}px auto auto ${leftPx}px` }
|
|
2010
|
+
: {})
|
|
2011
|
+
};
|
|
2012
|
+
return renderInOverlay(
|
|
2013
|
+
h("div", {
|
|
2014
|
+
className: "sm-nativeDialogLayer sm-confirmDialog" + (hasCoords ? " sm-confirmDialog-anchored" : ""),
|
|
2015
|
+
style: layerStyle,
|
|
2016
|
+
role: "presentation",
|
|
2017
|
+
onKeyDown
|
|
2018
|
+
},
|
|
2019
|
+
h("section", {
|
|
2020
|
+
className: "sm-nativeDialog",
|
|
2021
|
+
style: { pointerEvents: "auto" },
|
|
1493
2022
|
role: "dialog",
|
|
1494
2023
|
"aria-modal": "true",
|
|
1495
2024
|
"aria-labelledby": "sm-move-dialog-title"
|
|
@@ -1513,7 +2042,7 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
1513
2042
|
}, confirmLabel)
|
|
1514
2043
|
)
|
|
1515
2044
|
)
|
|
1516
|
-
);
|
|
2045
|
+
));
|
|
1517
2046
|
}
|
|
1518
2047
|
|
|
1519
2048
|
function MigratePresetDialog(props) {
|
|
@@ -1610,14 +2139,15 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
1610
2139
|
target === currentPreset ? h("div", { className: "sm-migrateWarn" }, t("migrate.same")) : null
|
|
1611
2140
|
)
|
|
1612
2141
|
);
|
|
1613
|
-
return
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
2142
|
+
return renderInOverlay(
|
|
2143
|
+
h("div", {
|
|
2144
|
+
className: "sm-nativeDialogLayer sm-confirmDialog sm-migrateConfirmLayer",
|
|
2145
|
+
role: "presentation",
|
|
2146
|
+
style: { zIndex: zIndex || undefined }
|
|
2147
|
+
},
|
|
2148
|
+
h("section", {
|
|
2149
|
+
className: "sm-nativeDialog sm-migrateDialog",
|
|
2150
|
+
style: { pointerEvents: "auto" },
|
|
1621
2151
|
role: "dialog",
|
|
1622
2152
|
"aria-modal": "true",
|
|
1623
2153
|
"aria-labelledby": "sm-migrate-dialog-title"
|
|
@@ -1641,9 +2171,295 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
1641
2171
|
}, busy ? t("busy.processing") : t("migrate.confirm"))
|
|
1642
2172
|
)
|
|
1643
2173
|
)
|
|
1644
|
-
);
|
|
2174
|
+
));
|
|
2175
|
+
}
|
|
2176
|
+
|
|
2177
|
+
const CURRENT_VERSION = "0.6.3";
|
|
2178
|
+
|
|
2179
|
+
function compareSemver(v1, v2) {
|
|
2180
|
+
if (typeof v1 !== "string" || typeof v2 !== "string") return 0;
|
|
2181
|
+
const parse = (v) => {
|
|
2182
|
+
// Strip build metadata (+...)
|
|
2183
|
+
const noBuild = v.trim().replace(/^[vV]/, "").split("+")[0];
|
|
2184
|
+
const hyphenIdx = noBuild.indexOf("-");
|
|
2185
|
+
const core = hyphenIdx === -1 ? noBuild : noBuild.slice(0, hyphenIdx);
|
|
2186
|
+
const prerelease = hyphenIdx === -1 ? undefined : noBuild.slice(hyphenIdx + 1);
|
|
2187
|
+
const parts = (core || "").split(".").map(n => parseInt(n, 10) || 0);
|
|
2188
|
+
while (parts.length < 3) parts.push(0);
|
|
2189
|
+
return { parts, prerelease: prerelease !== undefined ? prerelease.trim() : undefined };
|
|
2190
|
+
};
|
|
2191
|
+
const p1 = parse(v1);
|
|
2192
|
+
const p2 = parse(v2);
|
|
2193
|
+
for (let i = 0; i < 3; i++) {
|
|
2194
|
+
if (p1.parts[i] > p2.parts[i]) return 1;
|
|
2195
|
+
if (p1.parts[i] < p2.parts[i]) return -1;
|
|
2196
|
+
}
|
|
2197
|
+
// When major, minor, patch match: version without prerelease is higher
|
|
2198
|
+
if (p1.prerelease && !p2.prerelease) return -1;
|
|
2199
|
+
if (!p1.prerelease && p2.prerelease) return 1;
|
|
2200
|
+
if (p1.prerelease && p2.prerelease) {
|
|
2201
|
+
if (p1.prerelease === p2.prerelease) return 0;
|
|
2202
|
+
const id1 = p1.prerelease.split(".");
|
|
2203
|
+
const id2 = p2.prerelease.split(".");
|
|
2204
|
+
const maxLen = Math.max(id1.length, id2.length);
|
|
2205
|
+
for (let i = 0; i < maxLen; i++) {
|
|
2206
|
+
if (i >= id1.length) return -1;
|
|
2207
|
+
if (i >= id2.length) return 1;
|
|
2208
|
+
const part1 = id1[i];
|
|
2209
|
+
const part2 = id2[i];
|
|
2210
|
+
if (part1 === part2) continue;
|
|
2211
|
+
const num1 = /^\d+$/.test(part1) ? parseInt(part1, 10) : null;
|
|
2212
|
+
const num2 = /^\d+$/.test(part2) ? parseInt(part2, 10) : null;
|
|
2213
|
+
if (num1 !== null && num2 !== null) {
|
|
2214
|
+
if (num1 > num2) return 1;
|
|
2215
|
+
if (num1 < num2) return -1;
|
|
2216
|
+
} else if (num1 !== null && num2 === null) {
|
|
2217
|
+
return -1;
|
|
2218
|
+
} else if (num1 === null && num2 !== null) {
|
|
2219
|
+
return 1;
|
|
2220
|
+
} else {
|
|
2221
|
+
if (part1 > part2) return 1;
|
|
2222
|
+
if (part1 < part2) return -1;
|
|
2223
|
+
}
|
|
2224
|
+
}
|
|
2225
|
+
}
|
|
2226
|
+
return 0;
|
|
1645
2227
|
}
|
|
1646
2228
|
|
|
2229
|
+
let activeClientCtx = null;
|
|
2230
|
+
|
|
2231
|
+
const updateStore = {
|
|
2232
|
+
state: {
|
|
2233
|
+
status: "idle",
|
|
2234
|
+
currentVersion: CURRENT_VERSION,
|
|
2235
|
+
latestVersion: null,
|
|
2236
|
+
error: null,
|
|
2237
|
+
application: null,
|
|
2238
|
+
dialogOpen: false,
|
|
2239
|
+
checkedAt: null,
|
|
2240
|
+
},
|
|
2241
|
+
listeners: new Set(),
|
|
2242
|
+
getSnapshot() { return this.state; },
|
|
2243
|
+
subscribe(cb) {
|
|
2244
|
+
this.listeners.add(cb);
|
|
2245
|
+
return () => this.listeners.delete(cb);
|
|
2246
|
+
},
|
|
2247
|
+
_notify() {
|
|
2248
|
+
this.state = { ...this.state };
|
|
2249
|
+
for (const fn of [...this.listeners]) fn();
|
|
2250
|
+
},
|
|
2251
|
+
openDialog() {
|
|
2252
|
+
this.state.dialogOpen = true;
|
|
2253
|
+
this._notify();
|
|
2254
|
+
},
|
|
2255
|
+
closeDialog() {
|
|
2256
|
+
this.state.dialogOpen = false;
|
|
2257
|
+
this._notify();
|
|
2258
|
+
},
|
|
2259
|
+
getAutoCheck() {
|
|
2260
|
+
try {
|
|
2261
|
+
if (typeof localStorage !== "undefined") {
|
|
2262
|
+
return localStorage.getItem("dsh-session-manager-auto-check") !== "false";
|
|
2263
|
+
}
|
|
2264
|
+
} catch (_) {}
|
|
2265
|
+
return true;
|
|
2266
|
+
},
|
|
2267
|
+
setAutoCheck(enabled) {
|
|
2268
|
+
try {
|
|
2269
|
+
if (typeof localStorage !== "undefined") {
|
|
2270
|
+
localStorage.setItem("dsh-session-manager-auto-check", enabled ? "true" : "false");
|
|
2271
|
+
}
|
|
2272
|
+
} catch (_) {}
|
|
2273
|
+
this._notify();
|
|
2274
|
+
},
|
|
2275
|
+
// Dialog opacity preference (Issue #23). Reuses the same localStorage
|
|
2276
|
+
// backed preference store as autoCheck / registry instead of adding a
|
|
2277
|
+
// second storage mechanism.
|
|
2278
|
+
DIALOG_OPACITY: SM_DIALOG_OPACITY,
|
|
2279
|
+
DIALOG_OPACITY_KEY: SM_DIALOG_OPACITY_KEY,
|
|
2280
|
+
getDialogOpacity() {
|
|
2281
|
+
return smReadDialogOpacity();
|
|
2282
|
+
},
|
|
2283
|
+
setDialogOpacity(value) {
|
|
2284
|
+
const next = applyDialogOpacity(value);
|
|
2285
|
+
try {
|
|
2286
|
+
if (typeof localStorage !== "undefined") {
|
|
2287
|
+
localStorage.setItem(SM_DIALOG_OPACITY_KEY, String(next));
|
|
2288
|
+
}
|
|
2289
|
+
} catch (_) {}
|
|
2290
|
+
this._notify();
|
|
2291
|
+
return next;
|
|
2292
|
+
},
|
|
2293
|
+
resetDialogOpacity() {
|
|
2294
|
+
return this.setDialogOpacity(SM_DIALOG_OPACITY.default);
|
|
2295
|
+
},
|
|
2296
|
+
REGISTRY_OPTIONS: {
|
|
2297
|
+
"registry.npmjs.org": "https://registry.npmjs.org",
|
|
2298
|
+
"registry.npmmirror.com": "https://registry.npmmirror.com",
|
|
2299
|
+
},
|
|
2300
|
+
DEFAULT_REGISTRY: "registry.npmjs.org",
|
|
2301
|
+
getRegistry() {
|
|
2302
|
+
try {
|
|
2303
|
+
if (typeof localStorage !== "undefined") {
|
|
2304
|
+
const v = localStorage.getItem("dsh-session-manager-registry");
|
|
2305
|
+
if (v && this.REGISTRY_OPTIONS[v]) return v;
|
|
2306
|
+
}
|
|
2307
|
+
} catch (_) {}
|
|
2308
|
+
return this.DEFAULT_REGISTRY;
|
|
2309
|
+
},
|
|
2310
|
+
setRegistry(key) {
|
|
2311
|
+
try {
|
|
2312
|
+
if (typeof localStorage !== "undefined") {
|
|
2313
|
+
if (this.REGISTRY_OPTIONS[key]) {
|
|
2314
|
+
localStorage.setItem("dsh-session-manager-registry", key);
|
|
2315
|
+
} else {
|
|
2316
|
+
localStorage.setItem("dsh-session-manager-registry", this.DEFAULT_REGISTRY);
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2319
|
+
} catch (_) {}
|
|
2320
|
+
this._notify();
|
|
2321
|
+
},
|
|
2322
|
+
getRegistryUrl() {
|
|
2323
|
+
return this.REGISTRY_OPTIONS[this.getRegistry()] || this.REGISTRY_OPTIONS[this.DEFAULT_REGISTRY];
|
|
2324
|
+
},
|
|
2325
|
+
async checkForUpdate(options = {}) {
|
|
2326
|
+
const { silent = false, openOnFound = true, manual = false } = options;
|
|
2327
|
+
const shouldOpenDialog = options.openDialog ?? (manual && !silent && options.openOnFound !== false);
|
|
2328
|
+
if (this.state.status === "checking" || this.state.status === "updating") return this.state;
|
|
2329
|
+
|
|
2330
|
+
this.state.status = "checking";
|
|
2331
|
+
this.state.error = null;
|
|
2332
|
+
if (shouldOpenDialog) {
|
|
2333
|
+
this.state.dialogOpen = true;
|
|
2334
|
+
}
|
|
2335
|
+
this._notify();
|
|
2336
|
+
|
|
2337
|
+
try {
|
|
2338
|
+
let res = null;
|
|
2339
|
+
if (typeof window !== "undefined" && window.__DSH_SM_TEST_UPDATE__) {
|
|
2340
|
+
const testOverride = window.__DSH_SM_TEST_UPDATE__;
|
|
2341
|
+
if (testOverride.error) {
|
|
2342
|
+
throw new Error(testOverride.error);
|
|
2343
|
+
}
|
|
2344
|
+
const cur = testOverride.currentVersion || this.state.currentVersion;
|
|
2345
|
+
const lat = testOverride.latestVersion || "9.9.9";
|
|
2346
|
+
const hasUpdate = compareSemver(lat, cur) > 0;
|
|
2347
|
+
res = { ok: true, result: { currentVersion: cur, latestVersion: lat, hasUpdate } };
|
|
2348
|
+
} else {
|
|
2349
|
+
const registryUrl = this.getRegistryUrl();
|
|
2350
|
+
const registryParam = encodeURIComponent(registryUrl);
|
|
2351
|
+
try {
|
|
2352
|
+
res = await fetchApi("/update/check?registry=" + registryParam);
|
|
2353
|
+
} catch (fetchErr) {
|
|
2354
|
+
try {
|
|
2355
|
+
const base = registryUrl.endsWith("/") ? registryUrl : registryUrl + "/";
|
|
2356
|
+
const npmRes = await fetch(base + "dsh-session-manager/latest");
|
|
2357
|
+
if (npmRes.ok) {
|
|
2358
|
+
const npmData = await npmRes.json();
|
|
2359
|
+
if (npmData && npmData.version) {
|
|
2360
|
+
const cur = this.state.currentVersion;
|
|
2361
|
+
const lat = npmData.version;
|
|
2362
|
+
const hasUpdate = compareSemver(lat, cur) > 0;
|
|
2363
|
+
res = { ok: true, result: { currentVersion: cur, latestVersion: lat, hasUpdate } };
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2366
|
+
} catch (_) {}
|
|
2367
|
+
if (!res) throw fetchErr;
|
|
2368
|
+
}
|
|
2369
|
+
}
|
|
2370
|
+
|
|
2371
|
+
if (!res || !res.ok) {
|
|
2372
|
+
throw new Error(res?.error || "检查更新失败");
|
|
2373
|
+
}
|
|
2374
|
+
|
|
2375
|
+
const result = res.result || {};
|
|
2376
|
+
const currentVersion = result.currentVersion || this.state.currentVersion;
|
|
2377
|
+
const latestVersion = result.latestVersion || currentVersion;
|
|
2378
|
+
const hasUpdate = !!result.hasUpdate || compareSemver(latestVersion, currentVersion) > 0;
|
|
2379
|
+
|
|
2380
|
+
this.state.currentVersion = currentVersion;
|
|
2381
|
+
this.state.latestVersion = latestVersion;
|
|
2382
|
+
this.state.checkedAt = Date.now();
|
|
2383
|
+
|
|
2384
|
+
if (hasUpdate) {
|
|
2385
|
+
this.state.status = "available";
|
|
2386
|
+
if (openOnFound && !silent) {
|
|
2387
|
+
this.state.dialogOpen = true;
|
|
2388
|
+
}
|
|
2389
|
+
} else {
|
|
2390
|
+
this.state.status = "idle";
|
|
2391
|
+
if (shouldOpenDialog) {
|
|
2392
|
+
this.state.dialogOpen = true;
|
|
2393
|
+
}
|
|
2394
|
+
}
|
|
2395
|
+
this._notify();
|
|
2396
|
+
return this.state;
|
|
2397
|
+
} catch (err) {
|
|
2398
|
+
this.state.status = "error";
|
|
2399
|
+
this.state.error = err.message || "检查更新失败";
|
|
2400
|
+
if (shouldOpenDialog) {
|
|
2401
|
+
this.state.dialogOpen = true;
|
|
2402
|
+
}
|
|
2403
|
+
this._notify();
|
|
2404
|
+
return this.state;
|
|
2405
|
+
}
|
|
2406
|
+
},
|
|
2407
|
+
async startUpdate(options = {}) {
|
|
2408
|
+
const { openDialog = false } = options;
|
|
2409
|
+
if (this.state.status === "updating") return this.state;
|
|
2410
|
+
this.state.status = "updating";
|
|
2411
|
+
this.state.error = null;
|
|
2412
|
+
if (openDialog) {
|
|
2413
|
+
this.state.dialogOpen = true;
|
|
2414
|
+
}
|
|
2415
|
+
this._notify();
|
|
2416
|
+
|
|
2417
|
+
const targetVersion = this.state.latestVersion || "latest";
|
|
2418
|
+
const spec = "dsh-session-manager@" + targetVersion;
|
|
2419
|
+
|
|
2420
|
+
try {
|
|
2421
|
+
let outcome = null;
|
|
2422
|
+
if (typeof window !== "undefined" && window.__DSH_SM_TEST_UPDATE__) {
|
|
2423
|
+
const testOverride = window.__DSH_SM_TEST_UPDATE__;
|
|
2424
|
+
if (testOverride.error) {
|
|
2425
|
+
throw new Error(testOverride.error);
|
|
2426
|
+
}
|
|
2427
|
+
if (typeof testOverride.installBundle === "function") {
|
|
2428
|
+
outcome = await testOverride.installBundle(spec);
|
|
2429
|
+
} else {
|
|
2430
|
+
await new Promise(r => setTimeout(r, 100));
|
|
2431
|
+
outcome = { application: testOverride.application || "restart-required" };
|
|
2432
|
+
}
|
|
2433
|
+
} else {
|
|
2434
|
+
const remotePm = activeClientCtx?.remote?.pluginManager || activeClientCtx?.pluginManager;
|
|
2435
|
+
if (remotePm && typeof remotePm.installBundle === "function") {
|
|
2436
|
+
outcome = await remotePm.installBundle(spec);
|
|
2437
|
+
} else {
|
|
2438
|
+
const res = await callApi("/update/install", { version: targetVersion, registry: this.getRegistryUrl() });
|
|
2439
|
+
if (!res || !res.ok) {
|
|
2440
|
+
throw new Error(res?.error || "安装更新失败");
|
|
2441
|
+
}
|
|
2442
|
+
outcome = res.result;
|
|
2443
|
+
}
|
|
2444
|
+
}
|
|
2445
|
+
|
|
2446
|
+
const application = outcome?.application || "restart-required";
|
|
2447
|
+
this.state.status = "done";
|
|
2448
|
+
this.state.application = application;
|
|
2449
|
+
this._notify();
|
|
2450
|
+
return outcome;
|
|
2451
|
+
} catch (err) {
|
|
2452
|
+
this.state.status = "error";
|
|
2453
|
+
this.state.error = err.message || "更新安装失败";
|
|
2454
|
+
if (openDialog) {
|
|
2455
|
+
this.state.dialogOpen = true;
|
|
2456
|
+
}
|
|
2457
|
+
this._notify();
|
|
2458
|
+
return { ok: false, error: this.state.error };
|
|
2459
|
+
}
|
|
2460
|
+
}
|
|
2461
|
+
};
|
|
2462
|
+
|
|
1647
2463
|
const panelStore = {
|
|
1648
2464
|
open: false,
|
|
1649
2465
|
listeners: new Set(),
|
|
@@ -1661,6 +2477,7 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
1661
2477
|
setPendingMove(v) { this.pendingMove = v; this._emitPending(); },
|
|
1662
2478
|
consumePendingMove() { const v = this.pendingMove; this.pendingMove = null; return v; }
|
|
1663
2479
|
};
|
|
2480
|
+
const lastBatchContext = { action: null, ids: [] };
|
|
1664
2481
|
|
|
1665
2482
|
const DEFAULT_SORT = "updated-desc";
|
|
1666
2483
|
const SORT_ORDERS = ["updated-desc", "updated-asc", "created-desc", "created-asc", "priority"];
|
|
@@ -1716,6 +2533,11 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
1716
2533
|
const onMigrate = props.onMigrate;
|
|
1717
2534
|
const annotations = useAnnotations(true);
|
|
1718
2535
|
const marksReady = annotations.loaded && !annotations.error;
|
|
2536
|
+
const updateState = useSyncExternalStore(
|
|
2537
|
+
(cb) => updateStore.subscribe(cb),
|
|
2538
|
+
() => updateStore.getSnapshot(),
|
|
2539
|
+
() => updateStore.getSnapshot()
|
|
2540
|
+
);
|
|
1719
2541
|
const [onlyFavorite, setOnlyFavorite] = useState(false);
|
|
1720
2542
|
const [onlyReview, setOnlyReview] = useState(false);
|
|
1721
2543
|
const [tagFilter, setTagFilter] = useState("all");
|
|
@@ -1839,6 +2661,8 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
1839
2661
|
setBulkProgress(null);
|
|
1840
2662
|
setBulkResult({ action, actionLabel, items });
|
|
1841
2663
|
setBulkBusy(false);
|
|
2664
|
+
lastBatchContext.action = action;
|
|
2665
|
+
lastBatchContext.ids = ids;
|
|
1842
2666
|
try { await annotationStore.load(true); } catch (_) { /* ignore */ }
|
|
1843
2667
|
if (typeof props.onRefreshAfterBulk === "function") {
|
|
1844
2668
|
try { await props.onRefreshAfterBulk(action); } catch (_) { /* ignore */ }
|
|
@@ -1890,16 +2714,16 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
1890
2714
|
const onBulkTagApply = (tags) => {
|
|
1891
2715
|
const mode = bulkTagDraft && bulkTagDraft.mode;
|
|
1892
2716
|
setBulkTagDraft(null);
|
|
1893
|
-
if (mode === "add") onBulkAction("add-tags", { tags },
|
|
2717
|
+
if (mode === "add") onBulkAction("add-tags", { tags }, false);
|
|
1894
2718
|
};
|
|
1895
2719
|
const onBulkPriorityApply = (value) => {
|
|
1896
2720
|
const priority = Number(value);
|
|
1897
2721
|
setBulkTagDraft(null);
|
|
1898
|
-
if (Number.isInteger(priority) && priority >= 1 && priority <= 5) onBulkAction("set-priority", { priority },
|
|
2722
|
+
if (Number.isInteger(priority) && priority >= 1 && priority <= 5) onBulkAction("set-priority", { priority }, false);
|
|
1899
2723
|
};
|
|
1900
2724
|
const onBulkMoveApply = (value) => {
|
|
1901
2725
|
setBulkTagDraft(null);
|
|
1902
|
-
if (value) onBulkAction("move", { targetWorkspaceId: value },
|
|
2726
|
+
if (value) onBulkAction("move", { targetWorkspaceId: value }, false);
|
|
1903
2727
|
};
|
|
1904
2728
|
const [bulkPresetDraft, setBulkPresetDraft] = useState(null);
|
|
1905
2729
|
const [bulkPresetOptions, setBulkPresetOptions] = useState([]);
|
|
@@ -1925,7 +2749,7 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
1925
2749
|
};
|
|
1926
2750
|
const onBulkPresetApply = (value) => {
|
|
1927
2751
|
setBulkPresetDraft(null);
|
|
1928
|
-
if (value) onBulkAction("preset-migrate", { toPreset: value },
|
|
2752
|
+
if (value) onBulkAction("preset-migrate", { toPreset: value }, false);
|
|
1929
2753
|
};
|
|
1930
2754
|
const bulkMoveOptions = useMemo(() => workspaces.map(ws => ({ value: ws.id, label: ws.title || ws.name || ws.id })), [workspaces]);
|
|
1931
2755
|
const bulkPriorityOptions = useMemo(() => [1, 2, 3, 4, 5].map(value => ({ value: String(value), label: t("marks.priority." + value) })), [t]);
|
|
@@ -2158,29 +2982,74 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
2158
2982
|
"aria-labelledby": "sm-panel-dialog-title"
|
|
2159
2983
|
},
|
|
2160
2984
|
h("div", { className: "sm-nativeDialogHeader" },
|
|
2161
|
-
h("
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2985
|
+
h("div", { className: "sm-panelHeaderLeft" },
|
|
2986
|
+
renderTip(t("panel.github.title"), h("a", {
|
|
2987
|
+
href: "https://github.com/hkkz9522/dsh-session-manager",
|
|
2988
|
+
target: "_blank",
|
|
2989
|
+
rel: "noopener noreferrer",
|
|
2990
|
+
className: "sm-panelHeaderGithub",
|
|
2991
|
+
"aria-label": t("panel.github.title")
|
|
2992
|
+
},
|
|
2993
|
+
h("svg", { viewBox: "0 0 16 16", width: 16, height: 16, "aria-hidden": "true" },
|
|
2994
|
+
h("path", {
|
|
2995
|
+
fill: "currentColor",
|
|
2996
|
+
d: "M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"
|
|
2997
|
+
})
|
|
2998
|
+
)
|
|
2999
|
+
)),
|
|
3000
|
+
renderTip(updateState.status === "available"
|
|
3001
|
+
? t("panel.update.badge")
|
|
3002
|
+
: updateState.status === "checking"
|
|
3003
|
+
? t("update.checking")
|
|
3004
|
+
: updateState.status === "done"
|
|
3005
|
+
? t("update.done.applied")
|
|
3006
|
+
: updateState.status === "error"
|
|
3007
|
+
? (updateState.error || t("update.error"))
|
|
3008
|
+
: t("panel.update.title"),
|
|
3009
|
+
h("a", {
|
|
3010
|
+
role: "button",
|
|
3011
|
+
tabIndex: 0,
|
|
3012
|
+
className: "sm-panelHeaderGithub sm-panelHeaderWhale" + (updateState.status === "available" ? " sm-hasUpdate" : ""),
|
|
3013
|
+
"aria-label": updateState.status === "available"
|
|
3014
|
+
? t("panel.update.badge")
|
|
3015
|
+
: updateState.status === "checking"
|
|
3016
|
+
? t("update.checking")
|
|
3017
|
+
: t("panel.update.title"),
|
|
3018
|
+
onClick: (e) => {
|
|
3019
|
+
if (e && typeof e.preventDefault === "function") e.preventDefault();
|
|
3020
|
+
if (updateState.status === "available" || updateState.status === "done" || updateState.status === "updating") {
|
|
3021
|
+
updateStore.openDialog();
|
|
3022
|
+
} else {
|
|
3023
|
+
updateStore.openDialog();
|
|
3024
|
+
updateStore.checkForUpdate({ manual: true, silent: false, openDialog: true });
|
|
3025
|
+
}
|
|
3026
|
+
},
|
|
3027
|
+
onKeyDown: (e) => {
|
|
3028
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
3029
|
+
if (e && typeof e.preventDefault === "function") e.preventDefault();
|
|
3030
|
+
if (updateState.status === "available" || updateState.status === "done" || updateState.status === "updating") {
|
|
3031
|
+
updateStore.openDialog();
|
|
3032
|
+
} else {
|
|
3033
|
+
updateStore.openDialog();
|
|
3034
|
+
updateStore.checkForUpdate({ manual: true, silent: false, openDialog: true });
|
|
3035
|
+
}
|
|
3036
|
+
}
|
|
3037
|
+
}
|
|
3038
|
+
},
|
|
3039
|
+
h(NpmIcon, { size: 16 }),
|
|
3040
|
+
updateState.status === "available" ? h("span", { className: "sm-updateDot", "aria-hidden": "true" }) : null,
|
|
3041
|
+
updateState.status === "checking" ? h("span", { className: "sm-updateSpinner", "aria-hidden": "true" }) : null
|
|
3042
|
+
)),
|
|
2175
3043
|
),
|
|
2176
3044
|
h("h2", { id: "sm-panel-dialog-title", className: "sm-nativeDialogTitle" }, t("panel.title")),
|
|
2177
3045
|
h("div", { className: "sm-nativeDialogHeaderActions" },
|
|
2178
|
-
h("button", {
|
|
3046
|
+
renderTip(t("panel.close") || "关闭", h("button", {
|
|
2179
3047
|
type: "button",
|
|
2180
3048
|
className: "sm-panelHeaderClose",
|
|
2181
3049
|
disabled: busyId !== null || migrating,
|
|
2182
|
-
onClick: onPanelClose
|
|
2183
|
-
|
|
3050
|
+
onClick: onPanelClose,
|
|
3051
|
+
"aria-label": t("panel.close")
|
|
3052
|
+
}, h(CloseIcon, { size: 14 })))
|
|
2184
3053
|
)
|
|
2185
3054
|
),
|
|
2186
3055
|
h("div", { className: "sm-panel" },
|
|
@@ -2343,8 +3212,9 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
2343
3212
|
// Render the panel AND the inner dialog as siblings so React keeps
|
|
2344
3213
|
// both mounted. CSS z-index keeps the right ordering: the inner
|
|
2345
3214
|
// dialog (.sm-confirmDialog / .sm-moveDialog / .sm-migrateDialog)
|
|
2346
|
-
//
|
|
2347
|
-
//
|
|
3215
|
+
// lives in the #dsh-session-manager-overlay-root context (1050) and
|
|
3216
|
+
// therefore sits ON TOP OF the panel (1020, in DSH's own document
|
|
3217
|
+
// context). Clicking inside the panel that the inner dialog
|
|
2348
3218
|
// blocks is not possible because the inner backdrop covers the
|
|
2349
3219
|
// panel area entirely (the inner modal is centered).
|
|
2350
3220
|
const annotationDialog = annotationFor ? h(AnnotationDialog, { key: annotationFor.id, sessionId: annotationFor.id, displayTitle: annotationFor.displayTitle || annotationFor.id, t, anchor: annotationAnchor, onClose: () => { setAnnotationFor(null); setAnnotationAnchor(null); } }) : null;
|
|
@@ -2431,7 +3301,9 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
2431
3301
|
onCancel: () => setBulkPresetDraft(null),
|
|
2432
3302
|
onApply: onBulkPresetApply
|
|
2433
3303
|
}) : null;
|
|
2434
|
-
// Bulk dialogs
|
|
3304
|
+
// Bulk dialogs are portaled into the overlay root like every other
|
|
3305
|
+
// dialog, so their static z-index (10002) only orders them inside that
|
|
3306
|
+
// context; the root's own 1050 keeps them below DSH's 1100 tooltip tier.
|
|
2435
3307
|
return h(React.Fragment, null, panelModal, annotationDialog, moveDialog, deleteDialog, migrateDialog, bulkPreviewDialog, bulkProgressDialog, bulkResultDialog, bulkTagDialog, bulkPriorityDialog, bulkMoveDialog, bulkPresetDialog);
|
|
2436
3308
|
}
|
|
2437
3309
|
|
|
@@ -2494,30 +3366,119 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
2494
3366
|
});
|
|
2495
3367
|
return () => { alive = false; };
|
|
2496
3368
|
}, [moveFor ? (moveFor.id || "x") : null]);
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
const
|
|
2501
|
-
|
|
2502
|
-
|
|
3369
|
+
const [moreOpen, setMoreOpen] = useState(false);
|
|
3370
|
+
const headerRef = useRef(null);
|
|
3371
|
+
const moreBtnRef = useRef(null);
|
|
3372
|
+
const moreBtnElRef = useRef(null);
|
|
3373
|
+
useEffect(() => {
|
|
3374
|
+
if (!moreOpen) return;
|
|
3375
|
+
const onDocClick = (e) => {
|
|
3376
|
+
if (moreBtnRef.current && moreBtnRef.current.contains(e.target)) return;
|
|
3377
|
+
setMoreOpen(false);
|
|
3378
|
+
};
|
|
3379
|
+
const onKey = (e) => {
|
|
3380
|
+
if (e.key === "Escape") setMoreOpen(false);
|
|
3381
|
+
};
|
|
3382
|
+
window.addEventListener("click", onDocClick, true);
|
|
3383
|
+
window.addEventListener("keydown", onKey, true);
|
|
3384
|
+
return () => {
|
|
3385
|
+
window.removeEventListener("click", onDocClick, true);
|
|
3386
|
+
window.removeEventListener("keydown", onKey, true);
|
|
3387
|
+
};
|
|
3388
|
+
}, [moreOpen]);
|
|
3389
|
+
|
|
3390
|
+
const getMoreBtn = () => {
|
|
3391
|
+
if (moreBtnElRef.current && moreBtnElRef.current.nodeType === 1) return moreBtnElRef.current;
|
|
3392
|
+
if (moreBtnRef.current) {
|
|
3393
|
+
const btn = moreBtnRef.current.querySelector(".sm-headerCompactMenuBtn");
|
|
3394
|
+
if (btn) return btn;
|
|
3395
|
+
}
|
|
3396
|
+
if (headerRef.current) {
|
|
3397
|
+
const btn = headerRef.current.querySelector(".sm-headerCompactMenuBtn");
|
|
3398
|
+
if (btn) return btn;
|
|
3399
|
+
}
|
|
3400
|
+
return null;
|
|
3401
|
+
};
|
|
3402
|
+
|
|
3403
|
+
const isVisible = (element) => {
|
|
3404
|
+
if (!element || typeof element.getBoundingClientRect !== "function") return false;
|
|
3405
|
+
if (typeof element.isConnected === "boolean" && !element.isConnected) return false;
|
|
3406
|
+
const rect = element.getBoundingClientRect();
|
|
3407
|
+
if (rect.width === 0 && rect.height === 0) return false;
|
|
3408
|
+
if (typeof element.offsetParent !== "undefined" && element.offsetParent === null && element.style?.position !== "fixed") return false;
|
|
3409
|
+
return true;
|
|
3410
|
+
};
|
|
3411
|
+
|
|
3412
|
+
const resolveActiveAnchorEl = (targetEl, actionType) => {
|
|
3413
|
+
if (isVisible(targetEl)) return targetEl;
|
|
3414
|
+
const moreBtn = getMoreBtn();
|
|
3415
|
+
if (isVisible(moreBtn)) return moreBtn;
|
|
3416
|
+
if (headerRef.current) {
|
|
3417
|
+
if (actionType === "annotation") {
|
|
3418
|
+
const btn = headerRef.current.querySelector(".sm-headerSecondaryAction")
|
|
3419
|
+
|| headerRef.current.querySelector(".sm-annotationToggleOpen")
|
|
3420
|
+
|| headerRef.current.querySelector("[aria-label*='marks']")
|
|
3421
|
+
|| headerRef.current.querySelector("[aria-label*='标签']");
|
|
3422
|
+
if (isVisible(btn)) return btn;
|
|
3423
|
+
} else if (actionType === "move") {
|
|
3424
|
+
const btn = headerRef.current.querySelector(".sm-headerSecondaryActions button:first-child")
|
|
3425
|
+
|| headerRef.current.querySelector("[aria-label*='move']")
|
|
3426
|
+
|| headerRef.current.querySelector("[aria-label*='移动']");
|
|
3427
|
+
if (isVisible(btn)) return btn;
|
|
3428
|
+
} else if (actionType === "delete") {
|
|
3429
|
+
const btn = headerRef.current.querySelector(".sm-headerSecondaryActions button:last-child")
|
|
3430
|
+
|| headerRef.current.querySelector(".sm-headerBtnDanger");
|
|
3431
|
+
if (isVisible(btn)) return btn;
|
|
3432
|
+
}
|
|
3433
|
+
if (isVisible(headerRef.current)) return headerRef.current;
|
|
3434
|
+
}
|
|
3435
|
+
return moreBtn || targetEl || null;
|
|
3436
|
+
};
|
|
3437
|
+
|
|
3438
|
+
// Anchor dialogs to the trigger button with dynamic tracking (issue #19 / #20).
|
|
3439
|
+
const anchorFor = (el, actionType) => {
|
|
3440
|
+
const domEl = el?.nodeType === 1 ? el : (el?.currentTarget || el?.target || el?.current || el);
|
|
3441
|
+
if (!domEl || typeof domEl.getBoundingClientRect !== "function") return domEl || null;
|
|
3442
|
+
|
|
3443
|
+
const activeEl = resolveActiveAnchorEl(domEl, actionType);
|
|
3444
|
+
const r = (activeEl && isVisible(activeEl) ? activeEl : domEl).getBoundingClientRect();
|
|
3445
|
+
|
|
2503
3446
|
return {
|
|
2504
3447
|
top: Math.round(r.top + r.height + 6),
|
|
2505
|
-
left: Math.max(8, Math.round(r.right - 360))
|
|
3448
|
+
left: Math.max(8, Math.round(r.right - 360)),
|
|
3449
|
+
current: domEl,
|
|
3450
|
+
nodeType: domEl.nodeType,
|
|
3451
|
+
actionType: actionType,
|
|
3452
|
+
resolveActiveEl: () => resolveActiveAnchorEl(domEl, actionType),
|
|
3453
|
+
getBoundingClientRect: () => {
|
|
3454
|
+
const currentEl = resolveActiveAnchorEl(domEl, actionType);
|
|
3455
|
+
if (currentEl && typeof currentEl.getBoundingClientRect === "function") {
|
|
3456
|
+
const curR = currentEl.getBoundingClientRect();
|
|
3457
|
+
if (curR.width > 0 || curR.height > 0) return curR;
|
|
3458
|
+
}
|
|
3459
|
+
if (headerRef.current && typeof headerRef.current.getBoundingClientRect === "function") {
|
|
3460
|
+
const hr = headerRef.current.getBoundingClientRect();
|
|
3461
|
+
if (hr.width > 0 || hr.height > 0) return hr;
|
|
3462
|
+
}
|
|
3463
|
+
return r;
|
|
3464
|
+
}
|
|
2506
3465
|
};
|
|
2507
3466
|
};
|
|
2508
3467
|
const archiveLabelKey = isArchived ? "row.unarchive" : "row.archive";
|
|
2509
3468
|
return h(React.Fragment, null,
|
|
2510
3469
|
annotationFor ? h(AnnotationDialog, { key: annotationFor.id, sessionId: annotationFor.id, displayTitle: annotationFor.displayTitle, t, anchor: annotationAnchor, onClose: () => { setAnnotationFor(null); setAnnotationAnchor(null); } }) : null,
|
|
2511
|
-
h("div", { className: "sm-header" },
|
|
2512
|
-
h("button", {
|
|
3470
|
+
h("div", { className: "sm-header", ref: headerRef },
|
|
3471
|
+
(onArchive || onUnarchive) ? renderTip(t ? t(archiveLabelKey) : (isArchived ? "移出归档" : "归档会话"), h("button", {
|
|
2513
3472
|
type: "button",
|
|
2514
3473
|
className: "sm-headerBtn" + (isArchived ? " sm-headerBtnActive" : ""),
|
|
2515
3474
|
"aria-label": t ? t(archiveLabelKey) : (isArchived ? "移出归档" : "归档会话"),
|
|
2516
3475
|
onClick: () => runWithAlert("archive", () =>
|
|
2517
3476
|
isArchived ? onUnarchive(sessionId) : onArchive(sessionId)
|
|
2518
3477
|
)
|
|
2519
|
-
},
|
|
2520
|
-
|
|
3478
|
+
},
|
|
3479
|
+
h("span", { className: "sm-headerBtnIcon" }, isArchived ? "📤" : "📥"),
|
|
3480
|
+
h("span", { className: "sm-headerBtnLabel" }, isArchived ? (t ? t("row.unarchive") : "移出归档") : (t ? t("row.archive") : "归档"))
|
|
3481
|
+
)) : null,
|
|
2521
3482
|
annotationButtons(sessionId, props.displayTitle || sessionId, t, annotations, "sm-headerBtn", patch => runWithAlert("annotations", () => annotationStore.save(sessionId, patch)), (e) => {
|
|
2522
3483
|
const nextOpen = !(annotationFor && annotationFor.id === sessionId);
|
|
2523
3484
|
// Do NOT clear moveFor / confirmFor here: the z-index counter
|
|
@@ -2525,51 +3486,143 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
2525
3486
|
// popup must not silently dismiss a previously opened move or
|
|
2526
3487
|
// delete popup on the same session.
|
|
2527
3488
|
if (nextOpen && e && e.currentTarget) {
|
|
2528
|
-
|
|
2529
|
-
setAnnotationAnchor({ top: Math.round(r.top + r.height + 6), left: Math.max(8, Math.round(r.right - 360)) });
|
|
3489
|
+
setAnnotationAnchor(anchorFor(e.currentTarget, "annotation"));
|
|
2530
3490
|
} else setAnnotationAnchor(null);
|
|
2531
3491
|
setAnnotationFor(current => current?.id === sessionId ? null : { id: sessionId, displayTitle });
|
|
2532
3492
|
}, false, annotationFor?.id === sessionId),
|
|
2533
|
-
annotations.error ? h("button", { type: "button", className: "sm-headerBtn",
|
|
3493
|
+
annotations.error ? renderTip(t("marks.error", { message: annotations.error }), h("button", { type: "button", className: "sm-headerBtn", "aria-label": t("marks.retry"), onClick: () => annotationStore.load(true) }, "!")) : null,
|
|
2534
3494
|
|
|
2535
|
-
h("
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
e
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
3495
|
+
h("div", { className: "sm-headerSecondaryActions" },
|
|
3496
|
+
renderTip(t ? t("row.move") : "移动至工作区", h("button", {
|
|
3497
|
+
type: "button",
|
|
3498
|
+
className: "sm-headerBtn" + (moveFor ? " sm-headerBtnActive" : ""),
|
|
3499
|
+
"aria-label": t ? t("row.move") : "移动至工作区",
|
|
3500
|
+
onClick: (e) => {
|
|
3501
|
+
if (e && typeof e.stopPropagation === "function") e.stopPropagation();
|
|
3502
|
+
// Do NOT clear confirmFor / confirmAnchor here: opening the
|
|
3503
|
+
// move popup must not silently dismiss a previously opened
|
|
3504
|
+
// delete popup on the same session. The z-index counter
|
|
3505
|
+
// (see nextDialogZ) handles stacking.
|
|
3506
|
+
if (moveFor && moveFor.id === sessionId) {
|
|
3507
|
+
setMoveFor(null);
|
|
3508
|
+
setMoveAnchor(null);
|
|
3509
|
+
} else {
|
|
3510
|
+
setMoveAnchor(anchorFor(e?.currentTarget, "move"));
|
|
3511
|
+
setMoveFor({ id: sessionId, displayTitle, workspaceId: "" });
|
|
3512
|
+
}
|
|
2551
3513
|
}
|
|
2552
|
-
}
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
3514
|
+
},
|
|
3515
|
+
h("span", { className: "sm-headerBtnIcon" }, "↔"),
|
|
3516
|
+
h("span", { className: "sm-headerBtnLabel" }, t ? t("row.move") : "移动至工作区")
|
|
3517
|
+
)),
|
|
3518
|
+
renderTip(t ? t("row.delete") : "删除会话", h("button", {
|
|
3519
|
+
type: "button",
|
|
3520
|
+
className: "sm-headerBtn sm-headerBtnDanger" + (confirmFor ? " sm-headerBtnActive" : ""),
|
|
3521
|
+
"aria-label": t ? t("row.delete") : "删除会话",
|
|
3522
|
+
onClick: (e) => {
|
|
3523
|
+
if (e && typeof e.stopPropagation === "function") e.stopPropagation();
|
|
3524
|
+
// Do NOT clear moveFor / moveAnchor here: opening the delete
|
|
3525
|
+
// popup must not silently dismiss a previously opened move
|
|
3526
|
+
// popup on the same session. The z-index counter (see
|
|
3527
|
+
// nextDialogZ) handles stacking.
|
|
3528
|
+
if (confirmFor && confirmFor.id === sessionId) {
|
|
3529
|
+
setConfirmFor(null);
|
|
3530
|
+
setConfirmAnchor(null);
|
|
3531
|
+
} else {
|
|
3532
|
+
setConfirmAnchor(anchorFor(e?.currentTarget, "delete"));
|
|
3533
|
+
setConfirmFor({ id: sessionId, displayTitle });
|
|
3534
|
+
}
|
|
2570
3535
|
}
|
|
2571
|
-
}
|
|
2572
|
-
|
|
3536
|
+
},
|
|
3537
|
+
h("span", { className: "sm-headerBtnIcon" }, "🗑"),
|
|
3538
|
+
h("span", { className: "sm-headerBtnLabel" }, t ? t("row.delete") : "删除会话")
|
|
3539
|
+
))
|
|
3540
|
+
),
|
|
3541
|
+
h("div", { className: "sm-headerCompactMenu", ref: moreBtnRef },
|
|
3542
|
+
renderTip((t && t("header.more")) || "更多操作", h("button", {
|
|
3543
|
+
ref: moreBtnElRef,
|
|
3544
|
+
type: "button",
|
|
3545
|
+
className: "sm-headerBtn sm-headerCompactMenuBtn" + (moreOpen ? " sm-headerBtnActive" : ""),
|
|
3546
|
+
"aria-label": (t && t("header.more")) || "更多操作",
|
|
3547
|
+
"aria-haspopup": "menu",
|
|
3548
|
+
"aria-expanded": moreOpen,
|
|
3549
|
+
onClick: (e) => {
|
|
3550
|
+
if (e && typeof e.stopPropagation === "function") e.stopPropagation();
|
|
3551
|
+
setMoreOpen(v => !v);
|
|
3552
|
+
}
|
|
3553
|
+
},
|
|
3554
|
+
h("span", { className: "sm-headerBtnIcon" }, "⋯")
|
|
3555
|
+
)),
|
|
3556
|
+
moreOpen ? h("div", { className: "sm-headerMenu", role: "menu" },
|
|
3557
|
+
h("button", {
|
|
3558
|
+
type: "button",
|
|
3559
|
+
className: "sm-headerMenuItem",
|
|
3560
|
+
role: "menuitem",
|
|
3561
|
+
onClick: () => {
|
|
3562
|
+
const anchorEl = getMoreBtn() || moreBtnRef.current;
|
|
3563
|
+
setMoreOpen(false);
|
|
3564
|
+
const nextOpen = !(annotationFor && annotationFor.id === sessionId);
|
|
3565
|
+
if (nextOpen && anchorEl) {
|
|
3566
|
+
setAnnotationAnchor(anchorFor(anchorEl, "annotation"));
|
|
3567
|
+
} else setAnnotationAnchor(null);
|
|
3568
|
+
setAnnotationFor(curr => (curr?.id === sessionId ? null : { id: sessionId, displayTitle }));
|
|
3569
|
+
}
|
|
3570
|
+
},
|
|
3571
|
+
h("span", { className: "sm-headerBtnIcon" }, "🏷"),
|
|
3572
|
+
h("span", null, t ? t("marks.header.edit") : "标签/备注")
|
|
3573
|
+
),
|
|
3574
|
+
h("button", {
|
|
3575
|
+
type: "button",
|
|
3576
|
+
className: "sm-headerMenuItem",
|
|
3577
|
+
role: "menuitem",
|
|
3578
|
+
onClick: () => {
|
|
3579
|
+
const anchorEl = getMoreBtn() || moreBtnRef.current;
|
|
3580
|
+
setMoreOpen(false);
|
|
3581
|
+
if (moveFor && moveFor.id === sessionId) {
|
|
3582
|
+
setMoveFor(null);
|
|
3583
|
+
setMoveAnchor(null);
|
|
3584
|
+
} else {
|
|
3585
|
+
setMoveAnchor(anchorFor(anchorEl, "move"));
|
|
3586
|
+
setMoveFor({ id: sessionId, displayTitle, workspaceId: "" });
|
|
3587
|
+
}
|
|
3588
|
+
}
|
|
3589
|
+
},
|
|
3590
|
+
h("span", { className: "sm-headerBtnIcon" }, "↔"),
|
|
3591
|
+
h("span", null, t ? t("row.move") : "移动至工作区")
|
|
3592
|
+
),
|
|
3593
|
+
(onArchive || onUnarchive) ? h("button", {
|
|
3594
|
+
type: "button",
|
|
3595
|
+
className: "sm-headerMenuItem",
|
|
3596
|
+
role: "menuitem",
|
|
3597
|
+
onClick: () => {
|
|
3598
|
+
setMoreOpen(false);
|
|
3599
|
+
runWithAlert("archive", () => isArchived ? onUnarchive(sessionId) : onArchive(sessionId));
|
|
3600
|
+
}
|
|
3601
|
+
},
|
|
3602
|
+
h("span", { className: "sm-headerBtnIcon" }, isArchived ? "📤" : "📥"),
|
|
3603
|
+
h("span", null, isArchived ? (t ? t("row.unarchive") : "移出归档") : (t ? t("row.archive") : "归档"))
|
|
3604
|
+
) : null,
|
|
3605
|
+
h("button", {
|
|
3606
|
+
type: "button",
|
|
3607
|
+
className: "sm-headerMenuItem sm-headerMenuItemDanger",
|
|
3608
|
+
role: "menuitem",
|
|
3609
|
+
onClick: () => {
|
|
3610
|
+
const anchorEl = getMoreBtn() || moreBtnRef.current;
|
|
3611
|
+
setMoreOpen(false);
|
|
3612
|
+
if (confirmFor && confirmFor.id === sessionId) {
|
|
3613
|
+
setConfirmFor(null);
|
|
3614
|
+
setConfirmAnchor(null);
|
|
3615
|
+
} else {
|
|
3616
|
+
setConfirmAnchor(anchorFor(anchorEl, "delete"));
|
|
3617
|
+
setConfirmFor({ id: sessionId, displayTitle });
|
|
3618
|
+
}
|
|
3619
|
+
}
|
|
3620
|
+
},
|
|
3621
|
+
h("span", { className: "sm-headerBtnIcon" }, "🗑"),
|
|
3622
|
+
h("span", null, t ? t("row.delete") : "删除会话")
|
|
3623
|
+
)
|
|
3624
|
+
) : null
|
|
3625
|
+
)
|
|
2573
3626
|
),
|
|
2574
3627
|
confirmFor === null ? null : h(ConfirmDialog, {
|
|
2575
3628
|
open: true,
|
|
@@ -2626,8 +3679,8 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
2626
3679
|
// Bulk operations need to refresh ctx.sessions.list and the
|
|
2627
3680
|
// workspace projection after /batch mutates disk state so the
|
|
2628
3681
|
// panel reflects the new layout.
|
|
2629
|
-
onRefreshAfterBulk: async () => {
|
|
2630
|
-
try { await this.props.props.onBulkRefresh(); } catch (_) { /* ignore */ }
|
|
3682
|
+
onRefreshAfterBulk: async (...args) => {
|
|
3683
|
+
try { await this.props.props.onBulkRefresh?.(...args); } catch (_) { /* ignore */ }
|
|
2631
3684
|
},
|
|
2632
3685
|
onOpen: (id) => { try { this.props.panelStore.set(false); this.props.props.onOpen(id); } catch (_) {} },
|
|
2633
3686
|
onArchive: this.props.props.onArchive,
|
|
@@ -2653,10 +3706,14 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
2653
3706
|
() => panelStore.getSnapshot(),
|
|
2654
3707
|
() => panelStore.getSnapshot()
|
|
2655
3708
|
);
|
|
2656
|
-
const
|
|
3709
|
+
const updateState = useSyncExternalStore(
|
|
3710
|
+
(cb) => updateStore.subscribe(cb),
|
|
3711
|
+
() => updateStore.getSnapshot(),
|
|
3712
|
+
() => updateStore.getSnapshot()
|
|
3713
|
+
);
|
|
2657
3714
|
const btnClass = "sm-footerBtn" + (wide ? " sm-footerBtn-wide" : " sm-footerBtn-rail");
|
|
2658
3715
|
const btnLabel = t("footer.aria");
|
|
2659
|
-
return h(
|
|
3716
|
+
return h(React.Fragment, null,
|
|
2660
3717
|
h("button", {
|
|
2661
3718
|
type: "button",
|
|
2662
3719
|
className: btnClass,
|
|
@@ -2673,11 +3730,377 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
2673
3730
|
t: t,
|
|
2674
3731
|
useSessions: props.useSessions,
|
|
2675
3732
|
useWorkspaces: props.useWorkspaces,
|
|
2676
|
-
}) : null
|
|
3733
|
+
}) : null,
|
|
3734
|
+
updateState.dialogOpen ? h(UpdateDialog, { t: t }) : null
|
|
3735
|
+
);
|
|
3736
|
+
}
|
|
3737
|
+
|
|
3738
|
+
function NpmIcon(props) {
|
|
3739
|
+
const size = props.size || 16;
|
|
3740
|
+
return h("svg", {
|
|
3741
|
+
viewBox: "0 0 16 16",
|
|
3742
|
+
width: size,
|
|
3743
|
+
height: size,
|
|
3744
|
+
fill: "currentColor",
|
|
3745
|
+
"aria-hidden": "true",
|
|
3746
|
+
style: { display: "block" }
|
|
3747
|
+
},
|
|
3748
|
+
h("path", {
|
|
3749
|
+
fillRule: "evenodd",
|
|
3750
|
+
d: "M0 0v16h16V0H0zm13 13h-2V5H8v8H3V3h10v10z"
|
|
3751
|
+
})
|
|
3752
|
+
);
|
|
3753
|
+
}
|
|
3754
|
+
const WhaleIcon = NpmIcon;
|
|
3755
|
+
|
|
3756
|
+
function CloseIcon(props) {
|
|
3757
|
+
const size = props.size || 14;
|
|
3758
|
+
return h("svg", {
|
|
3759
|
+
viewBox: "0 0 16 16",
|
|
3760
|
+
width: size,
|
|
3761
|
+
height: size,
|
|
3762
|
+
fill: "none",
|
|
3763
|
+
stroke: "currentColor",
|
|
3764
|
+
strokeWidth: "1.8",
|
|
3765
|
+
strokeLinecap: "round",
|
|
3766
|
+
strokeLinejoin: "round",
|
|
3767
|
+
"aria-hidden": "true",
|
|
3768
|
+
style: { display: "block" }
|
|
3769
|
+
},
|
|
3770
|
+
h("path", { d: "M3.5 3.5l9 9M12.5 3.5l-9 9" })
|
|
3771
|
+
);
|
|
3772
|
+
}
|
|
3773
|
+
|
|
3774
|
+
function StarIcon(props) {
|
|
3775
|
+
const size = props.size || 14;
|
|
3776
|
+
return h("svg", {
|
|
3777
|
+
viewBox: "0 0 16 16",
|
|
3778
|
+
width: size,
|
|
3779
|
+
height: size,
|
|
3780
|
+
fill: "#eac54f",
|
|
3781
|
+
"aria-hidden": "true",
|
|
3782
|
+
style: { display: "block" }
|
|
3783
|
+
},
|
|
3784
|
+
h("path", {
|
|
3785
|
+
d: "M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.75.75 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25z"
|
|
3786
|
+
})
|
|
3787
|
+
);
|
|
3788
|
+
}
|
|
3789
|
+
|
|
3790
|
+
function IssueIcon(props) {
|
|
3791
|
+
const size = props.size || 14;
|
|
3792
|
+
return h("svg", {
|
|
3793
|
+
viewBox: "0 0 16 16",
|
|
3794
|
+
width: size,
|
|
3795
|
+
height: size,
|
|
3796
|
+
fill: "currentColor",
|
|
3797
|
+
"aria-hidden": "true",
|
|
3798
|
+
style: { display: "block" }
|
|
3799
|
+
},
|
|
3800
|
+
h("path", {
|
|
3801
|
+
fillRule: "evenodd",
|
|
3802
|
+
d: "M8 1.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13zM0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm9 3a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm-.25-6.25a.75.75 0 0 0-1.5 0v3.5a.75.75 0 0 0 1.5 0v-3.5z"
|
|
3803
|
+
})
|
|
3804
|
+
);
|
|
3805
|
+
}
|
|
3806
|
+
|
|
3807
|
+
function UpdateDialog(props) {
|
|
3808
|
+
const t = props.t || ((k) => k);
|
|
3809
|
+
const updateState = useSyncExternalStore(
|
|
3810
|
+
(cb) => updateStore.subscribe(cb),
|
|
3811
|
+
() => updateStore.getSnapshot(),
|
|
3812
|
+
() => updateStore.getSnapshot()
|
|
3813
|
+
);
|
|
3814
|
+
|
|
3815
|
+
const status = updateState.status;
|
|
3816
|
+
const isUpdating = status === "updating";
|
|
3817
|
+
const isDone = status === "done";
|
|
3818
|
+
const isError = status === "error";
|
|
3819
|
+
const isAvailable = status === "available";
|
|
3820
|
+
const isChecking = status === "checking";
|
|
3821
|
+
const isIdle = status === "idle";
|
|
3822
|
+
|
|
3823
|
+
let dialogTitle = t("update.title");
|
|
3824
|
+
if (isAvailable) dialogTitle = t("update.newVersion");
|
|
3825
|
+
else if (isUpdating) dialogTitle = t("update.installing");
|
|
3826
|
+
else if (isDone) dialogTitle = t("update.title");
|
|
3827
|
+
else if (isError) dialogTitle = t("update.error");
|
|
3828
|
+
|
|
3829
|
+
const handleClose = () => {
|
|
3830
|
+
if (!isUpdating) {
|
|
3831
|
+
updateStore.closeDialog();
|
|
3832
|
+
}
|
|
3833
|
+
};
|
|
3834
|
+
|
|
3835
|
+
return h(OverlayLayer, {
|
|
3836
|
+
className: "sm-updateDialogLayer",
|
|
3837
|
+
onBackdropClick: handleClose,
|
|
3838
|
+
onKeyDown: (e) => {
|
|
3839
|
+
if (e.key === "Escape" && !isUpdating) handleClose();
|
|
3840
|
+
}
|
|
3841
|
+
},
|
|
3842
|
+
h("section", {
|
|
3843
|
+
className: "sm-nativeDialog sm-updateDialog",
|
|
3844
|
+
style: { pointerEvents: "auto" },
|
|
3845
|
+
role: "dialog",
|
|
3846
|
+
"aria-modal": "true",
|
|
3847
|
+
"aria-labelledby": "sm-update-dialog-title"
|
|
3848
|
+
},
|
|
3849
|
+
h("div", { className: "sm-nativeDialogHeader" },
|
|
3850
|
+
h("h3", { id: "sm-update-dialog-title", className: "sm-nativeDialogTitle" }, dialogTitle),
|
|
3851
|
+
!isUpdating ? renderTip(t("update.btn.close"), h("button", {
|
|
3852
|
+
type: "button",
|
|
3853
|
+
className: "sm-panelHeaderClose",
|
|
3854
|
+
"aria-label": t("update.btn.close"),
|
|
3855
|
+
onClick: handleClose
|
|
3856
|
+
}, h(CloseIcon, { size: 14 }))) : null
|
|
3857
|
+
),
|
|
3858
|
+
h("div", { className: "sm-nativeDialogBody" },
|
|
3859
|
+
h("div", { className: "sm-updateVersionGrid" },
|
|
3860
|
+
h("span", { className: "sm-updateVersionLabel" }, t("update.currentVersion")),
|
|
3861
|
+
h("span", { className: "sm-updateVersionValue" }, "v" + updateState.currentVersion),
|
|
3862
|
+
h("span", { className: "sm-updateVersionLabel" }, t("update.latestVersion")),
|
|
3863
|
+
h("span", { className: "sm-updateVersionValue" }, updateState.latestVersion ? "v" + updateState.latestVersion : (isChecking ? t("update.checking") : "-"))
|
|
3864
|
+
),
|
|
3865
|
+
isChecking ? h("div", { className: "sm-updateStatusBox" }, t("update.checking")) : null,
|
|
3866
|
+
isAvailable ? h("div", { className: "sm-updateStatusBox sm-warn" }, t("update.newVersion") + " (v" + updateState.latestVersion + ")") : null,
|
|
3867
|
+
isUpdating ? h("div", { className: "sm-updateStatusBox sm-warn" }, t("update.installing")) : null,
|
|
3868
|
+
isDone ? h("div", { className: "sm-updateStatusBox sm-success" },
|
|
3869
|
+
updateState.application === "applied"
|
|
3870
|
+
? t("update.done.applied")
|
|
3871
|
+
: t("update.done.restart", { from: updateState.currentVersion, to: updateState.latestVersion || updateState.currentVersion })
|
|
3872
|
+
) : null,
|
|
3873
|
+
isError ? h("div", { className: "sm-updateStatusBox sm-error" }, (updateState.error || t("update.error"))) : null,
|
|
3874
|
+
(isIdle && updateState.latestVersion && !isAvailable) ? h("div", { className: "sm-updateStatusBox sm-success" }, t("update.isLatest")) : null
|
|
3875
|
+
),
|
|
3876
|
+
h("div", { className: "sm-nativeDialogFooter" },
|
|
3877
|
+
isAvailable ? h(React.Fragment, null,
|
|
3878
|
+
h("button", {
|
|
3879
|
+
type: "button",
|
|
3880
|
+
className: "sm-nativeDialogButton sm-nativeDialogCancel",
|
|
3881
|
+
onClick: handleClose
|
|
3882
|
+
}, t("update.btn.later")),
|
|
3883
|
+
h("button", {
|
|
3884
|
+
type: "button",
|
|
3885
|
+
className: "sm-nativeDialogButton sm-nativeDialogConfirm",
|
|
3886
|
+
onClick: () => updateStore.startUpdate()
|
|
3887
|
+
}, t("update.btn.update", { version: updateState.latestVersion }))
|
|
3888
|
+
) : null,
|
|
3889
|
+
isUpdating ? h("button", {
|
|
3890
|
+
type: "button",
|
|
3891
|
+
className: "sm-nativeDialogButton sm-nativeDialogConfirm",
|
|
3892
|
+
disabled: true
|
|
3893
|
+
}, t("update.btn.updating")) : null,
|
|
3894
|
+
isDone ? h("button", {
|
|
3895
|
+
type: "button",
|
|
3896
|
+
className: "sm-nativeDialogButton sm-nativeDialogConfirm",
|
|
3897
|
+
onClick: handleClose
|
|
3898
|
+
}, t("update.btn.done")) : null,
|
|
3899
|
+
isError ? h(React.Fragment, null,
|
|
3900
|
+
h("button", {
|
|
3901
|
+
type: "button",
|
|
3902
|
+
className: "sm-nativeDialogButton sm-nativeDialogCancel",
|
|
3903
|
+
onClick: handleClose
|
|
3904
|
+
}, t("update.btn.close")),
|
|
3905
|
+
h("button", {
|
|
3906
|
+
type: "button",
|
|
3907
|
+
className: "sm-nativeDialogButton sm-nativeDialogConfirm",
|
|
3908
|
+
onClick: () => {
|
|
3909
|
+
if (updateState.latestVersion && compareSemver(updateState.latestVersion, updateState.currentVersion) > 0) {
|
|
3910
|
+
updateStore.startUpdate();
|
|
3911
|
+
} else {
|
|
3912
|
+
updateStore.checkForUpdate({ manual: true, openDialog: true });
|
|
3913
|
+
}
|
|
3914
|
+
}
|
|
3915
|
+
}, t("update.btn.retry"))
|
|
3916
|
+
) : null,
|
|
3917
|
+
(isIdle || isChecking) ? h(React.Fragment, null,
|
|
3918
|
+
h("button", {
|
|
3919
|
+
type: "button",
|
|
3920
|
+
className: "sm-nativeDialogButton sm-nativeDialogCancel",
|
|
3921
|
+
onClick: handleClose
|
|
3922
|
+
}, t("update.btn.close")),
|
|
3923
|
+
!isChecking ? h("button", {
|
|
3924
|
+
type: "button",
|
|
3925
|
+
className: "sm-nativeDialogButton",
|
|
3926
|
+
onClick: () => updateStore.checkForUpdate({ manual: true, openDialog: true })
|
|
3927
|
+
}, t("update.btn.check")) : null
|
|
3928
|
+
) : null
|
|
3929
|
+
)
|
|
3930
|
+
)
|
|
3931
|
+
);
|
|
3932
|
+
}
|
|
3933
|
+
|
|
3934
|
+
function SessionManagerSettingsCard(props) {
|
|
3935
|
+
const t = props.t || ((k, v) => {
|
|
3936
|
+
const dict = zh[k] || en[k] || k;
|
|
3937
|
+
return dict.replace(/\{(\w+)\}/g, (_, name) => String(v?.[name] ?? ""));
|
|
3938
|
+
});
|
|
3939
|
+
const updateState = useSyncExternalStore(
|
|
3940
|
+
(cb) => updateStore.subscribe(cb),
|
|
3941
|
+
() => updateStore.getSnapshot(),
|
|
3942
|
+
() => updateStore.getSnapshot()
|
|
3943
|
+
);
|
|
3944
|
+
const autoCheck = updateStore.getAutoCheck();
|
|
3945
|
+
|
|
3946
|
+
const isChecking = updateState.status === "checking";
|
|
3947
|
+
const isUpdating = updateState.status === "updating";
|
|
3948
|
+
const isAvailable = updateState.status === "available";
|
|
3949
|
+
|
|
3950
|
+
const onToggleAutoCheck = (e) => {
|
|
3951
|
+
updateStore.setAutoCheck(e.target.checked);
|
|
3952
|
+
};
|
|
3953
|
+
const currentRegistry = updateStore.getRegistry();
|
|
3954
|
+
const onRegistryChange = (e) => {
|
|
3955
|
+
updateStore.setRegistry(e.target.value);
|
|
3956
|
+
};
|
|
3957
|
+
// Dialog opacity reads straight from the shared preference store, so
|
|
3958
|
+
// moving the slider updates every plugin dialog immediately.
|
|
3959
|
+
const dialogOpacity = updateStore.getDialogOpacity();
|
|
3960
|
+
const onDialogOpacityChange = (e) => {
|
|
3961
|
+
updateStore.setDialogOpacity(e.target.value);
|
|
3962
|
+
};
|
|
3963
|
+
|
|
3964
|
+
return h("div", { className: "sm-settingsCard" },
|
|
3965
|
+
h("div", { className: "sm-settingsHeader" },
|
|
3966
|
+
h("h3", { className: "sm-settingsTitle" },
|
|
3967
|
+
h(NpmIcon, { size: 18 }),
|
|
3968
|
+
h("span", null, t("settings.title")),
|
|
3969
|
+
h("span", { className: "sm-settingsTag" }, "v" + updateState.currentVersion)
|
|
3970
|
+
)
|
|
3971
|
+
),
|
|
3972
|
+
h("div", { className: "sm-settingsSection" },
|
|
3973
|
+
h("div", { className: "sm-settingsSectionHeader" },
|
|
3974
|
+
h("div", { className: "sm-settingsSectionTitle" }, t("settings.versionSection")),
|
|
3975
|
+
h("div", { className: "sm-settingsVersionActions" },
|
|
3976
|
+
h("button", {
|
|
3977
|
+
type: "button",
|
|
3978
|
+
className: "sm-nativeDialogButton sm-settingsCheckBtn",
|
|
3979
|
+
disabled: isChecking || isUpdating,
|
|
3980
|
+
onClick: () => updateStore.checkForUpdate({ manual: true, openOnFound: false, openDialog: false })
|
|
3981
|
+
}, isChecking ? t("update.checking") : t("update.btn.check")),
|
|
3982
|
+
isAvailable ? h("button", {
|
|
3983
|
+
type: "button",
|
|
3984
|
+
className: "sm-nativeDialogButton sm-nativeDialogConfirm sm-settingsCheckBtn",
|
|
3985
|
+
disabled: isUpdating,
|
|
3986
|
+
onClick: () => updateStore.startUpdate({ openDialog: false })
|
|
3987
|
+
}, isUpdating ? t("update.btn.updating") : t("update.btn.update", { version: updateState.latestVersion })) : null
|
|
3988
|
+
)
|
|
3989
|
+
),
|
|
3990
|
+
h("div", { className: "sm-settingsRow" },
|
|
3991
|
+
h("span", null, t("update.currentVersion")),
|
|
3992
|
+
h("span", { style: { fontFamily: "monospace" } }, "v" + updateState.currentVersion)
|
|
3993
|
+
),
|
|
3994
|
+
h("div", { className: "sm-settingsRow" },
|
|
3995
|
+
h("span", null, t("update.latestVersion")),
|
|
3996
|
+
h("span", { style: { fontFamily: "monospace" } },
|
|
3997
|
+
updateState.latestVersion ? "v" + updateState.latestVersion : (isChecking ? t("update.checking") : "-")
|
|
3998
|
+
)
|
|
3999
|
+
),
|
|
4000
|
+
updateState.status === "available" ? h("div", { className: "sm-updateStatusBox sm-warn" },
|
|
4001
|
+
t("update.newVersion") + " (v" + updateState.latestVersion + ")"
|
|
4002
|
+
) : null,
|
|
4003
|
+
updateState.status === "updating" ? h("div", { className: "sm-updateStatusBox sm-warn" },
|
|
4004
|
+
t("update.installing")
|
|
4005
|
+
) : null,
|
|
4006
|
+
updateState.status === "done" ? h("div", { className: "sm-updateStatusBox sm-success" },
|
|
4007
|
+
updateState.application === "applied" ? t("update.done.applied") : t("update.done.restart", { from: updateState.currentVersion, to: updateState.latestVersion || updateState.currentVersion })
|
|
4008
|
+
) : null,
|
|
4009
|
+
updateState.status === "error" ? h("div", { className: "sm-updateStatusBox sm-error" },
|
|
4010
|
+
updateState.error || t("update.error")
|
|
4011
|
+
) : null
|
|
4012
|
+
),
|
|
4013
|
+
h("div", { className: "sm-settingsSection" },
|
|
4014
|
+
h("div", { className: "sm-settingsSectionTitle" }, t("settings.prefSection")),
|
|
4015
|
+
h("div", { className: "sm-settingsRow" },
|
|
4016
|
+
h("span", null, t("settings.registry")),
|
|
4017
|
+
h("select", {
|
|
4018
|
+
className: "sm-settingsSelect",
|
|
4019
|
+
value: currentRegistry,
|
|
4020
|
+
onChange: onRegistryChange,
|
|
4021
|
+
"aria-label": t("settings.registry")
|
|
4022
|
+
},
|
|
4023
|
+
h("option", { value: "registry.npmjs.org" }, t("settings.registry.npm")),
|
|
4024
|
+
h("option", { value: "registry.npmmirror.com" }, t("settings.registry.china"))
|
|
4025
|
+
)
|
|
4026
|
+
),
|
|
4027
|
+
h("div", { className: "sm-settingsRow" },
|
|
4028
|
+
h("span", null, t("update.autoCheck")),
|
|
4029
|
+
h("label", { className: "sm-settingsCheckbox" },
|
|
4030
|
+
h("input", {
|
|
4031
|
+
type: "checkbox",
|
|
4032
|
+
checked: autoCheck,
|
|
4033
|
+
onChange: onToggleAutoCheck,
|
|
4034
|
+
"aria-label": t("update.autoCheck")
|
|
4035
|
+
}),
|
|
4036
|
+
h("span", null, t("update.autoCheck.enable"))
|
|
4037
|
+
)
|
|
4038
|
+
),
|
|
4039
|
+
h("div", { className: "sm-settingsRow" },
|
|
4040
|
+
h("span", null, t("settings.dialogOpacity")),
|
|
4041
|
+
h("div", { className: "sm-settingsSlider" },
|
|
4042
|
+
h("input", {
|
|
4043
|
+
type: "range",
|
|
4044
|
+
className: "sm-settingsRange",
|
|
4045
|
+
min: updateStore.DIALOG_OPACITY.min,
|
|
4046
|
+
max: updateStore.DIALOG_OPACITY.max,
|
|
4047
|
+
step: updateStore.DIALOG_OPACITY.step,
|
|
4048
|
+
value: dialogOpacity,
|
|
4049
|
+
"aria-label": t("settings.dialogOpacity"),
|
|
4050
|
+
"aria-valuemin": updateStore.DIALOG_OPACITY.min,
|
|
4051
|
+
"aria-valuemax": updateStore.DIALOG_OPACITY.max,
|
|
4052
|
+
"aria-valuenow": dialogOpacity,
|
|
4053
|
+
"aria-valuetext": t("settings.dialogOpacity.value", { value: dialogOpacity }),
|
|
4054
|
+
onChange: onDialogOpacityChange
|
|
4055
|
+
}),
|
|
4056
|
+
h("span", { className: "sm-settingsRangeValue" }, t("settings.dialogOpacity.value", { value: dialogOpacity })),
|
|
4057
|
+
h("button", {
|
|
4058
|
+
type: "button",
|
|
4059
|
+
className: "sm-settingsResetBtn",
|
|
4060
|
+
disabled: dialogOpacity === updateStore.DIALOG_OPACITY.default,
|
|
4061
|
+
onClick: () => updateStore.resetDialogOpacity()
|
|
4062
|
+
}, t("settings.dialogOpacity.reset"))
|
|
4063
|
+
)
|
|
4064
|
+
),
|
|
4065
|
+
h("div", { className: "sm-settingsHint" }, t("settings.dialogOpacity.hint"))
|
|
4066
|
+
),
|
|
4067
|
+
h("div", { className: "sm-settingsSection" },
|
|
4068
|
+
h("div", { className: "sm-settingsSectionTitle" }, t("settings.projectSection")),
|
|
4069
|
+
h("div", { className: "sm-settingsRow sm-settingsRowInline" },
|
|
4070
|
+
h("span", null, t("settings.github")),
|
|
4071
|
+
h("a", {
|
|
4072
|
+
href: "https://github.com/hkkz9522/dsh-session-manager",
|
|
4073
|
+
target: "_blank",
|
|
4074
|
+
rel: "noopener noreferrer",
|
|
4075
|
+
className: "sm-settingsLink"
|
|
4076
|
+
}, "hkkz9522/dsh-session-manager"),
|
|
4077
|
+
h("a", {
|
|
4078
|
+
href: "https://github.com/hkkz9522/dsh-session-manager",
|
|
4079
|
+
target: "_blank",
|
|
4080
|
+
rel: "noopener noreferrer",
|
|
4081
|
+
className: "sm-settingsBadgeLink",
|
|
4082
|
+
title: "Star on GitHub"
|
|
4083
|
+
},
|
|
4084
|
+
h(StarIcon, { size: 14 }),
|
|
4085
|
+
h("span", null, t("settings.star"))
|
|
4086
|
+
),
|
|
4087
|
+
h("a", {
|
|
4088
|
+
href: "https://github.com/hkkz9522/dsh-session-manager/issues",
|
|
4089
|
+
target: "_blank",
|
|
4090
|
+
rel: "noopener noreferrer",
|
|
4091
|
+
className: "sm-settingsBadgeLink",
|
|
4092
|
+
title: "GitHub Issues"
|
|
4093
|
+
},
|
|
4094
|
+
h(IssueIcon, { size: 14 }),
|
|
4095
|
+
h("span", null, t("settings.feedback"))
|
|
4096
|
+
)
|
|
4097
|
+
)
|
|
4098
|
+
)
|
|
2677
4099
|
);
|
|
2678
4100
|
}
|
|
2679
4101
|
|
|
2680
4102
|
function apply(ctx) {
|
|
4103
|
+
activeClientCtx = ctx;
|
|
2681
4104
|
ctx.effect(() => {
|
|
2682
4105
|
const refresh = () => { if (annotationStore.hasSubscribers()) void annotationStore.load(true); };
|
|
2683
4106
|
window.addEventListener("focus", refresh);
|
|
@@ -2692,6 +4115,34 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
2692
4115
|
return () => { window.removeEventListener("focus", refresh); channel?.close(); annotationStore.notify = null; };
|
|
2693
4116
|
}, "session-manager: annotation synchronization");
|
|
2694
4117
|
ctx.effect(() => ctx.locale.register(NS, { zh, en }), "session-manager: dictionaries");
|
|
4118
|
+
const getCurrentSessionId = () => {
|
|
4119
|
+
try {
|
|
4120
|
+
const id = ctx.uiWorkspace?.mainReference?.sessionId
|
|
4121
|
+
|| ctx.uiWorkspace?.selection?.getSnapshot?.()?.sessionId
|
|
4122
|
+
|| ctx.sessions?.list?.getSnapshot?.()?.current;
|
|
4123
|
+
return typeof id === "string" && id ? id : null;
|
|
4124
|
+
} catch (_) {
|
|
4125
|
+
return null;
|
|
4126
|
+
}
|
|
4127
|
+
};
|
|
4128
|
+
|
|
4129
|
+
const isCurrentSession = (id) => {
|
|
4130
|
+
if (!id) return false;
|
|
4131
|
+
return getCurrentSessionId() === id;
|
|
4132
|
+
};
|
|
4133
|
+
|
|
4134
|
+
const clearCurrentSession = () => {
|
|
4135
|
+
const uiWorkspace = ctx.uiWorkspace;
|
|
4136
|
+
if (uiWorkspace && typeof uiWorkspace.clearMain === "function") {
|
|
4137
|
+
try { uiWorkspace.clearMain(); } catch (_) {}
|
|
4138
|
+
} else if (uiWorkspace && typeof uiWorkspace.startSession === "function") {
|
|
4139
|
+
try { uiWorkspace.startSession(); } catch (_) {}
|
|
4140
|
+
}
|
|
4141
|
+
if (ctx.sessions && typeof ctx.sessions.clear === "function") {
|
|
4142
|
+
try { ctx.sessions.clear(); } catch (_) {}
|
|
4143
|
+
}
|
|
4144
|
+
};
|
|
4145
|
+
|
|
2695
4146
|
const actions = () => ({
|
|
2696
4147
|
// DSH 0.1.6+ removed ctx.sessions.open(); the navigation owner is
|
|
2697
4148
|
// `ctx.uiWorkspace.openSession()`, and the bare SessionController only
|
|
@@ -2713,18 +4164,28 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
2713
4164
|
}
|
|
2714
4165
|
throw new Error("session-manager: no Session open API on this DSH host");
|
|
2715
4166
|
},
|
|
2716
|
-
onArchive: async (sessionId) => {
|
|
4167
|
+
onArchive: async (sessionId) => {
|
|
4168
|
+
if (ctx.uiWorkspace && typeof ctx.uiWorkspace.archiveSession === "function") {
|
|
4169
|
+
await ctx.uiWorkspace.archiveSession(sessionId);
|
|
4170
|
+
} else {
|
|
4171
|
+
await ctx.workspaces.archiveSession(sessionId);
|
|
4172
|
+
}
|
|
4173
|
+
},
|
|
2717
4174
|
onUnarchive: async (sessionId) => {
|
|
2718
4175
|
const response = await callApi("/unarchive", { sessionId });
|
|
2719
4176
|
if (!response.ok) throw new Error(response.error || "unarchive failed");
|
|
2720
4177
|
},
|
|
2721
4178
|
onRemove: async (sessionId) => {
|
|
4179
|
+
const wasCurrent = isCurrentSession(sessionId);
|
|
2722
4180
|
const response = await callApi("/delete", { sessionId });
|
|
2723
4181
|
if (!response.ok) throw new Error(response.error || "delete failed");
|
|
2724
4182
|
await annotationStore.load(true);
|
|
2725
4183
|
if (response.result?.warning) window.alert(response.result.warning);
|
|
2726
|
-
|
|
2727
|
-
|
|
4184
|
+
if (wasCurrent || isCurrentSession(sessionId)) {
|
|
4185
|
+
clearCurrentSession();
|
|
4186
|
+
}
|
|
4187
|
+
try { await ctx.sessions?.refresh?.(); } catch (_) {}
|
|
4188
|
+
try { await ctx.workspaces?.refresh?.(); } catch (_) {}
|
|
2728
4189
|
},
|
|
2729
4190
|
onMove: async (sessionId, targetWorkspaceId) => {
|
|
2730
4191
|
const wasCurrent = ctx.sessions.list.getSnapshot().current === sessionId;
|
|
@@ -2754,7 +4215,6 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
2754
4215
|
if (!response.ok) throw new Error(response.error || "preset migration failed");
|
|
2755
4216
|
// The current DSH client session store derives agentPreset from
|
|
2756
4217
|
// the refreshed projection; older builds exposed noteAgentPreset,
|
|
2757
|
-
onOpenPanel: () => panelStore.toggle(),
|
|
2758
4218
|
await ctx.sessions.refresh();
|
|
2759
4219
|
// The migrate rewrite happens in-process on the live session, so
|
|
2760
4220
|
// we just need a delayed baseline to let the api-gateway's projection
|
|
@@ -2766,7 +4226,31 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
2766
4226
|
}, 250);
|
|
2767
4227
|
},
|
|
2768
4228
|
onOpenPanel: () => panelStore.toggle(),
|
|
2769
|
-
onBulkRefresh: async () => {
|
|
4229
|
+
onBulkRefresh: async (action, meta) => {
|
|
4230
|
+
const currentBefore = getCurrentSessionId();
|
|
4231
|
+
if (action === "delete" || action === "archive") {
|
|
4232
|
+
const items = meta?.items || meta?.result?.items || [];
|
|
4233
|
+
const successIds = items
|
|
4234
|
+
.filter(item => item && (item.status === "success" || item.ok === true))
|
|
4235
|
+
.map(item => item.sessionId);
|
|
4236
|
+
const batchIds = (lastBatchContext.action === action && Array.isArray(lastBatchContext.ids)) ? lastBatchContext.ids : [];
|
|
4237
|
+
const candidateIds = successIds.length > 0 ? successIds : (meta?.ids || batchIds);
|
|
4238
|
+
if (candidateIds.some(isCurrentSession)) {
|
|
4239
|
+
clearCurrentSession();
|
|
4240
|
+
}
|
|
4241
|
+
}
|
|
4242
|
+
try { await ctx.sessions?.refresh?.(); } catch (_) { /* ignore */ }
|
|
4243
|
+
try { await ctx.workspaces?.refresh?.(); } catch (_) { /* ignore */ }
|
|
4244
|
+
if (currentBefore && (action === "delete" || action === "archive")) {
|
|
4245
|
+
const sessionsSnapshot = ctx.sessions?.list?.getSnapshot?.();
|
|
4246
|
+
const workspacesSnapshot = ctx.workspaces?.list?.getSnapshot?.();
|
|
4247
|
+
const deleted = sessionsSnapshot?.byId && sessionsSnapshot.byId[currentBefore] === undefined;
|
|
4248
|
+
const archived = Array.isArray(workspacesSnapshot?.archivedSessionIds) && workspacesSnapshot.archivedSessionIds.includes(currentBefore);
|
|
4249
|
+
if (deleted || archived) {
|
|
4250
|
+
clearCurrentSession();
|
|
4251
|
+
}
|
|
4252
|
+
}
|
|
4253
|
+
},
|
|
2770
4254
|
});
|
|
2771
4255
|
ctx.slots.inject("conversation.session.header.actions", () => ctx.slots.register({
|
|
2772
4256
|
name: "conversation.session.header.actions",
|
|
@@ -2782,12 +4266,83 @@ function nextDialogZ() { return ++dialogZStackCounter; }
|
|
|
2782
4266
|
locale: NS,
|
|
2783
4267
|
inject: () => actions()
|
|
2784
4268
|
}, FooterAction));
|
|
4269
|
+
ctx.slots.inject("plugins.bundle.config", () => ctx.slots.register({
|
|
4270
|
+
name: "plugins.bundle.config",
|
|
4271
|
+
id: "dsh-session-manager-bundle-config",
|
|
4272
|
+
key: "dsh-session-manager",
|
|
4273
|
+
locale: NS,
|
|
4274
|
+
inject: () => actions()
|
|
4275
|
+
}, (ownerProps = {}) => (ownerProps?.view === "summary" ? null : h(SessionManagerSettingsCard, ownerProps))));
|
|
4276
|
+
|
|
4277
|
+
try {
|
|
4278
|
+
if (typeof ctx.inject === "function") {
|
|
4279
|
+
ctx.inject(["settingsScope"], (scoped) => {
|
|
4280
|
+
if (scoped && scoped.slots) {
|
|
4281
|
+
scoped.slots.inject("settings.plugin.item", () => scoped.slots.register({
|
|
4282
|
+
name: "settings.plugin.item",
|
|
4283
|
+
id: "session-manager-settings-scoped",
|
|
4284
|
+
key: "dsh-session-manager",
|
|
4285
|
+
locale: NS,
|
|
4286
|
+
inject: () => actions()
|
|
4287
|
+
}, SessionManagerSettingsCard));
|
|
4288
|
+
}
|
|
4289
|
+
});
|
|
4290
|
+
}
|
|
4291
|
+
} catch (_) {}
|
|
4292
|
+
|
|
4293
|
+
ctx.slots.inject("settings.plugin.item", () => ctx.slots.register({
|
|
4294
|
+
name: "settings.plugin.item",
|
|
4295
|
+
id: "session-manager-settings",
|
|
4296
|
+
key: "dsh-session-manager",
|
|
4297
|
+
order: 50,
|
|
4298
|
+
locale: NS,
|
|
4299
|
+
inject: () => actions()
|
|
4300
|
+
}, SessionManagerSettingsCard));
|
|
4301
|
+
|
|
4302
|
+
ctx.effect(() => {
|
|
4303
|
+
if (!updateStore.getAutoCheck()) return;
|
|
4304
|
+
const timer = setTimeout(() => {
|
|
4305
|
+
updateStore.checkForUpdate({ silent: true, openOnFound: false, openDialog: false }).catch(() => {});
|
|
4306
|
+
}, 1500);
|
|
4307
|
+
return () => {
|
|
4308
|
+
try {
|
|
4309
|
+
if (typeof clearTimeout === "function") clearTimeout(timer);
|
|
4310
|
+
else if (typeof window !== "undefined" && typeof window.clearTimeout === "function") window.clearTimeout(timer);
|
|
4311
|
+
} catch (_) {}
|
|
4312
|
+
};
|
|
4313
|
+
}, "session-manager: auto update check");
|
|
4314
|
+
|
|
4315
|
+
// Keep <html data-sm-theme> in step with DSH through the official theme
|
|
4316
|
+
// event. ui-layout's ThemePresenter subscribes to the same event and
|
|
4317
|
+
// writes documentElement.colorScheme plus body[data-ds-dark-theme], so
|
|
4318
|
+
// this is the authoritative change signal; the DOM observer above still
|
|
4319
|
+
// covers plain attribute flips, and a theme whose tokens change without
|
|
4320
|
+
// touching an observed attribute would otherwise leave the mirror stale.
|
|
4321
|
+
// The mirror only feeds two cosmetic branches (the token-less opacity
|
|
4322
|
+
// fallback and the priority colours) -- native UA chrome is DSH's job.
|
|
4323
|
+
try {
|
|
4324
|
+
if (typeof ctx.on === "function") {
|
|
4325
|
+
ctx.effect(() => {
|
|
4326
|
+
const off = ctx.on("theme/change", () => smApplyTheme());
|
|
4327
|
+
return () => { try { if (typeof off === "function") off(); } catch (_) {} };
|
|
4328
|
+
}, "session-manager: theme mirror");
|
|
4329
|
+
}
|
|
4330
|
+
} catch (_) { /* theme service absent: the DOM observer is enough */ }
|
|
2785
4331
|
}
|
|
2786
4332
|
|
|
2787
4333
|
const inject = ["slots", "sessions", "workspaces", "locale", "uiWorkspace"];
|
|
2788
4334
|
|
|
2789
4335
|
exports.apply = apply;
|
|
2790
4336
|
exports.inject = inject;
|
|
4337
|
+
exports.updateStore = updateStore;
|
|
4338
|
+
exports.compareSemver = compareSemver;
|
|
4339
|
+
exports.UpdateDialog = UpdateDialog;
|
|
4340
|
+
exports.SessionManagerSettingsCard = SessionManagerSettingsCard;
|
|
4341
|
+
exports.WhaleIcon = WhaleIcon;
|
|
4342
|
+
exports.NpmIcon = NpmIcon;
|
|
4343
|
+
exports.CloseIcon = CloseIcon;
|
|
4344
|
+
exports.StarIcon = StarIcon;
|
|
4345
|
+
exports.IssueIcon = IssueIcon;
|
|
2791
4346
|
return module.exports;
|
|
2792
4347
|
}
|
|
2793
4348
|
});
|