@linxin666/dsh-ssh 0.1.20 → 0.2.0
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 +1 -1
- package/README.zh.md +1 -1
- package/lib/client.js +224 -93
- package/lib/client.js.map +1 -1
- package/lib/index.js +25 -11
- package/lib/types/client/locales.d.ts +135 -127
- package/lib/types/client/panel/HostsTab.d.ts +16 -0
- package/lib/types/protocol.d.ts +1 -1
- package/package.json +12 -12
- package/src/client/locales.ts +16 -0
- package/src/client/panel/HostsTab.tsx +152 -48
- package/src/client/panel/panel.module.css +75 -0
- package/src/routes.ts +25 -5
package/README.i18n.yaml
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# node scripts/verify-docs.mjs --write <dir>
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: 4ea116d416ac311ffde1f1052d9857e46b9c4849
|
|
6
|
+
README.zh.md: d5bec45d8054b999d24832a4a8d103269b2c816d
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Built on the capability list of [badseal/ssh-skill](https://github.com/badseal/s
|
|
|
8
8
|
|
|
9
9
|
| Capability | Description |
|
|
10
10
|
| --- | --- |
|
|
11
|
-
| Host management | CRUD, search, connection test; config stored in `~/.dsh/dsh-ssh.json`; supports key / password auth, passphrase keys, ProxyJump jump hosts (multi-level) |
|
|
11
|
+
| Host management | CRUD, search, connection test; collapsible grouping by environment / tags with per-group batch test; config stored in `~/.dsh/dsh-ssh.json`; supports key / password auth, passphrase keys, ProxyJump jump hosts (multi-level) |
|
|
12
12
|
| Config import | One-click parse of a standard `~/.ssh/config` (Host/HostName/User/Port/IdentityFile/ProxyJump etc.); existing aliases are skipped |
|
|
13
13
|
| Persistent connection pool | Reuses a long-lived connection per host (opposite of the ssh-skill daemon), automatically disconnects after 30 minutes idle, auto-reconnects on disconnect (up to 3 times) |
|
|
14
14
|
| Command execution | exec with a timeout (default 60s), stdout/stderr separated, output truncation guard (2MB) |
|
package/README.zh.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
| 能力 | 说明 |
|
|
10
10
|
| --- | --- |
|
|
11
|
-
| 主机管理 |
|
|
11
|
+
| 主机管理 | 增删改查、搜索、连接测试;支持按环境 / 标签分组折叠与组内批量测试;配置存 `~/.dsh/dsh-ssh.json`;支持密钥 / 密码认证、passphrase 密钥、ProxyJump 跳板机(多级) |
|
|
12
12
|
| 配置导入 | 一键解析标准 `~/.ssh/config`(Host/HostName/User/Port/IdentityFile/ProxyJump 等),已有别名自动跳过 |
|
|
13
13
|
| 持久连接池 | 每台主机复用长连接(对应 ssh-skill 的守护进程),空闲 30 分钟自动断开,断线自动重连(最多 3 次) |
|
|
14
14
|
| 命令执行 | exec 带超时(默认 60s),stdout/stderr 分离,输出截断保护(2MB) |
|
package/lib/client.js
CHANGED
|
@@ -323,6 +323,14 @@ window.__ModuleLoader__.load({
|
|
|
323
323
|
"hosts.add": "新增主机",
|
|
324
324
|
"hosts.import": "导入 ~/.ssh/config",
|
|
325
325
|
"hosts.search": "搜索别名 / 描述 / 标签…",
|
|
326
|
+
"hosts.groupBy.label": "分组方式",
|
|
327
|
+
"hosts.groupBy.none": "不分组",
|
|
328
|
+
"hosts.groupBy.environment": "按环境分组",
|
|
329
|
+
"hosts.groupBy.tags": "按标签分组",
|
|
330
|
+
"hosts.group.ungrouped": "未设置环境",
|
|
331
|
+
"hosts.group.noTags": "无标签",
|
|
332
|
+
"hosts.group.count": "{count} 台",
|
|
333
|
+
"hosts.group.testAll": "测试全部",
|
|
326
334
|
"hosts.col.alias": "别名",
|
|
327
335
|
"hosts.col.host": "主机",
|
|
328
336
|
"hosts.col.user": "用户",
|
|
@@ -452,6 +460,14 @@ window.__ModuleLoader__.load({
|
|
|
452
460
|
"hosts.add": "Add host",
|
|
453
461
|
"hosts.import": "Import ~/.ssh/config",
|
|
454
462
|
"hosts.search": "Search alias / description / tags…",
|
|
463
|
+
"hosts.groupBy.label": "Group by",
|
|
464
|
+
"hosts.groupBy.none": "No grouping",
|
|
465
|
+
"hosts.groupBy.environment": "Group by environment",
|
|
466
|
+
"hosts.groupBy.tags": "Group by tags",
|
|
467
|
+
"hosts.group.ungrouped": "No environment",
|
|
468
|
+
"hosts.group.noTags": "No tags",
|
|
469
|
+
"hosts.group.count": "{count} hosts",
|
|
470
|
+
"hosts.group.testAll": "Test all",
|
|
455
471
|
"hosts.col.alias": "Alias",
|
|
456
472
|
"hosts.col.host": "Host",
|
|
457
473
|
"hosts.col.user": "User",
|
|
@@ -595,7 +611,7 @@ window.__ModuleLoader__.load({
|
|
|
595
611
|
}
|
|
596
612
|
//#endregion
|
|
597
613
|
//#region \0dsh-css:packages/dsh-ssh/src/client/panel/panel.module.css.mjs
|
|
598
|
-
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{width:100%;height:32px;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-radius:8px;align-items:center;gap:8px;padding:0 12px;font-size:13px;display:flex}.mL8Uca_entry:hover{background:var(--dsw-specific-sidebar-nav-item-hover);color:var(--dsw-alias-label-primary)}.mL8Uca_entry[data-active]{background:var(--dsw-specific-sidebar-nav-item-active);color:var(--dsw-alias-label-primary);font-weight:600}.mL8Uca_entryIcon{flex:none;justify-content:center;align-items:center;display:inline-flex}.mL8Uca_entryLabel{text-overflow:ellipsis;overflow:hidden}[data-dsh-frame][data-sidebar-collapsed] .mL8Uca_entry{justify-content:center;width:100%;padding:0}[data-dsh-frame][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_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-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{padding:8px 10px;position:absolute;inset:0}.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}";
|
|
614
|
+
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{width:100%;height:32px;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-radius:8px;align-items:center;gap:8px;padding:0 12px;font-size:13px;display:flex}.mL8Uca_entry:hover{background:var(--dsw-specific-sidebar-nav-item-hover);color:var(--dsw-alias-label-primary)}.mL8Uca_entry[data-active]{background:var(--dsw-specific-sidebar-nav-item-active);color:var(--dsw-alias-label-primary);font-weight:600}.mL8Uca_entryIcon{flex:none;justify-content:center;align-items:center;display:inline-flex}.mL8Uca_entryLabel{text-overflow:ellipsis;overflow:hidden}[data-dsh-frame][data-sidebar-collapsed] .mL8Uca_entry{justify-content:center;width:100%;padding:0}[data-dsh-frame][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-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{padding:8px 10px;position:absolute;inset:0}.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}";
|
|
599
615
|
const tagId = "@linxin666/dsh-ssh/panel.module.css";
|
|
600
616
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
601
617
|
const tag = document.createElement("style");
|
|
@@ -636,6 +652,13 @@ window.__ModuleLoader__.load({
|
|
|
636
652
|
"formError": "mL8Uca_formError",
|
|
637
653
|
"formRow": "mL8Uca_formRow",
|
|
638
654
|
"ghostButton": "mL8Uca_ghostButton",
|
|
655
|
+
"groupBySelect": "mL8Uca_groupBySelect",
|
|
656
|
+
"groupChevron": "mL8Uca_groupChevron",
|
|
657
|
+
"groupCount": "mL8Uca_groupCount",
|
|
658
|
+
"groupHeader": "mL8Uca_groupHeader",
|
|
659
|
+
"groupName": "mL8Uca_groupName",
|
|
660
|
+
"groupSection": "mL8Uca_groupSection",
|
|
661
|
+
"groupToggle": "mL8Uca_groupToggle",
|
|
639
662
|
"hiddenFile": "mL8Uca_hiddenFile",
|
|
640
663
|
"hint": "mL8Uca_hint",
|
|
641
664
|
"iconButton": "mL8Uca_iconButton",
|
|
@@ -1238,6 +1261,31 @@ window.__ModuleLoader__.load({
|
|
|
1238
1261
|
* add/edit/delete/test actions, ~/.ssh/config import, and a connect action
|
|
1239
1262
|
* that hands the alias to the terminal tab via onConnect.
|
|
1240
1263
|
*/
|
|
1264
|
+
/**
|
|
1265
|
+
* Bucket hosts into collapsible groups (#379). Grouping by tags places a
|
|
1266
|
+
* multi-tag host in every one of its tag groups (folder view); hosts without
|
|
1267
|
+
* the grouping key land in the '' bucket, which always sorts last. Groups
|
|
1268
|
+
* sort alphabetically; host order inside a group follows the API listing.
|
|
1269
|
+
*/
|
|
1270
|
+
function groupHosts(hosts, groupBy) {
|
|
1271
|
+
if (groupBy === "none") return [{
|
|
1272
|
+
key: "",
|
|
1273
|
+
hosts
|
|
1274
|
+
}];
|
|
1275
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
1276
|
+
const push = (key, host) => {
|
|
1277
|
+
const bucket = buckets.get(key);
|
|
1278
|
+
if (bucket === void 0) buckets.set(key, [host]);
|
|
1279
|
+
else bucket.push(host);
|
|
1280
|
+
};
|
|
1281
|
+
for (const host of hosts) if (groupBy === "environment") push(host.environment ?? "", host);
|
|
1282
|
+
else if (host.tags.length === 0) push("", host);
|
|
1283
|
+
else for (const tag of host.tags) push(tag, host);
|
|
1284
|
+
return [...buckets.entries()].sort(([a], [b]) => a === "" ? 1 : b === "" ? -1 : a.localeCompare(b)).map(([key, group]) => ({
|
|
1285
|
+
key,
|
|
1286
|
+
hosts: group
|
|
1287
|
+
}));
|
|
1288
|
+
}
|
|
1241
1289
|
/** The hosts table plus its toolbar and dialogs. */
|
|
1242
1290
|
function HostsTab({ api, onConnect }) {
|
|
1243
1291
|
const [hosts, setHosts] = (0, react.useState)(null);
|
|
@@ -1248,6 +1296,9 @@ window.__ModuleLoader__.load({
|
|
|
1248
1296
|
const [importing, setImporting] = (0, react.useState)(false);
|
|
1249
1297
|
const [notice, setNotice] = (0, react.useState)(null);
|
|
1250
1298
|
const [dialog, setDialog] = (0, react.useState)(null);
|
|
1299
|
+
const [groupBy, setGroupBy] = (0, react.useState)("none");
|
|
1300
|
+
const [collapsed, setCollapsed] = (0, react.useState)({});
|
|
1301
|
+
const [testingGroup, setTestingGroup] = (0, react.useState)(null);
|
|
1251
1302
|
const seqRef = (0, react.useRef)(0);
|
|
1252
1303
|
const load = (0, react.useCallback)(async (query) => {
|
|
1253
1304
|
const seq = ++seqRef.current;
|
|
@@ -1302,6 +1353,14 @@ window.__ModuleLoader__.load({
|
|
|
1302
1353
|
setError(errorMessage(cause));
|
|
1303
1354
|
}
|
|
1304
1355
|
};
|
|
1356
|
+
const testGroup = async (group) => {
|
|
1357
|
+
setTestingGroup(group.key);
|
|
1358
|
+
try {
|
|
1359
|
+
await Promise.all(group.hosts.map((host) => runTest(host.alias)));
|
|
1360
|
+
} finally {
|
|
1361
|
+
setTestingGroup(null);
|
|
1362
|
+
}
|
|
1363
|
+
};
|
|
1305
1364
|
const importConfig = async () => {
|
|
1306
1365
|
setImporting(true);
|
|
1307
1366
|
try {
|
|
@@ -1318,6 +1377,106 @@ window.__ModuleLoader__.load({
|
|
|
1318
1377
|
setImporting(false);
|
|
1319
1378
|
}
|
|
1320
1379
|
};
|
|
1380
|
+
const renderHostRow = (host) => {
|
|
1381
|
+
const test = testResults[host.alias];
|
|
1382
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
|
|
1383
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
|
|
1384
|
+
className: panel_module_css_default.mono,
|
|
1385
|
+
children: host.alias
|
|
1386
|
+
}),
|
|
1387
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("td", {
|
|
1388
|
+
className: panel_module_css_default.mono,
|
|
1389
|
+
children: [
|
|
1390
|
+
host.host,
|
|
1391
|
+
":",
|
|
1392
|
+
host.port
|
|
1393
|
+
]
|
|
1394
|
+
}),
|
|
1395
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: host.user }),
|
|
1396
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1397
|
+
className: panel_module_css_default.badge,
|
|
1398
|
+
"data-kind": host.auth,
|
|
1399
|
+
children: host.auth === "key" ? tt("form.auth.key") : tt("form.auth.password")
|
|
1400
|
+
}) }),
|
|
1401
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
|
|
1402
|
+
className: panel_module_css_default.cellMuted,
|
|
1403
|
+
children: host.environment ?? ""
|
|
1404
|
+
}),
|
|
1405
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
|
|
1406
|
+
className: panel_module_css_default.cellMuted,
|
|
1407
|
+
children: host.tags.join(", ")
|
|
1408
|
+
}),
|
|
1409
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
|
|
1410
|
+
className: panel_module_css_default.cellMuted,
|
|
1411
|
+
children: host.description ?? ""
|
|
1412
|
+
}),
|
|
1413
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1414
|
+
className: panel_module_css_default.actions,
|
|
1415
|
+
children: [
|
|
1416
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1417
|
+
type: "button",
|
|
1418
|
+
className: panel_module_css_default.linkButton,
|
|
1419
|
+
disabled: testingAlias === host.alias,
|
|
1420
|
+
onClick: () => {
|
|
1421
|
+
runTest(host.alias);
|
|
1422
|
+
},
|
|
1423
|
+
children: testingAlias === host.alias ? tt("hosts.testing") : tt("hosts.test")
|
|
1424
|
+
}),
|
|
1425
|
+
testingAlias === host.alias && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1426
|
+
className: panel_module_css_default.spinner,
|
|
1427
|
+
"aria-hidden": "true"
|
|
1428
|
+
}),
|
|
1429
|
+
test !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1430
|
+
className: panel_module_css_default.inlineTest,
|
|
1431
|
+
"data-status": test.ok ? "ok" : "fail",
|
|
1432
|
+
children: test.ok ? tt("hosts.testOk", { latency: test.latencyMs ?? 0 }) : tt("hosts.testFail", { error: test.error ?? "" })
|
|
1433
|
+
}),
|
|
1434
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1435
|
+
type: "button",
|
|
1436
|
+
className: panel_module_css_default.linkButton,
|
|
1437
|
+
onClick: () => {
|
|
1438
|
+
setDialog({
|
|
1439
|
+
mode: "edit",
|
|
1440
|
+
host
|
|
1441
|
+
});
|
|
1442
|
+
},
|
|
1443
|
+
children: tt("hosts.edit")
|
|
1444
|
+
}),
|
|
1445
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1446
|
+
type: "button",
|
|
1447
|
+
className: panel_module_css_default.linkButton,
|
|
1448
|
+
"data-danger": true,
|
|
1449
|
+
onClick: () => {
|
|
1450
|
+
deleteHost(host.alias);
|
|
1451
|
+
},
|
|
1452
|
+
children: tt("hosts.delete")
|
|
1453
|
+
}),
|
|
1454
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1455
|
+
type: "button",
|
|
1456
|
+
className: panel_module_css_default.ghostButton,
|
|
1457
|
+
onClick: () => {
|
|
1458
|
+
onConnect(host.alias);
|
|
1459
|
+
},
|
|
1460
|
+
children: tt("hosts.connected")
|
|
1461
|
+
})
|
|
1462
|
+
]
|
|
1463
|
+
}) })
|
|
1464
|
+
] }, host.alias);
|
|
1465
|
+
};
|
|
1466
|
+
const renderHostTable = (rows) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("table", {
|
|
1467
|
+
className: panel_module_css_default.table,
|
|
1468
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
|
|
1469
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: tt("hosts.col.alias") }),
|
|
1470
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: tt("hosts.col.host") }),
|
|
1471
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: tt("hosts.col.user") }),
|
|
1472
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: tt("hosts.col.auth") }),
|
|
1473
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: tt("hosts.col.environment") }),
|
|
1474
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: tt("hosts.col.tags") }),
|
|
1475
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: tt("hosts.col.description") }),
|
|
1476
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: tt("hosts.col.actions") })
|
|
1477
|
+
] }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tbody", { children: rows.map(renderHostRow) })]
|
|
1478
|
+
});
|
|
1479
|
+
const groups = hosts === null ? [] : groupHosts(hosts, groupBy);
|
|
1321
1480
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1322
1481
|
className: panel_module_css_default.fillBody,
|
|
1323
1482
|
children: [
|
|
@@ -1333,6 +1492,28 @@ window.__ModuleLoader__.load({
|
|
|
1333
1492
|
setSearch(event.target.value);
|
|
1334
1493
|
}
|
|
1335
1494
|
}),
|
|
1495
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
1496
|
+
className: panel_module_css_default.groupBySelect,
|
|
1497
|
+
"aria-label": tt("hosts.groupBy.label"),
|
|
1498
|
+
value: groupBy,
|
|
1499
|
+
onChange: (event) => {
|
|
1500
|
+
setGroupBy(event.target.value);
|
|
1501
|
+
},
|
|
1502
|
+
children: [
|
|
1503
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
1504
|
+
value: "none",
|
|
1505
|
+
children: tt("hosts.groupBy.none")
|
|
1506
|
+
}),
|
|
1507
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
1508
|
+
value: "environment",
|
|
1509
|
+
children: tt("hosts.groupBy.environment")
|
|
1510
|
+
}),
|
|
1511
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
1512
|
+
value: "tags",
|
|
1513
|
+
children: tt("hosts.groupBy.tags")
|
|
1514
|
+
})
|
|
1515
|
+
]
|
|
1516
|
+
}),
|
|
1336
1517
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: panel_module_css_default.toolbarSpacer }),
|
|
1337
1518
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1338
1519
|
type: "button",
|
|
@@ -1371,105 +1552,55 @@ window.__ModuleLoader__.load({
|
|
|
1371
1552
|
className: panel_module_css_default.empty,
|
|
1372
1553
|
children: tt("hosts.empty")
|
|
1373
1554
|
}),
|
|
1374
|
-
hosts !== null && hosts.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1555
|
+
hosts !== null && hosts.length > 0 && groupBy === "none" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1375
1556
|
className: panel_module_css_default.tableWrap,
|
|
1376
|
-
children:
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
host.host,
|
|
1398
|
-
":",
|
|
1399
|
-
host.port
|
|
1400
|
-
]
|
|
1401
|
-
}),
|
|
1402
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: host.user }),
|
|
1403
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1404
|
-
className: panel_module_css_default.badge,
|
|
1405
|
-
"data-kind": host.auth,
|
|
1406
|
-
children: host.auth === "key" ? tt("form.auth.key") : tt("form.auth.password")
|
|
1407
|
-
}) }),
|
|
1408
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
|
|
1409
|
-
className: panel_module_css_default.cellMuted,
|
|
1410
|
-
children: host.environment ?? ""
|
|
1411
|
-
}),
|
|
1412
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
|
|
1413
|
-
className: panel_module_css_default.cellMuted,
|
|
1414
|
-
children: host.tags.join(", ")
|
|
1415
|
-
}),
|
|
1416
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
|
|
1417
|
-
className: panel_module_css_default.cellMuted,
|
|
1418
|
-
children: host.description ?? ""
|
|
1419
|
-
}),
|
|
1420
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1421
|
-
className: panel_module_css_default.actions,
|
|
1557
|
+
children: renderHostTable(hosts)
|
|
1558
|
+
}),
|
|
1559
|
+
hosts !== null && hosts.length > 0 && groupBy !== "none" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1560
|
+
className: panel_module_css_default.tableWrap,
|
|
1561
|
+
children: groups.map((group) => {
|
|
1562
|
+
const isCollapsed = collapsed[group.key] === true;
|
|
1563
|
+
const label = group.key === "" ? groupBy === "tags" ? tt("hosts.group.noTags") : tt("hosts.group.ungrouped") : group.key;
|
|
1564
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1565
|
+
className: panel_module_css_default.groupSection,
|
|
1566
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1567
|
+
className: panel_module_css_default.groupHeader,
|
|
1568
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1569
|
+
type: "button",
|
|
1570
|
+
className: panel_module_css_default.groupToggle,
|
|
1571
|
+
"aria-expanded": !isCollapsed,
|
|
1572
|
+
onClick: () => {
|
|
1573
|
+
setCollapsed((prev) => ({
|
|
1574
|
+
...prev,
|
|
1575
|
+
[group.key]: !isCollapsed
|
|
1576
|
+
}));
|
|
1577
|
+
},
|
|
1422
1578
|
children: [
|
|
1423
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
disabled: testingAlias === host.alias,
|
|
1427
|
-
onClick: () => {
|
|
1428
|
-
runTest(host.alias);
|
|
1429
|
-
},
|
|
1430
|
-
children: testingAlias === host.alias ? tt("hosts.testing") : tt("hosts.test")
|
|
1431
|
-
}),
|
|
1432
|
-
testingAlias === host.alias && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1433
|
-
className: panel_module_css_default.spinner,
|
|
1579
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1580
|
+
className: panel_module_css_default.groupChevron,
|
|
1581
|
+
"data-collapsed": isCollapsed || void 0,
|
|
1434
1582
|
"aria-hidden": "true"
|
|
1435
1583
|
}),
|
|
1436
|
-
|
|
1437
|
-
className: panel_module_css_default.
|
|
1438
|
-
|
|
1439
|
-
children: test.ok ? tt("hosts.testOk", { latency: test.latencyMs ?? 0 }) : tt("hosts.testFail", { error: test.error ?? "" })
|
|
1584
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1585
|
+
className: panel_module_css_default.groupName,
|
|
1586
|
+
children: label
|
|
1440
1587
|
}),
|
|
1441
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
onClick: () => {
|
|
1445
|
-
setDialog({
|
|
1446
|
-
mode: "edit",
|
|
1447
|
-
host
|
|
1448
|
-
});
|
|
1449
|
-
},
|
|
1450
|
-
children: tt("hosts.edit")
|
|
1451
|
-
}),
|
|
1452
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1453
|
-
type: "button",
|
|
1454
|
-
className: panel_module_css_default.linkButton,
|
|
1455
|
-
"data-danger": true,
|
|
1456
|
-
onClick: () => {
|
|
1457
|
-
deleteHost(host.alias);
|
|
1458
|
-
},
|
|
1459
|
-
children: tt("hosts.delete")
|
|
1460
|
-
}),
|
|
1461
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1462
|
-
type: "button",
|
|
1463
|
-
className: panel_module_css_default.ghostButton,
|
|
1464
|
-
onClick: () => {
|
|
1465
|
-
onConnect(host.alias);
|
|
1466
|
-
},
|
|
1467
|
-
children: tt("hosts.connected")
|
|
1588
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1589
|
+
className: panel_module_css_default.groupCount,
|
|
1590
|
+
children: tt("hosts.group.count", { count: group.hosts.length })
|
|
1468
1591
|
})
|
|
1469
1592
|
]
|
|
1470
|
-
})
|
|
1471
|
-
|
|
1472
|
-
|
|
1593
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1594
|
+
type: "button",
|
|
1595
|
+
className: panel_module_css_default.linkButton,
|
|
1596
|
+
disabled: testingGroup === group.key,
|
|
1597
|
+
onClick: () => {
|
|
1598
|
+
testGroup(group);
|
|
1599
|
+
},
|
|
1600
|
+
children: testingGroup === group.key ? tt("hosts.testing") : tt("hosts.group.testAll")
|
|
1601
|
+
})]
|
|
1602
|
+
}), !isCollapsed && renderHostTable(group.hosts)]
|
|
1603
|
+
}, group.key);
|
|
1473
1604
|
})
|
|
1474
1605
|
}),
|
|
1475
1606
|
dialog !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HostFormDialog, {
|