@linxin666/dsh-ssh 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +75 -0
  2. package/cordis.patch.yml +12 -0
  3. package/lib/client.js +15638 -0
  4. package/lib/index.js +3297 -0
  5. package/lib/invariant.js +6 -0
  6. package/lib/types/client/api.d.ts +72 -0
  7. package/lib/types/client/index.d.ts +37 -0
  8. package/lib/types/client/locales.d.ts +137 -0
  9. package/lib/types/client/mount.d.ts +12 -0
  10. package/lib/types/client/panel/ClusterTab.d.ts +7 -0
  11. package/lib/types/client/panel/HostFormDialog.d.ts +12 -0
  12. package/lib/types/client/panel/HostsTab.d.ts +9 -0
  13. package/lib/types/client/panel/SshPanel.d.ts +13 -0
  14. package/lib/types/client/panel/TerminalTab.d.ts +11 -0
  15. package/lib/types/client/panel/TransferTab.d.ts +7 -0
  16. package/lib/types/client/panel/TunnelsTab.d.ts +7 -0
  17. package/lib/types/client/panel/controller.d.ts +22 -0
  18. package/lib/types/client/panel/helpers.d.ts +14 -0
  19. package/lib/types/client/panel/xterm.css.d.ts +2 -0
  20. package/lib/types/client/sidebar-entry.d.ts +24 -0
  21. package/lib/types/engine.d.ts +135 -0
  22. package/lib/types/index.d.ts +40 -0
  23. package/lib/types/invariant.d.ts +3 -0
  24. package/lib/types/protocol.d.ts +189 -0
  25. package/lib/types/routes.d.ts +29 -0
  26. package/lib/types/store.d.ts +54 -0
  27. package/lib/types/tools.d.ts +18 -0
  28. package/package.json +106 -0
  29. package/src/client/api.ts +363 -0
  30. package/src/client/css-modules.d.ts +5 -0
  31. package/src/client/index.ts +68 -0
  32. package/src/client/locales.ts +284 -0
  33. package/src/client/mount.tsx +83 -0
  34. package/src/client/panel/ClusterTab.tsx +123 -0
  35. package/src/client/panel/HostFormDialog.tsx +221 -0
  36. package/src/client/panel/HostsTab.tsx +166 -0
  37. package/src/client/panel/SshPanel.tsx +77 -0
  38. package/src/client/panel/TerminalTab.tsx +176 -0
  39. package/src/client/panel/TransferTab.tsx +232 -0
  40. package/src/client/panel/TunnelsTab.tsx +177 -0
  41. package/src/client/panel/controller.ts +48 -0
  42. package/src/client/panel/helpers.ts +26 -0
  43. package/src/client/panel/panel.module.css +833 -0
  44. package/src/client/panel/xterm.css.ts +2 -0
  45. package/src/client/sidebar-entry.ts +123 -0
  46. package/src/engine.ts +780 -0
  47. package/src/index.ts +155 -0
  48. package/src/invariant.ts +4 -0
  49. package/src/protocol.ts +188 -0
  50. package/src/routes.ts +540 -0
  51. package/src/store.ts +344 -0
  52. package/src/tools.ts +371 -0
