@worca/ui 0.22.0 → 0.23.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/app/main.bundle.js +6180 -4706
- package/app/main.bundle.js.map +4 -4
- package/app/protocol.js +2 -1
- package/app/styles.css +869 -15
- package/app/utils/state-actions.js +13 -2
- package/package.json +1 -1
- package/server/app.js +68 -1
- package/server/fleet-routes.js +1147 -0
- package/server/integrations/commands/fleet.js +266 -0
- package/server/integrations/commands/global.js +9 -0
- package/server/integrations/commands/parser.js +4 -1
- package/server/integrations/index.js +3 -0
- package/server/integrations/renderers.js +98 -0
- package/server/integrations/rest_client.js +7 -0
- package/server/worktrees-routes.js +34 -0
- package/server/ws-fleet-manifest-watcher.js +130 -0
- package/server/ws-message-router.js +20 -0
- package/server/ws-modular.js +10 -1
package/app/styles.css
CHANGED
|
@@ -1150,6 +1150,18 @@ sl-input [slot="prefix"] {
|
|
|
1150
1150
|
color: var(--status-cancelled);
|
|
1151
1151
|
}
|
|
1152
1152
|
|
|
1153
|
+
.status-halted {
|
|
1154
|
+
color: var(--status-paused);
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
.status-setup-failed {
|
|
1158
|
+
color: var(--status-failed);
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
.status-unrecoverable {
|
|
1162
|
+
color: var(--status-failed);
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1153
1165
|
/* --- 18b. Control Buttons --- */
|
|
1154
1166
|
.action-btn--amber {
|
|
1155
1167
|
border-color: var(--status-paused);
|
|
@@ -1171,6 +1183,19 @@ sl-input [slot="prefix"] {
|
|
|
1171
1183
|
color: #ffffff;
|
|
1172
1184
|
}
|
|
1173
1185
|
|
|
1186
|
+
.action-btn--teal {
|
|
1187
|
+
/* "Re-run" / "iterate again" actions — distinct from primary blue
|
|
1188
|
+
(resume) and status palette colors so it reads as a separate
|
|
1189
|
+
intent: launch a fresh attempt from this one. */
|
|
1190
|
+
border-color: #0891b2;
|
|
1191
|
+
color: #0891b2;
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
.action-btn--teal:hover {
|
|
1195
|
+
background: #0891b2;
|
|
1196
|
+
color: #ffffff;
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1174
1199
|
.action-btn--red {
|
|
1175
1200
|
border-color: var(--status-failed);
|
|
1176
1201
|
color: var(--status-failed);
|
|
@@ -1302,11 +1327,142 @@ sl-input [slot="prefix"] {
|
|
|
1302
1327
|
|
|
1303
1328
|
/* Status-colored left border accent on run cards */
|
|
1304
1329
|
.run-card.status-running { border-left: 3px solid var(--status-running); }
|
|
1330
|
+
.run-card.status-resuming { border-left: 3px solid var(--status-running); }
|
|
1305
1331
|
.run-card.status-paused { border-left: 3px solid var(--status-paused); }
|
|
1332
|
+
.run-card.status-interrupted { border-left: 3px solid var(--status-interrupted); }
|
|
1306
1333
|
.run-card.status-completed { border-left: 3px solid var(--status-completed); }
|
|
1307
1334
|
.run-card.status-failed { border-left: 3px solid var(--status-failed); }
|
|
1335
|
+
.run-card.status-error { border-left: 3px solid var(--status-error); }
|
|
1308
1336
|
.run-card.status-pending { border-left: 3px solid var(--status-pending); }
|
|
1337
|
+
.run-card.status-skipped { border-left: 3px solid var(--status-pending); }
|
|
1309
1338
|
.run-card.status-cancelled { border-left: 3px solid var(--status-cancelled); }
|
|
1339
|
+
.run-card.status-halted { border-left: 3px solid var(--status-paused); }
|
|
1340
|
+
.run-card.status-setup-failed { border-left: 3px solid var(--status-failed); }
|
|
1341
|
+
.run-card.status-unrecoverable { border-left: 3px solid var(--status-failed); }
|
|
1342
|
+
|
|
1343
|
+
/* ── Fleet card (shared component for Dashboard + Fleet list) ───────────
|
|
1344
|
+
The fleet card reuses the `.run-card` base class and its shared
|
|
1345
|
+
structural sub-elements (`.run-card-top`, `.run-card-status`,
|
|
1346
|
+
`.run-card-title`, `.run-card-meta`, `.run-card-meta-item`,
|
|
1347
|
+
`.run-card-actions`) — exactly like `.worktree-card` does. The
|
|
1348
|
+
`.fleet-card` / `.fleet-card-*` rules below are only the bits that are
|
|
1349
|
+
genuinely fleet-specific:
|
|
1350
|
+
- a layered "stack of cards" silhouette (::before / ::after layers)
|
|
1351
|
+
- the "Projects:" name-badge row
|
|
1352
|
+
- the failed-count pill + exception pills
|
|
1353
|
+
The box, hover, and status-accent styling all come from `.run-card`. */
|
|
1354
|
+
|
|
1355
|
+
/* Stack-of-cards illusion: two thin layers above-right behind the main card,
|
|
1356
|
+
each progressively offset and dimmed. Pure decoration — pointer-events
|
|
1357
|
+
off so they never steal clicks. */
|
|
1358
|
+
.fleet-card-stack {
|
|
1359
|
+
position: relative;
|
|
1360
|
+
isolation: isolate;
|
|
1361
|
+
}
|
|
1362
|
+
.fleet-card-stack::before,
|
|
1363
|
+
.fleet-card-stack::after {
|
|
1364
|
+
content: '';
|
|
1365
|
+
position: absolute;
|
|
1366
|
+
inset: 0;
|
|
1367
|
+
border: 1px solid var(--border-subtle);
|
|
1368
|
+
border-radius: var(--radius-lg);
|
|
1369
|
+
background: var(--surface);
|
|
1370
|
+
pointer-events: none;
|
|
1371
|
+
z-index: -1;
|
|
1372
|
+
}
|
|
1373
|
+
.fleet-card-stack::before {
|
|
1374
|
+
transform: translate(4px, -4px);
|
|
1375
|
+
opacity: 0.55;
|
|
1376
|
+
}
|
|
1377
|
+
.fleet-card-stack::after {
|
|
1378
|
+
transform: translate(8px, -8px);
|
|
1379
|
+
opacity: 0.3;
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
/* The status-coloured left edge comes from `.run-card.status-*` (the
|
|
1383
|
+
fleet card carries the `run-card` base class). The one fleet-specific
|
|
1384
|
+
override: a user-initiated halt reads as informational grey, matching
|
|
1385
|
+
its `neutral` status-badge variant — per the badge-color-language
|
|
1386
|
+
guide §CSS Variables. Circuit-breaker / targets-not-ready halts keep
|
|
1387
|
+
the inherited orange. */
|
|
1388
|
+
.fleet-card.status-halted[data-halt-reason="user"] {
|
|
1389
|
+
border-left-color: var(--status-pending);
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
/* Project name badges — the value of the "Projects:" meta label. Neutral
|
|
1393
|
+
(no status color), each clamped to ~20ch with an ellipsis; the JS also
|
|
1394
|
+
pre-truncates so the title attr carries the full name. Up to 3 render
|
|
1395
|
+
inline, the rest collapse into `.fleet-card-project-more`. */
|
|
1396
|
+
.fleet-card-project-badge {
|
|
1397
|
+
display: inline-block;
|
|
1398
|
+
max-width: 20ch;
|
|
1399
|
+
overflow: hidden;
|
|
1400
|
+
text-overflow: ellipsis;
|
|
1401
|
+
white-space: nowrap;
|
|
1402
|
+
vertical-align: bottom;
|
|
1403
|
+
padding: 1px 8px;
|
|
1404
|
+
font-size: 11px;
|
|
1405
|
+
color: var(--fg);
|
|
1406
|
+
background: var(--bg-tertiary);
|
|
1407
|
+
border: 1px solid var(--border-subtle);
|
|
1408
|
+
border-radius: 999px;
|
|
1409
|
+
flex-shrink: 0;
|
|
1410
|
+
}
|
|
1411
|
+
.fleet-card-project-more {
|
|
1412
|
+
font-size: 11px;
|
|
1413
|
+
color: var(--muted);
|
|
1414
|
+
flex-shrink: 0;
|
|
1415
|
+
}
|
|
1416
|
+
/* Failed-project count — rides the "Projects:" row after the name badges
|
|
1417
|
+
as a solid red badge (e.g. "1 failed"). Only rendered when at least one
|
|
1418
|
+
project failed; callers guard with `failedCount > 0`. */
|
|
1419
|
+
.fleet-card-failed-count {
|
|
1420
|
+
display: inline-block;
|
|
1421
|
+
flex-shrink: 0;
|
|
1422
|
+
padding: 1px 8px;
|
|
1423
|
+
font-size: 11px;
|
|
1424
|
+
font-weight: 500;
|
|
1425
|
+
color: #ffffff;
|
|
1426
|
+
background: var(--status-error);
|
|
1427
|
+
border-radius: 999px;
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
/* Exception counter pills — surface non-zero failure / halted / paused
|
|
1431
|
+
buckets when they don't already match the fleet's overall status badge.
|
|
1432
|
+
Variants follow the badge-color-language guide: `danger` for failures,
|
|
1433
|
+
`warning` for halts/pauses. Replaces the prior right-edge accent stripe
|
|
1434
|
+
(which was too subtle to be actionable). */
|
|
1435
|
+
.fleet-card-exception-pill {
|
|
1436
|
+
flex-shrink: 0;
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
.fleet-card-mono {
|
|
1440
|
+
font-family: var(--font-mono, ui-monospace, monospace);
|
|
1441
|
+
font-size: 11px;
|
|
1442
|
+
color: var(--fg);
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
.fleet-card-children-label {
|
|
1446
|
+
align-self: center;
|
|
1447
|
+
flex-shrink: 0;
|
|
1448
|
+
font-size: 12px;
|
|
1449
|
+
/* Color/weight inherited from `.meta-label` so this row matches the
|
|
1450
|
+
Plan/Base/Started/Duration label vocabulary on the rows below. */
|
|
1451
|
+
}
|
|
1452
|
+
.fleet-card-children-empty {
|
|
1453
|
+
font-size: 12px;
|
|
1454
|
+
color: var(--muted);
|
|
1455
|
+
font-style: italic;
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
/* "Projects:" label + name-badge list row. */
|
|
1459
|
+
.fleet-card-progress {
|
|
1460
|
+
display: flex;
|
|
1461
|
+
align-items: center;
|
|
1462
|
+
flex-wrap: wrap;
|
|
1463
|
+
gap: 6px;
|
|
1464
|
+
padding-left: 26px;
|
|
1465
|
+
}
|
|
1310
1466
|
|
|
1311
1467
|
/* --- 21. Dashboard --- */
|
|
1312
1468
|
.dashboard {
|
|
@@ -2340,7 +2496,39 @@ sl-details.live-output-panel::part(content) {
|
|
|
2340
2496
|
.new-run-advanced {
|
|
2341
2497
|
display: flex;
|
|
2342
2498
|
flex-direction: column;
|
|
2343
|
-
gap:
|
|
2499
|
+
gap: 24px;
|
|
2500
|
+
}
|
|
2501
|
+
|
|
2502
|
+
/* Advanced Options is dense — give each field a touch more breathing room
|
|
2503
|
+
between label / control / hint than the default 4px so multi-line
|
|
2504
|
+
sub-controls (head-template preview, plan-mode radio + warning) don't
|
|
2505
|
+
feel stacked. Scoped to .new-run-advanced so the rest of Settings
|
|
2506
|
+
keeps its tighter rhythm. */
|
|
2507
|
+
.new-run-advanced .settings-field {
|
|
2508
|
+
gap: 8px;
|
|
2509
|
+
}
|
|
2510
|
+
.new-run-advanced .settings-field-hint {
|
|
2511
|
+
margin-top: 4px;
|
|
2512
|
+
line-height: 1.5;
|
|
2513
|
+
}
|
|
2514
|
+
|
|
2515
|
+
/* Visual subgroup inside Advanced Options — small caps title + subtle
|
|
2516
|
+
underline divider. Keeps the section card's outer border doing the
|
|
2517
|
+
heavy lifting; the subgroup title is just a quiet "BRANCHES" /
|
|
2518
|
+
"PLANNING" / "CONCURRENCY" label for scanability. */
|
|
2519
|
+
.advanced-subgroup {
|
|
2520
|
+
display: flex;
|
|
2521
|
+
flex-direction: column;
|
|
2522
|
+
gap: 14px;
|
|
2523
|
+
}
|
|
2524
|
+
.advanced-subgroup-title {
|
|
2525
|
+
font-size: 11px;
|
|
2526
|
+
font-weight: 600;
|
|
2527
|
+
color: var(--muted);
|
|
2528
|
+
text-transform: uppercase;
|
|
2529
|
+
letter-spacing: 0.06em;
|
|
2530
|
+
padding-bottom: 6px;
|
|
2531
|
+
border-bottom: 1px dashed var(--border-subtle);
|
|
2344
2532
|
}
|
|
2345
2533
|
|
|
2346
2534
|
.new-run-grid {
|
|
@@ -2484,39 +2672,106 @@ sl-option.template-grouped:focus::part(suffix) {
|
|
|
2484
2672
|
background: var(--bg-tertiary);
|
|
2485
2673
|
}
|
|
2486
2674
|
|
|
2487
|
-
/* Sidebar new run button
|
|
2675
|
+
/* Sidebar new run button (split button pattern: primary + chevron).
|
|
2676
|
+
The split button is the W-040 UX choice — primary "New Pipeline"
|
|
2677
|
+
handles the common case; the chevron drops down to a menu of
|
|
2678
|
+
multi-project alternatives (Fleet, plus Workspace when W-047 ships). */
|
|
2488
2679
|
.sidebar-new-run {
|
|
2489
2680
|
padding: 8px 8px 4px;
|
|
2490
2681
|
}
|
|
2491
2682
|
|
|
2492
|
-
.sidebar-new-run-
|
|
2683
|
+
.sidebar-new-run-split {
|
|
2493
2684
|
display: flex;
|
|
2494
|
-
align-items:
|
|
2495
|
-
justify-content: center;
|
|
2496
|
-
gap: 8px;
|
|
2685
|
+
align-items: stretch;
|
|
2497
2686
|
width: 100%;
|
|
2498
|
-
|
|
2687
|
+
min-height: 36px;
|
|
2499
2688
|
border: 2px dashed var(--accent);
|
|
2500
2689
|
border-radius: var(--radius);
|
|
2690
|
+
overflow: hidden;
|
|
2691
|
+
background: transparent;
|
|
2692
|
+
transition: background var(--transition-fast), border-color var(--transition-fast);
|
|
2693
|
+
}
|
|
2694
|
+
|
|
2695
|
+
.sidebar-new-run-btn-primary {
|
|
2696
|
+
flex: 1 1 auto;
|
|
2697
|
+
display: flex;
|
|
2698
|
+
align-items: center;
|
|
2699
|
+
justify-content: center;
|
|
2700
|
+
gap: 8px;
|
|
2701
|
+
min-width: 0;
|
|
2702
|
+
padding: 6px 12px;
|
|
2703
|
+
border: 0;
|
|
2704
|
+
border-right: 2px dashed var(--accent);
|
|
2501
2705
|
background: transparent;
|
|
2502
2706
|
color: var(--accent);
|
|
2503
2707
|
font-size: 13px;
|
|
2504
2708
|
font-weight: 600;
|
|
2505
2709
|
font-family: inherit;
|
|
2506
2710
|
cursor: pointer;
|
|
2711
|
+
transition: background var(--transition-fast), color var(--transition-fast),
|
|
2712
|
+
border-color var(--transition-fast);
|
|
2713
|
+
}
|
|
2714
|
+
|
|
2715
|
+
.sidebar-new-run-btn-primary:hover:not(:disabled) {
|
|
2716
|
+
background: var(--accent);
|
|
2717
|
+
color: #ffffff;
|
|
2718
|
+
}
|
|
2719
|
+
|
|
2720
|
+
/* Disabled state: muted (not ghosted) so it reads as "waiting on something"
|
|
2721
|
+
rather than a broken control. Pairs with the title tooltip explaining
|
|
2722
|
+
why it's inactive (e.g., "Select a project first…"). */
|
|
2723
|
+
.sidebar-new-run-btn-primary:disabled {
|
|
2724
|
+
cursor: not-allowed;
|
|
2725
|
+
color: var(--muted);
|
|
2726
|
+
border-right-color: var(--muted);
|
|
2727
|
+
}
|
|
2728
|
+
|
|
2729
|
+
/* sl-dropdown defaults to inline-block; force it to fill the cross-axis
|
|
2730
|
+
so the slotted chevron button can stretch to the full split height. */
|
|
2731
|
+
.sidebar-new-run-chevron-dropdown {
|
|
2732
|
+
display: flex;
|
|
2733
|
+
flex: 0 0 auto;
|
|
2734
|
+
align-self: stretch;
|
|
2735
|
+
}
|
|
2736
|
+
|
|
2737
|
+
.sidebar-new-run-btn-chevron {
|
|
2738
|
+
display: flex;
|
|
2739
|
+
align-items: center;
|
|
2740
|
+
justify-content: center;
|
|
2741
|
+
align-self: stretch;
|
|
2742
|
+
height: 100%;
|
|
2743
|
+
min-height: 32px;
|
|
2744
|
+
padding: 0 12px;
|
|
2745
|
+
border: 0;
|
|
2746
|
+
background: transparent;
|
|
2747
|
+
color: var(--accent);
|
|
2748
|
+
cursor: pointer;
|
|
2507
2749
|
transition: background var(--transition-fast), color var(--transition-fast);
|
|
2508
2750
|
}
|
|
2509
2751
|
|
|
2510
|
-
.sidebar-new-run-btn:hover {
|
|
2752
|
+
.sidebar-new-run-btn-chevron:hover:not(:disabled) {
|
|
2511
2753
|
background: var(--accent);
|
|
2512
2754
|
color: #ffffff;
|
|
2513
2755
|
}
|
|
2514
2756
|
|
|
2515
|
-
.sidebar
|
|
2757
|
+
.sidebar-new-run-btn-chevron:disabled {
|
|
2758
|
+
cursor: not-allowed;
|
|
2759
|
+
color: var(--muted);
|
|
2760
|
+
}
|
|
2761
|
+
|
|
2762
|
+
/* Menu items: icon + label, slight indent under their icon */
|
|
2763
|
+
.sidebar-new-run-chevron-dropdown sl-menu-item::part(base) {
|
|
2764
|
+
display: flex;
|
|
2765
|
+
align-items: center;
|
|
2766
|
+
gap: 8px;
|
|
2767
|
+
font-size: 13px;
|
|
2768
|
+
}
|
|
2769
|
+
|
|
2770
|
+
.sidebar.collapsed .sidebar-new-run-btn-primary span {
|
|
2516
2771
|
display: none;
|
|
2517
2772
|
}
|
|
2518
2773
|
|
|
2519
|
-
.sidebar.collapsed .sidebar-new-run-btn {
|
|
2774
|
+
.sidebar.collapsed .sidebar-new-run-btn-primary {
|
|
2520
2775
|
padding: 8px;
|
|
2521
2776
|
}
|
|
2522
2777
|
|
|
@@ -2906,6 +3161,16 @@ sl-details.run-beads-panel::part(content) {
|
|
|
2906
3161
|
border: 1px solid var(--border-subtle);
|
|
2907
3162
|
}
|
|
2908
3163
|
|
|
3164
|
+
/* Default badge layout: when a badge contains an icon + text (e.g. the
|
|
3165
|
+
pipeline-page header status badge "<icon> Completed"), the children
|
|
3166
|
+
sit flush against each other. Give them a small gap. Single-child
|
|
3167
|
+
badges are unaffected because flex+gap only manifests between siblings. */
|
|
3168
|
+
sl-badge::part(base) {
|
|
3169
|
+
display: inline-flex;
|
|
3170
|
+
align-items: center;
|
|
3171
|
+
gap: 4px;
|
|
3172
|
+
}
|
|
3173
|
+
|
|
2909
3174
|
.run-bead-row sl-badge::part(base) {
|
|
2910
3175
|
font-size: 0.68rem;
|
|
2911
3176
|
padding: 0 5px;
|
|
@@ -3960,6 +4225,7 @@ sl-details.learnings-panel::part(content) {
|
|
|
3960
4225
|
.filter-chip-failed.active { background: var(--status-failed); border-color: var(--status-failed); }
|
|
3961
4226
|
.filter-chip-paused.active { background: var(--status-paused); border-color: var(--status-paused); }
|
|
3962
4227
|
.filter-chip-error.active { background: var(--status-failed); border-color: var(--status-failed); }
|
|
4228
|
+
.filter-chip-halted.active { background: var(--status-paused); border-color: var(--status-paused); }
|
|
3963
4229
|
.filter-chip .chip-count {
|
|
3964
4230
|
font-size: 0.68rem;
|
|
3965
4231
|
opacity: 0.7;
|
|
@@ -3970,6 +4236,7 @@ sl-details.learnings-panel::part(content) {
|
|
|
3970
4236
|
display: flex;
|
|
3971
4237
|
align-items: center;
|
|
3972
4238
|
justify-content: flex-end;
|
|
4239
|
+
flex-wrap: wrap;
|
|
3973
4240
|
gap: 8px;
|
|
3974
4241
|
padding-left: 26px;
|
|
3975
4242
|
}
|
|
@@ -4036,11 +4303,8 @@ sl-details.learnings-panel::part(content) {
|
|
|
4036
4303
|
.project-status-paused { background: var(--status-paused, #eab308); }
|
|
4037
4304
|
|
|
4038
4305
|
/* --- Dashboard Project Cards --- */
|
|
4039
|
-
.project-cards
|
|
4040
|
-
|
|
4041
|
-
.project-card:hover { border-color: var(--accent); box-shadow: var(--shadow-sm); }
|
|
4042
|
-
.project-card-name { font-weight: 600; margin-bottom: 4px; }
|
|
4043
|
-
.project-card-stats { font-size: 0.85rem; color: var(--text-secondary); }
|
|
4306
|
+
/* .project-cards / .project-card-* removed — see app/views/dashboard.js
|
|
4307
|
+
for the rationale (sidebar dropdown replaces them). */
|
|
4044
4308
|
|
|
4045
4309
|
/* --- Settings Projects List --- */
|
|
4046
4310
|
.projects-list-item { display: flex; justify-content: space-between; align-items: center; padding: 8px 0; border-bottom: 1px solid var(--border); }
|
|
@@ -4639,6 +4903,23 @@ sl-tooltip.bead-tooltip::part(body) {
|
|
|
4639
4903
|
flex: 1;
|
|
4640
4904
|
min-width: 240px;
|
|
4641
4905
|
}
|
|
4906
|
+
|
|
4907
|
+
/* Shared text-filter row — the line under the filter chips on the
|
|
4908
|
+
History and Fleets list pages. Mirrors `.worktrees-toolbar` so the
|
|
4909
|
+
three list pages present an identical filter affordance. The
|
|
4910
|
+
worktrees page keeps its own toolbar (it carries the extra
|
|
4911
|
+
"Cleanup all completed" button alongside the text input). */
|
|
4912
|
+
.list-filter-row {
|
|
4913
|
+
display: flex;
|
|
4914
|
+
align-items: center;
|
|
4915
|
+
gap: 12px;
|
|
4916
|
+
flex-wrap: wrap;
|
|
4917
|
+
margin-bottom: 12px;
|
|
4918
|
+
}
|
|
4919
|
+
.list-filter-row .list-text-filter {
|
|
4920
|
+
flex: 1;
|
|
4921
|
+
min-width: 240px;
|
|
4922
|
+
}
|
|
4642
4923
|
.worktree-card-path {
|
|
4643
4924
|
align-items: baseline;
|
|
4644
4925
|
}
|
|
@@ -4854,3 +5135,576 @@ sl-tooltip.bead-tooltip::part(body) {
|
|
|
4854
5135
|
line-height: 1.2;
|
|
4855
5136
|
flex: 0 0 auto;
|
|
4856
5137
|
}
|
|
5138
|
+
|
|
5139
|
+
/* ─── Fleet group (W-040 §13.2) ────────────────────────────────────────────── */
|
|
5140
|
+
.fleet-group {
|
|
5141
|
+
margin-bottom: 8px;
|
|
5142
|
+
border: 1px solid var(--border-subtle);
|
|
5143
|
+
border-radius: 8px;
|
|
5144
|
+
overflow: hidden;
|
|
5145
|
+
}
|
|
5146
|
+
|
|
5147
|
+
.fleet-header {
|
|
5148
|
+
display: flex;
|
|
5149
|
+
align-items: center;
|
|
5150
|
+
gap: 10px;
|
|
5151
|
+
padding: 10px 14px;
|
|
5152
|
+
background: var(--bg-secondary);
|
|
5153
|
+
cursor: pointer;
|
|
5154
|
+
user-select: none;
|
|
5155
|
+
}
|
|
5156
|
+
|
|
5157
|
+
.fleet-header:hover {
|
|
5158
|
+
background: var(--bg-tertiary);
|
|
5159
|
+
}
|
|
5160
|
+
|
|
5161
|
+
.fleet-toggle {
|
|
5162
|
+
flex-shrink: 0;
|
|
5163
|
+
color: var(--fg-muted);
|
|
5164
|
+
font-size: 14px;
|
|
5165
|
+
}
|
|
5166
|
+
|
|
5167
|
+
.fleet-title {
|
|
5168
|
+
flex: 0 1 auto;
|
|
5169
|
+
font-size: 13px;
|
|
5170
|
+
font-weight: 600;
|
|
5171
|
+
color: var(--fg);
|
|
5172
|
+
overflow: hidden;
|
|
5173
|
+
text-overflow: ellipsis;
|
|
5174
|
+
white-space: nowrap;
|
|
5175
|
+
}
|
|
5176
|
+
|
|
5177
|
+
.fleet-status-badge {
|
|
5178
|
+
flex-shrink: 0;
|
|
5179
|
+
}
|
|
5180
|
+
|
|
5181
|
+
.fleet-progress {
|
|
5182
|
+
flex-shrink: 0;
|
|
5183
|
+
font-size: 12px;
|
|
5184
|
+
color: var(--fg-muted);
|
|
5185
|
+
}
|
|
5186
|
+
|
|
5187
|
+
.fleet-progress-bar {
|
|
5188
|
+
flex: 1 1 80px;
|
|
5189
|
+
min-width: 60px;
|
|
5190
|
+
max-width: 160px;
|
|
5191
|
+
}
|
|
5192
|
+
|
|
5193
|
+
.fleet-cost {
|
|
5194
|
+
flex-shrink: 0;
|
|
5195
|
+
font-size: 12px;
|
|
5196
|
+
color: var(--fg-muted);
|
|
5197
|
+
}
|
|
5198
|
+
|
|
5199
|
+
.fleet-detail-btn {
|
|
5200
|
+
flex-shrink: 0;
|
|
5201
|
+
margin-left: auto;
|
|
5202
|
+
}
|
|
5203
|
+
|
|
5204
|
+
.fleet-children {
|
|
5205
|
+
padding: 8px;
|
|
5206
|
+
display: flex;
|
|
5207
|
+
flex-direction: column;
|
|
5208
|
+
gap: 8px;
|
|
5209
|
+
background: var(--bg-primary);
|
|
5210
|
+
}
|
|
5211
|
+
|
|
5212
|
+
/* ── Fleet launcher (page) ─────────────────────────────────────────────── */
|
|
5213
|
+
|
|
5214
|
+
.fleet-launcher-page,
|
|
5215
|
+
.fleet-detail-page {
|
|
5216
|
+
max-width: 760px;
|
|
5217
|
+
}
|
|
5218
|
+
|
|
5219
|
+
.fleet-launcher-projects-controls {
|
|
5220
|
+
display: flex;
|
|
5221
|
+
gap: 8px;
|
|
5222
|
+
align-items: center;
|
|
5223
|
+
margin-bottom: 4px;
|
|
5224
|
+
}
|
|
5225
|
+
|
|
5226
|
+
.fleet-launcher-projects-controls .input-project-filter {
|
|
5227
|
+
flex: 1 1 auto;
|
|
5228
|
+
}
|
|
5229
|
+
|
|
5230
|
+
/* Head-template preview rows — render below the input as a small inset
|
|
5231
|
+
panel so the per-project resolved branches feel attached to (not just
|
|
5232
|
+
stacked under) the template field. */
|
|
5233
|
+
.head-template-input {
|
|
5234
|
+
display: flex;
|
|
5235
|
+
flex-direction: column;
|
|
5236
|
+
gap: 8px;
|
|
5237
|
+
}
|
|
5238
|
+
.head-template-preview {
|
|
5239
|
+
display: flex;
|
|
5240
|
+
flex-direction: column;
|
|
5241
|
+
gap: 4px;
|
|
5242
|
+
padding: 8px 12px;
|
|
5243
|
+
background: var(--bg-primary);
|
|
5244
|
+
border: 1px solid var(--border-subtle);
|
|
5245
|
+
border-radius: var(--radius);
|
|
5246
|
+
font-size: 12px;
|
|
5247
|
+
}
|
|
5248
|
+
.head-template-preview-row {
|
|
5249
|
+
display: flex;
|
|
5250
|
+
align-items: center;
|
|
5251
|
+
gap: 8px;
|
|
5252
|
+
font-family: var(--font-mono, ui-monospace, monospace);
|
|
5253
|
+
}
|
|
5254
|
+
.head-template-preview-row .preview-arrow {
|
|
5255
|
+
color: var(--muted);
|
|
5256
|
+
}
|
|
5257
|
+
.head-template-preview-row .preview-branch {
|
|
5258
|
+
color: var(--text);
|
|
5259
|
+
}
|
|
5260
|
+
.head-template-preview-row.collision .preview-branch {
|
|
5261
|
+
color: var(--status-error);
|
|
5262
|
+
}
|
|
5263
|
+
.head-template-preview-row .collision-flag {
|
|
5264
|
+
margin-left: auto;
|
|
5265
|
+
font-size: 11px;
|
|
5266
|
+
color: var(--status-error);
|
|
5267
|
+
text-transform: uppercase;
|
|
5268
|
+
letter-spacing: 0.04em;
|
|
5269
|
+
}
|
|
5270
|
+
|
|
5271
|
+
/* Plan-mode radio container: stack the radios with breathing room and
|
|
5272
|
+
keep the divergence-warning alert visually attached to the chosen
|
|
5273
|
+
option without crowding it. */
|
|
5274
|
+
.plan-mode-radio {
|
|
5275
|
+
display: flex;
|
|
5276
|
+
flex-direction: column;
|
|
5277
|
+
gap: 10px;
|
|
5278
|
+
}
|
|
5279
|
+
.plan-mode-radio sl-radio-group::part(form-control) {
|
|
5280
|
+
display: flex;
|
|
5281
|
+
flex-direction: column;
|
|
5282
|
+
gap: 4px;
|
|
5283
|
+
}
|
|
5284
|
+
|
|
5285
|
+
/* Base-branch validation states */
|
|
5286
|
+
.base-branch-validating {
|
|
5287
|
+
display: flex;
|
|
5288
|
+
align-items: center;
|
|
5289
|
+
gap: 8px;
|
|
5290
|
+
font-size: 12px;
|
|
5291
|
+
color: var(--muted);
|
|
5292
|
+
padding: 4px 0;
|
|
5293
|
+
}
|
|
5294
|
+
.base-branch-error {
|
|
5295
|
+
font-size: 12px;
|
|
5296
|
+
color: var(--status-error);
|
|
5297
|
+
padding: 8px 12px;
|
|
5298
|
+
background: var(--bg-primary);
|
|
5299
|
+
border: 1px solid var(--status-error);
|
|
5300
|
+
border-radius: var(--radius);
|
|
5301
|
+
}
|
|
5302
|
+
.base-branch-missing-list {
|
|
5303
|
+
margin: 4px 0 0;
|
|
5304
|
+
padding-left: 20px;
|
|
5305
|
+
}
|
|
5306
|
+
|
|
5307
|
+
/* ── Fleet detail (page) ────────────────────────────────────────────────── */
|
|
5308
|
+
|
|
5309
|
+
/* The page top mirrors `runDetailView`'s overview: a clickable projects
|
|
5310
|
+
strip (analogue of the stage-timeline pills) sits above a single
|
|
5311
|
+
`.run-info-section` panel that holds the status badge + id chip + flat
|
|
5312
|
+
meta rows. No hero card — the per-project run-cards below carry the
|
|
5313
|
+
"card" affordance now. */
|
|
5314
|
+
.fleet-detail-overview {
|
|
5315
|
+
display: flex;
|
|
5316
|
+
flex-direction: column;
|
|
5317
|
+
gap: 8px;
|
|
5318
|
+
}
|
|
5319
|
+
|
|
5320
|
+
.fleet-projects-strip {
|
|
5321
|
+
display: flex;
|
|
5322
|
+
gap: 6px;
|
|
5323
|
+
width: 100%;
|
|
5324
|
+
}
|
|
5325
|
+
.fleet-projects-strip-segment {
|
|
5326
|
+
flex: 1 1 0;
|
|
5327
|
+
min-width: 0;
|
|
5328
|
+
display: inline-flex;
|
|
5329
|
+
align-items: center;
|
|
5330
|
+
justify-content: center;
|
|
5331
|
+
gap: 6px;
|
|
5332
|
+
padding: 8px 10px;
|
|
5333
|
+
border: 1px solid var(--border-subtle);
|
|
5334
|
+
border-left-width: 3px;
|
|
5335
|
+
border-radius: var(--radius-md);
|
|
5336
|
+
background: var(--bg-secondary);
|
|
5337
|
+
color: var(--fg);
|
|
5338
|
+
font-size: 12px;
|
|
5339
|
+
font-weight: 500;
|
|
5340
|
+
cursor: pointer;
|
|
5341
|
+
transition: background 120ms ease, transform 120ms ease;
|
|
5342
|
+
overflow: hidden;
|
|
5343
|
+
}
|
|
5344
|
+
.fleet-projects-strip-segment:hover {
|
|
5345
|
+
background: var(--bg-hover);
|
|
5346
|
+
}
|
|
5347
|
+
.fleet-projects-strip-segment:disabled {
|
|
5348
|
+
cursor: default;
|
|
5349
|
+
opacity: 0.75;
|
|
5350
|
+
}
|
|
5351
|
+
.fleet-projects-strip-segment.status-running { border-left-color: var(--status-running); }
|
|
5352
|
+
.fleet-projects-strip-segment.status-resuming { border-left-color: var(--status-running); }
|
|
5353
|
+
.fleet-projects-strip-segment.status-paused { border-left-color: var(--status-paused); }
|
|
5354
|
+
.fleet-projects-strip-segment.status-interrupted { border-left-color: var(--status-interrupted); }
|
|
5355
|
+
.fleet-projects-strip-segment.status-completed { border-left-color: var(--status-completed); }
|
|
5356
|
+
.fleet-projects-strip-segment.status-failed,
|
|
5357
|
+
.fleet-projects-strip-segment.status-setup-failed,
|
|
5358
|
+
.fleet-projects-strip-segment.status-unrecoverable { border-left-color: var(--status-failed); }
|
|
5359
|
+
.fleet-projects-strip-segment.status-error { border-left-color: var(--status-error); }
|
|
5360
|
+
.fleet-projects-strip-segment.status-halted { border-left-color: var(--status-paused); }
|
|
5361
|
+
.fleet-projects-strip-segment.status-pending,
|
|
5362
|
+
.fleet-projects-strip-segment.status-skipped,
|
|
5363
|
+
.fleet-projects-strip-segment.status-cancelled { border-left-color: var(--status-pending); }
|
|
5364
|
+
.fleet-projects-strip-icon {
|
|
5365
|
+
display: inline-flex;
|
|
5366
|
+
align-items: center;
|
|
5367
|
+
flex-shrink: 0;
|
|
5368
|
+
}
|
|
5369
|
+
.fleet-projects-strip-label {
|
|
5370
|
+
overflow: hidden;
|
|
5371
|
+
text-overflow: ellipsis;
|
|
5372
|
+
white-space: nowrap;
|
|
5373
|
+
min-width: 0;
|
|
5374
|
+
}
|
|
5375
|
+
|
|
5376
|
+
.fleet-info-section {
|
|
5377
|
+
/* Inherits .run-info-section padding/background — adds a couple of fleet
|
|
5378
|
+
-specific layout rules for the status row. */
|
|
5379
|
+
}
|
|
5380
|
+
.fleet-overview-status-row {
|
|
5381
|
+
display: flex;
|
|
5382
|
+
align-items: center;
|
|
5383
|
+
gap: 10px;
|
|
5384
|
+
flex-wrap: wrap;
|
|
5385
|
+
/* Match `.fleet-meta-line` so the "Fleet ID:" label renders in the
|
|
5386
|
+
same vocabulary as the Projects / Base / Started / Cost labels. */
|
|
5387
|
+
font-size: 13px;
|
|
5388
|
+
color: var(--fg);
|
|
5389
|
+
}
|
|
5390
|
+
.fleet-meta-line {
|
|
5391
|
+
display: flex;
|
|
5392
|
+
flex-wrap: wrap;
|
|
5393
|
+
gap: 4px 20px;
|
|
5394
|
+
font-size: 13px;
|
|
5395
|
+
color: var(--fg);
|
|
5396
|
+
}
|
|
5397
|
+
.fleet-meta-item {
|
|
5398
|
+
display: inline-flex;
|
|
5399
|
+
align-items: center;
|
|
5400
|
+
gap: 6px;
|
|
5401
|
+
}
|
|
5402
|
+
/* Projects row in the hero — label + name badges, same vocabulary as the
|
|
5403
|
+
fleet card's "Projects:" row. Tighter gap than the default meta line so
|
|
5404
|
+
the badges read as a contiguous list. */
|
|
5405
|
+
.fleet-meta-line-projects {
|
|
5406
|
+
align-items: center;
|
|
5407
|
+
gap: 6px;
|
|
5408
|
+
}
|
|
5409
|
+
.fleet-cost-strip {
|
|
5410
|
+
/* Reuses .pipeline-cost-strip — no overrides needed but keep the class
|
|
5411
|
+
so future tweaks can target fleet-specific copy. */
|
|
5412
|
+
}
|
|
5413
|
+
|
|
5414
|
+
/* Anchor wrapper around each project run-card so the projects strip can
|
|
5415
|
+
scroll to a specific card on click. */
|
|
5416
|
+
.fleet-project-anchor {
|
|
5417
|
+
scroll-margin-top: 80px;
|
|
5418
|
+
}
|
|
5419
|
+
|
|
5420
|
+
.fleet-detail-status-row {
|
|
5421
|
+
display: flex;
|
|
5422
|
+
align-items: center;
|
|
5423
|
+
gap: 12px;
|
|
5424
|
+
padding: 12px 16px;
|
|
5425
|
+
border: 1px solid var(--border-subtle);
|
|
5426
|
+
border-radius: var(--radius-lg);
|
|
5427
|
+
background: var(--bg-secondary);
|
|
5428
|
+
}
|
|
5429
|
+
|
|
5430
|
+
.fleet-detail-status-row .fleet-status-badge::part(base) {
|
|
5431
|
+
font-size: 12px;
|
|
5432
|
+
padding: 4px 10px;
|
|
5433
|
+
}
|
|
5434
|
+
|
|
5435
|
+
.fleet-id-chip {
|
|
5436
|
+
font-family: var(--sl-font-mono);
|
|
5437
|
+
font-size: 12px;
|
|
5438
|
+
color: var(--muted);
|
|
5439
|
+
padding: 2px 8px;
|
|
5440
|
+
background: var(--bg-tertiary);
|
|
5441
|
+
border-radius: 4px;
|
|
5442
|
+
border: 1px solid var(--border-subtle);
|
|
5443
|
+
}
|
|
5444
|
+
|
|
5445
|
+
.fleet-detail-body {
|
|
5446
|
+
margin-top: 4px;
|
|
5447
|
+
}
|
|
5448
|
+
|
|
5449
|
+
.fleet-manifest-grid {
|
|
5450
|
+
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
|
|
5451
|
+
}
|
|
5452
|
+
|
|
5453
|
+
.fleet-meta-mono {
|
|
5454
|
+
font-family: var(--sl-font-mono);
|
|
5455
|
+
font-size: 12.5px;
|
|
5456
|
+
color: var(--fg);
|
|
5457
|
+
background: var(--bg-tertiary);
|
|
5458
|
+
padding: 2px 6px;
|
|
5459
|
+
border-radius: 4px;
|
|
5460
|
+
display: inline-block;
|
|
5461
|
+
word-break: break-all;
|
|
5462
|
+
}
|
|
5463
|
+
|
|
5464
|
+
.fleet-meta-value {
|
|
5465
|
+
font-size: 13px;
|
|
5466
|
+
color: var(--fg);
|
|
5467
|
+
font-weight: 500;
|
|
5468
|
+
}
|
|
5469
|
+
|
|
5470
|
+
.fleet-wr-title {
|
|
5471
|
+
font-size: 16px;
|
|
5472
|
+
font-weight: 600;
|
|
5473
|
+
color: var(--fg);
|
|
5474
|
+
}
|
|
5475
|
+
|
|
5476
|
+
.fleet-wr-description {
|
|
5477
|
+
margin: 0;
|
|
5478
|
+
font-size: 13px;
|
|
5479
|
+
line-height: 1.55;
|
|
5480
|
+
color: var(--fg);
|
|
5481
|
+
white-space: pre-wrap;
|
|
5482
|
+
}
|
|
5483
|
+
|
|
5484
|
+
.fleet-guide-files {
|
|
5485
|
+
display: flex;
|
|
5486
|
+
flex-wrap: wrap;
|
|
5487
|
+
gap: 6px;
|
|
5488
|
+
margin-bottom: 4px;
|
|
5489
|
+
}
|
|
5490
|
+
|
|
5491
|
+
.fleet-guide-tag::part(base) {
|
|
5492
|
+
font-family: var(--sl-font-mono);
|
|
5493
|
+
}
|
|
5494
|
+
|
|
5495
|
+
.fleet-guide-actions {
|
|
5496
|
+
border-top: none;
|
|
5497
|
+
padding-top: 4px;
|
|
5498
|
+
}
|
|
5499
|
+
|
|
5500
|
+
.fleet-children-header {
|
|
5501
|
+
display: flex;
|
|
5502
|
+
align-items: baseline;
|
|
5503
|
+
justify-content: space-between;
|
|
5504
|
+
gap: 12px;
|
|
5505
|
+
}
|
|
5506
|
+
|
|
5507
|
+
.fleet-children-list {
|
|
5508
|
+
margin-top: 4px;
|
|
5509
|
+
}
|
|
5510
|
+
|
|
5511
|
+
.fleet-child-card {
|
|
5512
|
+
border-left-width: 3px;
|
|
5513
|
+
}
|
|
5514
|
+
|
|
5515
|
+
.fleet-child-card .run-card-meta code.fleet-meta-mono {
|
|
5516
|
+
background: transparent;
|
|
5517
|
+
padding: 0;
|
|
5518
|
+
font-size: 12px;
|
|
5519
|
+
}
|
|
5520
|
+
|
|
5521
|
+
.fleet-aggregate-cost-section .fleet-total-cost {
|
|
5522
|
+
font-size: 22px;
|
|
5523
|
+
font-weight: 600;
|
|
5524
|
+
color: var(--fg);
|
|
5525
|
+
font-variant-numeric: tabular-nums;
|
|
5526
|
+
}
|
|
5527
|
+
|
|
5528
|
+
.fleet-circuit-breaker-alert,
|
|
5529
|
+
.fleet-user-halt-alert {
|
|
5530
|
+
display: block;
|
|
5531
|
+
}
|
|
5532
|
+
|
|
5533
|
+
.fleet-circuit-breaker-alert .cb-trip-reason,
|
|
5534
|
+
.fleet-circuit-breaker-alert .cb-unstarted-count {
|
|
5535
|
+
display: block;
|
|
5536
|
+
margin-top: 4px;
|
|
5537
|
+
font-size: 12.5px;
|
|
5538
|
+
color: var(--fg);
|
|
5539
|
+
opacity: 0.85;
|
|
5540
|
+
}
|
|
5541
|
+
|
|
5542
|
+
.fleet-actions {
|
|
5543
|
+
display: flex;
|
|
5544
|
+
flex-wrap: wrap;
|
|
5545
|
+
gap: 10px;
|
|
5546
|
+
align-items: center;
|
|
5547
|
+
}
|
|
5548
|
+
|
|
5549
|
+
/* Run-detail "Fleet:" / "Workspace:" group line above the Branch row.
|
|
5550
|
+
Mirrors .run-branch exactly: same font-size, gap, and value weight.
|
|
5551
|
+
The only visual difference is the accent-colored anchor + underline-
|
|
5552
|
+
on-hover affordance signalling it's clickable. */
|
|
5553
|
+
.run-group {
|
|
5554
|
+
display: flex;
|
|
5555
|
+
align-items: center;
|
|
5556
|
+
gap: 6px;
|
|
5557
|
+
font-size: 13px;
|
|
5558
|
+
}
|
|
5559
|
+
|
|
5560
|
+
.run-group-link {
|
|
5561
|
+
/* Inherits font-family + font-size from .run-group → matches the plain
|
|
5562
|
+
<span class="meta-value"> on the Branch line, just colored and
|
|
5563
|
+
underlined-on-hover to read as a link. */
|
|
5564
|
+
color: var(--accent);
|
|
5565
|
+
font-weight: 600;
|
|
5566
|
+
text-decoration: none;
|
|
5567
|
+
word-break: break-all;
|
|
5568
|
+
}
|
|
5569
|
+
|
|
5570
|
+
.run-group-link:hover {
|
|
5571
|
+
text-decoration: underline;
|
|
5572
|
+
}
|
|
5573
|
+
|
|
5574
|
+
/* Run-card "Fleet:" / "Workspace:" meta-item — sized by parent
|
|
5575
|
+
.run-card-meta (12px). Same coloring as .run-group-link but no
|
|
5576
|
+
monospace. */
|
|
5577
|
+
.run-card-group-link {
|
|
5578
|
+
color: var(--accent);
|
|
5579
|
+
font-weight: 600;
|
|
5580
|
+
text-decoration: none;
|
|
5581
|
+
word-break: break-all;
|
|
5582
|
+
}
|
|
5583
|
+
|
|
5584
|
+
.run-card-group-link:hover {
|
|
5585
|
+
text-decoration: underline;
|
|
5586
|
+
}
|
|
5587
|
+
|
|
5588
|
+
/* Sidebar fleet-header clickable feedback */
|
|
5589
|
+
.fleet-header-clickable {
|
|
5590
|
+
transition: background-color var(--transition-fast);
|
|
5591
|
+
}
|
|
5592
|
+
|
|
5593
|
+
.fleet-header-clickable:hover {
|
|
5594
|
+
background-color: color-mix(in srgb, var(--accent) 6%, transparent);
|
|
5595
|
+
}
|
|
5596
|
+
|
|
5597
|
+
/* Fleet list view (route: /#/fleet-runs) — one `fleet-card` per fleet.
|
|
5598
|
+
No wrapping border / shared background; each card carries its own
|
|
5599
|
+
chrome plus the layered stack-of-cards shadow. Gap matches the
|
|
5600
|
+
gap between pipeline cards in run-list for visual consistency. */
|
|
5601
|
+
.fleet-list {
|
|
5602
|
+
display: flex;
|
|
5603
|
+
flex-direction: column;
|
|
5604
|
+
gap: 16px;
|
|
5605
|
+
}
|
|
5606
|
+
|
|
5607
|
+
.fleet-list-row {
|
|
5608
|
+
display: flex;
|
|
5609
|
+
align-items: center;
|
|
5610
|
+
gap: 12px;
|
|
5611
|
+
padding: 12px 16px;
|
|
5612
|
+
border-bottom: 1px solid var(--border-subtle);
|
|
5613
|
+
cursor: pointer;
|
|
5614
|
+
transition: background-color var(--transition-fast);
|
|
5615
|
+
}
|
|
5616
|
+
|
|
5617
|
+
.fleet-list-row:last-child {
|
|
5618
|
+
border-bottom: none;
|
|
5619
|
+
}
|
|
5620
|
+
|
|
5621
|
+
.fleet-list-row:hover {
|
|
5622
|
+
background-color: color-mix(in srgb, var(--accent) 6%, transparent);
|
|
5623
|
+
}
|
|
5624
|
+
|
|
5625
|
+
.fleet-list-row-title {
|
|
5626
|
+
font-size: 14px;
|
|
5627
|
+
font-weight: 600;
|
|
5628
|
+
color: var(--fg);
|
|
5629
|
+
flex: 1 1 auto;
|
|
5630
|
+
min-width: 0;
|
|
5631
|
+
overflow: hidden;
|
|
5632
|
+
text-overflow: ellipsis;
|
|
5633
|
+
white-space: nowrap;
|
|
5634
|
+
}
|
|
5635
|
+
|
|
5636
|
+
.fleet-list-row-badge {
|
|
5637
|
+
flex-shrink: 0;
|
|
5638
|
+
}
|
|
5639
|
+
|
|
5640
|
+
.fleet-list-row-meta {
|
|
5641
|
+
font-size: 12px;
|
|
5642
|
+
color: var(--muted);
|
|
5643
|
+
flex-shrink: 0;
|
|
5644
|
+
}
|
|
5645
|
+
|
|
5646
|
+
.fleet-list-row-id {
|
|
5647
|
+
font-family: var(--sl-font-mono);
|
|
5648
|
+
font-size: 11.5px;
|
|
5649
|
+
color: var(--muted);
|
|
5650
|
+
background: var(--bg-tertiary);
|
|
5651
|
+
padding: 2px 8px;
|
|
5652
|
+
border-radius: 4px;
|
|
5653
|
+
flex-shrink: 0;
|
|
5654
|
+
}
|
|
5655
|
+
|
|
5656
|
+
.fleet-list-loading,
|
|
5657
|
+
.fleet-list-empty {
|
|
5658
|
+
padding: 24px;
|
|
5659
|
+
text-align: center;
|
|
5660
|
+
color: var(--muted);
|
|
5661
|
+
display: flex;
|
|
5662
|
+
flex-direction: column;
|
|
5663
|
+
align-items: center;
|
|
5664
|
+
gap: 12px;
|
|
5665
|
+
}
|
|
5666
|
+
|
|
5667
|
+
.fleet-detail-empty {
|
|
5668
|
+
padding: 64px 24px;
|
|
5669
|
+
text-align: center;
|
|
5670
|
+
color: var(--muted);
|
|
5671
|
+
display: flex;
|
|
5672
|
+
flex-direction: column;
|
|
5673
|
+
align-items: center;
|
|
5674
|
+
gap: 12px;
|
|
5675
|
+
max-width: 540px;
|
|
5676
|
+
margin: 0 auto;
|
|
5677
|
+
}
|
|
5678
|
+
|
|
5679
|
+
.fleet-detail-empty sl-icon {
|
|
5680
|
+
font-size: 48px;
|
|
5681
|
+
color: var(--muted);
|
|
5682
|
+
opacity: 0.6;
|
|
5683
|
+
}
|
|
5684
|
+
|
|
5685
|
+
.fleet-detail-empty h2 {
|
|
5686
|
+
margin: 8px 0 0 0;
|
|
5687
|
+
font-size: 18px;
|
|
5688
|
+
color: var(--fg);
|
|
5689
|
+
}
|
|
5690
|
+
|
|
5691
|
+
.fleet-detail-empty p {
|
|
5692
|
+
margin: 0;
|
|
5693
|
+
line-height: 1.5;
|
|
5694
|
+
}
|
|
5695
|
+
|
|
5696
|
+
.fleet-detail-empty code {
|
|
5697
|
+
font-size: 12px;
|
|
5698
|
+
background: var(--bg-2, var(--border));
|
|
5699
|
+
padding: 1px 6px;
|
|
5700
|
+
border-radius: 4px;
|
|
5701
|
+
}
|
|
5702
|
+
|
|
5703
|
+
.fleet-detail-empty-hint {
|
|
5704
|
+
font-size: 13px;
|
|
5705
|
+
opacity: 0.85;
|
|
5706
|
+
}
|
|
5707
|
+
|
|
5708
|
+
.fleet-detail-empty-hint a {
|
|
5709
|
+
color: var(--accent, var(--fg));
|
|
5710
|
+
}
|