executable-stories-react 0.8.0 → 0.10.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/dist/index.cjs +558 -335
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +45 -1
- package/dist/index.d.ts +45 -1
- package/dist/index.js +551 -335
- package/dist/index.js.map +1 -1
- package/dist/interactive.cjs +772 -476
- package/dist/interactive.cjs.map +1 -1
- package/dist/interactive.d.cts +25 -3
- package/dist/interactive.d.ts +25 -3
- package/dist/interactive.js +762 -466
- package/dist/interactive.js.map +1 -1
- package/dist/report-island.global.js +28 -28
- package/dist/ssr.cjs +477 -299
- package/dist/ssr.cjs.map +1 -1
- package/dist/ssr.js +477 -299
- package/dist/ssr.js.map +1 -1
- package/dist/tailwind.css +1 -1
- package/package.json +1 -1
package/dist/interactive.js
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
// src/interactive/ReportInteractive.tsx
|
|
4
4
|
import {
|
|
5
|
-
useCallback as
|
|
5
|
+
useCallback as useCallback5,
|
|
6
6
|
useDeferredValue,
|
|
7
7
|
useId as useId2,
|
|
8
8
|
useMemo as useMemo3,
|
|
9
|
-
useRef as
|
|
10
|
-
useState as
|
|
9
|
+
useRef as useRef5,
|
|
10
|
+
useState as useState8
|
|
11
11
|
} from "react";
|
|
12
12
|
|
|
13
13
|
// src/result.ts
|
|
@@ -26,63 +26,6 @@ import { useMemo } from "react";
|
|
|
26
26
|
import { createContext } from "react";
|
|
27
27
|
var ReportContext = createContext(null);
|
|
28
28
|
|
|
29
|
-
// src/context/ReportRoot.tsx
|
|
30
|
-
import { jsx } from "react/jsx-runtime";
|
|
31
|
-
var EMPTY_CUSTOM = {};
|
|
32
|
-
var EMPTY_RENDERERS = {};
|
|
33
|
-
function ReportRoot({
|
|
34
|
-
report,
|
|
35
|
-
customRenderers,
|
|
36
|
-
renderers,
|
|
37
|
-
children
|
|
38
|
-
}) {
|
|
39
|
-
const value = useMemo(
|
|
40
|
-
() => ({
|
|
41
|
-
report,
|
|
42
|
-
customRenderers: customRenderers ?? EMPTY_CUSTOM,
|
|
43
|
-
renderers: renderers ?? EMPTY_RENDERERS
|
|
44
|
-
}),
|
|
45
|
-
[report, customRenderers, renderers]
|
|
46
|
-
);
|
|
47
|
-
return /* @__PURE__ */ jsx(ReportContext.Provider, { value, children });
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// src/hooks/useReport.ts
|
|
51
|
-
import { useContext } from "react";
|
|
52
|
-
function useReport() {
|
|
53
|
-
const ctx = useContext(ReportContext);
|
|
54
|
-
if (!ctx) {
|
|
55
|
-
throw new Error(
|
|
56
|
-
"useReport must be used inside <ReportRoot> or <Report>. Wrap your tree with one of those."
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
return ctx.report;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// ../executable-stories-core/dist/utils/duration.js
|
|
63
|
-
function formatDuration(ms) {
|
|
64
|
-
if (ms < 1e3) {
|
|
65
|
-
return `${Math.round(ms)} ms`;
|
|
66
|
-
}
|
|
67
|
-
if (ms < 6e4) {
|
|
68
|
-
return `${(ms / 1e3).toFixed(2)} s`;
|
|
69
|
-
}
|
|
70
|
-
const minutes = Math.floor(ms / 6e4);
|
|
71
|
-
const seconds = Math.floor(ms % 6e4 / 1e3);
|
|
72
|
-
if (minutes < 60) {
|
|
73
|
-
return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
|
|
74
|
-
}
|
|
75
|
-
const hours = Math.floor(minutes / 60);
|
|
76
|
-
const remainingMinutes = minutes % 60;
|
|
77
|
-
return `${hours}h ${remainingMinutes}m`;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// src/components/doc/DocNote.tsx
|
|
81
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
82
|
-
function DocNote({ entry }) {
|
|
83
|
-
return /* @__PURE__ */ jsx2("p", { className: "my-2 text-sm text-muted-foreground", children: entry.text });
|
|
84
|
-
}
|
|
85
|
-
|
|
86
29
|
// src/components/ui/badge.tsx
|
|
87
30
|
import "react";
|
|
88
31
|
import { cva } from "class-variance-authority";
|
|
@@ -141,14 +84,249 @@ function Badge({
|
|
|
141
84
|
});
|
|
142
85
|
}
|
|
143
86
|
|
|
144
|
-
// src/components/doc/
|
|
87
|
+
// src/components/doc/NarrativeBlocks.tsx
|
|
88
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
89
|
+
var FILE_TREE_TYPE = "file-tree";
|
|
90
|
+
var DATA_MODEL_TYPE = "data-model";
|
|
91
|
+
function isChangeKind(value) {
|
|
92
|
+
return value === "added" || value === "modified" || value === "removed" || value === "renamed";
|
|
93
|
+
}
|
|
94
|
+
function isRecord(value) {
|
|
95
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
96
|
+
}
|
|
97
|
+
function str(value) {
|
|
98
|
+
return typeof value === "string" && value !== "" ? value : void 0;
|
|
99
|
+
}
|
|
100
|
+
function AuthoredMarker({ authored }) {
|
|
101
|
+
if (authored !== "agent") return null;
|
|
102
|
+
return /* @__PURE__ */ jsx(Badge, { variant: "outline", className: "border-border text-[10px] text-muted-foreground", children: "AI-authored, not verified by a run" });
|
|
103
|
+
}
|
|
104
|
+
function BlockFrame({
|
|
105
|
+
title,
|
|
106
|
+
authored,
|
|
107
|
+
children
|
|
108
|
+
}) {
|
|
109
|
+
return /* @__PURE__ */ jsxs("figure", { className: "my-3", children: [
|
|
110
|
+
title || authored === "agent" ? /* @__PURE__ */ jsxs("figcaption", { className: "mb-1.5 flex flex-wrap items-center gap-2", children: [
|
|
111
|
+
title ? /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: title }) : null,
|
|
112
|
+
/* @__PURE__ */ jsx(AuthoredMarker, { authored })
|
|
113
|
+
] }) : null,
|
|
114
|
+
children
|
|
115
|
+
] });
|
|
116
|
+
}
|
|
117
|
+
function ChangeBadge({ change }) {
|
|
118
|
+
return /* @__PURE__ */ jsx(Badge, { variant: "tag", className: "text-[10px]", children: change });
|
|
119
|
+
}
|
|
120
|
+
function parseFileTree(data) {
|
|
121
|
+
if (!isRecord(data) || !Array.isArray(data.files)) return void 0;
|
|
122
|
+
const files = [];
|
|
123
|
+
for (const raw of data.files) {
|
|
124
|
+
if (typeof raw === "string") {
|
|
125
|
+
if (raw) files.push({ path: raw });
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (!isRecord(raw)) continue;
|
|
129
|
+
const path = str(raw.path);
|
|
130
|
+
if (!path) continue;
|
|
131
|
+
files.push({
|
|
132
|
+
path,
|
|
133
|
+
change: isChangeKind(raw.change) ? raw.change : void 0,
|
|
134
|
+
note: str(raw.note)
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
if (files.length === 0) return void 0;
|
|
138
|
+
return { title: str(data.title), authored: str(data.authored), files };
|
|
139
|
+
}
|
|
140
|
+
function buildTree(files) {
|
|
141
|
+
const root = { name: "", children: /* @__PURE__ */ new Map() };
|
|
142
|
+
for (const file of files) {
|
|
143
|
+
const segments = file.path.split("/").filter(Boolean);
|
|
144
|
+
let node = root;
|
|
145
|
+
segments.forEach((segment, index) => {
|
|
146
|
+
let child = node.children.get(segment);
|
|
147
|
+
if (!child) {
|
|
148
|
+
child = { name: segment, children: /* @__PURE__ */ new Map() };
|
|
149
|
+
node.children.set(segment, child);
|
|
150
|
+
}
|
|
151
|
+
if (index === segments.length - 1) child.file = file;
|
|
152
|
+
node = child;
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
return root;
|
|
156
|
+
}
|
|
157
|
+
function sortedChildren(node) {
|
|
158
|
+
return [...node.children.values()].sort((a, b) => {
|
|
159
|
+
const aDir = a.children.size > 0;
|
|
160
|
+
const bDir = b.children.size > 0;
|
|
161
|
+
if (aDir !== bDir) return aDir ? -1 : 1;
|
|
162
|
+
return a.name.localeCompare(b.name);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
function TreeBranch({ node, depth }) {
|
|
166
|
+
const children = sortedChildren(node);
|
|
167
|
+
return /* @__PURE__ */ jsx("ul", { className: cn("space-y-0.5", depth > 0 && "ml-3 border-l border-border/60 pl-3"), children: children.map((child) => {
|
|
168
|
+
const isDir = child.children.size > 0;
|
|
169
|
+
return /* @__PURE__ */ jsxs("li", { children: [
|
|
170
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-baseline gap-2", children: [
|
|
171
|
+
/* @__PURE__ */ jsx(
|
|
172
|
+
"span",
|
|
173
|
+
{
|
|
174
|
+
className: cn(
|
|
175
|
+
"font-mono text-xs",
|
|
176
|
+
isDir ? "text-muted-foreground" : "text-foreground"
|
|
177
|
+
),
|
|
178
|
+
children: isDir ? `${child.name}/` : child.name
|
|
179
|
+
}
|
|
180
|
+
),
|
|
181
|
+
child.file?.change ? /* @__PURE__ */ jsx(ChangeBadge, { change: child.file.change }) : null,
|
|
182
|
+
child.file?.note ? /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: child.file.note }) : null
|
|
183
|
+
] }),
|
|
184
|
+
isDir ? /* @__PURE__ */ jsx(TreeBranch, { node: child, depth: depth + 1 }) : null
|
|
185
|
+
] }, child.name);
|
|
186
|
+
}) });
|
|
187
|
+
}
|
|
188
|
+
function FileTreeBlock({ entry }) {
|
|
189
|
+
const data = parseFileTree(entry.data);
|
|
190
|
+
if (!data) return /* @__PURE__ */ jsx(UnreadableBlock, { entry });
|
|
191
|
+
return /* @__PURE__ */ jsx(BlockFrame, { title: data.title ?? "Files changed", authored: data.authored, children: /* @__PURE__ */ jsx("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border bg-card p-3", children: /* @__PURE__ */ jsx(TreeBranch, { node: buildTree(data.files), depth: 0 }) }) });
|
|
192
|
+
}
|
|
193
|
+
function parseDataModel(data) {
|
|
194
|
+
if (!isRecord(data) || !Array.isArray(data.fields)) return void 0;
|
|
195
|
+
const fields = [];
|
|
196
|
+
for (const raw of data.fields) {
|
|
197
|
+
if (!isRecord(raw)) continue;
|
|
198
|
+
const name = str(raw.name);
|
|
199
|
+
if (!name) continue;
|
|
200
|
+
fields.push({
|
|
201
|
+
name,
|
|
202
|
+
type: str(raw.type),
|
|
203
|
+
note: str(raw.note),
|
|
204
|
+
change: isChangeKind(raw.change) ? raw.change : void 0
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
if (fields.length === 0) return void 0;
|
|
208
|
+
return {
|
|
209
|
+
title: str(data.title),
|
|
210
|
+
authored: str(data.authored),
|
|
211
|
+
name: str(data.name),
|
|
212
|
+
fields
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
function DataModelBlock({ entry }) {
|
|
216
|
+
const data = parseDataModel(entry.data);
|
|
217
|
+
if (!data) return /* @__PURE__ */ jsx(UnreadableBlock, { entry });
|
|
218
|
+
const hasNotes = data.fields.some((f) => f.note);
|
|
219
|
+
return /* @__PURE__ */ jsx(BlockFrame, { title: data.title ?? data.name ?? "Data model", authored: data.authored, children: /* @__PURE__ */ jsx("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border", children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse text-sm", children: [
|
|
220
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "bg-muted/50", children: [
|
|
221
|
+
/* @__PURE__ */ jsx("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Field" }),
|
|
222
|
+
/* @__PURE__ */ jsx("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Type" }),
|
|
223
|
+
hasNotes ? /* @__PURE__ */ jsx("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Note" }) : null
|
|
224
|
+
] }) }),
|
|
225
|
+
/* @__PURE__ */ jsx("tbody", { children: data.fields.map((field) => /* @__PURE__ */ jsxs("tr", { children: [
|
|
226
|
+
/* @__PURE__ */ jsx("td", { className: "border-b border-border px-3 py-2", children: /* @__PURE__ */ jsxs("span", { className: "flex flex-wrap items-center gap-2", children: [
|
|
227
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono text-xs text-foreground", children: field.name }),
|
|
228
|
+
field.change ? /* @__PURE__ */ jsx(ChangeBadge, { change: field.change }) : null
|
|
229
|
+
] }) }),
|
|
230
|
+
/* @__PURE__ */ jsx("td", { className: "border-b border-border px-3 py-2 font-mono text-xs text-muted-foreground", children: field.type ?? "" }),
|
|
231
|
+
hasNotes ? /* @__PURE__ */ jsx("td", { className: "border-b border-border px-3 py-2 text-foreground", children: field.note ?? "" }) : null
|
|
232
|
+
] }, field.name)) })
|
|
233
|
+
] }) }) });
|
|
234
|
+
}
|
|
235
|
+
function UnreadableBlock({ entry }) {
|
|
236
|
+
return /* @__PURE__ */ jsxs("div", { className: "my-2", "data-type": entry.type, children: [
|
|
237
|
+
/* @__PURE__ */ jsxs("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: [
|
|
238
|
+
entry.type,
|
|
239
|
+
" (unrecognised shape)"
|
|
240
|
+
] }),
|
|
241
|
+
/* @__PURE__ */ jsx(
|
|
242
|
+
"pre",
|
|
243
|
+
{
|
|
244
|
+
tabIndex: 0,
|
|
245
|
+
className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground",
|
|
246
|
+
children: safeStringify(entry.data)
|
|
247
|
+
}
|
|
248
|
+
)
|
|
249
|
+
] });
|
|
250
|
+
}
|
|
251
|
+
function safeStringify(value) {
|
|
252
|
+
try {
|
|
253
|
+
return JSON.stringify(value, null, 2);
|
|
254
|
+
} catch {
|
|
255
|
+
return String(value);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
var narrativeBlockRenderers = {
|
|
259
|
+
[FILE_TREE_TYPE]: (entry) => /* @__PURE__ */ jsx(FileTreeBlock, { entry }),
|
|
260
|
+
[DATA_MODEL_TYPE]: (entry) => /* @__PURE__ */ jsx(DataModelBlock, { entry })
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
// src/context/ReportRoot.tsx
|
|
264
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
265
|
+
var EMPTY_RENDERERS = {};
|
|
266
|
+
function ReportRoot({
|
|
267
|
+
report,
|
|
268
|
+
customRenderers,
|
|
269
|
+
renderers,
|
|
270
|
+
children
|
|
271
|
+
}) {
|
|
272
|
+
const value = useMemo(
|
|
273
|
+
() => ({
|
|
274
|
+
report,
|
|
275
|
+
// Narrative blocks render everywhere the report does (static SSR, the
|
|
276
|
+
// island, Astro) without every host wiring them up. A host renderer for
|
|
277
|
+
// the same type still wins.
|
|
278
|
+
customRenderers: { ...narrativeBlockRenderers, ...customRenderers },
|
|
279
|
+
renderers: renderers ?? EMPTY_RENDERERS
|
|
280
|
+
}),
|
|
281
|
+
[report, customRenderers, renderers]
|
|
282
|
+
);
|
|
283
|
+
return /* @__PURE__ */ jsx2(ReportContext.Provider, { value, children });
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// src/hooks/useReport.ts
|
|
287
|
+
import { useContext } from "react";
|
|
288
|
+
function useReport() {
|
|
289
|
+
const ctx = useContext(ReportContext);
|
|
290
|
+
if (!ctx) {
|
|
291
|
+
throw new Error(
|
|
292
|
+
"useReport must be used inside <ReportRoot> or <Report>. Wrap your tree with one of those."
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
return ctx.report;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// ../executable-stories-core/dist/utils/duration.js
|
|
299
|
+
function formatDuration(ms) {
|
|
300
|
+
if (ms < 1e3) {
|
|
301
|
+
return `${Math.round(ms)} ms`;
|
|
302
|
+
}
|
|
303
|
+
if (ms < 6e4) {
|
|
304
|
+
return `${(ms / 1e3).toFixed(2)} s`;
|
|
305
|
+
}
|
|
306
|
+
const minutes = Math.floor(ms / 6e4);
|
|
307
|
+
const seconds = Math.floor(ms % 6e4 / 1e3);
|
|
308
|
+
if (minutes < 60) {
|
|
309
|
+
return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
|
|
310
|
+
}
|
|
311
|
+
const hours = Math.floor(minutes / 60);
|
|
312
|
+
const remainingMinutes = minutes % 60;
|
|
313
|
+
return `${hours}h ${remainingMinutes}m`;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// src/components/doc/DocNote.tsx
|
|
145
317
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
318
|
+
function DocNote({ entry }) {
|
|
319
|
+
return /* @__PURE__ */ jsx3("p", { className: "my-2 text-sm text-muted-foreground", children: entry.text });
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// src/components/doc/DocTag.tsx
|
|
323
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
146
324
|
function DocTag({ entry }) {
|
|
147
|
-
return /* @__PURE__ */
|
|
325
|
+
return /* @__PURE__ */ jsx4("ul", { className: "my-2 flex flex-wrap gap-1.5", "aria-label": "Tags", children: entry.names.map((n) => /* @__PURE__ */ jsx4("li", { children: /* @__PURE__ */ jsx4(Badge, { variant: "tag", children: n }) }, n)) });
|
|
148
326
|
}
|
|
149
327
|
|
|
150
328
|
// src/components/doc/DocKv.tsx
|
|
151
|
-
import { jsx as
|
|
329
|
+
import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
152
330
|
function formatValue(value) {
|
|
153
331
|
if (value === null) return "null";
|
|
154
332
|
if (typeof value === "string") return value;
|
|
@@ -160,19 +338,19 @@ function formatValue(value) {
|
|
|
160
338
|
}
|
|
161
339
|
}
|
|
162
340
|
function DocKv({ entry }) {
|
|
163
|
-
return /* @__PURE__ */
|
|
164
|
-
/* @__PURE__ */
|
|
165
|
-
/* @__PURE__ */
|
|
341
|
+
return /* @__PURE__ */ jsxs2("dl", { className: "my-2 flex flex-wrap items-baseline gap-x-2 text-sm", children: [
|
|
342
|
+
/* @__PURE__ */ jsx5("dt", { className: "font-semibold text-muted-foreground", children: entry.label }),
|
|
343
|
+
/* @__PURE__ */ jsx5("dd", { className: "font-mono text-foreground", children: formatValue(entry.value) })
|
|
166
344
|
] });
|
|
167
345
|
}
|
|
168
346
|
|
|
169
347
|
// src/hooks/useRenderers.ts
|
|
170
348
|
import { useContext as useContext2 } from "react";
|
|
171
|
-
var
|
|
349
|
+
var EMPTY_CUSTOM = {};
|
|
172
350
|
var EMPTY_RENDERERS2 = {};
|
|
173
351
|
function useCustomRenderers() {
|
|
174
352
|
const ctx = useContext2(ReportContext);
|
|
175
|
-
return ctx?.customRenderers ??
|
|
353
|
+
return ctx?.customRenderers ?? EMPTY_CUSTOM;
|
|
176
354
|
}
|
|
177
355
|
function useBuiltinRenderers() {
|
|
178
356
|
const ctx = useContext2(ReportContext);
|
|
@@ -180,37 +358,37 @@ function useBuiltinRenderers() {
|
|
|
180
358
|
}
|
|
181
359
|
|
|
182
360
|
// src/components/doc/DocCode.tsx
|
|
183
|
-
import { Fragment, jsx as
|
|
361
|
+
import { Fragment, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
184
362
|
function CodeFigure({ label, children }) {
|
|
185
|
-
return /* @__PURE__ */
|
|
186
|
-
label ? /* @__PURE__ */
|
|
187
|
-
/* @__PURE__ */
|
|
363
|
+
return /* @__PURE__ */ jsxs3("figure", { className: "my-3", children: [
|
|
364
|
+
label ? /* @__PURE__ */ jsx6("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: label }) : null,
|
|
365
|
+
/* @__PURE__ */ jsx6("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3", children })
|
|
188
366
|
] });
|
|
189
367
|
}
|
|
190
368
|
function DocCode({ entry }) {
|
|
191
369
|
const renderers = useBuiltinRenderers();
|
|
192
370
|
if (renderers.code) {
|
|
193
|
-
return /* @__PURE__ */
|
|
371
|
+
return /* @__PURE__ */ jsx6(Fragment, { children: renderers.code(entry) });
|
|
194
372
|
}
|
|
195
|
-
return /* @__PURE__ */
|
|
373
|
+
return /* @__PURE__ */ jsx6(CodeFigure, { label: entry.label, children: /* @__PURE__ */ jsx6("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
|
|
196
374
|
}
|
|
197
375
|
|
|
198
376
|
// src/components/doc/DocTable.tsx
|
|
199
|
-
import { jsx as
|
|
377
|
+
import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
200
378
|
function DocTable({ entry }) {
|
|
201
|
-
return /* @__PURE__ */
|
|
202
|
-
entry.label ? /* @__PURE__ */
|
|
203
|
-
/* @__PURE__ */
|
|
204
|
-
/* @__PURE__ */
|
|
205
|
-
/* @__PURE__ */
|
|
379
|
+
return /* @__PURE__ */ jsxs4("figure", { className: "my-3", children: [
|
|
380
|
+
entry.label ? /* @__PURE__ */ jsx7("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.label }) : null,
|
|
381
|
+
/* @__PURE__ */ jsx7("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border", children: /* @__PURE__ */ jsxs4("table", { className: "w-full border-collapse text-sm", children: [
|
|
382
|
+
/* @__PURE__ */ jsx7("thead", { children: /* @__PURE__ */ jsx7("tr", { className: "bg-muted/50", children: entry.columns.map((c) => /* @__PURE__ */ jsx7("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: c }, c)) }) }),
|
|
383
|
+
/* @__PURE__ */ jsx7("tbody", { children: entry.rows.map((row, i) => /* @__PURE__ */ jsx7("tr", { children: row.map((cell2, j) => /* @__PURE__ */ jsx7("td", { className: "border-b border-border px-3 py-2 text-foreground", children: cell2 }, j)) }, i)) })
|
|
206
384
|
] }) })
|
|
207
385
|
] });
|
|
208
386
|
}
|
|
209
387
|
|
|
210
388
|
// src/components/doc/DocLink.tsx
|
|
211
|
-
import { jsx as
|
|
389
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
212
390
|
function DocLink({ entry }) {
|
|
213
|
-
return /* @__PURE__ */
|
|
391
|
+
return /* @__PURE__ */ jsx8(
|
|
214
392
|
"a",
|
|
215
393
|
{
|
|
216
394
|
className: "text-sm font-medium text-primary underline underline-offset-2 hover:no-underline",
|
|
@@ -244,7 +422,7 @@ function isLocalFsPath(value) {
|
|
|
244
422
|
}
|
|
245
423
|
|
|
246
424
|
// src/components/doc/DocSection.tsx
|
|
247
|
-
import { Fragment as Fragment2, jsx as
|
|
425
|
+
import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
248
426
|
function neutralizeUrl(value) {
|
|
249
427
|
return safeUrl(value) ?? "#";
|
|
250
428
|
}
|
|
@@ -255,12 +433,12 @@ function safeMarkdownHtml(markdown) {
|
|
|
255
433
|
function DocSection({ entry }) {
|
|
256
434
|
const renderers = useBuiltinRenderers();
|
|
257
435
|
if (renderers.section) {
|
|
258
|
-
return /* @__PURE__ */
|
|
436
|
+
return /* @__PURE__ */ jsx9(Fragment2, { children: renderers.section(entry) });
|
|
259
437
|
}
|
|
260
438
|
const html = safeMarkdownHtml(entry.markdown);
|
|
261
|
-
return /* @__PURE__ */
|
|
262
|
-
entry.title ? /* @__PURE__ */
|
|
263
|
-
/* @__PURE__ */
|
|
439
|
+
return /* @__PURE__ */ jsxs5("section", { className: "my-3 text-sm", "aria-label": entry.title, children: [
|
|
440
|
+
entry.title ? /* @__PURE__ */ jsx9("h4", { className: "mb-1 font-semibold text-foreground", children: entry.title }) : null,
|
|
441
|
+
/* @__PURE__ */ jsx9(
|
|
264
442
|
"div",
|
|
265
443
|
{
|
|
266
444
|
className: "es-doc-prose prose prose-sm max-w-none",
|
|
@@ -271,11 +449,11 @@ function DocSection({ entry }) {
|
|
|
271
449
|
}
|
|
272
450
|
|
|
273
451
|
// src/components/doc/DocMermaid.tsx
|
|
274
|
-
import { Fragment as Fragment3, jsx as
|
|
452
|
+
import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
275
453
|
function MermaidSource({ entry, ref }) {
|
|
276
|
-
return /* @__PURE__ */
|
|
277
|
-
entry.title ? /* @__PURE__ */
|
|
278
|
-
/* @__PURE__ */
|
|
454
|
+
return /* @__PURE__ */ jsxs6("figure", { ref, className: "my-3", "aria-label": entry.title ?? "Diagram", children: [
|
|
455
|
+
entry.title ? /* @__PURE__ */ jsx10("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
|
|
456
|
+
/* @__PURE__ */ jsx10(
|
|
279
457
|
"pre",
|
|
280
458
|
{
|
|
281
459
|
"data-mermaid": true,
|
|
@@ -289,24 +467,24 @@ function MermaidSource({ entry, ref }) {
|
|
|
289
467
|
function DocMermaid({ entry }) {
|
|
290
468
|
const renderers = useBuiltinRenderers();
|
|
291
469
|
if (renderers.mermaid) {
|
|
292
|
-
return /* @__PURE__ */
|
|
470
|
+
return /* @__PURE__ */ jsx10(Fragment3, { children: renderers.mermaid(entry) });
|
|
293
471
|
}
|
|
294
|
-
return /* @__PURE__ */
|
|
472
|
+
return /* @__PURE__ */ jsx10(MermaidSource, { entry });
|
|
295
473
|
}
|
|
296
474
|
|
|
297
475
|
// src/components/doc/DocScreenshot.tsx
|
|
298
|
-
import { jsx as
|
|
476
|
+
import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
299
477
|
function DocScreenshot({ entry }) {
|
|
300
478
|
const src = isLocalFsPath(entry.path) ? void 0 : safeImageUrl(entry.path);
|
|
301
479
|
if (!src) {
|
|
302
|
-
return /* @__PURE__ */
|
|
303
|
-
/* @__PURE__ */
|
|
304
|
-
/* @__PURE__ */
|
|
305
|
-
entry.alt ? /* @__PURE__ */
|
|
480
|
+
return /* @__PURE__ */ jsxs7("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
|
|
481
|
+
/* @__PURE__ */ jsx11("div", { className: "font-medium", children: "Screenshot unavailable" }),
|
|
482
|
+
/* @__PURE__ */ jsx11("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
|
|
483
|
+
entry.alt ? /* @__PURE__ */ jsx11("figcaption", { className: "mt-1.5 text-xs", children: entry.alt }) : null
|
|
306
484
|
] });
|
|
307
485
|
}
|
|
308
|
-
return /* @__PURE__ */
|
|
309
|
-
/* @__PURE__ */
|
|
486
|
+
return /* @__PURE__ */ jsxs7("figure", { className: "my-3", children: [
|
|
487
|
+
/* @__PURE__ */ jsx11(
|
|
310
488
|
"img",
|
|
311
489
|
{
|
|
312
490
|
src,
|
|
@@ -315,24 +493,24 @@ function DocScreenshot({ entry }) {
|
|
|
315
493
|
className: "max-w-full rounded-md border border-border"
|
|
316
494
|
}
|
|
317
495
|
),
|
|
318
|
-
entry.alt ? /* @__PURE__ */
|
|
496
|
+
entry.alt ? /* @__PURE__ */ jsx11("figcaption", { className: "mt-1.5 text-xs text-muted-foreground", children: entry.alt }) : null
|
|
319
497
|
] });
|
|
320
498
|
}
|
|
321
499
|
|
|
322
500
|
// src/components/doc/DocVideo.tsx
|
|
323
|
-
import { jsx as
|
|
501
|
+
import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
324
502
|
function DocVideo({ entry }) {
|
|
325
503
|
if (isLocalFsPath(entry.path)) {
|
|
326
|
-
return /* @__PURE__ */
|
|
327
|
-
/* @__PURE__ */
|
|
328
|
-
/* @__PURE__ */
|
|
329
|
-
entry.caption ? /* @__PURE__ */
|
|
504
|
+
return /* @__PURE__ */ jsxs8("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
|
|
505
|
+
/* @__PURE__ */ jsx12("div", { className: "font-medium", children: "Video unavailable" }),
|
|
506
|
+
/* @__PURE__ */ jsx12("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
|
|
507
|
+
entry.caption ? /* @__PURE__ */ jsx12("figcaption", { className: "mt-1.5 text-xs", children: entry.caption }) : null
|
|
330
508
|
] });
|
|
331
509
|
}
|
|
332
510
|
const src = safeUrl(entry.path);
|
|
333
511
|
const poster = safeUrl(entry.poster);
|
|
334
|
-
return /* @__PURE__ */
|
|
335
|
-
/* @__PURE__ */
|
|
512
|
+
return /* @__PURE__ */ jsxs8("figure", { className: "my-3", children: [
|
|
513
|
+
/* @__PURE__ */ jsx12(
|
|
336
514
|
"video",
|
|
337
515
|
{
|
|
338
516
|
controls: true,
|
|
@@ -342,21 +520,21 @@ function DocVideo({ entry }) {
|
|
|
342
520
|
className: "max-w-full rounded-md border border-border"
|
|
343
521
|
}
|
|
344
522
|
),
|
|
345
|
-
entry.caption ? /* @__PURE__ */
|
|
523
|
+
entry.caption ? /* @__PURE__ */ jsx12("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: entry.caption }) : null
|
|
346
524
|
] });
|
|
347
525
|
}
|
|
348
526
|
|
|
349
527
|
// src/components/doc/DocHtml.tsx
|
|
350
|
-
import { jsx as
|
|
528
|
+
import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
351
529
|
function DocHtml({ entry }) {
|
|
352
530
|
const height = typeof entry.height === "number" ? `${entry.height}px` : entry.height ?? "400px";
|
|
353
531
|
const title = entry.title ?? "Embedded HTML";
|
|
354
532
|
const safeHref = safeUrl(entry.url ?? entry.path);
|
|
355
533
|
const frameProps = entry.content !== void 0 ? { srcDoc: entry.content } : { src: safeHref ?? "" };
|
|
356
|
-
return /* @__PURE__ */
|
|
357
|
-
/* @__PURE__ */
|
|
358
|
-
/* @__PURE__ */
|
|
359
|
-
safeHref ? /* @__PURE__ */
|
|
534
|
+
return /* @__PURE__ */ jsxs9("figure", { className: "my-3 overflow-hidden rounded-md border border-border", children: [
|
|
535
|
+
/* @__PURE__ */ jsxs9("figcaption", { className: "flex items-center justify-between border-b border-border bg-muted/40 px-3 py-1.5 text-xs font-medium text-muted-foreground", children: [
|
|
536
|
+
/* @__PURE__ */ jsx13("span", { children: entry.title ?? "HTML" }),
|
|
537
|
+
safeHref ? /* @__PURE__ */ jsx13(
|
|
360
538
|
"a",
|
|
361
539
|
{
|
|
362
540
|
href: safeHref,
|
|
@@ -369,7 +547,7 @@ function DocHtml({ entry }) {
|
|
|
369
547
|
}
|
|
370
548
|
) : null
|
|
371
549
|
] }),
|
|
372
|
-
/* @__PURE__ */
|
|
550
|
+
/* @__PURE__ */ jsx13(
|
|
373
551
|
"iframe",
|
|
374
552
|
{
|
|
375
553
|
...frameProps,
|
|
@@ -384,7 +562,7 @@ function DocHtml({ entry }) {
|
|
|
384
562
|
}
|
|
385
563
|
|
|
386
564
|
// src/components/doc/DocState.tsx
|
|
387
|
-
import { jsx as
|
|
565
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
388
566
|
function DocState({ entry }) {
|
|
389
567
|
let json;
|
|
390
568
|
try {
|
|
@@ -392,23 +570,23 @@ function DocState({ entry }) {
|
|
|
392
570
|
} catch {
|
|
393
571
|
json = String(entry.value);
|
|
394
572
|
}
|
|
395
|
-
return /* @__PURE__ */
|
|
573
|
+
return /* @__PURE__ */ jsx14(CodeFigure, { label: entry.label ?? "State", children: /* @__PURE__ */ jsx14("code", { className: "font-mono text-xs language-json", children: json }) });
|
|
396
574
|
}
|
|
397
575
|
|
|
398
576
|
// src/components/doc/DocCustom.tsx
|
|
399
|
-
import { Fragment as Fragment4, jsx as
|
|
577
|
+
import { Fragment as Fragment4, jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
400
578
|
function DocCustom({ entry }) {
|
|
401
579
|
const renderers = useCustomRenderers();
|
|
402
580
|
const renderer = renderers[entry.type];
|
|
403
581
|
if (renderer) {
|
|
404
|
-
return /* @__PURE__ */
|
|
582
|
+
return /* @__PURE__ */ jsx15(Fragment4, { children: renderer(entry) });
|
|
405
583
|
}
|
|
406
|
-
return /* @__PURE__ */
|
|
407
|
-
/* @__PURE__ */
|
|
408
|
-
/* @__PURE__ */
|
|
584
|
+
return /* @__PURE__ */ jsxs10("div", { className: "my-2", "data-type": entry.type, children: [
|
|
585
|
+
/* @__PURE__ */ jsx15("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: entry.type }),
|
|
586
|
+
/* @__PURE__ */ jsx15("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground", children: safeStringify2(entry.data) })
|
|
409
587
|
] });
|
|
410
588
|
}
|
|
411
|
-
function
|
|
589
|
+
function safeStringify2(value) {
|
|
412
590
|
try {
|
|
413
591
|
return JSON.stringify(value, null, 2);
|
|
414
592
|
} catch {
|
|
@@ -417,47 +595,47 @@ function safeStringify(value) {
|
|
|
417
595
|
}
|
|
418
596
|
|
|
419
597
|
// src/components/doc/DocEntry.tsx
|
|
420
|
-
import { jsx as
|
|
598
|
+
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
421
599
|
function DocEntry({ entry }) {
|
|
422
600
|
switch (entry.kind) {
|
|
423
601
|
case "note":
|
|
424
|
-
return /* @__PURE__ */
|
|
602
|
+
return /* @__PURE__ */ jsx16(DocNote, { entry });
|
|
425
603
|
case "tag":
|
|
426
|
-
return /* @__PURE__ */
|
|
604
|
+
return /* @__PURE__ */ jsx16(DocTag, { entry });
|
|
427
605
|
case "kv":
|
|
428
|
-
return /* @__PURE__ */
|
|
606
|
+
return /* @__PURE__ */ jsx16(DocKv, { entry });
|
|
429
607
|
case "code":
|
|
430
|
-
return /* @__PURE__ */
|
|
608
|
+
return /* @__PURE__ */ jsx16(DocCode, { entry });
|
|
431
609
|
case "table":
|
|
432
|
-
return /* @__PURE__ */
|
|
610
|
+
return /* @__PURE__ */ jsx16(DocTable, { entry });
|
|
433
611
|
case "link":
|
|
434
|
-
return /* @__PURE__ */
|
|
612
|
+
return /* @__PURE__ */ jsx16(DocLink, { entry });
|
|
435
613
|
case "section":
|
|
436
|
-
return /* @__PURE__ */
|
|
614
|
+
return /* @__PURE__ */ jsx16(DocSection, { entry });
|
|
437
615
|
case "mermaid":
|
|
438
|
-
return /* @__PURE__ */
|
|
616
|
+
return /* @__PURE__ */ jsx16(DocMermaid, { entry });
|
|
439
617
|
case "screenshot":
|
|
440
|
-
return /* @__PURE__ */
|
|
618
|
+
return /* @__PURE__ */ jsx16(DocScreenshot, { entry });
|
|
441
619
|
case "video":
|
|
442
|
-
return /* @__PURE__ */
|
|
620
|
+
return /* @__PURE__ */ jsx16(DocVideo, { entry });
|
|
443
621
|
case "html":
|
|
444
|
-
return /* @__PURE__ */
|
|
622
|
+
return /* @__PURE__ */ jsx16(DocHtml, { entry });
|
|
445
623
|
case "state":
|
|
446
|
-
return /* @__PURE__ */
|
|
624
|
+
return /* @__PURE__ */ jsx16(DocState, { entry });
|
|
447
625
|
case "custom":
|
|
448
|
-
return /* @__PURE__ */
|
|
626
|
+
return /* @__PURE__ */ jsx16(DocCustom, { entry });
|
|
449
627
|
}
|
|
450
628
|
}
|
|
451
629
|
|
|
452
630
|
// src/components/ReportDocEntries.tsx
|
|
453
|
-
import { Fragment as Fragment5, jsx as
|
|
631
|
+
import { Fragment as Fragment5, jsx as jsx17 } from "react/jsx-runtime";
|
|
454
632
|
function ReportDocEntries({ entries }) {
|
|
455
633
|
if (entries.length === 0) return null;
|
|
456
|
-
return /* @__PURE__ */
|
|
634
|
+
return /* @__PURE__ */ jsx17(Fragment5, { children: entries.map((entry, i) => /* @__PURE__ */ jsx17(DocEntry, { entry }, i)) });
|
|
457
635
|
}
|
|
458
636
|
|
|
459
637
|
// src/lib/step-params.tsx
|
|
460
|
-
import { jsx as
|
|
638
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
461
639
|
var STEP_PARAM_PATTERN = /"[^"]*"|(?<![\w.-])\d+(?:\.\d+)?(?![\w.-])/g;
|
|
462
640
|
function highlightStepParams(text) {
|
|
463
641
|
const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));
|
|
@@ -469,7 +647,7 @@ function highlightStepParams(text) {
|
|
|
469
647
|
const end = start + match[0].length;
|
|
470
648
|
if (start > lastIndex) nodes.push(text.slice(lastIndex, start));
|
|
471
649
|
nodes.push(
|
|
472
|
-
/* @__PURE__ */
|
|
650
|
+
/* @__PURE__ */ jsx18("span", { className: "font-medium text-step-param italic", children: match[0] }, i)
|
|
473
651
|
);
|
|
474
652
|
lastIndex = end;
|
|
475
653
|
});
|
|
@@ -478,7 +656,7 @@ function highlightStepParams(text) {
|
|
|
478
656
|
}
|
|
479
657
|
|
|
480
658
|
// src/components/ReportSteps.tsx
|
|
481
|
-
import { jsx as
|
|
659
|
+
import { jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
482
660
|
var STEP_GLYPH = {
|
|
483
661
|
passed: "\u2713",
|
|
484
662
|
failed: "\u2717",
|
|
@@ -493,21 +671,21 @@ var STEP_GLYPH_COLOR = {
|
|
|
493
671
|
};
|
|
494
672
|
function ReportSteps({ scenario }) {
|
|
495
673
|
if (scenario.steps.length === 0) return null;
|
|
496
|
-
return /* @__PURE__ */
|
|
674
|
+
return /* @__PURE__ */ jsx19("ol", { "data-slot": "steps", className: "flex flex-col", children: scenario.steps.map((step) => /* @__PURE__ */ jsx19(ReportStepItem, { step }, step.id)) });
|
|
497
675
|
}
|
|
498
676
|
function ReportStepItem({ step }) {
|
|
499
677
|
const kw = step.keyword.toLowerCase();
|
|
500
678
|
const continuation = kw === "and" || kw === "but";
|
|
501
|
-
return /* @__PURE__ */
|
|
679
|
+
return /* @__PURE__ */ jsxs11(
|
|
502
680
|
"li",
|
|
503
681
|
{
|
|
504
682
|
id: step.id,
|
|
505
683
|
"data-status": step.status,
|
|
506
684
|
className: cn("py-1.5 text-[0.8125rem] leading-normal", continuation && "pl-5"),
|
|
507
685
|
children: [
|
|
508
|
-
/* @__PURE__ */
|
|
509
|
-
/* @__PURE__ */
|
|
510
|
-
/* @__PURE__ */
|
|
686
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex items-baseline gap-2", children: [
|
|
687
|
+
/* @__PURE__ */ jsx19("span", { "aria-hidden": true, className: cn("w-4 shrink-0 text-center text-xs", STEP_GLYPH_COLOR[step.status]), children: STEP_GLYPH[step.status] ?? "\u25CB" }),
|
|
688
|
+
/* @__PURE__ */ jsx19(
|
|
511
689
|
"span",
|
|
512
690
|
{
|
|
513
691
|
className: cn(
|
|
@@ -517,10 +695,10 @@ function ReportStepItem({ step }) {
|
|
|
517
695
|
children: step.keyword
|
|
518
696
|
}
|
|
519
697
|
),
|
|
520
|
-
/* @__PURE__ */
|
|
521
|
-
step.durationMs > 0 ? /* @__PURE__ */
|
|
698
|
+
/* @__PURE__ */ jsx19("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
|
|
699
|
+
step.durationMs > 0 ? /* @__PURE__ */ jsx19("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(step.durationMs) }) : null
|
|
522
700
|
] }),
|
|
523
|
-
step.errorMessage ? /* @__PURE__ */
|
|
701
|
+
step.errorMessage ? /* @__PURE__ */ jsx19(
|
|
524
702
|
"pre",
|
|
525
703
|
{
|
|
526
704
|
role: "alert",
|
|
@@ -528,7 +706,7 @@ function ReportStepItem({ step }) {
|
|
|
528
706
|
children: step.errorMessage
|
|
529
707
|
}
|
|
530
708
|
) : null,
|
|
531
|
-
step.docEntries.length > 0 ? /* @__PURE__ */
|
|
709
|
+
step.docEntries.length > 0 ? /* @__PURE__ */ jsx19("div", { "data-es-docs": true, className: "mt-2 ml-6", children: /* @__PURE__ */ jsx19(ReportDocEntries, { entries: step.docEntries }) }) : null
|
|
532
710
|
]
|
|
533
711
|
}
|
|
534
712
|
);
|
|
@@ -653,7 +831,7 @@ function extractStoryboardFrames(scenario) {
|
|
|
653
831
|
}
|
|
654
832
|
|
|
655
833
|
// src/components/ReportStoryboard.tsx
|
|
656
|
-
import { jsx as
|
|
834
|
+
import { jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
657
835
|
var FRAME_GLYPH = {
|
|
658
836
|
passed: "\u2713",
|
|
659
837
|
failed: "\u2717",
|
|
@@ -669,32 +847,32 @@ var FRAME_GLYPH_COLOR = {
|
|
|
669
847
|
function ReportStoryboard({ scenario }) {
|
|
670
848
|
const frames = extractStoryboardFrames(scenario);
|
|
671
849
|
if (frames.length < 2) return null;
|
|
672
|
-
return /* @__PURE__ */
|
|
673
|
-
/* @__PURE__ */
|
|
674
|
-
/* @__PURE__ */
|
|
850
|
+
return /* @__PURE__ */ jsxs12("section", { "data-slot": "storyboard", "aria-label": "Storyboard", className: "mb-3", children: [
|
|
851
|
+
/* @__PURE__ */ jsx20("h4", { className: "mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Storyboard" }),
|
|
852
|
+
/* @__PURE__ */ jsx20("ol", { className: "flex items-start gap-3 overflow-x-auto pb-2", children: frames.map((frame) => /* @__PURE__ */ jsx20(StoryboardFrameItem, { frame }, frame.stepId)) })
|
|
675
853
|
] });
|
|
676
854
|
}
|
|
677
855
|
function StoryboardFrameItem({ frame }) {
|
|
678
856
|
const label = `${frame.keyword} ${frame.text}`;
|
|
679
857
|
const hasStates = frame.states.length > 0;
|
|
680
|
-
const caption = /* @__PURE__ */
|
|
681
|
-
/* @__PURE__ */
|
|
682
|
-
/* @__PURE__ */
|
|
683
|
-
/* @__PURE__ */
|
|
858
|
+
const caption = /* @__PURE__ */ jsxs12("p", { className: "mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug", children: [
|
|
859
|
+
/* @__PURE__ */ jsx20("span", { "aria-hidden": true, className: cn("shrink-0", FRAME_GLYPH_COLOR[frame.status]), children: FRAME_GLYPH[frame.status] ?? "\u25CB" }),
|
|
860
|
+
/* @__PURE__ */ jsxs12("span", { className: "min-w-0", children: [
|
|
861
|
+
/* @__PURE__ */ jsx20("span", { className: "font-mono font-semibold text-keyword", children: frame.keyword }),
|
|
684
862
|
" ",
|
|
685
|
-
/* @__PURE__ */
|
|
863
|
+
/* @__PURE__ */ jsx20("span", { className: "text-muted-foreground", children: frame.screenshot?.alt ?? frame.text })
|
|
686
864
|
] })
|
|
687
865
|
] });
|
|
688
866
|
return (
|
|
689
867
|
// State cards need room for diff rows; screenshot-only frames keep the
|
|
690
868
|
// original narrow film-cell width (and DOM) unchanged.
|
|
691
|
-
/* @__PURE__ */
|
|
692
|
-
frame.screenshot ? /* @__PURE__ */
|
|
693
|
-
hasStates ? /* @__PURE__ */
|
|
869
|
+
/* @__PURE__ */ jsxs12("li", { className: cn("shrink-0", hasStates ? "w-64" : "w-40"), children: [
|
|
870
|
+
frame.screenshot ? /* @__PURE__ */ jsx20(FrameScreenshot, { frame, label }) : null,
|
|
871
|
+
hasStates ? /* @__PURE__ */ jsx20("div", { className: cn("flex flex-col gap-1.5", frame.screenshot && "mt-1.5"), children: frame.states.map((card, i) => /* @__PURE__ */ jsx20(StateCardView, { card }, card.label ?? i)) }) : null,
|
|
694
872
|
frame.screenshot ? caption : (
|
|
695
873
|
// No screenshot means no image anchor, so the caption carries the
|
|
696
874
|
// jump-to-step link instead.
|
|
697
|
-
/* @__PURE__ */
|
|
875
|
+
/* @__PURE__ */ jsx20("a", { href: `#${frame.stepId}`, "aria-label": `Jump to step: ${label}`, className: "block hover:underline", children: caption })
|
|
698
876
|
)
|
|
699
877
|
] })
|
|
700
878
|
);
|
|
@@ -702,13 +880,13 @@ function StoryboardFrameItem({ frame }) {
|
|
|
702
880
|
function FrameScreenshot({ frame, label }) {
|
|
703
881
|
const path = frame.screenshot?.path ?? "";
|
|
704
882
|
const src = isLocalFsPath(path) ? void 0 : safeImageUrl(path);
|
|
705
|
-
return /* @__PURE__ */
|
|
883
|
+
return /* @__PURE__ */ jsx20(
|
|
706
884
|
"a",
|
|
707
885
|
{
|
|
708
886
|
href: `#${frame.stepId}`,
|
|
709
887
|
"aria-label": `Jump to step: ${label}`,
|
|
710
888
|
className: "block overflow-hidden rounded-md border border-border transition-colors hover:border-ring",
|
|
711
|
-
children: src ? /* @__PURE__ */
|
|
889
|
+
children: src ? /* @__PURE__ */ jsx20(
|
|
712
890
|
"img",
|
|
713
891
|
{
|
|
714
892
|
src,
|
|
@@ -716,7 +894,7 @@ function FrameScreenshot({ frame, label }) {
|
|
|
716
894
|
loading: "lazy",
|
|
717
895
|
className: "h-24 w-full bg-muted object-cover object-top"
|
|
718
896
|
}
|
|
719
|
-
) : /* @__PURE__ */
|
|
897
|
+
) : /* @__PURE__ */ jsx20("span", { className: "flex h-24 w-full items-center justify-center border-b border-dashed border-border bg-muted px-2 text-center text-[0.6875rem] text-muted-foreground", children: "Screenshot unavailable" })
|
|
720
898
|
}
|
|
721
899
|
);
|
|
722
900
|
}
|
|
@@ -735,12 +913,12 @@ function prettyJson(value) {
|
|
|
735
913
|
function StateCardView({ card }) {
|
|
736
914
|
const json = prettyJson(card.value);
|
|
737
915
|
const firstCapture = card.changes === void 0;
|
|
738
|
-
return /* @__PURE__ */
|
|
739
|
-
/* @__PURE__ */
|
|
740
|
-
/* @__PURE__ */
|
|
741
|
-
firstCapture ? /* @__PURE__ */
|
|
916
|
+
return /* @__PURE__ */ jsxs12("div", { "data-slot": "state-card", className: "rounded-md border border-border bg-card p-2", children: [
|
|
917
|
+
/* @__PURE__ */ jsxs12("p", { className: "flex flex-wrap items-baseline gap-1.5", children: [
|
|
918
|
+
/* @__PURE__ */ jsx20("span", { className: "inline-flex rounded-full border border-border px-1.5 font-mono text-[0.625rem] font-medium text-muted-foreground", children: card.label ?? "State" }),
|
|
919
|
+
firstCapture ? /* @__PURE__ */ jsx20("span", { className: "text-[0.625rem] text-muted-foreground italic", children: "first capture" }) : null
|
|
742
920
|
] }),
|
|
743
|
-
!firstCapture && (card.changes && card.changes.length > 0 ? /* @__PURE__ */
|
|
921
|
+
!firstCapture && (card.changes && card.changes.length > 0 ? /* @__PURE__ */ jsx20("ul", { className: "mt-1.5 flex flex-col gap-0.5", children: card.changes.map((change, i) => /* @__PURE__ */ jsx20(
|
|
744
922
|
"li",
|
|
745
923
|
{
|
|
746
924
|
className: cn(
|
|
@@ -750,15 +928,15 @@ function StateCardView({ card }) {
|
|
|
750
928
|
children: summarizeStateChanges([change])[0]
|
|
751
929
|
},
|
|
752
930
|
i
|
|
753
|
-
)) }) : /* @__PURE__ */
|
|
754
|
-
/* @__PURE__ */
|
|
931
|
+
)) }) : /* @__PURE__ */ jsx20("p", { className: "mt-1.5 text-[0.625rem] text-muted-foreground", children: "No changes" })),
|
|
932
|
+
/* @__PURE__ */ jsxs12(
|
|
755
933
|
"details",
|
|
756
934
|
{
|
|
757
935
|
open: firstCapture && json.length <= 240,
|
|
758
936
|
className: cn(firstCapture ? "mt-1.5" : "mt-1"),
|
|
759
937
|
children: [
|
|
760
|
-
/* @__PURE__ */
|
|
761
|
-
/* @__PURE__ */
|
|
938
|
+
/* @__PURE__ */ jsx20("summary", { className: "cursor-pointer text-[0.625rem] text-muted-foreground hover:text-foreground", children: "Snapshot" }),
|
|
939
|
+
/* @__PURE__ */ jsx20("pre", { tabIndex: 0, className: "mt-1 max-h-48 overflow-auto rounded-sm bg-muted p-1.5 font-mono text-[0.625rem] leading-snug", children: json })
|
|
762
940
|
]
|
|
763
941
|
}
|
|
764
942
|
)
|
|
@@ -766,17 +944,17 @@ function StateCardView({ card }) {
|
|
|
766
944
|
}
|
|
767
945
|
|
|
768
946
|
// src/components/ReportAttachments.tsx
|
|
769
|
-
import { Fragment as Fragment6, jsx as
|
|
947
|
+
import { Fragment as Fragment6, jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
770
948
|
function ReportAttachments({ attachments }) {
|
|
771
949
|
if (attachments.length === 0) return null;
|
|
772
950
|
return (
|
|
773
951
|
// role="group" (not a labelled <section>) so multiple scenarios' attachment
|
|
774
952
|
// blocks don't create duplicate "Attachments" region landmarks.
|
|
775
|
-
/* @__PURE__ */
|
|
953
|
+
/* @__PURE__ */ jsx21("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
|
|
776
954
|
const dataUri = att.contentEncoding === "BASE64" ? `data:${att.mediaType};base64,${att.body}` : `data:${att.mediaType},${encodeURIComponent(att.body)}`;
|
|
777
955
|
const isImage = att.mediaType.startsWith("image/");
|
|
778
|
-
return /* @__PURE__ */
|
|
779
|
-
/* @__PURE__ */
|
|
956
|
+
return /* @__PURE__ */ jsx21("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ jsxs13(Fragment6, { children: [
|
|
957
|
+
/* @__PURE__ */ jsx21(
|
|
780
958
|
"img",
|
|
781
959
|
{
|
|
782
960
|
src: dataUri,
|
|
@@ -785,8 +963,8 @@ function ReportAttachments({ attachments }) {
|
|
|
785
963
|
className: "max-w-full rounded-md border border-border"
|
|
786
964
|
}
|
|
787
965
|
),
|
|
788
|
-
/* @__PURE__ */
|
|
789
|
-
] }) : /* @__PURE__ */
|
|
966
|
+
/* @__PURE__ */ jsx21("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
|
|
967
|
+
] }) : /* @__PURE__ */ jsxs13(
|
|
790
968
|
"a",
|
|
791
969
|
{
|
|
792
970
|
href: dataUri,
|
|
@@ -795,7 +973,7 @@ function ReportAttachments({ attachments }) {
|
|
|
795
973
|
children: [
|
|
796
974
|
att.name,
|
|
797
975
|
" ",
|
|
798
|
-
/* @__PURE__ */
|
|
976
|
+
/* @__PURE__ */ jsxs13("span", { className: "text-muted-foreground", children: [
|
|
799
977
|
"(",
|
|
800
978
|
att.mediaType,
|
|
801
979
|
")"
|
|
@@ -883,7 +1061,7 @@ function traceWindow(rows) {
|
|
|
883
1061
|
}
|
|
884
1062
|
|
|
885
1063
|
// src/components/ReportTrace.tsx
|
|
886
|
-
import { jsx as
|
|
1064
|
+
import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
887
1065
|
var BAR_COLOR = {
|
|
888
1066
|
ok: "bg-pass",
|
|
889
1067
|
error: "bg-fail",
|
|
@@ -894,8 +1072,8 @@ function ReportTrace({ spans }) {
|
|
|
894
1072
|
const rows = toTraceRows(spans);
|
|
895
1073
|
if (rows.length === 0) return null;
|
|
896
1074
|
const { minStartMs, totalMs } = traceWindow(rows);
|
|
897
|
-
return /* @__PURE__ */
|
|
898
|
-
/* @__PURE__ */
|
|
1075
|
+
return /* @__PURE__ */ jsxs14("details", { className: "mt-3 rounded-md border border-border bg-muted/30", children: [
|
|
1076
|
+
/* @__PURE__ */ jsxs14("summary", { className: "cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground", children: [
|
|
899
1077
|
"Trace (",
|
|
900
1078
|
rows.length,
|
|
901
1079
|
" span",
|
|
@@ -904,11 +1082,11 @@ function ReportTrace({ spans }) {
|
|
|
904
1082
|
formatDuration(totalMs),
|
|
905
1083
|
")"
|
|
906
1084
|
] }),
|
|
907
|
-
/* @__PURE__ */
|
|
1085
|
+
/* @__PURE__ */ jsx22("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
|
|
908
1086
|
const leftPct = (row.startTimeMs - minStartMs) / totalMs * 100;
|
|
909
1087
|
const widthPct = Math.max(row.durationMs / totalMs * 100, 0.5);
|
|
910
|
-
return /* @__PURE__ */
|
|
911
|
-
/* @__PURE__ */
|
|
1088
|
+
return /* @__PURE__ */ jsxs14("li", { className: "flex items-center gap-2", children: [
|
|
1089
|
+
/* @__PURE__ */ jsx22(
|
|
912
1090
|
"span",
|
|
913
1091
|
{
|
|
914
1092
|
className: "min-w-0 flex-1 truncate text-foreground",
|
|
@@ -917,14 +1095,14 @@ function ReportTrace({ spans }) {
|
|
|
917
1095
|
children: row.name
|
|
918
1096
|
}
|
|
919
1097
|
),
|
|
920
|
-
/* @__PURE__ */
|
|
1098
|
+
/* @__PURE__ */ jsx22("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ jsx22(
|
|
921
1099
|
"span",
|
|
922
1100
|
{
|
|
923
1101
|
className: cn("absolute top-0 h-full rounded-sm", BAR_COLOR[row.status]),
|
|
924
1102
|
style: { left: `${leftPct}%`, width: `${widthPct}%` }
|
|
925
1103
|
}
|
|
926
1104
|
) }),
|
|
927
|
-
/* @__PURE__ */
|
|
1105
|
+
/* @__PURE__ */ jsx22("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
|
|
928
1106
|
] }, `${row.spanId}-${i}`);
|
|
929
1107
|
}) })
|
|
930
1108
|
] });
|
|
@@ -973,11 +1151,11 @@ function flakinessOf(entries) {
|
|
|
973
1151
|
if (transitionScore > 0.2 || failureRate > 0.3) return "unstable";
|
|
974
1152
|
return "stable";
|
|
975
1153
|
}
|
|
976
|
-
function diffSinceLastRun(
|
|
1154
|
+
function diffSinceLastRun(history, scenarios) {
|
|
977
1155
|
let hasPreviousRun = false;
|
|
978
1156
|
const delta = { newlyFailing: [], newlyPassing: [], added: [] };
|
|
979
1157
|
for (const scenario of scenarios) {
|
|
980
|
-
const entries =
|
|
1158
|
+
const entries = history[scenario.id];
|
|
981
1159
|
if (!entries || entries.length === 0) continue;
|
|
982
1160
|
const last = entries[entries.length - 1];
|
|
983
1161
|
const prev = entries[entries.length - 2];
|
|
@@ -993,7 +1171,7 @@ function diffSinceLastRun(history2, scenarios) {
|
|
|
993
1171
|
}
|
|
994
1172
|
|
|
995
1173
|
// src/components/ScenarioRunHistory.tsx
|
|
996
|
-
import { Fragment as Fragment7, jsx as
|
|
1174
|
+
import { Fragment as Fragment7, jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
997
1175
|
var MAX_DOTS = 10;
|
|
998
1176
|
var DOT_COLOR = {
|
|
999
1177
|
passed: "bg-pass",
|
|
@@ -1007,22 +1185,22 @@ function dotTitle(e) {
|
|
|
1007
1185
|
return parts.join(" \xB7 ");
|
|
1008
1186
|
}
|
|
1009
1187
|
function ScenarioRunHistory({ scenarioId }) {
|
|
1010
|
-
const
|
|
1011
|
-
const entries =
|
|
1188
|
+
const history = useScenarioHistory();
|
|
1189
|
+
const entries = history?.[scenarioId];
|
|
1012
1190
|
if (!entries || entries.length < 2) return null;
|
|
1013
1191
|
const recent = entries.slice(-MAX_DOTS);
|
|
1014
1192
|
const flaky = flakinessOf(recent) === "flaky";
|
|
1015
1193
|
const summary = flaky ? `${describeRunHistory(recent)} \xB7 Flaky` : describeRunHistory(recent);
|
|
1016
|
-
return /* @__PURE__ */
|
|
1017
|
-
flaky ? /* @__PURE__ */
|
|
1018
|
-
/* @__PURE__ */
|
|
1194
|
+
return /* @__PURE__ */ jsxs15(Fragment7, { children: [
|
|
1195
|
+
flaky ? /* @__PURE__ */ jsx23(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
|
|
1196
|
+
/* @__PURE__ */ jsx23(
|
|
1019
1197
|
"span",
|
|
1020
1198
|
{
|
|
1021
1199
|
role: "img",
|
|
1022
1200
|
"aria-label": `Run history: ${summary}`,
|
|
1023
1201
|
title: summary,
|
|
1024
1202
|
className: "flex shrink-0 items-center gap-[3px]",
|
|
1025
|
-
children: recent.map((e, i) => /* @__PURE__ */
|
|
1203
|
+
children: recent.map((e, i) => /* @__PURE__ */ jsx23(
|
|
1026
1204
|
"span",
|
|
1027
1205
|
{
|
|
1028
1206
|
"aria-hidden": true,
|
|
@@ -1251,9 +1429,9 @@ function scenarioPermalink(scenario) {
|
|
|
1251
1429
|
|
|
1252
1430
|
// src/components/ui/card.tsx
|
|
1253
1431
|
import "react";
|
|
1254
|
-
import { jsx as
|
|
1432
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
1255
1433
|
function Card({ className, ...props }) {
|
|
1256
|
-
return /* @__PURE__ */
|
|
1434
|
+
return /* @__PURE__ */ jsx24(
|
|
1257
1435
|
"div",
|
|
1258
1436
|
{
|
|
1259
1437
|
"data-slot": "card",
|
|
@@ -1266,7 +1444,7 @@ function Card({ className, ...props }) {
|
|
|
1266
1444
|
);
|
|
1267
1445
|
}
|
|
1268
1446
|
function CardHeader({ className, ...props }) {
|
|
1269
|
-
return /* @__PURE__ */
|
|
1447
|
+
return /* @__PURE__ */ jsx24(
|
|
1270
1448
|
"div",
|
|
1271
1449
|
{
|
|
1272
1450
|
"data-slot": "card-header",
|
|
@@ -1279,7 +1457,7 @@ function CardHeader({ className, ...props }) {
|
|
|
1279
1457
|
);
|
|
1280
1458
|
}
|
|
1281
1459
|
function CardContent({ className, ...props }) {
|
|
1282
|
-
return /* @__PURE__ */
|
|
1460
|
+
return /* @__PURE__ */ jsx24(
|
|
1283
1461
|
"div",
|
|
1284
1462
|
{
|
|
1285
1463
|
"data-slot": "card-content",
|
|
@@ -1293,13 +1471,13 @@ function CardContent({ className, ...props }) {
|
|
|
1293
1471
|
import "react";
|
|
1294
1472
|
import { Menu as MenuPrimitive } from "@base-ui/react/menu";
|
|
1295
1473
|
import { CheckIcon } from "lucide-react";
|
|
1296
|
-
import { jsx as
|
|
1474
|
+
import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1297
1475
|
var itemClasses = "relative flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 [&_svg:not([class*='text-'])]:text-muted-foreground";
|
|
1298
1476
|
function DropdownMenu(props) {
|
|
1299
|
-
return /* @__PURE__ */
|
|
1477
|
+
return /* @__PURE__ */ jsx25(MenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
|
|
1300
1478
|
}
|
|
1301
1479
|
function DropdownMenuTrigger(props) {
|
|
1302
|
-
return /* @__PURE__ */
|
|
1480
|
+
return /* @__PURE__ */ jsx25(MenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
|
|
1303
1481
|
}
|
|
1304
1482
|
function DropdownMenuContent({
|
|
1305
1483
|
className,
|
|
@@ -1307,14 +1485,14 @@ function DropdownMenuContent({
|
|
|
1307
1485
|
sideOffset = 4,
|
|
1308
1486
|
...props
|
|
1309
1487
|
}) {
|
|
1310
|
-
return /* @__PURE__ */
|
|
1488
|
+
return /* @__PURE__ */ jsx25(MenuPrimitive.Portal, { children: /* @__PURE__ */ jsx25(
|
|
1311
1489
|
MenuPrimitive.Positioner,
|
|
1312
1490
|
{
|
|
1313
1491
|
"data-slot": "dropdown-menu-positioner",
|
|
1314
1492
|
className: "z-50",
|
|
1315
1493
|
align,
|
|
1316
1494
|
sideOffset,
|
|
1317
|
-
children: /* @__PURE__ */
|
|
1495
|
+
children: /* @__PURE__ */ jsx25(
|
|
1318
1496
|
MenuPrimitive.Popup,
|
|
1319
1497
|
{
|
|
1320
1498
|
"data-slot": "dropdown-menu-content",
|
|
@@ -1332,7 +1510,7 @@ function DropdownMenuItem({
|
|
|
1332
1510
|
className,
|
|
1333
1511
|
...props
|
|
1334
1512
|
}) {
|
|
1335
|
-
return /* @__PURE__ */
|
|
1513
|
+
return /* @__PURE__ */ jsx25(
|
|
1336
1514
|
MenuPrimitive.Item,
|
|
1337
1515
|
{
|
|
1338
1516
|
"data-slot": "dropdown-menu-item",
|
|
@@ -1344,7 +1522,7 @@ function DropdownMenuItem({
|
|
|
1344
1522
|
|
|
1345
1523
|
// src/components/ReportScenario.tsx
|
|
1346
1524
|
import { LinkIcon, FileTextIcon, SparklesIcon, MoreHorizontalIcon } from "lucide-react";
|
|
1347
|
-
import { jsx as
|
|
1525
|
+
import { jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1348
1526
|
var STATUS_META = {
|
|
1349
1527
|
passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
|
|
1350
1528
|
failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
|
|
@@ -1360,7 +1538,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1360
1538
|
const collapsible = collapse !== null && !hideTitle;
|
|
1361
1539
|
const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
|
|
1362
1540
|
const actions = useScenarioActions();
|
|
1363
|
-
return /* @__PURE__ */
|
|
1541
|
+
return /* @__PURE__ */ jsxs17(
|
|
1364
1542
|
Card,
|
|
1365
1543
|
{
|
|
1366
1544
|
id: scenario.id,
|
|
@@ -1368,10 +1546,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1368
1546
|
...hideTitle ? { "aria-label": `${scenario.title}, ${label}` } : { "aria-labelledby": titleId },
|
|
1369
1547
|
className: "gap-0 py-0",
|
|
1370
1548
|
children: [
|
|
1371
|
-
/* @__PURE__ */
|
|
1372
|
-
/* @__PURE__ */
|
|
1373
|
-
hideTitle ? null : /* @__PURE__ */
|
|
1374
|
-
collapsible ? /* @__PURE__ */
|
|
1549
|
+
/* @__PURE__ */ jsxs17(CardHeader, { className: "px-4 py-3", children: [
|
|
1550
|
+
/* @__PURE__ */ jsxs17("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
|
|
1551
|
+
hideTitle ? null : /* @__PURE__ */ jsxs17("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
|
|
1552
|
+
collapsible ? /* @__PURE__ */ jsx26(
|
|
1375
1553
|
"button",
|
|
1376
1554
|
{
|
|
1377
1555
|
type: "button",
|
|
@@ -1380,49 +1558,49 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1380
1558
|
"aria-controls": bodyId,
|
|
1381
1559
|
"aria-label": `Toggle ${scenario.title}`,
|
|
1382
1560
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
1383
|
-
children: /* @__PURE__ */
|
|
1561
|
+
children: /* @__PURE__ */ jsx26("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
1384
1562
|
}
|
|
1385
1563
|
) : null,
|
|
1386
|
-
/* @__PURE__ */
|
|
1387
|
-
/* @__PURE__ */
|
|
1564
|
+
/* @__PURE__ */ jsx26("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
|
|
1565
|
+
/* @__PURE__ */ jsx26("span", { children: scenario.title })
|
|
1388
1566
|
] }),
|
|
1389
|
-
/* @__PURE__ */
|
|
1390
|
-
/* @__PURE__ */
|
|
1391
|
-
scenario.durationMs > 0 ? /* @__PURE__ */
|
|
1392
|
-
meta.showPill ? /* @__PURE__ */
|
|
1393
|
-
actions ? /* @__PURE__ */
|
|
1394
|
-
/* @__PURE__ */
|
|
1567
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
1568
|
+
/* @__PURE__ */ jsx26(ScenarioRunHistory, { scenarioId: scenario.id }),
|
|
1569
|
+
scenario.durationMs > 0 ? /* @__PURE__ */ jsx26("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
|
|
1570
|
+
meta.showPill ? /* @__PURE__ */ jsx26(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ jsx26("span", { className: "sr-only", children: `Status: ${label}` }),
|
|
1571
|
+
actions ? /* @__PURE__ */ jsxs17(DropdownMenu, { children: [
|
|
1572
|
+
/* @__PURE__ */ jsx26(
|
|
1395
1573
|
DropdownMenuTrigger,
|
|
1396
1574
|
{
|
|
1397
1575
|
"aria-label": `Actions for ${scenario.title}`,
|
|
1398
1576
|
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
1399
|
-
children: /* @__PURE__ */
|
|
1577
|
+
children: /* @__PURE__ */ jsx26(MoreHorizontalIcon, { "aria-hidden": true })
|
|
1400
1578
|
}
|
|
1401
1579
|
),
|
|
1402
|
-
/* @__PURE__ */
|
|
1403
|
-
/* @__PURE__ */
|
|
1404
|
-
/* @__PURE__ */
|
|
1580
|
+
/* @__PURE__ */ jsxs17(DropdownMenuContent, { align: "end", children: [
|
|
1581
|
+
/* @__PURE__ */ jsxs17(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
|
|
1582
|
+
/* @__PURE__ */ jsx26(LinkIcon, {}),
|
|
1405
1583
|
" Copy link"
|
|
1406
1584
|
] }),
|
|
1407
|
-
/* @__PURE__ */
|
|
1408
|
-
/* @__PURE__ */
|
|
1585
|
+
/* @__PURE__ */ jsxs17(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
|
|
1586
|
+
/* @__PURE__ */ jsx26(FileTextIcon, {}),
|
|
1409
1587
|
" Copy as Markdown"
|
|
1410
1588
|
] }),
|
|
1411
|
-
/* @__PURE__ */
|
|
1412
|
-
/* @__PURE__ */
|
|
1589
|
+
/* @__PURE__ */ jsxs17(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
|
|
1590
|
+
/* @__PURE__ */ jsx26(SparklesIcon, {}),
|
|
1413
1591
|
" Explain with AI"
|
|
1414
1592
|
] })
|
|
1415
1593
|
] })
|
|
1416
1594
|
] }) : null
|
|
1417
1595
|
] })
|
|
1418
1596
|
] }),
|
|
1419
|
-
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */
|
|
1420
|
-
scenario.tags.map((t) => /* @__PURE__ */
|
|
1421
|
-
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */
|
|
1597
|
+
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs17("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
|
|
1598
|
+
scenario.tags.map((t) => /* @__PURE__ */ jsx26("li", { children: /* @__PURE__ */ jsx26(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
|
|
1599
|
+
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ jsx26("li", { children: ticket.url ? /* @__PURE__ */ jsx26("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ jsx26(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ jsx26(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
|
|
1422
1600
|
] }) : null
|
|
1423
1601
|
] }),
|
|
1424
|
-
/* @__PURE__ */
|
|
1425
|
-
scenario.errorMessage ? /* @__PURE__ */
|
|
1602
|
+
/* @__PURE__ */ jsxs17(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
|
|
1603
|
+
scenario.errorMessage ? /* @__PURE__ */ jsx26(
|
|
1426
1604
|
"pre",
|
|
1427
1605
|
{
|
|
1428
1606
|
role: "alert",
|
|
@@ -1430,11 +1608,11 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1430
1608
|
children: scenario.errorMessage
|
|
1431
1609
|
}
|
|
1432
1610
|
) : null,
|
|
1433
|
-
/* @__PURE__ */
|
|
1434
|
-
/* @__PURE__ */
|
|
1435
|
-
scenario.docEntries.length > 0 ? /* @__PURE__ */
|
|
1436
|
-
/* @__PURE__ */
|
|
1437
|
-
/* @__PURE__ */
|
|
1611
|
+
/* @__PURE__ */ jsx26(ReportStoryboard, { scenario }),
|
|
1612
|
+
/* @__PURE__ */ jsx26(ReportSteps, { scenario }),
|
|
1613
|
+
scenario.docEntries.length > 0 ? /* @__PURE__ */ jsx26("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ jsx26(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
|
|
1614
|
+
/* @__PURE__ */ jsx26(ReportAttachments, { attachments: scenario.attachments }),
|
|
1615
|
+
/* @__PURE__ */ jsx26(ReportTrace, { spans: scenario.otelSpans })
|
|
1438
1616
|
] })
|
|
1439
1617
|
]
|
|
1440
1618
|
}
|
|
@@ -1442,13 +1620,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1442
1620
|
}
|
|
1443
1621
|
|
|
1444
1622
|
// src/components/ReportScenarioList.tsx
|
|
1445
|
-
import { Fragment as Fragment8, jsx as
|
|
1623
|
+
import { Fragment as Fragment8, jsx as jsx27 } from "react/jsx-runtime";
|
|
1446
1624
|
function ReportScenarioList({ feature }) {
|
|
1447
|
-
return /* @__PURE__ */
|
|
1625
|
+
return /* @__PURE__ */ jsx27(Fragment8, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ jsx27(ReportScenario, { scenario }, scenario.id)) });
|
|
1448
1626
|
}
|
|
1449
1627
|
|
|
1450
1628
|
// src/components/ReportFeature.tsx
|
|
1451
|
-
import { Fragment as Fragment9, jsx as
|
|
1629
|
+
import { Fragment as Fragment9, jsx as jsx28, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1452
1630
|
function ReportFeature({ feature }) {
|
|
1453
1631
|
const titleId = `${feature.id}-title`;
|
|
1454
1632
|
const bodyId = `${feature.id}-body`;
|
|
@@ -1459,7 +1637,7 @@ function ReportFeature({ feature }) {
|
|
|
1459
1637
|
return (
|
|
1460
1638
|
// Suite = a section heading + a divider, NOT another bordered card. Drops a
|
|
1461
1639
|
// layer of nesting so the scenario cards below read as the primary unit.
|
|
1462
|
-
/* @__PURE__ */
|
|
1640
|
+
/* @__PURE__ */ jsxs18(
|
|
1463
1641
|
"section",
|
|
1464
1642
|
{
|
|
1465
1643
|
id: feature.id,
|
|
@@ -1467,9 +1645,9 @@ function ReportFeature({ feature }) {
|
|
|
1467
1645
|
"aria-labelledby": titleId,
|
|
1468
1646
|
className: "flex flex-col gap-3",
|
|
1469
1647
|
children: [
|
|
1470
|
-
/* @__PURE__ */
|
|
1471
|
-
/* @__PURE__ */
|
|
1472
|
-
/* @__PURE__ */
|
|
1648
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
|
|
1649
|
+
/* @__PURE__ */ jsxs18("div", { className: "min-w-0", children: [
|
|
1650
|
+
/* @__PURE__ */ jsx28("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ jsxs18(
|
|
1473
1651
|
"button",
|
|
1474
1652
|
{
|
|
1475
1653
|
type: "button",
|
|
@@ -1478,31 +1656,31 @@ function ReportFeature({ feature }) {
|
|
|
1478
1656
|
"aria-controls": bodyId,
|
|
1479
1657
|
className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
|
|
1480
1658
|
children: [
|
|
1481
|
-
/* @__PURE__ */
|
|
1482
|
-
/* @__PURE__ */
|
|
1659
|
+
/* @__PURE__ */ jsx28("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
|
|
1660
|
+
/* @__PURE__ */ jsx28("span", { className: "truncate", children: feature.title })
|
|
1483
1661
|
]
|
|
1484
1662
|
}
|
|
1485
1663
|
) : feature.title }),
|
|
1486
|
-
/* @__PURE__ */
|
|
1664
|
+
/* @__PURE__ */ jsx28("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
|
|
1487
1665
|
] }),
|
|
1488
|
-
/* @__PURE__ */
|
|
1666
|
+
/* @__PURE__ */ jsxs18(
|
|
1489
1667
|
"p",
|
|
1490
1668
|
{
|
|
1491
1669
|
className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
|
|
1492
1670
|
"aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
|
|
1493
1671
|
children: [
|
|
1494
|
-
/* @__PURE__ */
|
|
1672
|
+
/* @__PURE__ */ jsxs18("span", { children: [
|
|
1495
1673
|
s.passed,
|
|
1496
1674
|
" passed"
|
|
1497
1675
|
] }),
|
|
1498
|
-
/* @__PURE__ */
|
|
1499
|
-
/* @__PURE__ */
|
|
1676
|
+
/* @__PURE__ */ jsx28("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1677
|
+
/* @__PURE__ */ jsxs18("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
|
|
1500
1678
|
s.failed,
|
|
1501
1679
|
" failed"
|
|
1502
1680
|
] }),
|
|
1503
|
-
skipped > 0 ? /* @__PURE__ */
|
|
1504
|
-
/* @__PURE__ */
|
|
1505
|
-
/* @__PURE__ */
|
|
1681
|
+
skipped > 0 ? /* @__PURE__ */ jsxs18(Fragment9, { children: [
|
|
1682
|
+
/* @__PURE__ */ jsx28("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1683
|
+
/* @__PURE__ */ jsxs18("span", { children: [
|
|
1506
1684
|
skipped,
|
|
1507
1685
|
" skipped"
|
|
1508
1686
|
] })
|
|
@@ -1511,7 +1689,7 @@ function ReportFeature({ feature }) {
|
|
|
1511
1689
|
}
|
|
1512
1690
|
)
|
|
1513
1691
|
] }),
|
|
1514
|
-
/* @__PURE__ */
|
|
1692
|
+
/* @__PURE__ */ jsx28("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ jsx28(ReportScenarioList, { feature }) })
|
|
1515
1693
|
]
|
|
1516
1694
|
}
|
|
1517
1695
|
)
|
|
@@ -1519,17 +1697,17 @@ function ReportFeature({ feature }) {
|
|
|
1519
1697
|
}
|
|
1520
1698
|
|
|
1521
1699
|
// src/components/ReportFeatureList.tsx
|
|
1522
|
-
import { jsx as
|
|
1700
|
+
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
1523
1701
|
function ReportFeatureList() {
|
|
1524
1702
|
const report = useReport();
|
|
1525
|
-
return /* @__PURE__ */
|
|
1703
|
+
return /* @__PURE__ */ jsx29("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ jsx29(ReportFeature, { feature }, feature.id)) });
|
|
1526
1704
|
}
|
|
1527
1705
|
|
|
1528
1706
|
// src/components/ui/empty.tsx
|
|
1529
1707
|
import { cva as cva2 } from "class-variance-authority";
|
|
1530
|
-
import { jsx as
|
|
1708
|
+
import { jsx as jsx30 } from "react/jsx-runtime";
|
|
1531
1709
|
function Empty({ className, ...props }) {
|
|
1532
|
-
return /* @__PURE__ */
|
|
1710
|
+
return /* @__PURE__ */ jsx30(
|
|
1533
1711
|
"div",
|
|
1534
1712
|
{
|
|
1535
1713
|
"data-slot": "empty",
|
|
@@ -1542,7 +1720,7 @@ function Empty({ className, ...props }) {
|
|
|
1542
1720
|
);
|
|
1543
1721
|
}
|
|
1544
1722
|
function EmptyHeader({ className, ...props }) {
|
|
1545
|
-
return /* @__PURE__ */
|
|
1723
|
+
return /* @__PURE__ */ jsx30(
|
|
1546
1724
|
"div",
|
|
1547
1725
|
{
|
|
1548
1726
|
"data-slot": "empty-header",
|
|
@@ -1569,7 +1747,7 @@ var emptyMediaVariants = cva2(
|
|
|
1569
1747
|
}
|
|
1570
1748
|
);
|
|
1571
1749
|
function EmptyTitle({ className, ...props }) {
|
|
1572
|
-
return /* @__PURE__ */
|
|
1750
|
+
return /* @__PURE__ */ jsx30(
|
|
1573
1751
|
"div",
|
|
1574
1752
|
{
|
|
1575
1753
|
"data-slot": "empty-title",
|
|
@@ -1580,16 +1758,16 @@ function EmptyTitle({ className, ...props }) {
|
|
|
1580
1758
|
}
|
|
1581
1759
|
|
|
1582
1760
|
// src/components/ReportEmpty.tsx
|
|
1583
|
-
import { jsx as
|
|
1761
|
+
import { jsx as jsx31 } from "react/jsx-runtime";
|
|
1584
1762
|
function ReportEmpty({ message }) {
|
|
1585
|
-
return /* @__PURE__ */
|
|
1763
|
+
return /* @__PURE__ */ jsx31(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ jsx31(EmptyHeader, { children: /* @__PURE__ */ jsx31(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
|
|
1586
1764
|
}
|
|
1587
1765
|
|
|
1588
1766
|
// src/components/ReportSummary.tsx
|
|
1589
|
-
import { jsx as
|
|
1767
|
+
import { jsx as jsx32, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1590
1768
|
function ReportSummary({ className }) {
|
|
1591
1769
|
const report = useReport();
|
|
1592
|
-
return /* @__PURE__ */
|
|
1770
|
+
return /* @__PURE__ */ jsx32(
|
|
1593
1771
|
ReportSummaryView,
|
|
1594
1772
|
{
|
|
1595
1773
|
summary: report.summary,
|
|
@@ -1615,7 +1793,7 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1615
1793
|
if (summary.pending > 0) {
|
|
1616
1794
|
cards.push({ status: "pending", label: "Pending", value: summary.pending });
|
|
1617
1795
|
}
|
|
1618
|
-
return /* @__PURE__ */
|
|
1796
|
+
return /* @__PURE__ */ jsx32(
|
|
1619
1797
|
"dl",
|
|
1620
1798
|
{
|
|
1621
1799
|
className: cn(
|
|
@@ -1628,17 +1806,17 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1628
1806
|
"aria-label": ariaLabel,
|
|
1629
1807
|
children: cards.map((c) => {
|
|
1630
1808
|
const tone = TONE[c.status];
|
|
1631
|
-
return /* @__PURE__ */
|
|
1809
|
+
return /* @__PURE__ */ jsxs19(
|
|
1632
1810
|
"div",
|
|
1633
1811
|
{
|
|
1634
1812
|
"data-status": c.status,
|
|
1635
1813
|
className: "rounded-lg border bg-card px-4 py-3",
|
|
1636
1814
|
children: [
|
|
1637
|
-
/* @__PURE__ */
|
|
1638
|
-
/* @__PURE__ */
|
|
1815
|
+
/* @__PURE__ */ jsxs19("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
|
|
1816
|
+
/* @__PURE__ */ jsx32("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
|
|
1639
1817
|
c.label
|
|
1640
1818
|
] }),
|
|
1641
|
-
/* @__PURE__ */
|
|
1819
|
+
/* @__PURE__ */ jsx32("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
|
|
1642
1820
|
]
|
|
1643
1821
|
},
|
|
1644
1822
|
c.status
|
|
@@ -1698,7 +1876,7 @@ function prUrl(ci) {
|
|
|
1698
1876
|
}
|
|
1699
1877
|
|
|
1700
1878
|
// src/components/ReportMeta.tsx
|
|
1701
|
-
import { jsx as
|
|
1879
|
+
import { jsx as jsx33, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1702
1880
|
function ReportMeta() {
|
|
1703
1881
|
const report = useReport();
|
|
1704
1882
|
const items = [];
|
|
@@ -1721,13 +1899,13 @@ function ReportMeta() {
|
|
|
1721
1899
|
const short = sha.slice(0, 8);
|
|
1722
1900
|
items.push({
|
|
1723
1901
|
label: "Commit",
|
|
1724
|
-
value: url ? /* @__PURE__ */
|
|
1902
|
+
value: url ? /* @__PURE__ */ jsx33("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
|
|
1725
1903
|
});
|
|
1726
1904
|
}
|
|
1727
1905
|
if (report.ci) {
|
|
1728
1906
|
items.push({
|
|
1729
1907
|
label: "CI",
|
|
1730
|
-
value: report.ci.url ? /* @__PURE__ */
|
|
1908
|
+
value: report.ci.url ? /* @__PURE__ */ jsxs20("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
|
|
1731
1909
|
ciDisplayName(report.ci.name),
|
|
1732
1910
|
report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
|
|
1733
1911
|
] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
|
|
@@ -1738,7 +1916,7 @@ function ReportMeta() {
|
|
|
1738
1916
|
const label = `#${report.ci.prNumber}`;
|
|
1739
1917
|
items.push({
|
|
1740
1918
|
label: "PR",
|
|
1741
|
-
value: url ? /* @__PURE__ */
|
|
1919
|
+
value: url ? /* @__PURE__ */ jsx33("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
|
|
1742
1920
|
});
|
|
1743
1921
|
}
|
|
1744
1922
|
if (items.length === 0) return null;
|
|
@@ -1746,50 +1924,50 @@ function ReportMeta() {
|
|
|
1746
1924
|
// Run metadata is useful but secondary to "what failed" — tuck it into a
|
|
1747
1925
|
// collapsed disclosure so it doesn't push the result down. Native <details>
|
|
1748
1926
|
// so it works with no JS (the SSR/no-hydration report still toggles).
|
|
1749
|
-
/* @__PURE__ */
|
|
1750
|
-
/* @__PURE__ */
|
|
1751
|
-
/* @__PURE__ */
|
|
1927
|
+
/* @__PURE__ */ jsxs20("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
|
|
1928
|
+
/* @__PURE__ */ jsxs20("summary", { className: "flex cursor-pointer list-none select-none items-center gap-1.5 px-4 py-2 font-medium text-muted-foreground [&::-webkit-details-marker]:hidden", children: [
|
|
1929
|
+
/* @__PURE__ */ jsx33("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
|
|
1752
1930
|
"Run details"
|
|
1753
1931
|
] }),
|
|
1754
|
-
/* @__PURE__ */
|
|
1755
|
-
/* @__PURE__ */
|
|
1756
|
-
/* @__PURE__ */
|
|
1932
|
+
/* @__PURE__ */ jsx33("dl", { className: "flex flex-wrap gap-x-5 gap-y-2 border-t border-border px-4 py-3 text-muted-foreground", "aria-label": "Run metadata", children: items.map((item) => /* @__PURE__ */ jsxs20("div", { className: "flex items-baseline gap-1.5", children: [
|
|
1933
|
+
/* @__PURE__ */ jsx33("dt", { className: "font-medium", children: item.label }),
|
|
1934
|
+
/* @__PURE__ */ jsx33("dd", { className: "font-mono text-foreground", children: item.value })
|
|
1757
1935
|
] }, item.label)) })
|
|
1758
1936
|
] })
|
|
1759
1937
|
);
|
|
1760
1938
|
}
|
|
1761
1939
|
|
|
1762
1940
|
// src/components/ReportSchemaError.tsx
|
|
1763
|
-
import { jsx as
|
|
1941
|
+
import { jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1764
1942
|
function ReportSchemaError({ error }) {
|
|
1765
|
-
return /* @__PURE__ */
|
|
1766
|
-
/* @__PURE__ */
|
|
1767
|
-
/* @__PURE__ */
|
|
1768
|
-
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */
|
|
1943
|
+
return /* @__PURE__ */ jsxs21("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
|
|
1944
|
+
/* @__PURE__ */ jsx34("p", { children: /* @__PURE__ */ jsx34("strong", { children: "Report could not be displayed." }) }),
|
|
1945
|
+
/* @__PURE__ */ jsx34("p", { children: error.message }),
|
|
1946
|
+
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ jsxs21("p", { children: [
|
|
1769
1947
|
"The report bundle is newer than this version of ",
|
|
1770
|
-
/* @__PURE__ */
|
|
1948
|
+
/* @__PURE__ */ jsx34("code", { children: "executable-stories-react" }),
|
|
1771
1949
|
". Upgrade the package, or regenerate the report with an older formatters CLI."
|
|
1772
1950
|
] }) : null,
|
|
1773
|
-
error.issues && error.issues.length > 0 ? /* @__PURE__ */
|
|
1774
|
-
/* @__PURE__ */
|
|
1951
|
+
error.issues && error.issues.length > 0 ? /* @__PURE__ */ jsxs21("details", { children: [
|
|
1952
|
+
/* @__PURE__ */ jsxs21("summary", { children: [
|
|
1775
1953
|
error.issues.length,
|
|
1776
1954
|
" validation issue",
|
|
1777
1955
|
error.issues.length === 1 ? "" : "s"
|
|
1778
1956
|
] }),
|
|
1779
|
-
/* @__PURE__ */
|
|
1957
|
+
/* @__PURE__ */ jsx34("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
|
|
1780
1958
|
] }) : null
|
|
1781
1959
|
] });
|
|
1782
1960
|
}
|
|
1783
1961
|
|
|
1784
1962
|
// src/components/ReportShell.tsx
|
|
1785
|
-
import { Fragment as Fragment10, jsx as
|
|
1963
|
+
import { Fragment as Fragment10, jsx as jsx35, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1786
1964
|
function ReportErrorShell({
|
|
1787
1965
|
error,
|
|
1788
1966
|
className,
|
|
1789
1967
|
title,
|
|
1790
1968
|
dataTheme
|
|
1791
1969
|
}) {
|
|
1792
|
-
return /* @__PURE__ */
|
|
1970
|
+
return /* @__PURE__ */ jsx35("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ jsx35(ReportSchemaError, { error }) });
|
|
1793
1971
|
}
|
|
1794
1972
|
|
|
1795
1973
|
// src/interactive/ReportInteractive.tsx
|
|
@@ -1798,12 +1976,12 @@ import { Monitor, Moon, Sun } from "lucide-react";
|
|
|
1798
1976
|
// src/components/ui/switch.tsx
|
|
1799
1977
|
import "react";
|
|
1800
1978
|
import { Switch as SwitchPrimitive } from "@base-ui/react/switch";
|
|
1801
|
-
import { jsx as
|
|
1979
|
+
import { jsx as jsx36 } from "react/jsx-runtime";
|
|
1802
1980
|
function Switch({
|
|
1803
1981
|
className,
|
|
1804
1982
|
...props
|
|
1805
1983
|
}) {
|
|
1806
|
-
return /* @__PURE__ */
|
|
1984
|
+
return /* @__PURE__ */ jsx36(
|
|
1807
1985
|
SwitchPrimitive.Root,
|
|
1808
1986
|
{
|
|
1809
1987
|
"data-slot": "switch",
|
|
@@ -1812,7 +1990,7 @@ function Switch({
|
|
|
1812
1990
|
className
|
|
1813
1991
|
),
|
|
1814
1992
|
...props,
|
|
1815
|
-
children: /* @__PURE__ */
|
|
1993
|
+
children: /* @__PURE__ */ jsx36(
|
|
1816
1994
|
SwitchPrimitive.Thumb,
|
|
1817
1995
|
{
|
|
1818
1996
|
"data-slot": "switch-thumb",
|
|
@@ -1828,7 +2006,7 @@ import * as React5 from "react";
|
|
|
1828
2006
|
import { ToggleGroup as ToggleGroupPrimitive } from "@base-ui/react/toggle-group";
|
|
1829
2007
|
import { Toggle as TogglePrimitive } from "@base-ui/react/toggle";
|
|
1830
2008
|
import { cva as cva3 } from "class-variance-authority";
|
|
1831
|
-
import { jsx as
|
|
2009
|
+
import { jsx as jsx37 } from "react/jsx-runtime";
|
|
1832
2010
|
var toggleItemVariants = cva3(
|
|
1833
2011
|
"inline-flex items-center justify-center gap-1.5 rounded-md font-medium whitespace-nowrap text-muted-foreground transition-[color,background-color,box-shadow] outline-none hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 data-[pressed]:bg-background data-[pressed]:text-foreground data-[pressed]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
1834
2012
|
{
|
|
@@ -1850,13 +2028,13 @@ function ToggleGroup({
|
|
|
1850
2028
|
children,
|
|
1851
2029
|
...props
|
|
1852
2030
|
}) {
|
|
1853
|
-
return /* @__PURE__ */
|
|
2031
|
+
return /* @__PURE__ */ jsx37(
|
|
1854
2032
|
ToggleGroupPrimitive,
|
|
1855
2033
|
{
|
|
1856
2034
|
"data-slot": "toggle-group",
|
|
1857
2035
|
className: cn("flex w-fit items-center gap-0.5 rounded-lg bg-muted p-0.5", className),
|
|
1858
2036
|
...props,
|
|
1859
|
-
children: /* @__PURE__ */
|
|
2037
|
+
children: /* @__PURE__ */ jsx37(ToggleGroupContext.Provider, { value: { size }, children })
|
|
1860
2038
|
}
|
|
1861
2039
|
);
|
|
1862
2040
|
}
|
|
@@ -1867,7 +2045,7 @@ function ToggleGroupItem({
|
|
|
1867
2045
|
...props
|
|
1868
2046
|
}) {
|
|
1869
2047
|
const context = React5.useContext(ToggleGroupContext);
|
|
1870
|
-
return /* @__PURE__ */
|
|
2048
|
+
return /* @__PURE__ */ jsx37(
|
|
1871
2049
|
TogglePrimitive,
|
|
1872
2050
|
{
|
|
1873
2051
|
"data-slot": "toggle-group-item",
|
|
@@ -1887,9 +2065,9 @@ import { Search } from "lucide-react";
|
|
|
1887
2065
|
|
|
1888
2066
|
// src/components/ui/input.tsx
|
|
1889
2067
|
import "react";
|
|
1890
|
-
import { jsx as
|
|
2068
|
+
import { jsx as jsx38 } from "react/jsx-runtime";
|
|
1891
2069
|
function Input({ className, type, ...props }) {
|
|
1892
|
-
return /* @__PURE__ */
|
|
2070
|
+
return /* @__PURE__ */ jsx38(
|
|
1893
2071
|
"input",
|
|
1894
2072
|
{
|
|
1895
2073
|
type,
|
|
@@ -1906,7 +2084,7 @@ function Input({ className, type, ...props }) {
|
|
|
1906
2084
|
}
|
|
1907
2085
|
|
|
1908
2086
|
// src/interactive/ReportSearch.tsx
|
|
1909
|
-
import { jsx as
|
|
2087
|
+
import { jsx as jsx39, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1910
2088
|
var ReportSearch = forwardRef(
|
|
1911
2089
|
function ReportSearch2(props, ref) {
|
|
1912
2090
|
const {
|
|
@@ -1928,17 +2106,17 @@ var ReportSearch = forwardRef(
|
|
|
1928
2106
|
e.preventDefault();
|
|
1929
2107
|
}
|
|
1930
2108
|
}
|
|
1931
|
-
return /* @__PURE__ */
|
|
1932
|
-
/* @__PURE__ */
|
|
1933
|
-
/* @__PURE__ */
|
|
1934
|
-
/* @__PURE__ */
|
|
2109
|
+
return /* @__PURE__ */ jsxs23("div", { className: cn("es-search flex flex-col gap-1", className), children: [
|
|
2110
|
+
/* @__PURE__ */ jsx39("label", { htmlFor: inputId, className: "sr-only", children: "Search" }),
|
|
2111
|
+
/* @__PURE__ */ jsxs23("div", { className: "relative w-full sm:w-72", children: [
|
|
2112
|
+
/* @__PURE__ */ jsx39(
|
|
1935
2113
|
Search,
|
|
1936
2114
|
{
|
|
1937
2115
|
"aria-hidden": true,
|
|
1938
2116
|
className: "pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground"
|
|
1939
2117
|
}
|
|
1940
2118
|
),
|
|
1941
|
-
/* @__PURE__ */
|
|
2119
|
+
/* @__PURE__ */ jsx39(
|
|
1942
2120
|
Input,
|
|
1943
2121
|
{
|
|
1944
2122
|
ref,
|
|
@@ -1955,7 +2133,7 @@ var ReportSearch = forwardRef(
|
|
|
1955
2133
|
}
|
|
1956
2134
|
)
|
|
1957
2135
|
] }),
|
|
1958
|
-
showCounts ? /* @__PURE__ */
|
|
2136
|
+
showCounts ? /* @__PURE__ */ jsxs23(
|
|
1959
2137
|
"span",
|
|
1960
2138
|
{
|
|
1961
2139
|
className: "text-xs tabular-nums text-muted-foreground",
|
|
@@ -1975,6 +2153,54 @@ var ReportSearch = forwardRef(
|
|
|
1975
2153
|
// src/interactive/ReportFailureBanner.tsx
|
|
1976
2154
|
import { useCallback as useCallback2 } from "react";
|
|
1977
2155
|
|
|
2156
|
+
// src/lib/hash-state.ts
|
|
2157
|
+
var DEFAULT_URL_STATE = {
|
|
2158
|
+
query: "",
|
|
2159
|
+
status: "all",
|
|
2160
|
+
tags: [],
|
|
2161
|
+
detail: "full"
|
|
2162
|
+
};
|
|
2163
|
+
var STATUSES = ["all", "passed", "failed", "skipped", "pending"];
|
|
2164
|
+
function splitHash(hash) {
|
|
2165
|
+
const raw = hash.replace(/^#/, "");
|
|
2166
|
+
const split = raw.indexOf("?");
|
|
2167
|
+
if (split === -1) return { anchor: raw, params: new URLSearchParams() };
|
|
2168
|
+
return { anchor: raw.slice(0, split), params: new URLSearchParams(raw.slice(split + 1)) };
|
|
2169
|
+
}
|
|
2170
|
+
function decodeUrlState(params) {
|
|
2171
|
+
const status = params.get("status");
|
|
2172
|
+
const tags = params.get("tags");
|
|
2173
|
+
return {
|
|
2174
|
+
query: params.get("q") ?? DEFAULT_URL_STATE.query,
|
|
2175
|
+
status: STATUSES.includes(status) ? status : DEFAULT_URL_STATE.status,
|
|
2176
|
+
tags: tags ? tags.split(",").filter(Boolean) : [],
|
|
2177
|
+
detail: params.get("docs") === "0" ? "minimal" : "full"
|
|
2178
|
+
};
|
|
2179
|
+
}
|
|
2180
|
+
function encodeUrlState(state) {
|
|
2181
|
+
const params = new URLSearchParams();
|
|
2182
|
+
if (state.query) params.set("q", state.query);
|
|
2183
|
+
if (state.status !== "all") params.set("status", state.status);
|
|
2184
|
+
if (state.tags.length > 0) params.set("tags", state.tags.join(","));
|
|
2185
|
+
if (state.detail === "minimal") params.set("docs", "0");
|
|
2186
|
+
return params.toString();
|
|
2187
|
+
}
|
|
2188
|
+
function formatHash(anchor, params) {
|
|
2189
|
+
if (params) return `#${anchor}?${params}`;
|
|
2190
|
+
return anchor ? `#${anchor}` : "";
|
|
2191
|
+
}
|
|
2192
|
+
function writeHash(anchor, params) {
|
|
2193
|
+
if (typeof window === "undefined") return;
|
|
2194
|
+
const next = formatHash(anchor, params);
|
|
2195
|
+
if (next === window.location.hash) return;
|
|
2196
|
+
const url = next || window.location.href.split("#")[0];
|
|
2197
|
+
try {
|
|
2198
|
+
window.history.replaceState(window.history.state, "", url);
|
|
2199
|
+
} catch {
|
|
2200
|
+
window.location.hash = next.slice(1);
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2203
|
+
|
|
1978
2204
|
// src/lib/scroll.ts
|
|
1979
2205
|
function prefersReducedMotion() {
|
|
1980
2206
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
@@ -1990,13 +2216,13 @@ function scrollToScenarioId(scenarioId, options = {}) {
|
|
|
1990
2216
|
behavior: prefersReducedMotion() ? "auto" : "smooth",
|
|
1991
2217
|
block: "start"
|
|
1992
2218
|
});
|
|
1993
|
-
if (options.updateHash !== false
|
|
1994
|
-
|
|
2219
|
+
if (options.updateHash !== false) {
|
|
2220
|
+
writeHash(scenarioId, splitHash(window.location.hash).params.toString());
|
|
1995
2221
|
}
|
|
1996
2222
|
}
|
|
1997
2223
|
|
|
1998
2224
|
// src/interactive/ReportFailureBanner.tsx
|
|
1999
|
-
import { jsx as
|
|
2225
|
+
import { jsx as jsx40, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2000
2226
|
function ReportFailureBanner({ failures }) {
|
|
2001
2227
|
const first = failures[0];
|
|
2002
2228
|
const jumpToFirst = useCallback2(() => {
|
|
@@ -2004,7 +2230,7 @@ function ReportFailureBanner({ failures }) {
|
|
|
2004
2230
|
scrollToScenarioId(first.scenarioId);
|
|
2005
2231
|
}, [first]);
|
|
2006
2232
|
if (failures.length === 0) return null;
|
|
2007
|
-
return /* @__PURE__ */
|
|
2233
|
+
return /* @__PURE__ */ jsxs24(
|
|
2008
2234
|
"div",
|
|
2009
2235
|
{
|
|
2010
2236
|
className: "es-failure-banner",
|
|
@@ -2012,13 +2238,13 @@ function ReportFailureBanner({ failures }) {
|
|
|
2012
2238
|
"aria-live": "polite",
|
|
2013
2239
|
"aria-label": "Failure summary",
|
|
2014
2240
|
children: [
|
|
2015
|
-
/* @__PURE__ */
|
|
2016
|
-
/* @__PURE__ */
|
|
2241
|
+
/* @__PURE__ */ jsxs24("span", { className: "es-failure-banner-text", children: [
|
|
2242
|
+
/* @__PURE__ */ jsx40("strong", { children: failures.length }),
|
|
2017
2243
|
" ",
|
|
2018
2244
|
"failure",
|
|
2019
2245
|
failures.length === 1 ? "" : "s"
|
|
2020
2246
|
] }),
|
|
2021
|
-
/* @__PURE__ */
|
|
2247
|
+
/* @__PURE__ */ jsx40(
|
|
2022
2248
|
"button",
|
|
2023
2249
|
{
|
|
2024
2250
|
type: "button",
|
|
@@ -2035,7 +2261,7 @@ function ReportFailureBanner({ failures }) {
|
|
|
2035
2261
|
|
|
2036
2262
|
// src/interactive/ReportFreshness.tsx
|
|
2037
2263
|
import { useEffect, useState as useState2 } from "react";
|
|
2038
|
-
import { Fragment as Fragment11, jsx as
|
|
2264
|
+
import { Fragment as Fragment11, jsx as jsx41, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2039
2265
|
function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
2040
2266
|
const [now, setNow] = useState2(nowMs);
|
|
2041
2267
|
useEffect(() => {
|
|
@@ -2043,7 +2269,7 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
2043
2269
|
}, [nowMs]);
|
|
2044
2270
|
if (lastRunMs === void 0 || now === void 0) return null;
|
|
2045
2271
|
const age = formatRelativeAge(lastRunMs, now);
|
|
2046
|
-
const runLink = ciUrl ? /* @__PURE__ */
|
|
2272
|
+
const runLink = ciUrl ? /* @__PURE__ */ jsx41(
|
|
2047
2273
|
"a",
|
|
2048
2274
|
{
|
|
2049
2275
|
href: ciUrl,
|
|
@@ -2054,9 +2280,9 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
2054
2280
|
}
|
|
2055
2281
|
) : null;
|
|
2056
2282
|
if (isReportStale(lastRunMs, staleAfterDays, now)) {
|
|
2057
|
-
return /* @__PURE__ */
|
|
2058
|
-
/* @__PURE__ */
|
|
2059
|
-
/* @__PURE__ */
|
|
2283
|
+
return /* @__PURE__ */ jsxs25("div", { className: "es-stale-banner", role: "status", "aria-label": "Report freshness", children: [
|
|
2284
|
+
/* @__PURE__ */ jsxs25("span", { children: [
|
|
2285
|
+
/* @__PURE__ */ jsxs25("strong", { children: [
|
|
2060
2286
|
"Last verified ",
|
|
2061
2287
|
age,
|
|
2062
2288
|
"."
|
|
@@ -2066,10 +2292,10 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
2066
2292
|
runLink
|
|
2067
2293
|
] });
|
|
2068
2294
|
}
|
|
2069
|
-
return /* @__PURE__ */
|
|
2295
|
+
return /* @__PURE__ */ jsxs25("p", { className: "es-freshness", "aria-label": "Report freshness", children: [
|
|
2070
2296
|
"Verified ",
|
|
2071
2297
|
age,
|
|
2072
|
-
runLink ? /* @__PURE__ */
|
|
2298
|
+
runLink ? /* @__PURE__ */ jsxs25(Fragment11, { children: [
|
|
2073
2299
|
" \xB7 ",
|
|
2074
2300
|
runLink
|
|
2075
2301
|
] }) : null
|
|
@@ -2077,15 +2303,15 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
2077
2303
|
}
|
|
2078
2304
|
|
|
2079
2305
|
// src/interactive/ReportLastRunDelta.tsx
|
|
2080
|
-
import { Fragment as Fragment12, jsx as
|
|
2306
|
+
import { Fragment as Fragment12, jsx as jsx42, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2081
2307
|
var MAX_LINKS = 5;
|
|
2082
2308
|
function ScenarioLinks({ scenarios, tone }) {
|
|
2083
|
-
return /* @__PURE__ */
|
|
2084
|
-
scenarios.slice(0, MAX_LINKS).map((s, i) => /* @__PURE__ */
|
|
2309
|
+
return /* @__PURE__ */ jsxs26(Fragment12, { children: [
|
|
2310
|
+
scenarios.slice(0, MAX_LINKS).map((s, i) => /* @__PURE__ */ jsxs26("span", { children: [
|
|
2085
2311
|
i > 0 ? ", " : "",
|
|
2086
|
-
/* @__PURE__ */
|
|
2312
|
+
/* @__PURE__ */ jsx42("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
|
|
2087
2313
|
] }, s.id)),
|
|
2088
|
-
scenarios.length > MAX_LINKS ? /* @__PURE__ */
|
|
2314
|
+
scenarios.length > MAX_LINKS ? /* @__PURE__ */ jsxs26("span", { children: [
|
|
2089
2315
|
" and ",
|
|
2090
2316
|
scenarios.length - MAX_LINKS,
|
|
2091
2317
|
" more"
|
|
@@ -2093,32 +2319,32 @@ function ScenarioLinks({ scenarios, tone }) {
|
|
|
2093
2319
|
] });
|
|
2094
2320
|
}
|
|
2095
2321
|
function ReportLastRunDelta({
|
|
2096
|
-
history
|
|
2322
|
+
history,
|
|
2097
2323
|
report
|
|
2098
2324
|
}) {
|
|
2099
|
-
if (!
|
|
2325
|
+
if (!history) return null;
|
|
2100
2326
|
const scenarios = report.features.flatMap((f) => f.scenarios.map((s) => ({ id: s.id, title: s.title })));
|
|
2101
|
-
const delta = diffSinceLastRun(
|
|
2327
|
+
const delta = diffSinceLastRun(history, scenarios);
|
|
2102
2328
|
if (!delta) return null;
|
|
2103
2329
|
const { newlyFailing, newlyPassing, added } = delta;
|
|
2104
2330
|
if (newlyFailing.length === 0 && newlyPassing.length === 0 && added.length === 0) {
|
|
2105
|
-
return /* @__PURE__ */
|
|
2331
|
+
return /* @__PURE__ */ jsx42("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: "Since last run: no behavior changes." });
|
|
2106
2332
|
}
|
|
2107
|
-
return /* @__PURE__ */
|
|
2108
|
-
/* @__PURE__ */
|
|
2109
|
-
newlyFailing.length > 0 ? /* @__PURE__ */
|
|
2333
|
+
return /* @__PURE__ */ jsxs26("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: [
|
|
2334
|
+
/* @__PURE__ */ jsx42("span", { className: "font-medium text-foreground", children: "Since last run:" }),
|
|
2335
|
+
newlyFailing.length > 0 ? /* @__PURE__ */ jsxs26("span", { className: "ml-2 text-fail", children: [
|
|
2110
2336
|
newlyFailing.length,
|
|
2111
2337
|
" newly failing (",
|
|
2112
|
-
/* @__PURE__ */
|
|
2338
|
+
/* @__PURE__ */ jsx42(ScenarioLinks, { scenarios: newlyFailing, tone: "text-fail" }),
|
|
2113
2339
|
")"
|
|
2114
2340
|
] }) : null,
|
|
2115
|
-
newlyPassing.length > 0 ? /* @__PURE__ */
|
|
2341
|
+
newlyPassing.length > 0 ? /* @__PURE__ */ jsxs26("span", { className: "ml-2 text-pass", children: [
|
|
2116
2342
|
newlyPassing.length,
|
|
2117
2343
|
" fixed (",
|
|
2118
|
-
/* @__PURE__ */
|
|
2344
|
+
/* @__PURE__ */ jsx42(ScenarioLinks, { scenarios: newlyPassing, tone: "text-pass" }),
|
|
2119
2345
|
")"
|
|
2120
2346
|
] }) : null,
|
|
2121
|
-
added.length > 0 ? /* @__PURE__ */
|
|
2347
|
+
added.length > 0 ? /* @__PURE__ */ jsxs26("span", { className: "ml-2", children: [
|
|
2122
2348
|
added.length,
|
|
2123
2349
|
" new"
|
|
2124
2350
|
] }) : null
|
|
@@ -2182,7 +2408,7 @@ function Button({
|
|
|
2182
2408
|
}
|
|
2183
2409
|
|
|
2184
2410
|
// src/interactive/ReportShortcutsHelp.tsx
|
|
2185
|
-
import { jsx as
|
|
2411
|
+
import { jsx as jsx43, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2186
2412
|
var SHORTCUTS = [
|
|
2187
2413
|
{ keys: "/", description: "Focus search" },
|
|
2188
2414
|
{ keys: "f", description: "Jump to next failure" },
|
|
@@ -2194,9 +2420,9 @@ var SHORTCUTS = [
|
|
|
2194
2420
|
];
|
|
2195
2421
|
function Keys({ keys }) {
|
|
2196
2422
|
const parts = keys.split(" ");
|
|
2197
|
-
return /* @__PURE__ */
|
|
2198
|
-
i > 0 ? /* @__PURE__ */
|
|
2199
|
-
/* @__PURE__ */
|
|
2423
|
+
return /* @__PURE__ */ jsx43("span", { className: "inline-flex items-center gap-1", children: parts.map((k, i) => /* @__PURE__ */ jsxs27("span", { className: "inline-flex items-center gap-1", children: [
|
|
2424
|
+
i > 0 ? /* @__PURE__ */ jsx43("span", { className: "text-xs text-muted-foreground", children: "+" }) : null,
|
|
2425
|
+
/* @__PURE__ */ jsx43("kbd", { className: "inline-flex h-6 min-w-6 items-center justify-center rounded border border-border bg-muted px-1.5 font-mono text-xs font-medium text-muted-foreground", children: k })
|
|
2200
2426
|
] }, k)) });
|
|
2201
2427
|
}
|
|
2202
2428
|
function ReportShortcutsHelp({ open, onClose }) {
|
|
@@ -2207,7 +2433,7 @@ function ReportShortcutsHelp({ open, onClose }) {
|
|
|
2207
2433
|
if (open && !dialog.open) dialog.showModal();
|
|
2208
2434
|
else if (!open && dialog.open) dialog.close();
|
|
2209
2435
|
}, [open]);
|
|
2210
|
-
return /* @__PURE__ */
|
|
2436
|
+
return /* @__PURE__ */ jsxs27(
|
|
2211
2437
|
"dialog",
|
|
2212
2438
|
{
|
|
2213
2439
|
ref: dialogRef,
|
|
@@ -2215,12 +2441,12 @@ function ReportShortcutsHelp({ open, onClose }) {
|
|
|
2215
2441
|
"aria-label": "Keyboard shortcuts",
|
|
2216
2442
|
onClose,
|
|
2217
2443
|
children: [
|
|
2218
|
-
/* @__PURE__ */
|
|
2219
|
-
/* @__PURE__ */
|
|
2220
|
-
/* @__PURE__ */
|
|
2221
|
-
/* @__PURE__ */
|
|
2444
|
+
/* @__PURE__ */ jsx43("h2", { className: "text-base font-semibold", children: "Keyboard shortcuts" }),
|
|
2445
|
+
/* @__PURE__ */ jsx43("dl", { className: "mt-4 grid grid-cols-[auto_1fr] items-center gap-x-4 gap-y-2.5", children: SHORTCUTS.map((s) => /* @__PURE__ */ jsxs27("div", { className: "col-span-2 grid grid-cols-subgrid items-center", children: [
|
|
2446
|
+
/* @__PURE__ */ jsx43("dt", { className: "justify-self-start", children: /* @__PURE__ */ jsx43(Keys, { keys: s.keys }) }),
|
|
2447
|
+
/* @__PURE__ */ jsx43("dd", { className: "text-sm text-muted-foreground", children: s.description })
|
|
2222
2448
|
] }, s.keys)) }),
|
|
2223
|
-
/* @__PURE__ */
|
|
2449
|
+
/* @__PURE__ */ jsx43("form", { method: "dialog", className: "mt-6", children: /* @__PURE__ */ jsx43(Button, { type: "submit", variant: "outline", size: "sm", children: "Close" }) })
|
|
2224
2450
|
]
|
|
2225
2451
|
}
|
|
2226
2452
|
);
|
|
@@ -2282,14 +2508,16 @@ function useKeyboardShortcuts(handlers) {
|
|
|
2282
2508
|
}
|
|
2283
2509
|
|
|
2284
2510
|
// src/interactive/use-deep-link-scroll.ts
|
|
2285
|
-
import { useEffect as useEffect4 } from "react";
|
|
2511
|
+
import { useEffect as useEffect4, useRef as useRef3 } from "react";
|
|
2286
2512
|
function useDeepLinkScroll() {
|
|
2513
|
+
const lastAnchor = useRef3(null);
|
|
2287
2514
|
useEffect4(() => {
|
|
2288
2515
|
function scrollToHash() {
|
|
2289
|
-
const
|
|
2290
|
-
if (!
|
|
2516
|
+
const { anchor } = splitHash(window.location.hash);
|
|
2517
|
+
if (!anchor || anchor === lastAnchor.current) return;
|
|
2518
|
+
lastAnchor.current = anchor;
|
|
2291
2519
|
requestAnimationFrame(() => {
|
|
2292
|
-
scrollToScenarioId(
|
|
2520
|
+
scrollToScenarioId(anchor, { updateHash: false });
|
|
2293
2521
|
});
|
|
2294
2522
|
}
|
|
2295
2523
|
scrollToHash();
|
|
@@ -2421,7 +2649,7 @@ function failuresFirst(report) {
|
|
|
2421
2649
|
|
|
2422
2650
|
// src/interactive/ReportFilters.tsx
|
|
2423
2651
|
import { useState as useState3 } from "react";
|
|
2424
|
-
import { jsx as
|
|
2652
|
+
import { jsx as jsx44, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
2425
2653
|
var TAG_LIMIT = 12;
|
|
2426
2654
|
function ReportFilters({
|
|
2427
2655
|
statuses,
|
|
@@ -2435,10 +2663,10 @@ function ReportFilters({
|
|
|
2435
2663
|
if (statuses.length === 0 && tags.length === 0) return null;
|
|
2436
2664
|
const tagsCollapsed = tags.length > TAG_LIMIT && !showAllTags;
|
|
2437
2665
|
const visibleTags = tagsCollapsed ? tags.slice(0, TAG_LIMIT) : tags;
|
|
2438
|
-
return /* @__PURE__ */
|
|
2439
|
-
statuses.length > 0 ? /* @__PURE__ */
|
|
2666
|
+
return /* @__PURE__ */ jsxs28("div", { className: "flex flex-col gap-2", children: [
|
|
2667
|
+
statuses.length > 0 ? /* @__PURE__ */ jsx44("div", { role: "group", "aria-label": "Filter by status", className: "flex flex-wrap gap-1", children: statuses.map((opt) => {
|
|
2440
2668
|
const active = status === opt.key;
|
|
2441
|
-
return /* @__PURE__ */
|
|
2669
|
+
return /* @__PURE__ */ jsxs28(
|
|
2442
2670
|
"button",
|
|
2443
2671
|
{
|
|
2444
2672
|
type: "button",
|
|
@@ -2450,23 +2678,23 @@ function ReportFilters({
|
|
|
2450
2678
|
),
|
|
2451
2679
|
children: [
|
|
2452
2680
|
opt.label,
|
|
2453
|
-
/* @__PURE__ */
|
|
2681
|
+
/* @__PURE__ */ jsx44("span", { className: "ml-1 font-mono opacity-70", children: opt.count })
|
|
2454
2682
|
]
|
|
2455
2683
|
},
|
|
2456
2684
|
opt.key
|
|
2457
2685
|
);
|
|
2458
2686
|
}) }) : null,
|
|
2459
|
-
tags.length > 0 ? /* @__PURE__ */
|
|
2687
|
+
tags.length > 0 ? /* @__PURE__ */ jsxs28("ul", { "aria-label": "Filter by tag", className: "flex flex-wrap items-center gap-1.5", children: [
|
|
2460
2688
|
visibleTags.map((tag) => {
|
|
2461
2689
|
const active = activeTags.includes(tag);
|
|
2462
|
-
return /* @__PURE__ */
|
|
2690
|
+
return /* @__PURE__ */ jsx44("li", { children: /* @__PURE__ */ jsx44(
|
|
2463
2691
|
"button",
|
|
2464
2692
|
{
|
|
2465
2693
|
type: "button",
|
|
2466
2694
|
"aria-pressed": active,
|
|
2467
2695
|
onClick: () => onToggleTag(tag),
|
|
2468
2696
|
className: "cursor-pointer",
|
|
2469
|
-
children: /* @__PURE__ */
|
|
2697
|
+
children: /* @__PURE__ */ jsx44(
|
|
2470
2698
|
Badge,
|
|
2471
2699
|
{
|
|
2472
2700
|
variant: "tag",
|
|
@@ -2479,7 +2707,7 @@ function ReportFilters({
|
|
|
2479
2707
|
}
|
|
2480
2708
|
) }, tag);
|
|
2481
2709
|
}),
|
|
2482
|
-
tags.length > TAG_LIMIT ? /* @__PURE__ */
|
|
2710
|
+
tags.length > TAG_LIMIT ? /* @__PURE__ */ jsx44("li", { children: /* @__PURE__ */ jsx44(
|
|
2483
2711
|
"button",
|
|
2484
2712
|
{
|
|
2485
2713
|
type: "button",
|
|
@@ -2495,7 +2723,7 @@ function ReportFilters({
|
|
|
2495
2723
|
|
|
2496
2724
|
// src/interactive/ReportToc.tsx
|
|
2497
2725
|
import { useEffect as useEffect5, useMemo as useMemo2, useState as useState4 } from "react";
|
|
2498
|
-
import { jsx as
|
|
2726
|
+
import { jsx as jsx45, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
2499
2727
|
var DOT = {
|
|
2500
2728
|
passed: "bg-pass",
|
|
2501
2729
|
failed: "bg-fail",
|
|
@@ -2524,11 +2752,11 @@ function TocContent({ onNavigate }) {
|
|
|
2524
2752
|
return () => observer.disconnect();
|
|
2525
2753
|
}, [scenarioIds]);
|
|
2526
2754
|
if (report.features.length === 0) return null;
|
|
2527
|
-
return /* @__PURE__ */
|
|
2528
|
-
/* @__PURE__ */
|
|
2529
|
-
/* @__PURE__ */
|
|
2755
|
+
return /* @__PURE__ */ jsx45("ul", { className: "flex list-none flex-col gap-4 pl-0", children: report.features.map((feature) => /* @__PURE__ */ jsxs29("li", { children: [
|
|
2756
|
+
/* @__PURE__ */ jsx45("p", { className: "mb-1.5 font-semibold leading-snug text-foreground", children: feature.title }),
|
|
2757
|
+
/* @__PURE__ */ jsx45("ul", { className: "flex list-none flex-col gap-0.5 pl-0", children: feature.scenarios.map((scenario) => {
|
|
2530
2758
|
const active = activeId === scenario.id;
|
|
2531
|
-
return /* @__PURE__ */
|
|
2759
|
+
return /* @__PURE__ */ jsx45("li", { children: /* @__PURE__ */ jsxs29(
|
|
2532
2760
|
"a",
|
|
2533
2761
|
{
|
|
2534
2762
|
href: `#${scenario.id}`,
|
|
@@ -2543,14 +2771,14 @@ function TocContent({ onNavigate }) {
|
|
|
2543
2771
|
active ? "border-primary font-medium text-foreground" : "border-border text-muted-foreground"
|
|
2544
2772
|
),
|
|
2545
2773
|
children: [
|
|
2546
|
-
/* @__PURE__ */
|
|
2774
|
+
/* @__PURE__ */ jsx45(
|
|
2547
2775
|
"span",
|
|
2548
2776
|
{
|
|
2549
2777
|
"aria-hidden": true,
|
|
2550
2778
|
className: cn("mt-1 size-1.5 shrink-0 rounded-full", DOT[scenario.status])
|
|
2551
2779
|
}
|
|
2552
2780
|
),
|
|
2553
|
-
/* @__PURE__ */
|
|
2781
|
+
/* @__PURE__ */ jsx45("span", { className: "break-words", children: scenario.title })
|
|
2554
2782
|
]
|
|
2555
2783
|
}
|
|
2556
2784
|
) }, scenario.id);
|
|
@@ -2560,14 +2788,14 @@ function TocContent({ onNavigate }) {
|
|
|
2560
2788
|
function ReportToc() {
|
|
2561
2789
|
const report = useReport();
|
|
2562
2790
|
if (report.features.length === 0) return null;
|
|
2563
|
-
return /* @__PURE__ */
|
|
2791
|
+
return /* @__PURE__ */ jsxs29(
|
|
2564
2792
|
"nav",
|
|
2565
2793
|
{
|
|
2566
2794
|
"aria-label": "Table of contents",
|
|
2567
2795
|
className: "sticky top-4 hidden h-fit w-64 shrink-0 self-start text-xs lg:block",
|
|
2568
2796
|
children: [
|
|
2569
|
-
/* @__PURE__ */
|
|
2570
|
-
/* @__PURE__ */
|
|
2797
|
+
/* @__PURE__ */ jsx45("p", { className: "mb-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Contents" }),
|
|
2798
|
+
/* @__PURE__ */ jsx45(TocContent, {})
|
|
2571
2799
|
]
|
|
2572
2800
|
}
|
|
2573
2801
|
);
|
|
@@ -2577,31 +2805,31 @@ function ReportToc() {
|
|
|
2577
2805
|
import { useState as useState5 } from "react";
|
|
2578
2806
|
import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
|
|
2579
2807
|
import { ListIcon, XIcon } from "lucide-react";
|
|
2580
|
-
import { jsx as
|
|
2808
|
+
import { jsx as jsx46, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
2581
2809
|
function ReportTocDrawer() {
|
|
2582
2810
|
const report = useReport();
|
|
2583
2811
|
const [open, setOpen] = useState5(false);
|
|
2584
2812
|
if (report.features.length === 0) return null;
|
|
2585
|
-
return /* @__PURE__ */
|
|
2586
|
-
/* @__PURE__ */
|
|
2587
|
-
/* @__PURE__ */
|
|
2813
|
+
return /* @__PURE__ */ jsxs30(DialogPrimitive.Root, { open, onOpenChange: setOpen, children: [
|
|
2814
|
+
/* @__PURE__ */ jsxs30(DialogPrimitive.Trigger, { className: "flex cursor-pointer items-center gap-1 rounded-md border border-border px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground lg:hidden [&_svg]:size-3.5", children: [
|
|
2815
|
+
/* @__PURE__ */ jsx46(ListIcon, { "aria-hidden": true }),
|
|
2588
2816
|
" Contents"
|
|
2589
2817
|
] }),
|
|
2590
|
-
/* @__PURE__ */
|
|
2591
|
-
/* @__PURE__ */
|
|
2592
|
-
/* @__PURE__ */
|
|
2593
|
-
/* @__PURE__ */
|
|
2594
|
-
/* @__PURE__ */
|
|
2595
|
-
/* @__PURE__ */
|
|
2818
|
+
/* @__PURE__ */ jsxs30(DialogPrimitive.Portal, { children: [
|
|
2819
|
+
/* @__PURE__ */ jsx46(DialogPrimitive.Backdrop, { className: "fixed inset-0 z-50 bg-black/50 transition-opacity duration-200 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0" }),
|
|
2820
|
+
/* @__PURE__ */ jsxs30(DialogPrimitive.Popup, { className: "fixed inset-y-0 left-0 z-50 flex w-72 max-w-[80vw] flex-col gap-3 overflow-y-auto border-r border-border bg-background p-4 font-sans text-xs shadow-lg outline-none transition-transform duration-200 data-[ending-style]:-translate-x-full data-[starting-style]:-translate-x-full", children: [
|
|
2821
|
+
/* @__PURE__ */ jsxs30("div", { className: "flex items-center justify-between", children: [
|
|
2822
|
+
/* @__PURE__ */ jsx46(DialogPrimitive.Title, { className: "text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Contents" }),
|
|
2823
|
+
/* @__PURE__ */ jsx46(
|
|
2596
2824
|
DialogPrimitive.Close,
|
|
2597
2825
|
{
|
|
2598
2826
|
"aria-label": "Close contents",
|
|
2599
2827
|
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
2600
|
-
children: /* @__PURE__ */
|
|
2828
|
+
children: /* @__PURE__ */ jsx46(XIcon, { "aria-hidden": true })
|
|
2601
2829
|
}
|
|
2602
2830
|
)
|
|
2603
2831
|
] }),
|
|
2604
|
-
/* @__PURE__ */
|
|
2832
|
+
/* @__PURE__ */ jsx46(TocContent, { onNavigate: () => setOpen(false) })
|
|
2605
2833
|
] })
|
|
2606
2834
|
] })
|
|
2607
2835
|
] });
|
|
@@ -2655,15 +2883,43 @@ function useTheme() {
|
|
|
2655
2883
|
return { pref, setPref };
|
|
2656
2884
|
}
|
|
2657
2885
|
|
|
2886
|
+
// src/interactive/use-url-state.ts
|
|
2887
|
+
import { useCallback as useCallback4, useEffect as useEffect7, useRef as useRef4, useState as useState7 } from "react";
|
|
2888
|
+
var WRITE_DELAY_MS = 250;
|
|
2889
|
+
function useUrlState() {
|
|
2890
|
+
const [state, setState] = useState7(DEFAULT_URL_STATE);
|
|
2891
|
+
const ready = useRef4(false);
|
|
2892
|
+
useEffect7(() => {
|
|
2893
|
+
const read = () => setState(decodeUrlState(splitHash(window.location.hash).params));
|
|
2894
|
+
read();
|
|
2895
|
+
ready.current = true;
|
|
2896
|
+
window.addEventListener("hashchange", read);
|
|
2897
|
+
return () => window.removeEventListener("hashchange", read);
|
|
2898
|
+
}, []);
|
|
2899
|
+
useEffect7(() => {
|
|
2900
|
+
if (!ready.current) return;
|
|
2901
|
+
const timer = setTimeout(
|
|
2902
|
+
() => writeHash(splitHash(window.location.hash).anchor, encodeUrlState(state)),
|
|
2903
|
+
WRITE_DELAY_MS
|
|
2904
|
+
);
|
|
2905
|
+
return () => clearTimeout(timer);
|
|
2906
|
+
}, [state]);
|
|
2907
|
+
const update = useCallback4(
|
|
2908
|
+
(patch) => setState((prev) => ({ ...prev, ...patch })),
|
|
2909
|
+
[]
|
|
2910
|
+
);
|
|
2911
|
+
return [state, update];
|
|
2912
|
+
}
|
|
2913
|
+
|
|
2658
2914
|
// src/interactive/ReportInteractive.tsx
|
|
2659
|
-
import { Fragment as Fragment13, jsx as
|
|
2915
|
+
import { Fragment as Fragment13, jsx as jsx47, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
2660
2916
|
function ReportInteractive(props) {
|
|
2661
2917
|
const { report, className, title, dataTheme } = props;
|
|
2662
2918
|
const result = unwrapReport(report);
|
|
2663
2919
|
if (!result.ok) {
|
|
2664
|
-
return /* @__PURE__ */
|
|
2920
|
+
return /* @__PURE__ */ jsx47(ReportErrorShell, { error: result.error, className, title, dataTheme });
|
|
2665
2921
|
}
|
|
2666
|
-
return /* @__PURE__ */
|
|
2922
|
+
return /* @__PURE__ */ jsx47(ReportInteractiveView, { ...props, report: result.data });
|
|
2667
2923
|
}
|
|
2668
2924
|
var THEME_OPTIONS = [
|
|
2669
2925
|
{ value: "light", label: "Light", Icon: Sun },
|
|
@@ -2671,7 +2927,7 @@ var THEME_OPTIONS = [
|
|
|
2671
2927
|
{ value: "dark", label: "Dark", Icon: Moon }
|
|
2672
2928
|
];
|
|
2673
2929
|
function ThemeSegment({ pref, onPref }) {
|
|
2674
|
-
return /* @__PURE__ */
|
|
2930
|
+
return /* @__PURE__ */ jsx47(
|
|
2675
2931
|
ToggleGroup,
|
|
2676
2932
|
{
|
|
2677
2933
|
size: "sm",
|
|
@@ -2681,7 +2937,7 @@ function ThemeSegment({ pref, onPref }) {
|
|
|
2681
2937
|
if (next) onPref(next);
|
|
2682
2938
|
},
|
|
2683
2939
|
"aria-label": "Color theme",
|
|
2684
|
-
children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */
|
|
2940
|
+
children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */ jsx47(ToggleGroupItem, { value, "aria-label": label, title: label, className: "px-2", children: /* @__PURE__ */ jsx47(Icon, {}) }, value))
|
|
2685
2941
|
}
|
|
2686
2942
|
);
|
|
2687
2943
|
}
|
|
@@ -2697,13 +2953,20 @@ function ReportInteractiveView({
|
|
|
2697
2953
|
staleAfterDays = 7,
|
|
2698
2954
|
scenarioHistory
|
|
2699
2955
|
}) {
|
|
2700
|
-
const [
|
|
2701
|
-
const
|
|
2702
|
-
const
|
|
2703
|
-
const
|
|
2704
|
-
|
|
2956
|
+
const [urlState, setUrlState] = useUrlState();
|
|
2957
|
+
const { query, status: statusFilter, tags: activeTags, detail } = urlState;
|
|
2958
|
+
const setQuery = useCallback5((next) => setUrlState({ query: next }), [setUrlState]);
|
|
2959
|
+
const setStatusFilter = useCallback5(
|
|
2960
|
+
(next) => setUrlState({ status: next }),
|
|
2961
|
+
[setUrlState]
|
|
2962
|
+
);
|
|
2963
|
+
const setDetail = useCallback5(
|
|
2964
|
+
(next) => setUrlState({ detail: next }),
|
|
2965
|
+
[setUrlState]
|
|
2966
|
+
);
|
|
2967
|
+
const [helpOpen, setHelpOpen] = useState8(false);
|
|
2705
2968
|
const { pref: themePref, setPref: setThemePref } = useTheme();
|
|
2706
|
-
const searchRef =
|
|
2969
|
+
const searchRef = useRef5(null);
|
|
2707
2970
|
const expandId = useId2();
|
|
2708
2971
|
const docsId = useId2();
|
|
2709
2972
|
const deferredQuery = useDeferredValue(query);
|
|
@@ -2727,18 +2990,20 @@ function ReportInteractiveView({
|
|
|
2727
2990
|
return opts;
|
|
2728
2991
|
}, [report]);
|
|
2729
2992
|
const tagOptions = useMemo3(() => allTags(report), [report]);
|
|
2730
|
-
const toggleTag =
|
|
2731
|
-
(tag) =>
|
|
2732
|
-
|
|
2993
|
+
const toggleTag = useCallback5(
|
|
2994
|
+
(tag) => setUrlState({
|
|
2995
|
+
tags: activeTags.includes(tag) ? activeTags.filter((t) => t !== tag) : [...activeTags, tag]
|
|
2996
|
+
}),
|
|
2997
|
+
[activeTags, setUrlState]
|
|
2733
2998
|
);
|
|
2734
|
-
const [toast, setToast] =
|
|
2735
|
-
const toastTimer =
|
|
2736
|
-
const showToast =
|
|
2999
|
+
const [toast, setToast] = useState8(null);
|
|
3000
|
+
const toastTimer = useRef5(null);
|
|
3001
|
+
const showToast = useCallback5((msg) => {
|
|
2737
3002
|
setToast(msg);
|
|
2738
3003
|
if (toastTimer.current) clearTimeout(toastTimer.current);
|
|
2739
3004
|
toastTimer.current = setTimeout(() => setToast(null), 1800);
|
|
2740
3005
|
}, []);
|
|
2741
|
-
const copy =
|
|
3006
|
+
const copy = useCallback5(
|
|
2742
3007
|
(text, msg) => {
|
|
2743
3008
|
if (typeof navigator !== "undefined" && navigator.clipboard) {
|
|
2744
3009
|
navigator.clipboard.writeText(text).then(() => showToast(msg), () => showToast("Copy failed"));
|
|
@@ -2754,15 +3019,15 @@ function ReportInteractiveView({
|
|
|
2754
3019
|
}),
|
|
2755
3020
|
[copy]
|
|
2756
3021
|
);
|
|
2757
|
-
const failureIndexRef =
|
|
3022
|
+
const failureIndexRef = useRef5(0);
|
|
2758
3023
|
const allCollapsibleIds = useMemo3(
|
|
2759
3024
|
() => report.features.flatMap((f) => [f.id, ...f.scenarios.map((s) => s.id)]),
|
|
2760
3025
|
[report]
|
|
2761
3026
|
);
|
|
2762
|
-
const collapse = useCollapseState(
|
|
2763
|
-
const collapseAll =
|
|
2764
|
-
const [expandedAll, setExpandedAll] =
|
|
2765
|
-
const setExpanded =
|
|
3027
|
+
const collapse = useCollapseState(useCallback5(() => defaultCollapsedIds(report), [report]));
|
|
3028
|
+
const collapseAll = useCallback5(() => collapse.collapseAll(allCollapsibleIds), [collapse, allCollapsibleIds]);
|
|
3029
|
+
const [expandedAll, setExpandedAll] = useState8(() => report.summary.failed === 0);
|
|
3030
|
+
const setExpanded = useCallback5(
|
|
2766
3031
|
(expanded) => {
|
|
2767
3032
|
if (expanded) collapse.expandAll();
|
|
2768
3033
|
else collapseAll();
|
|
@@ -2770,10 +3035,10 @@ function ReportInteractiveView({
|
|
|
2770
3035
|
},
|
|
2771
3036
|
[collapse, collapseAll]
|
|
2772
3037
|
);
|
|
2773
|
-
const focusSearch =
|
|
3038
|
+
const focusSearch = useCallback5(() => {
|
|
2774
3039
|
searchRef.current?.focus();
|
|
2775
3040
|
}, []);
|
|
2776
|
-
const stepFailure =
|
|
3041
|
+
const stepFailure = useCallback5(
|
|
2777
3042
|
(direction) => {
|
|
2778
3043
|
if (failures.length === 0) return;
|
|
2779
3044
|
failureIndexRef.current = (failureIndexRef.current + direction + failures.length) % failures.length;
|
|
@@ -2782,10 +3047,10 @@ function ReportInteractiveView({
|
|
|
2782
3047
|
},
|
|
2783
3048
|
[failures]
|
|
2784
3049
|
);
|
|
2785
|
-
const toggleHelp =
|
|
3050
|
+
const toggleHelp = useCallback5(() => {
|
|
2786
3051
|
setHelpOpen((v) => !v);
|
|
2787
3052
|
}, []);
|
|
2788
|
-
const escape =
|
|
3053
|
+
const escape = useCallback5(() => {
|
|
2789
3054
|
if (helpOpen) setHelpOpen(false);
|
|
2790
3055
|
else if (query !== "") setQuery("");
|
|
2791
3056
|
}, [helpOpen, query]);
|
|
@@ -2803,13 +3068,13 @@ function ReportInteractiveView({
|
|
|
2803
3068
|
const totalScenarios = report.summary.total;
|
|
2804
3069
|
const matchedScenarios = filtered.summary.total;
|
|
2805
3070
|
const showToc = !hideToc && totalScenarios > 3;
|
|
2806
|
-
return /* @__PURE__ */
|
|
3071
|
+
return /* @__PURE__ */ jsx47(CollapseProvider, { value: collapse.api, children: /* @__PURE__ */ jsx47(ScenarioActionsProvider, { value: scenarioActions, children: /* @__PURE__ */ jsx47(ScenarioHistoryProvider, { value: scenarioHistory ?? null, children: /* @__PURE__ */ jsx47(
|
|
2807
3072
|
ReportRoot,
|
|
2808
3073
|
{
|
|
2809
3074
|
report: filtered,
|
|
2810
3075
|
customRenderers,
|
|
2811
3076
|
renderers,
|
|
2812
|
-
children: /* @__PURE__ */
|
|
3077
|
+
children: /* @__PURE__ */ jsxs31(
|
|
2813
3078
|
"main",
|
|
2814
3079
|
{
|
|
2815
3080
|
className: cn("es-report", "es-report-interactive", className),
|
|
@@ -2818,8 +3083,8 @@ function ReportInteractiveView({
|
|
|
2818
3083
|
"data-theme": dataTheme,
|
|
2819
3084
|
"data-detail-level": detail,
|
|
2820
3085
|
children: [
|
|
2821
|
-
/* @__PURE__ */
|
|
2822
|
-
/* @__PURE__ */
|
|
3086
|
+
/* @__PURE__ */ jsxs31("header", { className: "es-report-header", children: [
|
|
3087
|
+
/* @__PURE__ */ jsxs31(
|
|
2823
3088
|
"div",
|
|
2824
3089
|
{
|
|
2825
3090
|
"data-es-navbar": true,
|
|
@@ -2828,9 +3093,9 @@ function ReportInteractiveView({
|
|
|
2828
3093
|
hideHeader ? "justify-end" : "justify-between"
|
|
2829
3094
|
),
|
|
2830
3095
|
children: [
|
|
2831
|
-
hideHeader ? null : /* @__PURE__ */
|
|
2832
|
-
/* @__PURE__ */
|
|
2833
|
-
/* @__PURE__ */
|
|
3096
|
+
hideHeader ? null : /* @__PURE__ */ jsx47("h1", { className: "min-w-0", children: title ?? "Story Report" }),
|
|
3097
|
+
/* @__PURE__ */ jsxs31("div", { className: "flex items-center gap-2", children: [
|
|
3098
|
+
/* @__PURE__ */ jsx47(
|
|
2834
3099
|
ReportSearch,
|
|
2835
3100
|
{
|
|
2836
3101
|
ref: searchRef,
|
|
@@ -2840,16 +3105,16 @@ function ReportInteractiveView({
|
|
|
2840
3105
|
totalCount: totalScenarios
|
|
2841
3106
|
}
|
|
2842
3107
|
),
|
|
2843
|
-
/* @__PURE__ */
|
|
3108
|
+
/* @__PURE__ */ jsx47(ThemeSegment, { pref: themePref, onPref: setThemePref })
|
|
2844
3109
|
] })
|
|
2845
3110
|
]
|
|
2846
3111
|
}
|
|
2847
3112
|
),
|
|
2848
|
-
hideHeader ? null : /* @__PURE__ */
|
|
2849
|
-
/* @__PURE__ */
|
|
2850
|
-
/* @__PURE__ */
|
|
3113
|
+
hideHeader ? null : /* @__PURE__ */ jsxs31(Fragment13, { children: [
|
|
3114
|
+
/* @__PURE__ */ jsx47(ReportSummary, {}),
|
|
3115
|
+
/* @__PURE__ */ jsx47(ReportMeta, {})
|
|
2851
3116
|
] }),
|
|
2852
|
-
/* @__PURE__ */
|
|
3117
|
+
/* @__PURE__ */ jsx47(
|
|
2853
3118
|
ReportFreshness,
|
|
2854
3119
|
{
|
|
2855
3120
|
lastRunMs: reportLastRunMs(report),
|
|
@@ -2857,8 +3122,8 @@ function ReportInteractiveView({
|
|
|
2857
3122
|
staleAfterDays
|
|
2858
3123
|
}
|
|
2859
3124
|
),
|
|
2860
|
-
/* @__PURE__ */
|
|
2861
|
-
/* @__PURE__ */
|
|
3125
|
+
/* @__PURE__ */ jsx47(ReportLastRunDelta, { history: scenarioHistory, report }),
|
|
3126
|
+
/* @__PURE__ */ jsx47(
|
|
2862
3127
|
ReportFilters,
|
|
2863
3128
|
{
|
|
2864
3129
|
statuses: statusOptions,
|
|
@@ -2869,14 +3134,14 @@ function ReportInteractiveView({
|
|
|
2869
3134
|
onToggleTag: toggleTag
|
|
2870
3135
|
}
|
|
2871
3136
|
),
|
|
2872
|
-
/* @__PURE__ */
|
|
2873
|
-
showToc ? /* @__PURE__ */
|
|
2874
|
-
/* @__PURE__ */
|
|
2875
|
-
/* @__PURE__ */
|
|
2876
|
-
/* @__PURE__ */
|
|
3137
|
+
/* @__PURE__ */ jsxs31("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-2 border-t border-border/60 pt-3", children: [
|
|
3138
|
+
showToc ? /* @__PURE__ */ jsx47(ReportTocDrawer, {}) : null,
|
|
3139
|
+
/* @__PURE__ */ jsxs31("div", { className: "flex items-center gap-2", children: [
|
|
3140
|
+
/* @__PURE__ */ jsx47(Switch, { id: expandId, checked: expandedAll, onCheckedChange: setExpanded }),
|
|
3141
|
+
/* @__PURE__ */ jsx47("label", { htmlFor: expandId, className: "cursor-pointer text-sm text-muted-foreground select-none", children: "Expand all" })
|
|
2877
3142
|
] }),
|
|
2878
|
-
/* @__PURE__ */
|
|
2879
|
-
/* @__PURE__ */
|
|
3143
|
+
/* @__PURE__ */ jsxs31("div", { className: "flex items-center gap-2", children: [
|
|
3144
|
+
/* @__PURE__ */ jsx47(
|
|
2880
3145
|
Switch,
|
|
2881
3146
|
{
|
|
2882
3147
|
id: docsId,
|
|
@@ -2884,16 +3149,16 @@ function ReportInteractiveView({
|
|
|
2884
3149
|
onCheckedChange: (checked) => setDetail(checked ? "full" : "minimal")
|
|
2885
3150
|
}
|
|
2886
3151
|
),
|
|
2887
|
-
/* @__PURE__ */
|
|
3152
|
+
/* @__PURE__ */ jsx47("label", { htmlFor: docsId, className: "cursor-pointer text-sm text-muted-foreground select-none", children: "Show documentation" })
|
|
2888
3153
|
] })
|
|
2889
3154
|
] })
|
|
2890
3155
|
] }),
|
|
2891
|
-
/* @__PURE__ */
|
|
2892
|
-
hasContent ? showToc ? /* @__PURE__ */
|
|
2893
|
-
/* @__PURE__ */
|
|
2894
|
-
/* @__PURE__ */
|
|
2895
|
-
] }) : /* @__PURE__ */
|
|
2896
|
-
/* @__PURE__ */
|
|
3156
|
+
/* @__PURE__ */ jsx47(ReportFailureBanner, { failures }),
|
|
3157
|
+
hasContent ? showToc ? /* @__PURE__ */ jsxs31("div", { className: "flex gap-6", children: [
|
|
3158
|
+
/* @__PURE__ */ jsx47(ReportToc, {}),
|
|
3159
|
+
/* @__PURE__ */ jsx47("div", { className: "flex min-w-0 flex-1 flex-col gap-4", children: /* @__PURE__ */ jsx47(ReportFeatureList, {}) })
|
|
3160
|
+
] }) : /* @__PURE__ */ jsx47("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ jsx47(ReportFeatureList, {}) }) : /* @__PURE__ */ jsx47(ReportEmpty, { message: query ? "No scenarios match the search." : void 0 }),
|
|
3161
|
+
/* @__PURE__ */ jsx47(
|
|
2897
3162
|
"button",
|
|
2898
3163
|
{
|
|
2899
3164
|
type: "button",
|
|
@@ -2904,8 +3169,8 @@ function ReportInteractiveView({
|
|
|
2904
3169
|
children: "?"
|
|
2905
3170
|
}
|
|
2906
3171
|
),
|
|
2907
|
-
/* @__PURE__ */
|
|
2908
|
-
toast ? /* @__PURE__ */
|
|
3172
|
+
/* @__PURE__ */ jsx47(ReportShortcutsHelp, { open: helpOpen, onClose: () => setHelpOpen(false) }),
|
|
3173
|
+
toast ? /* @__PURE__ */ jsx47(
|
|
2909
3174
|
"div",
|
|
2910
3175
|
{
|
|
2911
3176
|
role: "status",
|
|
@@ -2925,11 +3190,11 @@ function ReportInteractiveView({
|
|
|
2925
3190
|
import { useMemo as useMemo4 } from "react";
|
|
2926
3191
|
|
|
2927
3192
|
// src/interactive/island-renderers.tsx
|
|
2928
|
-
import { createElement, useEffect as
|
|
3193
|
+
import { createElement, useEffect as useEffect9, useState as useState10 } from "react";
|
|
2929
3194
|
|
|
2930
3195
|
// src/components/doc/MermaidView.tsx
|
|
2931
|
-
import { useEffect as
|
|
2932
|
-
import { jsx as
|
|
3196
|
+
import { useEffect as useEffect8, useRef as useRef6, useState as useState9 } from "react";
|
|
3197
|
+
import { Fragment as Fragment14, jsx as jsx48, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
2933
3198
|
function prefersDark(el) {
|
|
2934
3199
|
const themed = el?.closest("[data-theme]");
|
|
2935
3200
|
if (themed?.dataset.theme === "dark") return true;
|
|
@@ -2937,23 +3202,40 @@ function prefersDark(el) {
|
|
|
2937
3202
|
return typeof window !== "undefined" && !!window.matchMedia?.("(prefers-color-scheme: dark)").matches;
|
|
2938
3203
|
}
|
|
2939
3204
|
function MermaidView({ entry, load }) {
|
|
2940
|
-
const ref =
|
|
2941
|
-
const [svg, setSvg] =
|
|
2942
|
-
|
|
3205
|
+
const ref = useRef6(null);
|
|
3206
|
+
const [svg, setSvg] = useState9(null);
|
|
3207
|
+
const [error, setError] = useState9(null);
|
|
3208
|
+
useEffect8(() => {
|
|
2943
3209
|
let cancelled = false;
|
|
2944
3210
|
const draw = async () => {
|
|
3211
|
+
let mermaid;
|
|
3212
|
+
try {
|
|
3213
|
+
mermaid = await load();
|
|
3214
|
+
} catch {
|
|
3215
|
+
if (!cancelled) {
|
|
3216
|
+
setSvg(null);
|
|
3217
|
+
setError(null);
|
|
3218
|
+
}
|
|
3219
|
+
return;
|
|
3220
|
+
}
|
|
2945
3221
|
try {
|
|
2946
|
-
const mermaid = await load();
|
|
2947
3222
|
mermaid.initialize({
|
|
2948
3223
|
startOnLoad: false,
|
|
2949
3224
|
securityLevel: "strict",
|
|
2950
3225
|
theme: prefersDark(ref.current) ? "dark" : "default"
|
|
2951
3226
|
});
|
|
3227
|
+
await mermaid.parse(entry.code);
|
|
2952
3228
|
const id = `es-mermaid-${Math.random().toString(36).slice(2)}`;
|
|
2953
3229
|
const { svg: rendered } = await mermaid.render(id, entry.code);
|
|
2954
|
-
if (!cancelled)
|
|
2955
|
-
|
|
2956
|
-
|
|
3230
|
+
if (!cancelled) {
|
|
3231
|
+
setSvg(rendered);
|
|
3232
|
+
setError(null);
|
|
3233
|
+
}
|
|
3234
|
+
} catch (err) {
|
|
3235
|
+
if (!cancelled) {
|
|
3236
|
+
setSvg(null);
|
|
3237
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
3238
|
+
}
|
|
2957
3239
|
}
|
|
2958
3240
|
};
|
|
2959
3241
|
void draw();
|
|
@@ -2966,9 +3248,9 @@ function MermaidView({ entry, load }) {
|
|
|
2966
3248
|
};
|
|
2967
3249
|
}, [entry.code, load]);
|
|
2968
3250
|
if (svg) {
|
|
2969
|
-
return /* @__PURE__ */
|
|
2970
|
-
entry.title ? /* @__PURE__ */
|
|
2971
|
-
/* @__PURE__ */
|
|
3251
|
+
return /* @__PURE__ */ jsxs32("figure", { ref, className: "my-3", children: [
|
|
3252
|
+
entry.title ? /* @__PURE__ */ jsx48("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
|
|
3253
|
+
/* @__PURE__ */ jsx48(
|
|
2972
3254
|
"div",
|
|
2973
3255
|
{
|
|
2974
3256
|
role: "img",
|
|
@@ -2979,11 +3261,25 @@ function MermaidView({ entry, load }) {
|
|
|
2979
3261
|
)
|
|
2980
3262
|
] });
|
|
2981
3263
|
}
|
|
2982
|
-
return /* @__PURE__ */
|
|
3264
|
+
return /* @__PURE__ */ jsxs32(Fragment14, { children: [
|
|
3265
|
+
error ? /* @__PURE__ */ jsxs32(
|
|
3266
|
+
"p",
|
|
3267
|
+
{
|
|
3268
|
+
role: "alert",
|
|
3269
|
+
"data-es-mermaid-error": true,
|
|
3270
|
+
className: "mt-3 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive",
|
|
3271
|
+
children: [
|
|
3272
|
+
"Diagram failed to render: ",
|
|
3273
|
+
error
|
|
3274
|
+
]
|
|
3275
|
+
}
|
|
3276
|
+
) : null,
|
|
3277
|
+
/* @__PURE__ */ jsx48(MermaidSource, { entry, ref })
|
|
3278
|
+
] });
|
|
2983
3279
|
}
|
|
2984
3280
|
|
|
2985
3281
|
// src/interactive/island-renderers.tsx
|
|
2986
|
-
import { jsx as
|
|
3282
|
+
import { jsx as jsx49 } from "react/jsx-runtime";
|
|
2987
3283
|
var HLJS_ESM = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/highlight.min.js";
|
|
2988
3284
|
var MERMAID_ESM = "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
|
|
2989
3285
|
function cachedCdnModule(url) {
|
|
@@ -3000,8 +3296,8 @@ function cachedCdnModule(url) {
|
|
|
3000
3296
|
var loadMermaidFromCdn = cachedCdnModule(MERMAID_ESM);
|
|
3001
3297
|
var loadHljs = cachedCdnModule(HLJS_ESM);
|
|
3002
3298
|
function CdnHighlightedCode({ entry }) {
|
|
3003
|
-
const [html, setHtml] =
|
|
3004
|
-
|
|
3299
|
+
const [html, setHtml] = useState10(null);
|
|
3300
|
+
useEffect9(() => {
|
|
3005
3301
|
let cancelled = false;
|
|
3006
3302
|
void (async () => {
|
|
3007
3303
|
try {
|
|
@@ -3017,13 +3313,13 @@ function CdnHighlightedCode({ entry }) {
|
|
|
3017
3313
|
cancelled = true;
|
|
3018
3314
|
};
|
|
3019
3315
|
}, [entry.content, entry.lang]);
|
|
3020
|
-
return /* @__PURE__ */
|
|
3316
|
+
return /* @__PURE__ */ jsx49(CodeFigure, { label: entry.label, children: html !== null ? /* @__PURE__ */ jsx49(
|
|
3021
3317
|
"code",
|
|
3022
3318
|
{
|
|
3023
3319
|
className: cn("hljs font-mono text-xs", entry.lang && `language-${entry.lang}`),
|
|
3024
3320
|
dangerouslySetInnerHTML: { __html: html }
|
|
3025
3321
|
}
|
|
3026
|
-
) : /* @__PURE__ */
|
|
3322
|
+
) : /* @__PURE__ */ jsx49("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
|
|
3027
3323
|
}
|
|
3028
3324
|
function buildIslandRenderers(opts) {
|
|
3029
3325
|
const renderers = {};
|
|
@@ -3037,7 +3333,7 @@ function buildIslandRenderers(opts) {
|
|
|
3037
3333
|
}
|
|
3038
3334
|
|
|
3039
3335
|
// src/interactive/ReportInteractiveIsland.tsx
|
|
3040
|
-
import { jsx as
|
|
3336
|
+
import { jsx as jsx50 } from "react/jsx-runtime";
|
|
3041
3337
|
function ReportInteractiveIsland({
|
|
3042
3338
|
report,
|
|
3043
3339
|
title,
|
|
@@ -3051,7 +3347,7 @@ function ReportInteractiveIsland({
|
|
|
3051
3347
|
() => buildIslandRenderers({ syntaxHighlighting, mermaid }),
|
|
3052
3348
|
[syntaxHighlighting, mermaid]
|
|
3053
3349
|
);
|
|
3054
|
-
return /* @__PURE__ */
|
|
3350
|
+
return /* @__PURE__ */ jsx50(
|
|
3055
3351
|
ReportInteractive,
|
|
3056
3352
|
{
|
|
3057
3353
|
report,
|