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/index.js
CHANGED
|
@@ -17,63 +17,6 @@ import { useMemo } from "react";
|
|
|
17
17
|
import { createContext } from "react";
|
|
18
18
|
var ReportContext = createContext(null);
|
|
19
19
|
|
|
20
|
-
// src/context/ReportRoot.tsx
|
|
21
|
-
import { jsx } from "react/jsx-runtime";
|
|
22
|
-
var EMPTY_CUSTOM = {};
|
|
23
|
-
var EMPTY_RENDERERS = {};
|
|
24
|
-
function ReportRoot({
|
|
25
|
-
report,
|
|
26
|
-
customRenderers,
|
|
27
|
-
renderers,
|
|
28
|
-
children
|
|
29
|
-
}) {
|
|
30
|
-
const value = useMemo(
|
|
31
|
-
() => ({
|
|
32
|
-
report,
|
|
33
|
-
customRenderers: customRenderers ?? EMPTY_CUSTOM,
|
|
34
|
-
renderers: renderers ?? EMPTY_RENDERERS
|
|
35
|
-
}),
|
|
36
|
-
[report, customRenderers, renderers]
|
|
37
|
-
);
|
|
38
|
-
return /* @__PURE__ */ jsx(ReportContext.Provider, { value, children });
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// src/hooks/useReport.ts
|
|
42
|
-
import { useContext } from "react";
|
|
43
|
-
function useReport() {
|
|
44
|
-
const ctx = useContext(ReportContext);
|
|
45
|
-
if (!ctx) {
|
|
46
|
-
throw new Error(
|
|
47
|
-
"useReport must be used inside <ReportRoot> or <Report>. Wrap your tree with one of those."
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
return ctx.report;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// ../executable-stories-core/dist/utils/duration.js
|
|
54
|
-
function formatDuration(ms) {
|
|
55
|
-
if (ms < 1e3) {
|
|
56
|
-
return `${Math.round(ms)} ms`;
|
|
57
|
-
}
|
|
58
|
-
if (ms < 6e4) {
|
|
59
|
-
return `${(ms / 1e3).toFixed(2)} s`;
|
|
60
|
-
}
|
|
61
|
-
const minutes = Math.floor(ms / 6e4);
|
|
62
|
-
const seconds = Math.floor(ms % 6e4 / 1e3);
|
|
63
|
-
if (minutes < 60) {
|
|
64
|
-
return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
|
|
65
|
-
}
|
|
66
|
-
const hours = Math.floor(minutes / 60);
|
|
67
|
-
const remainingMinutes = minutes % 60;
|
|
68
|
-
return `${hours}h ${remainingMinutes}m`;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// src/components/doc/DocNote.tsx
|
|
72
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
73
|
-
function DocNote({ entry }) {
|
|
74
|
-
return /* @__PURE__ */ jsx2("p", { className: "my-2 text-sm text-muted-foreground", children: entry.text });
|
|
75
|
-
}
|
|
76
|
-
|
|
77
20
|
// src/components/ui/badge.tsx
|
|
78
21
|
import "react";
|
|
79
22
|
import { cva } from "class-variance-authority";
|
|
@@ -132,14 +75,237 @@ function Badge({
|
|
|
132
75
|
});
|
|
133
76
|
}
|
|
134
77
|
|
|
135
|
-
// src/components/doc/
|
|
78
|
+
// src/components/doc/NarrativeBlocks.tsx
|
|
79
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
80
|
+
var FILE_TREE_TYPE = "file-tree";
|
|
81
|
+
var DATA_MODEL_TYPE = "data-model";
|
|
82
|
+
function isChangeKind(value) {
|
|
83
|
+
return value === "added" || value === "modified" || value === "removed" || value === "renamed";
|
|
84
|
+
}
|
|
85
|
+
function isRecord(value) {
|
|
86
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
87
|
+
}
|
|
88
|
+
function str(value) {
|
|
89
|
+
return typeof value === "string" && value !== "" ? value : void 0;
|
|
90
|
+
}
|
|
91
|
+
function AuthoredMarker({ authored }) {
|
|
92
|
+
if (authored !== "agent") return null;
|
|
93
|
+
return /* @__PURE__ */ jsx(Badge, { variant: "outline", className: "border-border text-[10px] text-muted-foreground", children: "AI-authored, not verified by a run" });
|
|
94
|
+
}
|
|
95
|
+
function BlockFrame({
|
|
96
|
+
title,
|
|
97
|
+
authored,
|
|
98
|
+
children
|
|
99
|
+
}) {
|
|
100
|
+
return /* @__PURE__ */ jsxs("figure", { className: "my-3", children: [
|
|
101
|
+
title || authored === "agent" ? /* @__PURE__ */ jsxs("figcaption", { className: "mb-1.5 flex flex-wrap items-center gap-2", children: [
|
|
102
|
+
title ? /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: title }) : null,
|
|
103
|
+
/* @__PURE__ */ jsx(AuthoredMarker, { authored })
|
|
104
|
+
] }) : null,
|
|
105
|
+
children
|
|
106
|
+
] });
|
|
107
|
+
}
|
|
108
|
+
function ChangeBadge({ change }) {
|
|
109
|
+
return /* @__PURE__ */ jsx(Badge, { variant: "tag", className: "text-[10px]", children: change });
|
|
110
|
+
}
|
|
111
|
+
function parseFileTree(data) {
|
|
112
|
+
if (!isRecord(data) || !Array.isArray(data.files)) return void 0;
|
|
113
|
+
const files = [];
|
|
114
|
+
for (const raw of data.files) {
|
|
115
|
+
if (typeof raw === "string") {
|
|
116
|
+
if (raw) files.push({ path: raw });
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (!isRecord(raw)) continue;
|
|
120
|
+
const path = str(raw.path);
|
|
121
|
+
if (!path) continue;
|
|
122
|
+
files.push({
|
|
123
|
+
path,
|
|
124
|
+
change: isChangeKind(raw.change) ? raw.change : void 0,
|
|
125
|
+
note: str(raw.note)
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
if (files.length === 0) return void 0;
|
|
129
|
+
return { title: str(data.title), authored: str(data.authored), files };
|
|
130
|
+
}
|
|
131
|
+
function buildTree(files) {
|
|
132
|
+
const root = { name: "", children: /* @__PURE__ */ new Map() };
|
|
133
|
+
for (const file of files) {
|
|
134
|
+
const segments = file.path.split("/").filter(Boolean);
|
|
135
|
+
let node = root;
|
|
136
|
+
segments.forEach((segment, index) => {
|
|
137
|
+
let child = node.children.get(segment);
|
|
138
|
+
if (!child) {
|
|
139
|
+
child = { name: segment, children: /* @__PURE__ */ new Map() };
|
|
140
|
+
node.children.set(segment, child);
|
|
141
|
+
}
|
|
142
|
+
if (index === segments.length - 1) child.file = file;
|
|
143
|
+
node = child;
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
return root;
|
|
147
|
+
}
|
|
148
|
+
function sortedChildren(node) {
|
|
149
|
+
return [...node.children.values()].sort((a, b) => {
|
|
150
|
+
const aDir = a.children.size > 0;
|
|
151
|
+
const bDir = b.children.size > 0;
|
|
152
|
+
if (aDir !== bDir) return aDir ? -1 : 1;
|
|
153
|
+
return a.name.localeCompare(b.name);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
function TreeBranch({ node, depth }) {
|
|
157
|
+
const children = sortedChildren(node);
|
|
158
|
+
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) => {
|
|
159
|
+
const isDir = child.children.size > 0;
|
|
160
|
+
return /* @__PURE__ */ jsxs("li", { children: [
|
|
161
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-baseline gap-2", children: [
|
|
162
|
+
/* @__PURE__ */ jsx(
|
|
163
|
+
"span",
|
|
164
|
+
{
|
|
165
|
+
className: cn(
|
|
166
|
+
"font-mono text-xs",
|
|
167
|
+
isDir ? "text-muted-foreground" : "text-foreground"
|
|
168
|
+
),
|
|
169
|
+
children: isDir ? `${child.name}/` : child.name
|
|
170
|
+
}
|
|
171
|
+
),
|
|
172
|
+
child.file?.change ? /* @__PURE__ */ jsx(ChangeBadge, { change: child.file.change }) : null,
|
|
173
|
+
child.file?.note ? /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: child.file.note }) : null
|
|
174
|
+
] }),
|
|
175
|
+
isDir ? /* @__PURE__ */ jsx(TreeBranch, { node: child, depth: depth + 1 }) : null
|
|
176
|
+
] }, child.name);
|
|
177
|
+
}) });
|
|
178
|
+
}
|
|
179
|
+
function FileTreeBlock({ entry }) {
|
|
180
|
+
const data = parseFileTree(entry.data);
|
|
181
|
+
if (!data) return /* @__PURE__ */ jsx(UnreadableBlock, { entry });
|
|
182
|
+
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 }) }) });
|
|
183
|
+
}
|
|
184
|
+
function parseDataModel(data) {
|
|
185
|
+
if (!isRecord(data) || !Array.isArray(data.fields)) return void 0;
|
|
186
|
+
const fields = [];
|
|
187
|
+
for (const raw of data.fields) {
|
|
188
|
+
if (!isRecord(raw)) continue;
|
|
189
|
+
const name = str(raw.name);
|
|
190
|
+
if (!name) continue;
|
|
191
|
+
fields.push({
|
|
192
|
+
name,
|
|
193
|
+
type: str(raw.type),
|
|
194
|
+
note: str(raw.note),
|
|
195
|
+
change: isChangeKind(raw.change) ? raw.change : void 0
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
if (fields.length === 0) return void 0;
|
|
199
|
+
return {
|
|
200
|
+
title: str(data.title),
|
|
201
|
+
authored: str(data.authored),
|
|
202
|
+
name: str(data.name),
|
|
203
|
+
fields
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
function DataModelBlock({ entry }) {
|
|
207
|
+
const data = parseDataModel(entry.data);
|
|
208
|
+
if (!data) return /* @__PURE__ */ jsx(UnreadableBlock, { entry });
|
|
209
|
+
const hasNotes = data.fields.some((f) => f.note);
|
|
210
|
+
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: [
|
|
211
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "bg-muted/50", children: [
|
|
212
|
+
/* @__PURE__ */ jsx("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Field" }),
|
|
213
|
+
/* @__PURE__ */ jsx("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Type" }),
|
|
214
|
+
hasNotes ? /* @__PURE__ */ jsx("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Note" }) : null
|
|
215
|
+
] }) }),
|
|
216
|
+
/* @__PURE__ */ jsx("tbody", { children: data.fields.map((field) => /* @__PURE__ */ jsxs("tr", { children: [
|
|
217
|
+
/* @__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: [
|
|
218
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono text-xs text-foreground", children: field.name }),
|
|
219
|
+
field.change ? /* @__PURE__ */ jsx(ChangeBadge, { change: field.change }) : null
|
|
220
|
+
] }) }),
|
|
221
|
+
/* @__PURE__ */ jsx("td", { className: "border-b border-border px-3 py-2 font-mono text-xs text-muted-foreground", children: field.type ?? "" }),
|
|
222
|
+
hasNotes ? /* @__PURE__ */ jsx("td", { className: "border-b border-border px-3 py-2 text-foreground", children: field.note ?? "" }) : null
|
|
223
|
+
] }, field.name)) })
|
|
224
|
+
] }) }) });
|
|
225
|
+
}
|
|
226
|
+
function UnreadableBlock({ entry }) {
|
|
227
|
+
return /* @__PURE__ */ jsxs("div", { className: "my-2", "data-type": entry.type, children: [
|
|
228
|
+
/* @__PURE__ */ jsxs("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: [
|
|
229
|
+
entry.type,
|
|
230
|
+
" (unrecognised shape)"
|
|
231
|
+
] }),
|
|
232
|
+
/* @__PURE__ */ jsx(
|
|
233
|
+
"pre",
|
|
234
|
+
{
|
|
235
|
+
tabIndex: 0,
|
|
236
|
+
className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground",
|
|
237
|
+
children: safeStringify(entry.data)
|
|
238
|
+
}
|
|
239
|
+
)
|
|
240
|
+
] });
|
|
241
|
+
}
|
|
242
|
+
function safeStringify(value) {
|
|
243
|
+
try {
|
|
244
|
+
return JSON.stringify(value, null, 2);
|
|
245
|
+
} catch {
|
|
246
|
+
return String(value);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
var narrativeBlockRenderers = {
|
|
250
|
+
[FILE_TREE_TYPE]: (entry) => /* @__PURE__ */ jsx(FileTreeBlock, { entry }),
|
|
251
|
+
[DATA_MODEL_TYPE]: (entry) => /* @__PURE__ */ jsx(DataModelBlock, { entry })
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
// src/context/ReportRoot.tsx
|
|
255
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
256
|
+
var EMPTY_RENDERERS = {};
|
|
257
|
+
function ReportRoot({
|
|
258
|
+
report,
|
|
259
|
+
customRenderers,
|
|
260
|
+
renderers,
|
|
261
|
+
children
|
|
262
|
+
}) {
|
|
263
|
+
const value = useMemo(
|
|
264
|
+
() => ({
|
|
265
|
+
report,
|
|
266
|
+
// Narrative blocks render everywhere the report does (static SSR, the
|
|
267
|
+
// island, Astro) without every host wiring them up. A host renderer for
|
|
268
|
+
// the same type still wins.
|
|
269
|
+
customRenderers: { ...narrativeBlockRenderers, ...customRenderers },
|
|
270
|
+
renderers: renderers ?? EMPTY_RENDERERS
|
|
271
|
+
}),
|
|
272
|
+
[report, customRenderers, renderers]
|
|
273
|
+
);
|
|
274
|
+
return /* @__PURE__ */ jsx2(ReportContext.Provider, { value, children });
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// src/hooks/useReport.ts
|
|
278
|
+
import { useContext } from "react";
|
|
279
|
+
function useReport() {
|
|
280
|
+
const ctx = useContext(ReportContext);
|
|
281
|
+
if (!ctx) {
|
|
282
|
+
throw new Error(
|
|
283
|
+
"useReport must be used inside <ReportRoot> or <Report>. Wrap your tree with one of those."
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
return ctx.report;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// src/components/ReportScenario.tsx
|
|
290
|
+
import { formatDuration as formatDuration3 } from "executable-stories-core/utils/duration";
|
|
291
|
+
|
|
292
|
+
// src/components/ReportSteps.tsx
|
|
293
|
+
import { formatDuration } from "executable-stories-core/utils/duration";
|
|
294
|
+
|
|
295
|
+
// src/components/doc/DocNote.tsx
|
|
136
296
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
297
|
+
function DocNote({ entry }) {
|
|
298
|
+
return /* @__PURE__ */ jsx3("p", { className: "my-2 text-sm text-muted-foreground", children: entry.text });
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// src/components/doc/DocTag.tsx
|
|
302
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
137
303
|
function DocTag({ entry }) {
|
|
138
|
-
return /* @__PURE__ */
|
|
304
|
+
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)) });
|
|
139
305
|
}
|
|
140
306
|
|
|
141
307
|
// src/components/doc/DocKv.tsx
|
|
142
|
-
import { jsx as
|
|
308
|
+
import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
143
309
|
function formatValue(value) {
|
|
144
310
|
if (value === null) return "null";
|
|
145
311
|
if (typeof value === "string") return value;
|
|
@@ -151,19 +317,19 @@ function formatValue(value) {
|
|
|
151
317
|
}
|
|
152
318
|
}
|
|
153
319
|
function DocKv({ entry }) {
|
|
154
|
-
return /* @__PURE__ */
|
|
155
|
-
/* @__PURE__ */
|
|
156
|
-
/* @__PURE__ */
|
|
320
|
+
return /* @__PURE__ */ jsxs2("dl", { className: "my-2 flex flex-wrap items-baseline gap-x-2 text-sm", children: [
|
|
321
|
+
/* @__PURE__ */ jsx5("dt", { className: "font-semibold text-muted-foreground", children: entry.label }),
|
|
322
|
+
/* @__PURE__ */ jsx5("dd", { className: "font-mono text-foreground", children: formatValue(entry.value) })
|
|
157
323
|
] });
|
|
158
324
|
}
|
|
159
325
|
|
|
160
326
|
// src/hooks/useRenderers.ts
|
|
161
327
|
import { useContext as useContext2 } from "react";
|
|
162
|
-
var
|
|
328
|
+
var EMPTY_CUSTOM = {};
|
|
163
329
|
var EMPTY_RENDERERS2 = {};
|
|
164
330
|
function useCustomRenderers() {
|
|
165
331
|
const ctx = useContext2(ReportContext);
|
|
166
|
-
return ctx?.customRenderers ??
|
|
332
|
+
return ctx?.customRenderers ?? EMPTY_CUSTOM;
|
|
167
333
|
}
|
|
168
334
|
function useBuiltinRenderers() {
|
|
169
335
|
const ctx = useContext2(ReportContext);
|
|
@@ -171,37 +337,37 @@ function useBuiltinRenderers() {
|
|
|
171
337
|
}
|
|
172
338
|
|
|
173
339
|
// src/components/doc/DocCode.tsx
|
|
174
|
-
import { Fragment, jsx as
|
|
340
|
+
import { Fragment, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
175
341
|
function CodeFigure({ label, children }) {
|
|
176
|
-
return /* @__PURE__ */
|
|
177
|
-
label ? /* @__PURE__ */
|
|
178
|
-
/* @__PURE__ */
|
|
342
|
+
return /* @__PURE__ */ jsxs3("figure", { className: "my-3", children: [
|
|
343
|
+
label ? /* @__PURE__ */ jsx6("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: label }) : null,
|
|
344
|
+
/* @__PURE__ */ jsx6("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3", children })
|
|
179
345
|
] });
|
|
180
346
|
}
|
|
181
347
|
function DocCode({ entry }) {
|
|
182
348
|
const renderers = useBuiltinRenderers();
|
|
183
349
|
if (renderers.code) {
|
|
184
|
-
return /* @__PURE__ */
|
|
350
|
+
return /* @__PURE__ */ jsx6(Fragment, { children: renderers.code(entry) });
|
|
185
351
|
}
|
|
186
|
-
return /* @__PURE__ */
|
|
352
|
+
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 }) });
|
|
187
353
|
}
|
|
188
354
|
|
|
189
355
|
// src/components/doc/DocTable.tsx
|
|
190
|
-
import { jsx as
|
|
356
|
+
import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
191
357
|
function DocTable({ entry }) {
|
|
192
|
-
return /* @__PURE__ */
|
|
193
|
-
entry.label ? /* @__PURE__ */
|
|
194
|
-
/* @__PURE__ */
|
|
195
|
-
/* @__PURE__ */
|
|
196
|
-
/* @__PURE__ */
|
|
358
|
+
return /* @__PURE__ */ jsxs4("figure", { className: "my-3", children: [
|
|
359
|
+
entry.label ? /* @__PURE__ */ jsx7("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.label }) : null,
|
|
360
|
+
/* @__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: [
|
|
361
|
+
/* @__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)) }) }),
|
|
362
|
+
/* @__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)) })
|
|
197
363
|
] }) })
|
|
198
364
|
] });
|
|
199
365
|
}
|
|
200
366
|
|
|
201
367
|
// src/components/doc/DocLink.tsx
|
|
202
|
-
import { jsx as
|
|
368
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
203
369
|
function DocLink({ entry }) {
|
|
204
|
-
return /* @__PURE__ */
|
|
370
|
+
return /* @__PURE__ */ jsx8(
|
|
205
371
|
"a",
|
|
206
372
|
{
|
|
207
373
|
className: "text-sm font-medium text-primary underline underline-offset-2 hover:no-underline",
|
|
@@ -216,26 +382,11 @@ function DocLink({ entry }) {
|
|
|
216
382
|
// src/components/doc/DocSection.tsx
|
|
217
383
|
import { marked } from "marked";
|
|
218
384
|
|
|
219
|
-
//
|
|
220
|
-
|
|
221
|
-
if (!value) return void 0;
|
|
222
|
-
const trimmed = value.trim();
|
|
223
|
-
const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(trimmed);
|
|
224
|
-
if (scheme && !/^https?$/i.test(scheme[1] ?? "")) return void 0;
|
|
225
|
-
return trimmed;
|
|
226
|
-
}
|
|
227
|
-
function safeImageUrl(value) {
|
|
228
|
-
if (!value) return void 0;
|
|
229
|
-
const trimmed = value.trim();
|
|
230
|
-
if (/^data:image\//i.test(trimmed)) return trimmed;
|
|
231
|
-
return safeUrl(trimmed);
|
|
232
|
-
}
|
|
233
|
-
function isLocalFsPath(value) {
|
|
234
|
-
return /^(?:[/\\]|[A-Za-z]:[/\\])/.test(value);
|
|
235
|
-
}
|
|
385
|
+
// src/lib/url.ts
|
|
386
|
+
import { safeUrl, safeImageUrl, isLocalFsPath } from "executable-stories-core/utils/url";
|
|
236
387
|
|
|
237
388
|
// src/components/doc/DocSection.tsx
|
|
238
|
-
import { Fragment as Fragment2, jsx as
|
|
389
|
+
import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
239
390
|
function neutralizeUrl(value) {
|
|
240
391
|
return safeUrl(value) ?? "#";
|
|
241
392
|
}
|
|
@@ -246,12 +397,12 @@ function safeMarkdownHtml(markdown) {
|
|
|
246
397
|
function DocSection({ entry }) {
|
|
247
398
|
const renderers = useBuiltinRenderers();
|
|
248
399
|
if (renderers.section) {
|
|
249
|
-
return /* @__PURE__ */
|
|
400
|
+
return /* @__PURE__ */ jsx9(Fragment2, { children: renderers.section(entry) });
|
|
250
401
|
}
|
|
251
402
|
const html = safeMarkdownHtml(entry.markdown);
|
|
252
|
-
return /* @__PURE__ */
|
|
253
|
-
entry.title ? /* @__PURE__ */
|
|
254
|
-
/* @__PURE__ */
|
|
403
|
+
return /* @__PURE__ */ jsxs5("section", { className: "my-3 text-sm", "aria-label": entry.title, children: [
|
|
404
|
+
entry.title ? /* @__PURE__ */ jsx9("h4", { className: "mb-1 font-semibold text-foreground", children: entry.title }) : null,
|
|
405
|
+
/* @__PURE__ */ jsx9(
|
|
255
406
|
"div",
|
|
256
407
|
{
|
|
257
408
|
className: "es-doc-prose prose prose-sm max-w-none",
|
|
@@ -262,11 +413,11 @@ function DocSection({ entry }) {
|
|
|
262
413
|
}
|
|
263
414
|
|
|
264
415
|
// src/components/doc/DocMermaid.tsx
|
|
265
|
-
import { Fragment as Fragment3, jsx as
|
|
416
|
+
import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
266
417
|
function MermaidSource({ entry, ref }) {
|
|
267
|
-
return /* @__PURE__ */
|
|
268
|
-
entry.title ? /* @__PURE__ */
|
|
269
|
-
/* @__PURE__ */
|
|
418
|
+
return /* @__PURE__ */ jsxs6("figure", { ref, className: "my-3", "aria-label": entry.title ?? "Diagram", children: [
|
|
419
|
+
entry.title ? /* @__PURE__ */ jsx10("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
|
|
420
|
+
/* @__PURE__ */ jsx10(
|
|
270
421
|
"pre",
|
|
271
422
|
{
|
|
272
423
|
"data-mermaid": true,
|
|
@@ -280,24 +431,24 @@ function MermaidSource({ entry, ref }) {
|
|
|
280
431
|
function DocMermaid({ entry }) {
|
|
281
432
|
const renderers = useBuiltinRenderers();
|
|
282
433
|
if (renderers.mermaid) {
|
|
283
|
-
return /* @__PURE__ */
|
|
434
|
+
return /* @__PURE__ */ jsx10(Fragment3, { children: renderers.mermaid(entry) });
|
|
284
435
|
}
|
|
285
|
-
return /* @__PURE__ */
|
|
436
|
+
return /* @__PURE__ */ jsx10(MermaidSource, { entry });
|
|
286
437
|
}
|
|
287
438
|
|
|
288
439
|
// src/components/doc/DocScreenshot.tsx
|
|
289
|
-
import { jsx as
|
|
440
|
+
import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
290
441
|
function DocScreenshot({ entry }) {
|
|
291
442
|
const src = isLocalFsPath(entry.path) ? void 0 : safeImageUrl(entry.path);
|
|
292
443
|
if (!src) {
|
|
293
|
-
return /* @__PURE__ */
|
|
294
|
-
/* @__PURE__ */
|
|
295
|
-
/* @__PURE__ */
|
|
296
|
-
entry.alt ? /* @__PURE__ */
|
|
444
|
+
return /* @__PURE__ */ jsxs7("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
|
|
445
|
+
/* @__PURE__ */ jsx11("div", { className: "font-medium", children: "Screenshot unavailable" }),
|
|
446
|
+
/* @__PURE__ */ jsx11("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
|
|
447
|
+
entry.alt ? /* @__PURE__ */ jsx11("figcaption", { className: "mt-1.5 text-xs", children: entry.alt }) : null
|
|
297
448
|
] });
|
|
298
449
|
}
|
|
299
|
-
return /* @__PURE__ */
|
|
300
|
-
/* @__PURE__ */
|
|
450
|
+
return /* @__PURE__ */ jsxs7("figure", { className: "my-3", children: [
|
|
451
|
+
/* @__PURE__ */ jsx11(
|
|
301
452
|
"img",
|
|
302
453
|
{
|
|
303
454
|
src,
|
|
@@ -306,24 +457,24 @@ function DocScreenshot({ entry }) {
|
|
|
306
457
|
className: "max-w-full rounded-md border border-border"
|
|
307
458
|
}
|
|
308
459
|
),
|
|
309
|
-
entry.alt ? /* @__PURE__ */
|
|
460
|
+
entry.alt ? /* @__PURE__ */ jsx11("figcaption", { className: "mt-1.5 text-xs text-muted-foreground", children: entry.alt }) : null
|
|
310
461
|
] });
|
|
311
462
|
}
|
|
312
463
|
|
|
313
464
|
// src/components/doc/DocVideo.tsx
|
|
314
|
-
import { jsx as
|
|
465
|
+
import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
315
466
|
function DocVideo({ entry }) {
|
|
316
467
|
if (isLocalFsPath(entry.path)) {
|
|
317
|
-
return /* @__PURE__ */
|
|
318
|
-
/* @__PURE__ */
|
|
319
|
-
/* @__PURE__ */
|
|
320
|
-
entry.caption ? /* @__PURE__ */
|
|
468
|
+
return /* @__PURE__ */ jsxs8("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
|
|
469
|
+
/* @__PURE__ */ jsx12("div", { className: "font-medium", children: "Video unavailable" }),
|
|
470
|
+
/* @__PURE__ */ jsx12("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
|
|
471
|
+
entry.caption ? /* @__PURE__ */ jsx12("figcaption", { className: "mt-1.5 text-xs", children: entry.caption }) : null
|
|
321
472
|
] });
|
|
322
473
|
}
|
|
323
474
|
const src = safeUrl(entry.path);
|
|
324
475
|
const poster = safeUrl(entry.poster);
|
|
325
|
-
return /* @__PURE__ */
|
|
326
|
-
/* @__PURE__ */
|
|
476
|
+
return /* @__PURE__ */ jsxs8("figure", { className: "my-3", children: [
|
|
477
|
+
/* @__PURE__ */ jsx12(
|
|
327
478
|
"video",
|
|
328
479
|
{
|
|
329
480
|
controls: true,
|
|
@@ -333,21 +484,21 @@ function DocVideo({ entry }) {
|
|
|
333
484
|
className: "max-w-full rounded-md border border-border"
|
|
334
485
|
}
|
|
335
486
|
),
|
|
336
|
-
entry.caption ? /* @__PURE__ */
|
|
487
|
+
entry.caption ? /* @__PURE__ */ jsx12("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: entry.caption }) : null
|
|
337
488
|
] });
|
|
338
489
|
}
|
|
339
490
|
|
|
340
491
|
// src/components/doc/DocHtml.tsx
|
|
341
|
-
import { jsx as
|
|
492
|
+
import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
342
493
|
function DocHtml({ entry }) {
|
|
343
494
|
const height = typeof entry.height === "number" ? `${entry.height}px` : entry.height ?? "400px";
|
|
344
495
|
const title = entry.title ?? "Embedded HTML";
|
|
345
496
|
const safeHref = safeUrl(entry.url ?? entry.path);
|
|
346
497
|
const frameProps = entry.content !== void 0 ? { srcDoc: entry.content } : { src: safeHref ?? "" };
|
|
347
|
-
return /* @__PURE__ */
|
|
348
|
-
/* @__PURE__ */
|
|
349
|
-
/* @__PURE__ */
|
|
350
|
-
safeHref ? /* @__PURE__ */
|
|
498
|
+
return /* @__PURE__ */ jsxs9("figure", { className: "my-3 overflow-hidden rounded-md border border-border", children: [
|
|
499
|
+
/* @__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: [
|
|
500
|
+
/* @__PURE__ */ jsx13("span", { children: entry.title ?? "HTML" }),
|
|
501
|
+
safeHref ? /* @__PURE__ */ jsx13(
|
|
351
502
|
"a",
|
|
352
503
|
{
|
|
353
504
|
href: safeHref,
|
|
@@ -360,7 +511,7 @@ function DocHtml({ entry }) {
|
|
|
360
511
|
}
|
|
361
512
|
) : null
|
|
362
513
|
] }),
|
|
363
|
-
/* @__PURE__ */
|
|
514
|
+
/* @__PURE__ */ jsx13(
|
|
364
515
|
"iframe",
|
|
365
516
|
{
|
|
366
517
|
...frameProps,
|
|
@@ -375,7 +526,7 @@ function DocHtml({ entry }) {
|
|
|
375
526
|
}
|
|
376
527
|
|
|
377
528
|
// src/components/doc/DocState.tsx
|
|
378
|
-
import { jsx as
|
|
529
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
379
530
|
function DocState({ entry }) {
|
|
380
531
|
let json;
|
|
381
532
|
try {
|
|
@@ -383,23 +534,23 @@ function DocState({ entry }) {
|
|
|
383
534
|
} catch {
|
|
384
535
|
json = String(entry.value);
|
|
385
536
|
}
|
|
386
|
-
return /* @__PURE__ */
|
|
537
|
+
return /* @__PURE__ */ jsx14(CodeFigure, { label: entry.label ?? "State", children: /* @__PURE__ */ jsx14("code", { className: "font-mono text-xs language-json", children: json }) });
|
|
387
538
|
}
|
|
388
539
|
|
|
389
540
|
// src/components/doc/DocCustom.tsx
|
|
390
|
-
import { Fragment as Fragment4, jsx as
|
|
541
|
+
import { Fragment as Fragment4, jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
391
542
|
function DocCustom({ entry }) {
|
|
392
543
|
const renderers = useCustomRenderers();
|
|
393
544
|
const renderer = renderers[entry.type];
|
|
394
545
|
if (renderer) {
|
|
395
|
-
return /* @__PURE__ */
|
|
546
|
+
return /* @__PURE__ */ jsx15(Fragment4, { children: renderer(entry) });
|
|
396
547
|
}
|
|
397
|
-
return /* @__PURE__ */
|
|
398
|
-
/* @__PURE__ */
|
|
399
|
-
/* @__PURE__ */
|
|
548
|
+
return /* @__PURE__ */ jsxs10("div", { className: "my-2", "data-type": entry.type, children: [
|
|
549
|
+
/* @__PURE__ */ jsx15("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: entry.type }),
|
|
550
|
+
/* @__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) })
|
|
400
551
|
] });
|
|
401
552
|
}
|
|
402
|
-
function
|
|
553
|
+
function safeStringify2(value) {
|
|
403
554
|
try {
|
|
404
555
|
return JSON.stringify(value, null, 2);
|
|
405
556
|
} catch {
|
|
@@ -408,47 +559,47 @@ function safeStringify(value) {
|
|
|
408
559
|
}
|
|
409
560
|
|
|
410
561
|
// src/components/doc/DocEntry.tsx
|
|
411
|
-
import { jsx as
|
|
562
|
+
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
412
563
|
function DocEntry({ entry }) {
|
|
413
564
|
switch (entry.kind) {
|
|
414
565
|
case "note":
|
|
415
|
-
return /* @__PURE__ */
|
|
566
|
+
return /* @__PURE__ */ jsx16(DocNote, { entry });
|
|
416
567
|
case "tag":
|
|
417
|
-
return /* @__PURE__ */
|
|
568
|
+
return /* @__PURE__ */ jsx16(DocTag, { entry });
|
|
418
569
|
case "kv":
|
|
419
|
-
return /* @__PURE__ */
|
|
570
|
+
return /* @__PURE__ */ jsx16(DocKv, { entry });
|
|
420
571
|
case "code":
|
|
421
|
-
return /* @__PURE__ */
|
|
572
|
+
return /* @__PURE__ */ jsx16(DocCode, { entry });
|
|
422
573
|
case "table":
|
|
423
|
-
return /* @__PURE__ */
|
|
574
|
+
return /* @__PURE__ */ jsx16(DocTable, { entry });
|
|
424
575
|
case "link":
|
|
425
|
-
return /* @__PURE__ */
|
|
576
|
+
return /* @__PURE__ */ jsx16(DocLink, { entry });
|
|
426
577
|
case "section":
|
|
427
|
-
return /* @__PURE__ */
|
|
578
|
+
return /* @__PURE__ */ jsx16(DocSection, { entry });
|
|
428
579
|
case "mermaid":
|
|
429
|
-
return /* @__PURE__ */
|
|
580
|
+
return /* @__PURE__ */ jsx16(DocMermaid, { entry });
|
|
430
581
|
case "screenshot":
|
|
431
|
-
return /* @__PURE__ */
|
|
582
|
+
return /* @__PURE__ */ jsx16(DocScreenshot, { entry });
|
|
432
583
|
case "video":
|
|
433
|
-
return /* @__PURE__ */
|
|
584
|
+
return /* @__PURE__ */ jsx16(DocVideo, { entry });
|
|
434
585
|
case "html":
|
|
435
|
-
return /* @__PURE__ */
|
|
586
|
+
return /* @__PURE__ */ jsx16(DocHtml, { entry });
|
|
436
587
|
case "state":
|
|
437
|
-
return /* @__PURE__ */
|
|
588
|
+
return /* @__PURE__ */ jsx16(DocState, { entry });
|
|
438
589
|
case "custom":
|
|
439
|
-
return /* @__PURE__ */
|
|
590
|
+
return /* @__PURE__ */ jsx16(DocCustom, { entry });
|
|
440
591
|
}
|
|
441
592
|
}
|
|
442
593
|
|
|
443
594
|
// src/components/ReportDocEntries.tsx
|
|
444
|
-
import { Fragment as Fragment5, jsx as
|
|
595
|
+
import { Fragment as Fragment5, jsx as jsx17 } from "react/jsx-runtime";
|
|
445
596
|
function ReportDocEntries({ entries }) {
|
|
446
597
|
if (entries.length === 0) return null;
|
|
447
|
-
return /* @__PURE__ */
|
|
598
|
+
return /* @__PURE__ */ jsx17(Fragment5, { children: entries.map((entry, i) => /* @__PURE__ */ jsx17(DocEntry, { entry }, i)) });
|
|
448
599
|
}
|
|
449
600
|
|
|
450
601
|
// src/lib/step-params.tsx
|
|
451
|
-
import { jsx as
|
|
602
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
452
603
|
var STEP_PARAM_PATTERN = /"[^"]*"|(?<![\w.-])\d+(?:\.\d+)?(?![\w.-])/g;
|
|
453
604
|
function highlightStepParams(text) {
|
|
454
605
|
const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));
|
|
@@ -460,7 +611,7 @@ function highlightStepParams(text) {
|
|
|
460
611
|
const end = start + match[0].length;
|
|
461
612
|
if (start > lastIndex) nodes.push(text.slice(lastIndex, start));
|
|
462
613
|
nodes.push(
|
|
463
|
-
/* @__PURE__ */
|
|
614
|
+
/* @__PURE__ */ jsx18("span", { className: "font-medium text-step-param italic", children: match[0] }, i)
|
|
464
615
|
);
|
|
465
616
|
lastIndex = end;
|
|
466
617
|
});
|
|
@@ -469,7 +620,7 @@ function highlightStepParams(text) {
|
|
|
469
620
|
}
|
|
470
621
|
|
|
471
622
|
// src/components/ReportSteps.tsx
|
|
472
|
-
import { jsx as
|
|
623
|
+
import { jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
473
624
|
var STEP_GLYPH = {
|
|
474
625
|
passed: "\u2713",
|
|
475
626
|
failed: "\u2717",
|
|
@@ -484,21 +635,21 @@ var STEP_GLYPH_COLOR = {
|
|
|
484
635
|
};
|
|
485
636
|
function ReportSteps({ scenario }) {
|
|
486
637
|
if (scenario.steps.length === 0) return null;
|
|
487
|
-
return /* @__PURE__ */
|
|
638
|
+
return /* @__PURE__ */ jsx19("ol", { "data-slot": "steps", className: "flex flex-col", children: scenario.steps.map((step) => /* @__PURE__ */ jsx19(ReportStepItem, { step }, step.id)) });
|
|
488
639
|
}
|
|
489
640
|
function ReportStepItem({ step }) {
|
|
490
641
|
const kw = step.keyword.toLowerCase();
|
|
491
642
|
const continuation = kw === "and" || kw === "but";
|
|
492
|
-
return /* @__PURE__ */
|
|
643
|
+
return /* @__PURE__ */ jsxs11(
|
|
493
644
|
"li",
|
|
494
645
|
{
|
|
495
646
|
id: step.id,
|
|
496
647
|
"data-status": step.status,
|
|
497
648
|
className: cn("py-1.5 text-[0.8125rem] leading-normal", continuation && "pl-5"),
|
|
498
649
|
children: [
|
|
499
|
-
/* @__PURE__ */
|
|
500
|
-
/* @__PURE__ */
|
|
501
|
-
/* @__PURE__ */
|
|
650
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex items-baseline gap-2", children: [
|
|
651
|
+
/* @__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" }),
|
|
652
|
+
/* @__PURE__ */ jsx19(
|
|
502
653
|
"span",
|
|
503
654
|
{
|
|
504
655
|
className: cn(
|
|
@@ -508,10 +659,10 @@ function ReportStepItem({ step }) {
|
|
|
508
659
|
children: step.keyword
|
|
509
660
|
}
|
|
510
661
|
),
|
|
511
|
-
/* @__PURE__ */
|
|
512
|
-
step.durationMs > 0 ? /* @__PURE__ */
|
|
662
|
+
/* @__PURE__ */ jsx19("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
|
|
663
|
+
step.durationMs > 0 ? /* @__PURE__ */ jsx19("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(step.durationMs) }) : null
|
|
513
664
|
] }),
|
|
514
|
-
step.errorMessage ? /* @__PURE__ */
|
|
665
|
+
step.errorMessage ? /* @__PURE__ */ jsx19(
|
|
515
666
|
"pre",
|
|
516
667
|
{
|
|
517
668
|
role: "alert",
|
|
@@ -519,132 +670,17 @@ function ReportStepItem({ step }) {
|
|
|
519
670
|
children: step.errorMessage
|
|
520
671
|
}
|
|
521
672
|
) : null,
|
|
522
|
-
step.docEntries.length > 0 ? /* @__PURE__ */
|
|
673
|
+
step.docEntries.length > 0 ? /* @__PURE__ */ jsx19("div", { "data-es-docs": true, className: "mt-2 ml-6", children: /* @__PURE__ */ jsx19(ReportDocEntries, { entries: step.docEntries }) }) : null
|
|
523
674
|
]
|
|
524
675
|
}
|
|
525
676
|
);
|
|
526
677
|
}
|
|
527
678
|
|
|
528
|
-
// ../executable-stories-core/dist/state-diff.js
|
|
529
|
-
var isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
530
|
-
function deepEqual(a, b) {
|
|
531
|
-
if (Object.is(a, b)) return true;
|
|
532
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
533
|
-
return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
|
|
534
|
-
}
|
|
535
|
-
if (isPlainObject(a) && isPlainObject(b)) {
|
|
536
|
-
const ak = Object.keys(a);
|
|
537
|
-
const bk = Object.keys(b);
|
|
538
|
-
return ak.length === bk.length && ak.every((k) => k in b && deepEqual(a[k], b[k]));
|
|
539
|
-
}
|
|
540
|
-
return false;
|
|
541
|
-
}
|
|
542
|
-
var joinKey = (path, key) => path === "" ? key : `${path}.${key}`;
|
|
543
|
-
function walk(path, before, after, out) {
|
|
544
|
-
if (Object.is(before, after)) return;
|
|
545
|
-
if (Array.isArray(before) && Array.isArray(after)) {
|
|
546
|
-
const shared = Math.min(before.length, after.length);
|
|
547
|
-
for (let i = 0; i < shared; i++) walk(`${path}[${i}]`, before[i], after[i], out);
|
|
548
|
-
for (let i = shared; i < after.length; i++) out.push({ path: `${path}[${i}]`, kind: "added", after: after[i] });
|
|
549
|
-
for (let i = shared; i < before.length; i++) out.push({ path: `${path}[${i}]`, kind: "removed", before: before[i] });
|
|
550
|
-
return;
|
|
551
|
-
}
|
|
552
|
-
if (isPlainObject(before) && isPlainObject(after)) {
|
|
553
|
-
for (const key of Object.keys(after)) {
|
|
554
|
-
const p = joinKey(path, key);
|
|
555
|
-
if (key in before) walk(p, before[key], after[key], out);
|
|
556
|
-
else out.push({ path: p, kind: "added", after: after[key] });
|
|
557
|
-
}
|
|
558
|
-
for (const key of Object.keys(before)) {
|
|
559
|
-
if (!(key in after)) out.push({ path: joinKey(path, key), kind: "removed", before: before[key] });
|
|
560
|
-
}
|
|
561
|
-
return;
|
|
562
|
-
}
|
|
563
|
-
if (!deepEqual(before, after)) out.push({ path, kind: "changed", before, after });
|
|
564
|
-
}
|
|
565
|
-
function diffStateValues(before, after) {
|
|
566
|
-
const out = [];
|
|
567
|
-
walk("", before, after, out);
|
|
568
|
-
return out;
|
|
569
|
-
}
|
|
570
|
-
function formatStateValue(value, maxLen = 60) {
|
|
571
|
-
const s = value === void 0 ? "undefined" : JSON.stringify(value);
|
|
572
|
-
return s.length > maxLen ? `${s.slice(0, maxLen - 1)}\u2026` : s;
|
|
573
|
-
}
|
|
574
|
-
function summarizeStateChanges(changes) {
|
|
575
|
-
return changes.map((c) => {
|
|
576
|
-
const at = c.path === "" ? "(root)" : c.path;
|
|
577
|
-
switch (c.kind) {
|
|
578
|
-
case "added":
|
|
579
|
-
return `+ ${at}: ${formatStateValue(c.after)}`;
|
|
580
|
-
case "removed":
|
|
581
|
-
return `\u2212 ${at}`;
|
|
582
|
-
case "changed":
|
|
583
|
-
return `${at}: ${formatStateValue(c.before)} \u2192 ${formatStateValue(c.after)}`;
|
|
584
|
-
}
|
|
585
|
-
});
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
// ../executable-stories-core/dist/storyboard.js
|
|
589
|
-
function findScreenshot(entries) {
|
|
590
|
-
for (const entry of entries) {
|
|
591
|
-
if (entry.kind === "screenshot") return entry;
|
|
592
|
-
if (entry.children) {
|
|
593
|
-
const nested = findScreenshot(entry.children);
|
|
594
|
-
if (nested) return nested;
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
return void 0;
|
|
598
|
-
}
|
|
599
|
-
function findStates(entries, out = []) {
|
|
600
|
-
for (const entry of entries) {
|
|
601
|
-
if (entry.kind === "state") out.push(entry);
|
|
602
|
-
if (entry.children) findStates(entry.children, out);
|
|
603
|
-
}
|
|
604
|
-
return out;
|
|
605
|
-
}
|
|
606
|
-
var laneOf = (label) => label ?? "";
|
|
607
|
-
function extractStoryboardFrames(scenario) {
|
|
608
|
-
const frames = [];
|
|
609
|
-
const laneOrder = [];
|
|
610
|
-
const previous = /* @__PURE__ */ new Map();
|
|
611
|
-
for (const step of scenario.steps) {
|
|
612
|
-
const shot = findScreenshot(step.docEntries);
|
|
613
|
-
const stateDocs = findStates(step.docEntries);
|
|
614
|
-
if (!shot && stateDocs.length === 0) continue;
|
|
615
|
-
const byLane = /* @__PURE__ */ new Map();
|
|
616
|
-
for (const doc of stateDocs) {
|
|
617
|
-
const lane = laneOf(doc.label);
|
|
618
|
-
if (!byLane.has(lane) && !laneOrder.includes(lane)) laneOrder.push(lane);
|
|
619
|
-
byLane.set(lane, doc);
|
|
620
|
-
}
|
|
621
|
-
const states = [];
|
|
622
|
-
for (const lane of laneOrder) {
|
|
623
|
-
const doc = byLane.get(lane);
|
|
624
|
-
if (!doc) continue;
|
|
625
|
-
const card = {
|
|
626
|
-
...doc.label !== void 0 && { label: doc.label },
|
|
627
|
-
value: doc.value
|
|
628
|
-
};
|
|
629
|
-
if (previous.has(lane)) card.changes = diffStateValues(previous.get(lane), doc.value);
|
|
630
|
-
previous.set(lane, doc.value);
|
|
631
|
-
states.push(card);
|
|
632
|
-
}
|
|
633
|
-
frames.push({
|
|
634
|
-
stepId: step.id,
|
|
635
|
-
stepIndex: step.index,
|
|
636
|
-
keyword: step.keyword,
|
|
637
|
-
text: step.text,
|
|
638
|
-
status: step.status,
|
|
639
|
-
...shot && { screenshot: { path: shot.path, ...shot.alt !== void 0 && { alt: shot.alt } } },
|
|
640
|
-
states
|
|
641
|
-
});
|
|
642
|
-
}
|
|
643
|
-
return frames;
|
|
644
|
-
}
|
|
645
|
-
|
|
646
679
|
// src/components/ReportStoryboard.tsx
|
|
647
|
-
import {
|
|
680
|
+
import { extractStoryboardFrames } from "executable-stories-core/storyboard";
|
|
681
|
+
import { summarizeStateChanges } from "executable-stories-core/state-diff";
|
|
682
|
+
import { isLocalFsPath as isLocalFsPath2, safeImageUrl as safeImageUrl2 } from "executable-stories-core/utils/url";
|
|
683
|
+
import { jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
648
684
|
var FRAME_GLYPH = {
|
|
649
685
|
passed: "\u2713",
|
|
650
686
|
failed: "\u2717",
|
|
@@ -660,46 +696,46 @@ var FRAME_GLYPH_COLOR = {
|
|
|
660
696
|
function ReportStoryboard({ scenario }) {
|
|
661
697
|
const frames = extractStoryboardFrames(scenario);
|
|
662
698
|
if (frames.length < 2) return null;
|
|
663
|
-
return /* @__PURE__ */
|
|
664
|
-
/* @__PURE__ */
|
|
665
|
-
/* @__PURE__ */
|
|
699
|
+
return /* @__PURE__ */ jsxs12("section", { "data-slot": "storyboard", "aria-label": "Storyboard", className: "mb-3", children: [
|
|
700
|
+
/* @__PURE__ */ jsx20("h4", { className: "mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Storyboard" }),
|
|
701
|
+
/* @__PURE__ */ jsx20("ol", { className: "flex items-start gap-3 overflow-x-auto pb-2", children: frames.map((frame) => /* @__PURE__ */ jsx20(StoryboardFrameItem, { frame }, frame.stepId)) })
|
|
666
702
|
] });
|
|
667
703
|
}
|
|
668
704
|
function StoryboardFrameItem({ frame }) {
|
|
669
705
|
const label = `${frame.keyword} ${frame.text}`;
|
|
670
706
|
const hasStates = frame.states.length > 0;
|
|
671
|
-
const caption = /* @__PURE__ */
|
|
672
|
-
/* @__PURE__ */
|
|
673
|
-
/* @__PURE__ */
|
|
674
|
-
/* @__PURE__ */
|
|
707
|
+
const caption = /* @__PURE__ */ jsxs12("p", { className: "mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug", children: [
|
|
708
|
+
/* @__PURE__ */ jsx20("span", { "aria-hidden": true, className: cn("shrink-0", FRAME_GLYPH_COLOR[frame.status]), children: FRAME_GLYPH[frame.status] ?? "\u25CB" }),
|
|
709
|
+
/* @__PURE__ */ jsxs12("span", { className: "min-w-0", children: [
|
|
710
|
+
/* @__PURE__ */ jsx20("span", { className: "font-mono font-semibold text-keyword", children: frame.keyword }),
|
|
675
711
|
" ",
|
|
676
|
-
/* @__PURE__ */
|
|
712
|
+
/* @__PURE__ */ jsx20("span", { className: "text-muted-foreground", children: frame.screenshot?.alt ?? frame.text })
|
|
677
713
|
] })
|
|
678
714
|
] });
|
|
679
715
|
return (
|
|
680
716
|
// State cards need room for diff rows; screenshot-only frames keep the
|
|
681
717
|
// original narrow film-cell width (and DOM) unchanged.
|
|
682
|
-
/* @__PURE__ */
|
|
683
|
-
frame.screenshot ? /* @__PURE__ */
|
|
684
|
-
hasStates ? /* @__PURE__ */
|
|
718
|
+
/* @__PURE__ */ jsxs12("li", { className: cn("shrink-0", hasStates ? "w-64" : "w-40"), children: [
|
|
719
|
+
frame.screenshot ? /* @__PURE__ */ jsx20(FrameScreenshot, { frame, label }) : null,
|
|
720
|
+
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,
|
|
685
721
|
frame.screenshot ? caption : (
|
|
686
722
|
// No screenshot means no image anchor, so the caption carries the
|
|
687
723
|
// jump-to-step link instead.
|
|
688
|
-
/* @__PURE__ */
|
|
724
|
+
/* @__PURE__ */ jsx20("a", { href: `#${frame.stepId}`, "aria-label": `Jump to step: ${label}`, className: "block hover:underline", children: caption })
|
|
689
725
|
)
|
|
690
726
|
] })
|
|
691
727
|
);
|
|
692
728
|
}
|
|
693
729
|
function FrameScreenshot({ frame, label }) {
|
|
694
730
|
const path = frame.screenshot?.path ?? "";
|
|
695
|
-
const src =
|
|
696
|
-
return /* @__PURE__ */
|
|
731
|
+
const src = isLocalFsPath2(path) ? void 0 : safeImageUrl2(path);
|
|
732
|
+
return /* @__PURE__ */ jsx20(
|
|
697
733
|
"a",
|
|
698
734
|
{
|
|
699
735
|
href: `#${frame.stepId}`,
|
|
700
736
|
"aria-label": `Jump to step: ${label}`,
|
|
701
737
|
className: "block overflow-hidden rounded-md border border-border transition-colors hover:border-ring",
|
|
702
|
-
children: src ? /* @__PURE__ */
|
|
738
|
+
children: src ? /* @__PURE__ */ jsx20(
|
|
703
739
|
"img",
|
|
704
740
|
{
|
|
705
741
|
src,
|
|
@@ -707,7 +743,7 @@ function FrameScreenshot({ frame, label }) {
|
|
|
707
743
|
loading: "lazy",
|
|
708
744
|
className: "h-24 w-full bg-muted object-cover object-top"
|
|
709
745
|
}
|
|
710
|
-
) : /* @__PURE__ */
|
|
746
|
+
) : /* @__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" })
|
|
711
747
|
}
|
|
712
748
|
);
|
|
713
749
|
}
|
|
@@ -726,12 +762,12 @@ function prettyJson(value) {
|
|
|
726
762
|
function StateCardView({ card }) {
|
|
727
763
|
const json = prettyJson(card.value);
|
|
728
764
|
const firstCapture = card.changes === void 0;
|
|
729
|
-
return /* @__PURE__ */
|
|
730
|
-
/* @__PURE__ */
|
|
731
|
-
/* @__PURE__ */
|
|
732
|
-
firstCapture ? /* @__PURE__ */
|
|
765
|
+
return /* @__PURE__ */ jsxs12("div", { "data-slot": "state-card", className: "rounded-md border border-border bg-card p-2", children: [
|
|
766
|
+
/* @__PURE__ */ jsxs12("p", { className: "flex flex-wrap items-baseline gap-1.5", children: [
|
|
767
|
+
/* @__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" }),
|
|
768
|
+
firstCapture ? /* @__PURE__ */ jsx20("span", { className: "text-[0.625rem] text-muted-foreground italic", children: "first capture" }) : null
|
|
733
769
|
] }),
|
|
734
|
-
!firstCapture && (card.changes && card.changes.length > 0 ? /* @__PURE__ */
|
|
770
|
+
!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(
|
|
735
771
|
"li",
|
|
736
772
|
{
|
|
737
773
|
className: cn(
|
|
@@ -741,15 +777,15 @@ function StateCardView({ card }) {
|
|
|
741
777
|
children: summarizeStateChanges([change])[0]
|
|
742
778
|
},
|
|
743
779
|
i
|
|
744
|
-
)) }) : /* @__PURE__ */
|
|
745
|
-
/* @__PURE__ */
|
|
780
|
+
)) }) : /* @__PURE__ */ jsx20("p", { className: "mt-1.5 text-[0.625rem] text-muted-foreground", children: "No changes" })),
|
|
781
|
+
/* @__PURE__ */ jsxs12(
|
|
746
782
|
"details",
|
|
747
783
|
{
|
|
748
784
|
open: firstCapture && json.length <= 240,
|
|
749
785
|
className: cn(firstCapture ? "mt-1.5" : "mt-1"),
|
|
750
786
|
children: [
|
|
751
|
-
/* @__PURE__ */
|
|
752
|
-
/* @__PURE__ */
|
|
787
|
+
/* @__PURE__ */ jsx20("summary", { className: "cursor-pointer text-[0.625rem] text-muted-foreground hover:text-foreground", children: "Snapshot" }),
|
|
788
|
+
/* @__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 })
|
|
753
789
|
]
|
|
754
790
|
}
|
|
755
791
|
)
|
|
@@ -757,17 +793,17 @@ function StateCardView({ card }) {
|
|
|
757
793
|
}
|
|
758
794
|
|
|
759
795
|
// src/components/ReportAttachments.tsx
|
|
760
|
-
import { Fragment as Fragment6, jsx as
|
|
796
|
+
import { Fragment as Fragment6, jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
761
797
|
function ReportAttachments({ attachments }) {
|
|
762
798
|
if (attachments.length === 0) return null;
|
|
763
799
|
return (
|
|
764
800
|
// role="group" (not a labelled <section>) so multiple scenarios' attachment
|
|
765
801
|
// blocks don't create duplicate "Attachments" region landmarks.
|
|
766
|
-
/* @__PURE__ */
|
|
802
|
+
/* @__PURE__ */ jsx21("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
|
|
767
803
|
const dataUri = att.contentEncoding === "BASE64" ? `data:${att.mediaType};base64,${att.body}` : `data:${att.mediaType},${encodeURIComponent(att.body)}`;
|
|
768
804
|
const isImage = att.mediaType.startsWith("image/");
|
|
769
|
-
return /* @__PURE__ */
|
|
770
|
-
/* @__PURE__ */
|
|
805
|
+
return /* @__PURE__ */ jsx21("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ jsxs13(Fragment6, { children: [
|
|
806
|
+
/* @__PURE__ */ jsx21(
|
|
771
807
|
"img",
|
|
772
808
|
{
|
|
773
809
|
src: dataUri,
|
|
@@ -776,8 +812,8 @@ function ReportAttachments({ attachments }) {
|
|
|
776
812
|
className: "max-w-full rounded-md border border-border"
|
|
777
813
|
}
|
|
778
814
|
),
|
|
779
|
-
/* @__PURE__ */
|
|
780
|
-
] }) : /* @__PURE__ */
|
|
815
|
+
/* @__PURE__ */ jsx21("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
|
|
816
|
+
] }) : /* @__PURE__ */ jsxs13(
|
|
781
817
|
"a",
|
|
782
818
|
{
|
|
783
819
|
href: dataUri,
|
|
@@ -786,7 +822,7 @@ function ReportAttachments({ attachments }) {
|
|
|
786
822
|
children: [
|
|
787
823
|
att.name,
|
|
788
824
|
" ",
|
|
789
|
-
/* @__PURE__ */
|
|
825
|
+
/* @__PURE__ */ jsxs13("span", { className: "text-muted-foreground", children: [
|
|
790
826
|
"(",
|
|
791
827
|
att.mediaType,
|
|
792
828
|
")"
|
|
@@ -798,6 +834,9 @@ function ReportAttachments({ attachments }) {
|
|
|
798
834
|
);
|
|
799
835
|
}
|
|
800
836
|
|
|
837
|
+
// src/components/ReportTrace.tsx
|
|
838
|
+
import { formatDuration as formatDuration2 } from "executable-stories-core/utils/duration";
|
|
839
|
+
|
|
801
840
|
// src/lib/trace.ts
|
|
802
841
|
var VALID = /* @__PURE__ */ new Set(["ok", "error", "unset"]);
|
|
803
842
|
var safeStatus = (s) => VALID.has(s) ? s : "unset";
|
|
@@ -850,15 +889,15 @@ function toTraceRows(spans) {
|
|
|
850
889
|
roots.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);
|
|
851
890
|
const rows = [];
|
|
852
891
|
const seen = /* @__PURE__ */ new Set();
|
|
853
|
-
const
|
|
892
|
+
const walk = (node, depth) => {
|
|
854
893
|
if (seen.has(node.span.spanId)) return;
|
|
855
894
|
seen.add(node.span.spanId);
|
|
856
895
|
rows.push({ ...node.span, depth });
|
|
857
|
-
for (const child of node.children)
|
|
896
|
+
for (const child of node.children) walk(child, depth + 1);
|
|
858
897
|
};
|
|
859
|
-
for (const root of roots)
|
|
898
|
+
for (const root of roots) walk(root, 0);
|
|
860
899
|
for (const node of byId.values()) {
|
|
861
|
-
if (!seen.has(node.span.spanId))
|
|
900
|
+
if (!seen.has(node.span.spanId)) walk(node, 0);
|
|
862
901
|
}
|
|
863
902
|
return rows;
|
|
864
903
|
}
|
|
@@ -874,7 +913,7 @@ function traceWindow(rows) {
|
|
|
874
913
|
}
|
|
875
914
|
|
|
876
915
|
// src/components/ReportTrace.tsx
|
|
877
|
-
import { jsx as
|
|
916
|
+
import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
878
917
|
var BAR_COLOR = {
|
|
879
918
|
ok: "bg-pass",
|
|
880
919
|
error: "bg-fail",
|
|
@@ -885,21 +924,21 @@ function ReportTrace({ spans }) {
|
|
|
885
924
|
const rows = toTraceRows(spans);
|
|
886
925
|
if (rows.length === 0) return null;
|
|
887
926
|
const { minStartMs, totalMs } = traceWindow(rows);
|
|
888
|
-
return /* @__PURE__ */
|
|
889
|
-
/* @__PURE__ */
|
|
927
|
+
return /* @__PURE__ */ jsxs14("details", { className: "mt-3 rounded-md border border-border bg-muted/30", children: [
|
|
928
|
+
/* @__PURE__ */ jsxs14("summary", { className: "cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground", children: [
|
|
890
929
|
"Trace (",
|
|
891
930
|
rows.length,
|
|
892
931
|
" span",
|
|
893
932
|
rows.length === 1 ? "" : "s",
|
|
894
933
|
", ",
|
|
895
|
-
|
|
934
|
+
formatDuration2(totalMs),
|
|
896
935
|
")"
|
|
897
936
|
] }),
|
|
898
|
-
/* @__PURE__ */
|
|
937
|
+
/* @__PURE__ */ jsx22("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
|
|
899
938
|
const leftPct = (row.startTimeMs - minStartMs) / totalMs * 100;
|
|
900
939
|
const widthPct = Math.max(row.durationMs / totalMs * 100, 0.5);
|
|
901
|
-
return /* @__PURE__ */
|
|
902
|
-
/* @__PURE__ */
|
|
940
|
+
return /* @__PURE__ */ jsxs14("li", { className: "flex items-center gap-2", children: [
|
|
941
|
+
/* @__PURE__ */ jsx22(
|
|
903
942
|
"span",
|
|
904
943
|
{
|
|
905
944
|
className: "min-w-0 flex-1 truncate text-foreground",
|
|
@@ -908,14 +947,14 @@ function ReportTrace({ spans }) {
|
|
|
908
947
|
children: row.name
|
|
909
948
|
}
|
|
910
949
|
),
|
|
911
|
-
/* @__PURE__ */
|
|
950
|
+
/* @__PURE__ */ jsx22("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ jsx22(
|
|
912
951
|
"span",
|
|
913
952
|
{
|
|
914
953
|
className: cn("absolute top-0 h-full rounded-sm", BAR_COLOR[row.status]),
|
|
915
954
|
style: { left: `${leftPct}%`, width: `${widthPct}%` }
|
|
916
955
|
}
|
|
917
956
|
) }),
|
|
918
|
-
/* @__PURE__ */
|
|
957
|
+
/* @__PURE__ */ jsx22("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration2(row.durationMs) })
|
|
919
958
|
] }, `${row.spanId}-${i}`);
|
|
920
959
|
}) })
|
|
921
960
|
] });
|
|
@@ -966,7 +1005,7 @@ function flakinessOf(entries) {
|
|
|
966
1005
|
}
|
|
967
1006
|
|
|
968
1007
|
// src/components/ScenarioRunHistory.tsx
|
|
969
|
-
import { Fragment as Fragment7, jsx as
|
|
1008
|
+
import { Fragment as Fragment7, jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
970
1009
|
var MAX_DOTS = 10;
|
|
971
1010
|
var DOT_COLOR = {
|
|
972
1011
|
passed: "bg-pass",
|
|
@@ -986,16 +1025,16 @@ function ScenarioRunHistory({ scenarioId }) {
|
|
|
986
1025
|
const recent = entries.slice(-MAX_DOTS);
|
|
987
1026
|
const flaky = flakinessOf(recent) === "flaky";
|
|
988
1027
|
const summary = flaky ? `${describeRunHistory(recent)} \xB7 Flaky` : describeRunHistory(recent);
|
|
989
|
-
return /* @__PURE__ */
|
|
990
|
-
flaky ? /* @__PURE__ */
|
|
991
|
-
/* @__PURE__ */
|
|
1028
|
+
return /* @__PURE__ */ jsxs15(Fragment7, { children: [
|
|
1029
|
+
flaky ? /* @__PURE__ */ jsx23(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
|
|
1030
|
+
/* @__PURE__ */ jsx23(
|
|
992
1031
|
"span",
|
|
993
1032
|
{
|
|
994
1033
|
role: "img",
|
|
995
1034
|
"aria-label": `Run history: ${summary}`,
|
|
996
1035
|
title: summary,
|
|
997
1036
|
className: "flex shrink-0 items-center gap-[3px]",
|
|
998
|
-
children: recent.map((e, i) => /* @__PURE__ */
|
|
1037
|
+
children: recent.map((e, i) => /* @__PURE__ */ jsx23(
|
|
999
1038
|
"span",
|
|
1000
1039
|
{
|
|
1001
1040
|
"aria-hidden": true,
|
|
@@ -1026,6 +1065,7 @@ function useCollapse() {
|
|
|
1026
1065
|
|
|
1027
1066
|
// src/interactive/scenario-actions.tsx
|
|
1028
1067
|
import { createContext as createContext4, useContext as useContext5 } from "react";
|
|
1068
|
+
import { scenarioToMarkdown as coreScenarioToMarkdown } from "executable-stories-core/utils/scenario-markdown";
|
|
1029
1069
|
var ScenarioActionsContext = createContext4(null);
|
|
1030
1070
|
var ScenarioActionsProvider = ScenarioActionsContext.Provider;
|
|
1031
1071
|
function useScenarioActions() {
|
|
@@ -1034,9 +1074,9 @@ function useScenarioActions() {
|
|
|
1034
1074
|
|
|
1035
1075
|
// src/components/ui/card.tsx
|
|
1036
1076
|
import "react";
|
|
1037
|
-
import { jsx as
|
|
1077
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
1038
1078
|
function Card({ className, ...props }) {
|
|
1039
|
-
return /* @__PURE__ */
|
|
1079
|
+
return /* @__PURE__ */ jsx24(
|
|
1040
1080
|
"div",
|
|
1041
1081
|
{
|
|
1042
1082
|
"data-slot": "card",
|
|
@@ -1049,7 +1089,7 @@ function Card({ className, ...props }) {
|
|
|
1049
1089
|
);
|
|
1050
1090
|
}
|
|
1051
1091
|
function CardHeader({ className, ...props }) {
|
|
1052
|
-
return /* @__PURE__ */
|
|
1092
|
+
return /* @__PURE__ */ jsx24(
|
|
1053
1093
|
"div",
|
|
1054
1094
|
{
|
|
1055
1095
|
"data-slot": "card-header",
|
|
@@ -1062,7 +1102,7 @@ function CardHeader({ className, ...props }) {
|
|
|
1062
1102
|
);
|
|
1063
1103
|
}
|
|
1064
1104
|
function CardContent({ className, ...props }) {
|
|
1065
|
-
return /* @__PURE__ */
|
|
1105
|
+
return /* @__PURE__ */ jsx24(
|
|
1066
1106
|
"div",
|
|
1067
1107
|
{
|
|
1068
1108
|
"data-slot": "card-content",
|
|
@@ -1076,13 +1116,13 @@ function CardContent({ className, ...props }) {
|
|
|
1076
1116
|
import "react";
|
|
1077
1117
|
import { Menu as MenuPrimitive } from "@base-ui/react/menu";
|
|
1078
1118
|
import { CheckIcon } from "lucide-react";
|
|
1079
|
-
import { jsx as
|
|
1119
|
+
import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1080
1120
|
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";
|
|
1081
1121
|
function DropdownMenu(props) {
|
|
1082
|
-
return /* @__PURE__ */
|
|
1122
|
+
return /* @__PURE__ */ jsx25(MenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
|
|
1083
1123
|
}
|
|
1084
1124
|
function DropdownMenuTrigger(props) {
|
|
1085
|
-
return /* @__PURE__ */
|
|
1125
|
+
return /* @__PURE__ */ jsx25(MenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
|
|
1086
1126
|
}
|
|
1087
1127
|
function DropdownMenuContent({
|
|
1088
1128
|
className,
|
|
@@ -1090,14 +1130,14 @@ function DropdownMenuContent({
|
|
|
1090
1130
|
sideOffset = 4,
|
|
1091
1131
|
...props
|
|
1092
1132
|
}) {
|
|
1093
|
-
return /* @__PURE__ */
|
|
1133
|
+
return /* @__PURE__ */ jsx25(MenuPrimitive.Portal, { children: /* @__PURE__ */ jsx25(
|
|
1094
1134
|
MenuPrimitive.Positioner,
|
|
1095
1135
|
{
|
|
1096
1136
|
"data-slot": "dropdown-menu-positioner",
|
|
1097
1137
|
className: "z-50",
|
|
1098
1138
|
align,
|
|
1099
1139
|
sideOffset,
|
|
1100
|
-
children: /* @__PURE__ */
|
|
1140
|
+
children: /* @__PURE__ */ jsx25(
|
|
1101
1141
|
MenuPrimitive.Popup,
|
|
1102
1142
|
{
|
|
1103
1143
|
"data-slot": "dropdown-menu-content",
|
|
@@ -1115,7 +1155,7 @@ function DropdownMenuItem({
|
|
|
1115
1155
|
className,
|
|
1116
1156
|
...props
|
|
1117
1157
|
}) {
|
|
1118
|
-
return /* @__PURE__ */
|
|
1158
|
+
return /* @__PURE__ */ jsx25(
|
|
1119
1159
|
MenuPrimitive.Item,
|
|
1120
1160
|
{
|
|
1121
1161
|
"data-slot": "dropdown-menu-item",
|
|
@@ -1127,7 +1167,7 @@ function DropdownMenuItem({
|
|
|
1127
1167
|
|
|
1128
1168
|
// src/components/ReportScenario.tsx
|
|
1129
1169
|
import { LinkIcon, FileTextIcon, SparklesIcon, MoreHorizontalIcon } from "lucide-react";
|
|
1130
|
-
import { jsx as
|
|
1170
|
+
import { jsx as jsx26, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1131
1171
|
var STATUS_META = {
|
|
1132
1172
|
passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
|
|
1133
1173
|
failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
|
|
@@ -1143,7 +1183,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1143
1183
|
const collapsible = collapse !== null && !hideTitle;
|
|
1144
1184
|
const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
|
|
1145
1185
|
const actions = useScenarioActions();
|
|
1146
|
-
return /* @__PURE__ */
|
|
1186
|
+
return /* @__PURE__ */ jsxs17(
|
|
1147
1187
|
Card,
|
|
1148
1188
|
{
|
|
1149
1189
|
id: scenario.id,
|
|
@@ -1151,10 +1191,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1151
1191
|
...hideTitle ? { "aria-label": `${scenario.title}, ${label}` } : { "aria-labelledby": titleId },
|
|
1152
1192
|
className: "gap-0 py-0",
|
|
1153
1193
|
children: [
|
|
1154
|
-
/* @__PURE__ */
|
|
1155
|
-
/* @__PURE__ */
|
|
1156
|
-
hideTitle ? null : /* @__PURE__ */
|
|
1157
|
-
collapsible ? /* @__PURE__ */
|
|
1194
|
+
/* @__PURE__ */ jsxs17(CardHeader, { className: "px-4 py-3", children: [
|
|
1195
|
+
/* @__PURE__ */ jsxs17("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
|
|
1196
|
+
hideTitle ? null : /* @__PURE__ */ jsxs17("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
|
|
1197
|
+
collapsible ? /* @__PURE__ */ jsx26(
|
|
1158
1198
|
"button",
|
|
1159
1199
|
{
|
|
1160
1200
|
type: "button",
|
|
@@ -1163,49 +1203,49 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1163
1203
|
"aria-controls": bodyId,
|
|
1164
1204
|
"aria-label": `Toggle ${scenario.title}`,
|
|
1165
1205
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
1166
|
-
children: /* @__PURE__ */
|
|
1206
|
+
children: /* @__PURE__ */ jsx26("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
1167
1207
|
}
|
|
1168
1208
|
) : null,
|
|
1169
|
-
/* @__PURE__ */
|
|
1170
|
-
/* @__PURE__ */
|
|
1209
|
+
/* @__PURE__ */ jsx26("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
|
|
1210
|
+
/* @__PURE__ */ jsx26("span", { children: scenario.title })
|
|
1171
1211
|
] }),
|
|
1172
|
-
/* @__PURE__ */
|
|
1173
|
-
/* @__PURE__ */
|
|
1174
|
-
scenario.durationMs > 0 ? /* @__PURE__ */
|
|
1175
|
-
meta.showPill ? /* @__PURE__ */
|
|
1176
|
-
actions ? /* @__PURE__ */
|
|
1177
|
-
/* @__PURE__ */
|
|
1212
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
1213
|
+
/* @__PURE__ */ jsx26(ScenarioRunHistory, { scenarioId: scenario.id }),
|
|
1214
|
+
scenario.durationMs > 0 ? /* @__PURE__ */ jsx26("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration3(scenario.durationMs) }) : null,
|
|
1215
|
+
meta.showPill ? /* @__PURE__ */ jsx26(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ jsx26("span", { className: "sr-only", children: `Status: ${label}` }),
|
|
1216
|
+
actions ? /* @__PURE__ */ jsxs17(DropdownMenu, { children: [
|
|
1217
|
+
/* @__PURE__ */ jsx26(
|
|
1178
1218
|
DropdownMenuTrigger,
|
|
1179
1219
|
{
|
|
1180
1220
|
"aria-label": `Actions for ${scenario.title}`,
|
|
1181
1221
|
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
1182
|
-
children: /* @__PURE__ */
|
|
1222
|
+
children: /* @__PURE__ */ jsx26(MoreHorizontalIcon, { "aria-hidden": true })
|
|
1183
1223
|
}
|
|
1184
1224
|
),
|
|
1185
|
-
/* @__PURE__ */
|
|
1186
|
-
/* @__PURE__ */
|
|
1187
|
-
/* @__PURE__ */
|
|
1225
|
+
/* @__PURE__ */ jsxs17(DropdownMenuContent, { align: "end", children: [
|
|
1226
|
+
/* @__PURE__ */ jsxs17(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
|
|
1227
|
+
/* @__PURE__ */ jsx26(LinkIcon, {}),
|
|
1188
1228
|
" Copy link"
|
|
1189
1229
|
] }),
|
|
1190
|
-
/* @__PURE__ */
|
|
1191
|
-
/* @__PURE__ */
|
|
1230
|
+
/* @__PURE__ */ jsxs17(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
|
|
1231
|
+
/* @__PURE__ */ jsx26(FileTextIcon, {}),
|
|
1192
1232
|
" Copy as Markdown"
|
|
1193
1233
|
] }),
|
|
1194
|
-
/* @__PURE__ */
|
|
1195
|
-
/* @__PURE__ */
|
|
1234
|
+
/* @__PURE__ */ jsxs17(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
|
|
1235
|
+
/* @__PURE__ */ jsx26(SparklesIcon, {}),
|
|
1196
1236
|
" Explain with AI"
|
|
1197
1237
|
] })
|
|
1198
1238
|
] })
|
|
1199
1239
|
] }) : null
|
|
1200
1240
|
] })
|
|
1201
1241
|
] }),
|
|
1202
|
-
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */
|
|
1203
|
-
scenario.tags.map((t) => /* @__PURE__ */
|
|
1204
|
-
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */
|
|
1242
|
+
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: [
|
|
1243
|
+
scenario.tags.map((t) => /* @__PURE__ */ jsx26("li", { children: /* @__PURE__ */ jsx26(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
|
|
1244
|
+
(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}`))
|
|
1205
1245
|
] }) : null
|
|
1206
1246
|
] }),
|
|
1207
|
-
/* @__PURE__ */
|
|
1208
|
-
scenario.errorMessage ? /* @__PURE__ */
|
|
1247
|
+
/* @__PURE__ */ jsxs17(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
|
|
1248
|
+
scenario.errorMessage ? /* @__PURE__ */ jsx26(
|
|
1209
1249
|
"pre",
|
|
1210
1250
|
{
|
|
1211
1251
|
role: "alert",
|
|
@@ -1213,11 +1253,11 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1213
1253
|
children: scenario.errorMessage
|
|
1214
1254
|
}
|
|
1215
1255
|
) : null,
|
|
1216
|
-
/* @__PURE__ */
|
|
1217
|
-
/* @__PURE__ */
|
|
1218
|
-
scenario.docEntries.length > 0 ? /* @__PURE__ */
|
|
1219
|
-
/* @__PURE__ */
|
|
1220
|
-
/* @__PURE__ */
|
|
1256
|
+
/* @__PURE__ */ jsx26(ReportStoryboard, { scenario }),
|
|
1257
|
+
/* @__PURE__ */ jsx26(ReportSteps, { scenario }),
|
|
1258
|
+
scenario.docEntries.length > 0 ? /* @__PURE__ */ jsx26("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ jsx26(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
|
|
1259
|
+
/* @__PURE__ */ jsx26(ReportAttachments, { attachments: scenario.attachments }),
|
|
1260
|
+
/* @__PURE__ */ jsx26(ReportTrace, { spans: scenario.otelSpans })
|
|
1221
1261
|
] })
|
|
1222
1262
|
]
|
|
1223
1263
|
}
|
|
@@ -1225,13 +1265,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1225
1265
|
}
|
|
1226
1266
|
|
|
1227
1267
|
// src/components/ReportScenarioList.tsx
|
|
1228
|
-
import { Fragment as Fragment8, jsx as
|
|
1268
|
+
import { Fragment as Fragment8, jsx as jsx27 } from "react/jsx-runtime";
|
|
1229
1269
|
function ReportScenarioList({ feature }) {
|
|
1230
|
-
return /* @__PURE__ */
|
|
1270
|
+
return /* @__PURE__ */ jsx27(Fragment8, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ jsx27(ReportScenario, { scenario }, scenario.id)) });
|
|
1231
1271
|
}
|
|
1232
1272
|
|
|
1233
1273
|
// src/components/ReportFeature.tsx
|
|
1234
|
-
import { Fragment as Fragment9, jsx as
|
|
1274
|
+
import { Fragment as Fragment9, jsx as jsx28, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1235
1275
|
function ReportFeature({ feature }) {
|
|
1236
1276
|
const titleId = `${feature.id}-title`;
|
|
1237
1277
|
const bodyId = `${feature.id}-body`;
|
|
@@ -1242,7 +1282,7 @@ function ReportFeature({ feature }) {
|
|
|
1242
1282
|
return (
|
|
1243
1283
|
// Suite = a section heading + a divider, NOT another bordered card. Drops a
|
|
1244
1284
|
// layer of nesting so the scenario cards below read as the primary unit.
|
|
1245
|
-
/* @__PURE__ */
|
|
1285
|
+
/* @__PURE__ */ jsxs18(
|
|
1246
1286
|
"section",
|
|
1247
1287
|
{
|
|
1248
1288
|
id: feature.id,
|
|
@@ -1250,9 +1290,9 @@ function ReportFeature({ feature }) {
|
|
|
1250
1290
|
"aria-labelledby": titleId,
|
|
1251
1291
|
className: "flex flex-col gap-3",
|
|
1252
1292
|
children: [
|
|
1253
|
-
/* @__PURE__ */
|
|
1254
|
-
/* @__PURE__ */
|
|
1255
|
-
/* @__PURE__ */
|
|
1293
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
|
|
1294
|
+
/* @__PURE__ */ jsxs18("div", { className: "min-w-0", children: [
|
|
1295
|
+
/* @__PURE__ */ jsx28("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ jsxs18(
|
|
1256
1296
|
"button",
|
|
1257
1297
|
{
|
|
1258
1298
|
type: "button",
|
|
@@ -1261,31 +1301,31 @@ function ReportFeature({ feature }) {
|
|
|
1261
1301
|
"aria-controls": bodyId,
|
|
1262
1302
|
className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
|
|
1263
1303
|
children: [
|
|
1264
|
-
/* @__PURE__ */
|
|
1265
|
-
/* @__PURE__ */
|
|
1304
|
+
/* @__PURE__ */ jsx28("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
|
|
1305
|
+
/* @__PURE__ */ jsx28("span", { className: "truncate", children: feature.title })
|
|
1266
1306
|
]
|
|
1267
1307
|
}
|
|
1268
1308
|
) : feature.title }),
|
|
1269
|
-
/* @__PURE__ */
|
|
1309
|
+
/* @__PURE__ */ jsx28("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
|
|
1270
1310
|
] }),
|
|
1271
|
-
/* @__PURE__ */
|
|
1311
|
+
/* @__PURE__ */ jsxs18(
|
|
1272
1312
|
"p",
|
|
1273
1313
|
{
|
|
1274
1314
|
className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
|
|
1275
1315
|
"aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
|
|
1276
1316
|
children: [
|
|
1277
|
-
/* @__PURE__ */
|
|
1317
|
+
/* @__PURE__ */ jsxs18("span", { children: [
|
|
1278
1318
|
s.passed,
|
|
1279
1319
|
" passed"
|
|
1280
1320
|
] }),
|
|
1281
|
-
/* @__PURE__ */
|
|
1282
|
-
/* @__PURE__ */
|
|
1321
|
+
/* @__PURE__ */ jsx28("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1322
|
+
/* @__PURE__ */ jsxs18("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
|
|
1283
1323
|
s.failed,
|
|
1284
1324
|
" failed"
|
|
1285
1325
|
] }),
|
|
1286
|
-
skipped > 0 ? /* @__PURE__ */
|
|
1287
|
-
/* @__PURE__ */
|
|
1288
|
-
/* @__PURE__ */
|
|
1326
|
+
skipped > 0 ? /* @__PURE__ */ jsxs18(Fragment9, { children: [
|
|
1327
|
+
/* @__PURE__ */ jsx28("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1328
|
+
/* @__PURE__ */ jsxs18("span", { children: [
|
|
1289
1329
|
skipped,
|
|
1290
1330
|
" skipped"
|
|
1291
1331
|
] })
|
|
@@ -1294,7 +1334,7 @@ function ReportFeature({ feature }) {
|
|
|
1294
1334
|
}
|
|
1295
1335
|
)
|
|
1296
1336
|
] }),
|
|
1297
|
-
/* @__PURE__ */
|
|
1337
|
+
/* @__PURE__ */ jsx28("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ jsx28(ReportScenarioList, { feature }) })
|
|
1298
1338
|
]
|
|
1299
1339
|
}
|
|
1300
1340
|
)
|
|
@@ -1302,17 +1342,17 @@ function ReportFeature({ feature }) {
|
|
|
1302
1342
|
}
|
|
1303
1343
|
|
|
1304
1344
|
// src/components/ReportFeatureList.tsx
|
|
1305
|
-
import { jsx as
|
|
1345
|
+
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
1306
1346
|
function ReportFeatureList() {
|
|
1307
1347
|
const report = useReport();
|
|
1308
|
-
return /* @__PURE__ */
|
|
1348
|
+
return /* @__PURE__ */ jsx29("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ jsx29(ReportFeature, { feature }, feature.id)) });
|
|
1309
1349
|
}
|
|
1310
1350
|
|
|
1311
1351
|
// src/components/ui/empty.tsx
|
|
1312
1352
|
import { cva as cva2 } from "class-variance-authority";
|
|
1313
|
-
import { jsx as
|
|
1353
|
+
import { jsx as jsx30 } from "react/jsx-runtime";
|
|
1314
1354
|
function Empty({ className, ...props }) {
|
|
1315
|
-
return /* @__PURE__ */
|
|
1355
|
+
return /* @__PURE__ */ jsx30(
|
|
1316
1356
|
"div",
|
|
1317
1357
|
{
|
|
1318
1358
|
"data-slot": "empty",
|
|
@@ -1325,7 +1365,7 @@ function Empty({ className, ...props }) {
|
|
|
1325
1365
|
);
|
|
1326
1366
|
}
|
|
1327
1367
|
function EmptyHeader({ className, ...props }) {
|
|
1328
|
-
return /* @__PURE__ */
|
|
1368
|
+
return /* @__PURE__ */ jsx30(
|
|
1329
1369
|
"div",
|
|
1330
1370
|
{
|
|
1331
1371
|
"data-slot": "empty-header",
|
|
@@ -1352,7 +1392,7 @@ var emptyMediaVariants = cva2(
|
|
|
1352
1392
|
}
|
|
1353
1393
|
);
|
|
1354
1394
|
function EmptyTitle({ className, ...props }) {
|
|
1355
|
-
return /* @__PURE__ */
|
|
1395
|
+
return /* @__PURE__ */ jsx30(
|
|
1356
1396
|
"div",
|
|
1357
1397
|
{
|
|
1358
1398
|
"data-slot": "empty-title",
|
|
@@ -1363,16 +1403,16 @@ function EmptyTitle({ className, ...props }) {
|
|
|
1363
1403
|
}
|
|
1364
1404
|
|
|
1365
1405
|
// src/components/ReportEmpty.tsx
|
|
1366
|
-
import { jsx as
|
|
1406
|
+
import { jsx as jsx31 } from "react/jsx-runtime";
|
|
1367
1407
|
function ReportEmpty({ message }) {
|
|
1368
|
-
return /* @__PURE__ */
|
|
1408
|
+
return /* @__PURE__ */ jsx31(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ jsx31(EmptyHeader, { children: /* @__PURE__ */ jsx31(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
|
|
1369
1409
|
}
|
|
1370
1410
|
|
|
1371
1411
|
// src/components/ReportSummary.tsx
|
|
1372
|
-
import { jsx as
|
|
1412
|
+
import { jsx as jsx32, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1373
1413
|
function ReportSummary({ className }) {
|
|
1374
1414
|
const report = useReport();
|
|
1375
|
-
return /* @__PURE__ */
|
|
1415
|
+
return /* @__PURE__ */ jsx32(
|
|
1376
1416
|
ReportSummaryView,
|
|
1377
1417
|
{
|
|
1378
1418
|
summary: report.summary,
|
|
@@ -1398,7 +1438,7 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1398
1438
|
if (summary.pending > 0) {
|
|
1399
1439
|
cards.push({ status: "pending", label: "Pending", value: summary.pending });
|
|
1400
1440
|
}
|
|
1401
|
-
return /* @__PURE__ */
|
|
1441
|
+
return /* @__PURE__ */ jsx32(
|
|
1402
1442
|
"dl",
|
|
1403
1443
|
{
|
|
1404
1444
|
className: cn(
|
|
@@ -1411,17 +1451,17 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1411
1451
|
"aria-label": ariaLabel,
|
|
1412
1452
|
children: cards.map((c) => {
|
|
1413
1453
|
const tone = TONE[c.status];
|
|
1414
|
-
return /* @__PURE__ */
|
|
1454
|
+
return /* @__PURE__ */ jsxs19(
|
|
1415
1455
|
"div",
|
|
1416
1456
|
{
|
|
1417
1457
|
"data-status": c.status,
|
|
1418
1458
|
className: "rounded-lg border bg-card px-4 py-3",
|
|
1419
1459
|
children: [
|
|
1420
|
-
/* @__PURE__ */
|
|
1421
|
-
/* @__PURE__ */
|
|
1460
|
+
/* @__PURE__ */ jsxs19("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
|
|
1461
|
+
/* @__PURE__ */ jsx32("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
|
|
1422
1462
|
c.label
|
|
1423
1463
|
] }),
|
|
1424
|
-
/* @__PURE__ */
|
|
1464
|
+
/* @__PURE__ */ jsx32("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
|
|
1425
1465
|
]
|
|
1426
1466
|
},
|
|
1427
1467
|
c.status
|
|
@@ -1431,6 +1471,9 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1431
1471
|
);
|
|
1432
1472
|
}
|
|
1433
1473
|
|
|
1474
|
+
// src/components/ReportMeta.tsx
|
|
1475
|
+
import { formatDuration as formatDuration4 } from "executable-stories-core/utils/duration";
|
|
1476
|
+
|
|
1434
1477
|
// src/lib/provenance.ts
|
|
1435
1478
|
function reportLastRunMs(report) {
|
|
1436
1479
|
if (report.finishedAtMs && report.finishedAtMs > 0) return report.finishedAtMs;
|
|
@@ -1481,7 +1524,7 @@ function prUrl(ci) {
|
|
|
1481
1524
|
}
|
|
1482
1525
|
|
|
1483
1526
|
// src/components/ReportMeta.tsx
|
|
1484
|
-
import { jsx as
|
|
1527
|
+
import { jsx as jsx33, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1485
1528
|
function ReportMeta() {
|
|
1486
1529
|
const report = useReport();
|
|
1487
1530
|
const items = [];
|
|
@@ -1490,7 +1533,7 @@ function ReportMeta() {
|
|
|
1490
1533
|
items.push({ label: "Started", value: new Date(report.startedAtMs).toLocaleString() });
|
|
1491
1534
|
}
|
|
1492
1535
|
if (report.durationMs) {
|
|
1493
|
-
items.push({ label: "Duration", value:
|
|
1536
|
+
items.push({ label: "Duration", value: formatDuration4(report.durationMs) });
|
|
1494
1537
|
}
|
|
1495
1538
|
if (report.packageVersion) {
|
|
1496
1539
|
items.push({ label: "Version", value: report.packageVersion });
|
|
@@ -1504,13 +1547,13 @@ function ReportMeta() {
|
|
|
1504
1547
|
const short = sha.slice(0, 8);
|
|
1505
1548
|
items.push({
|
|
1506
1549
|
label: "Commit",
|
|
1507
|
-
value: url ? /* @__PURE__ */
|
|
1550
|
+
value: url ? /* @__PURE__ */ jsx33("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
|
|
1508
1551
|
});
|
|
1509
1552
|
}
|
|
1510
1553
|
if (report.ci) {
|
|
1511
1554
|
items.push({
|
|
1512
1555
|
label: "CI",
|
|
1513
|
-
value: report.ci.url ? /* @__PURE__ */
|
|
1556
|
+
value: report.ci.url ? /* @__PURE__ */ jsxs20("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
|
|
1514
1557
|
ciDisplayName(report.ci.name),
|
|
1515
1558
|
report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
|
|
1516
1559
|
] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
|
|
@@ -1521,7 +1564,7 @@ function ReportMeta() {
|
|
|
1521
1564
|
const label = `#${report.ci.prNumber}`;
|
|
1522
1565
|
items.push({
|
|
1523
1566
|
label: "PR",
|
|
1524
|
-
value: url ? /* @__PURE__ */
|
|
1567
|
+
value: url ? /* @__PURE__ */ jsx33("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
|
|
1525
1568
|
});
|
|
1526
1569
|
}
|
|
1527
1570
|
if (items.length === 0) return null;
|
|
@@ -1529,48 +1572,48 @@ function ReportMeta() {
|
|
|
1529
1572
|
// Run metadata is useful but secondary to "what failed" — tuck it into a
|
|
1530
1573
|
// collapsed disclosure so it doesn't push the result down. Native <details>
|
|
1531
1574
|
// so it works with no JS (the SSR/no-hydration report still toggles).
|
|
1532
|
-
/* @__PURE__ */
|
|
1533
|
-
/* @__PURE__ */
|
|
1534
|
-
/* @__PURE__ */
|
|
1575
|
+
/* @__PURE__ */ jsxs20("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
|
|
1576
|
+
/* @__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: [
|
|
1577
|
+
/* @__PURE__ */ jsx33("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
|
|
1535
1578
|
"Run details"
|
|
1536
1579
|
] }),
|
|
1537
|
-
/* @__PURE__ */
|
|
1538
|
-
/* @__PURE__ */
|
|
1539
|
-
/* @__PURE__ */
|
|
1580
|
+
/* @__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: [
|
|
1581
|
+
/* @__PURE__ */ jsx33("dt", { className: "font-medium", children: item.label }),
|
|
1582
|
+
/* @__PURE__ */ jsx33("dd", { className: "font-mono text-foreground", children: item.value })
|
|
1540
1583
|
] }, item.label)) })
|
|
1541
1584
|
] })
|
|
1542
1585
|
);
|
|
1543
1586
|
}
|
|
1544
1587
|
|
|
1545
1588
|
// src/components/ReportSchemaError.tsx
|
|
1546
|
-
import { jsx as
|
|
1589
|
+
import { jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1547
1590
|
function ReportSchemaError({ error }) {
|
|
1548
|
-
return /* @__PURE__ */
|
|
1549
|
-
/* @__PURE__ */
|
|
1550
|
-
/* @__PURE__ */
|
|
1551
|
-
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */
|
|
1591
|
+
return /* @__PURE__ */ jsxs21("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
|
|
1592
|
+
/* @__PURE__ */ jsx34("p", { children: /* @__PURE__ */ jsx34("strong", { children: "Report could not be displayed." }) }),
|
|
1593
|
+
/* @__PURE__ */ jsx34("p", { children: error.message }),
|
|
1594
|
+
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ jsxs21("p", { children: [
|
|
1552
1595
|
"The report bundle is newer than this version of ",
|
|
1553
|
-
/* @__PURE__ */
|
|
1596
|
+
/* @__PURE__ */ jsx34("code", { children: "executable-stories-react" }),
|
|
1554
1597
|
". Upgrade the package, or regenerate the report with an older formatters CLI."
|
|
1555
1598
|
] }) : null,
|
|
1556
|
-
error.issues && error.issues.length > 0 ? /* @__PURE__ */
|
|
1557
|
-
/* @__PURE__ */
|
|
1599
|
+
error.issues && error.issues.length > 0 ? /* @__PURE__ */ jsxs21("details", { children: [
|
|
1600
|
+
/* @__PURE__ */ jsxs21("summary", { children: [
|
|
1558
1601
|
error.issues.length,
|
|
1559
1602
|
" validation issue",
|
|
1560
1603
|
error.issues.length === 1 ? "" : "s"
|
|
1561
1604
|
] }),
|
|
1562
|
-
/* @__PURE__ */
|
|
1605
|
+
/* @__PURE__ */ jsx34("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
|
|
1563
1606
|
] }) : null
|
|
1564
1607
|
] });
|
|
1565
1608
|
}
|
|
1566
1609
|
|
|
1567
1610
|
// src/components/ReportShell.tsx
|
|
1568
|
-
import { Fragment as Fragment10, jsx as
|
|
1611
|
+
import { Fragment as Fragment10, jsx as jsx35, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1569
1612
|
function ReportTitleBlock({ title }) {
|
|
1570
|
-
return /* @__PURE__ */
|
|
1571
|
-
/* @__PURE__ */
|
|
1572
|
-
/* @__PURE__ */
|
|
1573
|
-
/* @__PURE__ */
|
|
1613
|
+
return /* @__PURE__ */ jsxs22(Fragment10, { children: [
|
|
1614
|
+
/* @__PURE__ */ jsx35("h1", { children: title ?? "Story Report" }),
|
|
1615
|
+
/* @__PURE__ */ jsx35(ReportSummary, {}),
|
|
1616
|
+
/* @__PURE__ */ jsx35(ReportMeta, {})
|
|
1574
1617
|
] });
|
|
1575
1618
|
}
|
|
1576
1619
|
function ReportErrorShell({
|
|
@@ -1579,28 +1622,28 @@ function ReportErrorShell({
|
|
|
1579
1622
|
title,
|
|
1580
1623
|
dataTheme
|
|
1581
1624
|
}) {
|
|
1582
|
-
return /* @__PURE__ */
|
|
1625
|
+
return /* @__PURE__ */ jsx35("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ jsx35(ReportSchemaError, { error }) });
|
|
1583
1626
|
}
|
|
1584
1627
|
|
|
1585
1628
|
// src/components/Report.tsx
|
|
1586
|
-
import { jsx as
|
|
1629
|
+
import { jsx as jsx36, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1587
1630
|
function Report(props) {
|
|
1588
1631
|
const { report, customRenderers, renderers, className, title, dataTheme } = props;
|
|
1589
1632
|
const result = unwrapReport(report);
|
|
1590
1633
|
if (!result.ok) {
|
|
1591
|
-
return /* @__PURE__ */
|
|
1634
|
+
return /* @__PURE__ */ jsx36(ReportErrorShell, { error: result.error, className, title, dataTheme });
|
|
1592
1635
|
}
|
|
1593
1636
|
const data = result.data;
|
|
1594
1637
|
const hasContent = data.features.length > 0;
|
|
1595
|
-
return /* @__PURE__ */
|
|
1596
|
-
/* @__PURE__ */
|
|
1597
|
-
hasContent ? /* @__PURE__ */
|
|
1638
|
+
return /* @__PURE__ */ jsx36(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ jsxs23("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
|
|
1639
|
+
/* @__PURE__ */ jsx36("header", { className: "es-report-header", children: /* @__PURE__ */ jsx36(ReportTitleBlock, { title }) }),
|
|
1640
|
+
hasContent ? /* @__PURE__ */ jsx36(ReportFeatureList, {}) : /* @__PURE__ */ jsx36(ReportEmpty, {})
|
|
1598
1641
|
] }) });
|
|
1599
1642
|
}
|
|
1600
1643
|
|
|
1601
1644
|
// src/components/doc/MermaidView.tsx
|
|
1602
1645
|
import { useEffect, useRef, useState as useState2 } from "react";
|
|
1603
|
-
import { Fragment as Fragment11, jsx as
|
|
1646
|
+
import { Fragment as Fragment11, jsx as jsx37, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
1604
1647
|
function prefersDark(el) {
|
|
1605
1648
|
const themed = el?.closest("[data-theme]");
|
|
1606
1649
|
if (themed?.dataset.theme === "dark") return true;
|
|
@@ -1654,9 +1697,9 @@ function MermaidView({ entry, load }) {
|
|
|
1654
1697
|
};
|
|
1655
1698
|
}, [entry.code, load]);
|
|
1656
1699
|
if (svg) {
|
|
1657
|
-
return /* @__PURE__ */
|
|
1658
|
-
entry.title ? /* @__PURE__ */
|
|
1659
|
-
/* @__PURE__ */
|
|
1700
|
+
return /* @__PURE__ */ jsxs24("figure", { ref, className: "my-3", children: [
|
|
1701
|
+
entry.title ? /* @__PURE__ */ jsx37("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
|
|
1702
|
+
/* @__PURE__ */ jsx37(
|
|
1660
1703
|
"div",
|
|
1661
1704
|
{
|
|
1662
1705
|
role: "img",
|
|
@@ -1667,8 +1710,8 @@ function MermaidView({ entry, load }) {
|
|
|
1667
1710
|
)
|
|
1668
1711
|
] });
|
|
1669
1712
|
}
|
|
1670
|
-
return /* @__PURE__ */
|
|
1671
|
-
error ? /* @__PURE__ */
|
|
1713
|
+
return /* @__PURE__ */ jsxs24(Fragment11, { children: [
|
|
1714
|
+
error ? /* @__PURE__ */ jsxs24(
|
|
1672
1715
|
"p",
|
|
1673
1716
|
{
|
|
1674
1717
|
role: "alert",
|
|
@@ -1680,19 +1723,19 @@ function MermaidView({ entry, load }) {
|
|
|
1680
1723
|
]
|
|
1681
1724
|
}
|
|
1682
1725
|
) : null,
|
|
1683
|
-
/* @__PURE__ */
|
|
1726
|
+
/* @__PURE__ */ jsx37(MermaidSource, { entry, ref })
|
|
1684
1727
|
] });
|
|
1685
1728
|
}
|
|
1686
1729
|
|
|
1687
1730
|
// src/components/doc/MermaidDiagram.tsx
|
|
1688
|
-
import { jsx as
|
|
1731
|
+
import { jsx as jsx38 } from "react/jsx-runtime";
|
|
1689
1732
|
var mermaidLoader;
|
|
1690
1733
|
function loadMermaid() {
|
|
1691
1734
|
mermaidLoader ??= import("mermaid").then((m) => m.default);
|
|
1692
1735
|
return mermaidLoader;
|
|
1693
1736
|
}
|
|
1694
1737
|
function MermaidDiagram({ entry, load = loadMermaid }) {
|
|
1695
|
-
return /* @__PURE__ */
|
|
1738
|
+
return /* @__PURE__ */ jsx38(MermaidView, { entry, load });
|
|
1696
1739
|
}
|
|
1697
1740
|
|
|
1698
1741
|
// src/components/ScenarioExplorer.tsx
|
|
@@ -1702,12 +1745,12 @@ import { useState as useState3 } from "react";
|
|
|
1702
1745
|
import "react";
|
|
1703
1746
|
import { Command as CommandPrimitive } from "cmdk";
|
|
1704
1747
|
import { SearchIcon } from "lucide-react";
|
|
1705
|
-
import { jsx as
|
|
1748
|
+
import { jsx as jsx39, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
1706
1749
|
function Command({
|
|
1707
1750
|
className,
|
|
1708
1751
|
...props
|
|
1709
1752
|
}) {
|
|
1710
|
-
return /* @__PURE__ */
|
|
1753
|
+
return /* @__PURE__ */ jsx39(
|
|
1711
1754
|
CommandPrimitive,
|
|
1712
1755
|
{
|
|
1713
1756
|
"data-slot": "command",
|
|
@@ -1723,14 +1766,14 @@ function CommandInput({
|
|
|
1723
1766
|
className,
|
|
1724
1767
|
...props
|
|
1725
1768
|
}) {
|
|
1726
|
-
return /* @__PURE__ */
|
|
1769
|
+
return /* @__PURE__ */ jsxs25(
|
|
1727
1770
|
"div",
|
|
1728
1771
|
{
|
|
1729
1772
|
"data-slot": "command-input-wrapper",
|
|
1730
1773
|
className: "flex h-9 items-center gap-2 border-b px-3",
|
|
1731
1774
|
children: [
|
|
1732
|
-
/* @__PURE__ */
|
|
1733
|
-
/* @__PURE__ */
|
|
1775
|
+
/* @__PURE__ */ jsx39(SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
|
|
1776
|
+
/* @__PURE__ */ jsx39(
|
|
1734
1777
|
CommandPrimitive.Input,
|
|
1735
1778
|
{
|
|
1736
1779
|
"data-slot": "command-input",
|
|
@@ -1749,7 +1792,7 @@ function CommandList({
|
|
|
1749
1792
|
className,
|
|
1750
1793
|
...props
|
|
1751
1794
|
}) {
|
|
1752
|
-
return /* @__PURE__ */
|
|
1795
|
+
return /* @__PURE__ */ jsx39(
|
|
1753
1796
|
CommandPrimitive.List,
|
|
1754
1797
|
{
|
|
1755
1798
|
"data-slot": "command-list",
|
|
@@ -1764,7 +1807,7 @@ function CommandList({
|
|
|
1764
1807
|
function CommandEmpty({
|
|
1765
1808
|
...props
|
|
1766
1809
|
}) {
|
|
1767
|
-
return /* @__PURE__ */
|
|
1810
|
+
return /* @__PURE__ */ jsx39(
|
|
1768
1811
|
CommandPrimitive.Empty,
|
|
1769
1812
|
{
|
|
1770
1813
|
"data-slot": "command-empty",
|
|
@@ -1777,7 +1820,7 @@ function CommandGroup({
|
|
|
1777
1820
|
className,
|
|
1778
1821
|
...props
|
|
1779
1822
|
}) {
|
|
1780
|
-
return /* @__PURE__ */
|
|
1823
|
+
return /* @__PURE__ */ jsx39(
|
|
1781
1824
|
CommandPrimitive.Group,
|
|
1782
1825
|
{
|
|
1783
1826
|
"data-slot": "command-group",
|
|
@@ -1793,7 +1836,7 @@ function CommandItem({
|
|
|
1793
1836
|
className,
|
|
1794
1837
|
...props
|
|
1795
1838
|
}) {
|
|
1796
|
-
return /* @__PURE__ */
|
|
1839
|
+
return /* @__PURE__ */ jsx39(
|
|
1797
1840
|
CommandPrimitive.Item,
|
|
1798
1841
|
{
|
|
1799
1842
|
"data-slot": "command-item",
|
|
@@ -1807,7 +1850,7 @@ function CommandItem({
|
|
|
1807
1850
|
}
|
|
1808
1851
|
|
|
1809
1852
|
// src/components/ScenarioExplorer.tsx
|
|
1810
|
-
import { jsx as
|
|
1853
|
+
import { jsx as jsx40, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
1811
1854
|
var STATUS_FILTERS = [
|
|
1812
1855
|
{ value: "all", label: "All" },
|
|
1813
1856
|
{ value: "passed", label: "Passed" },
|
|
@@ -1818,22 +1861,22 @@ var STATUS_FILTERS = [
|
|
|
1818
1861
|
function ScenarioExplorer({ scenarios, summary }) {
|
|
1819
1862
|
const [status, setStatus] = useState3("all");
|
|
1820
1863
|
const visible = status === "all" ? scenarios : scenarios.filter((s) => s.status === status);
|
|
1821
|
-
return /* @__PURE__ */
|
|
1822
|
-
summary ? /* @__PURE__ */
|
|
1864
|
+
return /* @__PURE__ */ jsxs26("div", { className: "font-sans text-foreground", children: [
|
|
1865
|
+
summary ? /* @__PURE__ */ jsxs26("p", { className: "mb-3 text-sm text-muted-foreground", children: [
|
|
1823
1866
|
summary.total,
|
|
1824
1867
|
" scenarios \xB7 ",
|
|
1825
|
-
/* @__PURE__ */
|
|
1868
|
+
/* @__PURE__ */ jsxs26("span", { className: "text-pass", children: [
|
|
1826
1869
|
summary.passed,
|
|
1827
1870
|
" passed"
|
|
1828
1871
|
] }),
|
|
1829
1872
|
" \xB7",
|
|
1830
1873
|
" ",
|
|
1831
|
-
/* @__PURE__ */
|
|
1874
|
+
/* @__PURE__ */ jsxs26("span", { className: "text-fail", children: [
|
|
1832
1875
|
summary.failed,
|
|
1833
1876
|
" failed"
|
|
1834
1877
|
] })
|
|
1835
1878
|
] }) : null,
|
|
1836
|
-
/* @__PURE__ */
|
|
1879
|
+
/* @__PURE__ */ jsx40("div", { className: "mb-2 flex flex-wrap gap-1.5", role: "group", "aria-label": "Filter by status", children: STATUS_FILTERS.map((f) => /* @__PURE__ */ jsx40(
|
|
1837
1880
|
"button",
|
|
1838
1881
|
{
|
|
1839
1882
|
type: "button",
|
|
@@ -1848,26 +1891,26 @@ function ScenarioExplorer({ scenarios, summary }) {
|
|
|
1848
1891
|
},
|
|
1849
1892
|
f.value
|
|
1850
1893
|
)) }),
|
|
1851
|
-
/* @__PURE__ */
|
|
1894
|
+
/* @__PURE__ */ jsxs26(
|
|
1852
1895
|
Command,
|
|
1853
1896
|
{
|
|
1854
1897
|
className: "rounded-lg border border-border bg-card",
|
|
1855
1898
|
filter: (value, search) => value.toLowerCase().includes(search.toLowerCase()) ? 1 : 0,
|
|
1856
1899
|
children: [
|
|
1857
|
-
/* @__PURE__ */
|
|
1858
|
-
/* @__PURE__ */
|
|
1859
|
-
/* @__PURE__ */
|
|
1860
|
-
/* @__PURE__ */
|
|
1900
|
+
/* @__PURE__ */ jsx40(CommandInput, { placeholder: "Search scenarios\u2026" }),
|
|
1901
|
+
/* @__PURE__ */ jsxs26(CommandList, { className: "max-h-none", children: [
|
|
1902
|
+
/* @__PURE__ */ jsx40(CommandEmpty, { children: "No scenarios match your filters." }),
|
|
1903
|
+
/* @__PURE__ */ jsx40(CommandGroup, { children: visible.map((s) => /* @__PURE__ */ jsx40(
|
|
1861
1904
|
CommandItem,
|
|
1862
1905
|
{
|
|
1863
1906
|
value: `${s.title} ${s.feature} ${s.tags.join(" ")}`,
|
|
1864
1907
|
asChild: true,
|
|
1865
1908
|
className: "cursor-pointer",
|
|
1866
|
-
children: /* @__PURE__ */
|
|
1867
|
-
/* @__PURE__ */
|
|
1868
|
-
/* @__PURE__ */
|
|
1869
|
-
s.tags.slice(0, 3).map((t) => /* @__PURE__ */
|
|
1870
|
-
/* @__PURE__ */
|
|
1909
|
+
children: /* @__PURE__ */ jsxs26("a", { href: s.href, className: "flex items-center gap-3", children: [
|
|
1910
|
+
/* @__PURE__ */ jsx40(Badge, { variant: s.status, children: s.status }),
|
|
1911
|
+
/* @__PURE__ */ jsx40("span", { className: "min-w-0 flex-1 truncate font-medium", children: s.title }),
|
|
1912
|
+
s.tags.slice(0, 3).map((t) => /* @__PURE__ */ jsx40(Badge, { variant: "tag", className: "hidden sm:inline-flex", children: t }, t)),
|
|
1913
|
+
/* @__PURE__ */ jsx40("code", { className: "hidden font-mono text-xs text-muted-foreground md:inline", children: s.feature })
|
|
1871
1914
|
] })
|
|
1872
1915
|
},
|
|
1873
1916
|
s.id
|
|
@@ -2889,6 +2932,8 @@ function parseStoryReport(input) {
|
|
|
2889
2932
|
});
|
|
2890
2933
|
}
|
|
2891
2934
|
export {
|
|
2935
|
+
DATA_MODEL_TYPE,
|
|
2936
|
+
DataModelBlock,
|
|
2892
2937
|
DocCode,
|
|
2893
2938
|
DocCustom,
|
|
2894
2939
|
DocEntry,
|
|
@@ -2902,6 +2947,8 @@ export {
|
|
|
2902
2947
|
DocTable,
|
|
2903
2948
|
DocTag,
|
|
2904
2949
|
DocVideo,
|
|
2950
|
+
FILE_TREE_TYPE,
|
|
2951
|
+
FileTreeBlock,
|
|
2905
2952
|
MermaidDiagram,
|
|
2906
2953
|
MermaidSource,
|
|
2907
2954
|
Report,
|
|
@@ -2931,7 +2978,10 @@ export {
|
|
|
2931
2978
|
err,
|
|
2932
2979
|
formatRelativeAge,
|
|
2933
2980
|
isReportStale,
|
|
2981
|
+
narrativeBlockRenderers,
|
|
2934
2982
|
ok,
|
|
2983
|
+
parseDataModel,
|
|
2984
|
+
parseFileTree,
|
|
2935
2985
|
parseStoryReport,
|
|
2936
2986
|
prUrl,
|
|
2937
2987
|
reportLastRunMs,
|