@clemrig/flow-ui 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/server.d.ts +5 -0
- package/dist/server.js +29 -13
- package/dist/server.js.map +1 -1
- package/package.json +14 -4
- package/page/app.css +1 -0
- package/page/app.js +13 -0
- package/page/index.html +13 -0
- package/dist/static/dashboard.js +0 -207
- package/dist/static/detail.js +0 -489
- package/dist/static/follow.js +0 -103
- package/dist/static/index.html +0 -20
- package/dist/static/style.css +0 -460
- package/dist/static/timeline.js +0 -443
package/dist/static/follow.js
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
/**
|
|
3
|
-
* Follows the selected run: asks only for the events not received yet, one
|
|
4
|
-
* request after the answer to the previous one, drops an answer for a selection
|
|
5
|
-
* that has changed since, and stops once the run has ended or does not exist,
|
|
6
|
-
* until the run list shows it updated since, as a resumed run is.
|
|
7
|
-
* Requests and timers are given, so that this logic is tested without a browser.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
/** @typedef {import("@clemrig/flow").RunEvent} RunEvent */
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* @typedef {object} Answer
|
|
14
|
-
* @property {{ status: string; updatedAt?: string }} run
|
|
15
|
-
* @property {RunEvent[]} events Events from the index the request asked for.
|
|
16
|
-
* @property {number} next The index to ask for next.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* @template Timer
|
|
21
|
-
* @param {object} options
|
|
22
|
-
* @param {(path: string) => Promise<any>} options.load Rejects with `status` set on an HTTP error.
|
|
23
|
-
* @param {(work: () => void) => Timer} options.schedule Runs `work` after the polling interval.
|
|
24
|
-
* @param {(timer: Timer | undefined) => void} options.cancel
|
|
25
|
-
* @param {(answer: any, events: RunEvent[]) => void} options.show The latest answer and every event received.
|
|
26
|
-
* @param {(error: unknown) => void} options.fail
|
|
27
|
-
*/
|
|
28
|
-
export function follower({ load, schedule, cancel, show, fail }) {
|
|
29
|
-
/** One selection: a new object each time, so that an old answer never matches. */
|
|
30
|
-
let current = {
|
|
31
|
-
id: "",
|
|
32
|
-
events: /** @type {RunEvent[]} */ ([]),
|
|
33
|
-
next: 0,
|
|
34
|
-
/** Whether following stopped, on the run's end or absence. */
|
|
35
|
-
stopped: false,
|
|
36
|
-
/** The run's last update, as the last answer showed it. */
|
|
37
|
-
updatedAt: /** @type {string | undefined} */ (undefined),
|
|
38
|
-
};
|
|
39
|
-
/** @type {Timer | undefined} */
|
|
40
|
-
let timer;
|
|
41
|
-
|
|
42
|
-
/** @param {typeof current} target */
|
|
43
|
-
async function refresh(target) {
|
|
44
|
-
if (!target.id) return;
|
|
45
|
-
/** @type {Answer} */
|
|
46
|
-
let answer;
|
|
47
|
-
try {
|
|
48
|
-
answer = await load(
|
|
49
|
-
`api/runs/${encodeURIComponent(target.id)}?after=${target.next}`,
|
|
50
|
-
);
|
|
51
|
-
} catch (error) {
|
|
52
|
-
if (target !== current) return;
|
|
53
|
-
fail(error);
|
|
54
|
-
// A run that does not exist will not appear later.
|
|
55
|
-
const status = /** @type {{ status?: number }} */ (error).status;
|
|
56
|
-
if (status !== 404) timer = schedule(() => refresh(target));
|
|
57
|
-
else target.stopped = true;
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
if (target !== current) return;
|
|
61
|
-
target.events.push(...answer.events);
|
|
62
|
-
target.next = answer.next;
|
|
63
|
-
target.updatedAt = answer.run.updatedAt;
|
|
64
|
-
show(answer, target.events);
|
|
65
|
-
if (answer.run.status === "running")
|
|
66
|
-
timer = schedule(() => refresh(target));
|
|
67
|
-
else target.stopped = true;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return {
|
|
71
|
-
/** @param {string} id */
|
|
72
|
-
select(id) {
|
|
73
|
-
if (id === current.id) return;
|
|
74
|
-
cancel(timer);
|
|
75
|
-
current = {
|
|
76
|
-
id,
|
|
77
|
-
events: [],
|
|
78
|
-
next: 0,
|
|
79
|
-
stopped: false,
|
|
80
|
-
updatedAt: undefined,
|
|
81
|
-
};
|
|
82
|
-
refresh(current);
|
|
83
|
-
},
|
|
84
|
-
/**
|
|
85
|
-
* The run list shows `id` last updated at `updatedAt`: following starts
|
|
86
|
-
* again, from the events already received, if it had stopped on an earlier
|
|
87
|
-
* state of the selected run, as when it was resumed since, even if the
|
|
88
|
-
* resumed run already ended again.
|
|
89
|
-
* @param {string} id
|
|
90
|
-
* @param {string} updatedAt
|
|
91
|
-
*/
|
|
92
|
-
listed(id, updatedAt) {
|
|
93
|
-
if (
|
|
94
|
-
id !== current.id ||
|
|
95
|
-
!current.stopped ||
|
|
96
|
-
updatedAt === current.updatedAt
|
|
97
|
-
)
|
|
98
|
-
return;
|
|
99
|
-
current.stopped = false;
|
|
100
|
-
refresh(current);
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
-
}
|
package/dist/static/index.html
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
-
<title>runs</title>
|
|
7
|
-
<link rel="stylesheet" href="style.css">
|
|
8
|
-
<script type="module" src="dashboard.js"></script>
|
|
9
|
-
</head>
|
|
10
|
-
<body>
|
|
11
|
-
<header><h1 id="title">runs</h1><span id="label"></span><span id="updated"></span></header>
|
|
12
|
-
<main>
|
|
13
|
-
<div>
|
|
14
|
-
<div class="table"><table><thead><tr><th>Workflow</th><th>Status</th><th>Stage</th><th>Duration</th><th>Cost</th><th>Updated</th></tr></thead><tbody id="runs"></tbody></table></div>
|
|
15
|
-
<p id="none" class="empty" hidden>No run yet.</p>
|
|
16
|
-
</div>
|
|
17
|
-
<div id="detail"><p class="empty">Select a run.</p></div>
|
|
18
|
-
</main>
|
|
19
|
-
</body>
|
|
20
|
-
</html>
|
package/dist/static/style.css
DELETED
|
@@ -1,460 +0,0 @@
|
|
|
1
|
-
:root {
|
|
2
|
-
color-scheme: light dark;
|
|
3
|
-
--bg: #f7f7f5;
|
|
4
|
-
--panel: #fff;
|
|
5
|
-
--fg: #1d1d1b;
|
|
6
|
-
--muted: #6f6e69;
|
|
7
|
-
--line: #e4e3df;
|
|
8
|
-
--accent: #2557d6;
|
|
9
|
-
--ok: #19773a;
|
|
10
|
-
--bad: #b42318;
|
|
11
|
-
--run: #a15c07;
|
|
12
|
-
}
|
|
13
|
-
@media (prefers-color-scheme: dark) {
|
|
14
|
-
:root {
|
|
15
|
-
--bg: #111110;
|
|
16
|
-
--panel: #1b1b19;
|
|
17
|
-
--fg: #e8e7e3;
|
|
18
|
-
--muted: #9b9a94;
|
|
19
|
-
--line: #2c2c29;
|
|
20
|
-
--accent: #7aa2ff;
|
|
21
|
-
--ok: #5bd28a;
|
|
22
|
-
--bad: #ff7a6b;
|
|
23
|
-
--run: #f2b14c;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
* {
|
|
27
|
-
box-sizing: border-box;
|
|
28
|
-
}
|
|
29
|
-
body {
|
|
30
|
-
margin: 0;
|
|
31
|
-
background: var(--bg);
|
|
32
|
-
color: var(--fg);
|
|
33
|
-
font:
|
|
34
|
-
14px / 1.45 ui-sans-serif,
|
|
35
|
-
system-ui,
|
|
36
|
-
-apple-system,
|
|
37
|
-
sans-serif;
|
|
38
|
-
}
|
|
39
|
-
header {
|
|
40
|
-
display: flex;
|
|
41
|
-
flex-wrap: wrap;
|
|
42
|
-
gap: 4px 12px;
|
|
43
|
-
align-items: baseline;
|
|
44
|
-
padding: 12px 16px;
|
|
45
|
-
border-bottom: 1px solid var(--line);
|
|
46
|
-
}
|
|
47
|
-
header h1 {
|
|
48
|
-
margin: 0;
|
|
49
|
-
font-size: 16px;
|
|
50
|
-
}
|
|
51
|
-
header span {
|
|
52
|
-
color: var(--muted);
|
|
53
|
-
font-size: 13px;
|
|
54
|
-
}
|
|
55
|
-
#updated {
|
|
56
|
-
margin-left: auto;
|
|
57
|
-
}
|
|
58
|
-
main {
|
|
59
|
-
display: grid;
|
|
60
|
-
grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr);
|
|
61
|
-
gap: 16px;
|
|
62
|
-
padding: 16px;
|
|
63
|
-
}
|
|
64
|
-
@media (max-width: 900px) {
|
|
65
|
-
main {
|
|
66
|
-
grid-template-columns: minmax(0, 1fr);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
.table {
|
|
70
|
-
overflow-x: auto;
|
|
71
|
-
background: var(--panel);
|
|
72
|
-
border: 1px solid var(--line);
|
|
73
|
-
border-radius: 6px;
|
|
74
|
-
}
|
|
75
|
-
table {
|
|
76
|
-
width: 100%;
|
|
77
|
-
border-collapse: collapse;
|
|
78
|
-
}
|
|
79
|
-
th,
|
|
80
|
-
td {
|
|
81
|
-
padding: 7px 10px;
|
|
82
|
-
border-bottom: 1px solid var(--line);
|
|
83
|
-
text-align: left;
|
|
84
|
-
white-space: nowrap;
|
|
85
|
-
}
|
|
86
|
-
th {
|
|
87
|
-
color: var(--muted);
|
|
88
|
-
font-size: 12px;
|
|
89
|
-
font-weight: 500;
|
|
90
|
-
}
|
|
91
|
-
tbody tr {
|
|
92
|
-
cursor: pointer;
|
|
93
|
-
}
|
|
94
|
-
tbody tr:hover,
|
|
95
|
-
tbody tr.selected {
|
|
96
|
-
background: color-mix(in srgb, var(--accent) 12%, transparent);
|
|
97
|
-
}
|
|
98
|
-
.completed,
|
|
99
|
-
.passed {
|
|
100
|
-
color: var(--ok);
|
|
101
|
-
}
|
|
102
|
-
.failed {
|
|
103
|
-
color: var(--bad);
|
|
104
|
-
}
|
|
105
|
-
.running {
|
|
106
|
-
color: var(--run);
|
|
107
|
-
}
|
|
108
|
-
section {
|
|
109
|
-
margin-bottom: 12px;
|
|
110
|
-
padding: 10px 12px;
|
|
111
|
-
background: var(--panel);
|
|
112
|
-
border: 1px solid var(--line);
|
|
113
|
-
border-radius: 6px;
|
|
114
|
-
}
|
|
115
|
-
h2 {
|
|
116
|
-
margin: 0 0 8px;
|
|
117
|
-
color: var(--muted);
|
|
118
|
-
font-size: 12px;
|
|
119
|
-
font-weight: 600;
|
|
120
|
-
letter-spacing: 0.04em;
|
|
121
|
-
text-transform: uppercase;
|
|
122
|
-
}
|
|
123
|
-
h3 {
|
|
124
|
-
margin: 0;
|
|
125
|
-
font-size: 14px;
|
|
126
|
-
overflow-wrap: anywhere;
|
|
127
|
-
}
|
|
128
|
-
h4 {
|
|
129
|
-
margin: 14px 0 6px;
|
|
130
|
-
color: var(--muted);
|
|
131
|
-
font-size: 11px;
|
|
132
|
-
font-weight: 600;
|
|
133
|
-
letter-spacing: 0.04em;
|
|
134
|
-
text-transform: uppercase;
|
|
135
|
-
}
|
|
136
|
-
ol {
|
|
137
|
-
margin: 0;
|
|
138
|
-
padding: 0;
|
|
139
|
-
list-style: none;
|
|
140
|
-
}
|
|
141
|
-
pre,
|
|
142
|
-
.mono,
|
|
143
|
-
.log {
|
|
144
|
-
font:
|
|
145
|
-
12px / 1.45 ui-monospace,
|
|
146
|
-
SFMono-Regular,
|
|
147
|
-
Menlo,
|
|
148
|
-
monospace;
|
|
149
|
-
overflow-wrap: anywhere;
|
|
150
|
-
}
|
|
151
|
-
pre {
|
|
152
|
-
margin: 0;
|
|
153
|
-
white-space: pre-wrap;
|
|
154
|
-
}
|
|
155
|
-
.empty {
|
|
156
|
-
margin: 0;
|
|
157
|
-
color: var(--muted);
|
|
158
|
-
}
|
|
159
|
-
.muted {
|
|
160
|
-
color: var(--muted);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/* States, carried as data so that they never meet the list's status classes. */
|
|
164
|
-
[data-state="passed"],
|
|
165
|
-
[data-state="completed"] {
|
|
166
|
-
--state: var(--ok);
|
|
167
|
-
}
|
|
168
|
-
[data-state="correction"] {
|
|
169
|
-
--state: var(--run);
|
|
170
|
-
}
|
|
171
|
-
[data-state="failed"] {
|
|
172
|
-
--state: var(--bad);
|
|
173
|
-
}
|
|
174
|
-
[data-state="running"] {
|
|
175
|
-
--state: var(--accent);
|
|
176
|
-
}
|
|
177
|
-
.pill {
|
|
178
|
-
padding: 1px 8px;
|
|
179
|
-
border-radius: 999px;
|
|
180
|
-
background: color-mix(in srgb, var(--state) 16%, transparent);
|
|
181
|
-
color: var(--state);
|
|
182
|
-
font-size: 12px;
|
|
183
|
-
font-weight: 600;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/* The run's card: facts on one line, then each launch with its strip. */
|
|
187
|
-
.overview-title {
|
|
188
|
-
display: flex;
|
|
189
|
-
align-items: center;
|
|
190
|
-
justify-content: space-between;
|
|
191
|
-
gap: 10px;
|
|
192
|
-
}
|
|
193
|
-
.facts {
|
|
194
|
-
display: flex;
|
|
195
|
-
flex-wrap: wrap;
|
|
196
|
-
gap: 6px 28px;
|
|
197
|
-
margin: 10px 0 14px;
|
|
198
|
-
}
|
|
199
|
-
.facts dt {
|
|
200
|
-
color: var(--muted);
|
|
201
|
-
font-size: 12px;
|
|
202
|
-
}
|
|
203
|
-
.facts dd {
|
|
204
|
-
margin: 0;
|
|
205
|
-
font-size: 15px;
|
|
206
|
-
font-weight: 600;
|
|
207
|
-
font-variant-numeric: tabular-nums;
|
|
208
|
-
}
|
|
209
|
-
.launch {
|
|
210
|
-
padding-top: 12px;
|
|
211
|
-
border-top: 1px solid var(--line);
|
|
212
|
-
}
|
|
213
|
-
.launch-head {
|
|
214
|
-
display: flex;
|
|
215
|
-
align-items: baseline;
|
|
216
|
-
justify-content: space-between;
|
|
217
|
-
gap: 12px;
|
|
218
|
-
margin-bottom: 6px;
|
|
219
|
-
font-size: 13px;
|
|
220
|
-
font-variant-numeric: tabular-nums;
|
|
221
|
-
}
|
|
222
|
-
.launch-head .state {
|
|
223
|
-
color: var(--state);
|
|
224
|
-
font-size: 12px;
|
|
225
|
-
font-weight: 600;
|
|
226
|
-
white-space: nowrap;
|
|
227
|
-
}
|
|
228
|
-
.launch-cause {
|
|
229
|
-
margin: 6px 0 0;
|
|
230
|
-
color: var(--bad);
|
|
231
|
-
font-size: 12px;
|
|
232
|
-
}
|
|
233
|
-
.pause {
|
|
234
|
-
margin: 10px 0;
|
|
235
|
-
color: var(--muted);
|
|
236
|
-
font-size: 12px;
|
|
237
|
-
}
|
|
238
|
-
.track {
|
|
239
|
-
display: flex;
|
|
240
|
-
gap: 2px;
|
|
241
|
-
height: 22px;
|
|
242
|
-
}
|
|
243
|
-
.segment {
|
|
244
|
-
min-width: 4px;
|
|
245
|
-
flex-basis: 0;
|
|
246
|
-
padding: 0 6px;
|
|
247
|
-
overflow: hidden;
|
|
248
|
-
border: 0;
|
|
249
|
-
border-radius: 3px;
|
|
250
|
-
background: var(--state);
|
|
251
|
-
color: var(--panel);
|
|
252
|
-
font:
|
|
253
|
-
600 11px / 22px ui-sans-serif,
|
|
254
|
-
system-ui,
|
|
255
|
-
sans-serif;
|
|
256
|
-
text-overflow: ellipsis;
|
|
257
|
-
white-space: nowrap;
|
|
258
|
-
cursor: pointer;
|
|
259
|
-
}
|
|
260
|
-
.segment[data-state="passed"]:not([data-kind="AGENT"]) {
|
|
261
|
-
background: color-mix(in srgb, var(--ok) 65%, var(--panel));
|
|
262
|
-
}
|
|
263
|
-
.segment[aria-current="true"] {
|
|
264
|
-
outline: 2px solid var(--fg);
|
|
265
|
-
outline-offset: 1px;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
/* The stages: the list beside the selected stage's panel. */
|
|
269
|
-
.stages-section {
|
|
270
|
-
display: grid;
|
|
271
|
-
grid-template-columns: minmax(0, 1fr);
|
|
272
|
-
gap: 16px;
|
|
273
|
-
}
|
|
274
|
-
@media (min-width: 1300px) {
|
|
275
|
-
.stages-section {
|
|
276
|
-
grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
|
|
277
|
-
align-items: start;
|
|
278
|
-
}
|
|
279
|
-
.stage-list {
|
|
280
|
-
max-height: 75vh;
|
|
281
|
-
overflow: auto;
|
|
282
|
-
}
|
|
283
|
-
.stage-panel {
|
|
284
|
-
position: sticky;
|
|
285
|
-
top: 12px;
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
.group {
|
|
289
|
-
margin: 10px 0 4px;
|
|
290
|
-
color: var(--muted);
|
|
291
|
-
font-size: 12px;
|
|
292
|
-
font-weight: 600;
|
|
293
|
-
}
|
|
294
|
-
.stages > li {
|
|
295
|
-
border-bottom: 1px solid var(--line);
|
|
296
|
-
}
|
|
297
|
-
.stages > li:last-child {
|
|
298
|
-
border-bottom: 0;
|
|
299
|
-
}
|
|
300
|
-
.stage {
|
|
301
|
-
display: grid;
|
|
302
|
-
grid-template-columns: 18px minmax(0, 1fr) 56px 84px;
|
|
303
|
-
gap: 8px;
|
|
304
|
-
align-items: center;
|
|
305
|
-
width: 100%;
|
|
306
|
-
padding: 4px;
|
|
307
|
-
border: 0;
|
|
308
|
-
background: none;
|
|
309
|
-
color: inherit;
|
|
310
|
-
font: inherit;
|
|
311
|
-
text-align: left;
|
|
312
|
-
cursor: pointer;
|
|
313
|
-
}
|
|
314
|
-
.stage:hover,
|
|
315
|
-
.stage[aria-current="true"] {
|
|
316
|
-
background: color-mix(in srgb, var(--accent) 10%, transparent);
|
|
317
|
-
}
|
|
318
|
-
.stage .icon {
|
|
319
|
-
color: var(--state);
|
|
320
|
-
font-weight: 700;
|
|
321
|
-
text-align: center;
|
|
322
|
-
}
|
|
323
|
-
.stage .name {
|
|
324
|
-
overflow: hidden;
|
|
325
|
-
font-weight: 600;
|
|
326
|
-
text-overflow: ellipsis;
|
|
327
|
-
white-space: nowrap;
|
|
328
|
-
}
|
|
329
|
-
.stage[data-kind="GATE"][data-state="passed"] {
|
|
330
|
-
font-size: 13px;
|
|
331
|
-
}
|
|
332
|
-
.stage[data-kind="GATE"][data-state="passed"] .name,
|
|
333
|
-
.stage[data-kind="GATE"][data-state="passed"] .icon {
|
|
334
|
-
color: var(--muted);
|
|
335
|
-
font-weight: 400;
|
|
336
|
-
}
|
|
337
|
-
.kind {
|
|
338
|
-
color: var(--muted);
|
|
339
|
-
font-size: 11px;
|
|
340
|
-
letter-spacing: 0.04em;
|
|
341
|
-
}
|
|
342
|
-
.kind.tag {
|
|
343
|
-
padding: 1px 6px;
|
|
344
|
-
border: 1px solid var(--line);
|
|
345
|
-
border-radius: 4px;
|
|
346
|
-
}
|
|
347
|
-
.took {
|
|
348
|
-
font:
|
|
349
|
-
12px / 1.45 ui-monospace,
|
|
350
|
-
SFMono-Regular,
|
|
351
|
-
Menlo,
|
|
352
|
-
monospace;
|
|
353
|
-
text-align: right;
|
|
354
|
-
white-space: nowrap;
|
|
355
|
-
}
|
|
356
|
-
.panel-title {
|
|
357
|
-
display: flex;
|
|
358
|
-
align-items: center;
|
|
359
|
-
gap: 8px;
|
|
360
|
-
}
|
|
361
|
-
.sheet {
|
|
362
|
-
display: grid;
|
|
363
|
-
grid-template-columns: max-content minmax(0, 1fr);
|
|
364
|
-
gap: 5px 14px;
|
|
365
|
-
margin: 12px 0 0;
|
|
366
|
-
font-size: 13px;
|
|
367
|
-
}
|
|
368
|
-
.sheet dt {
|
|
369
|
-
color: var(--muted);
|
|
370
|
-
}
|
|
371
|
-
.sheet dd {
|
|
372
|
-
margin: 0;
|
|
373
|
-
overflow-wrap: anywhere;
|
|
374
|
-
font-variant-numeric: tabular-nums;
|
|
375
|
-
}
|
|
376
|
-
.warn {
|
|
377
|
-
color: var(--run);
|
|
378
|
-
}
|
|
379
|
-
.bad {
|
|
380
|
-
color: var(--bad);
|
|
381
|
-
}
|
|
382
|
-
.callout {
|
|
383
|
-
margin: 12px 0 0;
|
|
384
|
-
padding: 8px 10px;
|
|
385
|
-
border-left: 3px solid currentColor;
|
|
386
|
-
border-radius: 4px;
|
|
387
|
-
background: color-mix(in srgb, currentColor 8%, transparent);
|
|
388
|
-
font-size: 12px;
|
|
389
|
-
white-space: pre-wrap;
|
|
390
|
-
}
|
|
391
|
-
.chips {
|
|
392
|
-
display: flex;
|
|
393
|
-
flex-wrap: wrap;
|
|
394
|
-
gap: 4px;
|
|
395
|
-
}
|
|
396
|
-
.chip {
|
|
397
|
-
padding: 1px 7px;
|
|
398
|
-
border: 1px solid var(--line);
|
|
399
|
-
border-radius: 999px;
|
|
400
|
-
font-size: 12px;
|
|
401
|
-
font-variant-numeric: tabular-nums;
|
|
402
|
-
}
|
|
403
|
-
.chip.warn {
|
|
404
|
-
border-color: color-mix(in srgb, var(--run) 50%, transparent);
|
|
405
|
-
}
|
|
406
|
-
.log {
|
|
407
|
-
max-height: 260px;
|
|
408
|
-
padding: 6px 8px;
|
|
409
|
-
overflow: auto;
|
|
410
|
-
border: 1px solid var(--line);
|
|
411
|
-
border-radius: 6px;
|
|
412
|
-
}
|
|
413
|
-
.log li {
|
|
414
|
-
display: grid;
|
|
415
|
-
grid-template-columns: 70px minmax(0, 1fr);
|
|
416
|
-
gap: 8px;
|
|
417
|
-
padding: 1px 0;
|
|
418
|
-
}
|
|
419
|
-
.log .at {
|
|
420
|
-
color: var(--muted);
|
|
421
|
-
}
|
|
422
|
-
details.output {
|
|
423
|
-
margin: 12px 0 0;
|
|
424
|
-
}
|
|
425
|
-
details.output summary {
|
|
426
|
-
cursor: pointer;
|
|
427
|
-
font-size: 13px;
|
|
428
|
-
font-weight: 600;
|
|
429
|
-
}
|
|
430
|
-
details.output pre {
|
|
431
|
-
max-height: 360px;
|
|
432
|
-
padding: 6px 8px;
|
|
433
|
-
overflow: auto;
|
|
434
|
-
border: 1px solid var(--line);
|
|
435
|
-
border-radius: 6px;
|
|
436
|
-
}
|
|
437
|
-
.log-head {
|
|
438
|
-
display: flex;
|
|
439
|
-
align-items: baseline;
|
|
440
|
-
justify-content: space-between;
|
|
441
|
-
}
|
|
442
|
-
button.link {
|
|
443
|
-
padding: 0;
|
|
444
|
-
border: 0;
|
|
445
|
-
background: none;
|
|
446
|
-
color: var(--accent);
|
|
447
|
-
font: inherit;
|
|
448
|
-
font-size: 12px;
|
|
449
|
-
cursor: pointer;
|
|
450
|
-
}
|
|
451
|
-
.runtime {
|
|
452
|
-
margin: 10px 0 0;
|
|
453
|
-
color: var(--muted);
|
|
454
|
-
font-size: 12px;
|
|
455
|
-
overflow-wrap: anywhere;
|
|
456
|
-
}
|
|
457
|
-
:is(.stage, .segment, button.link):focus-visible {
|
|
458
|
-
outline: 2px solid var(--accent);
|
|
459
|
-
outline-offset: 1px;
|
|
460
|
-
}
|