@worca/ui 0.21.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 +6144 -4668
- package/app/main.bundle.js.map +4 -4
- package/app/protocol.js +2 -1
- package/app/styles.css +909 -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 +226 -106
- 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
|
@@ -221,6 +221,19 @@ h1, h2, h3, h4, h5, h6 {
|
|
|
221
221
|
opacity: 1;
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
/* Loading spinner shown in sidebar nav items while underlying data is still
|
|
225
|
+
being fetched. Delayed fade-in avoids a noisy flash on fast loads. */
|
|
226
|
+
.sidebar-loading-spinner {
|
|
227
|
+
font-size: 14px;
|
|
228
|
+
--indicator-color: var(--text-secondary, currentColor);
|
|
229
|
+
opacity: 0;
|
|
230
|
+
animation: sidebar-spinner-fade 200ms ease-out 150ms forwards;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
@keyframes sidebar-spinner-fade {
|
|
234
|
+
to { opacity: 0.7; }
|
|
235
|
+
}
|
|
236
|
+
|
|
224
237
|
.sidebar-item.active sl-badge {
|
|
225
238
|
--sl-color-primary-600: #ffffff;
|
|
226
239
|
--sl-color-neutral-600: #ffffff;
|
|
@@ -1137,6 +1150,18 @@ sl-input [slot="prefix"] {
|
|
|
1137
1150
|
color: var(--status-cancelled);
|
|
1138
1151
|
}
|
|
1139
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
|
+
|
|
1140
1165
|
/* --- 18b. Control Buttons --- */
|
|
1141
1166
|
.action-btn--amber {
|
|
1142
1167
|
border-color: var(--status-paused);
|
|
@@ -1158,6 +1183,19 @@ sl-input [slot="prefix"] {
|
|
|
1158
1183
|
color: #ffffff;
|
|
1159
1184
|
}
|
|
1160
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
|
+
|
|
1161
1199
|
.action-btn--red {
|
|
1162
1200
|
border-color: var(--status-failed);
|
|
1163
1201
|
color: var(--status-failed);
|
|
@@ -1289,11 +1327,142 @@ sl-input [slot="prefix"] {
|
|
|
1289
1327
|
|
|
1290
1328
|
/* Status-colored left border accent on run cards */
|
|
1291
1329
|
.run-card.status-running { border-left: 3px solid var(--status-running); }
|
|
1330
|
+
.run-card.status-resuming { border-left: 3px solid var(--status-running); }
|
|
1292
1331
|
.run-card.status-paused { border-left: 3px solid var(--status-paused); }
|
|
1332
|
+
.run-card.status-interrupted { border-left: 3px solid var(--status-interrupted); }
|
|
1293
1333
|
.run-card.status-completed { border-left: 3px solid var(--status-completed); }
|
|
1294
1334
|
.run-card.status-failed { border-left: 3px solid var(--status-failed); }
|
|
1335
|
+
.run-card.status-error { border-left: 3px solid var(--status-error); }
|
|
1295
1336
|
.run-card.status-pending { border-left: 3px solid var(--status-pending); }
|
|
1337
|
+
.run-card.status-skipped { border-left: 3px solid var(--status-pending); }
|
|
1296
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
|
+
}
|
|
1297
1466
|
|
|
1298
1467
|
/* --- 21. Dashboard --- */
|
|
1299
1468
|
.dashboard {
|
|
@@ -2327,7 +2496,39 @@ sl-details.live-output-panel::part(content) {
|
|
|
2327
2496
|
.new-run-advanced {
|
|
2328
2497
|
display: flex;
|
|
2329
2498
|
flex-direction: column;
|
|
2330
|
-
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);
|
|
2331
2532
|
}
|
|
2332
2533
|
|
|
2333
2534
|
.new-run-grid {
|
|
@@ -2471,39 +2672,106 @@ sl-option.template-grouped:focus::part(suffix) {
|
|
|
2471
2672
|
background: var(--bg-tertiary);
|
|
2472
2673
|
}
|
|
2473
2674
|
|
|
2474
|
-
/* 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). */
|
|
2475
2679
|
.sidebar-new-run {
|
|
2476
2680
|
padding: 8px 8px 4px;
|
|
2477
2681
|
}
|
|
2478
2682
|
|
|
2479
|
-
.sidebar-new-run-
|
|
2683
|
+
.sidebar-new-run-split {
|
|
2480
2684
|
display: flex;
|
|
2481
|
-
align-items:
|
|
2482
|
-
justify-content: center;
|
|
2483
|
-
gap: 8px;
|
|
2685
|
+
align-items: stretch;
|
|
2484
2686
|
width: 100%;
|
|
2485
|
-
|
|
2687
|
+
min-height: 36px;
|
|
2486
2688
|
border: 2px dashed var(--accent);
|
|
2487
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);
|
|
2488
2705
|
background: transparent;
|
|
2489
2706
|
color: var(--accent);
|
|
2490
2707
|
font-size: 13px;
|
|
2491
2708
|
font-weight: 600;
|
|
2492
2709
|
font-family: inherit;
|
|
2493
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;
|
|
2494
2749
|
transition: background var(--transition-fast), color var(--transition-fast);
|
|
2495
2750
|
}
|
|
2496
2751
|
|
|
2497
|
-
.sidebar-new-run-btn:hover {
|
|
2752
|
+
.sidebar-new-run-btn-chevron:hover:not(:disabled) {
|
|
2498
2753
|
background: var(--accent);
|
|
2499
2754
|
color: #ffffff;
|
|
2500
2755
|
}
|
|
2501
2756
|
|
|
2502
|
-
.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 {
|
|
2503
2771
|
display: none;
|
|
2504
2772
|
}
|
|
2505
2773
|
|
|
2506
|
-
.sidebar.collapsed .sidebar-new-run-btn {
|
|
2774
|
+
.sidebar.collapsed .sidebar-new-run-btn-primary {
|
|
2507
2775
|
padding: 8px;
|
|
2508
2776
|
}
|
|
2509
2777
|
|
|
@@ -2893,6 +3161,16 @@ sl-details.run-beads-panel::part(content) {
|
|
|
2893
3161
|
border: 1px solid var(--border-subtle);
|
|
2894
3162
|
}
|
|
2895
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
|
+
|
|
2896
3174
|
.run-bead-row sl-badge::part(base) {
|
|
2897
3175
|
font-size: 0.68rem;
|
|
2898
3176
|
padding: 0 5px;
|
|
@@ -3947,6 +4225,7 @@ sl-details.learnings-panel::part(content) {
|
|
|
3947
4225
|
.filter-chip-failed.active { background: var(--status-failed); border-color: var(--status-failed); }
|
|
3948
4226
|
.filter-chip-paused.active { background: var(--status-paused); border-color: var(--status-paused); }
|
|
3949
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); }
|
|
3950
4229
|
.filter-chip .chip-count {
|
|
3951
4230
|
font-size: 0.68rem;
|
|
3952
4231
|
opacity: 0.7;
|
|
@@ -3957,6 +4236,7 @@ sl-details.learnings-panel::part(content) {
|
|
|
3957
4236
|
display: flex;
|
|
3958
4237
|
align-items: center;
|
|
3959
4238
|
justify-content: flex-end;
|
|
4239
|
+
flex-wrap: wrap;
|
|
3960
4240
|
gap: 8px;
|
|
3961
4241
|
padding-left: 26px;
|
|
3962
4242
|
}
|
|
@@ -4023,11 +4303,8 @@ sl-details.learnings-panel::part(content) {
|
|
|
4023
4303
|
.project-status-paused { background: var(--status-paused, #eab308); }
|
|
4024
4304
|
|
|
4025
4305
|
/* --- Dashboard Project Cards --- */
|
|
4026
|
-
.project-cards
|
|
4027
|
-
|
|
4028
|
-
.project-card:hover { border-color: var(--accent); box-shadow: var(--shadow-sm); }
|
|
4029
|
-
.project-card-name { font-weight: 600; margin-bottom: 4px; }
|
|
4030
|
-
.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). */
|
|
4031
4308
|
|
|
4032
4309
|
/* --- Settings Projects List --- */
|
|
4033
4310
|
.projects-list-item { display: flex; justify-content: space-between; align-items: center; padding: 8px 0; border-bottom: 1px solid var(--border); }
|
|
@@ -4626,6 +4903,23 @@ sl-tooltip.bead-tooltip::part(body) {
|
|
|
4626
4903
|
flex: 1;
|
|
4627
4904
|
min-width: 240px;
|
|
4628
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
|
+
}
|
|
4629
4923
|
.worktree-card-path {
|
|
4630
4924
|
align-items: baseline;
|
|
4631
4925
|
}
|
|
@@ -4635,6 +4929,33 @@ sl-tooltip.bead-tooltip::part(body) {
|
|
|
4635
4929
|
color: var(--muted);
|
|
4636
4930
|
word-break: break-all;
|
|
4637
4931
|
}
|
|
4932
|
+
/* Worktree card mid-cleanup state — surfaces server-side cleanup_state
|
|
4933
|
+
so a reload during a long bulk cleanup shows the same progress. */
|
|
4934
|
+
.worktree-card-cleaning {
|
|
4935
|
+
opacity: 0.72;
|
|
4936
|
+
pointer-events: none;
|
|
4937
|
+
}
|
|
4938
|
+
.worktree-card-cleaning .btn-cleanup {
|
|
4939
|
+
pointer-events: none;
|
|
4940
|
+
}
|
|
4941
|
+
.status-badge-cleaning {
|
|
4942
|
+
display: inline-flex;
|
|
4943
|
+
align-items: center;
|
|
4944
|
+
gap: 4px;
|
|
4945
|
+
}
|
|
4946
|
+
.badge-spinner,
|
|
4947
|
+
.btn-cleanup-spinner {
|
|
4948
|
+
font-size: 12px;
|
|
4949
|
+
}
|
|
4950
|
+
.worktree-card-cleanup-error {
|
|
4951
|
+
margin-top: 6px;
|
|
4952
|
+
padding: 6px 10px;
|
|
4953
|
+
border-radius: 6px;
|
|
4954
|
+
background: var(--sl-color-danger-50, #fef2f2);
|
|
4955
|
+
color: var(--sl-color-danger-700, #b91c1c);
|
|
4956
|
+
font-size: 12px;
|
|
4957
|
+
}
|
|
4958
|
+
|
|
4638
4959
|
.worktrees-bulk-groups {
|
|
4639
4960
|
margin: 8px 0 0;
|
|
4640
4961
|
padding-left: 18px;
|
|
@@ -4814,3 +5135,576 @@ sl-tooltip.bead-tooltip::part(body) {
|
|
|
4814
5135
|
line-height: 1.2;
|
|
4815
5136
|
flex: 0 0 auto;
|
|
4816
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
|
+
}
|