dsh-session-manager 0.7.0 → 0.7.1
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 +11 -0
- package/README.md +1 -1
- package/README.zh.md +1 -1
- package/lib/client.js +563 -103
- package/lib/index.js +675 -190
- 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}",
|
|
@@ -1131,6 +1137,10 @@ function isTopmostDialog(z) {
|
|
|
1131
1137
|
if (zRef.current === null) {
|
|
1132
1138
|
zRef.current = nextDialogZ();
|
|
1133
1139
|
}
|
|
1140
|
+
useEffect(() => {
|
|
1141
|
+
registerDialogZ(zRef.current);
|
|
1142
|
+
return () => unregisterDialogZ(zRef.current);
|
|
1143
|
+
}, []);
|
|
1134
1144
|
const root = getOverlayRoot();
|
|
1135
1145
|
const portal = getPortalFn();
|
|
1136
1146
|
|
|
@@ -1158,6 +1168,8 @@ function isTopmostDialog(z) {
|
|
|
1158
1168
|
zIndex: -1
|
|
1159
1169
|
},
|
|
1160
1170
|
onClick: (e) => {
|
|
1171
|
+
if (e && typeof e.stopPropagation === "function") e.stopPropagation();
|
|
1172
|
+
if (e && typeof e.stopImmediatePropagation === "function") e.stopImmediatePropagation();
|
|
1161
1173
|
if (e.target === e.currentTarget && onBackdropClick) {
|
|
1162
1174
|
onBackdropClick(e);
|
|
1163
1175
|
}
|
|
@@ -2591,18 +2603,51 @@ function isTopmostDialog(z) {
|
|
|
2591
2603
|
].join(String.fromCharCode(10))
|
|
2592
2604
|
};
|
|
2593
2605
|
const promptFor = lang => CLIPBOARD_PROMPT_TEXT[lang] || CLIPBOARD_PROMPT_TEXT.zh;
|
|
2606
|
+
function isClickInsideDialog(e, dialogRef, layerRef) {
|
|
2607
|
+
if (!e || !e.target) return false;
|
|
2608
|
+
const target = e.target;
|
|
2609
|
+
if (dialogRef && dialogRef.current && typeof dialogRef.current.contains === "function" && dialogRef.current.contains(target)) {
|
|
2610
|
+
return true;
|
|
2611
|
+
}
|
|
2612
|
+
if (layerRef && layerRef.current && typeof layerRef.current.contains === "function" && layerRef.current.contains(target)) {
|
|
2613
|
+
return true;
|
|
2614
|
+
}
|
|
2615
|
+
if (typeof target.closest === "function") {
|
|
2616
|
+
if (dialogRef && dialogRef.current && target.closest(".sm-nativeDialog") === dialogRef.current) {
|
|
2617
|
+
return true;
|
|
2618
|
+
}
|
|
2619
|
+
if (layerRef && layerRef.current && target.closest(".sm-nativeDialogLayer") === layerRef.current) {
|
|
2620
|
+
return true;
|
|
2621
|
+
}
|
|
2622
|
+
}
|
|
2623
|
+
if (activeCustomMenu && typeof activeCustomMenu.contains === "function" && activeCustomMenu.contains(target)) {
|
|
2624
|
+
if (activeCustomSelect) {
|
|
2625
|
+
if (dialogRef && dialogRef.current && typeof dialogRef.current.contains === "function" && dialogRef.current.contains(activeCustomSelect)) {
|
|
2626
|
+
return true;
|
|
2627
|
+
}
|
|
2628
|
+
if (layerRef && layerRef.current && typeof layerRef.current.contains === "function" && layerRef.current.contains(activeCustomSelect)) {
|
|
2629
|
+
return true;
|
|
2630
|
+
}
|
|
2631
|
+
}
|
|
2632
|
+
}
|
|
2633
|
+
return false;
|
|
2634
|
+
}
|
|
2635
|
+
|
|
2594
2636
|
function BatchPreviewDialog(props) {
|
|
2595
2637
|
const t = typeof props.t === "function" ? props.t : (key) => key;
|
|
2596
2638
|
const open = props.open === true;
|
|
2597
2639
|
const onCancel = typeof props.onCancel === "function" ? props.onCancel : () => {};
|
|
2598
2640
|
const onExecute = typeof props.onExecute === "function" ? props.onExecute : () => {};
|
|
2641
|
+
const danger = props.danger === true;
|
|
2599
2642
|
const actionLabel = props.actionLabel || "";
|
|
2600
2643
|
const summaryAction = props.summaryAction || actionLabel;
|
|
2644
|
+
const title = props.title || (props.action === "delete" ? (props.t ? t("confirm.delete.title") : "删除会话") : t("bulk.dialog.title", { action: actionLabel }));
|
|
2601
2645
|
const sessions = Array.isArray(props.sessions) ? props.sessions : [];
|
|
2602
2646
|
const warning = typeof props.warning === "string" ? props.warning : "";
|
|
2603
2647
|
const confirmLabel = props.confirmLabel || t("bulk.dialog.execute");
|
|
2604
2648
|
const cancelLabel = props.cancelLabel || t("bulk.dialog.cancel");
|
|
2605
|
-
const
|
|
2649
|
+
const dialogRef = useRef(null);
|
|
2650
|
+
const layerRef = useRef(null);
|
|
2606
2651
|
const [expanded, setExpanded] = useState(false);
|
|
2607
2652
|
const [zIndex] = useState(() => open ? nextDialogZ() : 0);
|
|
2608
2653
|
const floatingCoords = useFloatingPosition(props.anchor, open, { placement: "bottom-end", dialogWidth: 360, dialogHeight: 320 });
|
|
@@ -2614,15 +2659,33 @@ function isTopmostDialog(z) {
|
|
|
2614
2659
|
const handler = (e) => {
|
|
2615
2660
|
if (e.key !== "Escape" || e.defaultPrevented) return;
|
|
2616
2661
|
if (!isTopmostDialog(zIndex)) return;
|
|
2662
|
+
if (props.busy) return;
|
|
2617
2663
|
e.preventDefault(); e.stopPropagation(); escStateRef.current.onCancel();
|
|
2618
2664
|
};
|
|
2619
2665
|
window.addEventListener("keydown", handler);
|
|
2666
|
+
const mountTime = Date.now();
|
|
2667
|
+
const clickHandler = (e) => {
|
|
2668
|
+
if (Date.now() - mountTime < 50) return;
|
|
2669
|
+
if (e.defaultPrevented) return;
|
|
2670
|
+
if (props.busy) return;
|
|
2671
|
+
if (!isTopmostDialog(zIndex)) return;
|
|
2672
|
+
if (isClickInsideDialog(e, dialogRef, layerRef)) return;
|
|
2673
|
+
if (e && typeof e.preventDefault === "function") e.preventDefault();
|
|
2674
|
+
if (e && typeof e.stopPropagation === "function") e.stopPropagation();
|
|
2675
|
+
if (e && typeof e.stopImmediatePropagation === "function") e.stopImmediatePropagation();
|
|
2676
|
+
escStateRef.current.onCancel();
|
|
2677
|
+
};
|
|
2678
|
+
window.addEventListener("click", clickHandler, true);
|
|
2620
2679
|
return () => {
|
|
2621
2680
|
unregisterDialogZ(zIndex);
|
|
2622
2681
|
window.removeEventListener("keydown", handler);
|
|
2682
|
+
window.removeEventListener("click", clickHandler, true);
|
|
2623
2683
|
};
|
|
2624
2684
|
}, [open, zIndex]);
|
|
2625
2685
|
if (!open) return null;
|
|
2686
|
+
const loading = props.loading === true;
|
|
2687
|
+
const hasError = Boolean(props.error);
|
|
2688
|
+
const confirmDisabled = loading || hasError;
|
|
2626
2689
|
const showExpand = sessions.length > 12;
|
|
2627
2690
|
const visible = expanded ? sessions : sessions.slice(0, 12);
|
|
2628
2691
|
const topPx = floatingCoords ? floatingCoords.top : null;
|
|
@@ -2644,9 +2707,9 @@ function isTopmostDialog(z) {
|
|
|
2644
2707
|
: {})
|
|
2645
2708
|
};
|
|
2646
2709
|
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" },
|
|
2710
|
+
return portalOverlay(h("div", { ref: layerRef, className: "sm-nativeDialogLayer sm-bulkDialog" + (hasCoords ? " sm-bulkDialog-anchored" : ""), role: "presentation", style: layerStyle },
|
|
2711
|
+
h("section", { ref: dialogRef, className: "sm-nativeDialog", style: { pointerEvents: "auto" }, role: "dialog", "aria-modal": "true", "aria-labelledby": "sm-batch-preview-title" },
|
|
2712
|
+
h("div", { className: "sm-nativeDialogHeader" }, h("h2", { id: "sm-batch-preview-title", className: "sm-nativeDialogTitle" }, title)),
|
|
2650
2713
|
h("div", { className: "sm-nativeDialogBody" },
|
|
2651
2714
|
h("div", { className: "sm-bulkDialogSummary" }, t("bulk.dialog.summary", { count: sessions.length, action: actionLabel })),
|
|
2652
2715
|
warning ? h("div", { className: "sm-bulkDialogWarn" }, warning) : null,
|
|
@@ -2657,7 +2720,12 @@ function isTopmostDialog(z) {
|
|
|
2657
2720
|
),
|
|
2658
2721
|
h("div", { className: "sm-nativeDialogFooter" },
|
|
2659
2722
|
h("button", { type: "button", className: "sm-nativeDialogButton sm-nativeDialogCancel", onClick: onCancel }, cancelLabel),
|
|
2660
|
-
h("button", {
|
|
2723
|
+
h("button", {
|
|
2724
|
+
type: "button",
|
|
2725
|
+
className: "sm-nativeDialogButton" + (danger ? " sm-nativeDialogDanger" : " sm-nativeDialogConfirm"),
|
|
2726
|
+
disabled: props.busy || confirmDisabled,
|
|
2727
|
+
onClick: () => { if (!props.busy && !confirmDisabled) onExecute(); }
|
|
2728
|
+
}, confirmLabel)
|
|
2661
2729
|
)
|
|
2662
2730
|
)
|
|
2663
2731
|
));
|
|
@@ -2667,6 +2735,11 @@ function isTopmostDialog(z) {
|
|
|
2667
2735
|
const t = typeof props.t === "function" ? props.t : (key) => key;
|
|
2668
2736
|
const open = props.open === true;
|
|
2669
2737
|
const [zIndex] = useState(() => open ? nextDialogZ() : 0);
|
|
2738
|
+
useEffect(() => {
|
|
2739
|
+
if (!open) return;
|
|
2740
|
+
registerDialogZ(zIndex);
|
|
2741
|
+
return () => unregisterDialogZ(zIndex);
|
|
2742
|
+
}, [open, zIndex]);
|
|
2670
2743
|
const actionLabel = props.actionLabel || "";
|
|
2671
2744
|
const done = Number.isInteger(props.done) ? props.done : 0;
|
|
2672
2745
|
const total = Number.isInteger(props.total) ? props.total : 0;
|
|
@@ -2714,6 +2787,8 @@ function isTopmostDialog(z) {
|
|
|
2714
2787
|
function BatchResultDialog(props) {
|
|
2715
2788
|
const t = typeof props.t === "function" ? props.t : (key) => key;
|
|
2716
2789
|
const open = props.open === true;
|
|
2790
|
+
const dialogRef = useRef(null);
|
|
2791
|
+
const layerRef = useRef(null);
|
|
2717
2792
|
const [zIndex] = useState(() => open ? nextDialogZ() : 0);
|
|
2718
2793
|
const actionLabel = props.actionLabel || "";
|
|
2719
2794
|
const items = Array.isArray(props.items) ? props.items : [];
|
|
@@ -2733,9 +2808,22 @@ function isTopmostDialog(z) {
|
|
|
2733
2808
|
e.preventDefault(); e.stopPropagation(); escStateRef.current.onClose();
|
|
2734
2809
|
};
|
|
2735
2810
|
window.addEventListener("keydown", handler);
|
|
2811
|
+
const mountTime = Date.now();
|
|
2812
|
+
const clickHandler = (e) => {
|
|
2813
|
+
if (Date.now() - mountTime < 50) return;
|
|
2814
|
+
if (e.defaultPrevented) return;
|
|
2815
|
+
if (!isTopmostDialog(zIndex)) return;
|
|
2816
|
+
if (isClickInsideDialog(e, dialogRef, layerRef)) return;
|
|
2817
|
+
if (e && typeof e.preventDefault === "function") e.preventDefault();
|
|
2818
|
+
if (e && typeof e.stopPropagation === "function") e.stopPropagation();
|
|
2819
|
+
if (e && typeof e.stopImmediatePropagation === "function") e.stopImmediatePropagation();
|
|
2820
|
+
escStateRef.current.onClose();
|
|
2821
|
+
};
|
|
2822
|
+
window.addEventListener("click", clickHandler, true);
|
|
2736
2823
|
return () => {
|
|
2737
2824
|
unregisterDialogZ(zIndex);
|
|
2738
2825
|
window.removeEventListener("keydown", handler);
|
|
2826
|
+
window.removeEventListener("click", clickHandler, true);
|
|
2739
2827
|
};
|
|
2740
2828
|
}, [open, zIndex]);
|
|
2741
2829
|
if (!open) return null;
|
|
@@ -2777,8 +2865,8 @@ function isTopmostDialog(z) {
|
|
|
2777
2865
|
: {})
|
|
2778
2866
|
};
|
|
2779
2867
|
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" },
|
|
2868
|
+
return portalOverlay(h("div", { ref: layerRef, className: "sm-nativeDialogLayer sm-bulkDialog" + (hasCoords ? " sm-bulkDialog-anchored" : ""), role: "presentation", style: layerStyle },
|
|
2869
|
+
h("section", { ref: dialogRef, className: "sm-nativeDialog", style: { pointerEvents: "auto" }, role: "dialog", "aria-modal": "true", "aria-labelledby": "sm-batch-result-title" },
|
|
2782
2870
|
h("div", { className: "sm-nativeDialogHeader" }, h("h2", { id: "sm-batch-result-title", className: "sm-nativeDialogTitle" }, t("bulk.result.title", { action: actionLabel }))),
|
|
2783
2871
|
h("div", { className: "sm-nativeDialogBody" },
|
|
2784
2872
|
renderGroup("bulk.result.successGroup", groups.success),
|
|
@@ -2826,6 +2914,8 @@ function isTopmostDialog(z) {
|
|
|
2826
2914
|
function BulkTagInputDialog(props) {
|
|
2827
2915
|
const t = typeof props.t === "function" ? props.t : (key) => key;
|
|
2828
2916
|
const open = props.open === true;
|
|
2917
|
+
const dialogRef = useRef(null);
|
|
2918
|
+
const layerRef = useRef(null);
|
|
2829
2919
|
const [zIndex] = useState(() => open ? nextDialogZ() : 0);
|
|
2830
2920
|
const title = props.title || t("bulk.tagsAdd");
|
|
2831
2921
|
const description = props.description || "";
|
|
@@ -2847,9 +2937,22 @@ function isTopmostDialog(z) {
|
|
|
2847
2937
|
e.preventDefault(); e.stopPropagation(); escStateRef.current.onCancel();
|
|
2848
2938
|
};
|
|
2849
2939
|
window.addEventListener("keydown", handler);
|
|
2940
|
+
const mountTime = Date.now();
|
|
2941
|
+
const clickHandler = (e) => {
|
|
2942
|
+
if (Date.now() - mountTime < 50) return;
|
|
2943
|
+
if (e.defaultPrevented) return;
|
|
2944
|
+
if (!isTopmostDialog(zIndex)) return;
|
|
2945
|
+
if (isClickInsideDialog(e, dialogRef, layerRef)) return;
|
|
2946
|
+
if (e && typeof e.preventDefault === "function") e.preventDefault();
|
|
2947
|
+
if (e && typeof e.stopPropagation === "function") e.stopPropagation();
|
|
2948
|
+
if (e && typeof e.stopImmediatePropagation === "function") e.stopImmediatePropagation();
|
|
2949
|
+
escStateRef.current.onCancel();
|
|
2950
|
+
};
|
|
2951
|
+
window.addEventListener("click", clickHandler, true);
|
|
2850
2952
|
return () => {
|
|
2851
2953
|
unregisterDialogZ(zIndex);
|
|
2852
2954
|
window.removeEventListener("keydown", handler);
|
|
2955
|
+
window.removeEventListener("click", clickHandler, true);
|
|
2853
2956
|
};
|
|
2854
2957
|
}, [open, zIndex]);
|
|
2855
2958
|
if (!open) return null;
|
|
@@ -2876,8 +2979,8 @@ function isTopmostDialog(z) {
|
|
|
2876
2979
|
: {})
|
|
2877
2980
|
};
|
|
2878
2981
|
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" },
|
|
2982
|
+
return portalOverlay(h("div", { ref: layerRef, className: "sm-nativeDialogLayer sm-bulkDialog" + (hasCoords ? " sm-bulkDialog-anchored" : ""), role: "presentation", style: layerStyle },
|
|
2983
|
+
h("section", { ref: dialogRef, className: "sm-nativeDialog", style: { pointerEvents: "auto" }, role: "dialog", "aria-modal": "true", "aria-labelledby": "sm-bulk-tags-title" },
|
|
2881
2984
|
h("div", { className: "sm-nativeDialogHeader" }, h("h2", { id: "sm-bulk-tags-title", className: "sm-nativeDialogTitle" }, title)),
|
|
2882
2985
|
h("div", { className: "sm-nativeDialogBody" },
|
|
2883
2986
|
description ? h("div", { className: "sm-bulkDialogSummary" }, description) : null,
|
|
@@ -2894,6 +2997,8 @@ function isTopmostDialog(z) {
|
|
|
2894
2997
|
function BulkChoiceDialog(props) {
|
|
2895
2998
|
const t = typeof props.t === "function" ? props.t : (key) => key;
|
|
2896
2999
|
const open = props.open === true;
|
|
3000
|
+
const dialogRef = useRef(null);
|
|
3001
|
+
const layerRef = useRef(null);
|
|
2897
3002
|
const [zIndex] = useState(() => open ? nextDialogZ() : 0);
|
|
2898
3003
|
const title = props.title || "";
|
|
2899
3004
|
const description = props.description || "";
|
|
@@ -2915,9 +3020,22 @@ function isTopmostDialog(z) {
|
|
|
2915
3020
|
e.preventDefault(); e.stopPropagation(); escStateRef.current.onCancel();
|
|
2916
3021
|
};
|
|
2917
3022
|
window.addEventListener("keydown", handler);
|
|
3023
|
+
const mountTime = Date.now();
|
|
3024
|
+
const clickHandler = (e) => {
|
|
3025
|
+
if (Date.now() - mountTime < 50) return;
|
|
3026
|
+
if (e.defaultPrevented) return;
|
|
3027
|
+
if (!isTopmostDialog(zIndex)) return;
|
|
3028
|
+
if (isClickInsideDialog(e, dialogRef, layerRef)) return;
|
|
3029
|
+
if (e && typeof e.preventDefault === "function") e.preventDefault();
|
|
3030
|
+
if (e && typeof e.stopPropagation === "function") e.stopPropagation();
|
|
3031
|
+
if (e && typeof e.stopImmediatePropagation === "function") e.stopImmediatePropagation();
|
|
3032
|
+
escStateRef.current.onCancel();
|
|
3033
|
+
};
|
|
3034
|
+
window.addEventListener("click", clickHandler, true);
|
|
2918
3035
|
return () => {
|
|
2919
3036
|
unregisterDialogZ(zIndex);
|
|
2920
3037
|
window.removeEventListener("keydown", handler);
|
|
3038
|
+
window.removeEventListener("click", clickHandler, true);
|
|
2921
3039
|
};
|
|
2922
3040
|
}, [open, zIndex]);
|
|
2923
3041
|
if (!open) return null;
|
|
@@ -2940,8 +3058,8 @@ function isTopmostDialog(z) {
|
|
|
2940
3058
|
: {})
|
|
2941
3059
|
};
|
|
2942
3060
|
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" },
|
|
3061
|
+
return portalOverlay(h("div", { ref: layerRef, className: "sm-nativeDialogLayer sm-bulkDialog" + (hasCoords ? " sm-bulkDialog-anchored" : ""), role: "presentation", style: layerStyle },
|
|
3062
|
+
h("section", { ref: dialogRef, className: "sm-nativeDialog", style: { pointerEvents: "auto" }, role: "dialog", "aria-modal": "true", "aria-labelledby": "sm-bulk-choice-title" },
|
|
2945
3063
|
h("div", { className: "sm-nativeDialogHeader" }, h("h2", { id: "sm-bulk-choice-title", className: "sm-nativeDialogTitle" }, title)),
|
|
2946
3064
|
h("div", { className: "sm-nativeDialogBody" },
|
|
2947
3065
|
description ? h("div", { className: "sm-bulkDialogSummary" }, description) : null,
|
|
@@ -3167,6 +3285,8 @@ function isTopmostDialog(z) {
|
|
|
3167
3285
|
const onConfirm = typeof props.onConfirm === "function" ? props.onConfirm : () => {};
|
|
3168
3286
|
const busy = props.busy === true;
|
|
3169
3287
|
const danger = props.danger === true;
|
|
3288
|
+
const dialogRef = useRef(null);
|
|
3289
|
+
const layerRef = useRef(null);
|
|
3170
3290
|
// Claim a fresh z-index so this popup sits above any earlier popup.
|
|
3171
3291
|
const [zIndex] = useState(() => open ? nextDialogZ() : 0);
|
|
3172
3292
|
const title = props.title || "";
|
|
@@ -3202,9 +3322,23 @@ function isTopmostDialog(z) {
|
|
|
3202
3322
|
if (ae && typeof ae.blur === "function" && ae !== document.body) ae.blur();
|
|
3203
3323
|
};
|
|
3204
3324
|
window.addEventListener("keydown", handler);
|
|
3325
|
+
const mountTime = Date.now();
|
|
3326
|
+
const clickHandler = (e) => {
|
|
3327
|
+
if (Date.now() - mountTime < 50) return;
|
|
3328
|
+
if (e.defaultPrevented) return;
|
|
3329
|
+
if (escStateRef.current.busy) return;
|
|
3330
|
+
if (!isTopmostDialog(effectiveZ)) return;
|
|
3331
|
+
if (isClickInsideDialog(e, dialogRef, layerRef)) return;
|
|
3332
|
+
if (e && typeof e.preventDefault === "function") e.preventDefault();
|
|
3333
|
+
if (e && typeof e.stopPropagation === "function") e.stopPropagation();
|
|
3334
|
+
if (e && typeof e.stopImmediatePropagation === "function") e.stopImmediatePropagation();
|
|
3335
|
+
escStateRef.current.onCancel();
|
|
3336
|
+
};
|
|
3337
|
+
window.addEventListener("click", clickHandler, true);
|
|
3205
3338
|
return () => {
|
|
3206
3339
|
unregisterDialogZ(effectiveZ);
|
|
3207
3340
|
window.removeEventListener("keydown", handler);
|
|
3341
|
+
window.removeEventListener("click", clickHandler, true);
|
|
3208
3342
|
};
|
|
3209
3343
|
}, [open, zIndex]);
|
|
3210
3344
|
|
|
@@ -3232,13 +3366,17 @@ function isTopmostDialog(z) {
|
|
|
3232
3366
|
: {})
|
|
3233
3367
|
};
|
|
3234
3368
|
|
|
3369
|
+
const confirmDisabled = props.confirmDisabled === true;
|
|
3370
|
+
|
|
3235
3371
|
return renderInOverlay(
|
|
3236
3372
|
h("div", {
|
|
3373
|
+
ref: layerRef,
|
|
3237
3374
|
className: "sm-nativeDialogLayer sm-confirmDialog" + (hasCoords ? " sm-confirmDialog-anchored" : ""),
|
|
3238
3375
|
style: layerStyle,
|
|
3239
3376
|
role: "presentation"
|
|
3240
3377
|
},
|
|
3241
3378
|
h("section", {
|
|
3379
|
+
ref: dialogRef,
|
|
3242
3380
|
className: "sm-nativeDialog",
|
|
3243
3381
|
style: { pointerEvents: "auto" },
|
|
3244
3382
|
role: "dialog",
|
|
@@ -3262,8 +3400,8 @@ function isTopmostDialog(z) {
|
|
|
3262
3400
|
h("button", {
|
|
3263
3401
|
type: "button",
|
|
3264
3402
|
className: "sm-nativeDialogButton" + (danger ? " sm-nativeDialogDanger" : " sm-nativeDialogConfirm"),
|
|
3265
|
-
disabled: busy,
|
|
3266
|
-
onClick: () => { if (!busy) onConfirm(); }
|
|
3403
|
+
disabled: busy || confirmDisabled,
|
|
3404
|
+
onClick: () => { if (!busy && !confirmDisabled) onConfirm(); }
|
|
3267
3405
|
}, confirmLabel)
|
|
3268
3406
|
)
|
|
3269
3407
|
)
|
|
@@ -3276,6 +3414,8 @@ function isTopmostDialog(z) {
|
|
|
3276
3414
|
const onCancel = typeof props.onCancel === "function" ? props.onCancel : () => {};
|
|
3277
3415
|
const onConfirm = typeof props.onConfirm === "function" ? props.onConfirm : () => {};
|
|
3278
3416
|
const busy = props.busy === true;
|
|
3417
|
+
const dialogRef = useRef(null);
|
|
3418
|
+
const layerRef = useRef(null);
|
|
3279
3419
|
const title = props.title || t("confirm.move.title");
|
|
3280
3420
|
const description = props.description || "";
|
|
3281
3421
|
const currentWorkspaceId = props.currentWorkspaceId || "";
|
|
@@ -3324,9 +3464,23 @@ function isTopmostDialog(z) {
|
|
|
3324
3464
|
if (ae && typeof ae.blur === "function" && ae !== document.body) ae.blur();
|
|
3325
3465
|
};
|
|
3326
3466
|
window.addEventListener("keydown", handler);
|
|
3467
|
+
const mountTime = Date.now();
|
|
3468
|
+
const clickHandler = (e) => {
|
|
3469
|
+
if (Date.now() - mountTime < 50) return;
|
|
3470
|
+
if (e.defaultPrevented) return;
|
|
3471
|
+
if (escStateRef.current.busy) return;
|
|
3472
|
+
if (!isTopmostDialog(effectiveZ)) return;
|
|
3473
|
+
if (isClickInsideDialog(e, dialogRef, layerRef)) return;
|
|
3474
|
+
if (e && typeof e.preventDefault === "function") e.preventDefault();
|
|
3475
|
+
if (e && typeof e.stopPropagation === "function") e.stopPropagation();
|
|
3476
|
+
if (e && typeof e.stopImmediatePropagation === "function") e.stopImmediatePropagation();
|
|
3477
|
+
escStateRef.current.onCancel();
|
|
3478
|
+
};
|
|
3479
|
+
window.addEventListener("click", clickHandler, true);
|
|
3327
3480
|
return () => {
|
|
3328
3481
|
unregisterDialogZ(effectiveZ);
|
|
3329
3482
|
window.removeEventListener("keydown", handler);
|
|
3483
|
+
window.removeEventListener("click", clickHandler, true);
|
|
3330
3484
|
};
|
|
3331
3485
|
}, [open, zIndex]);
|
|
3332
3486
|
if (!open) return null;
|
|
@@ -3384,12 +3538,14 @@ function isTopmostDialog(z) {
|
|
|
3384
3538
|
};
|
|
3385
3539
|
return renderInOverlay(
|
|
3386
3540
|
h("div", {
|
|
3541
|
+
ref: layerRef,
|
|
3387
3542
|
className: "sm-nativeDialogLayer sm-confirmDialog" + (hasCoords ? " sm-confirmDialog-anchored" : ""),
|
|
3388
3543
|
style: layerStyle,
|
|
3389
3544
|
role: "presentation",
|
|
3390
3545
|
onKeyDown
|
|
3391
3546
|
},
|
|
3392
3547
|
h("section", {
|
|
3548
|
+
ref: dialogRef,
|
|
3393
3549
|
className: "sm-nativeDialog",
|
|
3394
3550
|
style: { pointerEvents: "auto" },
|
|
3395
3551
|
role: "dialog",
|
|
@@ -3425,6 +3581,8 @@ function isTopmostDialog(z) {
|
|
|
3425
3581
|
const onCancel = typeof props.onCancel === "function" ? props.onCancel : () => {};
|
|
3426
3582
|
const onRun = typeof props.onRun === "function" ? props.onRun : () => {};
|
|
3427
3583
|
const busy = props.busy === true;
|
|
3584
|
+
const dialogRef = useRef(null);
|
|
3585
|
+
const layerRef = useRef(null);
|
|
3428
3586
|
const sessionId = props.sessionId || "";
|
|
3429
3587
|
const description = props.description || "";
|
|
3430
3588
|
const fallbackPreset = props.currentPreset || "";
|
|
@@ -3483,9 +3641,23 @@ function isTopmostDialog(z) {
|
|
|
3483
3641
|
if (ae && typeof ae.blur === "function" && ae !== document.body) ae.blur();
|
|
3484
3642
|
};
|
|
3485
3643
|
window.addEventListener("keydown", handler);
|
|
3644
|
+
const mountTime = Date.now();
|
|
3645
|
+
const clickHandler = (e) => {
|
|
3646
|
+
if (Date.now() - mountTime < 50) return;
|
|
3647
|
+
if (e.defaultPrevented) return;
|
|
3648
|
+
if (escStateRef.current.busy) return;
|
|
3649
|
+
if (!isTopmostDialog(effectiveZ)) return;
|
|
3650
|
+
if (isClickInsideDialog(e, dialogRef, layerRef)) return;
|
|
3651
|
+
if (e && typeof e.preventDefault === "function") e.preventDefault();
|
|
3652
|
+
if (e && typeof e.stopPropagation === "function") e.stopPropagation();
|
|
3653
|
+
if (e && typeof e.stopImmediatePropagation === "function") e.stopImmediatePropagation();
|
|
3654
|
+
escStateRef.current.onCancel();
|
|
3655
|
+
};
|
|
3656
|
+
window.addEventListener("click", clickHandler, true);
|
|
3486
3657
|
return () => {
|
|
3487
3658
|
unregisterDialogZ(effectiveZ);
|
|
3488
3659
|
window.removeEventListener("keydown", handler);
|
|
3660
|
+
window.removeEventListener("click", clickHandler, true);
|
|
3489
3661
|
};
|
|
3490
3662
|
}, [open, zIndex]);
|
|
3491
3663
|
if (!open) return null;
|
|
@@ -3542,11 +3714,13 @@ function isTopmostDialog(z) {
|
|
|
3542
3714
|
};
|
|
3543
3715
|
return renderInOverlay(
|
|
3544
3716
|
h("div", {
|
|
3717
|
+
ref: layerRef,
|
|
3545
3718
|
className: "sm-nativeDialogLayer sm-confirmDialog" + (hasCoords ? " sm-confirmDialog-anchored" : ""),
|
|
3546
3719
|
role: "presentation",
|
|
3547
3720
|
style: layerStyle
|
|
3548
3721
|
},
|
|
3549
3722
|
h("section", {
|
|
3723
|
+
ref: dialogRef,
|
|
3550
3724
|
className: "sm-nativeDialog",
|
|
3551
3725
|
style: { pointerEvents: "auto" },
|
|
3552
3726
|
role: "dialog",
|
|
@@ -3575,7 +3749,7 @@ function isTopmostDialog(z) {
|
|
|
3575
3749
|
));
|
|
3576
3750
|
}
|
|
3577
3751
|
|
|
3578
|
-
const CURRENT_VERSION = "0.7.
|
|
3752
|
+
const CURRENT_VERSION = "0.7.1";
|
|
3579
3753
|
|
|
3580
3754
|
function compareSemver(v1, v2) {
|
|
3581
3755
|
if (typeof v1 !== "string" || typeof v2 !== "string") return 0;
|
|
@@ -3636,7 +3810,11 @@ function isTopmostDialog(z) {
|
|
|
3636
3810
|
application: null,
|
|
3637
3811
|
dialogOpen: false,
|
|
3638
3812
|
checkedAt: null,
|
|
3813
|
+
lastAttemptAt: null,
|
|
3639
3814
|
},
|
|
3815
|
+
CHECK_INTERVAL_MS: 6 * 60 * 60 * 1000,
|
|
3816
|
+
RETRY_COOLDOWN_MS: 30 * 60 * 1000,
|
|
3817
|
+
lastFailedAt: null,
|
|
3640
3818
|
listeners: new Set(),
|
|
3641
3819
|
getSnapshot() { return this.state; },
|
|
3642
3820
|
subscribe(cb) {
|
|
@@ -3671,6 +3849,29 @@ function isTopmostDialog(z) {
|
|
|
3671
3849
|
} catch (_) {}
|
|
3672
3850
|
this._notify();
|
|
3673
3851
|
},
|
|
3852
|
+
shouldAutoCheck(now = Date.now()) {
|
|
3853
|
+
if (!this.getAutoCheck()) return false;
|
|
3854
|
+
if (this.state.status === "checking" || this.state.status === "updating") return false;
|
|
3855
|
+
if (this.state.status === "available") return false;
|
|
3856
|
+
if (this.lastFailedAt && (now - this.lastFailedAt < this.RETRY_COOLDOWN_MS)) {
|
|
3857
|
+
return false;
|
|
3858
|
+
}
|
|
3859
|
+
if (this.state.checkedAt && (now - this.state.checkedAt < this.CHECK_INTERVAL_MS)) {
|
|
3860
|
+
return false;
|
|
3861
|
+
}
|
|
3862
|
+
return true;
|
|
3863
|
+
},
|
|
3864
|
+
async maybeAutoCheck(options = {}) {
|
|
3865
|
+
const now = typeof options.now === "number" ? options.now : Date.now();
|
|
3866
|
+
if (!this.shouldAutoCheck(now)) return this.state;
|
|
3867
|
+
return this.checkForUpdate({
|
|
3868
|
+
silent: true,
|
|
3869
|
+
openOnFound: false,
|
|
3870
|
+
openDialog: false,
|
|
3871
|
+
...options,
|
|
3872
|
+
manual: false
|
|
3873
|
+
});
|
|
3874
|
+
},
|
|
3674
3875
|
// Dialog opacity preference (Issue #23). Reuses the same localStorage
|
|
3675
3876
|
// backed preference store as autoCheck / registry instead of adding a
|
|
3676
3877
|
// second storage mechanism.
|
|
@@ -3733,7 +3934,17 @@ function isTopmostDialog(z) {
|
|
|
3733
3934
|
}
|
|
3734
3935
|
this._notify();
|
|
3735
3936
|
|
|
3937
|
+
const timeoutMs = typeof options.timeoutMs === "number" ? options.timeoutMs : 10000;
|
|
3938
|
+
let timeoutTimer = null;
|
|
3939
|
+
const abortController = typeof AbortController !== "undefined" ? new AbortController() : null;
|
|
3940
|
+
|
|
3736
3941
|
try {
|
|
3942
|
+
if (abortController) {
|
|
3943
|
+
timeoutTimer = setTimeout(() => {
|
|
3944
|
+
abortController.abort(new Error("检查更新超时"));
|
|
3945
|
+
}, timeoutMs);
|
|
3946
|
+
}
|
|
3947
|
+
|
|
3737
3948
|
let res = null;
|
|
3738
3949
|
if (typeof window !== "undefined" && window.__DSH_SM_TEST_UPDATE__) {
|
|
3739
3950
|
const testOverride = window.__DSH_SM_TEST_UPDATE__;
|
|
@@ -3747,12 +3958,16 @@ function isTopmostDialog(z) {
|
|
|
3747
3958
|
} else {
|
|
3748
3959
|
const registryUrl = this.getRegistryUrl();
|
|
3749
3960
|
const registryParam = encodeURIComponent(registryUrl);
|
|
3961
|
+
const fetchOpts = abortController ? { signal: abortController.signal } : undefined;
|
|
3750
3962
|
try {
|
|
3751
|
-
res = await fetchApi("/update/check?registry=" + registryParam);
|
|
3963
|
+
res = await fetchApi("/update/check?registry=" + registryParam, fetchOpts);
|
|
3752
3964
|
} catch (fetchErr) {
|
|
3965
|
+
if (abortController?.signal?.aborted || fetchErr.name === "AbortError" || fetchErr.message?.includes("超时")) {
|
|
3966
|
+
throw new Error("检查更新超时");
|
|
3967
|
+
}
|
|
3753
3968
|
try {
|
|
3754
3969
|
const base = registryUrl.endsWith("/") ? registryUrl : registryUrl + "/";
|
|
3755
|
-
const npmRes = await fetch(base + "dsh-session-manager/latest");
|
|
3970
|
+
const npmRes = await fetch(base + "dsh-session-manager/latest", fetchOpts);
|
|
3756
3971
|
if (npmRes.ok) {
|
|
3757
3972
|
const npmData = await npmRes.json();
|
|
3758
3973
|
if (npmData && npmData.version) {
|
|
@@ -3762,7 +3977,11 @@ function isTopmostDialog(z) {
|
|
|
3762
3977
|
res = { ok: true, result: { currentVersion: cur, latestVersion: lat, hasUpdate } };
|
|
3763
3978
|
}
|
|
3764
3979
|
}
|
|
3765
|
-
} catch (_) {
|
|
3980
|
+
} catch (_) {
|
|
3981
|
+
if (abortController?.signal?.aborted || fetchErr.name === "AbortError" || fetchErr.message?.includes("超时")) {
|
|
3982
|
+
throw new Error("检查更新超时");
|
|
3983
|
+
}
|
|
3984
|
+
}
|
|
3766
3985
|
if (!res) throw fetchErr;
|
|
3767
3986
|
}
|
|
3768
3987
|
}
|
|
@@ -3778,7 +3997,10 @@ function isTopmostDialog(z) {
|
|
|
3778
3997
|
|
|
3779
3998
|
this.state.currentVersion = currentVersion;
|
|
3780
3999
|
this.state.latestVersion = latestVersion;
|
|
3781
|
-
|
|
4000
|
+
const now = Date.now();
|
|
4001
|
+
this.state.checkedAt = now;
|
|
4002
|
+
this.state.lastAttemptAt = now;
|
|
4003
|
+
this.lastFailedAt = null;
|
|
3782
4004
|
|
|
3783
4005
|
if (hasUpdate) {
|
|
3784
4006
|
this.state.status = "available";
|
|
@@ -3794,13 +4016,18 @@ function isTopmostDialog(z) {
|
|
|
3794
4016
|
this._notify();
|
|
3795
4017
|
return this.state;
|
|
3796
4018
|
} catch (err) {
|
|
4019
|
+
const now = Date.now();
|
|
3797
4020
|
this.state.status = "error";
|
|
3798
|
-
this.state.error = err.message || "检查更新失败";
|
|
4021
|
+
this.state.error = (abortController?.signal?.aborted ? "检查更新超时" : (err.message || "检查更新失败"));
|
|
4022
|
+
this.state.lastAttemptAt = now;
|
|
4023
|
+
this.lastFailedAt = now;
|
|
3799
4024
|
if (shouldOpenDialog) {
|
|
3800
4025
|
this.state.dialogOpen = true;
|
|
3801
4026
|
}
|
|
3802
4027
|
this._notify();
|
|
3803
4028
|
return this.state;
|
|
4029
|
+
} finally {
|
|
4030
|
+
if (timeoutTimer) clearTimeout(timeoutTimer);
|
|
3804
4031
|
}
|
|
3805
4032
|
},
|
|
3806
4033
|
async startUpdate(options = {}) {
|
|
@@ -3864,8 +4091,15 @@ function isTopmostDialog(z) {
|
|
|
3864
4091
|
listeners: new Set(),
|
|
3865
4092
|
getSnapshot() { return this.open; },
|
|
3866
4093
|
subscribe(cb) { this.listeners.add(cb); return () => this.listeners.delete(cb); },
|
|
3867
|
-
set(v) {
|
|
3868
|
-
|
|
4094
|
+
set(v) {
|
|
4095
|
+
if (this.open === v) return;
|
|
4096
|
+
this.open = v;
|
|
4097
|
+
if (this.open) {
|
|
4098
|
+
try { updateStore.maybeAutoCheck().catch(() => {}); } catch (_) {}
|
|
4099
|
+
}
|
|
4100
|
+
for (const fn of [...this.listeners]) fn();
|
|
4101
|
+
},
|
|
4102
|
+
toggle() { this.set(!this.open); },
|
|
3869
4103
|
// Pending action queued by the title-bar buttons (e.g. 移动至工作区).
|
|
3870
4104
|
// The SessionManagerPanel consumes this on mount so it can pre-open
|
|
3871
4105
|
// the matching inner dialog (move / delete / migrate) next to itself.
|
|
@@ -3979,6 +4213,29 @@ function isTopmostDialog(z) {
|
|
|
3979
4213
|
const [now, setNow] = useState(() => Date.now());
|
|
3980
4214
|
const [moveFor, setMoveFor] = useState(null);
|
|
3981
4215
|
const [confirmFor, setConfirmFor] = useState(null);
|
|
4216
|
+
const [confirmPreviewState, setConfirmPreviewState] = useState({ loading: false, error: null, subagentCount: 0 });
|
|
4217
|
+
useEffect(() => {
|
|
4218
|
+
if (!confirmFor || !confirmFor.id) {
|
|
4219
|
+
setConfirmPreviewState({ loading: false, error: null, subagentCount: 0 });
|
|
4220
|
+
return;
|
|
4221
|
+
}
|
|
4222
|
+
let alive = true;
|
|
4223
|
+
setConfirmPreviewState({ loading: true, error: null, subagentCount: 0 });
|
|
4224
|
+
fetchApi("/delete-preview?sessionId=" + encodeURIComponent(confirmFor.id))
|
|
4225
|
+
.then((res) => {
|
|
4226
|
+
if (!alive) return;
|
|
4227
|
+
if (res && res.ok && res.result && typeof res.result.subagentCount === "number") {
|
|
4228
|
+
setConfirmPreviewState({ loading: false, error: null, subagentCount: res.result.subagentCount });
|
|
4229
|
+
} else {
|
|
4230
|
+
setConfirmPreviewState({ loading: false, error: res?.error || "获取子智能体预览失败", subagentCount: 0 });
|
|
4231
|
+
}
|
|
4232
|
+
})
|
|
4233
|
+
.catch((err) => {
|
|
4234
|
+
if (!alive) return;
|
|
4235
|
+
setConfirmPreviewState({ loading: false, error: err instanceof Error ? err.message : String(err), subagentCount: 0 });
|
|
4236
|
+
});
|
|
4237
|
+
return () => { alive = false; };
|
|
4238
|
+
}, [confirmFor?.id]);
|
|
3982
4239
|
const [workspaces, setWorkspaces] = useState([]);
|
|
3983
4240
|
const [createdTimes, setCreatedTimes] = useState({});
|
|
3984
4241
|
const [updatedTimes, setUpdatedTimes] = useState({});
|
|
@@ -4167,7 +4424,59 @@ function isTopmostDialog(z) {
|
|
|
4167
4424
|
};
|
|
4168
4425
|
const summaryAction = actionSummaryMap[action] || resolvedLabel;
|
|
4169
4426
|
if (needsConfirm) {
|
|
4170
|
-
|
|
4427
|
+
const baseWarning = action === "delete" ? t("bulk.dialog.warning.delete") : "";
|
|
4428
|
+
if (action === "delete") {
|
|
4429
|
+
setBulkPreview({
|
|
4430
|
+
action,
|
|
4431
|
+
payload,
|
|
4432
|
+
actionLabel: summaryAction,
|
|
4433
|
+
sessions,
|
|
4434
|
+
warning: baseWarning,
|
|
4435
|
+
loading: true,
|
|
4436
|
+
error: null
|
|
4437
|
+
});
|
|
4438
|
+
fetchApi("/delete-preview?sessionIds=" + encodeURIComponent(ids.join(",")))
|
|
4439
|
+
.then((res) => {
|
|
4440
|
+
if (res && res.ok && res.result && typeof res.result.subagentCount === "number") {
|
|
4441
|
+
const subCount = res.result.subagentCount;
|
|
4442
|
+
setBulkPreview((prev) => {
|
|
4443
|
+
if (!prev || prev.action !== "delete") return prev;
|
|
4444
|
+
const subText = subCount > 0 ? t("confirm.delete.subagents", { count: subCount }) : "";
|
|
4445
|
+
return {
|
|
4446
|
+
...prev,
|
|
4447
|
+
loading: false,
|
|
4448
|
+
error: null,
|
|
4449
|
+
warning: subText ? `${subText}\n${baseWarning}` : baseWarning
|
|
4450
|
+
};
|
|
4451
|
+
});
|
|
4452
|
+
} else {
|
|
4453
|
+
const errMsg = (res && res.error) || t("confirm.delete.previewError") || "检查关联子智能体会话失败,请稍后重试";
|
|
4454
|
+
setBulkPreview((prev) => {
|
|
4455
|
+
if (!prev || prev.action !== "delete") return prev;
|
|
4456
|
+
return {
|
|
4457
|
+
...prev,
|
|
4458
|
+
loading: false,
|
|
4459
|
+
error: errMsg,
|
|
4460
|
+
warning: `${errMsg}\n${baseWarning}`
|
|
4461
|
+
};
|
|
4462
|
+
});
|
|
4463
|
+
}
|
|
4464
|
+
})
|
|
4465
|
+
.catch((err) => {
|
|
4466
|
+
const errMsg = (err && err.message) || t("confirm.delete.previewError") || "检查关联子智能体会话失败,请稍后重试";
|
|
4467
|
+
setBulkPreview((prev) => {
|
|
4468
|
+
if (!prev || prev.action !== "delete") return prev;
|
|
4469
|
+
return {
|
|
4470
|
+
...prev,
|
|
4471
|
+
loading: false,
|
|
4472
|
+
error: errMsg,
|
|
4473
|
+
warning: `${errMsg}\n${baseWarning}`
|
|
4474
|
+
};
|
|
4475
|
+
});
|
|
4476
|
+
});
|
|
4477
|
+
return;
|
|
4478
|
+
}
|
|
4479
|
+
setBulkPreview({ action, payload, actionLabel: summaryAction, sessions, warning: baseWarning });
|
|
4171
4480
|
return;
|
|
4172
4481
|
}
|
|
4173
4482
|
void executeBulk({ action, payload, actionLabel: resolvedLabel, ids, sessions });
|
|
@@ -4460,28 +4769,56 @@ function isTopmostDialog(z) {
|
|
|
4460
4769
|
: h("div", { className: "sm-list" }, rows.map((s, i) => renderRow(s, i)));
|
|
4461
4770
|
|
|
4462
4771
|
const allWorkspaceRows = useMemo(() => {
|
|
4463
|
-
const
|
|
4772
|
+
const hasSessionList = Array.isArray(list?.ids);
|
|
4773
|
+
const sessionsByWorkspace = new Map();
|
|
4774
|
+
for (const ws of workspaces) {
|
|
4775
|
+
sessionsByWorkspace.set(ws.id, []);
|
|
4776
|
+
}
|
|
4777
|
+
if (hasSessionList) {
|
|
4778
|
+
for (const s of allRows) {
|
|
4779
|
+
const matchedWsIds = rowWorkspaces(s, workspaceIndex);
|
|
4780
|
+
for (const wsId of matchedWsIds) {
|
|
4781
|
+
const wsList = sessionsByWorkspace.get(wsId);
|
|
4782
|
+
if (wsList) wsList.push(s);
|
|
4783
|
+
}
|
|
4784
|
+
}
|
|
4785
|
+
}
|
|
4464
4786
|
return workspaces.map(ws => {
|
|
4465
|
-
const
|
|
4787
|
+
const wsSessions = sessionsByWorkspace.get(ws.id) || [];
|
|
4788
|
+
let sessionCount = 0;
|
|
4466
4789
|
let latestSessionTime = null;
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4790
|
+
if (hasSessionList) {
|
|
4791
|
+
sessionCount = wsSessions.length;
|
|
4792
|
+
for (const s of wsSessions) {
|
|
4793
|
+
const st = sessionTime(s?.updatedAt) ?? sessionTime(s?.createdAt);
|
|
4794
|
+
if (st !== null) {
|
|
4795
|
+
if (latestSessionTime === null || st > latestSessionTime) {
|
|
4796
|
+
latestSessionTime = st;
|
|
4797
|
+
}
|
|
4798
|
+
}
|
|
4799
|
+
}
|
|
4800
|
+
} else {
|
|
4801
|
+
const sids = Array.isArray(ws.sessionIds) ? ws.sessionIds : [];
|
|
4802
|
+
const byId = list?.byId || {};
|
|
4803
|
+
for (const sid of sids) {
|
|
4804
|
+
const s = byId[sid];
|
|
4805
|
+
if (s && (s.origin === "subagent" || (s.blank && s.id !== list?.current))) continue;
|
|
4806
|
+
sessionCount++;
|
|
4807
|
+
const st = sessionTime(s?.updatedAt) ?? sessionTime(s?.createdAt);
|
|
4808
|
+
if (st !== null) {
|
|
4809
|
+
if (latestSessionTime === null || st > latestSessionTime) {
|
|
4810
|
+
latestSessionTime = st;
|
|
4811
|
+
}
|
|
4474
4812
|
}
|
|
4475
4813
|
}
|
|
4476
4814
|
}
|
|
4477
|
-
const wsSelfTime = sessionTime(ws.updatedAt) ?? sessionTime(ws.createdAt);
|
|
4478
|
-
const resolvedTime = latestSessionTime !== null ? latestSessionTime : wsSelfTime;
|
|
4479
4815
|
return {
|
|
4480
4816
|
...ws,
|
|
4481
|
-
|
|
4817
|
+
sessionCount,
|
|
4818
|
+
latestUpdatedAt: latestSessionTime
|
|
4482
4819
|
};
|
|
4483
4820
|
});
|
|
4484
|
-
}, [workspaces, list?.
|
|
4821
|
+
}, [workspaces, allRows, workspaceIndex, list?.ids, list?.byId, list?.current]);
|
|
4485
4822
|
|
|
4486
4823
|
const filteredWorkspaceRows = useMemo(() => {
|
|
4487
4824
|
const needle = wsQuery.trim().toLowerCase();
|
|
@@ -4632,7 +4969,7 @@ function isTopmostDialog(z) {
|
|
|
4632
4969
|
const isBusy = workspaceArchiveStore.isBusy(ws.id);
|
|
4633
4970
|
const title = ws.title || ws.name || ws.id;
|
|
4634
4971
|
const path = ws.path || "";
|
|
4635
|
-
const sessionCount = Array.isArray(ws.sessionIds) ? ws.sessionIds.length : 0;
|
|
4972
|
+
const sessionCount = typeof ws.sessionCount === "number" ? ws.sessionCount : (Array.isArray(ws.sessionIds) ? ws.sessionIds.length : 0);
|
|
4636
4973
|
const timeFormatted = ws.latestUpdatedAt !== null
|
|
4637
4974
|
? t("workspace.lastUpdated", { time: formatRelative(ws.latestUpdatedAt, now) })
|
|
4638
4975
|
: "—";
|
|
@@ -4689,13 +5026,12 @@ function isTopmostDialog(z) {
|
|
|
4689
5026
|
},
|
|
4690
5027
|
h("div", { className: "sm-rowCheckboxSlot" + ((wsSelectedIds.size > 0 || wsSelectModeEnabled) ? " sm-rowCheckboxSlot-visible" : "") }, checkbox),
|
|
4691
5028
|
h("div", { className: "sm-rowMain" },
|
|
4692
|
-
h("div", { className: "sm-rowTitle" },
|
|
5029
|
+
h("div", { className: "sm-rowTitle", title: path || title },
|
|
4693
5030
|
h("span", null, title),
|
|
4694
5031
|
isArchived ? h("span", { className: "sm-badge sm-badgeArchived" }, t("workspace.badge.archived")) : null
|
|
4695
5032
|
),
|
|
4696
5033
|
h("div", { className: "sm-rowSecondary" },
|
|
4697
5034
|
h("div", { className: "sm-rowMeta" },
|
|
4698
|
-
(path ? (shortPath(path) + " · ") : "") +
|
|
4699
5035
|
t("workspace.sessions", { count: sessionCount }) +
|
|
4700
5036
|
" · " +
|
|
4701
5037
|
timeFormatted
|
|
@@ -4726,8 +5062,23 @@ function isTopmostDialog(z) {
|
|
|
4726
5062
|
// without re-subscribing on every render. The panel listener
|
|
4727
5063
|
// returns early when any inner dialog is open so the child
|
|
4728
5064
|
// dialog's own window listener gets the first shot at Esc.
|
|
5065
|
+
const panelRef = useRef(null);
|
|
4729
5066
|
const escStateRef = useRef({});
|
|
4730
|
-
escStateRef.current = {
|
|
5067
|
+
escStateRef.current = {
|
|
5068
|
+
busyId,
|
|
5069
|
+
confirmFor,
|
|
5070
|
+
moveFor,
|
|
5071
|
+
migrateFor,
|
|
5072
|
+
annotationFor,
|
|
5073
|
+
bulkPreview,
|
|
5074
|
+
bulkProgress,
|
|
5075
|
+
bulkResult,
|
|
5076
|
+
bulkBusy,
|
|
5077
|
+
bulkTagDraft,
|
|
5078
|
+
bulkPresetDraft,
|
|
5079
|
+
wsBulkBusy,
|
|
5080
|
+
onPanelClose
|
|
5081
|
+
};
|
|
4731
5082
|
useEffect(() => {
|
|
4732
5083
|
if (!open) return;
|
|
4733
5084
|
const handler = (e) => {
|
|
@@ -4735,8 +5086,10 @@ function isTopmostDialog(z) {
|
|
|
4735
5086
|
if (e.defaultPrevented) return;
|
|
4736
5087
|
if (e.isComposing || e.keyCode === 229) return;
|
|
4737
5088
|
const s = escStateRef.current;
|
|
4738
|
-
if (s.busyId !== null || s.wsBulkBusy) return;
|
|
4739
|
-
if (s.confirmFor || s.moveFor || s.migrateFor || s.annotationFor ||
|
|
5089
|
+
if (s.busyId !== null || s.wsBulkBusy || s.bulkBusy) return;
|
|
5090
|
+
if (s.confirmFor || s.moveFor || s.migrateFor || s.annotationFor || s.bulkPreview || s.bulkProgress || s.bulkResult || s.bulkTagDraft || s.bulkPresetDraft) return;
|
|
5091
|
+
if (typeof updateStore !== "undefined" && updateStore && typeof updateStore.getSnapshot === "function" && updateStore.getSnapshot()?.dialogOpen) return;
|
|
5092
|
+
if (activeDialogZStack && activeDialogZStack.length > 0) return;
|
|
4740
5093
|
e.preventDefault();
|
|
4741
5094
|
e.stopPropagation();
|
|
4742
5095
|
s.onPanelClose();
|
|
@@ -4750,7 +5103,28 @@ function isTopmostDialog(z) {
|
|
|
4750
5103
|
if (ae && typeof ae.blur === "function" && ae !== document.body) ae.blur();
|
|
4751
5104
|
};
|
|
4752
5105
|
window.addEventListener("keydown", handler);
|
|
4753
|
-
|
|
5106
|
+
const mountTime = Date.now();
|
|
5107
|
+
const clickHandler = (e) => {
|
|
5108
|
+
if (Date.now() - mountTime < 50) return;
|
|
5109
|
+
if (e.defaultPrevented) return;
|
|
5110
|
+
const s = escStateRef.current;
|
|
5111
|
+
if (s.busyId !== null || s.wsBulkBusy || s.bulkBusy) return;
|
|
5112
|
+
if (s.annotationFor !== null) return;
|
|
5113
|
+
if (s.confirmFor || s.moveFor || s.migrateFor) return;
|
|
5114
|
+
if (s.bulkPreview || s.bulkProgress || s.bulkResult || s.bulkTagDraft || s.bulkPresetDraft) return;
|
|
5115
|
+
if (typeof updateStore !== "undefined" && updateStore && typeof updateStore.getSnapshot === "function" && updateStore.getSnapshot()?.dialogOpen) return;
|
|
5116
|
+
if (activeDialogZStack && activeDialogZStack.length > 0) return;
|
|
5117
|
+
if (panelRef.current && typeof panelRef.current.contains === "function" && panelRef.current.contains(e.target)) return;
|
|
5118
|
+
if (e.target && typeof e.target.closest === "function") {
|
|
5119
|
+
if (e.target.closest(".sm-nativeDialog, .sm-panelDialog, .sm-bulkDialog, .sm-annotationDialog, .sm-annotationSurface, .sm-tooltip, .sm-footerBtn")) return;
|
|
5120
|
+
}
|
|
5121
|
+
s.onPanelClose();
|
|
5122
|
+
};
|
|
5123
|
+
window.addEventListener("click", clickHandler);
|
|
5124
|
+
return () => {
|
|
5125
|
+
window.removeEventListener("keydown", handler);
|
|
5126
|
+
window.removeEventListener("click", clickHandler);
|
|
5127
|
+
};
|
|
4754
5128
|
}, [open]);
|
|
4755
5129
|
// The panel is a document-level floating window, so it is portaled into
|
|
4756
5130
|
// the plugin's overlay root like every other dialog here (issue #28).
|
|
@@ -4773,6 +5147,7 @@ function isTopmostDialog(z) {
|
|
|
4773
5147
|
role: "presentation"
|
|
4774
5148
|
},
|
|
4775
5149
|
h("section", {
|
|
5150
|
+
ref: panelRef,
|
|
4776
5151
|
className: "sm-nativeDialog sm-panelDialog",
|
|
4777
5152
|
role: "dialog",
|
|
4778
5153
|
"aria-modal": "true",
|
|
@@ -5076,13 +5451,27 @@ function isTopmostDialog(z) {
|
|
|
5076
5451
|
onClose: () => { if (busyId === null) setConfirmFor(null); },
|
|
5077
5452
|
title: t("confirm.delete.title"),
|
|
5078
5453
|
description: (confirmFor.displayTitle && t("confirm.delete.desc", { title: confirmFor.displayTitle })) || "",
|
|
5079
|
-
warning:
|
|
5454
|
+
warning: (() => {
|
|
5455
|
+
const baseWarning = (confirmFor.running ? (t("confirm.delete.running") + " " + t("bulk.dialog.warning.delete")) : t("bulk.dialog.warning.delete"));
|
|
5456
|
+
if (confirmPreviewState.loading) {
|
|
5457
|
+
const loadingMsg = t("confirm.delete.previewLoading") || "正在检查关联的子智能体会话…";
|
|
5458
|
+
return `${loadingMsg}\n${baseWarning}`;
|
|
5459
|
+
}
|
|
5460
|
+
if (confirmPreviewState.error) {
|
|
5461
|
+
const errorMsg = confirmPreviewState.error;
|
|
5462
|
+
return `${errorMsg}\n${baseWarning}`;
|
|
5463
|
+
}
|
|
5464
|
+
const subagentWarning = confirmPreviewState.subagentCount > 0 ? t("confirm.delete.subagents", { count: confirmPreviewState.subagentCount }) : "";
|
|
5465
|
+
return subagentWarning ? `${subagentWarning}\n${baseWarning}` : baseWarning;
|
|
5466
|
+
})(),
|
|
5467
|
+
confirmDisabled: confirmPreviewState.loading || Boolean(confirmPreviewState.error),
|
|
5080
5468
|
confirmLabel: t("confirm.delete.confirm"),
|
|
5081
5469
|
cancelLabel: t("confirm.cancel"),
|
|
5082
5470
|
busy: busyId !== null,
|
|
5083
5471
|
danger: true,
|
|
5084
5472
|
onCancel: () => { if (busyId === null) setConfirmFor(null); },
|
|
5085
5473
|
onConfirm: () => {
|
|
5474
|
+
if (confirmPreviewState.loading || confirmPreviewState.error) return;
|
|
5086
5475
|
const target = confirmFor;
|
|
5087
5476
|
setConfirmFor(null);
|
|
5088
5477
|
runRow(target.id, () => onRemove(target.id));
|
|
@@ -5168,12 +5557,16 @@ function isTopmostDialog(z) {
|
|
|
5168
5557
|
delete: t("bulk.confirm.delete")
|
|
5169
5558
|
})[action] || t("bulk.dialog.execute");
|
|
5170
5559
|
const bulkPreviewDialog = bulkPreview ? h(BatchPreviewDialog, {
|
|
5171
|
-
open: true, t, actionLabel: bulkPreview.actionLabel,
|
|
5560
|
+
open: true, t, action: bulkPreview.action, actionLabel: bulkPreview.actionLabel,
|
|
5561
|
+
title: bulkPreview.action === "delete" ? t("confirm.delete.title") : undefined,
|
|
5172
5562
|
sessions: bulkPreview.sessions, warning: bulkPreview.warning,
|
|
5173
5563
|
confirmLabel: bulkConfirmLabelFor(bulkPreview.action),
|
|
5174
5564
|
danger: bulkPreview.action === "delete",
|
|
5565
|
+
loading: bulkPreview.loading === true,
|
|
5566
|
+
error: bulkPreview.error || null,
|
|
5175
5567
|
onCancel: () => setBulkPreview(null),
|
|
5176
5568
|
onExecute: () => {
|
|
5569
|
+
if (bulkPreview.loading || bulkPreview.error) return;
|
|
5177
5570
|
const preview = bulkPreview;
|
|
5178
5571
|
setBulkPreview(null);
|
|
5179
5572
|
void executeBulk({
|
|
@@ -5279,6 +5672,29 @@ function isTopmostDialog(z) {
|
|
|
5279
5672
|
|
|
5280
5673
|
const [confirmFor, setConfirmFor] = useState(null);
|
|
5281
5674
|
const [confirmAnchor, setConfirmAnchor] = useState(null);
|
|
5675
|
+
const [confirmPreviewState, setConfirmPreviewState] = useState({ loading: false, error: null, subagentCount: 0 });
|
|
5676
|
+
useEffect(() => {
|
|
5677
|
+
if (!confirmFor || !confirmFor.id) {
|
|
5678
|
+
setConfirmPreviewState({ loading: false, error: null, subagentCount: 0 });
|
|
5679
|
+
return;
|
|
5680
|
+
}
|
|
5681
|
+
let alive = true;
|
|
5682
|
+
setConfirmPreviewState({ loading: true, error: null, subagentCount: 0 });
|
|
5683
|
+
fetchApi("/delete-preview?sessionId=" + encodeURIComponent(confirmFor.id))
|
|
5684
|
+
.then((res) => {
|
|
5685
|
+
if (!alive) return;
|
|
5686
|
+
if (res && res.ok && res.result && typeof res.result.subagentCount === "number") {
|
|
5687
|
+
setConfirmPreviewState({ loading: false, error: null, subagentCount: res.result.subagentCount });
|
|
5688
|
+
} else {
|
|
5689
|
+
setConfirmPreviewState({ loading: false, error: res?.error || (t ? t("confirm.delete.previewError") : "检查关联子智能体会话失败,请稍后重试"), subagentCount: 0 });
|
|
5690
|
+
}
|
|
5691
|
+
})
|
|
5692
|
+
.catch((err) => {
|
|
5693
|
+
if (!alive) return;
|
|
5694
|
+
setConfirmPreviewState({ loading: false, error: (err && err.message) || (t ? t("confirm.delete.previewError") : "检查关联子智能体会话失败,请稍后重试"), subagentCount: 0 });
|
|
5695
|
+
});
|
|
5696
|
+
return () => { alive = false; };
|
|
5697
|
+
}, [confirmFor?.id]);
|
|
5282
5698
|
const [moveFor, setMoveFor] = useState(null);
|
|
5283
5699
|
const [moveAnchor, setMoveAnchor] = useState(null);
|
|
5284
5700
|
const [workspaces, setWorkspaces] = useState([]);
|
|
@@ -5608,13 +6024,30 @@ function isTopmostDialog(z) {
|
|
|
5608
6024
|
onClose: () => setConfirmFor(null),
|
|
5609
6025
|
onCancel: () => setConfirmFor(null),
|
|
5610
6026
|
onConfirm: () => {
|
|
6027
|
+
if (confirmPreviewState.loading || confirmPreviewState.error) return;
|
|
5611
6028
|
const target = confirmFor;
|
|
5612
6029
|
setConfirmFor(null);
|
|
5613
6030
|
runWithAlert("delete", () => onRemove(target.id));
|
|
5614
6031
|
},
|
|
5615
6032
|
title: t ? t("confirm.delete.title") : "删除会话",
|
|
5616
6033
|
description: (confirmFor && confirmFor.displayTitle && (t ? t("confirm.delete.desc", { title: confirmFor.displayTitle }) : ("「" + confirmFor.displayTitle + "」:删除,不可恢复"))) || "",
|
|
5617
|
-
warning: (
|
|
6034
|
+
warning: (() => {
|
|
6035
|
+
const baseWarn = (confirmFor && confirmFor.running && t ? t("confirm.delete.running") + " " : "") +
|
|
6036
|
+
(t ? t("bulk.dialog.warning.delete") : "删除操作不可撤销,请确认后再继续。");
|
|
6037
|
+
if (confirmPreviewState.loading) {
|
|
6038
|
+
const loadingMsg = (t ? t("confirm.delete.previewLoading") : "") || "正在检查关联的子智能体会话…";
|
|
6039
|
+
return `${loadingMsg}\n${baseWarn}`;
|
|
6040
|
+
}
|
|
6041
|
+
if (confirmPreviewState.error) {
|
|
6042
|
+
const errorMsg = confirmPreviewState.error;
|
|
6043
|
+
return `${errorMsg}\n${baseWarn}`;
|
|
6044
|
+
}
|
|
6045
|
+
const subagentsWarn = confirmPreviewState.subagentCount > 0
|
|
6046
|
+
? (t ? t("confirm.delete.subagents", { count: confirmPreviewState.subagentCount }) : `将连带删除 ${confirmPreviewState.subagentCount} 个关联的子智能体会话。`)
|
|
6047
|
+
: "";
|
|
6048
|
+
return subagentsWarn ? `${subagentsWarn}\n${baseWarn}` : baseWarn;
|
|
6049
|
+
})(),
|
|
6050
|
+
confirmDisabled: confirmPreviewState.loading || Boolean(confirmPreviewState.error),
|
|
5618
6051
|
confirmLabel: t ? t("confirm.delete.confirm") : "确认删除",
|
|
5619
6052
|
cancelLabel: t ? t("confirm.cancel") : "取消",
|
|
5620
6053
|
busy: false,
|
|
@@ -6011,18 +6444,6 @@ function isTopmostDialog(z) {
|
|
|
6011
6444
|
),
|
|
6012
6445
|
h("div", { className: "sm-settingsSection" },
|
|
6013
6446
|
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
6447
|
h("div", { className: "sm-settingsRow" },
|
|
6027
6448
|
h("span", null, t("update.autoCheck")),
|
|
6028
6449
|
h("label", { className: "sm-settingsCheckbox" },
|
|
@@ -6036,7 +6457,22 @@ function isTopmostDialog(z) {
|
|
|
6036
6457
|
)
|
|
6037
6458
|
),
|
|
6038
6459
|
h("div", { className: "sm-settingsRow" },
|
|
6039
|
-
h("span", null, t("settings.
|
|
6460
|
+
h("span", null, t("settings.registry")),
|
|
6461
|
+
h("select", {
|
|
6462
|
+
className: "sm-settingsSelect",
|
|
6463
|
+
value: currentRegistry,
|
|
6464
|
+
onChange: onRegistryChange,
|
|
6465
|
+
"aria-label": t("settings.registry")
|
|
6466
|
+
},
|
|
6467
|
+
h("option", { value: "registry.npmjs.org" }, t("settings.registry.npm")),
|
|
6468
|
+
h("option", { value: "registry.npmmirror.com" }, t("settings.registry.china"))
|
|
6469
|
+
)
|
|
6470
|
+
),
|
|
6471
|
+
h("div", { className: "sm-settingsRow" },
|
|
6472
|
+
h("div", { className: "sm-settingsRowLeft" },
|
|
6473
|
+
h("span", null, t("settings.dialogOpacity")),
|
|
6474
|
+
h("span", { className: "sm-settingsHint sm-settingsHintInline" }, t("settings.dialogOpacity.hint"))
|
|
6475
|
+
),
|
|
6040
6476
|
h("div", { className: "sm-settingsSlider" },
|
|
6041
6477
|
h("input", {
|
|
6042
6478
|
type: "range",
|
|
@@ -6060,39 +6496,42 @@ function isTopmostDialog(z) {
|
|
|
6060
6496
|
onClick: () => updateStore.resetDialogOpacity()
|
|
6061
6497
|
}, t("settings.dialogOpacity.reset"))
|
|
6062
6498
|
)
|
|
6063
|
-
)
|
|
6064
|
-
h("div", { className: "sm-settingsHint" }, t("settings.dialogOpacity.hint"))
|
|
6499
|
+
)
|
|
6065
6500
|
),
|
|
6066
6501
|
h("div", { className: "sm-settingsSection" },
|
|
6067
6502
|
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
|
-
|
|
6503
|
+
h("div", { className: "sm-settingsRow" },
|
|
6504
|
+
h("div", { className: "sm-settingsProjectLeft" },
|
|
6505
|
+
h("span", { className: "sm-settingsProjectLabel" }, t("settings.github")),
|
|
6506
|
+
h("a", {
|
|
6507
|
+
href: "https://github.com/hkkz9522/dsh-session-manager",
|
|
6508
|
+
target: "_blank",
|
|
6509
|
+
rel: "noopener noreferrer",
|
|
6510
|
+
className: "sm-settingsLink"
|
|
6511
|
+
}, "hkkz9522/dsh-session-manager")
|
|
6512
|
+
),
|
|
6513
|
+
h("div", { className: "sm-settingsBadgeActions" },
|
|
6514
|
+
renderTip(t("settings.star.tip"), h("a", {
|
|
6515
|
+
href: "https://github.com/hkkz9522/dsh-session-manager",
|
|
6516
|
+
target: "_blank",
|
|
6517
|
+
rel: "noopener noreferrer",
|
|
6518
|
+
className: "sm-settingsBadgeLink",
|
|
6519
|
+
"aria-label": t("settings.star.tip")
|
|
6520
|
+
},
|
|
6521
|
+
h(StarIcon, { size: 14 }),
|
|
6522
|
+
h("span", null, t("settings.star"))
|
|
6523
|
+
)),
|
|
6524
|
+
renderTip(t("settings.feedback.tip"), h("a", {
|
|
6525
|
+
href: "https://github.com/hkkz9522/dsh-session-manager/issues",
|
|
6526
|
+
target: "_blank",
|
|
6527
|
+
rel: "noopener noreferrer",
|
|
6528
|
+
className: "sm-settingsBadgeLink",
|
|
6529
|
+
"aria-label": t("settings.feedback.tip")
|
|
6530
|
+
},
|
|
6531
|
+
h(IssueIcon, { size: 14 }),
|
|
6532
|
+
h("span", null, t("settings.feedback"))
|
|
6533
|
+
))
|
|
6534
|
+
)
|
|
6096
6535
|
)
|
|
6097
6536
|
)
|
|
6098
6537
|
);
|
|
@@ -6186,7 +6625,18 @@ function isTopmostDialog(z) {
|
|
|
6186
6625
|
onRemove: async (sessionId) => {
|
|
6187
6626
|
const wasCurrent = isCurrentSession(sessionId);
|
|
6188
6627
|
const response = await callApi("/delete", { sessionId });
|
|
6189
|
-
if (!response.ok)
|
|
6628
|
+
if (!response.ok) {
|
|
6629
|
+
if (Array.isArray(response.deletedSubagents) && response.deletedSubagents.length > 0) {
|
|
6630
|
+
try { await annotationStore.load(true); } catch (_) {}
|
|
6631
|
+
try { await ctx.sessions?.refresh?.(); } catch (_) {}
|
|
6632
|
+
try { await ctx.workspaces?.refresh?.(); } catch (_) {}
|
|
6633
|
+
}
|
|
6634
|
+
const err = new Error(response.error || "delete failed");
|
|
6635
|
+
err.deletedSubagents = response.deletedSubagents || [];
|
|
6636
|
+
err.remainingSessions = response.remainingSessions || [sessionId];
|
|
6637
|
+
err.partialFailure = Boolean(response.partialFailure);
|
|
6638
|
+
throw err;
|
|
6639
|
+
}
|
|
6190
6640
|
await annotationStore.load(true);
|
|
6191
6641
|
if (response.result?.warning) window.alert(response.result.warning);
|
|
6192
6642
|
if (wasCurrent || isCurrentSession(sessionId)) {
|
|
@@ -6320,7 +6770,7 @@ function isTopmostDialog(z) {
|
|
|
6320
6770
|
ctx.effect(() => {
|
|
6321
6771
|
if (!updateStore.getAutoCheck()) return;
|
|
6322
6772
|
const timer = setTimeout(() => {
|
|
6323
|
-
updateStore.
|
|
6773
|
+
updateStore.maybeAutoCheck({ isStartup: true }).catch(() => {});
|
|
6324
6774
|
}, 1500);
|
|
6325
6775
|
return () => {
|
|
6326
6776
|
try {
|
|
@@ -6381,8 +6831,18 @@ function isTopmostDialog(z) {
|
|
|
6381
6831
|
exports.apply = apply;
|
|
6382
6832
|
exports.inject = inject;
|
|
6383
6833
|
exports.updateStore = updateStore;
|
|
6834
|
+
exports.panelStore = panelStore;
|
|
6384
6835
|
exports.compareSemver = compareSemver;
|
|
6836
|
+
exports.OverlayLayer = OverlayLayer;
|
|
6385
6837
|
exports.UpdateDialog = UpdateDialog;
|
|
6838
|
+
exports.ConfirmDialog = ConfirmDialog;
|
|
6839
|
+
exports.MoveDialog = MoveDialog;
|
|
6840
|
+
exports.MigratePresetDialog = MigratePresetDialog;
|
|
6841
|
+
exports.BatchPreviewDialog = BatchPreviewDialog;
|
|
6842
|
+
exports.BatchResultDialog = BatchResultDialog;
|
|
6843
|
+
exports.BulkTagInputDialog = BulkTagInputDialog;
|
|
6844
|
+
exports.BulkChoiceDialog = BulkChoiceDialog;
|
|
6845
|
+
exports.AnnotationDialog = AnnotationDialog;
|
|
6386
6846
|
exports.SessionManagerSettingsCard = SessionManagerSettingsCard;
|
|
6387
6847
|
exports.WhaleIcon = WhaleIcon;
|
|
6388
6848
|
exports.NpmIcon = NpmIcon;
|