executable-stories-react 0.9.0 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +540 -483
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -235
- package/dist/index.d.ts +50 -235
- package/dist/index.js +525 -475
- package/dist/index.js.map +1 -1
- package/dist/interactive.cjs +615 -689
- package/dist/interactive.cjs.map +1 -1
- package/dist/interactive.d.cts +1 -233
- package/dist/interactive.d.ts +1 -233
- package/dist/interactive.js +607 -681
- package/dist/interactive.js.map +1 -1
- package/dist/parse.d.cts +3 -234
- package/dist/parse.d.ts +3 -234
- package/dist/report-island.global.js +28 -28
- package/dist/ssr.cjs +492 -449
- package/dist/ssr.cjs.map +1 -1
- package/dist/ssr.d.cts +1 -232
- package/dist/ssr.d.ts +1 -232
- package/dist/ssr.js +484 -441
- package/dist/ssr.js.map +1 -1
- package/dist/tailwind.css +1 -1
- package/package.json +4 -4
package/dist/interactive.js
CHANGED
|
@@ -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,237 @@ 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
|
+
// src/components/ReportScenario.tsx
|
|
299
|
+
import { formatDuration as formatDuration3 } from "executable-stories-core/utils/duration";
|
|
300
|
+
|
|
301
|
+
// src/components/ReportSteps.tsx
|
|
302
|
+
import { formatDuration } from "executable-stories-core/utils/duration";
|
|
303
|
+
|
|
304
|
+
// src/components/doc/DocNote.tsx
|
|
145
305
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
306
|
+
function DocNote({ entry }) {
|
|
307
|
+
return /* @__PURE__ */ jsx3("p", { className: "my-2 text-sm text-muted-foreground", children: entry.text });
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// src/components/doc/DocTag.tsx
|
|
311
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
146
312
|
function DocTag({ entry }) {
|
|
147
|
-
return /* @__PURE__ */
|
|
313
|
+
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
314
|
}
|
|
149
315
|
|
|
150
316
|
// src/components/doc/DocKv.tsx
|
|
151
|
-
import { jsx as
|
|
317
|
+
import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
152
318
|
function formatValue(value) {
|
|
153
319
|
if (value === null) return "null";
|
|
154
320
|
if (typeof value === "string") return value;
|
|
@@ -160,19 +326,19 @@ function formatValue(value) {
|
|
|
160
326
|
}
|
|
161
327
|
}
|
|
162
328
|
function DocKv({ entry }) {
|
|
163
|
-
return /* @__PURE__ */
|
|
164
|
-
/* @__PURE__ */
|
|
165
|
-
/* @__PURE__ */
|
|
329
|
+
return /* @__PURE__ */ jsxs2("dl", { className: "my-2 flex flex-wrap items-baseline gap-x-2 text-sm", children: [
|
|
330
|
+
/* @__PURE__ */ jsx5("dt", { className: "font-semibold text-muted-foreground", children: entry.label }),
|
|
331
|
+
/* @__PURE__ */ jsx5("dd", { className: "font-mono text-foreground", children: formatValue(entry.value) })
|
|
166
332
|
] });
|
|
167
333
|
}
|
|
168
334
|
|
|
169
335
|
// src/hooks/useRenderers.ts
|
|
170
336
|
import { useContext as useContext2 } from "react";
|
|
171
|
-
var
|
|
337
|
+
var EMPTY_CUSTOM = {};
|
|
172
338
|
var EMPTY_RENDERERS2 = {};
|
|
173
339
|
function useCustomRenderers() {
|
|
174
340
|
const ctx = useContext2(ReportContext);
|
|
175
|
-
return ctx?.customRenderers ??
|
|
341
|
+
return ctx?.customRenderers ?? EMPTY_CUSTOM;
|
|
176
342
|
}
|
|
177
343
|
function useBuiltinRenderers() {
|
|
178
344
|
const ctx = useContext2(ReportContext);
|
|
@@ -180,37 +346,37 @@ function useBuiltinRenderers() {
|
|
|
180
346
|
}
|
|
181
347
|
|
|
182
348
|
// src/components/doc/DocCode.tsx
|
|
183
|
-
import { Fragment, jsx as
|
|
349
|
+
import { Fragment, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
184
350
|
function CodeFigure({ label, children }) {
|
|
185
|
-
return /* @__PURE__ */
|
|
186
|
-
label ? /* @__PURE__ */
|
|
187
|
-
/* @__PURE__ */
|
|
351
|
+
return /* @__PURE__ */ jsxs3("figure", { className: "my-3", children: [
|
|
352
|
+
label ? /* @__PURE__ */ jsx6("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: label }) : null,
|
|
353
|
+
/* @__PURE__ */ jsx6("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3", children })
|
|
188
354
|
] });
|
|
189
355
|
}
|
|
190
356
|
function DocCode({ entry }) {
|
|
191
357
|
const renderers = useBuiltinRenderers();
|
|
192
358
|
if (renderers.code) {
|
|
193
|
-
return /* @__PURE__ */
|
|
359
|
+
return /* @__PURE__ */ jsx6(Fragment, { children: renderers.code(entry) });
|
|
194
360
|
}
|
|
195
|
-
return /* @__PURE__ */
|
|
361
|
+
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
362
|
}
|
|
197
363
|
|
|
198
364
|
// src/components/doc/DocTable.tsx
|
|
199
|
-
import { jsx as
|
|
365
|
+
import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
200
366
|
function DocTable({ entry }) {
|
|
201
|
-
return /* @__PURE__ */
|
|
202
|
-
entry.label ? /* @__PURE__ */
|
|
203
|
-
/* @__PURE__ */
|
|
204
|
-
/* @__PURE__ */
|
|
205
|
-
/* @__PURE__ */
|
|
367
|
+
return /* @__PURE__ */ jsxs4("figure", { className: "my-3", children: [
|
|
368
|
+
entry.label ? /* @__PURE__ */ jsx7("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.label }) : null,
|
|
369
|
+
/* @__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: [
|
|
370
|
+
/* @__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)) }) }),
|
|
371
|
+
/* @__PURE__ */ jsx7("tbody", { children: entry.rows.map((row, i) => /* @__PURE__ */ jsx7("tr", { children: row.map((cell, j) => /* @__PURE__ */ jsx7("td", { className: "border-b border-border px-3 py-2 text-foreground", children: cell }, j)) }, i)) })
|
|
206
372
|
] }) })
|
|
207
373
|
] });
|
|
208
374
|
}
|
|
209
375
|
|
|
210
376
|
// src/components/doc/DocLink.tsx
|
|
211
|
-
import { jsx as
|
|
377
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
212
378
|
function DocLink({ entry }) {
|
|
213
|
-
return /* @__PURE__ */
|
|
379
|
+
return /* @__PURE__ */ jsx8(
|
|
214
380
|
"a",
|
|
215
381
|
{
|
|
216
382
|
className: "text-sm font-medium text-primary underline underline-offset-2 hover:no-underline",
|
|
@@ -225,26 +391,11 @@ function DocLink({ entry }) {
|
|
|
225
391
|
// src/components/doc/DocSection.tsx
|
|
226
392
|
import { marked } from "marked";
|
|
227
393
|
|
|
228
|
-
//
|
|
229
|
-
|
|
230
|
-
if (!value) return void 0;
|
|
231
|
-
const trimmed = value.trim();
|
|
232
|
-
const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(trimmed);
|
|
233
|
-
if (scheme && !/^https?$/i.test(scheme[1] ?? "")) return void 0;
|
|
234
|
-
return trimmed;
|
|
235
|
-
}
|
|
236
|
-
function safeImageUrl(value) {
|
|
237
|
-
if (!value) return void 0;
|
|
238
|
-
const trimmed = value.trim();
|
|
239
|
-
if (/^data:image\//i.test(trimmed)) return trimmed;
|
|
240
|
-
return safeUrl(trimmed);
|
|
241
|
-
}
|
|
242
|
-
function isLocalFsPath(value) {
|
|
243
|
-
return /^(?:[/\\]|[A-Za-z]:[/\\])/.test(value);
|
|
244
|
-
}
|
|
394
|
+
// src/lib/url.ts
|
|
395
|
+
import { safeUrl, safeImageUrl, isLocalFsPath } from "executable-stories-core/utils/url";
|
|
245
396
|
|
|
246
397
|
// src/components/doc/DocSection.tsx
|
|
247
|
-
import { Fragment as Fragment2, jsx as
|
|
398
|
+
import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
248
399
|
function neutralizeUrl(value) {
|
|
249
400
|
return safeUrl(value) ?? "#";
|
|
250
401
|
}
|
|
@@ -255,12 +406,12 @@ function safeMarkdownHtml(markdown) {
|
|
|
255
406
|
function DocSection({ entry }) {
|
|
256
407
|
const renderers = useBuiltinRenderers();
|
|
257
408
|
if (renderers.section) {
|
|
258
|
-
return /* @__PURE__ */
|
|
409
|
+
return /* @__PURE__ */ jsx9(Fragment2, { children: renderers.section(entry) });
|
|
259
410
|
}
|
|
260
411
|
const html = safeMarkdownHtml(entry.markdown);
|
|
261
|
-
return /* @__PURE__ */
|
|
262
|
-
entry.title ? /* @__PURE__ */
|
|
263
|
-
/* @__PURE__ */
|
|
412
|
+
return /* @__PURE__ */ jsxs5("section", { className: "my-3 text-sm", "aria-label": entry.title, children: [
|
|
413
|
+
entry.title ? /* @__PURE__ */ jsx9("h4", { className: "mb-1 font-semibold text-foreground", children: entry.title }) : null,
|
|
414
|
+
/* @__PURE__ */ jsx9(
|
|
264
415
|
"div",
|
|
265
416
|
{
|
|
266
417
|
className: "es-doc-prose prose prose-sm max-w-none",
|
|
@@ -271,11 +422,11 @@ function DocSection({ entry }) {
|
|
|
271
422
|
}
|
|
272
423
|
|
|
273
424
|
// src/components/doc/DocMermaid.tsx
|
|
274
|
-
import { Fragment as Fragment3, jsx as
|
|
425
|
+
import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
275
426
|
function MermaidSource({ entry, ref }) {
|
|
276
|
-
return /* @__PURE__ */
|
|
277
|
-
entry.title ? /* @__PURE__ */
|
|
278
|
-
/* @__PURE__ */
|
|
427
|
+
return /* @__PURE__ */ jsxs6("figure", { ref, className: "my-3", "aria-label": entry.title ?? "Diagram", children: [
|
|
428
|
+
entry.title ? /* @__PURE__ */ jsx10("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
|
|
429
|
+
/* @__PURE__ */ jsx10(
|
|
279
430
|
"pre",
|
|
280
431
|
{
|
|
281
432
|
"data-mermaid": true,
|
|
@@ -289,24 +440,24 @@ function MermaidSource({ entry, ref }) {
|
|
|
289
440
|
function DocMermaid({ entry }) {
|
|
290
441
|
const renderers = useBuiltinRenderers();
|
|
291
442
|
if (renderers.mermaid) {
|
|
292
|
-
return /* @__PURE__ */
|
|
443
|
+
return /* @__PURE__ */ jsx10(Fragment3, { children: renderers.mermaid(entry) });
|
|
293
444
|
}
|
|
294
|
-
return /* @__PURE__ */
|
|
445
|
+
return /* @__PURE__ */ jsx10(MermaidSource, { entry });
|
|
295
446
|
}
|
|
296
447
|
|
|
297
448
|
// src/components/doc/DocScreenshot.tsx
|
|
298
|
-
import { jsx as
|
|
449
|
+
import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
299
450
|
function DocScreenshot({ entry }) {
|
|
300
451
|
const src = isLocalFsPath(entry.path) ? void 0 : safeImageUrl(entry.path);
|
|
301
452
|
if (!src) {
|
|
302
|
-
return /* @__PURE__ */
|
|
303
|
-
/* @__PURE__ */
|
|
304
|
-
/* @__PURE__ */
|
|
305
|
-
entry.alt ? /* @__PURE__ */
|
|
453
|
+
return /* @__PURE__ */ jsxs7("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
|
|
454
|
+
/* @__PURE__ */ jsx11("div", { className: "font-medium", children: "Screenshot unavailable" }),
|
|
455
|
+
/* @__PURE__ */ jsx11("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
|
|
456
|
+
entry.alt ? /* @__PURE__ */ jsx11("figcaption", { className: "mt-1.5 text-xs", children: entry.alt }) : null
|
|
306
457
|
] });
|
|
307
458
|
}
|
|
308
|
-
return /* @__PURE__ */
|
|
309
|
-
/* @__PURE__ */
|
|
459
|
+
return /* @__PURE__ */ jsxs7("figure", { className: "my-3", children: [
|
|
460
|
+
/* @__PURE__ */ jsx11(
|
|
310
461
|
"img",
|
|
311
462
|
{
|
|
312
463
|
src,
|
|
@@ -315,24 +466,24 @@ function DocScreenshot({ entry }) {
|
|
|
315
466
|
className: "max-w-full rounded-md border border-border"
|
|
316
467
|
}
|
|
317
468
|
),
|
|
318
|
-
entry.alt ? /* @__PURE__ */
|
|
469
|
+
entry.alt ? /* @__PURE__ */ jsx11("figcaption", { className: "mt-1.5 text-xs text-muted-foreground", children: entry.alt }) : null
|
|
319
470
|
] });
|
|
320
471
|
}
|
|
321
472
|
|
|
322
473
|
// src/components/doc/DocVideo.tsx
|
|
323
|
-
import { jsx as
|
|
474
|
+
import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
324
475
|
function DocVideo({ entry }) {
|
|
325
476
|
if (isLocalFsPath(entry.path)) {
|
|
326
|
-
return /* @__PURE__ */
|
|
327
|
-
/* @__PURE__ */
|
|
328
|
-
/* @__PURE__ */
|
|
329
|
-
entry.caption ? /* @__PURE__ */
|
|
477
|
+
return /* @__PURE__ */ jsxs8("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
|
|
478
|
+
/* @__PURE__ */ jsx12("div", { className: "font-medium", children: "Video unavailable" }),
|
|
479
|
+
/* @__PURE__ */ jsx12("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
|
|
480
|
+
entry.caption ? /* @__PURE__ */ jsx12("figcaption", { className: "mt-1.5 text-xs", children: entry.caption }) : null
|
|
330
481
|
] });
|
|
331
482
|
}
|
|
332
483
|
const src = safeUrl(entry.path);
|
|
333
484
|
const poster = safeUrl(entry.poster);
|
|
334
|
-
return /* @__PURE__ */
|
|
335
|
-
/* @__PURE__ */
|
|
485
|
+
return /* @__PURE__ */ jsxs8("figure", { className: "my-3", children: [
|
|
486
|
+
/* @__PURE__ */ jsx12(
|
|
336
487
|
"video",
|
|
337
488
|
{
|
|
338
489
|
controls: true,
|
|
@@ -342,21 +493,21 @@ function DocVideo({ entry }) {
|
|
|
342
493
|
className: "max-w-full rounded-md border border-border"
|
|
343
494
|
}
|
|
344
495
|
),
|
|
345
|
-
entry.caption ? /* @__PURE__ */
|
|
496
|
+
entry.caption ? /* @__PURE__ */ jsx12("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: entry.caption }) : null
|
|
346
497
|
] });
|
|
347
498
|
}
|
|
348
499
|
|
|
349
500
|
// src/components/doc/DocHtml.tsx
|
|
350
|
-
import { jsx as
|
|
501
|
+
import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
351
502
|
function DocHtml({ entry }) {
|
|
352
503
|
const height = typeof entry.height === "number" ? `${entry.height}px` : entry.height ?? "400px";
|
|
353
504
|
const title = entry.title ?? "Embedded HTML";
|
|
354
505
|
const safeHref = safeUrl(entry.url ?? entry.path);
|
|
355
506
|
const frameProps = entry.content !== void 0 ? { srcDoc: entry.content } : { src: safeHref ?? "" };
|
|
356
|
-
return /* @__PURE__ */
|
|
357
|
-
/* @__PURE__ */
|
|
358
|
-
/* @__PURE__ */
|
|
359
|
-
safeHref ? /* @__PURE__ */
|
|
507
|
+
return /* @__PURE__ */ jsxs9("figure", { className: "my-3 overflow-hidden rounded-md border border-border", children: [
|
|
508
|
+
/* @__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: [
|
|
509
|
+
/* @__PURE__ */ jsx13("span", { children: entry.title ?? "HTML" }),
|
|
510
|
+
safeHref ? /* @__PURE__ */ jsx13(
|
|
360
511
|
"a",
|
|
361
512
|
{
|
|
362
513
|
href: safeHref,
|
|
@@ -369,7 +520,7 @@ function DocHtml({ entry }) {
|
|
|
369
520
|
}
|
|
370
521
|
) : null
|
|
371
522
|
] }),
|
|
372
|
-
/* @__PURE__ */
|
|
523
|
+
/* @__PURE__ */ jsx13(
|
|
373
524
|
"iframe",
|
|
374
525
|
{
|
|
375
526
|
...frameProps,
|
|
@@ -384,7 +535,7 @@ function DocHtml({ entry }) {
|
|
|
384
535
|
}
|
|
385
536
|
|
|
386
537
|
// src/components/doc/DocState.tsx
|
|
387
|
-
import { jsx as
|
|
538
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
388
539
|
function DocState({ entry }) {
|
|
389
540
|
let json;
|
|
390
541
|
try {
|
|
@@ -392,23 +543,23 @@ function DocState({ entry }) {
|
|
|
392
543
|
} catch {
|
|
393
544
|
json = String(entry.value);
|
|
394
545
|
}
|
|
395
|
-
return /* @__PURE__ */
|
|
546
|
+
return /* @__PURE__ */ jsx14(CodeFigure, { label: entry.label ?? "State", children: /* @__PURE__ */ jsx14("code", { className: "font-mono text-xs language-json", children: json }) });
|
|
396
547
|
}
|
|
397
548
|
|
|
398
549
|
// src/components/doc/DocCustom.tsx
|
|
399
|
-
import { Fragment as Fragment4, jsx as
|
|
550
|
+
import { Fragment as Fragment4, jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
400
551
|
function DocCustom({ entry }) {
|
|
401
552
|
const renderers = useCustomRenderers();
|
|
402
553
|
const renderer = renderers[entry.type];
|
|
403
554
|
if (renderer) {
|
|
404
|
-
return /* @__PURE__ */
|
|
555
|
+
return /* @__PURE__ */ jsx15(Fragment4, { children: renderer(entry) });
|
|
405
556
|
}
|
|
406
|
-
return /* @__PURE__ */
|
|
407
|
-
/* @__PURE__ */
|
|
408
|
-
/* @__PURE__ */
|
|
557
|
+
return /* @__PURE__ */ jsxs10("div", { className: "my-2", "data-type": entry.type, children: [
|
|
558
|
+
/* @__PURE__ */ jsx15("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: entry.type }),
|
|
559
|
+
/* @__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
560
|
] });
|
|
410
561
|
}
|
|
411
|
-
function
|
|
562
|
+
function safeStringify2(value) {
|
|
412
563
|
try {
|
|
413
564
|
return JSON.stringify(value, null, 2);
|
|
414
565
|
} catch {
|
|
@@ -417,47 +568,47 @@ function safeStringify(value) {
|
|
|
417
568
|
}
|
|
418
569
|
|
|
419
570
|
// src/components/doc/DocEntry.tsx
|
|
420
|
-
import { jsx as
|
|
571
|
+
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
421
572
|
function DocEntry({ entry }) {
|
|
422
573
|
switch (entry.kind) {
|
|
423
574
|
case "note":
|
|
424
|
-
return /* @__PURE__ */
|
|
575
|
+
return /* @__PURE__ */ jsx16(DocNote, { entry });
|
|
425
576
|
case "tag":
|
|
426
|
-
return /* @__PURE__ */
|
|
577
|
+
return /* @__PURE__ */ jsx16(DocTag, { entry });
|
|
427
578
|
case "kv":
|
|
428
|
-
return /* @__PURE__ */
|
|
579
|
+
return /* @__PURE__ */ jsx16(DocKv, { entry });
|
|
429
580
|
case "code":
|
|
430
|
-
return /* @__PURE__ */
|
|
581
|
+
return /* @__PURE__ */ jsx16(DocCode, { entry });
|
|
431
582
|
case "table":
|
|
432
|
-
return /* @__PURE__ */
|
|
583
|
+
return /* @__PURE__ */ jsx16(DocTable, { entry });
|
|
433
584
|
case "link":
|
|
434
|
-
return /* @__PURE__ */
|
|
585
|
+
return /* @__PURE__ */ jsx16(DocLink, { entry });
|
|
435
586
|
case "section":
|
|
436
|
-
return /* @__PURE__ */
|
|
587
|
+
return /* @__PURE__ */ jsx16(DocSection, { entry });
|
|
437
588
|
case "mermaid":
|
|
438
|
-
return /* @__PURE__ */
|
|
589
|
+
return /* @__PURE__ */ jsx16(DocMermaid, { entry });
|
|
439
590
|
case "screenshot":
|
|
440
|
-
return /* @__PURE__ */
|
|
591
|
+
return /* @__PURE__ */ jsx16(DocScreenshot, { entry });
|
|
441
592
|
case "video":
|
|
442
|
-
return /* @__PURE__ */
|
|
593
|
+
return /* @__PURE__ */ jsx16(DocVideo, { entry });
|
|
443
594
|
case "html":
|
|
444
|
-
return /* @__PURE__ */
|
|
595
|
+
return /* @__PURE__ */ jsx16(DocHtml, { entry });
|
|
445
596
|
case "state":
|
|
446
|
-
return /* @__PURE__ */
|
|
597
|
+
return /* @__PURE__ */ jsx16(DocState, { entry });
|
|
447
598
|
case "custom":
|
|
448
|
-
return /* @__PURE__ */
|
|
599
|
+
return /* @__PURE__ */ jsx16(DocCustom, { entry });
|
|
449
600
|
}
|
|
450
601
|
}
|
|
451
602
|
|
|
452
603
|
// src/components/ReportDocEntries.tsx
|
|
453
|
-
import { Fragment as Fragment5, jsx as
|
|
604
|
+
import { Fragment as Fragment5, jsx as jsx17 } from "react/jsx-runtime";
|
|
454
605
|
function ReportDocEntries({ entries }) {
|
|
455
606
|
if (entries.length === 0) return null;
|
|
456
|
-
return /* @__PURE__ */
|
|
607
|
+
return /* @__PURE__ */ jsx17(Fragment5, { children: entries.map((entry, i) => /* @__PURE__ */ jsx17(DocEntry, { entry }, i)) });
|
|
457
608
|
}
|
|
458
609
|
|
|
459
610
|
// src/lib/step-params.tsx
|
|
460
|
-
import { jsx as
|
|
611
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
461
612
|
var STEP_PARAM_PATTERN = /"[^"]*"|(?<![\w.-])\d+(?:\.\d+)?(?![\w.-])/g;
|
|
462
613
|
function highlightStepParams(text) {
|
|
463
614
|
const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));
|
|
@@ -469,7 +620,7 @@ function highlightStepParams(text) {
|
|
|
469
620
|
const end = start + match[0].length;
|
|
470
621
|
if (start > lastIndex) nodes.push(text.slice(lastIndex, start));
|
|
471
622
|
nodes.push(
|
|
472
|
-
/* @__PURE__ */
|
|
623
|
+
/* @__PURE__ */ jsx18("span", { className: "font-medium text-step-param italic", children: match[0] }, i)
|
|
473
624
|
);
|
|
474
625
|
lastIndex = end;
|
|
475
626
|
});
|
|
@@ -478,7 +629,7 @@ function highlightStepParams(text) {
|
|
|
478
629
|
}
|
|
479
630
|
|
|
480
631
|
// src/components/ReportSteps.tsx
|
|
481
|
-
import { jsx as
|
|
632
|
+
import { jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
482
633
|
var STEP_GLYPH = {
|
|
483
634
|
passed: "\u2713",
|
|
484
635
|
failed: "\u2717",
|
|
@@ -493,21 +644,21 @@ var STEP_GLYPH_COLOR = {
|
|
|
493
644
|
};
|
|
494
645
|
function ReportSteps({ scenario }) {
|
|
495
646
|
if (scenario.steps.length === 0) return null;
|
|
496
|
-
return /* @__PURE__ */
|
|
647
|
+
return /* @__PURE__ */ jsx19("ol", { "data-slot": "steps", className: "flex flex-col", children: scenario.steps.map((step) => /* @__PURE__ */ jsx19(ReportStepItem, { step }, step.id)) });
|
|
497
648
|
}
|
|
498
649
|
function ReportStepItem({ step }) {
|
|
499
650
|
const kw = step.keyword.toLowerCase();
|
|
500
651
|
const continuation = kw === "and" || kw === "but";
|
|
501
|
-
return /* @__PURE__ */
|
|
652
|
+
return /* @__PURE__ */ jsxs11(
|
|
502
653
|
"li",
|
|
503
654
|
{
|
|
504
655
|
id: step.id,
|
|
505
656
|
"data-status": step.status,
|
|
506
657
|
className: cn("py-1.5 text-[0.8125rem] leading-normal", continuation && "pl-5"),
|
|
507
658
|
children: [
|
|
508
|
-
/* @__PURE__ */
|
|
509
|
-
/* @__PURE__ */
|
|
510
|
-
/* @__PURE__ */
|
|
659
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex items-baseline gap-2", children: [
|
|
660
|
+
/* @__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" }),
|
|
661
|
+
/* @__PURE__ */ jsx19(
|
|
511
662
|
"span",
|
|
512
663
|
{
|
|
513
664
|
className: cn(
|
|
@@ -517,10 +668,10 @@ function ReportStepItem({ step }) {
|
|
|
517
668
|
children: step.keyword
|
|
518
669
|
}
|
|
519
670
|
),
|
|
520
|
-
/* @__PURE__ */
|
|
521
|
-
step.durationMs > 0 ? /* @__PURE__ */
|
|
671
|
+
/* @__PURE__ */ jsx19("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
|
|
672
|
+
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
673
|
] }),
|
|
523
|
-
step.errorMessage ? /* @__PURE__ */
|
|
674
|
+
step.errorMessage ? /* @__PURE__ */ jsx19(
|
|
524
675
|
"pre",
|
|
525
676
|
{
|
|
526
677
|
role: "alert",
|
|
@@ -528,132 +679,17 @@ function ReportStepItem({ step }) {
|
|
|
528
679
|
children: step.errorMessage
|
|
529
680
|
}
|
|
530
681
|
) : null,
|
|
531
|
-
step.docEntries.length > 0 ? /* @__PURE__ */
|
|
682
|
+
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
683
|
]
|
|
533
684
|
}
|
|
534
685
|
);
|
|
535
686
|
}
|
|
536
687
|
|
|
537
|
-
// ../executable-stories-core/dist/state-diff.js
|
|
538
|
-
var isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
539
|
-
function deepEqual(a, b) {
|
|
540
|
-
if (Object.is(a, b)) return true;
|
|
541
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
542
|
-
return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
|
|
543
|
-
}
|
|
544
|
-
if (isPlainObject(a) && isPlainObject(b)) {
|
|
545
|
-
const ak = Object.keys(a);
|
|
546
|
-
const bk = Object.keys(b);
|
|
547
|
-
return ak.length === bk.length && ak.every((k) => k in b && deepEqual(a[k], b[k]));
|
|
548
|
-
}
|
|
549
|
-
return false;
|
|
550
|
-
}
|
|
551
|
-
var joinKey = (path, key) => path === "" ? key : `${path}.${key}`;
|
|
552
|
-
function walk(path, before, after, out) {
|
|
553
|
-
if (Object.is(before, after)) return;
|
|
554
|
-
if (Array.isArray(before) && Array.isArray(after)) {
|
|
555
|
-
const shared = Math.min(before.length, after.length);
|
|
556
|
-
for (let i = 0; i < shared; i++) walk(`${path}[${i}]`, before[i], after[i], out);
|
|
557
|
-
for (let i = shared; i < after.length; i++) out.push({ path: `${path}[${i}]`, kind: "added", after: after[i] });
|
|
558
|
-
for (let i = shared; i < before.length; i++) out.push({ path: `${path}[${i}]`, kind: "removed", before: before[i] });
|
|
559
|
-
return;
|
|
560
|
-
}
|
|
561
|
-
if (isPlainObject(before) && isPlainObject(after)) {
|
|
562
|
-
for (const key of Object.keys(after)) {
|
|
563
|
-
const p = joinKey(path, key);
|
|
564
|
-
if (key in before) walk(p, before[key], after[key], out);
|
|
565
|
-
else out.push({ path: p, kind: "added", after: after[key] });
|
|
566
|
-
}
|
|
567
|
-
for (const key of Object.keys(before)) {
|
|
568
|
-
if (!(key in after)) out.push({ path: joinKey(path, key), kind: "removed", before: before[key] });
|
|
569
|
-
}
|
|
570
|
-
return;
|
|
571
|
-
}
|
|
572
|
-
if (!deepEqual(before, after)) out.push({ path, kind: "changed", before, after });
|
|
573
|
-
}
|
|
574
|
-
function diffStateValues(before, after) {
|
|
575
|
-
const out = [];
|
|
576
|
-
walk("", before, after, out);
|
|
577
|
-
return out;
|
|
578
|
-
}
|
|
579
|
-
function formatStateValue(value, maxLen = 60) {
|
|
580
|
-
const s = value === void 0 ? "undefined" : JSON.stringify(value);
|
|
581
|
-
return s.length > maxLen ? `${s.slice(0, maxLen - 1)}\u2026` : s;
|
|
582
|
-
}
|
|
583
|
-
function summarizeStateChanges(changes) {
|
|
584
|
-
return changes.map((c) => {
|
|
585
|
-
const at = c.path === "" ? "(root)" : c.path;
|
|
586
|
-
switch (c.kind) {
|
|
587
|
-
case "added":
|
|
588
|
-
return `+ ${at}: ${formatStateValue(c.after)}`;
|
|
589
|
-
case "removed":
|
|
590
|
-
return `\u2212 ${at}`;
|
|
591
|
-
case "changed":
|
|
592
|
-
return `${at}: ${formatStateValue(c.before)} \u2192 ${formatStateValue(c.after)}`;
|
|
593
|
-
}
|
|
594
|
-
});
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
// ../executable-stories-core/dist/storyboard.js
|
|
598
|
-
function findScreenshot(entries) {
|
|
599
|
-
for (const entry of entries) {
|
|
600
|
-
if (entry.kind === "screenshot") return entry;
|
|
601
|
-
if (entry.children) {
|
|
602
|
-
const nested = findScreenshot(entry.children);
|
|
603
|
-
if (nested) return nested;
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
return void 0;
|
|
607
|
-
}
|
|
608
|
-
function findStates(entries, out = []) {
|
|
609
|
-
for (const entry of entries) {
|
|
610
|
-
if (entry.kind === "state") out.push(entry);
|
|
611
|
-
if (entry.children) findStates(entry.children, out);
|
|
612
|
-
}
|
|
613
|
-
return out;
|
|
614
|
-
}
|
|
615
|
-
var laneOf = (label) => label ?? "";
|
|
616
|
-
function extractStoryboardFrames(scenario) {
|
|
617
|
-
const frames = [];
|
|
618
|
-
const laneOrder = [];
|
|
619
|
-
const previous = /* @__PURE__ */ new Map();
|
|
620
|
-
for (const step of scenario.steps) {
|
|
621
|
-
const shot = findScreenshot(step.docEntries);
|
|
622
|
-
const stateDocs = findStates(step.docEntries);
|
|
623
|
-
if (!shot && stateDocs.length === 0) continue;
|
|
624
|
-
const byLane = /* @__PURE__ */ new Map();
|
|
625
|
-
for (const doc of stateDocs) {
|
|
626
|
-
const lane = laneOf(doc.label);
|
|
627
|
-
if (!byLane.has(lane) && !laneOrder.includes(lane)) laneOrder.push(lane);
|
|
628
|
-
byLane.set(lane, doc);
|
|
629
|
-
}
|
|
630
|
-
const states = [];
|
|
631
|
-
for (const lane of laneOrder) {
|
|
632
|
-
const doc = byLane.get(lane);
|
|
633
|
-
if (!doc) continue;
|
|
634
|
-
const card = {
|
|
635
|
-
...doc.label !== void 0 && { label: doc.label },
|
|
636
|
-
value: doc.value
|
|
637
|
-
};
|
|
638
|
-
if (previous.has(lane)) card.changes = diffStateValues(previous.get(lane), doc.value);
|
|
639
|
-
previous.set(lane, doc.value);
|
|
640
|
-
states.push(card);
|
|
641
|
-
}
|
|
642
|
-
frames.push({
|
|
643
|
-
stepId: step.id,
|
|
644
|
-
stepIndex: step.index,
|
|
645
|
-
keyword: step.keyword,
|
|
646
|
-
text: step.text,
|
|
647
|
-
status: step.status,
|
|
648
|
-
...shot && { screenshot: { path: shot.path, ...shot.alt !== void 0 && { alt: shot.alt } } },
|
|
649
|
-
states
|
|
650
|
-
});
|
|
651
|
-
}
|
|
652
|
-
return frames;
|
|
653
|
-
}
|
|
654
|
-
|
|
655
688
|
// src/components/ReportStoryboard.tsx
|
|
656
|
-
import {
|
|
689
|
+
import { extractStoryboardFrames } from "executable-stories-core/storyboard";
|
|
690
|
+
import { summarizeStateChanges } from "executable-stories-core/state-diff";
|
|
691
|
+
import { isLocalFsPath as isLocalFsPath2, safeImageUrl as safeImageUrl2 } from "executable-stories-core/utils/url";
|
|
692
|
+
import { jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
657
693
|
var FRAME_GLYPH = {
|
|
658
694
|
passed: "\u2713",
|
|
659
695
|
failed: "\u2717",
|
|
@@ -669,46 +705,46 @@ var FRAME_GLYPH_COLOR = {
|
|
|
669
705
|
function ReportStoryboard({ scenario }) {
|
|
670
706
|
const frames = extractStoryboardFrames(scenario);
|
|
671
707
|
if (frames.length < 2) return null;
|
|
672
|
-
return /* @__PURE__ */
|
|
673
|
-
/* @__PURE__ */
|
|
674
|
-
/* @__PURE__ */
|
|
708
|
+
return /* @__PURE__ */ jsxs12("section", { "data-slot": "storyboard", "aria-label": "Storyboard", className: "mb-3", children: [
|
|
709
|
+
/* @__PURE__ */ jsx20("h4", { className: "mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Storyboard" }),
|
|
710
|
+
/* @__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
711
|
] });
|
|
676
712
|
}
|
|
677
713
|
function StoryboardFrameItem({ frame }) {
|
|
678
714
|
const label = `${frame.keyword} ${frame.text}`;
|
|
679
715
|
const hasStates = frame.states.length > 0;
|
|
680
|
-
const caption = /* @__PURE__ */
|
|
681
|
-
/* @__PURE__ */
|
|
682
|
-
/* @__PURE__ */
|
|
683
|
-
/* @__PURE__ */
|
|
716
|
+
const caption = /* @__PURE__ */ jsxs12("p", { className: "mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug", children: [
|
|
717
|
+
/* @__PURE__ */ jsx20("span", { "aria-hidden": true, className: cn("shrink-0", FRAME_GLYPH_COLOR[frame.status]), children: FRAME_GLYPH[frame.status] ?? "\u25CB" }),
|
|
718
|
+
/* @__PURE__ */ jsxs12("span", { className: "min-w-0", children: [
|
|
719
|
+
/* @__PURE__ */ jsx20("span", { className: "font-mono font-semibold text-keyword", children: frame.keyword }),
|
|
684
720
|
" ",
|
|
685
|
-
/* @__PURE__ */
|
|
721
|
+
/* @__PURE__ */ jsx20("span", { className: "text-muted-foreground", children: frame.screenshot?.alt ?? frame.text })
|
|
686
722
|
] })
|
|
687
723
|
] });
|
|
688
724
|
return (
|
|
689
725
|
// State cards need room for diff rows; screenshot-only frames keep the
|
|
690
726
|
// original narrow film-cell width (and DOM) unchanged.
|
|
691
|
-
/* @__PURE__ */
|
|
692
|
-
frame.screenshot ? /* @__PURE__ */
|
|
693
|
-
hasStates ? /* @__PURE__ */
|
|
727
|
+
/* @__PURE__ */ jsxs12("li", { className: cn("shrink-0", hasStates ? "w-64" : "w-40"), children: [
|
|
728
|
+
frame.screenshot ? /* @__PURE__ */ jsx20(FrameScreenshot, { frame, label }) : null,
|
|
729
|
+
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
730
|
frame.screenshot ? caption : (
|
|
695
731
|
// No screenshot means no image anchor, so the caption carries the
|
|
696
732
|
// jump-to-step link instead.
|
|
697
|
-
/* @__PURE__ */
|
|
733
|
+
/* @__PURE__ */ jsx20("a", { href: `#${frame.stepId}`, "aria-label": `Jump to step: ${label}`, className: "block hover:underline", children: caption })
|
|
698
734
|
)
|
|
699
735
|
] })
|
|
700
736
|
);
|
|
701
737
|
}
|
|
702
738
|
function FrameScreenshot({ frame, label }) {
|
|
703
739
|
const path = frame.screenshot?.path ?? "";
|
|
704
|
-
const src =
|
|
705
|
-
return /* @__PURE__ */
|
|
740
|
+
const src = isLocalFsPath2(path) ? void 0 : safeImageUrl2(path);
|
|
741
|
+
return /* @__PURE__ */ jsx20(
|
|
706
742
|
"a",
|
|
707
743
|
{
|
|
708
744
|
href: `#${frame.stepId}`,
|
|
709
745
|
"aria-label": `Jump to step: ${label}`,
|
|
710
746
|
className: "block overflow-hidden rounded-md border border-border transition-colors hover:border-ring",
|
|
711
|
-
children: src ? /* @__PURE__ */
|
|
747
|
+
children: src ? /* @__PURE__ */ jsx20(
|
|
712
748
|
"img",
|
|
713
749
|
{
|
|
714
750
|
src,
|
|
@@ -716,7 +752,7 @@ function FrameScreenshot({ frame, label }) {
|
|
|
716
752
|
loading: "lazy",
|
|
717
753
|
className: "h-24 w-full bg-muted object-cover object-top"
|
|
718
754
|
}
|
|
719
|
-
) : /* @__PURE__ */
|
|
755
|
+
) : /* @__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
756
|
}
|
|
721
757
|
);
|
|
722
758
|
}
|
|
@@ -735,12 +771,12 @@ function prettyJson(value) {
|
|
|
735
771
|
function StateCardView({ card }) {
|
|
736
772
|
const json = prettyJson(card.value);
|
|
737
773
|
const firstCapture = card.changes === void 0;
|
|
738
|
-
return /* @__PURE__ */
|
|
739
|
-
/* @__PURE__ */
|
|
740
|
-
/* @__PURE__ */
|
|
741
|
-
firstCapture ? /* @__PURE__ */
|
|
774
|
+
return /* @__PURE__ */ jsxs12("div", { "data-slot": "state-card", className: "rounded-md border border-border bg-card p-2", children: [
|
|
775
|
+
/* @__PURE__ */ jsxs12("p", { className: "flex flex-wrap items-baseline gap-1.5", children: [
|
|
776
|
+
/* @__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" }),
|
|
777
|
+
firstCapture ? /* @__PURE__ */ jsx20("span", { className: "text-[0.625rem] text-muted-foreground italic", children: "first capture" }) : null
|
|
742
778
|
] }),
|
|
743
|
-
!firstCapture && (card.changes && card.changes.length > 0 ? /* @__PURE__ */
|
|
779
|
+
!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
780
|
"li",
|
|
745
781
|
{
|
|
746
782
|
className: cn(
|
|
@@ -750,15 +786,15 @@ function StateCardView({ card }) {
|
|
|
750
786
|
children: summarizeStateChanges([change])[0]
|
|
751
787
|
},
|
|
752
788
|
i
|
|
753
|
-
)) }) : /* @__PURE__ */
|
|
754
|
-
/* @__PURE__ */
|
|
789
|
+
)) }) : /* @__PURE__ */ jsx20("p", { className: "mt-1.5 text-[0.625rem] text-muted-foreground", children: "No changes" })),
|
|
790
|
+
/* @__PURE__ */ jsxs12(
|
|
755
791
|
"details",
|
|
756
792
|
{
|
|
757
793
|
open: firstCapture && json.length <= 240,
|
|
758
794
|
className: cn(firstCapture ? "mt-1.5" : "mt-1"),
|
|
759
795
|
children: [
|
|
760
|
-
/* @__PURE__ */
|
|
761
|
-
/* @__PURE__ */
|
|
796
|
+
/* @__PURE__ */ jsx20("summary", { className: "cursor-pointer text-[0.625rem] text-muted-foreground hover:text-foreground", children: "Snapshot" }),
|
|
797
|
+
/* @__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
798
|
]
|
|
763
799
|
}
|
|
764
800
|
)
|
|
@@ -766,17 +802,17 @@ function StateCardView({ card }) {
|
|
|
766
802
|
}
|
|
767
803
|
|
|
768
804
|
// src/components/ReportAttachments.tsx
|
|
769
|
-
import { Fragment as Fragment6, jsx as
|
|
805
|
+
import { Fragment as Fragment6, jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
770
806
|
function ReportAttachments({ attachments }) {
|
|
771
807
|
if (attachments.length === 0) return null;
|
|
772
808
|
return (
|
|
773
809
|
// role="group" (not a labelled <section>) so multiple scenarios' attachment
|
|
774
810
|
// blocks don't create duplicate "Attachments" region landmarks.
|
|
775
|
-
/* @__PURE__ */
|
|
811
|
+
/* @__PURE__ */ jsx21("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
|
|
776
812
|
const dataUri = att.contentEncoding === "BASE64" ? `data:${att.mediaType};base64,${att.body}` : `data:${att.mediaType},${encodeURIComponent(att.body)}`;
|
|
777
813
|
const isImage = att.mediaType.startsWith("image/");
|
|
778
|
-
return /* @__PURE__ */
|
|
779
|
-
/* @__PURE__ */
|
|
814
|
+
return /* @__PURE__ */ jsx21("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ jsxs13(Fragment6, { children: [
|
|
815
|
+
/* @__PURE__ */ jsx21(
|
|
780
816
|
"img",
|
|
781
817
|
{
|
|
782
818
|
src: dataUri,
|
|
@@ -785,8 +821,8 @@ function ReportAttachments({ attachments }) {
|
|
|
785
821
|
className: "max-w-full rounded-md border border-border"
|
|
786
822
|
}
|
|
787
823
|
),
|
|
788
|
-
/* @__PURE__ */
|
|
789
|
-
] }) : /* @__PURE__ */
|
|
824
|
+
/* @__PURE__ */ jsx21("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
|
|
825
|
+
] }) : /* @__PURE__ */ jsxs13(
|
|
790
826
|
"a",
|
|
791
827
|
{
|
|
792
828
|
href: dataUri,
|
|
@@ -795,7 +831,7 @@ function ReportAttachments({ attachments }) {
|
|
|
795
831
|
children: [
|
|
796
832
|
att.name,
|
|
797
833
|
" ",
|
|
798
|
-
/* @__PURE__ */
|
|
834
|
+
/* @__PURE__ */ jsxs13("span", { className: "text-muted-foreground", children: [
|
|
799
835
|
"(",
|
|
800
836
|
att.mediaType,
|
|
801
837
|
")"
|
|
@@ -807,6 +843,9 @@ function ReportAttachments({ attachments }) {
|
|
|
807
843
|
);
|
|
808
844
|
}
|
|
809
845
|
|
|
846
|
+
// src/components/ReportTrace.tsx
|
|
847
|
+
import { formatDuration as formatDuration2 } from "executable-stories-core/utils/duration";
|
|
848
|
+
|
|
810
849
|
// src/lib/trace.ts
|
|
811
850
|
var VALID = /* @__PURE__ */ new Set(["ok", "error", "unset"]);
|
|
812
851
|
var safeStatus = (s) => VALID.has(s) ? s : "unset";
|
|
@@ -859,15 +898,15 @@ function toTraceRows(spans) {
|
|
|
859
898
|
roots.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);
|
|
860
899
|
const rows = [];
|
|
861
900
|
const seen = /* @__PURE__ */ new Set();
|
|
862
|
-
const
|
|
901
|
+
const walk = (node, depth) => {
|
|
863
902
|
if (seen.has(node.span.spanId)) return;
|
|
864
903
|
seen.add(node.span.spanId);
|
|
865
904
|
rows.push({ ...node.span, depth });
|
|
866
|
-
for (const child of node.children)
|
|
905
|
+
for (const child of node.children) walk(child, depth + 1);
|
|
867
906
|
};
|
|
868
|
-
for (const root of roots)
|
|
907
|
+
for (const root of roots) walk(root, 0);
|
|
869
908
|
for (const node of byId.values()) {
|
|
870
|
-
if (!seen.has(node.span.spanId))
|
|
909
|
+
if (!seen.has(node.span.spanId)) walk(node, 0);
|
|
871
910
|
}
|
|
872
911
|
return rows;
|
|
873
912
|
}
|
|
@@ -883,7 +922,7 @@ function traceWindow(rows) {
|
|
|
883
922
|
}
|
|
884
923
|
|
|
885
924
|
// src/components/ReportTrace.tsx
|
|
886
|
-
import { jsx as
|
|
925
|
+
import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
887
926
|
var BAR_COLOR = {
|
|
888
927
|
ok: "bg-pass",
|
|
889
928
|
error: "bg-fail",
|
|
@@ -894,21 +933,21 @@ function ReportTrace({ spans }) {
|
|
|
894
933
|
const rows = toTraceRows(spans);
|
|
895
934
|
if (rows.length === 0) return null;
|
|
896
935
|
const { minStartMs, totalMs } = traceWindow(rows);
|
|
897
|
-
return /* @__PURE__ */
|
|
898
|
-
/* @__PURE__ */
|
|
936
|
+
return /* @__PURE__ */ jsxs14("details", { className: "mt-3 rounded-md border border-border bg-muted/30", children: [
|
|
937
|
+
/* @__PURE__ */ jsxs14("summary", { className: "cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground", children: [
|
|
899
938
|
"Trace (",
|
|
900
939
|
rows.length,
|
|
901
940
|
" span",
|
|
902
941
|
rows.length === 1 ? "" : "s",
|
|
903
942
|
", ",
|
|
904
|
-
|
|
943
|
+
formatDuration2(totalMs),
|
|
905
944
|
")"
|
|
906
945
|
] }),
|
|
907
|
-
/* @__PURE__ */
|
|
946
|
+
/* @__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
947
|
const leftPct = (row.startTimeMs - minStartMs) / totalMs * 100;
|
|
909
948
|
const widthPct = Math.max(row.durationMs / totalMs * 100, 0.5);
|
|
910
|
-
return /* @__PURE__ */
|
|
911
|
-
/* @__PURE__ */
|
|
949
|
+
return /* @__PURE__ */ jsxs14("li", { className: "flex items-center gap-2", children: [
|
|
950
|
+
/* @__PURE__ */ jsx22(
|
|
912
951
|
"span",
|
|
913
952
|
{
|
|
914
953
|
className: "min-w-0 flex-1 truncate text-foreground",
|
|
@@ -917,14 +956,14 @@ function ReportTrace({ spans }) {
|
|
|
917
956
|
children: row.name
|
|
918
957
|
}
|
|
919
958
|
),
|
|
920
|
-
/* @__PURE__ */
|
|
959
|
+
/* @__PURE__ */ jsx22("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ jsx22(
|
|
921
960
|
"span",
|
|
922
961
|
{
|
|
923
962
|
className: cn("absolute top-0 h-full rounded-sm", BAR_COLOR[row.status]),
|
|
924
963
|
style: { left: `${leftPct}%`, width: `${widthPct}%` }
|
|
925
964
|
}
|
|
926
965
|
) }),
|
|
927
|
-
/* @__PURE__ */
|
|
966
|
+
/* @__PURE__ */ jsx22("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration2(row.durationMs) })
|
|
928
967
|
] }, `${row.spanId}-${i}`);
|
|
929
968
|
}) })
|
|
930
969
|
] });
|
|
@@ -993,7 +1032,7 @@ function diffSinceLastRun(history, scenarios) {
|
|
|
993
1032
|
}
|
|
994
1033
|
|
|
995
1034
|
// src/components/ScenarioRunHistory.tsx
|
|
996
|
-
import { Fragment as Fragment7, jsx as
|
|
1035
|
+
import { Fragment as Fragment7, jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
997
1036
|
var MAX_DOTS = 10;
|
|
998
1037
|
var DOT_COLOR = {
|
|
999
1038
|
passed: "bg-pass",
|
|
@@ -1013,16 +1052,16 @@ function ScenarioRunHistory({ scenarioId }) {
|
|
|
1013
1052
|
const recent = entries.slice(-MAX_DOTS);
|
|
1014
1053
|
const flaky = flakinessOf(recent) === "flaky";
|
|
1015
1054
|
const summary = flaky ? `${describeRunHistory(recent)} \xB7 Flaky` : describeRunHistory(recent);
|
|
1016
|
-
return /* @__PURE__ */
|
|
1017
|
-
flaky ? /* @__PURE__ */
|
|
1018
|
-
/* @__PURE__ */
|
|
1055
|
+
return /* @__PURE__ */ jsxs15(Fragment7, { children: [
|
|
1056
|
+
flaky ? /* @__PURE__ */ jsx23(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
|
|
1057
|
+
/* @__PURE__ */ jsx23(
|
|
1019
1058
|
"span",
|
|
1020
1059
|
{
|
|
1021
1060
|
role: "img",
|
|
1022
1061
|
"aria-label": `Run history: ${summary}`,
|
|
1023
1062
|
title: summary,
|
|
1024
1063
|
className: "flex shrink-0 items-center gap-[3px]",
|
|
1025
|
-
children: recent.map((e, i) => /* @__PURE__ */
|
|
1064
|
+
children: recent.map((e, i) => /* @__PURE__ */ jsx23(
|
|
1026
1065
|
"span",
|
|
1027
1066
|
{
|
|
1028
1067
|
"aria-hidden": true,
|
|
@@ -1100,130 +1139,14 @@ function useCollapseState(computeDefault) {
|
|
|
1100
1139
|
|
|
1101
1140
|
// src/interactive/scenario-actions.tsx
|
|
1102
1141
|
import { createContext as createContext4, useContext as useContext5 } from "react";
|
|
1103
|
-
|
|
1104
|
-
// ../executable-stories-core/dist/utils/scenario-markdown.js
|
|
1105
|
-
function cell(value) {
|
|
1106
|
-
return value.replaceAll("|", "\\|").replaceAll("\n", " ");
|
|
1107
|
-
}
|
|
1108
|
-
function stringify(value) {
|
|
1109
|
-
if (typeof value === "string") return value;
|
|
1110
|
-
try {
|
|
1111
|
-
return JSON.stringify(value, null, 2) ?? String(value);
|
|
1112
|
-
} catch {
|
|
1113
|
-
return String(value);
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
|
-
function docEntryToMarkdown(entry, stateLanes) {
|
|
1117
|
-
const lines = [];
|
|
1118
|
-
switch (entry.kind) {
|
|
1119
|
-
case "note":
|
|
1120
|
-
lines.push(entry.text);
|
|
1121
|
-
break;
|
|
1122
|
-
case "tag":
|
|
1123
|
-
lines.push(entry.names.map((n) => `\`@${n}\``).join(" "));
|
|
1124
|
-
break;
|
|
1125
|
-
case "kv":
|
|
1126
|
-
lines.push(`**${entry.label}:** ${stringify(entry.value)}`);
|
|
1127
|
-
break;
|
|
1128
|
-
case "code":
|
|
1129
|
-
lines.push(`**${entry.label}**`, "", "```" + (entry.lang ?? ""), entry.content, "```");
|
|
1130
|
-
break;
|
|
1131
|
-
case "table": {
|
|
1132
|
-
lines.push(`**${entry.label}**`, "");
|
|
1133
|
-
lines.push(`| ${entry.columns.map(cell).join(" | ")} |`);
|
|
1134
|
-
lines.push(`| ${entry.columns.map(() => "---").join(" | ")} |`);
|
|
1135
|
-
for (const row of entry.rows) lines.push(`| ${row.map(cell).join(" | ")} |`);
|
|
1136
|
-
break;
|
|
1137
|
-
}
|
|
1138
|
-
case "link":
|
|
1139
|
-
lines.push(`[${entry.label}](${entry.url})`);
|
|
1140
|
-
break;
|
|
1141
|
-
case "section":
|
|
1142
|
-
lines.push(`### ${entry.title}`, "", entry.markdown);
|
|
1143
|
-
break;
|
|
1144
|
-
case "mermaid":
|
|
1145
|
-
if (entry.title) lines.push(`**${entry.title}**`, "");
|
|
1146
|
-
lines.push("```mermaid", entry.code, "```");
|
|
1147
|
-
break;
|
|
1148
|
-
case "screenshot":
|
|
1149
|
-
lines.push(``);
|
|
1150
|
-
break;
|
|
1151
|
-
case "video":
|
|
1152
|
-
lines.push(`Video: ${entry.path}${entry.caption ? ` \u2014 ${entry.caption}` : ""}`);
|
|
1153
|
-
break;
|
|
1154
|
-
case "html": {
|
|
1155
|
-
const htmlTitle = entry.title ?? "Embedded HTML";
|
|
1156
|
-
if (entry.content) {
|
|
1157
|
-
lines.push(`**${htmlTitle}**`, "", "```html", entry.content, "```");
|
|
1158
|
-
} else if (entry.url) {
|
|
1159
|
-
lines.push(`[${htmlTitle}](${entry.url})`);
|
|
1160
|
-
} else {
|
|
1161
|
-
lines.push(`Embedded HTML: ${entry.path ?? "(inline)"}`);
|
|
1162
|
-
}
|
|
1163
|
-
break;
|
|
1164
|
-
}
|
|
1165
|
-
case "custom":
|
|
1166
|
-
lines.push(`**${entry.type}**`, "", "```json", stringify(entry.data), "```");
|
|
1167
|
-
break;
|
|
1168
|
-
case "state": {
|
|
1169
|
-
const lane = entry.label ?? "";
|
|
1170
|
-
lines.push(`**${entry.label ?? "State"}**`);
|
|
1171
|
-
if (stateLanes?.has(lane)) {
|
|
1172
|
-
const summary = summarizeStateChanges(diffStateValues(stateLanes.get(lane), entry.value));
|
|
1173
|
-
if (summary.length > 0) lines.push("", ...summary.map((l) => `- ${l}`));
|
|
1174
|
-
}
|
|
1175
|
-
stateLanes?.set(lane, entry.value);
|
|
1176
|
-
lines.push("", "<details>", "<summary>snapshot</summary>", "", "```json", stringify(entry.value ?? null), "```", "", "</details>");
|
|
1177
|
-
break;
|
|
1178
|
-
}
|
|
1179
|
-
}
|
|
1180
|
-
for (const child of entry.children ?? []) {
|
|
1181
|
-
lines.push("", ...docEntryToMarkdown(child, stateLanes));
|
|
1182
|
-
}
|
|
1183
|
-
return lines;
|
|
1184
|
-
}
|
|
1185
|
-
function stepLines(step, ordinal, full, stateLanes) {
|
|
1186
|
-
const status = step.status === "passed" ? "" : ` \u2014 **${step.status}**`;
|
|
1187
|
-
const lines = [`${ordinal}. **${step.keyword}** ${step.text}${status}`];
|
|
1188
|
-
if (!full) return lines;
|
|
1189
|
-
if (step.errorMessage) {
|
|
1190
|
-
lines.push(...step.errorMessage.split("\n").map((l) => ` > ${l}`));
|
|
1191
|
-
}
|
|
1192
|
-
for (const entry of step.docEntries) {
|
|
1193
|
-
lines.push("", ...docEntryToMarkdown(entry, stateLanes).map((l) => l === "" ? l : ` ${l}`));
|
|
1194
|
-
}
|
|
1195
|
-
return lines;
|
|
1196
|
-
}
|
|
1197
|
-
function scenarioToMarkdown(scenario, options = {}) {
|
|
1198
|
-
const { variant = "full", meta = [] } = options;
|
|
1199
|
-
const full = variant === "full";
|
|
1200
|
-
const lines = full ? [`# ${scenario.title}`, ""] : [`## ${scenario.title} _(${scenario.status})_`, ""];
|
|
1201
|
-
if (full && meta.length > 0) lines.push(...meta);
|
|
1202
|
-
const stateLanes = /* @__PURE__ */ new Map();
|
|
1203
|
-
if (scenario.steps.length > 0) {
|
|
1204
|
-
if (full) lines.push("", "## Steps", "");
|
|
1205
|
-
scenario.steps.forEach((step, i) => lines.push(...stepLines(step, i + 1, full, stateLanes)));
|
|
1206
|
-
}
|
|
1207
|
-
if (scenario.errorMessage) {
|
|
1208
|
-
if (full) lines.push("", "## Failure", "");
|
|
1209
|
-
else lines.push("");
|
|
1210
|
-
lines.push("```", scenario.errorMessage.trim(), "```");
|
|
1211
|
-
}
|
|
1212
|
-
if (full && scenario.docEntries.length > 0) {
|
|
1213
|
-
lines.push("", "## Docs", "");
|
|
1214
|
-
for (const entry of scenario.docEntries) lines.push(...docEntryToMarkdown(entry, stateLanes), "");
|
|
1215
|
-
}
|
|
1216
|
-
return lines.join("\n").replaceAll(/\n{3,}/g, "\n\n").trimEnd() + (full ? "\n" : "");
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
// src/interactive/scenario-actions.tsx
|
|
1142
|
+
import { scenarioToMarkdown as coreScenarioToMarkdown } from "executable-stories-core/utils/scenario-markdown";
|
|
1220
1143
|
var ScenarioActionsContext = createContext4(null);
|
|
1221
1144
|
var ScenarioActionsProvider = ScenarioActionsContext.Provider;
|
|
1222
1145
|
function useScenarioActions() {
|
|
1223
1146
|
return useContext5(ScenarioActionsContext);
|
|
1224
1147
|
}
|
|
1225
|
-
function
|
|
1226
|
-
return
|
|
1148
|
+
function scenarioToMarkdown(scenario) {
|
|
1149
|
+
return coreScenarioToMarkdown(scenario, { variant: "compact" });
|
|
1227
1150
|
}
|
|
1228
1151
|
function scenarioToPrompt(scenario) {
|
|
1229
1152
|
const lines = [
|
|
@@ -1251,9 +1174,9 @@ function scenarioPermalink(scenario) {
|
|
|
1251
1174
|
|
|
1252
1175
|
// src/components/ui/card.tsx
|
|
1253
1176
|
import "react";
|
|
1254
|
-
import { jsx as
|
|
1177
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
1255
1178
|
function Card({ className, ...props }) {
|
|
1256
|
-
return /* @__PURE__ */
|
|
1179
|
+
return /* @__PURE__ */ jsx24(
|
|
1257
1180
|
"div",
|
|
1258
1181
|
{
|
|
1259
1182
|
"data-slot": "card",
|
|
@@ -1266,7 +1189,7 @@ function Card({ className, ...props }) {
|
|
|
1266
1189
|
);
|
|
1267
1190
|
}
|
|
1268
1191
|
function CardHeader({ className, ...props }) {
|
|
1269
|
-
return /* @__PURE__ */
|
|
1192
|
+
return /* @__PURE__ */ jsx24(
|
|
1270
1193
|
"div",
|
|
1271
1194
|
{
|
|
1272
1195
|
"data-slot": "card-header",
|
|
@@ -1279,7 +1202,7 @@ function CardHeader({ className, ...props }) {
|
|
|
1279
1202
|
);
|
|
1280
1203
|
}
|
|
1281
1204
|
function CardContent({ className, ...props }) {
|
|
1282
|
-
return /* @__PURE__ */
|
|
1205
|
+
return /* @__PURE__ */ jsx24(
|
|
1283
1206
|
"div",
|
|
1284
1207
|
{
|
|
1285
1208
|
"data-slot": "card-content",
|
|
@@ -1293,13 +1216,13 @@ function CardContent({ className, ...props }) {
|
|
|
1293
1216
|
import "react";
|
|
1294
1217
|
import { Menu as MenuPrimitive } from "@base-ui/react/menu";
|
|
1295
1218
|
import { CheckIcon } from "lucide-react";
|
|
1296
|
-
import { jsx as
|
|
1219
|
+
import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1297
1220
|
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
1221
|
function DropdownMenu(props) {
|
|
1299
|
-
return /* @__PURE__ */
|
|
1222
|
+
return /* @__PURE__ */ jsx25(MenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
|
|
1300
1223
|
}
|
|
1301
1224
|
function DropdownMenuTrigger(props) {
|
|
1302
|
-
return /* @__PURE__ */
|
|
1225
|
+
return /* @__PURE__ */ jsx25(MenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
|
|
1303
1226
|
}
|
|
1304
1227
|
function DropdownMenuContent({
|
|
1305
1228
|
className,
|
|
@@ -1307,14 +1230,14 @@ function DropdownMenuContent({
|
|
|
1307
1230
|
sideOffset = 4,
|
|
1308
1231
|
...props
|
|
1309
1232
|
}) {
|
|
1310
|
-
return /* @__PURE__ */
|
|
1233
|
+
return /* @__PURE__ */ jsx25(MenuPrimitive.Portal, { children: /* @__PURE__ */ jsx25(
|
|
1311
1234
|
MenuPrimitive.Positioner,
|
|
1312
1235
|
{
|
|
1313
1236
|
"data-slot": "dropdown-menu-positioner",
|
|
1314
1237
|
className: "z-50",
|
|
1315
1238
|
align,
|
|
1316
1239
|
sideOffset,
|
|
1317
|
-
children: /* @__PURE__ */
|
|
1240
|
+
children: /* @__PURE__ */ jsx25(
|
|
1318
1241
|
MenuPrimitive.Popup,
|
|
1319
1242
|
{
|
|
1320
1243
|
"data-slot": "dropdown-menu-content",
|
|
@@ -1332,7 +1255,7 @@ function DropdownMenuItem({
|
|
|
1332
1255
|
className,
|
|
1333
1256
|
...props
|
|
1334
1257
|
}) {
|
|
1335
|
-
return /* @__PURE__ */
|
|
1258
|
+
return /* @__PURE__ */ jsx25(
|
|
1336
1259
|
MenuPrimitive.Item,
|
|
1337
1260
|
{
|
|
1338
1261
|
"data-slot": "dropdown-menu-item",
|
|
@@ -1344,7 +1267,7 @@ function DropdownMenuItem({
|
|
|
1344
1267
|
|
|
1345
1268
|
// src/components/ReportScenario.tsx
|
|
1346
1269
|
import { LinkIcon, FileTextIcon, SparklesIcon, MoreHorizontalIcon } from "lucide-react";
|
|
1347
|
-
import { jsx as
|
|
1270
|
+
import { jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1348
1271
|
var STATUS_META = {
|
|
1349
1272
|
passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
|
|
1350
1273
|
failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
|
|
@@ -1360,7 +1283,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1360
1283
|
const collapsible = collapse !== null && !hideTitle;
|
|
1361
1284
|
const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
|
|
1362
1285
|
const actions = useScenarioActions();
|
|
1363
|
-
return /* @__PURE__ */
|
|
1286
|
+
return /* @__PURE__ */ jsxs17(
|
|
1364
1287
|
Card,
|
|
1365
1288
|
{
|
|
1366
1289
|
id: scenario.id,
|
|
@@ -1368,10 +1291,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1368
1291
|
...hideTitle ? { "aria-label": `${scenario.title}, ${label}` } : { "aria-labelledby": titleId },
|
|
1369
1292
|
className: "gap-0 py-0",
|
|
1370
1293
|
children: [
|
|
1371
|
-
/* @__PURE__ */
|
|
1372
|
-
/* @__PURE__ */
|
|
1373
|
-
hideTitle ? null : /* @__PURE__ */
|
|
1374
|
-
collapsible ? /* @__PURE__ */
|
|
1294
|
+
/* @__PURE__ */ jsxs17(CardHeader, { className: "px-4 py-3", children: [
|
|
1295
|
+
/* @__PURE__ */ jsxs17("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
|
|
1296
|
+
hideTitle ? null : /* @__PURE__ */ jsxs17("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
|
|
1297
|
+
collapsible ? /* @__PURE__ */ jsx26(
|
|
1375
1298
|
"button",
|
|
1376
1299
|
{
|
|
1377
1300
|
type: "button",
|
|
@@ -1380,49 +1303,49 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1380
1303
|
"aria-controls": bodyId,
|
|
1381
1304
|
"aria-label": `Toggle ${scenario.title}`,
|
|
1382
1305
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
1383
|
-
children: /* @__PURE__ */
|
|
1306
|
+
children: /* @__PURE__ */ jsx26("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
1384
1307
|
}
|
|
1385
1308
|
) : null,
|
|
1386
|
-
/* @__PURE__ */
|
|
1387
|
-
/* @__PURE__ */
|
|
1309
|
+
/* @__PURE__ */ jsx26("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
|
|
1310
|
+
/* @__PURE__ */ jsx26("span", { children: scenario.title })
|
|
1388
1311
|
] }),
|
|
1389
|
-
/* @__PURE__ */
|
|
1390
|
-
/* @__PURE__ */
|
|
1391
|
-
scenario.durationMs > 0 ? /* @__PURE__ */
|
|
1392
|
-
meta.showPill ? /* @__PURE__ */
|
|
1393
|
-
actions ? /* @__PURE__ */
|
|
1394
|
-
/* @__PURE__ */
|
|
1312
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
1313
|
+
/* @__PURE__ */ jsx26(ScenarioRunHistory, { scenarioId: scenario.id }),
|
|
1314
|
+
scenario.durationMs > 0 ? /* @__PURE__ */ jsx26("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration3(scenario.durationMs) }) : null,
|
|
1315
|
+
meta.showPill ? /* @__PURE__ */ jsx26(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ jsx26("span", { className: "sr-only", children: `Status: ${label}` }),
|
|
1316
|
+
actions ? /* @__PURE__ */ jsxs17(DropdownMenu, { children: [
|
|
1317
|
+
/* @__PURE__ */ jsx26(
|
|
1395
1318
|
DropdownMenuTrigger,
|
|
1396
1319
|
{
|
|
1397
1320
|
"aria-label": `Actions for ${scenario.title}`,
|
|
1398
1321
|
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
1399
|
-
children: /* @__PURE__ */
|
|
1322
|
+
children: /* @__PURE__ */ jsx26(MoreHorizontalIcon, { "aria-hidden": true })
|
|
1400
1323
|
}
|
|
1401
1324
|
),
|
|
1402
|
-
/* @__PURE__ */
|
|
1403
|
-
/* @__PURE__ */
|
|
1404
|
-
/* @__PURE__ */
|
|
1325
|
+
/* @__PURE__ */ jsxs17(DropdownMenuContent, { align: "end", children: [
|
|
1326
|
+
/* @__PURE__ */ jsxs17(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
|
|
1327
|
+
/* @__PURE__ */ jsx26(LinkIcon, {}),
|
|
1405
1328
|
" Copy link"
|
|
1406
1329
|
] }),
|
|
1407
|
-
/* @__PURE__ */
|
|
1408
|
-
/* @__PURE__ */
|
|
1330
|
+
/* @__PURE__ */ jsxs17(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
|
|
1331
|
+
/* @__PURE__ */ jsx26(FileTextIcon, {}),
|
|
1409
1332
|
" Copy as Markdown"
|
|
1410
1333
|
] }),
|
|
1411
|
-
/* @__PURE__ */
|
|
1412
|
-
/* @__PURE__ */
|
|
1334
|
+
/* @__PURE__ */ jsxs17(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
|
|
1335
|
+
/* @__PURE__ */ jsx26(SparklesIcon, {}),
|
|
1413
1336
|
" Explain with AI"
|
|
1414
1337
|
] })
|
|
1415
1338
|
] })
|
|
1416
1339
|
] }) : null
|
|
1417
1340
|
] })
|
|
1418
1341
|
] }),
|
|
1419
|
-
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */
|
|
1420
|
-
scenario.tags.map((t) => /* @__PURE__ */
|
|
1421
|
-
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */
|
|
1342
|
+
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: [
|
|
1343
|
+
scenario.tags.map((t) => /* @__PURE__ */ jsx26("li", { children: /* @__PURE__ */ jsx26(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
|
|
1344
|
+
(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
1345
|
] }) : null
|
|
1423
1346
|
] }),
|
|
1424
|
-
/* @__PURE__ */
|
|
1425
|
-
scenario.errorMessage ? /* @__PURE__ */
|
|
1347
|
+
/* @__PURE__ */ jsxs17(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
|
|
1348
|
+
scenario.errorMessage ? /* @__PURE__ */ jsx26(
|
|
1426
1349
|
"pre",
|
|
1427
1350
|
{
|
|
1428
1351
|
role: "alert",
|
|
@@ -1430,11 +1353,11 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1430
1353
|
children: scenario.errorMessage
|
|
1431
1354
|
}
|
|
1432
1355
|
) : null,
|
|
1433
|
-
/* @__PURE__ */
|
|
1434
|
-
/* @__PURE__ */
|
|
1435
|
-
scenario.docEntries.length > 0 ? /* @__PURE__ */
|
|
1436
|
-
/* @__PURE__ */
|
|
1437
|
-
/* @__PURE__ */
|
|
1356
|
+
/* @__PURE__ */ jsx26(ReportStoryboard, { scenario }),
|
|
1357
|
+
/* @__PURE__ */ jsx26(ReportSteps, { scenario }),
|
|
1358
|
+
scenario.docEntries.length > 0 ? /* @__PURE__ */ jsx26("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ jsx26(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
|
|
1359
|
+
/* @__PURE__ */ jsx26(ReportAttachments, { attachments: scenario.attachments }),
|
|
1360
|
+
/* @__PURE__ */ jsx26(ReportTrace, { spans: scenario.otelSpans })
|
|
1438
1361
|
] })
|
|
1439
1362
|
]
|
|
1440
1363
|
}
|
|
@@ -1442,13 +1365,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1442
1365
|
}
|
|
1443
1366
|
|
|
1444
1367
|
// src/components/ReportScenarioList.tsx
|
|
1445
|
-
import { Fragment as Fragment8, jsx as
|
|
1368
|
+
import { Fragment as Fragment8, jsx as jsx27 } from "react/jsx-runtime";
|
|
1446
1369
|
function ReportScenarioList({ feature }) {
|
|
1447
|
-
return /* @__PURE__ */
|
|
1370
|
+
return /* @__PURE__ */ jsx27(Fragment8, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ jsx27(ReportScenario, { scenario }, scenario.id)) });
|
|
1448
1371
|
}
|
|
1449
1372
|
|
|
1450
1373
|
// src/components/ReportFeature.tsx
|
|
1451
|
-
import { Fragment as Fragment9, jsx as
|
|
1374
|
+
import { Fragment as Fragment9, jsx as jsx28, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1452
1375
|
function ReportFeature({ feature }) {
|
|
1453
1376
|
const titleId = `${feature.id}-title`;
|
|
1454
1377
|
const bodyId = `${feature.id}-body`;
|
|
@@ -1459,7 +1382,7 @@ function ReportFeature({ feature }) {
|
|
|
1459
1382
|
return (
|
|
1460
1383
|
// Suite = a section heading + a divider, NOT another bordered card. Drops a
|
|
1461
1384
|
// layer of nesting so the scenario cards below read as the primary unit.
|
|
1462
|
-
/* @__PURE__ */
|
|
1385
|
+
/* @__PURE__ */ jsxs18(
|
|
1463
1386
|
"section",
|
|
1464
1387
|
{
|
|
1465
1388
|
id: feature.id,
|
|
@@ -1467,9 +1390,9 @@ function ReportFeature({ feature }) {
|
|
|
1467
1390
|
"aria-labelledby": titleId,
|
|
1468
1391
|
className: "flex flex-col gap-3",
|
|
1469
1392
|
children: [
|
|
1470
|
-
/* @__PURE__ */
|
|
1471
|
-
/* @__PURE__ */
|
|
1472
|
-
/* @__PURE__ */
|
|
1393
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
|
|
1394
|
+
/* @__PURE__ */ jsxs18("div", { className: "min-w-0", children: [
|
|
1395
|
+
/* @__PURE__ */ jsx28("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ jsxs18(
|
|
1473
1396
|
"button",
|
|
1474
1397
|
{
|
|
1475
1398
|
type: "button",
|
|
@@ -1478,31 +1401,31 @@ function ReportFeature({ feature }) {
|
|
|
1478
1401
|
"aria-controls": bodyId,
|
|
1479
1402
|
className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
|
|
1480
1403
|
children: [
|
|
1481
|
-
/* @__PURE__ */
|
|
1482
|
-
/* @__PURE__ */
|
|
1404
|
+
/* @__PURE__ */ jsx28("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
|
|
1405
|
+
/* @__PURE__ */ jsx28("span", { className: "truncate", children: feature.title })
|
|
1483
1406
|
]
|
|
1484
1407
|
}
|
|
1485
1408
|
) : feature.title }),
|
|
1486
|
-
/* @__PURE__ */
|
|
1409
|
+
/* @__PURE__ */ jsx28("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
|
|
1487
1410
|
] }),
|
|
1488
|
-
/* @__PURE__ */
|
|
1411
|
+
/* @__PURE__ */ jsxs18(
|
|
1489
1412
|
"p",
|
|
1490
1413
|
{
|
|
1491
1414
|
className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
|
|
1492
1415
|
"aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
|
|
1493
1416
|
children: [
|
|
1494
|
-
/* @__PURE__ */
|
|
1417
|
+
/* @__PURE__ */ jsxs18("span", { children: [
|
|
1495
1418
|
s.passed,
|
|
1496
1419
|
" passed"
|
|
1497
1420
|
] }),
|
|
1498
|
-
/* @__PURE__ */
|
|
1499
|
-
/* @__PURE__ */
|
|
1421
|
+
/* @__PURE__ */ jsx28("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1422
|
+
/* @__PURE__ */ jsxs18("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
|
|
1500
1423
|
s.failed,
|
|
1501
1424
|
" failed"
|
|
1502
1425
|
] }),
|
|
1503
|
-
skipped > 0 ? /* @__PURE__ */
|
|
1504
|
-
/* @__PURE__ */
|
|
1505
|
-
/* @__PURE__ */
|
|
1426
|
+
skipped > 0 ? /* @__PURE__ */ jsxs18(Fragment9, { children: [
|
|
1427
|
+
/* @__PURE__ */ jsx28("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1428
|
+
/* @__PURE__ */ jsxs18("span", { children: [
|
|
1506
1429
|
skipped,
|
|
1507
1430
|
" skipped"
|
|
1508
1431
|
] })
|
|
@@ -1511,7 +1434,7 @@ function ReportFeature({ feature }) {
|
|
|
1511
1434
|
}
|
|
1512
1435
|
)
|
|
1513
1436
|
] }),
|
|
1514
|
-
/* @__PURE__ */
|
|
1437
|
+
/* @__PURE__ */ jsx28("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ jsx28(ReportScenarioList, { feature }) })
|
|
1515
1438
|
]
|
|
1516
1439
|
}
|
|
1517
1440
|
)
|
|
@@ -1519,17 +1442,17 @@ function ReportFeature({ feature }) {
|
|
|
1519
1442
|
}
|
|
1520
1443
|
|
|
1521
1444
|
// src/components/ReportFeatureList.tsx
|
|
1522
|
-
import { jsx as
|
|
1445
|
+
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
1523
1446
|
function ReportFeatureList() {
|
|
1524
1447
|
const report = useReport();
|
|
1525
|
-
return /* @__PURE__ */
|
|
1448
|
+
return /* @__PURE__ */ jsx29("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ jsx29(ReportFeature, { feature }, feature.id)) });
|
|
1526
1449
|
}
|
|
1527
1450
|
|
|
1528
1451
|
// src/components/ui/empty.tsx
|
|
1529
1452
|
import { cva as cva2 } from "class-variance-authority";
|
|
1530
|
-
import { jsx as
|
|
1453
|
+
import { jsx as jsx30 } from "react/jsx-runtime";
|
|
1531
1454
|
function Empty({ className, ...props }) {
|
|
1532
|
-
return /* @__PURE__ */
|
|
1455
|
+
return /* @__PURE__ */ jsx30(
|
|
1533
1456
|
"div",
|
|
1534
1457
|
{
|
|
1535
1458
|
"data-slot": "empty",
|
|
@@ -1542,7 +1465,7 @@ function Empty({ className, ...props }) {
|
|
|
1542
1465
|
);
|
|
1543
1466
|
}
|
|
1544
1467
|
function EmptyHeader({ className, ...props }) {
|
|
1545
|
-
return /* @__PURE__ */
|
|
1468
|
+
return /* @__PURE__ */ jsx30(
|
|
1546
1469
|
"div",
|
|
1547
1470
|
{
|
|
1548
1471
|
"data-slot": "empty-header",
|
|
@@ -1569,7 +1492,7 @@ var emptyMediaVariants = cva2(
|
|
|
1569
1492
|
}
|
|
1570
1493
|
);
|
|
1571
1494
|
function EmptyTitle({ className, ...props }) {
|
|
1572
|
-
return /* @__PURE__ */
|
|
1495
|
+
return /* @__PURE__ */ jsx30(
|
|
1573
1496
|
"div",
|
|
1574
1497
|
{
|
|
1575
1498
|
"data-slot": "empty-title",
|
|
@@ -1580,16 +1503,16 @@ function EmptyTitle({ className, ...props }) {
|
|
|
1580
1503
|
}
|
|
1581
1504
|
|
|
1582
1505
|
// src/components/ReportEmpty.tsx
|
|
1583
|
-
import { jsx as
|
|
1506
|
+
import { jsx as jsx31 } from "react/jsx-runtime";
|
|
1584
1507
|
function ReportEmpty({ message }) {
|
|
1585
|
-
return /* @__PURE__ */
|
|
1508
|
+
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
1509
|
}
|
|
1587
1510
|
|
|
1588
1511
|
// src/components/ReportSummary.tsx
|
|
1589
|
-
import { jsx as
|
|
1512
|
+
import { jsx as jsx32, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1590
1513
|
function ReportSummary({ className }) {
|
|
1591
1514
|
const report = useReport();
|
|
1592
|
-
return /* @__PURE__ */
|
|
1515
|
+
return /* @__PURE__ */ jsx32(
|
|
1593
1516
|
ReportSummaryView,
|
|
1594
1517
|
{
|
|
1595
1518
|
summary: report.summary,
|
|
@@ -1615,7 +1538,7 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1615
1538
|
if (summary.pending > 0) {
|
|
1616
1539
|
cards.push({ status: "pending", label: "Pending", value: summary.pending });
|
|
1617
1540
|
}
|
|
1618
|
-
return /* @__PURE__ */
|
|
1541
|
+
return /* @__PURE__ */ jsx32(
|
|
1619
1542
|
"dl",
|
|
1620
1543
|
{
|
|
1621
1544
|
className: cn(
|
|
@@ -1628,17 +1551,17 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1628
1551
|
"aria-label": ariaLabel,
|
|
1629
1552
|
children: cards.map((c) => {
|
|
1630
1553
|
const tone = TONE[c.status];
|
|
1631
|
-
return /* @__PURE__ */
|
|
1554
|
+
return /* @__PURE__ */ jsxs19(
|
|
1632
1555
|
"div",
|
|
1633
1556
|
{
|
|
1634
1557
|
"data-status": c.status,
|
|
1635
1558
|
className: "rounded-lg border bg-card px-4 py-3",
|
|
1636
1559
|
children: [
|
|
1637
|
-
/* @__PURE__ */
|
|
1638
|
-
/* @__PURE__ */
|
|
1560
|
+
/* @__PURE__ */ jsxs19("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
|
|
1561
|
+
/* @__PURE__ */ jsx32("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
|
|
1639
1562
|
c.label
|
|
1640
1563
|
] }),
|
|
1641
|
-
/* @__PURE__ */
|
|
1564
|
+
/* @__PURE__ */ jsx32("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
|
|
1642
1565
|
]
|
|
1643
1566
|
},
|
|
1644
1567
|
c.status
|
|
@@ -1648,6 +1571,9 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1648
1571
|
);
|
|
1649
1572
|
}
|
|
1650
1573
|
|
|
1574
|
+
// src/components/ReportMeta.tsx
|
|
1575
|
+
import { formatDuration as formatDuration4 } from "executable-stories-core/utils/duration";
|
|
1576
|
+
|
|
1651
1577
|
// src/lib/provenance.ts
|
|
1652
1578
|
function reportLastRunMs(report) {
|
|
1653
1579
|
if (report.finishedAtMs && report.finishedAtMs > 0) return report.finishedAtMs;
|
|
@@ -1698,7 +1624,7 @@ function prUrl(ci) {
|
|
|
1698
1624
|
}
|
|
1699
1625
|
|
|
1700
1626
|
// src/components/ReportMeta.tsx
|
|
1701
|
-
import { jsx as
|
|
1627
|
+
import { jsx as jsx33, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1702
1628
|
function ReportMeta() {
|
|
1703
1629
|
const report = useReport();
|
|
1704
1630
|
const items = [];
|
|
@@ -1707,7 +1633,7 @@ function ReportMeta() {
|
|
|
1707
1633
|
items.push({ label: "Started", value: new Date(report.startedAtMs).toLocaleString() });
|
|
1708
1634
|
}
|
|
1709
1635
|
if (report.durationMs) {
|
|
1710
|
-
items.push({ label: "Duration", value:
|
|
1636
|
+
items.push({ label: "Duration", value: formatDuration4(report.durationMs) });
|
|
1711
1637
|
}
|
|
1712
1638
|
if (report.packageVersion) {
|
|
1713
1639
|
items.push({ label: "Version", value: report.packageVersion });
|
|
@@ -1721,13 +1647,13 @@ function ReportMeta() {
|
|
|
1721
1647
|
const short = sha.slice(0, 8);
|
|
1722
1648
|
items.push({
|
|
1723
1649
|
label: "Commit",
|
|
1724
|
-
value: url ? /* @__PURE__ */
|
|
1650
|
+
value: url ? /* @__PURE__ */ jsx33("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
|
|
1725
1651
|
});
|
|
1726
1652
|
}
|
|
1727
1653
|
if (report.ci) {
|
|
1728
1654
|
items.push({
|
|
1729
1655
|
label: "CI",
|
|
1730
|
-
value: report.ci.url ? /* @__PURE__ */
|
|
1656
|
+
value: report.ci.url ? /* @__PURE__ */ jsxs20("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
|
|
1731
1657
|
ciDisplayName(report.ci.name),
|
|
1732
1658
|
report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
|
|
1733
1659
|
] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
|
|
@@ -1738,7 +1664,7 @@ function ReportMeta() {
|
|
|
1738
1664
|
const label = `#${report.ci.prNumber}`;
|
|
1739
1665
|
items.push({
|
|
1740
1666
|
label: "PR",
|
|
1741
|
-
value: url ? /* @__PURE__ */
|
|
1667
|
+
value: url ? /* @__PURE__ */ jsx33("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
|
|
1742
1668
|
});
|
|
1743
1669
|
}
|
|
1744
1670
|
if (items.length === 0) return null;
|
|
@@ -1746,50 +1672,50 @@ function ReportMeta() {
|
|
|
1746
1672
|
// Run metadata is useful but secondary to "what failed" — tuck it into a
|
|
1747
1673
|
// collapsed disclosure so it doesn't push the result down. Native <details>
|
|
1748
1674
|
// so it works with no JS (the SSR/no-hydration report still toggles).
|
|
1749
|
-
/* @__PURE__ */
|
|
1750
|
-
/* @__PURE__ */
|
|
1751
|
-
/* @__PURE__ */
|
|
1675
|
+
/* @__PURE__ */ jsxs20("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
|
|
1676
|
+
/* @__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: [
|
|
1677
|
+
/* @__PURE__ */ jsx33("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
|
|
1752
1678
|
"Run details"
|
|
1753
1679
|
] }),
|
|
1754
|
-
/* @__PURE__ */
|
|
1755
|
-
/* @__PURE__ */
|
|
1756
|
-
/* @__PURE__ */
|
|
1680
|
+
/* @__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: [
|
|
1681
|
+
/* @__PURE__ */ jsx33("dt", { className: "font-medium", children: item.label }),
|
|
1682
|
+
/* @__PURE__ */ jsx33("dd", { className: "font-mono text-foreground", children: item.value })
|
|
1757
1683
|
] }, item.label)) })
|
|
1758
1684
|
] })
|
|
1759
1685
|
);
|
|
1760
1686
|
}
|
|
1761
1687
|
|
|
1762
1688
|
// src/components/ReportSchemaError.tsx
|
|
1763
|
-
import { jsx as
|
|
1689
|
+
import { jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1764
1690
|
function ReportSchemaError({ error }) {
|
|
1765
|
-
return /* @__PURE__ */
|
|
1766
|
-
/* @__PURE__ */
|
|
1767
|
-
/* @__PURE__ */
|
|
1768
|
-
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */
|
|
1691
|
+
return /* @__PURE__ */ jsxs21("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
|
|
1692
|
+
/* @__PURE__ */ jsx34("p", { children: /* @__PURE__ */ jsx34("strong", { children: "Report could not be displayed." }) }),
|
|
1693
|
+
/* @__PURE__ */ jsx34("p", { children: error.message }),
|
|
1694
|
+
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ jsxs21("p", { children: [
|
|
1769
1695
|
"The report bundle is newer than this version of ",
|
|
1770
|
-
/* @__PURE__ */
|
|
1696
|
+
/* @__PURE__ */ jsx34("code", { children: "executable-stories-react" }),
|
|
1771
1697
|
". Upgrade the package, or regenerate the report with an older formatters CLI."
|
|
1772
1698
|
] }) : null,
|
|
1773
|
-
error.issues && error.issues.length > 0 ? /* @__PURE__ */
|
|
1774
|
-
/* @__PURE__ */
|
|
1699
|
+
error.issues && error.issues.length > 0 ? /* @__PURE__ */ jsxs21("details", { children: [
|
|
1700
|
+
/* @__PURE__ */ jsxs21("summary", { children: [
|
|
1775
1701
|
error.issues.length,
|
|
1776
1702
|
" validation issue",
|
|
1777
1703
|
error.issues.length === 1 ? "" : "s"
|
|
1778
1704
|
] }),
|
|
1779
|
-
/* @__PURE__ */
|
|
1705
|
+
/* @__PURE__ */ jsx34("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
|
|
1780
1706
|
] }) : null
|
|
1781
1707
|
] });
|
|
1782
1708
|
}
|
|
1783
1709
|
|
|
1784
1710
|
// src/components/ReportShell.tsx
|
|
1785
|
-
import { Fragment as Fragment10, jsx as
|
|
1711
|
+
import { Fragment as Fragment10, jsx as jsx35, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1786
1712
|
function ReportErrorShell({
|
|
1787
1713
|
error,
|
|
1788
1714
|
className,
|
|
1789
1715
|
title,
|
|
1790
1716
|
dataTheme
|
|
1791
1717
|
}) {
|
|
1792
|
-
return /* @__PURE__ */
|
|
1718
|
+
return /* @__PURE__ */ jsx35("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ jsx35(ReportSchemaError, { error }) });
|
|
1793
1719
|
}
|
|
1794
1720
|
|
|
1795
1721
|
// src/interactive/ReportInteractive.tsx
|
|
@@ -1798,12 +1724,12 @@ import { Monitor, Moon, Sun } from "lucide-react";
|
|
|
1798
1724
|
// src/components/ui/switch.tsx
|
|
1799
1725
|
import "react";
|
|
1800
1726
|
import { Switch as SwitchPrimitive } from "@base-ui/react/switch";
|
|
1801
|
-
import { jsx as
|
|
1727
|
+
import { jsx as jsx36 } from "react/jsx-runtime";
|
|
1802
1728
|
function Switch({
|
|
1803
1729
|
className,
|
|
1804
1730
|
...props
|
|
1805
1731
|
}) {
|
|
1806
|
-
return /* @__PURE__ */
|
|
1732
|
+
return /* @__PURE__ */ jsx36(
|
|
1807
1733
|
SwitchPrimitive.Root,
|
|
1808
1734
|
{
|
|
1809
1735
|
"data-slot": "switch",
|
|
@@ -1812,7 +1738,7 @@ function Switch({
|
|
|
1812
1738
|
className
|
|
1813
1739
|
),
|
|
1814
1740
|
...props,
|
|
1815
|
-
children: /* @__PURE__ */
|
|
1741
|
+
children: /* @__PURE__ */ jsx36(
|
|
1816
1742
|
SwitchPrimitive.Thumb,
|
|
1817
1743
|
{
|
|
1818
1744
|
"data-slot": "switch-thumb",
|
|
@@ -1828,7 +1754,7 @@ import * as React5 from "react";
|
|
|
1828
1754
|
import { ToggleGroup as ToggleGroupPrimitive } from "@base-ui/react/toggle-group";
|
|
1829
1755
|
import { Toggle as TogglePrimitive } from "@base-ui/react/toggle";
|
|
1830
1756
|
import { cva as cva3 } from "class-variance-authority";
|
|
1831
|
-
import { jsx as
|
|
1757
|
+
import { jsx as jsx37 } from "react/jsx-runtime";
|
|
1832
1758
|
var toggleItemVariants = cva3(
|
|
1833
1759
|
"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
1760
|
{
|
|
@@ -1850,13 +1776,13 @@ function ToggleGroup({
|
|
|
1850
1776
|
children,
|
|
1851
1777
|
...props
|
|
1852
1778
|
}) {
|
|
1853
|
-
return /* @__PURE__ */
|
|
1779
|
+
return /* @__PURE__ */ jsx37(
|
|
1854
1780
|
ToggleGroupPrimitive,
|
|
1855
1781
|
{
|
|
1856
1782
|
"data-slot": "toggle-group",
|
|
1857
1783
|
className: cn("flex w-fit items-center gap-0.5 rounded-lg bg-muted p-0.5", className),
|
|
1858
1784
|
...props,
|
|
1859
|
-
children: /* @__PURE__ */
|
|
1785
|
+
children: /* @__PURE__ */ jsx37(ToggleGroupContext.Provider, { value: { size }, children })
|
|
1860
1786
|
}
|
|
1861
1787
|
);
|
|
1862
1788
|
}
|
|
@@ -1867,7 +1793,7 @@ function ToggleGroupItem({
|
|
|
1867
1793
|
...props
|
|
1868
1794
|
}) {
|
|
1869
1795
|
const context = React5.useContext(ToggleGroupContext);
|
|
1870
|
-
return /* @__PURE__ */
|
|
1796
|
+
return /* @__PURE__ */ jsx37(
|
|
1871
1797
|
TogglePrimitive,
|
|
1872
1798
|
{
|
|
1873
1799
|
"data-slot": "toggle-group-item",
|
|
@@ -1887,9 +1813,9 @@ import { Search } from "lucide-react";
|
|
|
1887
1813
|
|
|
1888
1814
|
// src/components/ui/input.tsx
|
|
1889
1815
|
import "react";
|
|
1890
|
-
import { jsx as
|
|
1816
|
+
import { jsx as jsx38 } from "react/jsx-runtime";
|
|
1891
1817
|
function Input({ className, type, ...props }) {
|
|
1892
|
-
return /* @__PURE__ */
|
|
1818
|
+
return /* @__PURE__ */ jsx38(
|
|
1893
1819
|
"input",
|
|
1894
1820
|
{
|
|
1895
1821
|
type,
|
|
@@ -1906,7 +1832,7 @@ function Input({ className, type, ...props }) {
|
|
|
1906
1832
|
}
|
|
1907
1833
|
|
|
1908
1834
|
// src/interactive/ReportSearch.tsx
|
|
1909
|
-
import { jsx as
|
|
1835
|
+
import { jsx as jsx39, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1910
1836
|
var ReportSearch = forwardRef(
|
|
1911
1837
|
function ReportSearch2(props, ref) {
|
|
1912
1838
|
const {
|
|
@@ -1928,17 +1854,17 @@ var ReportSearch = forwardRef(
|
|
|
1928
1854
|
e.preventDefault();
|
|
1929
1855
|
}
|
|
1930
1856
|
}
|
|
1931
|
-
return /* @__PURE__ */
|
|
1932
|
-
/* @__PURE__ */
|
|
1933
|
-
/* @__PURE__ */
|
|
1934
|
-
/* @__PURE__ */
|
|
1857
|
+
return /* @__PURE__ */ jsxs23("div", { className: cn("es-search flex flex-col gap-1", className), children: [
|
|
1858
|
+
/* @__PURE__ */ jsx39("label", { htmlFor: inputId, className: "sr-only", children: "Search" }),
|
|
1859
|
+
/* @__PURE__ */ jsxs23("div", { className: "relative w-full sm:w-72", children: [
|
|
1860
|
+
/* @__PURE__ */ jsx39(
|
|
1935
1861
|
Search,
|
|
1936
1862
|
{
|
|
1937
1863
|
"aria-hidden": true,
|
|
1938
1864
|
className: "pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground"
|
|
1939
1865
|
}
|
|
1940
1866
|
),
|
|
1941
|
-
/* @__PURE__ */
|
|
1867
|
+
/* @__PURE__ */ jsx39(
|
|
1942
1868
|
Input,
|
|
1943
1869
|
{
|
|
1944
1870
|
ref,
|
|
@@ -1955,7 +1881,7 @@ var ReportSearch = forwardRef(
|
|
|
1955
1881
|
}
|
|
1956
1882
|
)
|
|
1957
1883
|
] }),
|
|
1958
|
-
showCounts ? /* @__PURE__ */
|
|
1884
|
+
showCounts ? /* @__PURE__ */ jsxs23(
|
|
1959
1885
|
"span",
|
|
1960
1886
|
{
|
|
1961
1887
|
className: "text-xs tabular-nums text-muted-foreground",
|
|
@@ -2044,7 +1970,7 @@ function scrollToScenarioId(scenarioId, options = {}) {
|
|
|
2044
1970
|
}
|
|
2045
1971
|
|
|
2046
1972
|
// src/interactive/ReportFailureBanner.tsx
|
|
2047
|
-
import { jsx as
|
|
1973
|
+
import { jsx as jsx40, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2048
1974
|
function ReportFailureBanner({ failures }) {
|
|
2049
1975
|
const first = failures[0];
|
|
2050
1976
|
const jumpToFirst = useCallback2(() => {
|
|
@@ -2052,7 +1978,7 @@ function ReportFailureBanner({ failures }) {
|
|
|
2052
1978
|
scrollToScenarioId(first.scenarioId);
|
|
2053
1979
|
}, [first]);
|
|
2054
1980
|
if (failures.length === 0) return null;
|
|
2055
|
-
return /* @__PURE__ */
|
|
1981
|
+
return /* @__PURE__ */ jsxs24(
|
|
2056
1982
|
"div",
|
|
2057
1983
|
{
|
|
2058
1984
|
className: "es-failure-banner",
|
|
@@ -2060,13 +1986,13 @@ function ReportFailureBanner({ failures }) {
|
|
|
2060
1986
|
"aria-live": "polite",
|
|
2061
1987
|
"aria-label": "Failure summary",
|
|
2062
1988
|
children: [
|
|
2063
|
-
/* @__PURE__ */
|
|
2064
|
-
/* @__PURE__ */
|
|
1989
|
+
/* @__PURE__ */ jsxs24("span", { className: "es-failure-banner-text", children: [
|
|
1990
|
+
/* @__PURE__ */ jsx40("strong", { children: failures.length }),
|
|
2065
1991
|
" ",
|
|
2066
1992
|
"failure",
|
|
2067
1993
|
failures.length === 1 ? "" : "s"
|
|
2068
1994
|
] }),
|
|
2069
|
-
/* @__PURE__ */
|
|
1995
|
+
/* @__PURE__ */ jsx40(
|
|
2070
1996
|
"button",
|
|
2071
1997
|
{
|
|
2072
1998
|
type: "button",
|
|
@@ -2083,7 +2009,7 @@ function ReportFailureBanner({ failures }) {
|
|
|
2083
2009
|
|
|
2084
2010
|
// src/interactive/ReportFreshness.tsx
|
|
2085
2011
|
import { useEffect, useState as useState2 } from "react";
|
|
2086
|
-
import { Fragment as Fragment11, jsx as
|
|
2012
|
+
import { Fragment as Fragment11, jsx as jsx41, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2087
2013
|
function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
2088
2014
|
const [now, setNow] = useState2(nowMs);
|
|
2089
2015
|
useEffect(() => {
|
|
@@ -2091,7 +2017,7 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
2091
2017
|
}, [nowMs]);
|
|
2092
2018
|
if (lastRunMs === void 0 || now === void 0) return null;
|
|
2093
2019
|
const age = formatRelativeAge(lastRunMs, now);
|
|
2094
|
-
const runLink = ciUrl ? /* @__PURE__ */
|
|
2020
|
+
const runLink = ciUrl ? /* @__PURE__ */ jsx41(
|
|
2095
2021
|
"a",
|
|
2096
2022
|
{
|
|
2097
2023
|
href: ciUrl,
|
|
@@ -2102,9 +2028,9 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
2102
2028
|
}
|
|
2103
2029
|
) : null;
|
|
2104
2030
|
if (isReportStale(lastRunMs, staleAfterDays, now)) {
|
|
2105
|
-
return /* @__PURE__ */
|
|
2106
|
-
/* @__PURE__ */
|
|
2107
|
-
/* @__PURE__ */
|
|
2031
|
+
return /* @__PURE__ */ jsxs25("div", { className: "es-stale-banner", role: "status", "aria-label": "Report freshness", children: [
|
|
2032
|
+
/* @__PURE__ */ jsxs25("span", { children: [
|
|
2033
|
+
/* @__PURE__ */ jsxs25("strong", { children: [
|
|
2108
2034
|
"Last verified ",
|
|
2109
2035
|
age,
|
|
2110
2036
|
"."
|
|
@@ -2114,10 +2040,10 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
2114
2040
|
runLink
|
|
2115
2041
|
] });
|
|
2116
2042
|
}
|
|
2117
|
-
return /* @__PURE__ */
|
|
2043
|
+
return /* @__PURE__ */ jsxs25("p", { className: "es-freshness", "aria-label": "Report freshness", children: [
|
|
2118
2044
|
"Verified ",
|
|
2119
2045
|
age,
|
|
2120
|
-
runLink ? /* @__PURE__ */
|
|
2046
|
+
runLink ? /* @__PURE__ */ jsxs25(Fragment11, { children: [
|
|
2121
2047
|
" \xB7 ",
|
|
2122
2048
|
runLink
|
|
2123
2049
|
] }) : null
|
|
@@ -2125,15 +2051,15 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
2125
2051
|
}
|
|
2126
2052
|
|
|
2127
2053
|
// src/interactive/ReportLastRunDelta.tsx
|
|
2128
|
-
import { Fragment as Fragment12, jsx as
|
|
2054
|
+
import { Fragment as Fragment12, jsx as jsx42, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2129
2055
|
var MAX_LINKS = 5;
|
|
2130
2056
|
function ScenarioLinks({ scenarios, tone }) {
|
|
2131
|
-
return /* @__PURE__ */
|
|
2132
|
-
scenarios.slice(0, MAX_LINKS).map((s, i) => /* @__PURE__ */
|
|
2057
|
+
return /* @__PURE__ */ jsxs26(Fragment12, { children: [
|
|
2058
|
+
scenarios.slice(0, MAX_LINKS).map((s, i) => /* @__PURE__ */ jsxs26("span", { children: [
|
|
2133
2059
|
i > 0 ? ", " : "",
|
|
2134
|
-
/* @__PURE__ */
|
|
2060
|
+
/* @__PURE__ */ jsx42("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
|
|
2135
2061
|
] }, s.id)),
|
|
2136
|
-
scenarios.length > MAX_LINKS ? /* @__PURE__ */
|
|
2062
|
+
scenarios.length > MAX_LINKS ? /* @__PURE__ */ jsxs26("span", { children: [
|
|
2137
2063
|
" and ",
|
|
2138
2064
|
scenarios.length - MAX_LINKS,
|
|
2139
2065
|
" more"
|
|
@@ -2150,23 +2076,23 @@ function ReportLastRunDelta({
|
|
|
2150
2076
|
if (!delta) return null;
|
|
2151
2077
|
const { newlyFailing, newlyPassing, added } = delta;
|
|
2152
2078
|
if (newlyFailing.length === 0 && newlyPassing.length === 0 && added.length === 0) {
|
|
2153
|
-
return /* @__PURE__ */
|
|
2079
|
+
return /* @__PURE__ */ jsx42("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: "Since last run: no behavior changes." });
|
|
2154
2080
|
}
|
|
2155
|
-
return /* @__PURE__ */
|
|
2156
|
-
/* @__PURE__ */
|
|
2157
|
-
newlyFailing.length > 0 ? /* @__PURE__ */
|
|
2081
|
+
return /* @__PURE__ */ jsxs26("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: [
|
|
2082
|
+
/* @__PURE__ */ jsx42("span", { className: "font-medium text-foreground", children: "Since last run:" }),
|
|
2083
|
+
newlyFailing.length > 0 ? /* @__PURE__ */ jsxs26("span", { className: "ml-2 text-fail", children: [
|
|
2158
2084
|
newlyFailing.length,
|
|
2159
2085
|
" newly failing (",
|
|
2160
|
-
/* @__PURE__ */
|
|
2086
|
+
/* @__PURE__ */ jsx42(ScenarioLinks, { scenarios: newlyFailing, tone: "text-fail" }),
|
|
2161
2087
|
")"
|
|
2162
2088
|
] }) : null,
|
|
2163
|
-
newlyPassing.length > 0 ? /* @__PURE__ */
|
|
2089
|
+
newlyPassing.length > 0 ? /* @__PURE__ */ jsxs26("span", { className: "ml-2 text-pass", children: [
|
|
2164
2090
|
newlyPassing.length,
|
|
2165
2091
|
" fixed (",
|
|
2166
|
-
/* @__PURE__ */
|
|
2092
|
+
/* @__PURE__ */ jsx42(ScenarioLinks, { scenarios: newlyPassing, tone: "text-pass" }),
|
|
2167
2093
|
")"
|
|
2168
2094
|
] }) : null,
|
|
2169
|
-
added.length > 0 ? /* @__PURE__ */
|
|
2095
|
+
added.length > 0 ? /* @__PURE__ */ jsxs26("span", { className: "ml-2", children: [
|
|
2170
2096
|
added.length,
|
|
2171
2097
|
" new"
|
|
2172
2098
|
] }) : null
|
|
@@ -2230,7 +2156,7 @@ function Button({
|
|
|
2230
2156
|
}
|
|
2231
2157
|
|
|
2232
2158
|
// src/interactive/ReportShortcutsHelp.tsx
|
|
2233
|
-
import { jsx as
|
|
2159
|
+
import { jsx as jsx43, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2234
2160
|
var SHORTCUTS = [
|
|
2235
2161
|
{ keys: "/", description: "Focus search" },
|
|
2236
2162
|
{ keys: "f", description: "Jump to next failure" },
|
|
@@ -2242,9 +2168,9 @@ var SHORTCUTS = [
|
|
|
2242
2168
|
];
|
|
2243
2169
|
function Keys({ keys }) {
|
|
2244
2170
|
const parts = keys.split(" ");
|
|
2245
|
-
return /* @__PURE__ */
|
|
2246
|
-
i > 0 ? /* @__PURE__ */
|
|
2247
|
-
/* @__PURE__ */
|
|
2171
|
+
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: [
|
|
2172
|
+
i > 0 ? /* @__PURE__ */ jsx43("span", { className: "text-xs text-muted-foreground", children: "+" }) : null,
|
|
2173
|
+
/* @__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 })
|
|
2248
2174
|
] }, k)) });
|
|
2249
2175
|
}
|
|
2250
2176
|
function ReportShortcutsHelp({ open, onClose }) {
|
|
@@ -2255,7 +2181,7 @@ function ReportShortcutsHelp({ open, onClose }) {
|
|
|
2255
2181
|
if (open && !dialog.open) dialog.showModal();
|
|
2256
2182
|
else if (!open && dialog.open) dialog.close();
|
|
2257
2183
|
}, [open]);
|
|
2258
|
-
return /* @__PURE__ */
|
|
2184
|
+
return /* @__PURE__ */ jsxs27(
|
|
2259
2185
|
"dialog",
|
|
2260
2186
|
{
|
|
2261
2187
|
ref: dialogRef,
|
|
@@ -2263,12 +2189,12 @@ function ReportShortcutsHelp({ open, onClose }) {
|
|
|
2263
2189
|
"aria-label": "Keyboard shortcuts",
|
|
2264
2190
|
onClose,
|
|
2265
2191
|
children: [
|
|
2266
|
-
/* @__PURE__ */
|
|
2267
|
-
/* @__PURE__ */
|
|
2268
|
-
/* @__PURE__ */
|
|
2269
|
-
/* @__PURE__ */
|
|
2192
|
+
/* @__PURE__ */ jsx43("h2", { className: "text-base font-semibold", children: "Keyboard shortcuts" }),
|
|
2193
|
+
/* @__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: [
|
|
2194
|
+
/* @__PURE__ */ jsx43("dt", { className: "justify-self-start", children: /* @__PURE__ */ jsx43(Keys, { keys: s.keys }) }),
|
|
2195
|
+
/* @__PURE__ */ jsx43("dd", { className: "text-sm text-muted-foreground", children: s.description })
|
|
2270
2196
|
] }, s.keys)) }),
|
|
2271
|
-
/* @__PURE__ */
|
|
2197
|
+
/* @__PURE__ */ jsx43("form", { method: "dialog", className: "mt-6", children: /* @__PURE__ */ jsx43(Button, { type: "submit", variant: "outline", size: "sm", children: "Close" }) })
|
|
2272
2198
|
]
|
|
2273
2199
|
}
|
|
2274
2200
|
);
|
|
@@ -2471,7 +2397,7 @@ function failuresFirst(report) {
|
|
|
2471
2397
|
|
|
2472
2398
|
// src/interactive/ReportFilters.tsx
|
|
2473
2399
|
import { useState as useState3 } from "react";
|
|
2474
|
-
import { jsx as
|
|
2400
|
+
import { jsx as jsx44, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
2475
2401
|
var TAG_LIMIT = 12;
|
|
2476
2402
|
function ReportFilters({
|
|
2477
2403
|
statuses,
|
|
@@ -2485,10 +2411,10 @@ function ReportFilters({
|
|
|
2485
2411
|
if (statuses.length === 0 && tags.length === 0) return null;
|
|
2486
2412
|
const tagsCollapsed = tags.length > TAG_LIMIT && !showAllTags;
|
|
2487
2413
|
const visibleTags = tagsCollapsed ? tags.slice(0, TAG_LIMIT) : tags;
|
|
2488
|
-
return /* @__PURE__ */
|
|
2489
|
-
statuses.length > 0 ? /* @__PURE__ */
|
|
2414
|
+
return /* @__PURE__ */ jsxs28("div", { className: "flex flex-col gap-2", children: [
|
|
2415
|
+
statuses.length > 0 ? /* @__PURE__ */ jsx44("div", { role: "group", "aria-label": "Filter by status", className: "flex flex-wrap gap-1", children: statuses.map((opt) => {
|
|
2490
2416
|
const active = status === opt.key;
|
|
2491
|
-
return /* @__PURE__ */
|
|
2417
|
+
return /* @__PURE__ */ jsxs28(
|
|
2492
2418
|
"button",
|
|
2493
2419
|
{
|
|
2494
2420
|
type: "button",
|
|
@@ -2500,23 +2426,23 @@ function ReportFilters({
|
|
|
2500
2426
|
),
|
|
2501
2427
|
children: [
|
|
2502
2428
|
opt.label,
|
|
2503
|
-
/* @__PURE__ */
|
|
2429
|
+
/* @__PURE__ */ jsx44("span", { className: "ml-1 font-mono opacity-70", children: opt.count })
|
|
2504
2430
|
]
|
|
2505
2431
|
},
|
|
2506
2432
|
opt.key
|
|
2507
2433
|
);
|
|
2508
2434
|
}) }) : null,
|
|
2509
|
-
tags.length > 0 ? /* @__PURE__ */
|
|
2435
|
+
tags.length > 0 ? /* @__PURE__ */ jsxs28("ul", { "aria-label": "Filter by tag", className: "flex flex-wrap items-center gap-1.5", children: [
|
|
2510
2436
|
visibleTags.map((tag) => {
|
|
2511
2437
|
const active = activeTags.includes(tag);
|
|
2512
|
-
return /* @__PURE__ */
|
|
2438
|
+
return /* @__PURE__ */ jsx44("li", { children: /* @__PURE__ */ jsx44(
|
|
2513
2439
|
"button",
|
|
2514
2440
|
{
|
|
2515
2441
|
type: "button",
|
|
2516
2442
|
"aria-pressed": active,
|
|
2517
2443
|
onClick: () => onToggleTag(tag),
|
|
2518
2444
|
className: "cursor-pointer",
|
|
2519
|
-
children: /* @__PURE__ */
|
|
2445
|
+
children: /* @__PURE__ */ jsx44(
|
|
2520
2446
|
Badge,
|
|
2521
2447
|
{
|
|
2522
2448
|
variant: "tag",
|
|
@@ -2529,7 +2455,7 @@ function ReportFilters({
|
|
|
2529
2455
|
}
|
|
2530
2456
|
) }, tag);
|
|
2531
2457
|
}),
|
|
2532
|
-
tags.length > TAG_LIMIT ? /* @__PURE__ */
|
|
2458
|
+
tags.length > TAG_LIMIT ? /* @__PURE__ */ jsx44("li", { children: /* @__PURE__ */ jsx44(
|
|
2533
2459
|
"button",
|
|
2534
2460
|
{
|
|
2535
2461
|
type: "button",
|
|
@@ -2545,7 +2471,7 @@ function ReportFilters({
|
|
|
2545
2471
|
|
|
2546
2472
|
// src/interactive/ReportToc.tsx
|
|
2547
2473
|
import { useEffect as useEffect5, useMemo as useMemo2, useState as useState4 } from "react";
|
|
2548
|
-
import { jsx as
|
|
2474
|
+
import { jsx as jsx45, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
2549
2475
|
var DOT = {
|
|
2550
2476
|
passed: "bg-pass",
|
|
2551
2477
|
failed: "bg-fail",
|
|
@@ -2574,11 +2500,11 @@ function TocContent({ onNavigate }) {
|
|
|
2574
2500
|
return () => observer.disconnect();
|
|
2575
2501
|
}, [scenarioIds]);
|
|
2576
2502
|
if (report.features.length === 0) return null;
|
|
2577
|
-
return /* @__PURE__ */
|
|
2578
|
-
/* @__PURE__ */
|
|
2579
|
-
/* @__PURE__ */
|
|
2503
|
+
return /* @__PURE__ */ jsx45("ul", { className: "flex list-none flex-col gap-4 pl-0", children: report.features.map((feature) => /* @__PURE__ */ jsxs29("li", { children: [
|
|
2504
|
+
/* @__PURE__ */ jsx45("p", { className: "mb-1.5 font-semibold leading-snug text-foreground", children: feature.title }),
|
|
2505
|
+
/* @__PURE__ */ jsx45("ul", { className: "flex list-none flex-col gap-0.5 pl-0", children: feature.scenarios.map((scenario) => {
|
|
2580
2506
|
const active = activeId === scenario.id;
|
|
2581
|
-
return /* @__PURE__ */
|
|
2507
|
+
return /* @__PURE__ */ jsx45("li", { children: /* @__PURE__ */ jsxs29(
|
|
2582
2508
|
"a",
|
|
2583
2509
|
{
|
|
2584
2510
|
href: `#${scenario.id}`,
|
|
@@ -2593,14 +2519,14 @@ function TocContent({ onNavigate }) {
|
|
|
2593
2519
|
active ? "border-primary font-medium text-foreground" : "border-border text-muted-foreground"
|
|
2594
2520
|
),
|
|
2595
2521
|
children: [
|
|
2596
|
-
/* @__PURE__ */
|
|
2522
|
+
/* @__PURE__ */ jsx45(
|
|
2597
2523
|
"span",
|
|
2598
2524
|
{
|
|
2599
2525
|
"aria-hidden": true,
|
|
2600
2526
|
className: cn("mt-1 size-1.5 shrink-0 rounded-full", DOT[scenario.status])
|
|
2601
2527
|
}
|
|
2602
2528
|
),
|
|
2603
|
-
/* @__PURE__ */
|
|
2529
|
+
/* @__PURE__ */ jsx45("span", { className: "break-words", children: scenario.title })
|
|
2604
2530
|
]
|
|
2605
2531
|
}
|
|
2606
2532
|
) }, scenario.id);
|
|
@@ -2610,14 +2536,14 @@ function TocContent({ onNavigate }) {
|
|
|
2610
2536
|
function ReportToc() {
|
|
2611
2537
|
const report = useReport();
|
|
2612
2538
|
if (report.features.length === 0) return null;
|
|
2613
|
-
return /* @__PURE__ */
|
|
2539
|
+
return /* @__PURE__ */ jsxs29(
|
|
2614
2540
|
"nav",
|
|
2615
2541
|
{
|
|
2616
2542
|
"aria-label": "Table of contents",
|
|
2617
2543
|
className: "sticky top-4 hidden h-fit w-64 shrink-0 self-start text-xs lg:block",
|
|
2618
2544
|
children: [
|
|
2619
|
-
/* @__PURE__ */
|
|
2620
|
-
/* @__PURE__ */
|
|
2545
|
+
/* @__PURE__ */ jsx45("p", { className: "mb-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Contents" }),
|
|
2546
|
+
/* @__PURE__ */ jsx45(TocContent, {})
|
|
2621
2547
|
]
|
|
2622
2548
|
}
|
|
2623
2549
|
);
|
|
@@ -2627,31 +2553,31 @@ function ReportToc() {
|
|
|
2627
2553
|
import { useState as useState5 } from "react";
|
|
2628
2554
|
import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
|
|
2629
2555
|
import { ListIcon, XIcon } from "lucide-react";
|
|
2630
|
-
import { jsx as
|
|
2556
|
+
import { jsx as jsx46, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
2631
2557
|
function ReportTocDrawer() {
|
|
2632
2558
|
const report = useReport();
|
|
2633
2559
|
const [open, setOpen] = useState5(false);
|
|
2634
2560
|
if (report.features.length === 0) return null;
|
|
2635
|
-
return /* @__PURE__ */
|
|
2636
|
-
/* @__PURE__ */
|
|
2637
|
-
/* @__PURE__ */
|
|
2561
|
+
return /* @__PURE__ */ jsxs30(DialogPrimitive.Root, { open, onOpenChange: setOpen, children: [
|
|
2562
|
+
/* @__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: [
|
|
2563
|
+
/* @__PURE__ */ jsx46(ListIcon, { "aria-hidden": true }),
|
|
2638
2564
|
" Contents"
|
|
2639
2565
|
] }),
|
|
2640
|
-
/* @__PURE__ */
|
|
2641
|
-
/* @__PURE__ */
|
|
2642
|
-
/* @__PURE__ */
|
|
2643
|
-
/* @__PURE__ */
|
|
2644
|
-
/* @__PURE__ */
|
|
2645
|
-
/* @__PURE__ */
|
|
2566
|
+
/* @__PURE__ */ jsxs30(DialogPrimitive.Portal, { children: [
|
|
2567
|
+
/* @__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" }),
|
|
2568
|
+
/* @__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: [
|
|
2569
|
+
/* @__PURE__ */ jsxs30("div", { className: "flex items-center justify-between", children: [
|
|
2570
|
+
/* @__PURE__ */ jsx46(DialogPrimitive.Title, { className: "text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Contents" }),
|
|
2571
|
+
/* @__PURE__ */ jsx46(
|
|
2646
2572
|
DialogPrimitive.Close,
|
|
2647
2573
|
{
|
|
2648
2574
|
"aria-label": "Close contents",
|
|
2649
2575
|
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
2650
|
-
children: /* @__PURE__ */
|
|
2576
|
+
children: /* @__PURE__ */ jsx46(XIcon, { "aria-hidden": true })
|
|
2651
2577
|
}
|
|
2652
2578
|
)
|
|
2653
2579
|
] }),
|
|
2654
|
-
/* @__PURE__ */
|
|
2580
|
+
/* @__PURE__ */ jsx46(TocContent, { onNavigate: () => setOpen(false) })
|
|
2655
2581
|
] })
|
|
2656
2582
|
] })
|
|
2657
2583
|
] });
|
|
@@ -2734,14 +2660,14 @@ function useUrlState() {
|
|
|
2734
2660
|
}
|
|
2735
2661
|
|
|
2736
2662
|
// src/interactive/ReportInteractive.tsx
|
|
2737
|
-
import { Fragment as Fragment13, jsx as
|
|
2663
|
+
import { Fragment as Fragment13, jsx as jsx47, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
2738
2664
|
function ReportInteractive(props) {
|
|
2739
2665
|
const { report, className, title, dataTheme } = props;
|
|
2740
2666
|
const result = unwrapReport(report);
|
|
2741
2667
|
if (!result.ok) {
|
|
2742
|
-
return /* @__PURE__ */
|
|
2668
|
+
return /* @__PURE__ */ jsx47(ReportErrorShell, { error: result.error, className, title, dataTheme });
|
|
2743
2669
|
}
|
|
2744
|
-
return /* @__PURE__ */
|
|
2670
|
+
return /* @__PURE__ */ jsx47(ReportInteractiveView, { ...props, report: result.data });
|
|
2745
2671
|
}
|
|
2746
2672
|
var THEME_OPTIONS = [
|
|
2747
2673
|
{ value: "light", label: "Light", Icon: Sun },
|
|
@@ -2749,7 +2675,7 @@ var THEME_OPTIONS = [
|
|
|
2749
2675
|
{ value: "dark", label: "Dark", Icon: Moon }
|
|
2750
2676
|
];
|
|
2751
2677
|
function ThemeSegment({ pref, onPref }) {
|
|
2752
|
-
return /* @__PURE__ */
|
|
2678
|
+
return /* @__PURE__ */ jsx47(
|
|
2753
2679
|
ToggleGroup,
|
|
2754
2680
|
{
|
|
2755
2681
|
size: "sm",
|
|
@@ -2759,7 +2685,7 @@ function ThemeSegment({ pref, onPref }) {
|
|
|
2759
2685
|
if (next) onPref(next);
|
|
2760
2686
|
},
|
|
2761
2687
|
"aria-label": "Color theme",
|
|
2762
|
-
children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */
|
|
2688
|
+
children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */ jsx47(ToggleGroupItem, { value, "aria-label": label, title: label, className: "px-2", children: /* @__PURE__ */ jsx47(Icon, {}) }, value))
|
|
2763
2689
|
}
|
|
2764
2690
|
);
|
|
2765
2691
|
}
|
|
@@ -2836,7 +2762,7 @@ function ReportInteractiveView({
|
|
|
2836
2762
|
const scenarioActions = useMemo3(
|
|
2837
2763
|
() => ({
|
|
2838
2764
|
copyLink: (s) => copy(scenarioPermalink(s), "Link copied"),
|
|
2839
|
-
copyMarkdown: (s) => copy(
|
|
2765
|
+
copyMarkdown: (s) => copy(scenarioToMarkdown(s), "Markdown copied"),
|
|
2840
2766
|
copyPrompt: (s) => copy(scenarioToPrompt(s), "Prompt copied")
|
|
2841
2767
|
}),
|
|
2842
2768
|
[copy]
|
|
@@ -2890,13 +2816,13 @@ function ReportInteractiveView({
|
|
|
2890
2816
|
const totalScenarios = report.summary.total;
|
|
2891
2817
|
const matchedScenarios = filtered.summary.total;
|
|
2892
2818
|
const showToc = !hideToc && totalScenarios > 3;
|
|
2893
|
-
return /* @__PURE__ */
|
|
2819
|
+
return /* @__PURE__ */ jsx47(CollapseProvider, { value: collapse.api, children: /* @__PURE__ */ jsx47(ScenarioActionsProvider, { value: scenarioActions, children: /* @__PURE__ */ jsx47(ScenarioHistoryProvider, { value: scenarioHistory ?? null, children: /* @__PURE__ */ jsx47(
|
|
2894
2820
|
ReportRoot,
|
|
2895
2821
|
{
|
|
2896
2822
|
report: filtered,
|
|
2897
2823
|
customRenderers,
|
|
2898
2824
|
renderers,
|
|
2899
|
-
children: /* @__PURE__ */
|
|
2825
|
+
children: /* @__PURE__ */ jsxs31(
|
|
2900
2826
|
"main",
|
|
2901
2827
|
{
|
|
2902
2828
|
className: cn("es-report", "es-report-interactive", className),
|
|
@@ -2905,8 +2831,8 @@ function ReportInteractiveView({
|
|
|
2905
2831
|
"data-theme": dataTheme,
|
|
2906
2832
|
"data-detail-level": detail,
|
|
2907
2833
|
children: [
|
|
2908
|
-
/* @__PURE__ */
|
|
2909
|
-
/* @__PURE__ */
|
|
2834
|
+
/* @__PURE__ */ jsxs31("header", { className: "es-report-header", children: [
|
|
2835
|
+
/* @__PURE__ */ jsxs31(
|
|
2910
2836
|
"div",
|
|
2911
2837
|
{
|
|
2912
2838
|
"data-es-navbar": true,
|
|
@@ -2915,9 +2841,9 @@ function ReportInteractiveView({
|
|
|
2915
2841
|
hideHeader ? "justify-end" : "justify-between"
|
|
2916
2842
|
),
|
|
2917
2843
|
children: [
|
|
2918
|
-
hideHeader ? null : /* @__PURE__ */
|
|
2919
|
-
/* @__PURE__ */
|
|
2920
|
-
/* @__PURE__ */
|
|
2844
|
+
hideHeader ? null : /* @__PURE__ */ jsx47("h1", { className: "min-w-0", children: title ?? "Story Report" }),
|
|
2845
|
+
/* @__PURE__ */ jsxs31("div", { className: "flex items-center gap-2", children: [
|
|
2846
|
+
/* @__PURE__ */ jsx47(
|
|
2921
2847
|
ReportSearch,
|
|
2922
2848
|
{
|
|
2923
2849
|
ref: searchRef,
|
|
@@ -2927,16 +2853,16 @@ function ReportInteractiveView({
|
|
|
2927
2853
|
totalCount: totalScenarios
|
|
2928
2854
|
}
|
|
2929
2855
|
),
|
|
2930
|
-
/* @__PURE__ */
|
|
2856
|
+
/* @__PURE__ */ jsx47(ThemeSegment, { pref: themePref, onPref: setThemePref })
|
|
2931
2857
|
] })
|
|
2932
2858
|
]
|
|
2933
2859
|
}
|
|
2934
2860
|
),
|
|
2935
|
-
hideHeader ? null : /* @__PURE__ */
|
|
2936
|
-
/* @__PURE__ */
|
|
2937
|
-
/* @__PURE__ */
|
|
2861
|
+
hideHeader ? null : /* @__PURE__ */ jsxs31(Fragment13, { children: [
|
|
2862
|
+
/* @__PURE__ */ jsx47(ReportSummary, {}),
|
|
2863
|
+
/* @__PURE__ */ jsx47(ReportMeta, {})
|
|
2938
2864
|
] }),
|
|
2939
|
-
/* @__PURE__ */
|
|
2865
|
+
/* @__PURE__ */ jsx47(
|
|
2940
2866
|
ReportFreshness,
|
|
2941
2867
|
{
|
|
2942
2868
|
lastRunMs: reportLastRunMs(report),
|
|
@@ -2944,8 +2870,8 @@ function ReportInteractiveView({
|
|
|
2944
2870
|
staleAfterDays
|
|
2945
2871
|
}
|
|
2946
2872
|
),
|
|
2947
|
-
/* @__PURE__ */
|
|
2948
|
-
/* @__PURE__ */
|
|
2873
|
+
/* @__PURE__ */ jsx47(ReportLastRunDelta, { history: scenarioHistory, report }),
|
|
2874
|
+
/* @__PURE__ */ jsx47(
|
|
2949
2875
|
ReportFilters,
|
|
2950
2876
|
{
|
|
2951
2877
|
statuses: statusOptions,
|
|
@@ -2956,14 +2882,14 @@ function ReportInteractiveView({
|
|
|
2956
2882
|
onToggleTag: toggleTag
|
|
2957
2883
|
}
|
|
2958
2884
|
),
|
|
2959
|
-
/* @__PURE__ */
|
|
2960
|
-
showToc ? /* @__PURE__ */
|
|
2961
|
-
/* @__PURE__ */
|
|
2962
|
-
/* @__PURE__ */
|
|
2963
|
-
/* @__PURE__ */
|
|
2885
|
+
/* @__PURE__ */ jsxs31("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-2 border-t border-border/60 pt-3", children: [
|
|
2886
|
+
showToc ? /* @__PURE__ */ jsx47(ReportTocDrawer, {}) : null,
|
|
2887
|
+
/* @__PURE__ */ jsxs31("div", { className: "flex items-center gap-2", children: [
|
|
2888
|
+
/* @__PURE__ */ jsx47(Switch, { id: expandId, checked: expandedAll, onCheckedChange: setExpanded }),
|
|
2889
|
+
/* @__PURE__ */ jsx47("label", { htmlFor: expandId, className: "cursor-pointer text-sm text-muted-foreground select-none", children: "Expand all" })
|
|
2964
2890
|
] }),
|
|
2965
|
-
/* @__PURE__ */
|
|
2966
|
-
/* @__PURE__ */
|
|
2891
|
+
/* @__PURE__ */ jsxs31("div", { className: "flex items-center gap-2", children: [
|
|
2892
|
+
/* @__PURE__ */ jsx47(
|
|
2967
2893
|
Switch,
|
|
2968
2894
|
{
|
|
2969
2895
|
id: docsId,
|
|
@@ -2971,16 +2897,16 @@ function ReportInteractiveView({
|
|
|
2971
2897
|
onCheckedChange: (checked) => setDetail(checked ? "full" : "minimal")
|
|
2972
2898
|
}
|
|
2973
2899
|
),
|
|
2974
|
-
/* @__PURE__ */
|
|
2900
|
+
/* @__PURE__ */ jsx47("label", { htmlFor: docsId, className: "cursor-pointer text-sm text-muted-foreground select-none", children: "Show documentation" })
|
|
2975
2901
|
] })
|
|
2976
2902
|
] })
|
|
2977
2903
|
] }),
|
|
2978
|
-
/* @__PURE__ */
|
|
2979
|
-
hasContent ? showToc ? /* @__PURE__ */
|
|
2980
|
-
/* @__PURE__ */
|
|
2981
|
-
/* @__PURE__ */
|
|
2982
|
-
] }) : /* @__PURE__ */
|
|
2983
|
-
/* @__PURE__ */
|
|
2904
|
+
/* @__PURE__ */ jsx47(ReportFailureBanner, { failures }),
|
|
2905
|
+
hasContent ? showToc ? /* @__PURE__ */ jsxs31("div", { className: "flex gap-6", children: [
|
|
2906
|
+
/* @__PURE__ */ jsx47(ReportToc, {}),
|
|
2907
|
+
/* @__PURE__ */ jsx47("div", { className: "flex min-w-0 flex-1 flex-col gap-4", children: /* @__PURE__ */ jsx47(ReportFeatureList, {}) })
|
|
2908
|
+
] }) : /* @__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 }),
|
|
2909
|
+
/* @__PURE__ */ jsx47(
|
|
2984
2910
|
"button",
|
|
2985
2911
|
{
|
|
2986
2912
|
type: "button",
|
|
@@ -2991,8 +2917,8 @@ function ReportInteractiveView({
|
|
|
2991
2917
|
children: "?"
|
|
2992
2918
|
}
|
|
2993
2919
|
),
|
|
2994
|
-
/* @__PURE__ */
|
|
2995
|
-
toast ? /* @__PURE__ */
|
|
2920
|
+
/* @__PURE__ */ jsx47(ReportShortcutsHelp, { open: helpOpen, onClose: () => setHelpOpen(false) }),
|
|
2921
|
+
toast ? /* @__PURE__ */ jsx47(
|
|
2996
2922
|
"div",
|
|
2997
2923
|
{
|
|
2998
2924
|
role: "status",
|
|
@@ -3016,7 +2942,7 @@ import { createElement, useEffect as useEffect9, useState as useState10 } from "
|
|
|
3016
2942
|
|
|
3017
2943
|
// src/components/doc/MermaidView.tsx
|
|
3018
2944
|
import { useEffect as useEffect8, useRef as useRef6, useState as useState9 } from "react";
|
|
3019
|
-
import { Fragment as Fragment14, jsx as
|
|
2945
|
+
import { Fragment as Fragment14, jsx as jsx48, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
3020
2946
|
function prefersDark(el) {
|
|
3021
2947
|
const themed = el?.closest("[data-theme]");
|
|
3022
2948
|
if (themed?.dataset.theme === "dark") return true;
|
|
@@ -3070,9 +2996,9 @@ function MermaidView({ entry, load }) {
|
|
|
3070
2996
|
};
|
|
3071
2997
|
}, [entry.code, load]);
|
|
3072
2998
|
if (svg) {
|
|
3073
|
-
return /* @__PURE__ */
|
|
3074
|
-
entry.title ? /* @__PURE__ */
|
|
3075
|
-
/* @__PURE__ */
|
|
2999
|
+
return /* @__PURE__ */ jsxs32("figure", { ref, className: "my-3", children: [
|
|
3000
|
+
entry.title ? /* @__PURE__ */ jsx48("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
|
|
3001
|
+
/* @__PURE__ */ jsx48(
|
|
3076
3002
|
"div",
|
|
3077
3003
|
{
|
|
3078
3004
|
role: "img",
|
|
@@ -3083,8 +3009,8 @@ function MermaidView({ entry, load }) {
|
|
|
3083
3009
|
)
|
|
3084
3010
|
] });
|
|
3085
3011
|
}
|
|
3086
|
-
return /* @__PURE__ */
|
|
3087
|
-
error ? /* @__PURE__ */
|
|
3012
|
+
return /* @__PURE__ */ jsxs32(Fragment14, { children: [
|
|
3013
|
+
error ? /* @__PURE__ */ jsxs32(
|
|
3088
3014
|
"p",
|
|
3089
3015
|
{
|
|
3090
3016
|
role: "alert",
|
|
@@ -3096,12 +3022,12 @@ function MermaidView({ entry, load }) {
|
|
|
3096
3022
|
]
|
|
3097
3023
|
}
|
|
3098
3024
|
) : null,
|
|
3099
|
-
/* @__PURE__ */
|
|
3025
|
+
/* @__PURE__ */ jsx48(MermaidSource, { entry, ref })
|
|
3100
3026
|
] });
|
|
3101
3027
|
}
|
|
3102
3028
|
|
|
3103
3029
|
// src/interactive/island-renderers.tsx
|
|
3104
|
-
import { jsx as
|
|
3030
|
+
import { jsx as jsx49 } from "react/jsx-runtime";
|
|
3105
3031
|
var HLJS_ESM = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/highlight.min.js";
|
|
3106
3032
|
var MERMAID_ESM = "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
|
|
3107
3033
|
function cachedCdnModule(url) {
|
|
@@ -3135,13 +3061,13 @@ function CdnHighlightedCode({ entry }) {
|
|
|
3135
3061
|
cancelled = true;
|
|
3136
3062
|
};
|
|
3137
3063
|
}, [entry.content, entry.lang]);
|
|
3138
|
-
return /* @__PURE__ */
|
|
3064
|
+
return /* @__PURE__ */ jsx49(CodeFigure, { label: entry.label, children: html !== null ? /* @__PURE__ */ jsx49(
|
|
3139
3065
|
"code",
|
|
3140
3066
|
{
|
|
3141
3067
|
className: cn("hljs font-mono text-xs", entry.lang && `language-${entry.lang}`),
|
|
3142
3068
|
dangerouslySetInnerHTML: { __html: html }
|
|
3143
3069
|
}
|
|
3144
|
-
) : /* @__PURE__ */
|
|
3070
|
+
) : /* @__PURE__ */ jsx49("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
|
|
3145
3071
|
}
|
|
3146
3072
|
function buildIslandRenderers(opts) {
|
|
3147
3073
|
const renderers = {};
|
|
@@ -3155,7 +3081,7 @@ function buildIslandRenderers(opts) {
|
|
|
3155
3081
|
}
|
|
3156
3082
|
|
|
3157
3083
|
// src/interactive/ReportInteractiveIsland.tsx
|
|
3158
|
-
import { jsx as
|
|
3084
|
+
import { jsx as jsx50 } from "react/jsx-runtime";
|
|
3159
3085
|
function ReportInteractiveIsland({
|
|
3160
3086
|
report,
|
|
3161
3087
|
title,
|
|
@@ -3169,7 +3095,7 @@ function ReportInteractiveIsland({
|
|
|
3169
3095
|
() => buildIslandRenderers({ syntaxHighlighting, mermaid }),
|
|
3170
3096
|
[syntaxHighlighting, mermaid]
|
|
3171
3097
|
);
|
|
3172
|
-
return /* @__PURE__ */
|
|
3098
|
+
return /* @__PURE__ */ jsx50(
|
|
3173
3099
|
ReportInteractive,
|
|
3174
3100
|
{
|
|
3175
3101
|
report,
|