dsh-session-manager 0.7.0 → 0.7.2
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 +19 -0
- package/README.md +18 -16
- package/README.zh.md +19 -17
- package/lib/client.js +591 -132
- package/lib/index.js +693 -197
- package/lib/session-files.js +73 -6
- package/package.json +2 -2
package/lib/client.js
CHANGED
|
@@ -200,14 +200,14 @@ function isTopmostDialog(z) {
|
|
|
200
200
|
"update.autoCheck": "自动检查更新",
|
|
201
201
|
"update.autoCheck.enable": "开启",
|
|
202
202
|
"settings.registry": "安装源",
|
|
203
|
-
"settings.registry.npm": "npm 官方源
|
|
204
|
-
"settings.registry.china": "
|
|
203
|
+
"settings.registry.npm": "npm 官方源 (npmjs.org)",
|
|
204
|
+
"settings.registry.china": "国内镜像源 (npmmirror.com)",
|
|
205
205
|
"settings.title": "会话管理",
|
|
206
206
|
"settings.pluginName": "dsh-session-manager",
|
|
207
207
|
"settings.versionSection": "插件版本",
|
|
208
208
|
"settings.prefSection": "偏好设置",
|
|
209
209
|
"settings.dialogOpacity": "弹窗透明度",
|
|
210
|
-
"settings.dialogOpacity.hint": "
|
|
210
|
+
"settings.dialogOpacity.hint": "仅调整插件弹窗的背景透明度",
|
|
211
211
|
"settings.dialogOpacity.value": "{value}%",
|
|
212
212
|
"settings.dialogOpacity.reset": "恢复默认",
|
|
213
213
|
"settings.projectSection": "项目",
|
|
@@ -264,6 +264,9 @@ function isTopmostDialog(z) {
|
|
|
264
264
|
"confirm.delete.title": "删除会话",
|
|
265
265
|
"confirm.delete.desc": "「{title}」:删除,不可恢复",
|
|
266
266
|
"confirm.delete.running": "该会话正在运行,删除将立即中断它。",
|
|
267
|
+
"confirm.delete.subagents": "将连带删除 {count} 个关联的子智能体会话。",
|
|
268
|
+
"confirm.delete.previewLoading": "正在检查关联的子智能体会话…",
|
|
269
|
+
"confirm.delete.previewError": "检查关联子智能体会话失败,无法确认删除安全,请稍后重试。",
|
|
267
270
|
"confirm.delete.confirm": "确认删除",
|
|
268
271
|
"confirm.move.title": "移动会话到工作区",
|
|
269
272
|
"confirm.move.desc": "「{title}」:移动至目标工作区",
|
|
@@ -468,14 +471,14 @@ function isTopmostDialog(z) {
|
|
|
468
471
|
"update.autoCheck": "Automatically check for updates",
|
|
469
472
|
"update.autoCheck.enable": "Enable",
|
|
470
473
|
"settings.registry": "Install Source",
|
|
471
|
-
"settings.registry.npm": "npm
|
|
472
|
-
"settings.registry.china": "China
|
|
474
|
+
"settings.registry.npm": "Official npm (npmjs.org)",
|
|
475
|
+
"settings.registry.china": "China mirror (npmmirror.com)",
|
|
473
476
|
"settings.title": "Session Manager",
|
|
474
477
|
"settings.pluginName": "dsh-session-manager",
|
|
475
478
|
"settings.versionSection": "Plugin Version",
|
|
476
479
|
"settings.prefSection": "Preferences",
|
|
477
480
|
"settings.dialogOpacity": "Dialog opacity",
|
|
478
|
-
"settings.dialogOpacity.hint": "Adjusts
|
|
481
|
+
"settings.dialogOpacity.hint": "Adjusts dialog background opacity only",
|
|
479
482
|
"settings.dialogOpacity.value": "{value}%",
|
|
480
483
|
"settings.dialogOpacity.reset": "Reset to default",
|
|
481
484
|
"settings.projectSection": "Project",
|
|
@@ -599,6 +602,9 @@ function isTopmostDialog(z) {
|
|
|
599
602
|
"confirm.delete.title": "Delete session",
|
|
600
603
|
"confirm.delete.desc": "\"{title}\": Delete, cannot be undone",
|
|
601
604
|
"confirm.delete.running": "This session is running; deleting will interrupt it immediately.",
|
|
605
|
+
"confirm.delete.subagents": "Will also delete {count} associated subagent session(s).",
|
|
606
|
+
"confirm.delete.previewLoading": "Checking for associated subagent sessions...",
|
|
607
|
+
"confirm.delete.previewError": "Failed to check associated subagents. Cannot verify deletion safety. Please try again later.",
|
|
602
608
|
"confirm.delete.confirm": "Delete",
|
|
603
609
|
"confirm.move.title": "Move session to workspace",
|
|
604
610
|
"confirm.move.desc": "\"{title}\": Move to target workspace",
|
|
@@ -726,7 +732,7 @@ function isTopmostDialog(z) {
|
|
|
726
732
|
// applied). Tooltip visibility is governed by the layering contract
|
|
727
733
|
// above, not by this rule; it is kept as the scoped replacement for the
|
|
728
734
|
// unscoped selector Issue #21 removed.
|
|
729
|
-
".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;height:28px;font-size:12px;line-height:20px;padding:3px 26px 3px 10px;border-radius:8px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#111);cursor:pointer}.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;max-width:calc(100vw - 32px);max-height:calc(100vh - 32px);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:calc(100vw - 32px);max-height:min(70vh,calc(100vh - 32px));z-index:auto;display:flex;flex-direction:column;overflow:hidden}.sm-migrateConfirmLayer .sm-migratePanel{min-width:0;max-height:calc(100vh - 120px);overflow-y:auto}.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}",
|
|
735
|
+
".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:16px;min-height:36px;margin-top:8px}.sm-settingsRow:first-of-type{margin-top:0}.sm-settingsRow>span:first-child{white-space:nowrap;flex-shrink:0}.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:30px;height:30px;width:280px;min-width:280px;max-width:280px;flex:0 0 280px;box-sizing:border-box;font-size:12px;line-height:20px;padding:4px 26px 4px 10px;border-radius:8px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#111);cursor:pointer}.sm-settingsRowLeft{display:flex;flex-direction:column;align-items:flex-start;justify-content:center;gap:2px;min-width:0;flex:1 1 auto}.sm-settingsRowLeft>span:first-child{white-space:nowrap;flex-shrink:0}.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;max-width:calc(100vw - 32px);max-height:calc(100vh - 32px);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:calc(100vw - 32px);max-height:min(70vh,calc(100vh - 32px));z-index:auto;display:flex;flex-direction:column;overflow:hidden}.sm-migrateConfirmLayer .sm-migratePanel{min-width:0;max-height:calc(100vh - 120px);overflow-y:auto}.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-settingsProjectLeft{display:flex;align-items:center;gap:8px;min-width:0;flex-wrap:nowrap}.sm-settingsProjectLabel{color:var(--dsw-alias-label-primary,#111);white-space:nowrap;flex-shrink:0}.sm-settingsBadgeActions{display:flex;align-items:center;gap:8px;margin-left:auto;flex:0 0 280px;width:280px;min-width:280px;max-width:280px;box-sizing:border-box;justify-content:flex-end}.sm-settingsBadgeActions>*{display:inline-flex;flex:1 1 0;min-width:0}.sm-settingsBadgeLink{display:inline-flex;align-items:center;justify-content:center;gap:6px;width:100%;padding:4px 10px;min-height:28px;height:28px;box-sizing:border-box;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;white-space:nowrap;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}",
|
|
730
736
|
|
|
731
737
|
// Issue #23 — dialog opacity.
|
|
732
738
|
//
|
|
@@ -768,14 +774,14 @@ function isTopmostDialog(z) {
|
|
|
768
774
|
".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)}",
|
|
769
775
|
".sm-panelDialog option:disabled,.sm-nativeDialog option:disabled,.sm-settingsCard option:disabled,.sm-headerMenu option:disabled{color:var(--dsw-alias-label-tertiary,#888)}",
|
|
770
776
|
".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)}",
|
|
771
|
-
".sm-settingsSlider{display:flex;align-items:center;gap:8px;flex:
|
|
772
|
-
".sm-settingsRange{flex:1 1
|
|
777
|
+
".sm-settingsSlider{display:flex;align-items:center;gap:8px;flex:0 0 280px;width:280px;min-width:280px;max-width:280px;box-sizing:border-box;justify-content:flex-end}",
|
|
778
|
+
".sm-settingsRange{flex:1 1 auto;min-width:70px;margin:0;cursor:pointer;accent-color:var(--dsw-alias-state-business-primary,#356ae6)}",
|
|
773
779
|
".sm-settingsRange:disabled{cursor:not-allowed}",
|
|
774
|
-
".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)}",
|
|
775
|
-
".sm-settingsResetBtn{min-height:
|
|
780
|
+
".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);flex-shrink:0}",
|
|
781
|
+
".sm-settingsResetBtn{min-height:28px;height:28px;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;flex:0 0 auto;box-sizing:border-box}",
|
|
776
782
|
".sm-settingsResetBtn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary,#111)}",
|
|
777
783
|
".sm-settingsResetBtn:disabled{opacity:.5;cursor:not-allowed}",
|
|
778
|
-
".sm-settingsHint{
|
|
784
|
+
".sm-settingsHint{font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary,#888)}.sm-settingsHintInline{margin-left:0;font-weight:normal}",
|
|
779
785
|
|
|
780
786
|
// DSH's own theme is the single source of colour. Every rule above reads
|
|
781
787
|
// --dsw-alias-* tokens directly and none of them is redefined here: the
|
|
@@ -842,7 +848,7 @@ function isTopmostDialog(z) {
|
|
|
842
848
|
".sm-bulkDialog .sm-nativeDialog{width:100%;max-height:min(640px,calc(100vh - 32px))}",
|
|
843
849
|
".sm-bulkDialogBody{display:flex;flex-direction:column;gap:12px;min-height:0}",
|
|
844
850
|
".sm-bulkDialogSummary{font-size:13px;line-height:20px;color:var(--dsw-alias-label-primary,#111)}",
|
|
845
|
-
".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}",
|
|
851
|
+
".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;white-space:pre-line}",
|
|
846
852
|
".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}",
|
|
847
853
|
".sm-bulkSessionItem{font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary,#666);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}",
|
|
848
854
|
".sm-bulkProgressBar{position:relative;height:8px;background:var(--dsw-alias-bg-skeleton,#0000000a);border-radius:4px;overflow:hidden}",
|
|
@@ -856,7 +862,8 @@ function isTopmostDialog(z) {
|
|
|
856
862
|
".sm-bulkResultItemReason{color:var(--dsw-alias-state-error-primary);font-size:11px;line-height:16px;word-break:break-word}",
|
|
857
863
|
".sm-bulkResultItemReasonSkip{color:var(--dsw-alias-label-tertiary,#888)}",
|
|
858
864
|
".sm-bulkResultFooter{display:flex;justify-content:space-between;align-items:center;gap:8px;flex-wrap:wrap}",
|
|
859
|
-
".sm-footerBtn-wide
|
|
865
|
+
"[class*=footerActions]:has(.sm-footerBtn-wide),[class*=footer-actions]:has(.sm-footerBtn-wide),[class*=footer]:has(> .sm-footerBtn-wide),[class*=footer] > div:has(> .sm-footerBtn-wide){flex-wrap:wrap;align-content:flex-start;height:auto}",
|
|
866
|
+
".sm-footerBtn-wide{flex:1 1 100%;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}",
|
|
860
867
|
".sm-footerBtn-wide:hover,.sm-footerBtn-wide:focus-visible{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}",
|
|
861
868
|
".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}",
|
|
862
869
|
".sm-footerBtn-rail:hover,.sm-footerBtn-rail:focus-visible{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}",
|
|
@@ -1131,6 +1138,10 @@ function isTopmostDialog(z) {
|
|
|
1131
1138
|
if (zRef.current === null) {
|
|
1132
1139
|
zRef.current = nextDialogZ();
|
|
1133
1140
|
}
|
|
1141
|
+
useEffect(() => {
|
|
1142
|
+
registerDialogZ(zRef.current);
|
|
1143
|
+
return () => unregisterDialogZ(zRef.current);
|
|
1144
|
+
}, []);
|
|
1134
1145
|
const root = getOverlayRoot();
|
|
1135
1146
|
const portal = getPortalFn();
|
|
1136
1147
|
|
|
@@ -1158,6 +1169,8 @@ function isTopmostDialog(z) {
|
|
|
1158
1169
|
zIndex: -1
|
|
1159
1170
|
},
|
|
1160
1171
|
onClick: (e) => {
|
|
1172
|
+
if (e && typeof e.stopPropagation === "function") e.stopPropagation();
|
|
1173
|
+
if (e && typeof e.stopImmediatePropagation === "function") e.stopImmediatePropagation();
|
|
1161
1174
|
if (e.target === e.currentTarget && onBackdropClick) {
|
|
1162
1175
|
onBackdropClick(e);
|
|
1163
1176
|
}
|
|
@@ -2088,6 +2101,18 @@ function isTopmostDialog(z) {
|
|
|
2088
2101
|
}
|
|
2089
2102
|
}
|
|
2090
2103
|
|
|
2104
|
+
function getTargetSmSelect(target) {
|
|
2105
|
+
if (!target || typeof target.closest !== "function") return null;
|
|
2106
|
+
const direct = target.closest(SM_SELECT_SELECTOR);
|
|
2107
|
+
if (direct && direct.tagName === "SELECT") return direct;
|
|
2108
|
+
const container = target.closest(".sm-wsSortField, .sm-annotationPriority, .sm-viewField, .sm-moveSection, .sm-settingsRow, .sm-customSelectWrapper");
|
|
2109
|
+
if (container) {
|
|
2110
|
+
const sel = container.querySelector("select");
|
|
2111
|
+
if (sel && sel.tagName === "SELECT") return sel;
|
|
2112
|
+
}
|
|
2113
|
+
return null;
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2091
2116
|
function installCustomDropdownInterceptor() {
|
|
2092
2117
|
if (typeof document === "undefined" || typeof document.addEventListener !== "function") {
|
|
2093
2118
|
return () => {};
|
|
@@ -2101,24 +2126,8 @@ function isTopmostDialog(z) {
|
|
|
2101
2126
|
if (activeCustomMenu && activeCustomMenu.contains(e.target)) return;
|
|
2102
2127
|
if (e.target?.closest?.("button, input, textarea, a")) return;
|
|
2103
2128
|
|
|
2104
|
-
|
|
2105
|
-
if (
|
|
2106
|
-
select = e.target;
|
|
2107
|
-
} else if (e.target?.closest?.("select")) {
|
|
2108
|
-
select = e.target.closest("select");
|
|
2109
|
-
} else {
|
|
2110
|
-
const container = e.target?.closest?.(".sm-wsSortField, .sm-annotationPriority, .sm-viewField, .sm-moveSection, .sm-settingsRow, .sm-customSelectWrapper");
|
|
2111
|
-
if (container) {
|
|
2112
|
-
select = container.querySelector("select");
|
|
2113
|
-
} else {
|
|
2114
|
-
const nearest = e.target?.closest?.(SM_SELECT_SELECTOR);
|
|
2115
|
-
if (nearest && nearest.tagName === "SELECT") {
|
|
2116
|
-
select = nearest;
|
|
2117
|
-
}
|
|
2118
|
-
}
|
|
2119
|
-
}
|
|
2120
|
-
|
|
2121
|
-
if (select && select.tagName === "SELECT") {
|
|
2129
|
+
const select = getTargetSmSelect(e.target);
|
|
2130
|
+
if (select) {
|
|
2122
2131
|
e.preventDefault();
|
|
2123
2132
|
e.stopPropagation();
|
|
2124
2133
|
if (select.disabled) return;
|
|
@@ -2134,14 +2143,8 @@ function isTopmostDialog(z) {
|
|
|
2134
2143
|
|
|
2135
2144
|
const onClick = (e) => {
|
|
2136
2145
|
if (e.target?.closest?.("button, input, textarea, a")) return;
|
|
2137
|
-
|
|
2138
|
-
if (
|
|
2139
|
-
select = e.target;
|
|
2140
|
-
} else {
|
|
2141
|
-
const container = e.target?.closest?.(".sm-wsSortField, .sm-annotationPriority, .sm-viewField, .sm-moveSection, .sm-settingsRow, .sm-customSelectWrapper");
|
|
2142
|
-
if (container) select = container.querySelector("select");
|
|
2143
|
-
}
|
|
2144
|
-
if (select && select.tagName === "SELECT") {
|
|
2146
|
+
const select = getTargetSmSelect(e.target);
|
|
2147
|
+
if (select) {
|
|
2145
2148
|
e.preventDefault();
|
|
2146
2149
|
e.stopPropagation();
|
|
2147
2150
|
}
|
|
@@ -2158,7 +2161,7 @@ function isTopmostDialog(z) {
|
|
|
2158
2161
|
}
|
|
2159
2162
|
|
|
2160
2163
|
const focused = document.activeElement;
|
|
2161
|
-
const targetSelect = activeCustomSelect || (focused
|
|
2164
|
+
const targetSelect = activeCustomSelect || getTargetSmSelect(focused);
|
|
2162
2165
|
if (!targetSelect || targetSelect.tagName !== "SELECT") return;
|
|
2163
2166
|
|
|
2164
2167
|
if (e.key === "Enter" || e.key === " ") {
|
|
@@ -2184,7 +2187,14 @@ function isTopmostDialog(z) {
|
|
|
2184
2187
|
}
|
|
2185
2188
|
};
|
|
2186
2189
|
|
|
2187
|
-
const onResizeOrScroll = () => {
|
|
2190
|
+
const onResizeOrScroll = (e) => {
|
|
2191
|
+
// Ignore scrolls that originate inside the open menu: the listener is bound on
|
|
2192
|
+
// window with capture=true, so scrolling the menu's own option list (wheel or
|
|
2193
|
+
// scrollbar drag) would otherwise close it immediately.
|
|
2194
|
+
// Reference: PR #37
|
|
2195
|
+
if (activeCustomMenu && e && e.type === "scroll" && e.target && typeof activeCustomMenu.contains === "function" && activeCustomMenu.contains(e.target)) {
|
|
2196
|
+
return;
|
|
2197
|
+
}
|
|
2188
2198
|
if (activeCustomMenu) closeCustomSelect();
|
|
2189
2199
|
};
|
|
2190
2200
|
|
|
@@ -2591,18 +2601,51 @@ function isTopmostDialog(z) {
|
|
|
2591
2601
|
].join(String.fromCharCode(10))
|
|
2592
2602
|
};
|
|
2593
2603
|
const promptFor = lang => CLIPBOARD_PROMPT_TEXT[lang] || CLIPBOARD_PROMPT_TEXT.zh;
|
|
2604
|
+
function isClickInsideDialog(e, dialogRef, layerRef) {
|
|
2605
|
+
if (!e || !e.target) return false;
|
|
2606
|
+
const target = e.target;
|
|
2607
|
+
if (dialogRef && dialogRef.current && typeof dialogRef.current.contains === "function" && dialogRef.current.contains(target)) {
|
|
2608
|
+
return true;
|
|
2609
|
+
}
|
|
2610
|
+
if (layerRef && layerRef.current && typeof layerRef.current.contains === "function" && layerRef.current.contains(target)) {
|
|
2611
|
+
return true;
|
|
2612
|
+
}
|
|
2613
|
+
if (typeof target.closest === "function") {
|
|
2614
|
+
if (dialogRef && dialogRef.current && target.closest(".sm-nativeDialog") === dialogRef.current) {
|
|
2615
|
+
return true;
|
|
2616
|
+
}
|
|
2617
|
+
if (layerRef && layerRef.current && target.closest(".sm-nativeDialogLayer") === layerRef.current) {
|
|
2618
|
+
return true;
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
if (activeCustomMenu && typeof activeCustomMenu.contains === "function" && activeCustomMenu.contains(target)) {
|
|
2622
|
+
if (activeCustomSelect) {
|
|
2623
|
+
if (dialogRef && dialogRef.current && typeof dialogRef.current.contains === "function" && dialogRef.current.contains(activeCustomSelect)) {
|
|
2624
|
+
return true;
|
|
2625
|
+
}
|
|
2626
|
+
if (layerRef && layerRef.current && typeof layerRef.current.contains === "function" && layerRef.current.contains(activeCustomSelect)) {
|
|
2627
|
+
return true;
|
|
2628
|
+
}
|
|
2629
|
+
}
|
|
2630
|
+
}
|
|
2631
|
+
return false;
|
|
2632
|
+
}
|
|
2633
|
+
|
|
2594
2634
|
function BatchPreviewDialog(props) {
|
|
2595
2635
|
const t = typeof props.t === "function" ? props.t : (key) => key;
|
|
2596
2636
|
const open = props.open === true;
|
|
2597
2637
|
const onCancel = typeof props.onCancel === "function" ? props.onCancel : () => {};
|
|
2598
2638
|
const onExecute = typeof props.onExecute === "function" ? props.onExecute : () => {};
|
|
2639
|
+
const danger = props.danger === true;
|
|
2599
2640
|
const actionLabel = props.actionLabel || "";
|
|
2600
2641
|
const summaryAction = props.summaryAction || actionLabel;
|
|
2642
|
+
const title = props.title || (props.action === "delete" ? (props.t ? t("confirm.delete.title") : "删除会话") : t("bulk.dialog.title", { action: actionLabel }));
|
|
2601
2643
|
const sessions = Array.isArray(props.sessions) ? props.sessions : [];
|
|
2602
2644
|
const warning = typeof props.warning === "string" ? props.warning : "";
|
|
2603
2645
|
const confirmLabel = props.confirmLabel || t("bulk.dialog.execute");
|
|
2604
2646
|
const cancelLabel = props.cancelLabel || t("bulk.dialog.cancel");
|
|
2605
|
-
const
|
|
2647
|
+
const dialogRef = useRef(null);
|
|
2648
|
+
const layerRef = useRef(null);
|
|
2606
2649
|
const [expanded, setExpanded] = useState(false);
|
|
2607
2650
|
const [zIndex] = useState(() => open ? nextDialogZ() : 0);
|
|
2608
2651
|
const floatingCoords = useFloatingPosition(props.anchor, open, { placement: "bottom-end", dialogWidth: 360, dialogHeight: 320 });
|
|
@@ -2614,15 +2657,33 @@ function isTopmostDialog(z) {
|
|
|
2614
2657
|
const handler = (e) => {
|
|
2615
2658
|
if (e.key !== "Escape" || e.defaultPrevented) return;
|
|
2616
2659
|
if (!isTopmostDialog(zIndex)) return;
|
|
2660
|
+
if (props.busy) return;
|
|
2617
2661
|
e.preventDefault(); e.stopPropagation(); escStateRef.current.onCancel();
|
|
2618
2662
|
};
|
|
2619
2663
|
window.addEventListener("keydown", handler);
|
|
2664
|
+
const mountTime = Date.now();
|
|
2665
|
+
const clickHandler = (e) => {
|
|
2666
|
+
if (Date.now() - mountTime < 50) return;
|
|
2667
|
+
if (e.defaultPrevented) return;
|
|
2668
|
+
if (props.busy) return;
|
|
2669
|
+
if (!isTopmostDialog(zIndex)) return;
|
|
2670
|
+
if (isClickInsideDialog(e, dialogRef, layerRef)) return;
|
|
2671
|
+
if (e && typeof e.preventDefault === "function") e.preventDefault();
|
|
2672
|
+
if (e && typeof e.stopPropagation === "function") e.stopPropagation();
|
|
2673
|
+
if (e && typeof e.stopImmediatePropagation === "function") e.stopImmediatePropagation();
|
|
2674
|
+
escStateRef.current.onCancel();
|
|
2675
|
+
};
|
|
2676
|
+
window.addEventListener("click", clickHandler, true);
|
|
2620
2677
|
return () => {
|
|
2621
2678
|
unregisterDialogZ(zIndex);
|
|
2622
2679
|
window.removeEventListener("keydown", handler);
|
|
2680
|
+
window.removeEventListener("click", clickHandler, true);
|
|
2623
2681
|
};
|
|
2624
2682
|
}, [open, zIndex]);
|
|
2625
2683
|
if (!open) return null;
|
|
2684
|
+
const loading = props.loading === true;
|
|
2685
|
+
const hasError = Boolean(props.error);
|
|
2686
|
+
const confirmDisabled = loading || hasError;
|
|
2626
2687
|
const showExpand = sessions.length > 12;
|
|
2627
2688
|
const visible = expanded ? sessions : sessions.slice(0, 12);
|
|
2628
2689
|
const topPx = floatingCoords ? floatingCoords.top : null;
|
|
@@ -2644,9 +2705,9 @@ function isTopmostDialog(z) {
|
|
|
2644
2705
|
: {})
|
|
2645
2706
|
};
|
|
2646
2707
|
const portalOverlay = renderInOverlay;
|
|
2647
|
-
return portalOverlay(h("div", { className: "sm-nativeDialogLayer sm-bulkDialog" + (hasCoords ? " sm-bulkDialog-anchored" : ""), role: "presentation", style: layerStyle },
|
|
2648
|
-
h("section", { className: "sm-nativeDialog", style: { pointerEvents: "auto" }, role: "dialog", "aria-modal": "true", "aria-labelledby": "sm-batch-preview-title" },
|
|
2649
|
-
h("div", { className: "sm-nativeDialogHeader" }, h("h2", { id: "sm-batch-preview-title", className: "sm-nativeDialogTitle" },
|
|
2708
|
+
return portalOverlay(h("div", { ref: layerRef, className: "sm-nativeDialogLayer sm-bulkDialog" + (hasCoords ? " sm-bulkDialog-anchored" : ""), role: "presentation", style: layerStyle },
|
|
2709
|
+
h("section", { ref: dialogRef, className: "sm-nativeDialog", style: { pointerEvents: "auto" }, role: "dialog", "aria-modal": "true", "aria-labelledby": "sm-batch-preview-title" },
|
|
2710
|
+
h("div", { className: "sm-nativeDialogHeader" }, h("h2", { id: "sm-batch-preview-title", className: "sm-nativeDialogTitle" }, title)),
|
|
2650
2711
|
h("div", { className: "sm-nativeDialogBody" },
|
|
2651
2712
|
h("div", { className: "sm-bulkDialogSummary" }, t("bulk.dialog.summary", { count: sessions.length, action: actionLabel })),
|
|
2652
2713
|
warning ? h("div", { className: "sm-bulkDialogWarn" }, warning) : null,
|
|
@@ -2657,7 +2718,12 @@ function isTopmostDialog(z) {
|
|
|
2657
2718
|
),
|
|
2658
2719
|
h("div", { className: "sm-nativeDialogFooter" },
|
|
2659
2720
|
h("button", { type: "button", className: "sm-nativeDialogButton sm-nativeDialogCancel", onClick: onCancel }, cancelLabel),
|
|
2660
|
-
h("button", {
|
|
2721
|
+
h("button", {
|
|
2722
|
+
type: "button",
|
|
2723
|
+
className: "sm-nativeDialogButton" + (danger ? " sm-nativeDialogDanger" : " sm-nativeDialogConfirm"),
|
|
2724
|
+
disabled: props.busy || confirmDisabled,
|
|
2725
|
+
onClick: () => { if (!props.busy && !confirmDisabled) onExecute(); }
|
|
2726
|
+
}, confirmLabel)
|
|
2661
2727
|
)
|
|
2662
2728
|
)
|
|
2663
2729
|
));
|
|
@@ -2667,6 +2733,11 @@ function isTopmostDialog(z) {
|
|
|
2667
2733
|
const t = typeof props.t === "function" ? props.t : (key) => key;
|
|
2668
2734
|
const open = props.open === true;
|
|
2669
2735
|
const [zIndex] = useState(() => open ? nextDialogZ() : 0);
|
|
2736
|
+
useEffect(() => {
|
|
2737
|
+
if (!open) return;
|
|
2738
|
+
registerDialogZ(zIndex);
|
|
2739
|
+
return () => unregisterDialogZ(zIndex);
|
|
2740
|
+
}, [open, zIndex]);
|
|
2670
2741
|
const actionLabel = props.actionLabel || "";
|
|
2671
2742
|
const done = Number.isInteger(props.done) ? props.done : 0;
|
|
2672
2743
|
const total = Number.isInteger(props.total) ? props.total : 0;
|
|
@@ -2714,6 +2785,8 @@ function isTopmostDialog(z) {
|
|
|
2714
2785
|
function BatchResultDialog(props) {
|
|
2715
2786
|
const t = typeof props.t === "function" ? props.t : (key) => key;
|
|
2716
2787
|
const open = props.open === true;
|
|
2788
|
+
const dialogRef = useRef(null);
|
|
2789
|
+
const layerRef = useRef(null);
|
|
2717
2790
|
const [zIndex] = useState(() => open ? nextDialogZ() : 0);
|
|
2718
2791
|
const actionLabel = props.actionLabel || "";
|
|
2719
2792
|
const items = Array.isArray(props.items) ? props.items : [];
|
|
@@ -2733,9 +2806,22 @@ function isTopmostDialog(z) {
|
|
|
2733
2806
|
e.preventDefault(); e.stopPropagation(); escStateRef.current.onClose();
|
|
2734
2807
|
};
|
|
2735
2808
|
window.addEventListener("keydown", handler);
|
|
2809
|
+
const mountTime = Date.now();
|
|
2810
|
+
const clickHandler = (e) => {
|
|
2811
|
+
if (Date.now() - mountTime < 50) return;
|
|
2812
|
+
if (e.defaultPrevented) return;
|
|
2813
|
+
if (!isTopmostDialog(zIndex)) return;
|
|
2814
|
+
if (isClickInsideDialog(e, dialogRef, layerRef)) return;
|
|
2815
|
+
if (e && typeof e.preventDefault === "function") e.preventDefault();
|
|
2816
|
+
if (e && typeof e.stopPropagation === "function") e.stopPropagation();
|
|
2817
|
+
if (e && typeof e.stopImmediatePropagation === "function") e.stopImmediatePropagation();
|
|
2818
|
+
escStateRef.current.onClose();
|
|
2819
|
+
};
|
|
2820
|
+
window.addEventListener("click", clickHandler, true);
|
|
2736
2821
|
return () => {
|
|
2737
2822
|
unregisterDialogZ(zIndex);
|
|
2738
2823
|
window.removeEventListener("keydown", handler);
|
|
2824
|
+
window.removeEventListener("click", clickHandler, true);
|
|
2739
2825
|
};
|
|
2740
2826
|
}, [open, zIndex]);
|
|
2741
2827
|
if (!open) return null;
|
|
@@ -2777,8 +2863,8 @@ function isTopmostDialog(z) {
|
|
|
2777
2863
|
: {})
|
|
2778
2864
|
};
|
|
2779
2865
|
const portalOverlay = renderInOverlay;
|
|
2780
|
-
return portalOverlay(h("div", { className: "sm-nativeDialogLayer sm-bulkDialog" + (hasCoords ? " sm-bulkDialog-anchored" : ""), role: "presentation", style: layerStyle },
|
|
2781
|
-
h("section", { className: "sm-nativeDialog", style: { pointerEvents: "auto" }, role: "dialog", "aria-modal": "true", "aria-labelledby": "sm-batch-result-title" },
|
|
2866
|
+
return portalOverlay(h("div", { ref: layerRef, className: "sm-nativeDialogLayer sm-bulkDialog" + (hasCoords ? " sm-bulkDialog-anchored" : ""), role: "presentation", style: layerStyle },
|
|
2867
|
+
h("section", { ref: dialogRef, className: "sm-nativeDialog", style: { pointerEvents: "auto" }, role: "dialog", "aria-modal": "true", "aria-labelledby": "sm-batch-result-title" },
|
|
2782
2868
|
h("div", { className: "sm-nativeDialogHeader" }, h("h2", { id: "sm-batch-result-title", className: "sm-nativeDialogTitle" }, t("bulk.result.title", { action: actionLabel }))),
|
|
2783
2869
|
h("div", { className: "sm-nativeDialogBody" },
|
|
2784
2870
|
renderGroup("bulk.result.successGroup", groups.success),
|
|
@@ -2826,6 +2912,8 @@ function isTopmostDialog(z) {
|
|
|
2826
2912
|
function BulkTagInputDialog(props) {
|
|
2827
2913
|
const t = typeof props.t === "function" ? props.t : (key) => key;
|
|
2828
2914
|
const open = props.open === true;
|
|
2915
|
+
const dialogRef = useRef(null);
|
|
2916
|
+
const layerRef = useRef(null);
|
|
2829
2917
|
const [zIndex] = useState(() => open ? nextDialogZ() : 0);
|
|
2830
2918
|
const title = props.title || t("bulk.tagsAdd");
|
|
2831
2919
|
const description = props.description || "";
|
|
@@ -2847,9 +2935,22 @@ function isTopmostDialog(z) {
|
|
|
2847
2935
|
e.preventDefault(); e.stopPropagation(); escStateRef.current.onCancel();
|
|
2848
2936
|
};
|
|
2849
2937
|
window.addEventListener("keydown", handler);
|
|
2938
|
+
const mountTime = Date.now();
|
|
2939
|
+
const clickHandler = (e) => {
|
|
2940
|
+
if (Date.now() - mountTime < 50) return;
|
|
2941
|
+
if (e.defaultPrevented) return;
|
|
2942
|
+
if (!isTopmostDialog(zIndex)) return;
|
|
2943
|
+
if (isClickInsideDialog(e, dialogRef, layerRef)) return;
|
|
2944
|
+
if (e && typeof e.preventDefault === "function") e.preventDefault();
|
|
2945
|
+
if (e && typeof e.stopPropagation === "function") e.stopPropagation();
|
|
2946
|
+
if (e && typeof e.stopImmediatePropagation === "function") e.stopImmediatePropagation();
|
|
2947
|
+
escStateRef.current.onCancel();
|
|
2948
|
+
};
|
|
2949
|
+
window.addEventListener("click", clickHandler, true);
|
|
2850
2950
|
return () => {
|
|
2851
2951
|
unregisterDialogZ(zIndex);
|
|
2852
2952
|
window.removeEventListener("keydown", handler);
|
|
2953
|
+
window.removeEventListener("click", clickHandler, true);
|
|
2853
2954
|
};
|
|
2854
2955
|
}, [open, zIndex]);
|
|
2855
2956
|
if (!open) return null;
|
|
@@ -2876,8 +2977,8 @@ function isTopmostDialog(z) {
|
|
|
2876
2977
|
: {})
|
|
2877
2978
|
};
|
|
2878
2979
|
const portalOverlay = renderInOverlay;
|
|
2879
|
-
return portalOverlay(h("div", { className: "sm-nativeDialogLayer sm-bulkDialog" + (hasCoords ? " sm-bulkDialog-anchored" : ""), role: "presentation", style: layerStyle },
|
|
2880
|
-
h("section", { className: "sm-nativeDialog", style: { pointerEvents: "auto" }, role: "dialog", "aria-modal": "true", "aria-labelledby": "sm-bulk-tags-title" },
|
|
2980
|
+
return portalOverlay(h("div", { ref: layerRef, className: "sm-nativeDialogLayer sm-bulkDialog" + (hasCoords ? " sm-bulkDialog-anchored" : ""), role: "presentation", style: layerStyle },
|
|
2981
|
+
h("section", { ref: dialogRef, className: "sm-nativeDialog", style: { pointerEvents: "auto" }, role: "dialog", "aria-modal": "true", "aria-labelledby": "sm-bulk-tags-title" },
|
|
2881
2982
|
h("div", { className: "sm-nativeDialogHeader" }, h("h2", { id: "sm-bulk-tags-title", className: "sm-nativeDialogTitle" }, title)),
|
|
2882
2983
|
h("div", { className: "sm-nativeDialogBody" },
|
|
2883
2984
|
description ? h("div", { className: "sm-bulkDialogSummary" }, description) : null,
|
|
@@ -2894,6 +2995,8 @@ function isTopmostDialog(z) {
|
|
|
2894
2995
|
function BulkChoiceDialog(props) {
|
|
2895
2996
|
const t = typeof props.t === "function" ? props.t : (key) => key;
|
|
2896
2997
|
const open = props.open === true;
|
|
2998
|
+
const dialogRef = useRef(null);
|
|
2999
|
+
const layerRef = useRef(null);
|
|
2897
3000
|
const [zIndex] = useState(() => open ? nextDialogZ() : 0);
|
|
2898
3001
|
const title = props.title || "";
|
|
2899
3002
|
const description = props.description || "";
|
|
@@ -2915,9 +3018,22 @@ function isTopmostDialog(z) {
|
|
|
2915
3018
|
e.preventDefault(); e.stopPropagation(); escStateRef.current.onCancel();
|
|
2916
3019
|
};
|
|
2917
3020
|
window.addEventListener("keydown", handler);
|
|
3021
|
+
const mountTime = Date.now();
|
|
3022
|
+
const clickHandler = (e) => {
|
|
3023
|
+
if (Date.now() - mountTime < 50) return;
|
|
3024
|
+
if (e.defaultPrevented) return;
|
|
3025
|
+
if (!isTopmostDialog(zIndex)) return;
|
|
3026
|
+
if (isClickInsideDialog(e, dialogRef, layerRef)) return;
|
|
3027
|
+
if (e && typeof e.preventDefault === "function") e.preventDefault();
|
|
3028
|
+
if (e && typeof e.stopPropagation === "function") e.stopPropagation();
|
|
3029
|
+
if (e && typeof e.stopImmediatePropagation === "function") e.stopImmediatePropagation();
|
|
3030
|
+
escStateRef.current.onCancel();
|
|
3031
|
+
};
|
|
3032
|
+
window.addEventListener("click", clickHandler, true);
|
|
2918
3033
|
return () => {
|
|
2919
3034
|
unregisterDialogZ(zIndex);
|
|
2920
3035
|
window.removeEventListener("keydown", handler);
|
|
3036
|
+
window.removeEventListener("click", clickHandler, true);
|
|
2921
3037
|
};
|
|
2922
3038
|
}, [open, zIndex]);
|
|
2923
3039
|
if (!open) return null;
|
|
@@ -2940,8 +3056,8 @@ function isTopmostDialog(z) {
|
|
|
2940
3056
|
: {})
|
|
2941
3057
|
};
|
|
2942
3058
|
const portalOverlay = renderInOverlay;
|
|
2943
|
-
return portalOverlay(h("div", { className: "sm-nativeDialogLayer sm-bulkDialog" + (hasCoords ? " sm-bulkDialog-anchored" : ""), role: "presentation", style: layerStyle },
|
|
2944
|
-
h("section", { className: "sm-nativeDialog", style: { pointerEvents: "auto" }, role: "dialog", "aria-modal": "true", "aria-labelledby": "sm-bulk-choice-title" },
|
|
3059
|
+
return portalOverlay(h("div", { ref: layerRef, className: "sm-nativeDialogLayer sm-bulkDialog" + (hasCoords ? " sm-bulkDialog-anchored" : ""), role: "presentation", style: layerStyle },
|
|
3060
|
+
h("section", { ref: dialogRef, className: "sm-nativeDialog", style: { pointerEvents: "auto" }, role: "dialog", "aria-modal": "true", "aria-labelledby": "sm-bulk-choice-title" },
|
|
2945
3061
|
h("div", { className: "sm-nativeDialogHeader" }, h("h2", { id: "sm-bulk-choice-title", className: "sm-nativeDialogTitle" }, title)),
|
|
2946
3062
|
h("div", { className: "sm-nativeDialogBody" },
|
|
2947
3063
|
description ? h("div", { className: "sm-bulkDialogSummary" }, description) : null,
|
|
@@ -3167,6 +3283,8 @@ function isTopmostDialog(z) {
|
|
|
3167
3283
|
const onConfirm = typeof props.onConfirm === "function" ? props.onConfirm : () => {};
|
|
3168
3284
|
const busy = props.busy === true;
|
|
3169
3285
|
const danger = props.danger === true;
|
|
3286
|
+
const dialogRef = useRef(null);
|
|
3287
|
+
const layerRef = useRef(null);
|
|
3170
3288
|
// Claim a fresh z-index so this popup sits above any earlier popup.
|
|
3171
3289
|
const [zIndex] = useState(() => open ? nextDialogZ() : 0);
|
|
3172
3290
|
const title = props.title || "";
|
|
@@ -3202,9 +3320,23 @@ function isTopmostDialog(z) {
|
|
|
3202
3320
|
if (ae && typeof ae.blur === "function" && ae !== document.body) ae.blur();
|
|
3203
3321
|
};
|
|
3204
3322
|
window.addEventListener("keydown", handler);
|
|
3323
|
+
const mountTime = Date.now();
|
|
3324
|
+
const clickHandler = (e) => {
|
|
3325
|
+
if (Date.now() - mountTime < 50) return;
|
|
3326
|
+
if (e.defaultPrevented) return;
|
|
3327
|
+
if (escStateRef.current.busy) return;
|
|
3328
|
+
if (!isTopmostDialog(effectiveZ)) return;
|
|
3329
|
+
if (isClickInsideDialog(e, dialogRef, layerRef)) return;
|
|
3330
|
+
if (e && typeof e.preventDefault === "function") e.preventDefault();
|
|
3331
|
+
if (e && typeof e.stopPropagation === "function") e.stopPropagation();
|
|
3332
|
+
if (e && typeof e.stopImmediatePropagation === "function") e.stopImmediatePropagation();
|
|
3333
|
+
escStateRef.current.onCancel();
|
|
3334
|
+
};
|
|
3335
|
+
window.addEventListener("click", clickHandler, true);
|
|
3205
3336
|
return () => {
|
|
3206
3337
|
unregisterDialogZ(effectiveZ);
|
|
3207
3338
|
window.removeEventListener("keydown", handler);
|
|
3339
|
+
window.removeEventListener("click", clickHandler, true);
|
|
3208
3340
|
};
|
|
3209
3341
|
}, [open, zIndex]);
|
|
3210
3342
|
|
|
@@ -3232,13 +3364,17 @@ function isTopmostDialog(z) {
|
|
|
3232
3364
|
: {})
|
|
3233
3365
|
};
|
|
3234
3366
|
|
|
3367
|
+
const confirmDisabled = props.confirmDisabled === true;
|
|
3368
|
+
|
|
3235
3369
|
return renderInOverlay(
|
|
3236
3370
|
h("div", {
|
|
3371
|
+
ref: layerRef,
|
|
3237
3372
|
className: "sm-nativeDialogLayer sm-confirmDialog" + (hasCoords ? " sm-confirmDialog-anchored" : ""),
|
|
3238
3373
|
style: layerStyle,
|
|
3239
3374
|
role: "presentation"
|
|
3240
3375
|
},
|
|
3241
3376
|
h("section", {
|
|
3377
|
+
ref: dialogRef,
|
|
3242
3378
|
className: "sm-nativeDialog",
|
|
3243
3379
|
style: { pointerEvents: "auto" },
|
|
3244
3380
|
role: "dialog",
|
|
@@ -3262,8 +3398,8 @@ function isTopmostDialog(z) {
|
|
|
3262
3398
|
h("button", {
|
|
3263
3399
|
type: "button",
|
|
3264
3400
|
className: "sm-nativeDialogButton" + (danger ? " sm-nativeDialogDanger" : " sm-nativeDialogConfirm"),
|
|
3265
|
-
disabled: busy,
|
|
3266
|
-
onClick: () => { if (!busy) onConfirm(); }
|
|
3401
|
+
disabled: busy || confirmDisabled,
|
|
3402
|
+
onClick: () => { if (!busy && !confirmDisabled) onConfirm(); }
|
|
3267
3403
|
}, confirmLabel)
|
|
3268
3404
|
)
|
|
3269
3405
|
)
|
|
@@ -3276,6 +3412,8 @@ function isTopmostDialog(z) {
|
|
|
3276
3412
|
const onCancel = typeof props.onCancel === "function" ? props.onCancel : () => {};
|
|
3277
3413
|
const onConfirm = typeof props.onConfirm === "function" ? props.onConfirm : () => {};
|
|
3278
3414
|
const busy = props.busy === true;
|
|
3415
|
+
const dialogRef = useRef(null);
|
|
3416
|
+
const layerRef = useRef(null);
|
|
3279
3417
|
const title = props.title || t("confirm.move.title");
|
|
3280
3418
|
const description = props.description || "";
|
|
3281
3419
|
const currentWorkspaceId = props.currentWorkspaceId || "";
|
|
@@ -3324,9 +3462,23 @@ function isTopmostDialog(z) {
|
|
|
3324
3462
|
if (ae && typeof ae.blur === "function" && ae !== document.body) ae.blur();
|
|
3325
3463
|
};
|
|
3326
3464
|
window.addEventListener("keydown", handler);
|
|
3465
|
+
const mountTime = Date.now();
|
|
3466
|
+
const clickHandler = (e) => {
|
|
3467
|
+
if (Date.now() - mountTime < 50) return;
|
|
3468
|
+
if (e.defaultPrevented) return;
|
|
3469
|
+
if (escStateRef.current.busy) return;
|
|
3470
|
+
if (!isTopmostDialog(effectiveZ)) return;
|
|
3471
|
+
if (isClickInsideDialog(e, dialogRef, layerRef)) return;
|
|
3472
|
+
if (e && typeof e.preventDefault === "function") e.preventDefault();
|
|
3473
|
+
if (e && typeof e.stopPropagation === "function") e.stopPropagation();
|
|
3474
|
+
if (e && typeof e.stopImmediatePropagation === "function") e.stopImmediatePropagation();
|
|
3475
|
+
escStateRef.current.onCancel();
|
|
3476
|
+
};
|
|
3477
|
+
window.addEventListener("click", clickHandler, true);
|
|
3327
3478
|
return () => {
|
|
3328
3479
|
unregisterDialogZ(effectiveZ);
|
|
3329
3480
|
window.removeEventListener("keydown", handler);
|
|
3481
|
+
window.removeEventListener("click", clickHandler, true);
|
|
3330
3482
|
};
|
|
3331
3483
|
}, [open, zIndex]);
|
|
3332
3484
|
if (!open) return null;
|
|
@@ -3384,12 +3536,14 @@ function isTopmostDialog(z) {
|
|
|
3384
3536
|
};
|
|
3385
3537
|
return renderInOverlay(
|
|
3386
3538
|
h("div", {
|
|
3539
|
+
ref: layerRef,
|
|
3387
3540
|
className: "sm-nativeDialogLayer sm-confirmDialog" + (hasCoords ? " sm-confirmDialog-anchored" : ""),
|
|
3388
3541
|
style: layerStyle,
|
|
3389
3542
|
role: "presentation",
|
|
3390
3543
|
onKeyDown
|
|
3391
3544
|
},
|
|
3392
3545
|
h("section", {
|
|
3546
|
+
ref: dialogRef,
|
|
3393
3547
|
className: "sm-nativeDialog",
|
|
3394
3548
|
style: { pointerEvents: "auto" },
|
|
3395
3549
|
role: "dialog",
|
|
@@ -3425,6 +3579,8 @@ function isTopmostDialog(z) {
|
|
|
3425
3579
|
const onCancel = typeof props.onCancel === "function" ? props.onCancel : () => {};
|
|
3426
3580
|
const onRun = typeof props.onRun === "function" ? props.onRun : () => {};
|
|
3427
3581
|
const busy = props.busy === true;
|
|
3582
|
+
const dialogRef = useRef(null);
|
|
3583
|
+
const layerRef = useRef(null);
|
|
3428
3584
|
const sessionId = props.sessionId || "";
|
|
3429
3585
|
const description = props.description || "";
|
|
3430
3586
|
const fallbackPreset = props.currentPreset || "";
|
|
@@ -3483,9 +3639,23 @@ function isTopmostDialog(z) {
|
|
|
3483
3639
|
if (ae && typeof ae.blur === "function" && ae !== document.body) ae.blur();
|
|
3484
3640
|
};
|
|
3485
3641
|
window.addEventListener("keydown", handler);
|
|
3642
|
+
const mountTime = Date.now();
|
|
3643
|
+
const clickHandler = (e) => {
|
|
3644
|
+
if (Date.now() - mountTime < 50) return;
|
|
3645
|
+
if (e.defaultPrevented) return;
|
|
3646
|
+
if (escStateRef.current.busy) return;
|
|
3647
|
+
if (!isTopmostDialog(effectiveZ)) return;
|
|
3648
|
+
if (isClickInsideDialog(e, dialogRef, layerRef)) return;
|
|
3649
|
+
if (e && typeof e.preventDefault === "function") e.preventDefault();
|
|
3650
|
+
if (e && typeof e.stopPropagation === "function") e.stopPropagation();
|
|
3651
|
+
if (e && typeof e.stopImmediatePropagation === "function") e.stopImmediatePropagation();
|
|
3652
|
+
escStateRef.current.onCancel();
|
|
3653
|
+
};
|
|
3654
|
+
window.addEventListener("click", clickHandler, true);
|
|
3486
3655
|
return () => {
|
|
3487
3656
|
unregisterDialogZ(effectiveZ);
|
|
3488
3657
|
window.removeEventListener("keydown", handler);
|
|
3658
|
+
window.removeEventListener("click", clickHandler, true);
|
|
3489
3659
|
};
|
|
3490
3660
|
}, [open, zIndex]);
|
|
3491
3661
|
if (!open) return null;
|
|
@@ -3542,11 +3712,13 @@ function isTopmostDialog(z) {
|
|
|
3542
3712
|
};
|
|
3543
3713
|
return renderInOverlay(
|
|
3544
3714
|
h("div", {
|
|
3715
|
+
ref: layerRef,
|
|
3545
3716
|
className: "sm-nativeDialogLayer sm-confirmDialog" + (hasCoords ? " sm-confirmDialog-anchored" : ""),
|
|
3546
3717
|
role: "presentation",
|
|
3547
3718
|
style: layerStyle
|
|
3548
3719
|
},
|
|
3549
3720
|
h("section", {
|
|
3721
|
+
ref: dialogRef,
|
|
3550
3722
|
className: "sm-nativeDialog",
|
|
3551
3723
|
style: { pointerEvents: "auto" },
|
|
3552
3724
|
role: "dialog",
|
|
@@ -3575,7 +3747,7 @@ function isTopmostDialog(z) {
|
|
|
3575
3747
|
));
|
|
3576
3748
|
}
|
|
3577
3749
|
|
|
3578
|
-
const CURRENT_VERSION = "0.7.
|
|
3750
|
+
const CURRENT_VERSION = "0.7.2";
|
|
3579
3751
|
|
|
3580
3752
|
function compareSemver(v1, v2) {
|
|
3581
3753
|
if (typeof v1 !== "string" || typeof v2 !== "string") return 0;
|
|
@@ -3636,7 +3808,11 @@ function isTopmostDialog(z) {
|
|
|
3636
3808
|
application: null,
|
|
3637
3809
|
dialogOpen: false,
|
|
3638
3810
|
checkedAt: null,
|
|
3811
|
+
lastAttemptAt: null,
|
|
3639
3812
|
},
|
|
3813
|
+
CHECK_INTERVAL_MS: 6 * 60 * 60 * 1000,
|
|
3814
|
+
RETRY_COOLDOWN_MS: 30 * 60 * 1000,
|
|
3815
|
+
lastFailedAt: null,
|
|
3640
3816
|
listeners: new Set(),
|
|
3641
3817
|
getSnapshot() { return this.state; },
|
|
3642
3818
|
subscribe(cb) {
|
|
@@ -3671,6 +3847,29 @@ function isTopmostDialog(z) {
|
|
|
3671
3847
|
} catch (_) {}
|
|
3672
3848
|
this._notify();
|
|
3673
3849
|
},
|
|
3850
|
+
shouldAutoCheck(now = Date.now()) {
|
|
3851
|
+
if (!this.getAutoCheck()) return false;
|
|
3852
|
+
if (this.state.status === "checking" || this.state.status === "updating") return false;
|
|
3853
|
+
if (this.state.status === "available") return false;
|
|
3854
|
+
if (this.lastFailedAt && (now - this.lastFailedAt < this.RETRY_COOLDOWN_MS)) {
|
|
3855
|
+
return false;
|
|
3856
|
+
}
|
|
3857
|
+
if (this.state.checkedAt && (now - this.state.checkedAt < this.CHECK_INTERVAL_MS)) {
|
|
3858
|
+
return false;
|
|
3859
|
+
}
|
|
3860
|
+
return true;
|
|
3861
|
+
},
|
|
3862
|
+
async maybeAutoCheck(options = {}) {
|
|
3863
|
+
const now = typeof options.now === "number" ? options.now : Date.now();
|
|
3864
|
+
if (!this.shouldAutoCheck(now)) return this.state;
|
|
3865
|
+
return this.checkForUpdate({
|
|
3866
|
+
silent: true,
|
|
3867
|
+
openOnFound: false,
|
|
3868
|
+
openDialog: false,
|
|
3869
|
+
...options,
|
|
3870
|
+
manual: false
|
|
3871
|
+
});
|
|
3872
|
+
},
|
|
3674
3873
|
// Dialog opacity preference (Issue #23). Reuses the same localStorage
|
|
3675
3874
|
// backed preference store as autoCheck / registry instead of adding a
|
|
3676
3875
|
// second storage mechanism.
|
|
@@ -3733,7 +3932,17 @@ function isTopmostDialog(z) {
|
|
|
3733
3932
|
}
|
|
3734
3933
|
this._notify();
|
|
3735
3934
|
|
|
3935
|
+
const timeoutMs = typeof options.timeoutMs === "number" ? options.timeoutMs : 10000;
|
|
3936
|
+
let timeoutTimer = null;
|
|
3937
|
+
const abortController = typeof AbortController !== "undefined" ? new AbortController() : null;
|
|
3938
|
+
|
|
3736
3939
|
try {
|
|
3940
|
+
if (abortController) {
|
|
3941
|
+
timeoutTimer = setTimeout(() => {
|
|
3942
|
+
abortController.abort(new Error("检查更新超时"));
|
|
3943
|
+
}, timeoutMs);
|
|
3944
|
+
}
|
|
3945
|
+
|
|
3737
3946
|
let res = null;
|
|
3738
3947
|
if (typeof window !== "undefined" && window.__DSH_SM_TEST_UPDATE__) {
|
|
3739
3948
|
const testOverride = window.__DSH_SM_TEST_UPDATE__;
|
|
@@ -3747,12 +3956,16 @@ function isTopmostDialog(z) {
|
|
|
3747
3956
|
} else {
|
|
3748
3957
|
const registryUrl = this.getRegistryUrl();
|
|
3749
3958
|
const registryParam = encodeURIComponent(registryUrl);
|
|
3959
|
+
const fetchOpts = abortController ? { signal: abortController.signal } : undefined;
|
|
3750
3960
|
try {
|
|
3751
|
-
res = await fetchApi("/update/check?registry=" + registryParam);
|
|
3961
|
+
res = await fetchApi("/update/check?registry=" + registryParam, fetchOpts);
|
|
3752
3962
|
} catch (fetchErr) {
|
|
3963
|
+
if (abortController?.signal?.aborted || fetchErr.name === "AbortError" || fetchErr.message?.includes("超时")) {
|
|
3964
|
+
throw new Error("检查更新超时");
|
|
3965
|
+
}
|
|
3753
3966
|
try {
|
|
3754
3967
|
const base = registryUrl.endsWith("/") ? registryUrl : registryUrl + "/";
|
|
3755
|
-
const npmRes = await fetch(base + "dsh-session-manager/latest");
|
|
3968
|
+
const npmRes = await fetch(base + "dsh-session-manager/latest", fetchOpts);
|
|
3756
3969
|
if (npmRes.ok) {
|
|
3757
3970
|
const npmData = await npmRes.json();
|
|
3758
3971
|
if (npmData && npmData.version) {
|
|
@@ -3762,7 +3975,11 @@ function isTopmostDialog(z) {
|
|
|
3762
3975
|
res = { ok: true, result: { currentVersion: cur, latestVersion: lat, hasUpdate } };
|
|
3763
3976
|
}
|
|
3764
3977
|
}
|
|
3765
|
-
} catch (_) {
|
|
3978
|
+
} catch (_) {
|
|
3979
|
+
if (abortController?.signal?.aborted || fetchErr.name === "AbortError" || fetchErr.message?.includes("超时")) {
|
|
3980
|
+
throw new Error("检查更新超时");
|
|
3981
|
+
}
|
|
3982
|
+
}
|
|
3766
3983
|
if (!res) throw fetchErr;
|
|
3767
3984
|
}
|
|
3768
3985
|
}
|
|
@@ -3778,7 +3995,10 @@ function isTopmostDialog(z) {
|
|
|
3778
3995
|
|
|
3779
3996
|
this.state.currentVersion = currentVersion;
|
|
3780
3997
|
this.state.latestVersion = latestVersion;
|
|
3781
|
-
|
|
3998
|
+
const now = Date.now();
|
|
3999
|
+
this.state.checkedAt = now;
|
|
4000
|
+
this.state.lastAttemptAt = now;
|
|
4001
|
+
this.lastFailedAt = null;
|
|
3782
4002
|
|
|
3783
4003
|
if (hasUpdate) {
|
|
3784
4004
|
this.state.status = "available";
|
|
@@ -3794,13 +4014,18 @@ function isTopmostDialog(z) {
|
|
|
3794
4014
|
this._notify();
|
|
3795
4015
|
return this.state;
|
|
3796
4016
|
} catch (err) {
|
|
4017
|
+
const now = Date.now();
|
|
3797
4018
|
this.state.status = "error";
|
|
3798
|
-
this.state.error = err.message || "检查更新失败";
|
|
4019
|
+
this.state.error = (abortController?.signal?.aborted ? "检查更新超时" : (err.message || "检查更新失败"));
|
|
4020
|
+
this.state.lastAttemptAt = now;
|
|
4021
|
+
this.lastFailedAt = now;
|
|
3799
4022
|
if (shouldOpenDialog) {
|
|
3800
4023
|
this.state.dialogOpen = true;
|
|
3801
4024
|
}
|
|
3802
4025
|
this._notify();
|
|
3803
4026
|
return this.state;
|
|
4027
|
+
} finally {
|
|
4028
|
+
if (timeoutTimer) clearTimeout(timeoutTimer);
|
|
3804
4029
|
}
|
|
3805
4030
|
},
|
|
3806
4031
|
async startUpdate(options = {}) {
|
|
@@ -3864,8 +4089,15 @@ function isTopmostDialog(z) {
|
|
|
3864
4089
|
listeners: new Set(),
|
|
3865
4090
|
getSnapshot() { return this.open; },
|
|
3866
4091
|
subscribe(cb) { this.listeners.add(cb); return () => this.listeners.delete(cb); },
|
|
3867
|
-
set(v) {
|
|
3868
|
-
|
|
4092
|
+
set(v) {
|
|
4093
|
+
if (this.open === v) return;
|
|
4094
|
+
this.open = v;
|
|
4095
|
+
if (this.open) {
|
|
4096
|
+
try { updateStore.maybeAutoCheck().catch(() => {}); } catch (_) {}
|
|
4097
|
+
}
|
|
4098
|
+
for (const fn of [...this.listeners]) fn();
|
|
4099
|
+
},
|
|
4100
|
+
toggle() { this.set(!this.open); },
|
|
3869
4101
|
// Pending action queued by the title-bar buttons (e.g. 移动至工作区).
|
|
3870
4102
|
// The SessionManagerPanel consumes this on mount so it can pre-open
|
|
3871
4103
|
// the matching inner dialog (move / delete / migrate) next to itself.
|
|
@@ -3979,6 +4211,29 @@ function isTopmostDialog(z) {
|
|
|
3979
4211
|
const [now, setNow] = useState(() => Date.now());
|
|
3980
4212
|
const [moveFor, setMoveFor] = useState(null);
|
|
3981
4213
|
const [confirmFor, setConfirmFor] = useState(null);
|
|
4214
|
+
const [confirmPreviewState, setConfirmPreviewState] = useState({ loading: false, error: null, subagentCount: 0 });
|
|
4215
|
+
useEffect(() => {
|
|
4216
|
+
if (!confirmFor || !confirmFor.id) {
|
|
4217
|
+
setConfirmPreviewState({ loading: false, error: null, subagentCount: 0 });
|
|
4218
|
+
return;
|
|
4219
|
+
}
|
|
4220
|
+
let alive = true;
|
|
4221
|
+
setConfirmPreviewState({ loading: true, error: null, subagentCount: 0 });
|
|
4222
|
+
fetchApi("/delete-preview?sessionId=" + encodeURIComponent(confirmFor.id))
|
|
4223
|
+
.then((res) => {
|
|
4224
|
+
if (!alive) return;
|
|
4225
|
+
if (res && res.ok && res.result && typeof res.result.subagentCount === "number") {
|
|
4226
|
+
setConfirmPreviewState({ loading: false, error: null, subagentCount: res.result.subagentCount });
|
|
4227
|
+
} else {
|
|
4228
|
+
setConfirmPreviewState({ loading: false, error: res?.error || "获取子智能体预览失败", subagentCount: 0 });
|
|
4229
|
+
}
|
|
4230
|
+
})
|
|
4231
|
+
.catch((err) => {
|
|
4232
|
+
if (!alive) return;
|
|
4233
|
+
setConfirmPreviewState({ loading: false, error: err instanceof Error ? err.message : String(err), subagentCount: 0 });
|
|
4234
|
+
});
|
|
4235
|
+
return () => { alive = false; };
|
|
4236
|
+
}, [confirmFor?.id]);
|
|
3982
4237
|
const [workspaces, setWorkspaces] = useState([]);
|
|
3983
4238
|
const [createdTimes, setCreatedTimes] = useState({});
|
|
3984
4239
|
const [updatedTimes, setUpdatedTimes] = useState({});
|
|
@@ -4167,7 +4422,59 @@ function isTopmostDialog(z) {
|
|
|
4167
4422
|
};
|
|
4168
4423
|
const summaryAction = actionSummaryMap[action] || resolvedLabel;
|
|
4169
4424
|
if (needsConfirm) {
|
|
4170
|
-
|
|
4425
|
+
const baseWarning = action === "delete" ? t("bulk.dialog.warning.delete") : "";
|
|
4426
|
+
if (action === "delete") {
|
|
4427
|
+
setBulkPreview({
|
|
4428
|
+
action,
|
|
4429
|
+
payload,
|
|
4430
|
+
actionLabel: summaryAction,
|
|
4431
|
+
sessions,
|
|
4432
|
+
warning: baseWarning,
|
|
4433
|
+
loading: true,
|
|
4434
|
+
error: null
|
|
4435
|
+
});
|
|
4436
|
+
fetchApi("/delete-preview?sessionIds=" + encodeURIComponent(ids.join(",")))
|
|
4437
|
+
.then((res) => {
|
|
4438
|
+
if (res && res.ok && res.result && typeof res.result.subagentCount === "number") {
|
|
4439
|
+
const subCount = res.result.subagentCount;
|
|
4440
|
+
setBulkPreview((prev) => {
|
|
4441
|
+
if (!prev || prev.action !== "delete") return prev;
|
|
4442
|
+
const subText = subCount > 0 ? t("confirm.delete.subagents", { count: subCount }) : "";
|
|
4443
|
+
return {
|
|
4444
|
+
...prev,
|
|
4445
|
+
loading: false,
|
|
4446
|
+
error: null,
|
|
4447
|
+
warning: subText ? `${subText}\n${baseWarning}` : baseWarning
|
|
4448
|
+
};
|
|
4449
|
+
});
|
|
4450
|
+
} else {
|
|
4451
|
+
const errMsg = (res && res.error) || t("confirm.delete.previewError") || "检查关联子智能体会话失败,请稍后重试";
|
|
4452
|
+
setBulkPreview((prev) => {
|
|
4453
|
+
if (!prev || prev.action !== "delete") return prev;
|
|
4454
|
+
return {
|
|
4455
|
+
...prev,
|
|
4456
|
+
loading: false,
|
|
4457
|
+
error: errMsg,
|
|
4458
|
+
warning: `${errMsg}\n${baseWarning}`
|
|
4459
|
+
};
|
|
4460
|
+
});
|
|
4461
|
+
}
|
|
4462
|
+
})
|
|
4463
|
+
.catch((err) => {
|
|
4464
|
+
const errMsg = (err && err.message) || t("confirm.delete.previewError") || "检查关联子智能体会话失败,请稍后重试";
|
|
4465
|
+
setBulkPreview((prev) => {
|
|
4466
|
+
if (!prev || prev.action !== "delete") return prev;
|
|
4467
|
+
return {
|
|
4468
|
+
...prev,
|
|
4469
|
+
loading: false,
|
|
4470
|
+
error: errMsg,
|
|
4471
|
+
warning: `${errMsg}\n${baseWarning}`
|
|
4472
|
+
};
|
|
4473
|
+
});
|
|
4474
|
+
});
|
|
4475
|
+
return;
|
|
4476
|
+
}
|
|
4477
|
+
setBulkPreview({ action, payload, actionLabel: summaryAction, sessions, warning: baseWarning });
|
|
4171
4478
|
return;
|
|
4172
4479
|
}
|
|
4173
4480
|
void executeBulk({ action, payload, actionLabel: resolvedLabel, ids, sessions });
|
|
@@ -4460,28 +4767,56 @@ function isTopmostDialog(z) {
|
|
|
4460
4767
|
: h("div", { className: "sm-list" }, rows.map((s, i) => renderRow(s, i)));
|
|
4461
4768
|
|
|
4462
4769
|
const allWorkspaceRows = useMemo(() => {
|
|
4463
|
-
const
|
|
4770
|
+
const hasSessionList = Array.isArray(list?.ids);
|
|
4771
|
+
const sessionsByWorkspace = new Map();
|
|
4772
|
+
for (const ws of workspaces) {
|
|
4773
|
+
sessionsByWorkspace.set(ws.id, []);
|
|
4774
|
+
}
|
|
4775
|
+
if (hasSessionList) {
|
|
4776
|
+
for (const s of allRows) {
|
|
4777
|
+
const matchedWsIds = rowWorkspaces(s, workspaceIndex);
|
|
4778
|
+
for (const wsId of matchedWsIds) {
|
|
4779
|
+
const wsList = sessionsByWorkspace.get(wsId);
|
|
4780
|
+
if (wsList) wsList.push(s);
|
|
4781
|
+
}
|
|
4782
|
+
}
|
|
4783
|
+
}
|
|
4464
4784
|
return workspaces.map(ws => {
|
|
4465
|
-
const
|
|
4785
|
+
const wsSessions = sessionsByWorkspace.get(ws.id) || [];
|
|
4786
|
+
let sessionCount = 0;
|
|
4466
4787
|
let latestSessionTime = null;
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4788
|
+
if (hasSessionList) {
|
|
4789
|
+
sessionCount = wsSessions.length;
|
|
4790
|
+
for (const s of wsSessions) {
|
|
4791
|
+
const st = sessionTime(s?.updatedAt) ?? sessionTime(s?.createdAt);
|
|
4792
|
+
if (st !== null) {
|
|
4793
|
+
if (latestSessionTime === null || st > latestSessionTime) {
|
|
4794
|
+
latestSessionTime = st;
|
|
4795
|
+
}
|
|
4796
|
+
}
|
|
4797
|
+
}
|
|
4798
|
+
} else {
|
|
4799
|
+
const sids = Array.isArray(ws.sessionIds) ? ws.sessionIds : [];
|
|
4800
|
+
const byId = list?.byId || {};
|
|
4801
|
+
for (const sid of sids) {
|
|
4802
|
+
const s = byId[sid];
|
|
4803
|
+
if (s && (s.origin === "subagent" || (s.blank && s.id !== list?.current))) continue;
|
|
4804
|
+
sessionCount++;
|
|
4805
|
+
const st = sessionTime(s?.updatedAt) ?? sessionTime(s?.createdAt);
|
|
4806
|
+
if (st !== null) {
|
|
4807
|
+
if (latestSessionTime === null || st > latestSessionTime) {
|
|
4808
|
+
latestSessionTime = st;
|
|
4809
|
+
}
|
|
4474
4810
|
}
|
|
4475
4811
|
}
|
|
4476
4812
|
}
|
|
4477
|
-
const wsSelfTime = sessionTime(ws.updatedAt) ?? sessionTime(ws.createdAt);
|
|
4478
|
-
const resolvedTime = latestSessionTime !== null ? latestSessionTime : wsSelfTime;
|
|
4479
4813
|
return {
|
|
4480
4814
|
...ws,
|
|
4481
|
-
|
|
4815
|
+
sessionCount,
|
|
4816
|
+
latestUpdatedAt: latestSessionTime
|
|
4482
4817
|
};
|
|
4483
4818
|
});
|
|
4484
|
-
}, [workspaces, list?.
|
|
4819
|
+
}, [workspaces, allRows, workspaceIndex, list?.ids, list?.byId, list?.current]);
|
|
4485
4820
|
|
|
4486
4821
|
const filteredWorkspaceRows = useMemo(() => {
|
|
4487
4822
|
const needle = wsQuery.trim().toLowerCase();
|
|
@@ -4632,7 +4967,7 @@ function isTopmostDialog(z) {
|
|
|
4632
4967
|
const isBusy = workspaceArchiveStore.isBusy(ws.id);
|
|
4633
4968
|
const title = ws.title || ws.name || ws.id;
|
|
4634
4969
|
const path = ws.path || "";
|
|
4635
|
-
const sessionCount = Array.isArray(ws.sessionIds) ? ws.sessionIds.length : 0;
|
|
4970
|
+
const sessionCount = typeof ws.sessionCount === "number" ? ws.sessionCount : (Array.isArray(ws.sessionIds) ? ws.sessionIds.length : 0);
|
|
4636
4971
|
const timeFormatted = ws.latestUpdatedAt !== null
|
|
4637
4972
|
? t("workspace.lastUpdated", { time: formatRelative(ws.latestUpdatedAt, now) })
|
|
4638
4973
|
: "—";
|
|
@@ -4689,13 +5024,12 @@ function isTopmostDialog(z) {
|
|
|
4689
5024
|
},
|
|
4690
5025
|
h("div", { className: "sm-rowCheckboxSlot" + ((wsSelectedIds.size > 0 || wsSelectModeEnabled) ? " sm-rowCheckboxSlot-visible" : "") }, checkbox),
|
|
4691
5026
|
h("div", { className: "sm-rowMain" },
|
|
4692
|
-
h("div", { className: "sm-rowTitle" },
|
|
5027
|
+
h("div", { className: "sm-rowTitle", title: path || title },
|
|
4693
5028
|
h("span", null, title),
|
|
4694
5029
|
isArchived ? h("span", { className: "sm-badge sm-badgeArchived" }, t("workspace.badge.archived")) : null
|
|
4695
5030
|
),
|
|
4696
5031
|
h("div", { className: "sm-rowSecondary" },
|
|
4697
5032
|
h("div", { className: "sm-rowMeta" },
|
|
4698
|
-
(path ? (shortPath(path) + " · ") : "") +
|
|
4699
5033
|
t("workspace.sessions", { count: sessionCount }) +
|
|
4700
5034
|
" · " +
|
|
4701
5035
|
timeFormatted
|
|
@@ -4726,8 +5060,23 @@ function isTopmostDialog(z) {
|
|
|
4726
5060
|
// without re-subscribing on every render. The panel listener
|
|
4727
5061
|
// returns early when any inner dialog is open so the child
|
|
4728
5062
|
// dialog's own window listener gets the first shot at Esc.
|
|
5063
|
+
const panelRef = useRef(null);
|
|
4729
5064
|
const escStateRef = useRef({});
|
|
4730
|
-
escStateRef.current = {
|
|
5065
|
+
escStateRef.current = {
|
|
5066
|
+
busyId,
|
|
5067
|
+
confirmFor,
|
|
5068
|
+
moveFor,
|
|
5069
|
+
migrateFor,
|
|
5070
|
+
annotationFor,
|
|
5071
|
+
bulkPreview,
|
|
5072
|
+
bulkProgress,
|
|
5073
|
+
bulkResult,
|
|
5074
|
+
bulkBusy,
|
|
5075
|
+
bulkTagDraft,
|
|
5076
|
+
bulkPresetDraft,
|
|
5077
|
+
wsBulkBusy,
|
|
5078
|
+
onPanelClose
|
|
5079
|
+
};
|
|
4731
5080
|
useEffect(() => {
|
|
4732
5081
|
if (!open) return;
|
|
4733
5082
|
const handler = (e) => {
|
|
@@ -4735,8 +5084,10 @@ function isTopmostDialog(z) {
|
|
|
4735
5084
|
if (e.defaultPrevented) return;
|
|
4736
5085
|
if (e.isComposing || e.keyCode === 229) return;
|
|
4737
5086
|
const s = escStateRef.current;
|
|
4738
|
-
if (s.busyId !== null || s.wsBulkBusy) return;
|
|
4739
|
-
if (s.confirmFor || s.moveFor || s.migrateFor || s.annotationFor ||
|
|
5087
|
+
if (s.busyId !== null || s.wsBulkBusy || s.bulkBusy) return;
|
|
5088
|
+
if (s.confirmFor || s.moveFor || s.migrateFor || s.annotationFor || s.bulkPreview || s.bulkProgress || s.bulkResult || s.bulkTagDraft || s.bulkPresetDraft) return;
|
|
5089
|
+
if (typeof updateStore !== "undefined" && updateStore && typeof updateStore.getSnapshot === "function" && updateStore.getSnapshot()?.dialogOpen) return;
|
|
5090
|
+
if (activeDialogZStack && activeDialogZStack.length > 0) return;
|
|
4740
5091
|
e.preventDefault();
|
|
4741
5092
|
e.stopPropagation();
|
|
4742
5093
|
s.onPanelClose();
|
|
@@ -4750,7 +5101,28 @@ function isTopmostDialog(z) {
|
|
|
4750
5101
|
if (ae && typeof ae.blur === "function" && ae !== document.body) ae.blur();
|
|
4751
5102
|
};
|
|
4752
5103
|
window.addEventListener("keydown", handler);
|
|
4753
|
-
|
|
5104
|
+
const mountTime = Date.now();
|
|
5105
|
+
const clickHandler = (e) => {
|
|
5106
|
+
if (Date.now() - mountTime < 50) return;
|
|
5107
|
+
if (e.defaultPrevented) return;
|
|
5108
|
+
const s = escStateRef.current;
|
|
5109
|
+
if (s.busyId !== null || s.wsBulkBusy || s.bulkBusy) return;
|
|
5110
|
+
if (s.annotationFor !== null) return;
|
|
5111
|
+
if (s.confirmFor || s.moveFor || s.migrateFor) return;
|
|
5112
|
+
if (s.bulkPreview || s.bulkProgress || s.bulkResult || s.bulkTagDraft || s.bulkPresetDraft) return;
|
|
5113
|
+
if (typeof updateStore !== "undefined" && updateStore && typeof updateStore.getSnapshot === "function" && updateStore.getSnapshot()?.dialogOpen) return;
|
|
5114
|
+
if (activeDialogZStack && activeDialogZStack.length > 0) return;
|
|
5115
|
+
if (panelRef.current && typeof panelRef.current.contains === "function" && panelRef.current.contains(e.target)) return;
|
|
5116
|
+
if (e.target && typeof e.target.closest === "function") {
|
|
5117
|
+
if (e.target.closest(".sm-nativeDialog, .sm-panelDialog, .sm-bulkDialog, .sm-annotationDialog, .sm-annotationSurface, .sm-tooltip, .sm-footerBtn")) return;
|
|
5118
|
+
}
|
|
5119
|
+
s.onPanelClose();
|
|
5120
|
+
};
|
|
5121
|
+
window.addEventListener("click", clickHandler);
|
|
5122
|
+
return () => {
|
|
5123
|
+
window.removeEventListener("keydown", handler);
|
|
5124
|
+
window.removeEventListener("click", clickHandler);
|
|
5125
|
+
};
|
|
4754
5126
|
}, [open]);
|
|
4755
5127
|
// The panel is a document-level floating window, so it is portaled into
|
|
4756
5128
|
// the plugin's overlay root like every other dialog here (issue #28).
|
|
@@ -4773,6 +5145,7 @@ function isTopmostDialog(z) {
|
|
|
4773
5145
|
role: "presentation"
|
|
4774
5146
|
},
|
|
4775
5147
|
h("section", {
|
|
5148
|
+
ref: panelRef,
|
|
4776
5149
|
className: "sm-nativeDialog sm-panelDialog",
|
|
4777
5150
|
role: "dialog",
|
|
4778
5151
|
"aria-modal": "true",
|
|
@@ -5076,13 +5449,27 @@ function isTopmostDialog(z) {
|
|
|
5076
5449
|
onClose: () => { if (busyId === null) setConfirmFor(null); },
|
|
5077
5450
|
title: t("confirm.delete.title"),
|
|
5078
5451
|
description: (confirmFor.displayTitle && t("confirm.delete.desc", { title: confirmFor.displayTitle })) || "",
|
|
5079
|
-
warning:
|
|
5452
|
+
warning: (() => {
|
|
5453
|
+
const baseWarning = (confirmFor.running ? (t("confirm.delete.running") + " " + t("bulk.dialog.warning.delete")) : t("bulk.dialog.warning.delete"));
|
|
5454
|
+
if (confirmPreviewState.loading) {
|
|
5455
|
+
const loadingMsg = t("confirm.delete.previewLoading") || "正在检查关联的子智能体会话…";
|
|
5456
|
+
return `${loadingMsg}\n${baseWarning}`;
|
|
5457
|
+
}
|
|
5458
|
+
if (confirmPreviewState.error) {
|
|
5459
|
+
const errorMsg = confirmPreviewState.error;
|
|
5460
|
+
return `${errorMsg}\n${baseWarning}`;
|
|
5461
|
+
}
|
|
5462
|
+
const subagentWarning = confirmPreviewState.subagentCount > 0 ? t("confirm.delete.subagents", { count: confirmPreviewState.subagentCount }) : "";
|
|
5463
|
+
return subagentWarning ? `${subagentWarning}\n${baseWarning}` : baseWarning;
|
|
5464
|
+
})(),
|
|
5465
|
+
confirmDisabled: confirmPreviewState.loading || Boolean(confirmPreviewState.error),
|
|
5080
5466
|
confirmLabel: t("confirm.delete.confirm"),
|
|
5081
5467
|
cancelLabel: t("confirm.cancel"),
|
|
5082
5468
|
busy: busyId !== null,
|
|
5083
5469
|
danger: true,
|
|
5084
5470
|
onCancel: () => { if (busyId === null) setConfirmFor(null); },
|
|
5085
5471
|
onConfirm: () => {
|
|
5472
|
+
if (confirmPreviewState.loading || confirmPreviewState.error) return;
|
|
5086
5473
|
const target = confirmFor;
|
|
5087
5474
|
setConfirmFor(null);
|
|
5088
5475
|
runRow(target.id, () => onRemove(target.id));
|
|
@@ -5168,12 +5555,16 @@ function isTopmostDialog(z) {
|
|
|
5168
5555
|
delete: t("bulk.confirm.delete")
|
|
5169
5556
|
})[action] || t("bulk.dialog.execute");
|
|
5170
5557
|
const bulkPreviewDialog = bulkPreview ? h(BatchPreviewDialog, {
|
|
5171
|
-
open: true, t, actionLabel: bulkPreview.actionLabel,
|
|
5558
|
+
open: true, t, action: bulkPreview.action, actionLabel: bulkPreview.actionLabel,
|
|
5559
|
+
title: bulkPreview.action === "delete" ? t("confirm.delete.title") : undefined,
|
|
5172
5560
|
sessions: bulkPreview.sessions, warning: bulkPreview.warning,
|
|
5173
5561
|
confirmLabel: bulkConfirmLabelFor(bulkPreview.action),
|
|
5174
5562
|
danger: bulkPreview.action === "delete",
|
|
5563
|
+
loading: bulkPreview.loading === true,
|
|
5564
|
+
error: bulkPreview.error || null,
|
|
5175
5565
|
onCancel: () => setBulkPreview(null),
|
|
5176
5566
|
onExecute: () => {
|
|
5567
|
+
if (bulkPreview.loading || bulkPreview.error) return;
|
|
5177
5568
|
const preview = bulkPreview;
|
|
5178
5569
|
setBulkPreview(null);
|
|
5179
5570
|
void executeBulk({
|
|
@@ -5279,6 +5670,29 @@ function isTopmostDialog(z) {
|
|
|
5279
5670
|
|
|
5280
5671
|
const [confirmFor, setConfirmFor] = useState(null);
|
|
5281
5672
|
const [confirmAnchor, setConfirmAnchor] = useState(null);
|
|
5673
|
+
const [confirmPreviewState, setConfirmPreviewState] = useState({ loading: false, error: null, subagentCount: 0 });
|
|
5674
|
+
useEffect(() => {
|
|
5675
|
+
if (!confirmFor || !confirmFor.id) {
|
|
5676
|
+
setConfirmPreviewState({ loading: false, error: null, subagentCount: 0 });
|
|
5677
|
+
return;
|
|
5678
|
+
}
|
|
5679
|
+
let alive = true;
|
|
5680
|
+
setConfirmPreviewState({ loading: true, error: null, subagentCount: 0 });
|
|
5681
|
+
fetchApi("/delete-preview?sessionId=" + encodeURIComponent(confirmFor.id))
|
|
5682
|
+
.then((res) => {
|
|
5683
|
+
if (!alive) return;
|
|
5684
|
+
if (res && res.ok && res.result && typeof res.result.subagentCount === "number") {
|
|
5685
|
+
setConfirmPreviewState({ loading: false, error: null, subagentCount: res.result.subagentCount });
|
|
5686
|
+
} else {
|
|
5687
|
+
setConfirmPreviewState({ loading: false, error: res?.error || (t ? t("confirm.delete.previewError") : "检查关联子智能体会话失败,请稍后重试"), subagentCount: 0 });
|
|
5688
|
+
}
|
|
5689
|
+
})
|
|
5690
|
+
.catch((err) => {
|
|
5691
|
+
if (!alive) return;
|
|
5692
|
+
setConfirmPreviewState({ loading: false, error: (err && err.message) || (t ? t("confirm.delete.previewError") : "检查关联子智能体会话失败,请稍后重试"), subagentCount: 0 });
|
|
5693
|
+
});
|
|
5694
|
+
return () => { alive = false; };
|
|
5695
|
+
}, [confirmFor?.id]);
|
|
5282
5696
|
const [moveFor, setMoveFor] = useState(null);
|
|
5283
5697
|
const [moveAnchor, setMoveAnchor] = useState(null);
|
|
5284
5698
|
const [workspaces, setWorkspaces] = useState([]);
|
|
@@ -5608,13 +6022,30 @@ function isTopmostDialog(z) {
|
|
|
5608
6022
|
onClose: () => setConfirmFor(null),
|
|
5609
6023
|
onCancel: () => setConfirmFor(null),
|
|
5610
6024
|
onConfirm: () => {
|
|
6025
|
+
if (confirmPreviewState.loading || confirmPreviewState.error) return;
|
|
5611
6026
|
const target = confirmFor;
|
|
5612
6027
|
setConfirmFor(null);
|
|
5613
6028
|
runWithAlert("delete", () => onRemove(target.id));
|
|
5614
6029
|
},
|
|
5615
6030
|
title: t ? t("confirm.delete.title") : "删除会话",
|
|
5616
6031
|
description: (confirmFor && confirmFor.displayTitle && (t ? t("confirm.delete.desc", { title: confirmFor.displayTitle }) : ("「" + confirmFor.displayTitle + "」:删除,不可恢复"))) || "",
|
|
5617
|
-
warning: (
|
|
6032
|
+
warning: (() => {
|
|
6033
|
+
const baseWarn = (confirmFor && confirmFor.running && t ? t("confirm.delete.running") + " " : "") +
|
|
6034
|
+
(t ? t("bulk.dialog.warning.delete") : "删除操作不可撤销,请确认后再继续。");
|
|
6035
|
+
if (confirmPreviewState.loading) {
|
|
6036
|
+
const loadingMsg = (t ? t("confirm.delete.previewLoading") : "") || "正在检查关联的子智能体会话…";
|
|
6037
|
+
return `${loadingMsg}\n${baseWarn}`;
|
|
6038
|
+
}
|
|
6039
|
+
if (confirmPreviewState.error) {
|
|
6040
|
+
const errorMsg = confirmPreviewState.error;
|
|
6041
|
+
return `${errorMsg}\n${baseWarn}`;
|
|
6042
|
+
}
|
|
6043
|
+
const subagentsWarn = confirmPreviewState.subagentCount > 0
|
|
6044
|
+
? (t ? t("confirm.delete.subagents", { count: confirmPreviewState.subagentCount }) : `将连带删除 ${confirmPreviewState.subagentCount} 个关联的子智能体会话。`)
|
|
6045
|
+
: "";
|
|
6046
|
+
return subagentsWarn ? `${subagentsWarn}\n${baseWarn}` : baseWarn;
|
|
6047
|
+
})(),
|
|
6048
|
+
confirmDisabled: confirmPreviewState.loading || Boolean(confirmPreviewState.error),
|
|
5618
6049
|
confirmLabel: t ? t("confirm.delete.confirm") : "确认删除",
|
|
5619
6050
|
cancelLabel: t ? t("confirm.cancel") : "取消",
|
|
5620
6051
|
busy: false,
|
|
@@ -6011,18 +6442,6 @@ function isTopmostDialog(z) {
|
|
|
6011
6442
|
),
|
|
6012
6443
|
h("div", { className: "sm-settingsSection" },
|
|
6013
6444
|
h("div", { className: "sm-settingsSectionTitle" }, t("settings.prefSection")),
|
|
6014
|
-
h("div", { className: "sm-settingsRow" },
|
|
6015
|
-
h("span", null, t("settings.registry")),
|
|
6016
|
-
h("select", {
|
|
6017
|
-
className: "sm-settingsSelect sm-viewSelect",
|
|
6018
|
-
value: currentRegistry,
|
|
6019
|
-
onChange: onRegistryChange,
|
|
6020
|
-
"aria-label": t("settings.registry")
|
|
6021
|
-
},
|
|
6022
|
-
h("option", { value: "registry.npmjs.org" }, t("settings.registry.npm")),
|
|
6023
|
-
h("option", { value: "registry.npmmirror.com" }, t("settings.registry.china"))
|
|
6024
|
-
)
|
|
6025
|
-
),
|
|
6026
6445
|
h("div", { className: "sm-settingsRow" },
|
|
6027
6446
|
h("span", null, t("update.autoCheck")),
|
|
6028
6447
|
h("label", { className: "sm-settingsCheckbox" },
|
|
@@ -6036,7 +6455,22 @@ function isTopmostDialog(z) {
|
|
|
6036
6455
|
)
|
|
6037
6456
|
),
|
|
6038
6457
|
h("div", { className: "sm-settingsRow" },
|
|
6039
|
-
h("span", null, t("settings.
|
|
6458
|
+
h("span", null, t("settings.registry")),
|
|
6459
|
+
h("select", {
|
|
6460
|
+
className: "sm-settingsSelect",
|
|
6461
|
+
value: currentRegistry,
|
|
6462
|
+
onChange: onRegistryChange,
|
|
6463
|
+
"aria-label": t("settings.registry")
|
|
6464
|
+
},
|
|
6465
|
+
h("option", { value: "registry.npmjs.org" }, t("settings.registry.npm")),
|
|
6466
|
+
h("option", { value: "registry.npmmirror.com" }, t("settings.registry.china"))
|
|
6467
|
+
)
|
|
6468
|
+
),
|
|
6469
|
+
h("div", { className: "sm-settingsRow" },
|
|
6470
|
+
h("div", { className: "sm-settingsRowLeft" },
|
|
6471
|
+
h("span", null, t("settings.dialogOpacity")),
|
|
6472
|
+
h("span", { className: "sm-settingsHint sm-settingsHintInline" }, t("settings.dialogOpacity.hint"))
|
|
6473
|
+
),
|
|
6040
6474
|
h("div", { className: "sm-settingsSlider" },
|
|
6041
6475
|
h("input", {
|
|
6042
6476
|
type: "range",
|
|
@@ -6060,39 +6494,42 @@ function isTopmostDialog(z) {
|
|
|
6060
6494
|
onClick: () => updateStore.resetDialogOpacity()
|
|
6061
6495
|
}, t("settings.dialogOpacity.reset"))
|
|
6062
6496
|
)
|
|
6063
|
-
)
|
|
6064
|
-
h("div", { className: "sm-settingsHint" }, t("settings.dialogOpacity.hint"))
|
|
6497
|
+
)
|
|
6065
6498
|
),
|
|
6066
6499
|
h("div", { className: "sm-settingsSection" },
|
|
6067
6500
|
h("div", { className: "sm-settingsSectionTitle" }, t("settings.projectSection")),
|
|
6068
|
-
h("div", { className: "sm-settingsRow
|
|
6069
|
-
h("
|
|
6070
|
-
|
|
6071
|
-
|
|
6072
|
-
|
|
6073
|
-
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
|
|
6077
|
-
|
|
6078
|
-
|
|
6079
|
-
|
|
6080
|
-
|
|
6081
|
-
|
|
6082
|
-
|
|
6083
|
-
|
|
6084
|
-
|
|
6085
|
-
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
6501
|
+
h("div", { className: "sm-settingsRow" },
|
|
6502
|
+
h("div", { className: "sm-settingsProjectLeft" },
|
|
6503
|
+
h("span", { className: "sm-settingsProjectLabel" }, t("settings.github")),
|
|
6504
|
+
h("a", {
|
|
6505
|
+
href: "https://github.com/hkkz9522/dsh-session-manager",
|
|
6506
|
+
target: "_blank",
|
|
6507
|
+
rel: "noopener noreferrer",
|
|
6508
|
+
className: "sm-settingsLink"
|
|
6509
|
+
}, "hkkz9522/dsh-session-manager")
|
|
6510
|
+
),
|
|
6511
|
+
h("div", { className: "sm-settingsBadgeActions" },
|
|
6512
|
+
renderTip(t("settings.star.tip"), h("a", {
|
|
6513
|
+
href: "https://github.com/hkkz9522/dsh-session-manager",
|
|
6514
|
+
target: "_blank",
|
|
6515
|
+
rel: "noopener noreferrer",
|
|
6516
|
+
className: "sm-settingsBadgeLink",
|
|
6517
|
+
"aria-label": t("settings.star.tip")
|
|
6518
|
+
},
|
|
6519
|
+
h(StarIcon, { size: 14 }),
|
|
6520
|
+
h("span", null, t("settings.star"))
|
|
6521
|
+
)),
|
|
6522
|
+
renderTip(t("settings.feedback.tip"), h("a", {
|
|
6523
|
+
href: "https://github.com/hkkz9522/dsh-session-manager/issues",
|
|
6524
|
+
target: "_blank",
|
|
6525
|
+
rel: "noopener noreferrer",
|
|
6526
|
+
className: "sm-settingsBadgeLink",
|
|
6527
|
+
"aria-label": t("settings.feedback.tip")
|
|
6528
|
+
},
|
|
6529
|
+
h(IssueIcon, { size: 14 }),
|
|
6530
|
+
h("span", null, t("settings.feedback"))
|
|
6531
|
+
))
|
|
6532
|
+
)
|
|
6096
6533
|
)
|
|
6097
6534
|
)
|
|
6098
6535
|
);
|
|
@@ -6186,7 +6623,18 @@ function isTopmostDialog(z) {
|
|
|
6186
6623
|
onRemove: async (sessionId) => {
|
|
6187
6624
|
const wasCurrent = isCurrentSession(sessionId);
|
|
6188
6625
|
const response = await callApi("/delete", { sessionId });
|
|
6189
|
-
if (!response.ok)
|
|
6626
|
+
if (!response.ok) {
|
|
6627
|
+
if (Array.isArray(response.deletedSubagents) && response.deletedSubagents.length > 0) {
|
|
6628
|
+
try { await annotationStore.load(true); } catch (_) {}
|
|
6629
|
+
try { await ctx.sessions?.refresh?.(); } catch (_) {}
|
|
6630
|
+
try { await ctx.workspaces?.refresh?.(); } catch (_) {}
|
|
6631
|
+
}
|
|
6632
|
+
const err = new Error(response.error || "delete failed");
|
|
6633
|
+
err.deletedSubagents = response.deletedSubagents || [];
|
|
6634
|
+
err.remainingSessions = response.remainingSessions || [sessionId];
|
|
6635
|
+
err.partialFailure = Boolean(response.partialFailure);
|
|
6636
|
+
throw err;
|
|
6637
|
+
}
|
|
6190
6638
|
await annotationStore.load(true);
|
|
6191
6639
|
if (response.result?.warning) window.alert(response.result.warning);
|
|
6192
6640
|
if (wasCurrent || isCurrentSession(sessionId)) {
|
|
@@ -6320,7 +6768,7 @@ function isTopmostDialog(z) {
|
|
|
6320
6768
|
ctx.effect(() => {
|
|
6321
6769
|
if (!updateStore.getAutoCheck()) return;
|
|
6322
6770
|
const timer = setTimeout(() => {
|
|
6323
|
-
updateStore.
|
|
6771
|
+
updateStore.maybeAutoCheck({ isStartup: true }).catch(() => {});
|
|
6324
6772
|
}, 1500);
|
|
6325
6773
|
return () => {
|
|
6326
6774
|
try {
|
|
@@ -6381,8 +6829,18 @@ function isTopmostDialog(z) {
|
|
|
6381
6829
|
exports.apply = apply;
|
|
6382
6830
|
exports.inject = inject;
|
|
6383
6831
|
exports.updateStore = updateStore;
|
|
6832
|
+
exports.panelStore = panelStore;
|
|
6384
6833
|
exports.compareSemver = compareSemver;
|
|
6834
|
+
exports.OverlayLayer = OverlayLayer;
|
|
6385
6835
|
exports.UpdateDialog = UpdateDialog;
|
|
6836
|
+
exports.ConfirmDialog = ConfirmDialog;
|
|
6837
|
+
exports.MoveDialog = MoveDialog;
|
|
6838
|
+
exports.MigratePresetDialog = MigratePresetDialog;
|
|
6839
|
+
exports.BatchPreviewDialog = BatchPreviewDialog;
|
|
6840
|
+
exports.BatchResultDialog = BatchResultDialog;
|
|
6841
|
+
exports.BulkTagInputDialog = BulkTagInputDialog;
|
|
6842
|
+
exports.BulkChoiceDialog = BulkChoiceDialog;
|
|
6843
|
+
exports.AnnotationDialog = AnnotationDialog;
|
|
6386
6844
|
exports.SessionManagerSettingsCard = SessionManagerSettingsCard;
|
|
6387
6845
|
exports.WhaleIcon = WhaleIcon;
|
|
6388
6846
|
exports.NpmIcon = NpmIcon;
|
|
@@ -6396,6 +6854,7 @@ function isTopmostDialog(z) {
|
|
|
6396
6854
|
exports.openCustomSelect = openCustomSelect;
|
|
6397
6855
|
exports.closeCustomSelect = closeCustomSelect;
|
|
6398
6856
|
exports.installCustomDropdownInterceptor = installCustomDropdownInterceptor;
|
|
6857
|
+
exports.getTargetSmSelect = getTargetSmSelect;
|
|
6399
6858
|
exports.SM_SELECT_SELECTOR = SM_SELECT_SELECTOR;
|
|
6400
6859
|
return module.exports;
|
|
6401
6860
|
}
|