plum-e2e 2.4.13 → 2.5.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.
- package/CLAUDE.md +1 -1
- package/backend/_scaffold/utils/browser.ts +47 -2
- package/backend/_scaffold/utils/hooks.ts +25 -2
- package/backend/config/scripts/run-tests.js +35 -13
- package/backend/logs/runner-cmr8o2x3n0000mg01410tpuck.log +20 -0
- package/backend/logs/runner-cmr90hvcx0000n2016edtmrtv.log +43 -0
- package/backend/logs/runner-cmr90i7h20001n201g2wg6v3n.log +43 -0
- package/backend/logs/runner-cmr90iilm0002n201mmisva95.log +43 -0
- package/backend/logs/runner-cmr90j70r0003n201xz8525dz.log +20 -0
- package/backend/logs/runner-cmr90yup70000qp017ianc2gp.log +43 -0
- package/backend/logs/runner-cmr90zbtm0001qp01u9tfdkh1.log +20 -0
- package/backend/logs/runner-cmr91a3mw0000tb01414rd1df.log +20 -0
- package/backend/logs/runner-cmr91dhla0001tb01jp7thjnl.log +20 -0
- package/backend/prisma/migrations/20260706000000_add_report_logs/migration.sql +2 -0
- package/backend/prisma/migrations/20260707032554_add_perf_indexes/migration.sql +44 -0
- package/backend/prisma/schema.prisma +20 -0
- package/backend/routes/node.routes.js +42 -4
- package/backend/routes/reports.routes.js +4 -2
- package/backend/services/reportService.js +58 -20
- package/backend/services/runnerService.js +11 -1
- package/backend/websockets/socketHandler.js +162 -16
- package/bin/plum.js +96 -68
- package/frontend/package.json +1 -1
- package/frontend/src/lib/api/reports.js +16 -5
- package/frontend/src/lib/components/layout/RunnerPanel.svelte +53 -55
- package/frontend/src/lib/components/ui/AutomatedBadge.svelte +56 -0
- package/frontend/src/lib/components/ui/BackLink.svelte +77 -0
- package/frontend/src/lib/components/ui/Badge.svelte +1 -1
- package/frontend/src/lib/components/ui/Button.svelte +1 -1
- package/frontend/src/lib/components/ui/CaseIdChip.svelte +59 -0
- package/frontend/src/lib/components/ui/ConfirmModal.svelte +1 -1
- package/frontend/src/lib/components/ui/Pagination.svelte +1 -1
- package/frontend/src/lib/components/ui/PriorityBadge.svelte +83 -0
- package/frontend/src/lib/components/ui/ResultChip.svelte +92 -0
- package/frontend/src/lib/components/ui/StatusDot.svelte +64 -0
- package/frontend/src/lib/components/ui/StepKeyword.svelte +79 -0
- package/frontend/src/lib/components/ui/StepStatusIcon.svelte +66 -0
- package/frontend/src/lib/components/ui/TagChip.svelte +51 -0
- package/frontend/src/lib/constants.js +14 -0
- package/frontend/src/lib/stores/runner.js +5 -3
- package/frontend/src/lib/styles/tokens.css +26 -0
- package/frontend/src/lib/utils/format.js +74 -0
- package/frontend/src/routes/+page.svelte +3 -3
- package/frontend/src/routes/login/+page.svelte +55 -40
- package/frontend/src/routes/reports/+page.svelte +35 -27
- package/frontend/src/routes/reports/[id]/+page.svelte +703 -215
- package/frontend/src/routes/reports/live/+page.svelte +281 -283
- package/frontend/src/routes/scheduled-tests/+page.svelte +3 -3
- package/frontend/src/routes/settings/+page.svelte +6 -6
- package/frontend/src/routes/setup/+page.svelte +2 -1
- package/frontend/src/routes/test-repository/+page.svelte +5 -5
- package/frontend/src/routes/test-repository/runs/[id]/+page.svelte +33 -152
- package/frontend/src/routes/test-repository/suites/[id]/+page.svelte +4 -4
- package/frontend/vite.config.js +7 -1
- package/package.json +1 -1
|
@@ -630,7 +630,7 @@
|
|
|
630
630
|
width: 14px;
|
|
631
631
|
height: 14px;
|
|
632
632
|
border-radius: 50%;
|
|
633
|
-
background:
|
|
633
|
+
background: var(--white);
|
|
634
634
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
|
635
635
|
transition: left var(--duration-fast);
|
|
636
636
|
}
|
|
@@ -666,7 +666,7 @@
|
|
|
666
666
|
|
|
667
667
|
.run-icon-btn:hover {
|
|
668
668
|
background: var(--accent);
|
|
669
|
-
color:
|
|
669
|
+
color: var(--white);
|
|
670
670
|
border-color: var(--accent);
|
|
671
671
|
}
|
|
672
672
|
|
|
@@ -803,7 +803,7 @@
|
|
|
803
803
|
}
|
|
804
804
|
.seg-btn.active {
|
|
805
805
|
background: var(--accent);
|
|
806
|
-
color:
|
|
806
|
+
color: var(--white);
|
|
807
807
|
}
|
|
808
808
|
.seg-btn.active .seg-label {
|
|
809
809
|
opacity: 0.85;
|
|
@@ -1828,7 +1828,7 @@
|
|
|
1828
1828
|
flex-shrink: 0;
|
|
1829
1829
|
width: 40px;
|
|
1830
1830
|
height: 22px;
|
|
1831
|
-
border-radius:
|
|
1831
|
+
border-radius: var(--radius-pill);
|
|
1832
1832
|
border: none;
|
|
1833
1833
|
background: var(--border);
|
|
1834
1834
|
cursor: pointer;
|
|
@@ -1908,7 +1908,7 @@
|
|
|
1908
1908
|
color: var(--text-muted);
|
|
1909
1909
|
background: var(--bg-subtle);
|
|
1910
1910
|
border: 1px solid var(--border);
|
|
1911
|
-
border-radius:
|
|
1911
|
+
border-radius: var(--radius-pill);
|
|
1912
1912
|
padding: 0.1rem 0.45rem;
|
|
1913
1913
|
flex-shrink: 0;
|
|
1914
1914
|
}
|
|
@@ -1935,7 +1935,7 @@
|
|
|
1935
1935
|
font-size: 0.7rem;
|
|
1936
1936
|
font-weight: 500;
|
|
1937
1937
|
padding: 0.15rem 0.5rem;
|
|
1938
|
-
border-radius:
|
|
1938
|
+
border-radius: var(--radius-pill);
|
|
1939
1939
|
flex-shrink: 0;
|
|
1940
1940
|
}
|
|
1941
1941
|
|
|
@@ -2084,7 +2084,7 @@
|
|
|
2084
2084
|
flex-shrink: 0;
|
|
2085
2085
|
width: 40px;
|
|
2086
2086
|
height: 22px;
|
|
2087
|
-
border-radius:
|
|
2087
|
+
border-radius: var(--radius-pill);
|
|
2088
2088
|
border: none;
|
|
2089
2089
|
background: var(--border);
|
|
2090
2090
|
cursor: pointer;
|
|
@@ -2274,7 +2274,7 @@
|
|
|
2274
2274
|
.role-chip {
|
|
2275
2275
|
font-size: 0.7rem;
|
|
2276
2276
|
font-weight: 500;
|
|
2277
|
-
border-radius:
|
|
2277
|
+
border-radius: var(--radius-pill);
|
|
2278
2278
|
padding: 0.15rem 0.55rem;
|
|
2279
2279
|
flex-shrink: 0;
|
|
2280
2280
|
}
|
|
@@ -2295,7 +2295,7 @@
|
|
|
2295
2295
|
color: var(--text-muted);
|
|
2296
2296
|
background: var(--bg-subtle);
|
|
2297
2297
|
border: 1px solid var(--border);
|
|
2298
|
-
border-radius:
|
|
2298
|
+
border-radius: var(--radius-pill);
|
|
2299
2299
|
padding: 0.15rem 0.55rem;
|
|
2300
2300
|
flex-shrink: 0;
|
|
2301
2301
|
}
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
<script>
|
|
19
19
|
import { onMount } from 'svelte';
|
|
20
|
+
import { goto } from '$app/navigation';
|
|
20
21
|
import { setup, checkNeedsSetup } from '$lib/api/auth';
|
|
21
22
|
import { auth } from '$lib/stores/auth';
|
|
22
23
|
import { login as apiLogin } from '$lib/api/auth';
|
|
@@ -228,7 +229,7 @@
|
|
|
228
229
|
.submit-btn {
|
|
229
230
|
height: 40px;
|
|
230
231
|
background: var(--accent);
|
|
231
|
-
color:
|
|
232
|
+
color: var(--white);
|
|
232
233
|
border: none;
|
|
233
234
|
border-radius: var(--radius-sm);
|
|
234
235
|
font-family: var(--font-body);
|
|
@@ -890,7 +890,7 @@
|
|
|
890
890
|
font-size: 0.7rem;
|
|
891
891
|
background: var(--bg-subtle);
|
|
892
892
|
border: 1px solid var(--border);
|
|
893
|
-
border-radius:
|
|
893
|
+
border-radius: var(--radius-pill);
|
|
894
894
|
padding: 0.05rem 0.4rem;
|
|
895
895
|
color: var(--text-muted);
|
|
896
896
|
}
|
|
@@ -991,7 +991,7 @@
|
|
|
991
991
|
color: var(--text-muted);
|
|
992
992
|
background: var(--bg-elevated);
|
|
993
993
|
border: 1px solid var(--border);
|
|
994
|
-
border-radius:
|
|
994
|
+
border-radius: var(--radius-pill);
|
|
995
995
|
cursor: pointer;
|
|
996
996
|
transition:
|
|
997
997
|
color var(--duration-fast),
|
|
@@ -1181,7 +1181,7 @@
|
|
|
1181
1181
|
text-transform: uppercase;
|
|
1182
1182
|
color: var(--pass);
|
|
1183
1183
|
background: var(--pass-soft);
|
|
1184
|
-
border-radius:
|
|
1184
|
+
border-radius: var(--radius-pill);
|
|
1185
1185
|
padding: 0.1rem 0.4rem;
|
|
1186
1186
|
flex-shrink: 0;
|
|
1187
1187
|
}
|
|
@@ -1190,7 +1190,7 @@
|
|
|
1190
1190
|
.priority-badge {
|
|
1191
1191
|
font-size: 0.68rem;
|
|
1192
1192
|
font-weight: 500;
|
|
1193
|
-
border-radius:
|
|
1193
|
+
border-radius: var(--radius-pill);
|
|
1194
1194
|
padding: 0.15rem 0.5rem;
|
|
1195
1195
|
flex-shrink: 0;
|
|
1196
1196
|
}
|
|
@@ -1320,7 +1320,7 @@
|
|
|
1320
1320
|
color: var(--text-muted);
|
|
1321
1321
|
background: var(--bg-subtle);
|
|
1322
1322
|
border: 1px solid var(--border);
|
|
1323
|
-
border-radius:
|
|
1323
|
+
border-radius: var(--radius-pill);
|
|
1324
1324
|
padding: 0.1rem 0.4rem;
|
|
1325
1325
|
}
|
|
1326
1326
|
|
|
@@ -31,7 +31,12 @@
|
|
|
31
31
|
import { auth } from '$lib/stores/auth';
|
|
32
32
|
import Button from '$lib/components/ui/Button.svelte';
|
|
33
33
|
import Toast from '$lib/components/ui/Toast.svelte';
|
|
34
|
-
import
|
|
34
|
+
import EmptyState from '$lib/components/ui/EmptyState.svelte';
|
|
35
|
+
import AutomatedBadge from '$lib/components/ui/AutomatedBadge.svelte';
|
|
36
|
+
import PriorityBadge from '$lib/components/ui/PriorityBadge.svelte';
|
|
37
|
+
import CaseIdChip from '$lib/components/ui/CaseIdChip.svelte';
|
|
38
|
+
import ResultChip from '$lib/components/ui/ResultChip.svelte';
|
|
39
|
+
import { TOAST_TIMEOUT_MS, RUN_REFRESH_MS } from '$lib/constants';
|
|
35
40
|
|
|
36
41
|
const runId = $page.params.id;
|
|
37
42
|
|
|
@@ -133,7 +138,7 @@
|
|
|
133
138
|
const fresh = await fetchRun(runId);
|
|
134
139
|
run = fresh;
|
|
135
140
|
} catch {}
|
|
136
|
-
},
|
|
141
|
+
}, RUN_REFRESH_MS);
|
|
137
142
|
});
|
|
138
143
|
|
|
139
144
|
onDestroy(() => {
|
|
@@ -169,13 +174,18 @@
|
|
|
169
174
|
(tc) =>
|
|
170
175
|
!runCaseIds.has(tc.id) &&
|
|
171
176
|
(!search ||
|
|
177
|
+
suite.displayId.toLowerCase().includes(search.toLowerCase()) ||
|
|
178
|
+
suite.name.toLowerCase().includes(search.toLowerCase()) ||
|
|
172
179
|
tc.title.toLowerCase().includes(search.toLowerCase()) ||
|
|
173
180
|
tc.displayId.toLowerCase().includes(search.toLowerCase()))
|
|
174
181
|
)
|
|
175
182
|
}))
|
|
176
183
|
.filter(
|
|
177
184
|
(suite) =>
|
|
178
|
-
!search ||
|
|
185
|
+
!search ||
|
|
186
|
+
suite.cases.length > 0 ||
|
|
187
|
+
suite.displayId.toLowerCase().includes(search.toLowerCase()) ||
|
|
188
|
+
suite.name.toLowerCase().includes(search.toLowerCase())
|
|
179
189
|
);
|
|
180
190
|
|
|
181
191
|
function addCase(tc) {
|
|
@@ -292,18 +302,6 @@
|
|
|
292
302
|
dragOverEntryId = null;
|
|
293
303
|
}
|
|
294
304
|
|
|
295
|
-
function priorityClass(p) {
|
|
296
|
-
return p?.toLowerCase() ?? 'medium';
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
function statusClass(s) {
|
|
300
|
-
if (s === 'pass') return 'pass';
|
|
301
|
-
if (s === 'fail') return 'fail';
|
|
302
|
-
if (s === 'blocked') return 'warn';
|
|
303
|
-
if (s === 'skip') return 'muted';
|
|
304
|
-
return 'pending';
|
|
305
|
-
}
|
|
306
|
-
|
|
307
305
|
$: completedCount = run?.entries.filter((e) => e.status !== 'pending').length ?? 0;
|
|
308
306
|
$: totalCount = run?.entries.length ?? 0;
|
|
309
307
|
$: passCount = run?.entries.filter((e) => e.status === 'pass').length ?? 0;
|
|
@@ -378,7 +376,7 @@
|
|
|
378
376
|
</div>
|
|
379
377
|
|
|
380
378
|
{#if run.entries.length === 0}
|
|
381
|
-
<
|
|
379
|
+
<EmptyState message="No cases in this run." size="sm" />
|
|
382
380
|
{:else}
|
|
383
381
|
<div class="entry-sort-bar">
|
|
384
382
|
{#each [['order', 'Order'], ['name', 'Name'], ['priority', 'Priority'], ['status', 'Status'], ['suite', 'Suite']] as [val, label]}
|
|
@@ -428,16 +426,14 @@
|
|
|
428
426
|
{/if}
|
|
429
427
|
<div class="entry-info">
|
|
430
428
|
<div class="entry-badges">
|
|
431
|
-
<
|
|
432
|
-
<
|
|
433
|
-
>{entry.case.priority}</span
|
|
434
|
-
>
|
|
429
|
+
<CaseIdChip id={entry.case.displayId} />
|
|
430
|
+
<PriorityBadge priority={entry.case.priority} />
|
|
435
431
|
</div>
|
|
436
432
|
<p class="entry-title">{entry.case.title}</p>
|
|
437
433
|
<span class="entry-suite">{entry.case.suite?.name ?? ''}</span>
|
|
438
434
|
</div>
|
|
439
435
|
{#if entry.case.isAutomated}
|
|
440
|
-
<
|
|
436
|
+
<AutomatedBadge />
|
|
441
437
|
{:else}
|
|
442
438
|
<select
|
|
443
439
|
class="assignee-select"
|
|
@@ -511,13 +507,11 @@
|
|
|
511
507
|
<div class="browser-cases" transition:fly={{ y: -4, duration: 120 }}>
|
|
512
508
|
{#each suite.cases as tc (tc.id)}
|
|
513
509
|
<button class="browser-case" on:click={() => addCase(tc)}>
|
|
514
|
-
<
|
|
510
|
+
<CaseIdChip id={tc.displayId} small />
|
|
515
511
|
<span class="browser-case-title">{tc.title}</span>
|
|
516
|
-
<
|
|
517
|
-
>{tc.priority}</span
|
|
518
|
-
>
|
|
512
|
+
<PriorityBadge priority={tc.priority} small />
|
|
519
513
|
{#if tc.isAutomated}
|
|
520
|
-
<
|
|
514
|
+
<AutomatedBadge />
|
|
521
515
|
{/if}
|
|
522
516
|
</button>
|
|
523
517
|
{/each}
|
|
@@ -586,8 +580,8 @@
|
|
|
586
580
|
>
|
|
587
581
|
</button>
|
|
588
582
|
{/if}
|
|
589
|
-
<
|
|
590
|
-
{#if entry.case.isAutomated}<
|
|
583
|
+
<CaseIdChip id={entry.case.displayId} />
|
|
584
|
+
{#if entry.case.isAutomated}<AutomatedBadge />{/if}
|
|
591
585
|
<div>
|
|
592
586
|
<p class="exec-title">{entry.case.title}</p>
|
|
593
587
|
<span class="exec-suite">{entry.case.suite?.name ?? ''}</span>
|
|
@@ -596,7 +590,7 @@
|
|
|
596
590
|
<div class="exec-actions">
|
|
597
591
|
{#if entry.case.isAutomated}
|
|
598
592
|
<div class="exec-assignee-row">
|
|
599
|
-
<
|
|
593
|
+
<AutomatedBadge />
|
|
600
594
|
</div>
|
|
601
595
|
<div class="exec-assignee-divider"></div>
|
|
602
596
|
{:else if entry.assignedTo || (!isLocked && entry.assignedTo?.id !== currentUserId)}
|
|
@@ -617,7 +611,7 @@
|
|
|
617
611
|
<div class="exec-assignee-divider"></div>
|
|
618
612
|
{/if}
|
|
619
613
|
{#if isLocked || run.status !== 'in-progress'}
|
|
620
|
-
<
|
|
614
|
+
<ResultChip status={entry.status} />
|
|
621
615
|
{:else if entry.status === 'pending' || entry.status === 'in-progress'}
|
|
622
616
|
<div class="exec-btns">
|
|
623
617
|
<button
|
|
@@ -640,7 +634,7 @@
|
|
|
640
634
|
</div>
|
|
641
635
|
{:else}
|
|
642
636
|
<div class="exec-btns">
|
|
643
|
-
<
|
|
637
|
+
<ResultChip status={entry.status} />
|
|
644
638
|
<button
|
|
645
639
|
class="exec-reset"
|
|
646
640
|
on:click={() => handleMarkEntry(entry, 'pending')}
|
|
@@ -731,7 +725,7 @@
|
|
|
731
725
|
font-size: 0.7rem;
|
|
732
726
|
font-weight: 500;
|
|
733
727
|
text-transform: capitalize;
|
|
734
|
-
border-radius:
|
|
728
|
+
border-radius: var(--radius-pill);
|
|
735
729
|
padding: 0.2rem 0.6rem;
|
|
736
730
|
border: 1px solid var(--border);
|
|
737
731
|
color: var(--text-muted);
|
|
@@ -764,7 +758,7 @@
|
|
|
764
758
|
color: var(--text-muted);
|
|
765
759
|
background: var(--bg-subtle);
|
|
766
760
|
border: 1px solid var(--border);
|
|
767
|
-
border-radius:
|
|
761
|
+
border-radius: var(--radius-pill);
|
|
768
762
|
padding: 0.1rem 0.45rem;
|
|
769
763
|
margin-left: auto;
|
|
770
764
|
}
|
|
@@ -830,7 +824,7 @@
|
|
|
830
824
|
font-size: 0.7rem;
|
|
831
825
|
background: var(--bg-subtle);
|
|
832
826
|
border: 1px solid var(--border);
|
|
833
|
-
border-radius:
|
|
827
|
+
border-radius: var(--radius-pill);
|
|
834
828
|
padding: 0.05rem 0.4rem;
|
|
835
829
|
color: var(--text-muted);
|
|
836
830
|
}
|
|
@@ -869,7 +863,7 @@
|
|
|
869
863
|
font-size: 0.7rem;
|
|
870
864
|
background: var(--bg-elevated);
|
|
871
865
|
border: 1px solid var(--border);
|
|
872
|
-
border-radius:
|
|
866
|
+
border-radius: var(--radius-pill);
|
|
873
867
|
padding: 0.05rem 0.4rem;
|
|
874
868
|
color: var(--text-muted);
|
|
875
869
|
}
|
|
@@ -891,14 +885,6 @@
|
|
|
891
885
|
border-color: var(--accent);
|
|
892
886
|
}
|
|
893
887
|
|
|
894
|
-
.drop-hint {
|
|
895
|
-
padding: 2rem 1.25rem;
|
|
896
|
-
font-size: 0.8125rem;
|
|
897
|
-
color: var(--text-muted);
|
|
898
|
-
text-align: center;
|
|
899
|
-
line-height: 1.6;
|
|
900
|
-
}
|
|
901
|
-
|
|
902
888
|
.entry-sort-bar {
|
|
903
889
|
display: flex;
|
|
904
890
|
align-items: center;
|
|
@@ -911,7 +897,7 @@
|
|
|
911
897
|
.entry-sort-chip {
|
|
912
898
|
font-size: 0.75rem;
|
|
913
899
|
padding: 0.2rem 0.55rem;
|
|
914
|
-
border-radius:
|
|
900
|
+
border-radius: var(--radius-pill);
|
|
915
901
|
border: 1px solid var(--border);
|
|
916
902
|
background: var(--bg);
|
|
917
903
|
color: var(--text-muted);
|
|
@@ -995,33 +981,6 @@
|
|
|
995
981
|
color: var(--text-muted);
|
|
996
982
|
}
|
|
997
983
|
|
|
998
|
-
.assignee-auto-label {
|
|
999
|
-
font-size: 0.72rem;
|
|
1000
|
-
font-weight: 500;
|
|
1001
|
-
color: var(--accent);
|
|
1002
|
-
background: var(--accent-soft);
|
|
1003
|
-
border-radius: 100px;
|
|
1004
|
-
padding: 0.15rem 0.5rem;
|
|
1005
|
-
flex-shrink: 0;
|
|
1006
|
-
}
|
|
1007
|
-
|
|
1008
|
-
.auto-pill {
|
|
1009
|
-
font-size: 0.62rem;
|
|
1010
|
-
font-weight: 600;
|
|
1011
|
-
text-transform: uppercase;
|
|
1012
|
-
letter-spacing: 0.05em;
|
|
1013
|
-
color: var(--accent);
|
|
1014
|
-
background: var(--accent-soft);
|
|
1015
|
-
border-radius: 100px;
|
|
1016
|
-
padding: 0.1rem 0.4rem;
|
|
1017
|
-
flex-shrink: 0;
|
|
1018
|
-
}
|
|
1019
|
-
|
|
1020
|
-
.auto-label {
|
|
1021
|
-
color: var(--accent);
|
|
1022
|
-
font-weight: 500;
|
|
1023
|
-
}
|
|
1024
|
-
|
|
1025
984
|
.exec-locked-banner {
|
|
1026
985
|
font-size: 0.8125rem;
|
|
1027
986
|
color: var(--text-muted);
|
|
@@ -1165,9 +1124,6 @@
|
|
|
1165
1124
|
}
|
|
1166
1125
|
|
|
1167
1126
|
/* ── Execute ── */
|
|
1168
|
-
.execute-workspace {
|
|
1169
|
-
}
|
|
1170
|
-
|
|
1171
1127
|
.progress-bar-wrap {
|
|
1172
1128
|
margin-bottom: 1.25rem;
|
|
1173
1129
|
}
|
|
@@ -1197,14 +1153,14 @@
|
|
|
1197
1153
|
.progress-bar {
|
|
1198
1154
|
height: 6px;
|
|
1199
1155
|
background: var(--bg-subtle);
|
|
1200
|
-
border-radius:
|
|
1156
|
+
border-radius: var(--radius-pill);
|
|
1201
1157
|
overflow: hidden;
|
|
1202
1158
|
display: flex;
|
|
1203
1159
|
}
|
|
1204
1160
|
|
|
1205
1161
|
.progress-fill {
|
|
1206
1162
|
height: 100%;
|
|
1207
|
-
border-radius:
|
|
1163
|
+
border-radius: var(--radius-pill);
|
|
1208
1164
|
transition: width 0.3s var(--ease-out);
|
|
1209
1165
|
}
|
|
1210
1166
|
|
|
@@ -1365,7 +1321,7 @@
|
|
|
1365
1321
|
color: var(--accent);
|
|
1366
1322
|
background: none;
|
|
1367
1323
|
border: 1px solid var(--accent);
|
|
1368
|
-
border-radius:
|
|
1324
|
+
border-radius: var(--radius-pill);
|
|
1369
1325
|
padding: 0.1rem 0.5rem;
|
|
1370
1326
|
cursor: pointer;
|
|
1371
1327
|
transition: background var(--duration-fast);
|
|
@@ -1380,36 +1336,6 @@
|
|
|
1380
1336
|
cursor: not-allowed;
|
|
1381
1337
|
}
|
|
1382
1338
|
|
|
1383
|
-
.result-chip {
|
|
1384
|
-
font-size: 0.7rem;
|
|
1385
|
-
font-weight: 600;
|
|
1386
|
-
text-transform: uppercase;
|
|
1387
|
-
letter-spacing: 0.05em;
|
|
1388
|
-
padding: 0.2rem 0.6rem;
|
|
1389
|
-
border-radius: 100px;
|
|
1390
|
-
}
|
|
1391
|
-
|
|
1392
|
-
.result-chip.pass {
|
|
1393
|
-
background: var(--pass-soft);
|
|
1394
|
-
color: var(--pass);
|
|
1395
|
-
}
|
|
1396
|
-
.result-chip.fail {
|
|
1397
|
-
background: var(--fail-soft);
|
|
1398
|
-
color: var(--fail);
|
|
1399
|
-
}
|
|
1400
|
-
.result-chip.warn {
|
|
1401
|
-
background: var(--warn-soft);
|
|
1402
|
-
color: var(--warn);
|
|
1403
|
-
}
|
|
1404
|
-
.result-chip.muted {
|
|
1405
|
-
background: var(--bg-subtle);
|
|
1406
|
-
color: var(--text-muted);
|
|
1407
|
-
}
|
|
1408
|
-
.result-chip.pending {
|
|
1409
|
-
background: var(--bg-subtle);
|
|
1410
|
-
color: var(--text-muted);
|
|
1411
|
-
}
|
|
1412
|
-
|
|
1413
1339
|
.exec-chevron {
|
|
1414
1340
|
background: none;
|
|
1415
1341
|
border: none;
|
|
@@ -1469,51 +1395,6 @@
|
|
|
1469
1395
|
margin-top: 0.2rem;
|
|
1470
1396
|
}
|
|
1471
1397
|
|
|
1472
|
-
/* ── Shared chips ── */
|
|
1473
|
-
.id-chip {
|
|
1474
|
-
font-family: 'JetBrains Mono', monospace;
|
|
1475
|
-
font-weight: 600;
|
|
1476
|
-
color: var(--accent);
|
|
1477
|
-
background: var(--accent-soft);
|
|
1478
|
-
border-radius: 4px;
|
|
1479
|
-
letter-spacing: 0.02em;
|
|
1480
|
-
font-size: 0.7rem;
|
|
1481
|
-
padding: 0.1rem 0.4rem;
|
|
1482
|
-
flex-shrink: 0;
|
|
1483
|
-
}
|
|
1484
|
-
|
|
1485
|
-
.id-chip.small {
|
|
1486
|
-
font-size: 0.63rem;
|
|
1487
|
-
}
|
|
1488
|
-
|
|
1489
|
-
.priority-badge {
|
|
1490
|
-
font-size: 0.65rem;
|
|
1491
|
-
font-weight: 500;
|
|
1492
|
-
border-radius: 100px;
|
|
1493
|
-
padding: 0.12rem 0.45rem;
|
|
1494
|
-
flex-shrink: 0;
|
|
1495
|
-
}
|
|
1496
|
-
|
|
1497
|
-
.priority-badge.small {
|
|
1498
|
-
font-size: 0.6rem;
|
|
1499
|
-
}
|
|
1500
|
-
.priority-badge.critical {
|
|
1501
|
-
background: var(--fail-soft);
|
|
1502
|
-
color: var(--fail);
|
|
1503
|
-
}
|
|
1504
|
-
.priority-badge.high {
|
|
1505
|
-
background: var(--warn-soft);
|
|
1506
|
-
color: var(--warn);
|
|
1507
|
-
}
|
|
1508
|
-
.priority-badge.medium {
|
|
1509
|
-
background: var(--node-soft);
|
|
1510
|
-
color: var(--node);
|
|
1511
|
-
}
|
|
1512
|
-
.priority-badge.low {
|
|
1513
|
-
background: var(--bg-subtle);
|
|
1514
|
-
color: var(--text-muted);
|
|
1515
|
-
}
|
|
1516
|
-
|
|
1517
1398
|
.icon-btn {
|
|
1518
1399
|
display: flex;
|
|
1519
1400
|
align-items: center;
|
|
@@ -980,7 +980,7 @@
|
|
|
980
980
|
color: var(--text-muted);
|
|
981
981
|
background: var(--bg);
|
|
982
982
|
border: 1px solid var(--border);
|
|
983
|
-
border-radius:
|
|
983
|
+
border-radius: var(--radius-pill);
|
|
984
984
|
cursor: pointer;
|
|
985
985
|
transition:
|
|
986
986
|
color var(--duration-fast),
|
|
@@ -1321,7 +1321,7 @@
|
|
|
1321
1321
|
text-transform: uppercase;
|
|
1322
1322
|
letter-spacing: 0.05em;
|
|
1323
1323
|
padding: 0.15rem 0.5rem;
|
|
1324
|
-
border-radius:
|
|
1324
|
+
border-radius: var(--radius-pill);
|
|
1325
1325
|
align-self: flex-start;
|
|
1326
1326
|
}
|
|
1327
1327
|
|
|
@@ -1364,7 +1364,7 @@
|
|
|
1364
1364
|
.priority-badge {
|
|
1365
1365
|
font-size: 0.68rem;
|
|
1366
1366
|
font-weight: 500;
|
|
1367
|
-
border-radius:
|
|
1367
|
+
border-radius: var(--radius-pill);
|
|
1368
1368
|
padding: 0.15rem 0.5rem;
|
|
1369
1369
|
}
|
|
1370
1370
|
|
|
@@ -1393,7 +1393,7 @@
|
|
|
1393
1393
|
font-weight: 500;
|
|
1394
1394
|
background: var(--pass-soft);
|
|
1395
1395
|
color: var(--pass);
|
|
1396
|
-
border-radius:
|
|
1396
|
+
border-radius: var(--radius-pill);
|
|
1397
1397
|
padding: 0.15rem 0.5rem;
|
|
1398
1398
|
}
|
|
1399
1399
|
|
package/frontend/vite.config.js
CHANGED
|
@@ -19,5 +19,11 @@ import { sveltekit } from '@sveltejs/kit/vite';
|
|
|
19
19
|
import { defineConfig } from 'vite';
|
|
20
20
|
|
|
21
21
|
export default defineConfig({
|
|
22
|
-
plugins: [sveltekit()]
|
|
22
|
+
plugins: [sveltekit()],
|
|
23
|
+
server: {
|
|
24
|
+
// Plum is reverse-proxied behind whatever domain each self-hoster picks
|
|
25
|
+
// (see "Setting Up the Server" docs), so the Host header can't be known
|
|
26
|
+
// ahead of time. Disable Vite's dev-server host allowlist check entirely.
|
|
27
|
+
allowedHosts: true
|
|
28
|
+
}
|
|
23
29
|
});
|