@@ -0,0 +1,833 @@
1
+ /**
2
+ * dsh-ssh panel styles. Scoped by the plugin's own data attributes so nothing
3
+ * leaks into the rest of the GUI; colors ride the dsh --dsw-* tokens so the
4
+ * panel follows the active theme (light/dark and skins). The center-column
5
+ * hide rules are attribute-scoped and must stay in this stylesheet (it is
6
+ * imported by mount.tsx, so the styles load with the plugin).
7
+ */
8
+
9
+ /* --- center-column takeover (global rules, attribute-scoped) ----------------- */
10
+
11
+ [data-pane='conversation'] {
12
+ position: relative;
13
+ }
14
+
15
+ /* The panel container rides inside the conversation grid item as an extra
16
+ trailing child; hidden unless the panel is active. */
17
+ [data-dsh-ssh-view] {
18
+ position: absolute;
19
+ inset: 0;
20
+ display: none;
21
+ z-index: 5;
22
+ }
23
+
24
+ html[data-dsh-ssh-active] [data-dsh-ssh-view] {
25
+ display: block;
26
+ }
27
+
28
+ /* While the panel is active, the conversation content underneath is hidden
29
+ (it stays mounted and stateful). */
30
+ html[data-dsh-ssh-active] [data-pane='conversation'] > :not([data-dsh-ssh-view]) {
31
+ display: none;
32
+ }
33
+
34
+ /* --- sidebar entry row ------------------------------------------------------- */
35
+
36
+ .entry {
37
+ display: flex;
38
+ align-items: center;
39
+ gap: 8px;
40
+ width: 100%;
41
+ height: 32px;
42
+ padding: 0 12px;
43
+ background: transparent;
44
+ border: none;
45
+ border-radius: 8px;
46
+ color: var(--dsw-alias-label-secondary);
47
+ cursor: pointer;
48
+ font-size: 13px;
49
+ white-space: nowrap;
50
+ }
51
+
52
+ .entry:hover {
53
+ background: var(--dsw-specific-sidebar-nav-item-hover);
54
+ color: var(--dsw-alias-label-primary);
55
+ }
56
+
57
+ .entry[data-active] {
58
+ background: var(--dsw-specific-sidebar-nav-item-active);
59
+ color: var(--dsw-alias-label-primary);
60
+ font-weight: 600;
61
+ }
62
+
63
+ .entryIcon {
64
+ display: inline-flex;
65
+ align-items: center;
66
+ justify-content: center;
67
+ flex: none;
68
+ }
69
+
70
+ .entryLabel {
71
+ overflow: hidden;
72
+ text-overflow: ellipsis;
73
+ }
74
+
75
+ /* Collapsed rail: icon-only, centered, matching the shell's 56px rail. */
76
+ [data-dsh-frame][data-sidebar-collapsed] .entry {
77
+ justify-content: center;
78
+ padding: 0;
79
+ width: 100%;
80
+ }
81
+
82
+ [data-dsh-frame][data-sidebar-collapsed] .entryLabel {
83
+ display: none;
84
+ }
85
+
86
+ /* --- panel frame -------------------------------------------------------------- */
87
+
88
+ .view {
89
+ overflow: hidden;
90
+ }
91
+
92
+ .panel {
93
+ display: flex;
94
+ flex-direction: column;
95
+ height: 100%;
96
+ min-width: 0;
97
+ min-height: 0;
98
+ padding: 14px 16px 16px;
99
+ gap: 10px;
100
+ background: var(--dsw-alias-bg-base);
101
+ color: var(--dsw-alias-label-primary);
102
+ font-family: var(--dsw-font-family);
103
+ }
104
+
105
+ .panelHeader {
106
+ display: flex;
107
+ align-items: center;
108
+ gap: 10px;
109
+ flex: none;
110
+ }
111
+
112
+ .panelTitle {
113
+ margin: 0;
114
+ flex: 1;
115
+ font-size: 16px;
116
+ font-weight: 700;
117
+ color: var(--dsw-alias-label-primary);
118
+ white-space: nowrap;
119
+ }
120
+
121
+ /* --- tab bar ------------------------------------------------------------------ */
122
+
123
+ .tabBar {
124
+ display: flex;
125
+ gap: 2px;
126
+ flex: none;
127
+ border-bottom: 1px solid var(--dsw-alias-border-l1);
128
+ }
129
+
130
+ .tab {
131
+ padding: 7px 14px;
132
+ font-size: 13px;
133
+ color: var(--dsw-alias-label-secondary);
134
+ background: transparent;
135
+ border: none;
136
+ border-bottom: 2px solid transparent;
137
+ border-radius: 6px 6px 0 0;
138
+ cursor: pointer;
139
+ white-space: nowrap;
140
+ }
141
+
142
+ .tab:hover {
143
+ color: var(--dsw-alias-label-primary);
144
+ background: var(--dsw-alias-interactive-bg-hover);
145
+ }
146
+
147
+ .tab[data-active] {
148
+ color: var(--dsw-alias-label-primary);
149
+ font-weight: 600;
150
+ border-bottom-color: var(--dsw-alias-state-business-primary);
151
+ }
152
+
153
+ .panelContent {
154
+ flex: 1;
155
+ min-height: 0;
156
+ display: flex;
157
+ flex-direction: column;
158
+ overflow: hidden;
159
+ }
160
+
161
+ /* Scrollable tab body (transfer / tunnels); hosts and cluster use fillBody so
162
+ their toolbars stay put while the table scrolls internally. */
163
+ .tabBody {
164
+ display: flex;
165
+ flex-direction: column;
166
+ gap: 10px;
167
+ flex: 1;
168
+ min-height: 0;
169
+ overflow-y: auto;
170
+ }
171
+
172
+ .fillBody {
173
+ display: flex;
174
+ flex-direction: column;
175
+ gap: 10px;
176
+ flex: 1;
177
+ min-height: 0;
178
+ overflow: hidden;
179
+ }
180
+
181
+ /* --- toolbar / controls ------------------------------------------------------- */
182
+
183
+ .toolbar {
184
+ display: flex;
185
+ align-items: center;
186
+ gap: 8px;
187
+ flex: none;
188
+ flex-wrap: wrap;
189
+ }
190
+
191
+ .controls {
192
+ display: flex;
193
+ align-items: center;
194
+ gap: 8px;
195
+ flex: none;
196
+ flex-wrap: wrap;
197
+ }
198
+
199
+ .controls .input {
200
+ flex: 0 1 260px;
201
+ min-width: 150px;
202
+ }
203
+
204
+ .toolbarSpacer {
205
+ flex: 1;
206
+ }
207
+
208
+ .search {
209
+ flex: 0 1 260px;
210
+ min-width: 120px;
211
+ padding: 6px 10px;
212
+ font-size: 13px;
213
+ color: var(--dsw-alias-label-primary);
214
+ background: var(--dsw-specific-input-major);
215
+ border: 1px solid var(--dsw-alias-border-l2);
216
+ border-radius: 8px;
217
+ outline: none;
218
+ }
219
+
220
+ .search::placeholder {
221
+ color: var(--dsw-alias-label-tertiary);
222
+ }
223
+
224
+ /* --- tables ------------------------------------------------------------------- */
225
+
226
+ .tableWrap {
227
+ flex: 1;
228
+ min-height: 0;
229
+ overflow: auto;
230
+ border: 1px solid var(--dsw-alias-border-l1);
231
+ border-radius: 10px;
232
+ }
233
+
234
+ .table {
235
+ width: 100%;
236
+ border-collapse: collapse;
237
+ font-size: 12.5px;
238
+ }
239
+
240
+ .table th {
241
+ position: sticky;
242
+ top: 0;
243
+ z-index: 1;
244
+ padding: 8px 10px;
245
+ text-align: left;
246
+ background: var(--dsw-alias-bg-layer-2);
247
+ color: var(--dsw-alias-label-secondary);
248
+ font-weight: 600;
249
+ border-bottom: 1px solid var(--dsw-alias-border-l1);
250
+ white-space: nowrap;
251
+ }
252
+
253
+ .table td {
254
+ padding: 7px 10px;
255
+ border-bottom: 1px solid var(--dsw-alias-separator-primary);
256
+ vertical-align: top;
257
+ }
258
+
259
+ .table tbody tr:last-child td {
260
+ border-bottom: none;
261
+ }
262
+
263
+ .table tbody tr:hover td {
264
+ background: var(--dsw-alias-interactive-bg-hover);
265
+ }
266
+
267
+ .mono {
268
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
269
+ }
270
+
271
+ .cellMuted {
272
+ color: var(--dsw-alias-label-tertiary);
273
+ }
274
+
275
+ .actions {
276
+ display: flex;
277
+ align-items: center;
278
+ gap: 8px;
279
+ white-space: nowrap;
280
+ }
281
+
282
+ .inlineTest {
283
+ display: inline-flex;
284
+ align-items: center;
285
+ gap: 6px;
286
+ font-size: 11.5px;
287
+ color: var(--dsw-alias-label-secondary);
288
+ }
289
+
290
+ .inlineTest[data-status='ok'] {
291
+ color: var(--dsw-alias-state-success-primary);
292
+ }
293
+
294
+ .inlineTest[data-status='fail'] {
295
+ color: var(--dsw-alias-state-error-primary);
296
+ }
297
+
298
+ /* --- badges ------------------------------------------------------------------- */
299
+
300
+ .badge {
301
+ display: inline-block;
302
+ padding: 1px 8px;
303
+ font-size: 11px;
304
+ line-height: 1.6;
305
+ border-radius: 999px;
306
+ border: 1px solid var(--dsw-alias-border-l2);
307
+ color: var(--dsw-alias-label-secondary);
308
+ white-space: nowrap;
309
+ }
310
+
311
+ .badge[data-kind='key'] {
312
+ color: var(--dsw-alias-state-business-primary);
313
+ border-color: var(--dsw-alias-state-business-primary);
314
+ }
315
+
316
+ .badge[data-kind='password'] {
317
+ color: var(--dsw-alias-state-warn-primary);
318
+ border-color: var(--dsw-alias-state-warn-primary);
319
+ }
320
+
321
+ .badge[data-status='ok'] {
322
+ color: var(--dsw-alias-state-success-primary);
323
+ border-color: var(--dsw-alias-state-success-primary);
324
+ }
325
+
326
+ .badge[data-status='fail'] {
327
+ color: var(--dsw-alias-state-error-primary);
328
+ border-color: var(--dsw-alias-state-error-primary);
329
+ }
330
+
331
+ .badge[data-status='timeout'] {
332
+ color: var(--dsw-alias-state-warn-primary);
333
+ border-color: var(--dsw-alias-state-warn-primary);
334
+ }
335
+
336
+ /* --- buttons ------------------------------------------------------------------ */
337
+
338
+ .primaryButton {
339
+ padding: 6px 14px;
340
+ font-size: 13px;
341
+ font-weight: 600;
342
+ color: var(--dsw-alias-label-primary-foreground);
343
+ background: var(--dsw-alias-button-info-fill);
344
+ border: none;
345
+ border-radius: 8px;
346
+ cursor: pointer;
347
+ white-space: nowrap;
348
+ }
349
+
350
+ .primaryButton:hover:not(:disabled) {
351
+ background: var(--dsw-alias-button-info-hover);
352
+ }
353
+
354
+ .primaryButton:disabled {
355
+ opacity: 0.5;
356
+ cursor: default;
357
+ }
358
+
359
+ .ghostButton {
360
+ padding: 5px 12px;
361
+ font-size: 12px;
362
+ color: var(--dsw-alias-label-primary);
363
+ background: transparent;
364
+ border: 1px solid var(--dsw-alias-border-l2);
365
+ border-radius: 8px;
366
+ cursor: pointer;
367
+ white-space: nowrap;
368
+ }
369
+
370
+ .ghostButton:hover:not(:disabled) {
371
+ background: var(--dsw-alias-interactive-bg-hover);
372
+ }
373
+
374
+ .ghostButton:disabled {
375
+ opacity: 0.45;
376
+ cursor: default;
377
+ }
378
+
379
+ .iconButton {
380
+ display: inline-flex;
381
+ align-items: center;
382
+ justify-content: center;
383
+ width: 26px;
384
+ height: 26px;
385
+ padding: 0;
386
+ background: transparent;
387
+ border: none;
388
+ border-radius: 6px;
389
+ color: var(--dsw-alias-label-secondary);
390
+ cursor: pointer;
391
+ font-size: 13px;
392
+ }
393
+
394
+ .iconButton:hover {
395
+ background: var(--dsw-alias-interactive-bg-hover);
396
+ color: var(--dsw-alias-label-primary);
397
+ }
398
+
399
+ .linkButton {
400
+ padding: 0;
401
+ font-size: 12px;
402
+ color: var(--dsw-alias-state-business-primary);
403
+ background: none;
404
+ border: none;
405
+ cursor: pointer;
406
+ white-space: nowrap;
407
+ }
408
+
409
+ .linkButton:hover:not(:disabled) {
410
+ text-decoration: underline;
411
+ }
412
+
413
+ .linkButton:disabled {
414
+ opacity: 0.45;
415
+ cursor: default;
416
+ }
417
+
418
+ .linkButton[data-danger] {
419
+ color: var(--dsw-alias-state-error-primary);
420
+ }
421
+
422
+ /* --- spinner / banners / states ------------------------------------------------ */
423
+
424
+ .spinner {
425
+ display: inline-block;
426
+ width: 11px;
427
+ height: 11px;
428
+ flex: none;
429
+ border: 2px solid var(--dsw-alias-state-business-primary);
430
+ border-top-color: transparent;
431
+ border-radius: 50%;
432
+ animation: dshSshSpin 800ms linear infinite;
433
+ vertical-align: -1px;
434
+ }
435
+
436
+ @keyframes dshSshSpin {
437
+ to { transform: rotate(360deg); }
438
+ }
439
+
440
+ .banner {
441
+ padding: 8px 12px;
442
+ font-size: 12.5px;
443
+ line-height: 1.5;
444
+ border-radius: 8px;
445
+ border: 1px solid var(--dsw-alias-border-l2);
446
+ color: var(--dsw-alias-label-secondary);
447
+ overflow-wrap: anywhere;
448
+ }
449
+
450
+ .banner[data-kind='ok'] {
451
+ color: var(--dsw-alias-state-success-primary);
452
+ border-color: var(--dsw-alias-state-success-primary);
453
+ }
454
+
455
+ .banner[data-kind='error'] {
456
+ color: var(--dsw-alias-state-error-primary);
457
+ border-color: var(--dsw-alias-state-error-primary);
458
+ }
459
+
460
+ .banner[data-kind='info'] {
461
+ color: var(--dsw-alias-state-business-primary);
462
+ border-color: var(--dsw-alias-state-business-primary);
463
+ }
464
+
465
+ .empty {
466
+ padding: 28px 12px;
467
+ text-align: center;
468
+ font-size: 12.5px;
469
+ color: var(--dsw-alias-label-tertiary);
470
+ }
471
+
472
+ .loading {
473
+ padding: 28px 12px;
474
+ text-align: center;
475
+ font-size: 12.5px;
476
+ color: var(--dsw-alias-label-tertiary);
477
+ }
478
+
479
+ /* --- modal (host form) -------------------------------------------------------- */
480
+
481
+ .modalBackdrop {
482
+ position: fixed;
483
+ inset: 0;
484
+ z-index: 40;
485
+ display: flex;
486
+ align-items: center;
487
+ justify-content: center;
488
+ background: var(--dsw-alias-bg-mask-1);
489
+ }
490
+
491
+ .modal {
492
+ display: flex;
493
+ flex-direction: column;
494
+ gap: 12px;
495
+ width: min(560px, calc(100vw - 48px));
496
+ max-height: calc(100vh - 96px);
497
+ overflow-y: auto;
498
+ padding: 18px;
499
+ background: var(--dsw-alias-bg-base);
500
+ border: 1px solid var(--dsw-alias-border-l2);
501
+ border-radius: 14px;
502
+ box-shadow: var(--dsw-shadow-lv3);
503
+ color: var(--dsw-alias-label-primary);
504
+ }
505
+
506
+ .modalTitle {
507
+ margin: 0;
508
+ font-size: 15px;
509
+ font-weight: 700;
510
+ }
511
+
512
+ .modalFooter {
513
+ display: flex;
514
+ justify-content: flex-end;
515
+ gap: 10px;
516
+ margin-top: 4px;
517
+ }
518
+
519
+ .formError {
520
+ margin: 0;
521
+ font-size: 12px;
522
+ color: var(--dsw-alias-state-error-primary);
523
+ }
524
+
525
+ .hint {
526
+ font-size: 11.5px;
527
+ color: var(--dsw-alias-label-tertiary);
528
+ }
529
+
530
+ .field {
531
+ display: flex;
532
+ flex-direction: column;
533
+ gap: 5px;
534
+ }
535
+
536
+ .fieldLabel {
537
+ font-size: 12px;
538
+ font-weight: 600;
539
+ color: var(--dsw-alias-label-secondary);
540
+ }
541
+
542
+ .input {
543
+ padding: 7px 10px;
544
+ font-size: 13px;
545
+ color: var(--dsw-alias-label-primary);
546
+ background: var(--dsw-specific-input-major);
547
+ border: 1px solid var(--dsw-alias-border-l2);
548
+ border-radius: 8px;
549
+ outline: none;
550
+ resize: vertical;
551
+ font-family: inherit;
552
+ }
553
+
554
+ .input:focus {
555
+ border-color: var(--dsw-alias-state-business-primary);
556
+ }
557
+
558
+ .input::placeholder {
559
+ color: var(--dsw-alias-label-tertiary);
560
+ }
561
+
562
+ .input:disabled {
563
+ opacity: 0.55;
564
+ }
565
+
566
+ .formRow {
567
+ display: grid;
568
+ grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
569
+ gap: 10px 12px;
570
+ }
571
+
572
+ .radioRow {
573
+ display: flex;
574
+ gap: 16px;
575
+ align-items: center;
576
+ }
577
+
578
+ .radioLabel {
579
+ display: inline-flex;
580
+ gap: 6px;
581
+ align-items: center;
582
+ font-size: 13px;
583
+ color: var(--dsw-alias-label-primary);
584
+ cursor: pointer;
585
+ }
586
+
587
+ /* --- terminal ----------------------------------------------------------------- */
588
+
589
+ .termBody {
590
+ display: flex;
591
+ flex-direction: column;
592
+ gap: 8px;
593
+ flex: 1;
594
+ min-height: 0;
595
+ overflow: hidden;
596
+ }
597
+
598
+ .termWrap {
599
+ position: relative;
600
+ flex: 1;
601
+ min-height: 0;
602
+ border: 1px solid var(--dsw-alias-border-l1);
603
+ border-radius: 10px;
604
+ overflow: hidden;
605
+ background: #0b0e14;
606
+ }
607
+
608
+ .termContainer {
609
+ position: absolute;
610
+ inset: 0;
611
+ padding: 8px 10px;
612
+ }
613
+
614
+ .termPlaceholder {
615
+ position: absolute;
616
+ inset: 0;
617
+ z-index: 2;
618
+ display: flex;
619
+ align-items: center;
620
+ justify-content: center;
621
+ padding: 0 24px;
622
+ text-align: center;
623
+ font-size: 12.5px;
624
+ color: var(--dsw-alias-label-tertiary);
625
+ background: var(--dsw-alias-bg-base);
626
+ }
627
+
628
+ /* --- transfer ----------------------------------------------------------------- */
629
+
630
+ .hiddenFile {
631
+ display: none;
632
+ }
633
+
634
+ .browsePanel {
635
+ display: flex;
636
+ flex-direction: column;
637
+ flex: none;
638
+ border: 1px solid var(--dsw-alias-border-l1);
639
+ border-radius: 10px;
640
+ overflow: hidden;
641
+ }
642
+
643
+ .browseHeader {
644
+ display: flex;
645
+ align-items: center;
646
+ gap: 8px;
647
+ padding: 8px 10px;
648
+ background: var(--dsw-alias-bg-layer-2);
649
+ border-bottom: 1px solid var(--dsw-alias-border-l1);
650
+ }
651
+
652
+ .browsePath {
653
+ flex: 1;
654
+ min-width: 0;
655
+ overflow: hidden;
656
+ text-overflow: ellipsis;
657
+ white-space: nowrap;
658
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
659
+ font-size: 12px;
660
+ color: var(--dsw-alias-label-secondary);
661
+ }
662
+
663
+ .browseList {
664
+ max-height: 240px;
665
+ overflow-y: auto;
666
+ }
667
+
668
+ .dirRow {
669
+ display: grid;
670
+ grid-template-columns: minmax(0, 1fr) auto auto;
671
+ gap: 12px;
672
+ width: 100%;
673
+ padding: 5px 10px;
674
+ text-align: left;
675
+ font: inherit;
676
+ font-size: 12.5px;
677
+ color: var(--dsw-alias-label-primary);
678
+ background: transparent;
679
+ border: none;
680
+ border-bottom: 1px solid var(--dsw-alias-separator-primary);
681
+ cursor: pointer;
682
+ }
683
+
684
+ .dirRow:hover {
685
+ background: var(--dsw-alias-interactive-bg-hover);
686
+ }
687
+
688
+ .dirRow[data-type='dir'] .dirName {
689
+ color: var(--dsw-alias-state-business-primary);
690
+ }
691
+
692
+ .dirRow[data-up] {
693
+ color: var(--dsw-alias-label-secondary);
694
+ }
695
+
696
+ .dirName {
697
+ overflow: hidden;
698
+ text-overflow: ellipsis;
699
+ white-space: nowrap;
700
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
701
+ }
702
+
703
+ .dirType {
704
+ color: var(--dsw-alias-label-tertiary);
705
+ white-space: nowrap;
706
+ }
707
+
708
+ .dirSize {
709
+ color: var(--dsw-alias-label-tertiary);
710
+ white-space: nowrap;
711
+ text-align: right;
712
+ }
713
+
714
+ .transferBlock {
715
+ display: flex;
716
+ flex-direction: column;
717
+ gap: 6px;
718
+ flex: none;
719
+ }
720
+
721
+ .progressMeta {
722
+ display: flex;
723
+ gap: 12px;
724
+ flex-wrap: wrap;
725
+ font-size: 12px;
726
+ color: var(--dsw-alias-label-secondary);
727
+ }
728
+
729
+ .progressTrack {
730
+ height: 8px;
731
+ border-radius: 999px;
732
+ background: var(--dsw-alias-interactive-bg-hover);
733
+ overflow: hidden;
734
+ }
735
+
736
+ .progressBar {
737
+ height: 100%;
738
+ border-radius: 999px;
739
+ background: var(--dsw-alias-state-business-primary);
740
+ transition: width 120ms linear;
741
+ }
742
+
743
+ /* --- tunnels ------------------------------------------------------------------ */
744
+
745
+ .tunnelList {
746
+ display: flex;
747
+ flex-direction: column;
748
+ gap: 8px;
749
+ flex: none;
750
+ }
751
+
752
+ .tunnelRow {
753
+ display: flex;
754
+ align-items: center;
755
+ gap: 10px;
756
+ padding: 8px 12px;
757
+ background: var(--dsw-alias-bg-layer-2);
758
+ border: 1px solid var(--dsw-alias-border-l2);
759
+ border-radius: 10px;
760
+ }
761
+
762
+ .tunnelRow[data-state='forwarding'] {
763
+ border-color: var(--dsw-alias-state-success-primary);
764
+ }
765
+
766
+ .tunnelRow[data-state='connecting'] {
767
+ border-color: var(--dsw-alias-state-warn-primary);
768
+ }
769
+
770
+ .tunnelRow[data-state='failed'] {
771
+ border-color: var(--dsw-alias-state-error-primary);
772
+ }
773
+
774
+ .tunnelLabel {
775
+ flex: 1;
776
+ min-width: 0;
777
+ overflow: hidden;
778
+ text-overflow: ellipsis;
779
+ white-space: nowrap;
780
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
781
+ font-size: 12.5px;
782
+ }
783
+
784
+ .formCard {
785
+ display: flex;
786
+ flex-direction: column;
787
+ gap: 10px;
788
+ padding: 12px;
789
+ background: var(--dsw-alias-bg-layer-2);
790
+ border: 1px solid var(--dsw-alias-border-l1);
791
+ border-radius: 10px;
792
+ flex: none;
793
+ }
794
+
795
+ /* --- cluster ------------------------------------------------------------------ */
796
+
797
+ .clusterForm {
798
+ display: flex;
799
+ flex-direction: column;
800
+ gap: 8px;
801
+ flex: none;
802
+ }
803
+
804
+ .clusterFilters {
805
+ display: grid;
806
+ grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
807
+ gap: 10px;
808
+ }
809
+
810
+ .commandInput {
811
+ min-height: 96px;
812
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
813
+ }
814
+
815
+ .cellDetails summary {
816
+ cursor: pointer;
817
+ font-size: 12px;
818
+ color: var(--dsw-alias-label-secondary);
819
+ }
820
+
821
+ .cellPre {
822
+ margin: 4px 0 0;
823
+ padding: 6px 8px;
824
+ max-height: 180px;
825
+ overflow: auto;
826
+ background: var(--dsw-alias-bg-layer-2);
827
+ border: 1px solid var(--dsw-alias-border-l2);
828
+ border-radius: 6px;
829
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
830
+ font-size: 11.5px;
831
+ white-space: pre-wrap;
832
+ word-break: break-all;
833
+ }