@linxin666/dsh-ssh 0.3.19 → 0.3.21
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/README.i18n.yaml +2 -2
- package/README.md +10 -4
- package/README.zh.md +10 -4
- package/lib/client.js +252 -38
- package/lib/client.js.map +1 -1
- package/lib/index.js +504 -52
- package/lib/types/client/body-mutations.d.ts +45 -0
- package/lib/types/client/locales.d.ts +9 -1
- package/lib/types/client/panel/TunnelsTab.d.ts +4 -2
- package/lib/types/client/panel-mount-core.d.ts +1 -1
- package/lib/types/client/sidebar-entry-core.d.ts +0 -15
- package/lib/types/engine/connection-pool.d.ts +20 -0
- package/lib/types/engine/proxy-command.d.ts +36 -0
- package/lib/types/index.d.ts +1 -1
- package/lib/types/protocol.d.ts +24 -2
- package/lib/types/ssh-config.d.ts +34 -0
- package/lib/types/store.d.ts +11 -3
- package/lib/types/tools.d.ts +24 -0
- package/package.json +14 -14
- package/src/client/body-mutations.ts +133 -0
- package/src/client/locales.ts +18 -2
- package/src/client/panel/HostFormDialog.tsx +15 -0
- package/src/client/panel/HostsTab.tsx +37 -2
- package/src/client/panel/SshPanel.tsx +6 -2
- package/src/client/panel/TunnelsTab.tsx +50 -10
- package/src/client/panel/panel.module.css +27 -0
- package/src/client/panel-mount-core.ts +21 -13
- package/src/client/sidebar-entry-core.ts +10 -7
- package/src/engine/connection-pool.ts +122 -10
- package/src/engine/proxy-command.ts +248 -0
- package/src/index.ts +1 -1
- package/src/protocol.ts +26 -2
- package/src/routes.ts +1 -1
- package/src/ssh-config.ts +153 -0
- package/src/store.ts +64 -40
- package/src/tools.ts +35 -5
package/lib/client.js
CHANGED
|
@@ -63,6 +63,12 @@ window.__ModuleLoader__.load({
|
|
|
63
63
|
"hosts.delete": "删除",
|
|
64
64
|
"hosts.deleteConfirm": "确定删除主机「{alias}」?将同时停止其隧道。",
|
|
65
65
|
"hosts.imported": "解析 {parsed} 个配置块,新增 {added} 台主机,跳过 {skipped} 个。",
|
|
66
|
+
"hosts.proxyBadge": "代理",
|
|
67
|
+
"import.reason.wildcard": "通配符 pattern,需手动配置",
|
|
68
|
+
"import.reason.existing": "别名已存在",
|
|
69
|
+
"import.reason.match": "Match 条件块,不支持",
|
|
70
|
+
"import.reason.invalid": "字段不合法,无法导入",
|
|
71
|
+
"import.more": "其余 {count} 个未显示",
|
|
66
72
|
"hosts.testing": "连接测试中…",
|
|
67
73
|
"hosts.testOk": "连接成功({latency} ms)",
|
|
68
74
|
"hosts.testFail": "连接失败:{error}",
|
|
@@ -89,7 +95,9 @@ window.__ModuleLoader__.load({
|
|
|
89
95
|
"form.passwordHint": "明文保存在 $DSH_HOME/dsh-ssh.json(本机私有文件)",
|
|
90
96
|
"form.passwordRequired": "密码认证需要填写密码。",
|
|
91
97
|
"form.proxyJump": "跳板机别名",
|
|
92
|
-
"form.proxyJumpHint": "
|
|
98
|
+
"form.proxyJumpHint": "逗号分隔的本地主机别名,或 [user@]host[:port] 地址,按顺序连接",
|
|
99
|
+
"form.proxyCommand": "ProxyCommand",
|
|
100
|
+
"form.proxyCommandHint": "OpenSSH ProxyCommand:%h 主机、%p 端口、%r 用户、%n 别名;留空或填 none 表示不使用。与跳板机别名互斥。",
|
|
93
101
|
"form.description": "备注",
|
|
94
102
|
"form.environment": "环境",
|
|
95
103
|
"form.environmentHint": "如 development / production",
|
|
@@ -210,6 +218,12 @@ window.__ModuleLoader__.load({
|
|
|
210
218
|
"hosts.delete": "Delete",
|
|
211
219
|
"hosts.deleteConfirm": "Delete host \"{alias}\"? Its tunnels will be stopped.",
|
|
212
220
|
"hosts.imported": "Parsed {parsed} blocks, added {added} hosts, skipped {skipped}.",
|
|
221
|
+
"hosts.proxyBadge": "proxy",
|
|
222
|
+
"import.reason.wildcard": "wildcard pattern — configure it by hand",
|
|
223
|
+
"import.reason.existing": "alias already configured",
|
|
224
|
+
"import.reason.match": "Match block — not supported",
|
|
225
|
+
"import.reason.invalid": "invalid fields — not imported",
|
|
226
|
+
"import.more": "{count} more not shown",
|
|
213
227
|
"hosts.testing": "Testing connection…",
|
|
214
228
|
"hosts.testOk": "Connected ({latency} ms)",
|
|
215
229
|
"hosts.testFail": "Connection failed: {error}",
|
|
@@ -236,7 +250,9 @@ window.__ModuleLoader__.load({
|
|
|
236
250
|
"form.passwordHint": "Stored in plaintext in $DSH_HOME/dsh-ssh.json (private local file)",
|
|
237
251
|
"form.passwordRequired": "Password auth requires a password.",
|
|
238
252
|
"form.proxyJump": "Jump host aliases",
|
|
239
|
-
"form.proxyJumpHint": "Comma-separated local aliases, chained in order",
|
|
253
|
+
"form.proxyJumpHint": "Comma-separated local aliases or [user@]host[:port] addresses, chained in order",
|
|
254
|
+
"form.proxyCommand": "ProxyCommand",
|
|
255
|
+
"form.proxyCommandHint": "OpenSSH ProxyCommand: %h host, %p port, %r user, %n alias; empty or none disables it. Mutually exclusive with the jump chain.",
|
|
240
256
|
"form.description": "Description",
|
|
241
257
|
"form.environment": "Environment",
|
|
242
258
|
"form.environmentHint": "e.g. development / production",
|
|
@@ -689,7 +705,7 @@ window.__ModuleLoader__.load({
|
|
|
689
705
|
};
|
|
690
706
|
//#endregion
|
|
691
707
|
//#region \0dsh-css:packages/dsh-ssh/src/client/panel/panel.module.css.mjs
|
|
692
|
-
const css = "[data-pane=conversation],[class*=centerCol]{position:relative}[data-dsh-ssh-view]{z-index:60;background:var(--dsw-alias-bg-base);display:none;position:absolute;inset:0}html[data-dsh-ssh-active]:not([data-dsh-taskboard-active]) [data-dsh-ssh-view]{display:block}html[data-dsh-ssh-active]:not([data-dsh-taskboard-active]) [data-pane=conversation]>:not([data-dsh-ssh-view]),html[data-dsh-ssh-active]:not([data-dsh-taskboard-active]) [class*=centerCol]>:not([data-dsh-ssh-view]){display:none!important}.mL8Uca_entry{box-sizing:border-box;width:100%;min-height:36px;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-radius:8px;align-items:center;gap:10px;padding:0 10px;font-size:13px;display:flex}.mL8Uca_entry:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.mL8Uca_entry[data-active]{background:var(--dsw-alias-interactive-bg-active);color:var(--dsw-alias-label-primary);font-weight:600}.mL8Uca_entryIcon{flex:none;justify-content:center;align-items:center;width:24px;height:24px;display:inline-flex}.mL8Uca_entryIcon svg{width:18px;height:18px;display:block}.mL8Uca_entryLabel{text-overflow:ellipsis;overflow:hidden}[data-dsh-frame][data-sidebar-collapsed] .mL8Uca_entry,[data-sidebar-collapsed] .mL8Uca_entry{border-radius:50%;justify-content:center;width:36px;min-height:36px;margin:0 auto 12px;padding:0}[data-dsh-frame][data-sidebar-collapsed] .mL8Uca_entryLabel,[data-sidebar-collapsed] .mL8Uca_entryLabel{display:none}.mL8Uca_view{overflow:hidden}.mL8Uca_panel{background:var(--dsw-alias-bg-base);min-width:0;height:100%;min-height:0;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-family);flex-direction:column;gap:10px;padding:14px 16px 16px;display:flex}.mL8Uca_panelHeader{flex:none;align-items:center;gap:10px;display:flex}.mL8Uca_panelTitle{color:var(--dsw-alias-label-primary);white-space:nowrap;flex:1;margin:0;font-size:16px;font-weight:700}.mL8Uca_backButton{align-items:center;gap:4px;display:inline-flex}.mL8Uca_tabBar{border-bottom:1px solid var(--dsw-alias-border-l1);flex:none;gap:2px;display:flex}.mL8Uca_tab{color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-bottom:2px solid #0000;border-radius:6px 6px 0 0;padding:7px 14px;font-size:13px}.mL8Uca_tab:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}.mL8Uca_tab[data-active]{color:var(--dsw-alias-label-primary);border-bottom-color:var(--dsw-alias-state-business-primary);font-weight:600}.mL8Uca_panelContent{flex-direction:column;flex:1;min-height:0;display:flex;overflow:hidden}.mL8Uca_tabBody{flex-direction:column;flex:1;gap:10px;min-height:0;display:flex;overflow-y:auto}.mL8Uca_fillBody{flex-direction:column;flex:1;gap:10px;min-height:0;display:flex;overflow:hidden}.mL8Uca_toolbar,.mL8Uca_controls{flex-wrap:wrap;flex:none;align-items:center;gap:8px;display:flex}.mL8Uca_controls .mL8Uca_input{flex:0 260px;min-width:150px}.mL8Uca_toolbarSpacer{flex:1}.mL8Uca_search{min-width:120px;color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;outline:none;flex:0 260px;padding:6px 10px;font-size:13px}.mL8Uca_search::placeholder{color:var(--dsw-alias-label-tertiary)}.mL8Uca_groupBySelect{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;outline:none;padding:6px 8px;font-size:13px}.mL8Uca_groupSection+.mL8Uca_groupSection{border-top:1px solid var(--dsw-alias-border-l1)}.mL8Uca_groupHeader{background:var(--dsw-alias-bg-base,var(--dsw-specific-input-major));align-items:center;gap:8px;padding:4px 8px;display:flex;position:sticky;top:0}.mL8Uca_groupToggle{min-width:0;color:var(--dsw-alias-label-primary);cursor:pointer;text-align:left;background:0 0;border:none;border-radius:6px;flex:1;align-items:center;gap:6px;padding:4px 6px;font-size:12.5px;font-weight:500;display:flex}.mL8Uca_groupToggle:hover{background:var(--dsw-alias-interactive-bg-hover)}.mL8Uca_groupChevron{border-right:1.5px solid var(--dsw-alias-label-tertiary);border-bottom:1.5px solid var(--dsw-alias-label-tertiary);flex:none;width:7px;height:7px;margin-bottom:2px;transition:transform .12s;transform:rotate(45deg)}.mL8Uca_groupChevron[data-collapsed]{margin-bottom:0;transform:rotate(-45deg)}.mL8Uca_groupName{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.mL8Uca_groupCount{color:var(--dsw-alias-label-tertiary);flex:none;font-weight:400}.mL8Uca_tableWrap{border:1px solid var(--dsw-alias-border-l1);border-radius:10px;flex:1;min-height:0;overflow:auto}.mL8Uca_table{border-collapse:collapse;width:100%;font-size:12.5px}.mL8Uca_table th{z-index:1;text-align:left;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary);border-bottom:1px solid var(--dsw-alias-border-l1);white-space:nowrap;padding:8px 10px;font-weight:600;position:sticky;top:0}.mL8Uca_table td{border-bottom:1px solid var(--dsw-alias-separator-primary);vertical-align:top;padding:7px 10px}.mL8Uca_table tbody tr:last-child td{border-bottom:none}.mL8Uca_table tbody tr:hover td{background:var(--dsw-alias-interactive-bg-hover)}.mL8Uca_mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}.mL8Uca_cellMuted{color:var(--dsw-alias-label-tertiary)}.mL8Uca_actions{white-space:nowrap;align-items:center;gap:8px;display:flex}.mL8Uca_inlineTest{color:var(--dsw-alias-label-secondary);align-items:center;gap:6px;font-size:11.5px;display:inline-flex}.mL8Uca_inlineTest[data-status=ok]{color:var(--dsw-alias-state-success-primary)}.mL8Uca_inlineTest[data-status=fail]{color:var(--dsw-alias-state-error-primary)}.mL8Uca_badge{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);white-space:nowrap;border-radius:999px;padding:1px 8px;font-size:11px;line-height:1.6;display:inline-block}.mL8Uca_badge[data-kind=key]{color:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary)}.mL8Uca_badge[data-kind=password]{color:var(--dsw-alias-state-warn-primary);border-color:var(--dsw-alias-state-warn-primary)}.mL8Uca_badge[data-kind=agent],.mL8Uca_badge[data-status=ok]{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}.mL8Uca_badge[data-status=fail]{color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary)}.mL8Uca_badge[data-status=timeout]{color:var(--dsw-alias-state-warn-primary);border-color:var(--dsw-alias-state-warn-primary)}.mL8Uca_primaryButton{color:var(--dsw-alias-label-primary-foreground);background:var(--dsw-alias-button-info-fill);cursor:pointer;white-space:nowrap;border:none;border-radius:8px;padding:6px 14px;font-size:13px;font-weight:600}.mL8Uca_primaryButton:hover:not(:disabled){background:var(--dsw-alias-button-info-hover)}.mL8Uca_primaryButton:disabled{opacity:.5;cursor:default}.mL8Uca_ghostButton{color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;white-space:nowrap;background:0 0;border-radius:8px;padding:5px 12px;font-size:12px}.mL8Uca_ghostButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.mL8Uca_ghostButton:disabled{opacity:.45;cursor:default}.mL8Uca_iconButton{width:26px;height:26px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;padding:0;font-size:13px;display:inline-flex}.mL8Uca_iconButton:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.mL8Uca_linkButton{color:var(--dsw-alias-state-business-primary);cursor:pointer;white-space:nowrap;background:0 0;border:none;padding:0;font-size:12px}.mL8Uca_linkButton:hover:not(:disabled){text-decoration:underline}.mL8Uca_linkButton:disabled{opacity:.45;cursor:default}.mL8Uca_linkButton[data-danger]{color:var(--dsw-alias-state-error-primary)}.mL8Uca_spinner{border:2px solid var(--dsw-alias-state-business-primary);vertical-align:-1px;border-top-color:#0000;border-radius:50%;flex:none;width:11px;height:11px;animation:.8s linear infinite mL8Uca_dshSshSpin;display:inline-block}@keyframes mL8Uca_dshSshSpin{to{transform:rotate(360deg)}}.mL8Uca_banner{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;border-radius:8px;padding:8px 12px;font-size:12.5px;line-height:1.5}.mL8Uca_banner[data-kind=ok]{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}.mL8Uca_banner[data-kind=error]{color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary)}.mL8Uca_banner[data-kind=info]{color:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary)}.mL8Uca_empty,.mL8Uca_loading{text-align:center;color:var(--dsw-alias-label-tertiary);padding:28px 12px;font-size:12.5px}.mL8Uca_modalBackdrop{z-index:40;background:var(--dsw-alias-bg-mask-1);justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.mL8Uca_modal{background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);width:min(560px,100vw - 48px);max-height:calc(100vh - 96px);box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);border-radius:14px;flex-direction:column;gap:12px;padding:18px;display:flex;overflow-y:auto}.mL8Uca_modalTitle{margin:0;font-size:15px;font-weight:700}.mL8Uca_modalFooter{justify-content:flex-end;gap:10px;margin-top:4px;display:flex}.mL8Uca_formError{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px}.mL8Uca_hint{color:var(--dsw-alias-label-tertiary);font-size:11.5px}.mL8Uca_field{flex-direction:column;gap:5px;display:flex}.mL8Uca_fieldLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600}.mL8Uca_input{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);resize:vertical;border-radius:8px;outline:none;padding:7px 10px;font-family:inherit;font-size:13px}.mL8Uca_input:focus{border-color:var(--dsw-alias-state-business-primary)}.mL8Uca_input::placeholder{color:var(--dsw-alias-label-tertiary)}.mL8Uca_input:disabled{opacity:.55}.mL8Uca_formRow{grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px 12px;display:grid}.mL8Uca_radioRow{align-items:center;gap:16px;display:flex}.mL8Uca_radioLabel{color:var(--dsw-alias-label-primary);cursor:pointer;align-items:center;gap:6px;font-size:13px;display:inline-flex}.mL8Uca_termBody{flex-direction:column;flex:1;gap:8px;min-height:0;display:flex;overflow:hidden}.mL8Uca_termWrap{border:1px solid var(--dsw-alias-border-l1);background:#0b0e14;border-radius:10px;flex:1;min-height:0;position:relative;overflow:hidden}.mL8Uca_termContainer{position:absolute;inset:8px 10px}.mL8Uca_termPlaceholder{z-index:2;text-align:center;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-base);justify-content:center;align-items:center;padding:0 24px;font-size:12.5px;display:flex;position:absolute;inset:0}.mL8Uca_hiddenFile{display:none}.mL8Uca_browsePanel{border:1px solid var(--dsw-alias-border-l1);border-radius:10px;flex-direction:column;flex:none;display:flex;overflow:hidden}.mL8Uca_browseHeader{background:var(--dsw-alias-bg-layer-2);border-bottom:1px solid var(--dsw-alias-border-l1);align-items:center;gap:8px;padding:8px 10px;display:flex}.mL8Uca_browsePath{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-secondary);flex:1;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12px;overflow:hidden}.mL8Uca_browseList{max-height:240px;overflow-y:auto}.mL8Uca_dirRow{text-align:left;width:100%;font:inherit;color:var(--dsw-alias-label-primary);border:none;border-bottom:1px solid var(--dsw-alias-separator-primary);cursor:pointer;background:0 0;grid-template-columns:minmax(0,1fr) auto auto;gap:12px;padding:5px 10px;font-size:12.5px;display:grid}.mL8Uca_dirRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.mL8Uca_dirRow[data-type=dir] .mL8Uca_dirName{color:var(--dsw-alias-state-business-primary)}.mL8Uca_dirRow[data-up]{color:var(--dsw-alias-label-secondary)}.mL8Uca_dirName{text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;overflow:hidden}.mL8Uca_dirType{color:var(--dsw-alias-label-tertiary);white-space:nowrap}.mL8Uca_dirSize{color:var(--dsw-alias-label-tertiary);white-space:nowrap;text-align:right}.mL8Uca_transferBlock{flex-direction:column;flex:none;gap:6px;display:flex}.mL8Uca_progressMeta{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;gap:12px;font-size:12px;display:flex}.mL8Uca_progressTrack{background:var(--dsw-alias-interactive-bg-hover);border-radius:999px;height:8px;overflow:hidden}.mL8Uca_progressBar{background:var(--dsw-alias-state-business-primary);border-radius:999px;height:100%;transition:width .12s linear}.mL8Uca_tunnelList{flex-direction:column;flex:none;gap:8px;display:flex}.mL8Uca_tunnelRow{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;align-items:center;gap:10px;padding:8px 12px;display:flex}.mL8Uca_tunnelRow[data-state=forwarding]{border-color:var(--dsw-alias-state-success-primary)}.mL8Uca_tunnelRow[data-state=connecting]{border-color:var(--dsw-alias-state-warn-primary)}.mL8Uca_tunnelRow[data-state=failed]{border-color:var(--dsw-alias-state-error-primary)}.mL8Uca_tunnelLabel{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12.5px;overflow:hidden}.mL8Uca_formCard{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;flex-direction:column;flex:none;gap:10px;padding:12px;display:flex}.mL8Uca_clusterForm{flex-direction:column;flex:none;gap:8px;display:flex}.mL8Uca_clusterFilters{grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:10px;display:grid}.mL8Uca_commandInput{min-height:96px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}.mL8Uca_cellDetails summary{cursor:pointer;color:var(--dsw-alias-label-secondary);font-size:12px}.mL8Uca_cellPre{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);white-space:pre-wrap;word-break:break-all;border-radius:6px;max-height:180px;margin:4px 0 0;padding:6px 8px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11.5px;overflow:auto}";
|
|
708
|
+
const css = "[data-pane=conversation],[class*=centerCol]{position:relative}[data-dsh-ssh-view]{z-index:60;background:var(--dsw-alias-bg-base);display:none;position:absolute;inset:0}html[data-dsh-ssh-active]:not([data-dsh-taskboard-active]) [data-dsh-ssh-view]{display:block}html[data-dsh-ssh-active]:not([data-dsh-taskboard-active]) [data-pane=conversation]>:not([data-dsh-ssh-view]),html[data-dsh-ssh-active]:not([data-dsh-taskboard-active]) [class*=centerCol]>:not([data-dsh-ssh-view]){display:none!important}.mL8Uca_entry{box-sizing:border-box;width:100%;min-height:36px;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-radius:8px;align-items:center;gap:10px;padding:0 10px;font-size:13px;display:flex}.mL8Uca_entry:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.mL8Uca_entry[data-active]{background:var(--dsw-alias-interactive-bg-active);color:var(--dsw-alias-label-primary);font-weight:600}.mL8Uca_entryIcon{flex:none;justify-content:center;align-items:center;width:24px;height:24px;display:inline-flex}.mL8Uca_entryIcon svg{width:18px;height:18px;display:block}.mL8Uca_entryLabel{text-overflow:ellipsis;overflow:hidden}[data-dsh-frame][data-sidebar-collapsed] .mL8Uca_entry,[data-sidebar-collapsed] .mL8Uca_entry{border-radius:50%;justify-content:center;width:36px;min-height:36px;margin:0 auto 12px;padding:0}[data-dsh-frame][data-sidebar-collapsed] .mL8Uca_entryLabel,[data-sidebar-collapsed] .mL8Uca_entryLabel{display:none}.mL8Uca_view{overflow:hidden}.mL8Uca_panel{background:var(--dsw-alias-bg-base);min-width:0;height:100%;min-height:0;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-family);flex-direction:column;gap:10px;padding:14px 16px 16px;display:flex}.mL8Uca_panelHeader{flex:none;align-items:center;gap:10px;display:flex}.mL8Uca_panelTitle{color:var(--dsw-alias-label-primary);white-space:nowrap;flex:1;margin:0;font-size:16px;font-weight:700}.mL8Uca_backButton{align-items:center;gap:4px;display:inline-flex}.mL8Uca_tabBar{border-bottom:1px solid var(--dsw-alias-border-l1);flex:none;gap:2px;display:flex}.mL8Uca_tab{color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-bottom:2px solid #0000;border-radius:6px 6px 0 0;padding:7px 14px;font-size:13px}.mL8Uca_tab:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}.mL8Uca_tab[data-active]{color:var(--dsw-alias-label-primary);border-bottom-color:var(--dsw-alias-state-business-primary);font-weight:600}.mL8Uca_panelContent{flex-direction:column;flex:1;min-height:0;display:flex;overflow:hidden}.mL8Uca_tabBody{flex-direction:column;flex:1;gap:10px;min-height:0;display:flex;overflow-y:auto}.mL8Uca_fillBody{flex-direction:column;flex:1;gap:10px;min-height:0;display:flex;overflow:hidden}.mL8Uca_toolbar,.mL8Uca_controls{flex-wrap:wrap;flex:none;align-items:center;gap:8px;display:flex}.mL8Uca_controls .mL8Uca_input{flex:0 260px;min-width:150px}.mL8Uca_toolbarSpacer{flex:1}.mL8Uca_search{min-width:120px;color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;outline:none;flex:0 260px;padding:6px 10px;font-size:13px}.mL8Uca_search::placeholder{color:var(--dsw-alias-label-tertiary)}.mL8Uca_groupBySelect{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;outline:none;padding:6px 8px;font-size:13px}.mL8Uca_groupSection+.mL8Uca_groupSection{border-top:1px solid var(--dsw-alias-border-l1)}.mL8Uca_groupHeader{background:var(--dsw-alias-bg-base,var(--dsw-specific-input-major));align-items:center;gap:8px;padding:4px 8px;display:flex;position:sticky;top:0}.mL8Uca_groupToggle{min-width:0;color:var(--dsw-alias-label-primary);cursor:pointer;text-align:left;background:0 0;border:none;border-radius:6px;flex:1;align-items:center;gap:6px;padding:4px 6px;font-size:12.5px;font-weight:500;display:flex}.mL8Uca_groupToggle:hover{background:var(--dsw-alias-interactive-bg-hover)}.mL8Uca_groupChevron{border-right:1.5px solid var(--dsw-alias-label-tertiary);border-bottom:1.5px solid var(--dsw-alias-label-tertiary);flex:none;width:7px;height:7px;margin-bottom:2px;transition:transform .12s;transform:rotate(45deg)}.mL8Uca_groupChevron[data-collapsed]{margin-bottom:0;transform:rotate(-45deg)}.mL8Uca_groupName{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.mL8Uca_groupCount{color:var(--dsw-alias-label-tertiary);flex:none;font-weight:400}.mL8Uca_tableWrap{border:1px solid var(--dsw-alias-border-l1);border-radius:10px;flex:1;min-height:0;overflow:auto}.mL8Uca_table{border-collapse:collapse;width:100%;font-size:12.5px}.mL8Uca_table th{z-index:1;text-align:left;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary);border-bottom:1px solid var(--dsw-alias-border-l1);white-space:nowrap;padding:8px 10px;font-weight:600;position:sticky;top:0}.mL8Uca_table td{border-bottom:1px solid var(--dsw-alias-separator-primary);vertical-align:top;padding:7px 10px}.mL8Uca_table tbody tr:last-child td{border-bottom:none}.mL8Uca_table tbody tr:hover td{background:var(--dsw-alias-interactive-bg-hover)}.mL8Uca_mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}.mL8Uca_cellMuted{color:var(--dsw-alias-label-tertiary)}.mL8Uca_actions{white-space:nowrap;align-items:center;gap:8px;display:flex}.mL8Uca_inlineTest{color:var(--dsw-alias-label-secondary);align-items:center;gap:6px;font-size:11.5px;display:inline-flex}.mL8Uca_inlineTest[data-status=ok]{color:var(--dsw-alias-state-success-primary)}.mL8Uca_inlineTest[data-status=fail]{color:var(--dsw-alias-state-error-primary)}.mL8Uca_badge{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);white-space:nowrap;border-radius:999px;padding:1px 8px;font-size:11px;line-height:1.6;display:inline-block}.mL8Uca_badge[data-kind=key]{color:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary)}.mL8Uca_badge[data-kind=password]{color:var(--dsw-alias-state-warn-primary);border-color:var(--dsw-alias-state-warn-primary)}.mL8Uca_badge[data-kind=agent]{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}.mL8Uca_badge[data-kind=proxy]{color:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);margin-left:6px}.mL8Uca_badge[data-status=ok]{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}.mL8Uca_badge[data-status=fail]{color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary)}.mL8Uca_badge[data-status=timeout]{color:var(--dsw-alias-state-warn-primary);border-color:var(--dsw-alias-state-warn-primary)}.mL8Uca_primaryButton{color:var(--dsw-alias-label-primary-foreground);background:var(--dsw-alias-button-info-fill);cursor:pointer;white-space:nowrap;border:none;border-radius:8px;padding:6px 14px;font-size:13px;font-weight:600}.mL8Uca_primaryButton:hover:not(:disabled){background:var(--dsw-alias-button-info-hover)}.mL8Uca_primaryButton:disabled{opacity:.5;cursor:default}.mL8Uca_ghostButton{color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;white-space:nowrap;background:0 0;border-radius:8px;padding:5px 12px;font-size:12px}.mL8Uca_ghostButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.mL8Uca_ghostButton:disabled{opacity:.45;cursor:default}.mL8Uca_iconButton{width:26px;height:26px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;padding:0;font-size:13px;display:inline-flex}.mL8Uca_iconButton:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.mL8Uca_linkButton{color:var(--dsw-alias-state-business-primary);cursor:pointer;white-space:nowrap;background:0 0;border:none;padding:0;font-size:12px}.mL8Uca_linkButton:hover:not(:disabled){text-decoration:underline}.mL8Uca_linkButton:disabled{opacity:.45;cursor:default}.mL8Uca_linkButton[data-danger]{color:var(--dsw-alias-state-error-primary)}.mL8Uca_spinner{border:2px solid var(--dsw-alias-state-business-primary);vertical-align:-1px;border-top-color:#0000;border-radius:50%;flex:none;width:11px;height:11px;animation:.8s linear infinite mL8Uca_dshSshSpin;display:inline-block}@keyframes mL8Uca_dshSshSpin{to{transform:rotate(360deg)}}.mL8Uca_banner{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;border-radius:8px;padding:8px 12px;font-size:12.5px;line-height:1.5}.mL8Uca_importSkips{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);border-radius:8px;flex-direction:column;gap:4px;margin:6px 0 0;padding:8px 12px;list-style:none;display:flex}.mL8Uca_importSkipRow{justify-content:space-between;align-items:baseline;gap:12px;font-size:12px;display:flex}.mL8Uca_banner[data-kind=ok]{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}.mL8Uca_banner[data-kind=error]{color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary)}.mL8Uca_banner[data-kind=info]{color:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary)}.mL8Uca_empty,.mL8Uca_loading{text-align:center;color:var(--dsw-alias-label-tertiary);padding:28px 12px;font-size:12.5px}.mL8Uca_modalBackdrop{z-index:40;background:var(--dsw-alias-bg-mask-1);justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.mL8Uca_modal{background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);width:min(560px,100vw - 48px);max-height:calc(100vh - 96px);box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);border-radius:14px;flex-direction:column;gap:12px;padding:18px;display:flex;overflow-y:auto}.mL8Uca_modalTitle{margin:0;font-size:15px;font-weight:700}.mL8Uca_modalFooter{justify-content:flex-end;gap:10px;margin-top:4px;display:flex}.mL8Uca_formError{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px}.mL8Uca_hint{color:var(--dsw-alias-label-tertiary);font-size:11.5px}.mL8Uca_field{flex-direction:column;gap:5px;display:flex}.mL8Uca_fieldLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600}.mL8Uca_input{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);resize:vertical;border-radius:8px;outline:none;padding:7px 10px;font-family:inherit;font-size:13px}.mL8Uca_input:focus{border-color:var(--dsw-alias-state-business-primary)}.mL8Uca_input::placeholder{color:var(--dsw-alias-label-tertiary)}.mL8Uca_input:disabled{opacity:.55}.mL8Uca_formRow{grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px 12px;display:grid}.mL8Uca_radioRow{align-items:center;gap:16px;display:flex}.mL8Uca_radioLabel{color:var(--dsw-alias-label-primary);cursor:pointer;align-items:center;gap:6px;font-size:13px;display:inline-flex}.mL8Uca_termBody{flex-direction:column;flex:1;gap:8px;min-height:0;display:flex;overflow:hidden}.mL8Uca_termWrap{border:1px solid var(--dsw-alias-border-l1);background:#0b0e14;border-radius:10px;flex:1;min-height:0;position:relative;overflow:hidden}.mL8Uca_termContainer{position:absolute;inset:8px 10px}.mL8Uca_termPlaceholder{z-index:2;text-align:center;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-base);justify-content:center;align-items:center;padding:0 24px;font-size:12.5px;display:flex;position:absolute;inset:0}.mL8Uca_hiddenFile{display:none}.mL8Uca_browsePanel{border:1px solid var(--dsw-alias-border-l1);border-radius:10px;flex-direction:column;flex:none;display:flex;overflow:hidden}.mL8Uca_browseHeader{background:var(--dsw-alias-bg-layer-2);border-bottom:1px solid var(--dsw-alias-border-l1);align-items:center;gap:8px;padding:8px 10px;display:flex}.mL8Uca_browsePath{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-secondary);flex:1;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12px;overflow:hidden}.mL8Uca_browseList{max-height:240px;overflow-y:auto}.mL8Uca_dirRow{text-align:left;width:100%;font:inherit;color:var(--dsw-alias-label-primary);border:none;border-bottom:1px solid var(--dsw-alias-separator-primary);cursor:pointer;background:0 0;grid-template-columns:minmax(0,1fr) auto auto;gap:12px;padding:5px 10px;font-size:12.5px;display:grid}.mL8Uca_dirRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.mL8Uca_dirRow[data-type=dir] .mL8Uca_dirName{color:var(--dsw-alias-state-business-primary)}.mL8Uca_dirRow[data-up]{color:var(--dsw-alias-label-secondary)}.mL8Uca_dirName{text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;overflow:hidden}.mL8Uca_dirType{color:var(--dsw-alias-label-tertiary);white-space:nowrap}.mL8Uca_dirSize{color:var(--dsw-alias-label-tertiary);white-space:nowrap;text-align:right}.mL8Uca_transferBlock{flex-direction:column;flex:none;gap:6px;display:flex}.mL8Uca_progressMeta{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;gap:12px;font-size:12px;display:flex}.mL8Uca_progressTrack{background:var(--dsw-alias-interactive-bg-hover);border-radius:999px;height:8px;overflow:hidden}.mL8Uca_progressBar{background:var(--dsw-alias-state-business-primary);border-radius:999px;height:100%;transition:width .12s linear}.mL8Uca_tunnelList{flex-direction:column;flex:none;gap:8px;display:flex}.mL8Uca_tunnelRow{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;align-items:center;gap:10px;padding:8px 12px;display:flex}.mL8Uca_tunnelRow[data-state=forwarding]{border-color:var(--dsw-alias-state-success-primary)}.mL8Uca_tunnelRow[data-state=connecting]{border-color:var(--dsw-alias-state-warn-primary)}.mL8Uca_tunnelRow[data-state=failed]{border-color:var(--dsw-alias-state-error-primary)}.mL8Uca_tunnelLabel{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12.5px;overflow:hidden}.mL8Uca_formCard{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;flex-direction:column;flex:none;gap:10px;padding:12px;display:flex}.mL8Uca_clusterForm{flex-direction:column;flex:none;gap:8px;display:flex}.mL8Uca_clusterFilters{grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:10px;display:grid}.mL8Uca_commandInput{min-height:96px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}.mL8Uca_cellDetails summary{cursor:pointer;color:var(--dsw-alias-label-secondary);font-size:12px}.mL8Uca_cellPre{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);white-space:pre-wrap;word-break:break-all;border-radius:6px;max-height:180px;margin:4px 0 0;padding:6px 8px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11.5px;overflow:auto}";
|
|
693
709
|
const tagId = "@linxin666/dsh-ssh/packages/dsh-ssh/src/client/panel/panel.module.css";
|
|
694
710
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
695
711
|
const tag = document.createElement("style");
|
|
@@ -740,6 +756,8 @@ window.__ModuleLoader__.load({
|
|
|
740
756
|
"hiddenFile": "mL8Uca_hiddenFile",
|
|
741
757
|
"hint": "mL8Uca_hint",
|
|
742
758
|
"iconButton": "mL8Uca_iconButton",
|
|
759
|
+
"importSkipRow": "mL8Uca_importSkipRow",
|
|
760
|
+
"importSkips": "mL8Uca_importSkips",
|
|
743
761
|
"inlineTest": "mL8Uca_inlineTest",
|
|
744
762
|
"input": "mL8Uca_input",
|
|
745
763
|
"linkButton": "mL8Uca_linkButton",
|
|
@@ -974,6 +992,7 @@ window.__ModuleLoader__.load({
|
|
|
974
992
|
password: "",
|
|
975
993
|
agentPath: "",
|
|
976
994
|
proxyJump: (editing?.proxyJump ?? []).join(", "),
|
|
995
|
+
proxyCommand: editing?.proxyCommand ?? "",
|
|
977
996
|
description: editing?.description ?? "",
|
|
978
997
|
environment: editing?.environment ?? "",
|
|
979
998
|
tags: (editing?.tags ?? []).join(", "),
|
|
@@ -1034,6 +1053,7 @@ window.__ModuleLoader__.load({
|
|
|
1034
1053
|
agentPath: form.agentPath.trim() === "" ? void 0 : form.agentPath.trim()
|
|
1035
1054
|
},
|
|
1036
1055
|
proxyJump: splitList(form.proxyJump),
|
|
1056
|
+
proxyCommand: form.proxyCommand.trim(),
|
|
1037
1057
|
description: form.description.trim() === "" ? void 0 : form.description.trim(),
|
|
1038
1058
|
environment: form.environment.trim() === "" ? void 0 : form.environment.trim(),
|
|
1039
1059
|
tags: splitList(form.tags),
|
|
@@ -1279,6 +1299,27 @@ window.__ModuleLoader__.load({
|
|
|
1279
1299
|
})
|
|
1280
1300
|
]
|
|
1281
1301
|
}),
|
|
1302
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1303
|
+
className: panel_module_css_default.field,
|
|
1304
|
+
children: [
|
|
1305
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1306
|
+
className: panel_module_css_default.fieldLabel,
|
|
1307
|
+
children: tt("form.proxyCommand")
|
|
1308
|
+
}),
|
|
1309
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1310
|
+
className: panel_module_css_default.input,
|
|
1311
|
+
value: form.proxyCommand,
|
|
1312
|
+
placeholder: "corp-vpn proxy %h %p %r",
|
|
1313
|
+
onChange: (event) => {
|
|
1314
|
+
set("proxyCommand", event.target.value);
|
|
1315
|
+
}
|
|
1316
|
+
}),
|
|
1317
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1318
|
+
className: panel_module_css_default.hint,
|
|
1319
|
+
children: tt("form.proxyCommandHint")
|
|
1320
|
+
})
|
|
1321
|
+
]
|
|
1322
|
+
}),
|
|
1282
1323
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1283
1324
|
className: panel_module_css_default.formRow,
|
|
1284
1325
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
@@ -1380,6 +1421,15 @@ window.__ModuleLoader__.load({
|
|
|
1380
1421
|
* add/edit/delete/test actions, ~/.ssh/config import, and a connect action
|
|
1381
1422
|
* that hands the alias to the terminal tab via onConnect.
|
|
1382
1423
|
*/
|
|
1424
|
+
/** Skipped-block rows rendered before the "and N more" summary. */
|
|
1425
|
+
const IMPORT_SKIP_LIMIT = 8;
|
|
1426
|
+
/** Locale key per import skip reason (no dynamic key concatenation). */
|
|
1427
|
+
const IMPORT_REASON_KEY = {
|
|
1428
|
+
wildcard: "import.reason.wildcard",
|
|
1429
|
+
existing: "import.reason.existing",
|
|
1430
|
+
match: "import.reason.match",
|
|
1431
|
+
invalid: "import.reason.invalid"
|
|
1432
|
+
};
|
|
1383
1433
|
/**
|
|
1384
1434
|
* Bucket hosts into collapsible groups (#379). Grouping by tags places a
|
|
1385
1435
|
* multi-tag host in every one of its tag groups (folder view); hosts without
|
|
@@ -1414,6 +1464,8 @@ window.__ModuleLoader__.load({
|
|
|
1414
1464
|
const [testResults, setTestResults] = (0, react.useState)({});
|
|
1415
1465
|
const [importing, setImporting] = (0, react.useState)(false);
|
|
1416
1466
|
const [notice, setNotice] = (0, react.useState)(null);
|
|
1467
|
+
/** Blocks the last import skipped, with the reason each one was left out. */
|
|
1468
|
+
const [importSkips, setImportSkips] = (0, react.useState)([]);
|
|
1417
1469
|
const [dialog, setDialog] = (0, react.useState)(null);
|
|
1418
1470
|
const [groupBy, setGroupBy] = (0, react.useState)("none");
|
|
1419
1471
|
const [collapsed, setCollapsed] = (0, react.useState)({});
|
|
@@ -1501,6 +1553,7 @@ window.__ModuleLoader__.load({
|
|
|
1501
1553
|
added: result.added,
|
|
1502
1554
|
skipped: result.skipped
|
|
1503
1555
|
}));
|
|
1556
|
+
setImportSkips(result.skippedBlocks);
|
|
1504
1557
|
load();
|
|
1505
1558
|
} catch (cause) {
|
|
1506
1559
|
if (!mountedRef.current) return;
|
|
@@ -1521,7 +1574,13 @@ window.__ModuleLoader__.load({
|
|
|
1521
1574
|
children: [
|
|
1522
1575
|
host.host,
|
|
1523
1576
|
":",
|
|
1524
|
-
host.port
|
|
1577
|
+
host.port,
|
|
1578
|
+
host.proxyCommand !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1579
|
+
className: panel_module_css_default.badge,
|
|
1580
|
+
"data-kind": "proxy",
|
|
1581
|
+
title: host.proxyCommand,
|
|
1582
|
+
children: tt("hosts.proxyBadge")
|
|
1583
|
+
})
|
|
1525
1584
|
]
|
|
1526
1585
|
}),
|
|
1527
1586
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: host.user }),
|
|
@@ -1671,6 +1730,25 @@ window.__ModuleLoader__.load({
|
|
|
1671
1730
|
"data-kind": "ok",
|
|
1672
1731
|
children: notice
|
|
1673
1732
|
}),
|
|
1733
|
+
notice !== null && importSkips.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ul", {
|
|
1734
|
+
className: panel_module_css_default.importSkips,
|
|
1735
|
+
children: [importSkips.slice(0, IMPORT_SKIP_LIMIT).map((block) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
1736
|
+
className: panel_module_css_default.importSkipRow,
|
|
1737
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1738
|
+
className: panel_module_css_default.mono,
|
|
1739
|
+
children: block.name
|
|
1740
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1741
|
+
className: panel_module_css_default.cellMuted,
|
|
1742
|
+
children: tt(IMPORT_REASON_KEY[block.reason])
|
|
1743
|
+
})]
|
|
1744
|
+
}, block.name)), importSkips.length > IMPORT_SKIP_LIMIT && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
1745
|
+
className: panel_module_css_default.importSkipRow,
|
|
1746
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1747
|
+
className: panel_module_css_default.cellMuted,
|
|
1748
|
+
children: tt("import.more", { count: importSkips.length - IMPORT_SKIP_LIMIT })
|
|
1749
|
+
})
|
|
1750
|
+
})]
|
|
1751
|
+
}),
|
|
1674
1752
|
error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1675
1753
|
className: panel_module_css_default.banner,
|
|
1676
1754
|
"data-kind": "error",
|
|
@@ -15439,10 +15517,10 @@ window.__ModuleLoader__.load({
|
|
|
15439
15517
|
//#region src/client/panel/TunnelsTab.tsx
|
|
15440
15518
|
/**
|
|
15441
15519
|
* Tunnels tab: the live local port-forward list (auto-refresh every 5s while
|
|
15442
|
-
*
|
|
15520
|
+
* visible) with per-row stop, a stop-all action scoped to the selected alias,
|
|
15443
15521
|
* and a new-tunnel form.
|
|
15444
15522
|
*/
|
|
15445
|
-
/** Live-tunnel polling interval while the tab
|
|
15523
|
+
/** Live-tunnel polling interval while the tab and page are visible (ms). */
|
|
15446
15524
|
const TUNNEL_POLL_MS = 5e3;
|
|
15447
15525
|
/**
|
|
15448
15526
|
* Return `next` only when the tunnel list changed in a user-visible way
|
|
@@ -15461,7 +15539,7 @@ window.__ModuleLoader__.load({
|
|
|
15461
15539
|
return null;
|
|
15462
15540
|
}
|
|
15463
15541
|
/** The tunnels tab. */
|
|
15464
|
-
function TunnelsTab({ api }) {
|
|
15542
|
+
function TunnelsTab({ api, active = true }) {
|
|
15465
15543
|
const [hosts, setHosts] = (0, react.useState)([]);
|
|
15466
15544
|
const [tunnels, setTunnels] = (0, react.useState)(null);
|
|
15467
15545
|
const [error, setError] = (0, react.useState)(null);
|
|
@@ -15484,27 +15562,61 @@ window.__ModuleLoader__.load({
|
|
|
15484
15562
|
};
|
|
15485
15563
|
}, [api]);
|
|
15486
15564
|
const seqRef = (0, react.useRef)(0);
|
|
15565
|
+
const automaticRead = (0, react.useRef)({ running: false });
|
|
15487
15566
|
(0, react.useEffect)(() => {
|
|
15567
|
+
if (!active) return;
|
|
15568
|
+
let disposed = false;
|
|
15569
|
+
const read = automaticRead.current;
|
|
15570
|
+
let timer;
|
|
15488
15571
|
const load = async () => {
|
|
15572
|
+
if (disposed || read.running || document.visibilityState === "hidden") return;
|
|
15573
|
+
read.running = true;
|
|
15489
15574
|
const seq = ++seqRef.current;
|
|
15490
15575
|
try {
|
|
15491
15576
|
const list = await api.listTunnels();
|
|
15492
|
-
if (seq !== seqRef.current) return;
|
|
15577
|
+
if (disposed || seq !== seqRef.current) return;
|
|
15493
15578
|
setTunnels((prev) => diffTunnels(prev, list) ?? prev);
|
|
15494
15579
|
setError(null);
|
|
15495
15580
|
} catch (cause) {
|
|
15496
|
-
if (seq !== seqRef.current) return;
|
|
15581
|
+
if (disposed || seq !== seqRef.current) return;
|
|
15497
15582
|
setError(errorMessage(cause));
|
|
15583
|
+
} finally {
|
|
15584
|
+
read.running = false;
|
|
15585
|
+
const resume = read.resume;
|
|
15586
|
+
read.resume = void 0;
|
|
15587
|
+
resume?.();
|
|
15498
15588
|
}
|
|
15499
15589
|
};
|
|
15500
|
-
|
|
15501
|
-
|
|
15502
|
-
|
|
15503
|
-
|
|
15590
|
+
const resume = () => {
|
|
15591
|
+
if (disposed || document.visibilityState === "hidden") return;
|
|
15592
|
+
if (read.running) read.resume = resume;
|
|
15593
|
+
else load();
|
|
15594
|
+
};
|
|
15595
|
+
const stop = () => {
|
|
15596
|
+
if (timer !== void 0) clearInterval(timer);
|
|
15597
|
+
timer = void 0;
|
|
15598
|
+
};
|
|
15599
|
+
const onVisibility = () => {
|
|
15600
|
+
if (document.visibilityState === "hidden") {
|
|
15601
|
+
stop();
|
|
15602
|
+
if (read.resume === resume) read.resume = void 0;
|
|
15603
|
+
} else if (timer === void 0) {
|
|
15604
|
+
resume();
|
|
15605
|
+
timer = setInterval(() => {
|
|
15606
|
+
load();
|
|
15607
|
+
}, TUNNEL_POLL_MS);
|
|
15608
|
+
}
|
|
15609
|
+
};
|
|
15610
|
+
document.addEventListener("visibilitychange", onVisibility);
|
|
15611
|
+
onVisibility();
|
|
15504
15612
|
return () => {
|
|
15505
|
-
|
|
15613
|
+
disposed = true;
|
|
15614
|
+
seqRef.current += 1;
|
|
15615
|
+
if (read.resume === resume) read.resume = void 0;
|
|
15616
|
+
stop();
|
|
15617
|
+
document.removeEventListener("visibilitychange", onVisibility);
|
|
15506
15618
|
};
|
|
15507
|
-
}, [api]);
|
|
15619
|
+
}, [api, active]);
|
|
15508
15620
|
const refresh = async () => {
|
|
15509
15621
|
const seq = ++seqRef.current;
|
|
15510
15622
|
try {
|
|
@@ -15748,6 +15860,7 @@ window.__ModuleLoader__.load({
|
|
|
15748
15860
|
];
|
|
15749
15861
|
/** The tabbed SSH panel. */
|
|
15750
15862
|
function SshPanel({ controller, api, terminalFont }) {
|
|
15863
|
+
const panelOpen = (0, react.useSyncExternalStore)((0, react.useCallback)((listener) => controller.subscribe(listener), [controller]), (0, react.useCallback)(() => controller.getSnapshot().panelOpen, [controller]));
|
|
15751
15864
|
const [activeTab, setActiveTab] = (0, react.useState)("hosts");
|
|
15752
15865
|
const [connectRequest, setConnectRequest] = (0, react.useState)(null);
|
|
15753
15866
|
const handleConnect = (alias) => {
|
|
@@ -15811,7 +15924,10 @@ window.__ModuleLoader__.load({
|
|
|
15811
15924
|
terminalFont
|
|
15812
15925
|
}),
|
|
15813
15926
|
activeTab === "transfer" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TransferTab, { api }),
|
|
15814
|
-
activeTab === "tunnels" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TunnelsTab, {
|
|
15927
|
+
activeTab === "tunnels" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TunnelsTab, {
|
|
15928
|
+
api,
|
|
15929
|
+
active: panelOpen
|
|
15930
|
+
}),
|
|
15815
15931
|
activeTab === "cluster" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ClusterTab, { api })
|
|
15816
15932
|
]
|
|
15817
15933
|
})
|
|
@@ -15819,6 +15935,94 @@ window.__ModuleLoader__.load({
|
|
|
15819
15935
|
});
|
|
15820
15936
|
}
|
|
15821
15937
|
//#endregion
|
|
15938
|
+
//#region src/client/body-mutations.ts
|
|
15939
|
+
/** Cross-bundle registry key; `Symbol.for` so every module copy agrees. */
|
|
15940
|
+
const HUB_KEY = Symbol.for("dsh-web.body-mutation-hub");
|
|
15941
|
+
const INVALIDATION_ONLY = Symbol.for("dsh-web.body-mutation-invalidation");
|
|
15942
|
+
function needsRecords(subscribers) {
|
|
15943
|
+
for (const listener of subscribers) if (!listener[INVALIDATION_ONLY]) return true;
|
|
15944
|
+
return false;
|
|
15945
|
+
}
|
|
15946
|
+
/**
|
|
15947
|
+
* Subscribe to a coalesced DOM re-check without retaining mutation records.
|
|
15948
|
+
* The marked wrapper also works with an older hub, which delivers records
|
|
15949
|
+
* that it simply ignores until a page reload picks up the updated hub.
|
|
15950
|
+
*/
|
|
15951
|
+
function subscribeBodyInvalidations(subscriber) {
|
|
15952
|
+
const listener = () => {
|
|
15953
|
+
subscriber();
|
|
15954
|
+
};
|
|
15955
|
+
listener[INVALIDATION_ONLY] = true;
|
|
15956
|
+
return subscribeBodyMutations(listener);
|
|
15957
|
+
}
|
|
15958
|
+
/**
|
|
15959
|
+
* Subscribe to body-level childList mutations.
|
|
15960
|
+
* @param subscriber - called at most once per animation frame with the records
|
|
15961
|
+
* collected since the previous flush; must be safe to run repeatedly.
|
|
15962
|
+
* @returns the disposer removing this subscriber (and the observer when it was
|
|
15963
|
+
* the last one).
|
|
15964
|
+
*/
|
|
15965
|
+
function subscribeBodyMutations(subscriber) {
|
|
15966
|
+
if (typeof globalThis === "undefined" || typeof document === "undefined") return () => {};
|
|
15967
|
+
if (typeof MutationObserver !== "function") return () => {};
|
|
15968
|
+
const registry = globalThis;
|
|
15969
|
+
let hub = registry[HUB_KEY];
|
|
15970
|
+
if (hub === void 0) {
|
|
15971
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
15972
|
+
const created = {
|
|
15973
|
+
observer: void 0,
|
|
15974
|
+
subscribers,
|
|
15975
|
+
pending: [],
|
|
15976
|
+
scheduled: false
|
|
15977
|
+
};
|
|
15978
|
+
const flush = () => {
|
|
15979
|
+
created.frame = void 0;
|
|
15980
|
+
created.scheduled = false;
|
|
15981
|
+
const batch = created.pending;
|
|
15982
|
+
created.pending = [];
|
|
15983
|
+
for (const listener of [...subscribers]) {
|
|
15984
|
+
if (!subscribers.has(listener)) continue;
|
|
15985
|
+
try {
|
|
15986
|
+
listener(batch);
|
|
15987
|
+
} catch {}
|
|
15988
|
+
}
|
|
15989
|
+
};
|
|
15990
|
+
const schedule = () => {
|
|
15991
|
+
if (created.scheduled) return;
|
|
15992
|
+
created.scheduled = true;
|
|
15993
|
+
if (typeof requestAnimationFrame === "function") created.frame = requestAnimationFrame(flush);
|
|
15994
|
+
else flush();
|
|
15995
|
+
};
|
|
15996
|
+
created.observer = new MutationObserver((records) => {
|
|
15997
|
+
if (needsRecords(subscribers)) for (const record of records) created.pending.push(record);
|
|
15998
|
+
schedule();
|
|
15999
|
+
});
|
|
16000
|
+
created.observer.observe(document.body ?? document.documentElement, {
|
|
16001
|
+
childList: true,
|
|
16002
|
+
subtree: true
|
|
16003
|
+
});
|
|
16004
|
+
registry[HUB_KEY] = created;
|
|
16005
|
+
hub = created;
|
|
16006
|
+
}
|
|
16007
|
+
const active = hub;
|
|
16008
|
+
active.subscribers.add(subscriber);
|
|
16009
|
+
let subscribed = true;
|
|
16010
|
+
return () => {
|
|
16011
|
+
if (!subscribed) return;
|
|
16012
|
+
subscribed = false;
|
|
16013
|
+
active.subscribers.delete(subscriber);
|
|
16014
|
+
if (!needsRecords(active.subscribers)) active.pending = [];
|
|
16015
|
+
if (active.subscribers.size === 0 && registry[HUB_KEY] === active) {
|
|
16016
|
+
active.observer.disconnect();
|
|
16017
|
+
if (active.frame !== void 0 && typeof cancelAnimationFrame === "function") cancelAnimationFrame(active.frame);
|
|
16018
|
+
active.frame = void 0;
|
|
16019
|
+
active.pending = [];
|
|
16020
|
+
active.scheduled = false;
|
|
16021
|
+
delete registry[HUB_KEY];
|
|
16022
|
+
}
|
|
16023
|
+
};
|
|
16024
|
+
}
|
|
16025
|
+
//#endregion
|
|
15822
16026
|
//#region src/client/panel-mount-core.ts
|
|
15823
16027
|
/**
|
|
15824
16028
|
* Center-column panel takeover lifecycle.
|
|
@@ -15863,32 +16067,31 @@ window.__ModuleLoader__.load({
|
|
|
15863
16067
|
});
|
|
15864
16068
|
} catch {}
|
|
15865
16069
|
const ensure = () => {
|
|
15866
|
-
if (container !== void 0) {
|
|
15867
|
-
if (container.isConnected) return;
|
|
16070
|
+
if (container !== void 0 && !container.isConnected) {
|
|
15868
16071
|
root?.unmount();
|
|
15869
16072
|
root = void 0;
|
|
15870
16073
|
container.remove();
|
|
15871
16074
|
container = void 0;
|
|
15872
16075
|
}
|
|
15873
|
-
|
|
15874
|
-
|
|
15875
|
-
|
|
15876
|
-
|
|
15877
|
-
|
|
15878
|
-
|
|
15879
|
-
|
|
16076
|
+
if (container === void 0) {
|
|
16077
|
+
const column = conversationColumn();
|
|
16078
|
+
if (column === void 0) return;
|
|
16079
|
+
container = document.createElement("div");
|
|
16080
|
+
container.dataset[options.viewDatasetKey] = "";
|
|
16081
|
+
container.dataset.dshPlugin = options.pluginName;
|
|
16082
|
+
container.className = options.viewClassName;
|
|
16083
|
+
column.appendChild(container);
|
|
16084
|
+
}
|
|
16085
|
+
if (root !== void 0 || !options.isOpen()) return;
|
|
15880
16086
|
root = (0, react_dom_client.createRoot)(container);
|
|
15881
16087
|
options.render(root);
|
|
15882
16088
|
};
|
|
15883
|
-
const
|
|
16089
|
+
const unsubscribeBody = subscribeBodyInvalidations(() => {
|
|
15884
16090
|
ensure();
|
|
15885
16091
|
});
|
|
15886
|
-
waitObserver.observe(document.body, {
|
|
15887
|
-
childList: true,
|
|
15888
|
-
subtree: true
|
|
15889
|
-
});
|
|
15890
16092
|
const applyActive = () => {
|
|
15891
16093
|
if (options.isOpen()) {
|
|
16094
|
+
ensure();
|
|
15892
16095
|
document.documentElement.removeAttribute(options.siblingActiveAttribute);
|
|
15893
16096
|
document.documentElement.setAttribute(options.activeAttribute, "");
|
|
15894
16097
|
document.dispatchEvent(new CustomEvent(ACTIVATE_EVENT, { detail: options.panelName }));
|
|
@@ -15911,7 +16114,7 @@ window.__ModuleLoader__.load({
|
|
|
15911
16114
|
return () => {
|
|
15912
16115
|
document.removeEventListener("click", onClickSidebarRow, true);
|
|
15913
16116
|
document.removeEventListener(ACTIVATE_EVENT, onOtherActivate);
|
|
15914
|
-
|
|
16117
|
+
unsubscribeBody();
|
|
15915
16118
|
unsubscribe();
|
|
15916
16119
|
unsubscribeLocale?.();
|
|
15917
16120
|
document.documentElement.removeAttribute(options.activeAttribute);
|
|
@@ -15988,6 +16191,21 @@ window.__ModuleLoader__.load({
|
|
|
15988
16191
|
};
|
|
15989
16192
|
//#endregion
|
|
15990
16193
|
//#region src/client/sidebar-entry-core.ts
|
|
16194
|
+
/**
|
|
16195
|
+
* Shared sidebar entry injection core.
|
|
16196
|
+
*
|
|
16197
|
+
* dsh's sidebar shell exposes no slot an external plugin can register into,
|
|
16198
|
+
* so the entry row is injected between the shell's New Session button and the
|
|
16199
|
+
* workspace browser. The injection self-heals: a MutationObserver watches the
|
|
16200
|
+
* sidebar root and re-inserts the row whenever a React re-render displaces it
|
|
16201
|
+
* (re-insertion happens in the same frame, before paint, so no flicker).
|
|
16202
|
+
*
|
|
16203
|
+
* The row is plain DOM (no React tree) so it can never disturb the shell's
|
|
16204
|
+
* reconciliation; the view it toggles is a separate root owned by the caller.
|
|
16205
|
+
*
|
|
16206
|
+
* Packages receive this file as a generated copy via scripts/sync-shared.mjs;
|
|
16207
|
+
* edit the shared source and re-run the sync instead of editing a copy.
|
|
16208
|
+
*/
|
|
15991
16209
|
/** Find the sidebar shell root element, or undefined while not yet mounted. */
|
|
15992
16210
|
function sidebarRoot() {
|
|
15993
16211
|
const column = document.querySelector("[data-pane=\"sidebar\"], [class*=\"sidebarCol\"]");
|
|
@@ -16076,13 +16294,9 @@ window.__ModuleLoader__.load({
|
|
|
16076
16294
|
subtree: true
|
|
16077
16295
|
});
|
|
16078
16296
|
};
|
|
16079
|
-
const
|
|
16297
|
+
const unsubscribeBody = subscribeBodyInvalidations(() => {
|
|
16080
16298
|
tryPlace();
|
|
16081
16299
|
});
|
|
16082
|
-
waitObserver.observe(document.body, {
|
|
16083
|
-
childList: true,
|
|
16084
|
-
subtree: true
|
|
16085
|
-
});
|
|
16086
16300
|
const rootObserver = new MutationObserver(() => {
|
|
16087
16301
|
if (root === void 0 || !root.isConnected) {
|
|
16088
16302
|
placed = false;
|
|
@@ -16102,7 +16316,7 @@ window.__ModuleLoader__.load({
|
|
|
16102
16316
|
})();
|
|
16103
16317
|
tryPlace();
|
|
16104
16318
|
return () => {
|
|
16105
|
-
|
|
16319
|
+
unsubscribeBody();
|
|
16106
16320
|
rootObserver.disconnect();
|
|
16107
16321
|
unsubscribeRefresh?.();
|
|
16108
16322
|
unsubscribeActive?.();
|
|
@@ -16152,7 +16366,7 @@ window.__ModuleLoader__.load({
|
|
|
16152
16366
|
/** The building package's version, when the bundle carries it. */
|
|
16153
16367
|
function bakedVersion() {
|
|
16154
16368
|
try {
|
|
16155
|
-
return "0.3.
|
|
16369
|
+
return "0.3.21";
|
|
16156
16370
|
} catch {
|
|
16157
16371
|
return;
|
|
16158
16372
|
}
|