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.cjs
CHANGED
|
@@ -31,6 +31,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
// src/index.ts
|
|
32
32
|
var src_exports = {};
|
|
33
33
|
__export(src_exports, {
|
|
34
|
+
DATA_MODEL_TYPE: () => DATA_MODEL_TYPE,
|
|
35
|
+
DataModelBlock: () => DataModelBlock,
|
|
34
36
|
DocCode: () => DocCode,
|
|
35
37
|
DocCustom: () => DocCustom,
|
|
36
38
|
DocEntry: () => DocEntry,
|
|
@@ -44,6 +46,8 @@ __export(src_exports, {
|
|
|
44
46
|
DocTable: () => DocTable,
|
|
45
47
|
DocTag: () => DocTag,
|
|
46
48
|
DocVideo: () => DocVideo,
|
|
49
|
+
FILE_TREE_TYPE: () => FILE_TREE_TYPE,
|
|
50
|
+
FileTreeBlock: () => FileTreeBlock,
|
|
47
51
|
MermaidDiagram: () => MermaidDiagram,
|
|
48
52
|
MermaidSource: () => MermaidSource,
|
|
49
53
|
Report: () => Report,
|
|
@@ -73,7 +77,10 @@ __export(src_exports, {
|
|
|
73
77
|
err: () => err,
|
|
74
78
|
formatRelativeAge: () => formatRelativeAge,
|
|
75
79
|
isReportStale: () => isReportStale,
|
|
80
|
+
narrativeBlockRenderers: () => narrativeBlockRenderers,
|
|
76
81
|
ok: () => ok,
|
|
82
|
+
parseDataModel: () => parseDataModel,
|
|
83
|
+
parseFileTree: () => parseFileTree,
|
|
77
84
|
parseStoryReport: () => parseStoryReport,
|
|
78
85
|
prUrl: () => prUrl,
|
|
79
86
|
reportLastRunMs: () => reportLastRunMs,
|
|
@@ -101,63 +108,6 @@ var import_react2 = require("react");
|
|
|
101
108
|
var import_react = require("react");
|
|
102
109
|
var ReportContext = (0, import_react.createContext)(null);
|
|
103
110
|
|
|
104
|
-
// src/context/ReportRoot.tsx
|
|
105
|
-
var import_jsx_runtime = require("react/jsx-runtime");
|
|
106
|
-
var EMPTY_CUSTOM = {};
|
|
107
|
-
var EMPTY_RENDERERS = {};
|
|
108
|
-
function ReportRoot({
|
|
109
|
-
report,
|
|
110
|
-
customRenderers,
|
|
111
|
-
renderers,
|
|
112
|
-
children
|
|
113
|
-
}) {
|
|
114
|
-
const value = (0, import_react2.useMemo)(
|
|
115
|
-
() => ({
|
|
116
|
-
report,
|
|
117
|
-
customRenderers: customRenderers ?? EMPTY_CUSTOM,
|
|
118
|
-
renderers: renderers ?? EMPTY_RENDERERS
|
|
119
|
-
}),
|
|
120
|
-
[report, customRenderers, renderers]
|
|
121
|
-
);
|
|
122
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ReportContext.Provider, { value, children });
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// src/hooks/useReport.ts
|
|
126
|
-
var import_react3 = require("react");
|
|
127
|
-
function useReport() {
|
|
128
|
-
const ctx = (0, import_react3.useContext)(ReportContext);
|
|
129
|
-
if (!ctx) {
|
|
130
|
-
throw new Error(
|
|
131
|
-
"useReport must be used inside <ReportRoot> or <Report>. Wrap your tree with one of those."
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
return ctx.report;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// ../executable-stories-core/dist/utils/duration.js
|
|
138
|
-
function formatDuration(ms) {
|
|
139
|
-
if (ms < 1e3) {
|
|
140
|
-
return `${Math.round(ms)} ms`;
|
|
141
|
-
}
|
|
142
|
-
if (ms < 6e4) {
|
|
143
|
-
return `${(ms / 1e3).toFixed(2)} s`;
|
|
144
|
-
}
|
|
145
|
-
const minutes = Math.floor(ms / 6e4);
|
|
146
|
-
const seconds = Math.floor(ms % 6e4 / 1e3);
|
|
147
|
-
if (minutes < 60) {
|
|
148
|
-
return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
|
|
149
|
-
}
|
|
150
|
-
const hours = Math.floor(minutes / 60);
|
|
151
|
-
const remainingMinutes = minutes % 60;
|
|
152
|
-
return `${hours}h ${remainingMinutes}m`;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// src/components/doc/DocNote.tsx
|
|
156
|
-
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
157
|
-
function DocNote({ entry }) {
|
|
158
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "my-2 text-sm text-muted-foreground", children: entry.text });
|
|
159
|
-
}
|
|
160
|
-
|
|
161
111
|
// src/components/ui/badge.tsx
|
|
162
112
|
var React = require("react");
|
|
163
113
|
var import_class_variance_authority = require("class-variance-authority");
|
|
@@ -216,14 +166,237 @@ function Badge({
|
|
|
216
166
|
});
|
|
217
167
|
}
|
|
218
168
|
|
|
219
|
-
// src/components/doc/
|
|
169
|
+
// src/components/doc/NarrativeBlocks.tsx
|
|
170
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
171
|
+
var FILE_TREE_TYPE = "file-tree";
|
|
172
|
+
var DATA_MODEL_TYPE = "data-model";
|
|
173
|
+
function isChangeKind(value) {
|
|
174
|
+
return value === "added" || value === "modified" || value === "removed" || value === "renamed";
|
|
175
|
+
}
|
|
176
|
+
function isRecord(value) {
|
|
177
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
178
|
+
}
|
|
179
|
+
function str(value) {
|
|
180
|
+
return typeof value === "string" && value !== "" ? value : void 0;
|
|
181
|
+
}
|
|
182
|
+
function AuthoredMarker({ authored }) {
|
|
183
|
+
if (authored !== "agent") return null;
|
|
184
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge, { variant: "outline", className: "border-border text-[10px] text-muted-foreground", children: "AI-authored, not verified by a run" });
|
|
185
|
+
}
|
|
186
|
+
function BlockFrame({
|
|
187
|
+
title,
|
|
188
|
+
authored,
|
|
189
|
+
children
|
|
190
|
+
}) {
|
|
191
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("figure", { className: "my-3", children: [
|
|
192
|
+
title || authored === "agent" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("figcaption", { className: "mb-1.5 flex flex-wrap items-center gap-2", children: [
|
|
193
|
+
title ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-xs font-medium text-muted-foreground", children: title }) : null,
|
|
194
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AuthoredMarker, { authored })
|
|
195
|
+
] }) : null,
|
|
196
|
+
children
|
|
197
|
+
] });
|
|
198
|
+
}
|
|
199
|
+
function ChangeBadge({ change }) {
|
|
200
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge, { variant: "tag", className: "text-[10px]", children: change });
|
|
201
|
+
}
|
|
202
|
+
function parseFileTree(data) {
|
|
203
|
+
if (!isRecord(data) || !Array.isArray(data.files)) return void 0;
|
|
204
|
+
const files = [];
|
|
205
|
+
for (const raw of data.files) {
|
|
206
|
+
if (typeof raw === "string") {
|
|
207
|
+
if (raw) files.push({ path: raw });
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
if (!isRecord(raw)) continue;
|
|
211
|
+
const path = str(raw.path);
|
|
212
|
+
if (!path) continue;
|
|
213
|
+
files.push({
|
|
214
|
+
path,
|
|
215
|
+
change: isChangeKind(raw.change) ? raw.change : void 0,
|
|
216
|
+
note: str(raw.note)
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
if (files.length === 0) return void 0;
|
|
220
|
+
return { title: str(data.title), authored: str(data.authored), files };
|
|
221
|
+
}
|
|
222
|
+
function buildTree(files) {
|
|
223
|
+
const root = { name: "", children: /* @__PURE__ */ new Map() };
|
|
224
|
+
for (const file of files) {
|
|
225
|
+
const segments = file.path.split("/").filter(Boolean);
|
|
226
|
+
let node = root;
|
|
227
|
+
segments.forEach((segment, index) => {
|
|
228
|
+
let child = node.children.get(segment);
|
|
229
|
+
if (!child) {
|
|
230
|
+
child = { name: segment, children: /* @__PURE__ */ new Map() };
|
|
231
|
+
node.children.set(segment, child);
|
|
232
|
+
}
|
|
233
|
+
if (index === segments.length - 1) child.file = file;
|
|
234
|
+
node = child;
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
return root;
|
|
238
|
+
}
|
|
239
|
+
function sortedChildren(node) {
|
|
240
|
+
return [...node.children.values()].sort((a, b) => {
|
|
241
|
+
const aDir = a.children.size > 0;
|
|
242
|
+
const bDir = b.children.size > 0;
|
|
243
|
+
if (aDir !== bDir) return aDir ? -1 : 1;
|
|
244
|
+
return a.name.localeCompare(b.name);
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
function TreeBranch({ node, depth }) {
|
|
248
|
+
const children = sortedChildren(node);
|
|
249
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: cn("space-y-0.5", depth > 0 && "ml-3 border-l border-border/60 pl-3"), children: children.map((child) => {
|
|
250
|
+
const isDir = child.children.size > 0;
|
|
251
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { children: [
|
|
252
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-wrap items-baseline gap-2", children: [
|
|
253
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
254
|
+
"span",
|
|
255
|
+
{
|
|
256
|
+
className: cn(
|
|
257
|
+
"font-mono text-xs",
|
|
258
|
+
isDir ? "text-muted-foreground" : "text-foreground"
|
|
259
|
+
),
|
|
260
|
+
children: isDir ? `${child.name}/` : child.name
|
|
261
|
+
}
|
|
262
|
+
),
|
|
263
|
+
child.file?.change ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChangeBadge, { change: child.file.change }) : null,
|
|
264
|
+
child.file?.note ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-xs text-muted-foreground", children: child.file.note }) : null
|
|
265
|
+
] }),
|
|
266
|
+
isDir ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TreeBranch, { node: child, depth: depth + 1 }) : null
|
|
267
|
+
] }, child.name);
|
|
268
|
+
}) });
|
|
269
|
+
}
|
|
270
|
+
function FileTreeBlock({ entry }) {
|
|
271
|
+
const data = parseFileTree(entry.data);
|
|
272
|
+
if (!data) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UnreadableBlock, { entry });
|
|
273
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BlockFrame, { title: data.title ?? "Files changed", authored: data.authored, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border bg-card p-3", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TreeBranch, { node: buildTree(data.files), depth: 0 }) }) });
|
|
274
|
+
}
|
|
275
|
+
function parseDataModel(data) {
|
|
276
|
+
if (!isRecord(data) || !Array.isArray(data.fields)) return void 0;
|
|
277
|
+
const fields = [];
|
|
278
|
+
for (const raw of data.fields) {
|
|
279
|
+
if (!isRecord(raw)) continue;
|
|
280
|
+
const name = str(raw.name);
|
|
281
|
+
if (!name) continue;
|
|
282
|
+
fields.push({
|
|
283
|
+
name,
|
|
284
|
+
type: str(raw.type),
|
|
285
|
+
note: str(raw.note),
|
|
286
|
+
change: isChangeKind(raw.change) ? raw.change : void 0
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
if (fields.length === 0) return void 0;
|
|
290
|
+
return {
|
|
291
|
+
title: str(data.title),
|
|
292
|
+
authored: str(data.authored),
|
|
293
|
+
name: str(data.name),
|
|
294
|
+
fields
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
function DataModelBlock({ entry }) {
|
|
298
|
+
const data = parseDataModel(entry.data);
|
|
299
|
+
if (!data) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UnreadableBlock, { entry });
|
|
300
|
+
const hasNotes = data.fields.some((f) => f.note);
|
|
301
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BlockFrame, { title: data.title ?? data.name ?? "Data model", authored: data.authored, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { className: "w-full border-collapse text-sm", children: [
|
|
302
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { className: "bg-muted/50", children: [
|
|
303
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Field" }),
|
|
304
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Type" }),
|
|
305
|
+
hasNotes ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Note" }) : null
|
|
306
|
+
] }) }),
|
|
307
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: data.fields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
|
|
308
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: "border-b border-border px-3 py-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "flex flex-wrap items-center gap-2", children: [
|
|
309
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-mono text-xs text-foreground", children: field.name }),
|
|
310
|
+
field.change ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChangeBadge, { change: field.change }) : null
|
|
311
|
+
] }) }),
|
|
312
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: "border-b border-border px-3 py-2 font-mono text-xs text-muted-foreground", children: field.type ?? "" }),
|
|
313
|
+
hasNotes ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: "border-b border-border px-3 py-2 text-foreground", children: field.note ?? "" }) : null
|
|
314
|
+
] }, field.name)) })
|
|
315
|
+
] }) }) });
|
|
316
|
+
}
|
|
317
|
+
function UnreadableBlock({ entry }) {
|
|
318
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "my-2", "data-type": entry.type, children: [
|
|
319
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: [
|
|
320
|
+
entry.type,
|
|
321
|
+
" (unrecognised shape)"
|
|
322
|
+
] }),
|
|
323
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
324
|
+
"pre",
|
|
325
|
+
{
|
|
326
|
+
tabIndex: 0,
|
|
327
|
+
className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground",
|
|
328
|
+
children: safeStringify(entry.data)
|
|
329
|
+
}
|
|
330
|
+
)
|
|
331
|
+
] });
|
|
332
|
+
}
|
|
333
|
+
function safeStringify(value) {
|
|
334
|
+
try {
|
|
335
|
+
return JSON.stringify(value, null, 2);
|
|
336
|
+
} catch {
|
|
337
|
+
return String(value);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
var narrativeBlockRenderers = {
|
|
341
|
+
[FILE_TREE_TYPE]: (entry) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileTreeBlock, { entry }),
|
|
342
|
+
[DATA_MODEL_TYPE]: (entry) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DataModelBlock, { entry })
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
// src/context/ReportRoot.tsx
|
|
346
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
347
|
+
var EMPTY_RENDERERS = {};
|
|
348
|
+
function ReportRoot({
|
|
349
|
+
report,
|
|
350
|
+
customRenderers,
|
|
351
|
+
renderers,
|
|
352
|
+
children
|
|
353
|
+
}) {
|
|
354
|
+
const value = (0, import_react2.useMemo)(
|
|
355
|
+
() => ({
|
|
356
|
+
report,
|
|
357
|
+
// Narrative blocks render everywhere the report does (static SSR, the
|
|
358
|
+
// island, Astro) without every host wiring them up. A host renderer for
|
|
359
|
+
// the same type still wins.
|
|
360
|
+
customRenderers: { ...narrativeBlockRenderers, ...customRenderers },
|
|
361
|
+
renderers: renderers ?? EMPTY_RENDERERS
|
|
362
|
+
}),
|
|
363
|
+
[report, customRenderers, renderers]
|
|
364
|
+
);
|
|
365
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ReportContext.Provider, { value, children });
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// src/hooks/useReport.ts
|
|
369
|
+
var import_react3 = require("react");
|
|
370
|
+
function useReport() {
|
|
371
|
+
const ctx = (0, import_react3.useContext)(ReportContext);
|
|
372
|
+
if (!ctx) {
|
|
373
|
+
throw new Error(
|
|
374
|
+
"useReport must be used inside <ReportRoot> or <Report>. Wrap your tree with one of those."
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
return ctx.report;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// src/components/ReportScenario.tsx
|
|
381
|
+
var import_duration3 = require("executable-stories-core/utils/duration");
|
|
382
|
+
|
|
383
|
+
// src/components/ReportSteps.tsx
|
|
384
|
+
var import_duration = require("executable-stories-core/utils/duration");
|
|
385
|
+
|
|
386
|
+
// src/components/doc/DocNote.tsx
|
|
220
387
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
388
|
+
function DocNote({ entry }) {
|
|
389
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "my-2 text-sm text-muted-foreground", children: entry.text });
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// src/components/doc/DocTag.tsx
|
|
393
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
221
394
|
function DocTag({ entry }) {
|
|
222
|
-
return /* @__PURE__ */ (0,
|
|
395
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { className: "my-2 flex flex-wrap gap-1.5", "aria-label": "Tags", children: entry.names.map((n) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Badge, { variant: "tag", children: n }) }, n)) });
|
|
223
396
|
}
|
|
224
397
|
|
|
225
398
|
// src/components/doc/DocKv.tsx
|
|
226
|
-
var
|
|
399
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
227
400
|
function formatValue(value) {
|
|
228
401
|
if (value === null) return "null";
|
|
229
402
|
if (typeof value === "string") return value;
|
|
@@ -235,19 +408,19 @@ function formatValue(value) {
|
|
|
235
408
|
}
|
|
236
409
|
}
|
|
237
410
|
function DocKv({ entry }) {
|
|
238
|
-
return /* @__PURE__ */ (0,
|
|
239
|
-
/* @__PURE__ */ (0,
|
|
240
|
-
/* @__PURE__ */ (0,
|
|
411
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("dl", { className: "my-2 flex flex-wrap items-baseline gap-x-2 text-sm", children: [
|
|
412
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { className: "font-semibold text-muted-foreground", children: entry.label }),
|
|
413
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { className: "font-mono text-foreground", children: formatValue(entry.value) })
|
|
241
414
|
] });
|
|
242
415
|
}
|
|
243
416
|
|
|
244
417
|
// src/hooks/useRenderers.ts
|
|
245
418
|
var import_react4 = require("react");
|
|
246
|
-
var
|
|
419
|
+
var EMPTY_CUSTOM = {};
|
|
247
420
|
var EMPTY_RENDERERS2 = {};
|
|
248
421
|
function useCustomRenderers() {
|
|
249
422
|
const ctx = (0, import_react4.useContext)(ReportContext);
|
|
250
|
-
return ctx?.customRenderers ??
|
|
423
|
+
return ctx?.customRenderers ?? EMPTY_CUSTOM;
|
|
251
424
|
}
|
|
252
425
|
function useBuiltinRenderers() {
|
|
253
426
|
const ctx = (0, import_react4.useContext)(ReportContext);
|
|
@@ -255,37 +428,37 @@ function useBuiltinRenderers() {
|
|
|
255
428
|
}
|
|
256
429
|
|
|
257
430
|
// src/components/doc/DocCode.tsx
|
|
258
|
-
var
|
|
431
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
259
432
|
function CodeFigure({ label, children }) {
|
|
260
|
-
return /* @__PURE__ */ (0,
|
|
261
|
-
label ? /* @__PURE__ */ (0,
|
|
262
|
-
/* @__PURE__ */ (0,
|
|
433
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("figure", { className: "my-3", children: [
|
|
434
|
+
label ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: label }) : null,
|
|
435
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3", children })
|
|
263
436
|
] });
|
|
264
437
|
}
|
|
265
438
|
function DocCode({ entry }) {
|
|
266
439
|
const renderers = useBuiltinRenderers();
|
|
267
440
|
if (renderers.code) {
|
|
268
|
-
return /* @__PURE__ */ (0,
|
|
441
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: renderers.code(entry) });
|
|
269
442
|
}
|
|
270
|
-
return /* @__PURE__ */ (0,
|
|
443
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CodeFigure, { label: entry.label, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
|
|
271
444
|
}
|
|
272
445
|
|
|
273
446
|
// src/components/doc/DocTable.tsx
|
|
274
|
-
var
|
|
447
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
275
448
|
function DocTable({ entry }) {
|
|
276
|
-
return /* @__PURE__ */ (0,
|
|
277
|
-
entry.label ? /* @__PURE__ */ (0,
|
|
278
|
-
/* @__PURE__ */ (0,
|
|
279
|
-
/* @__PURE__ */ (0,
|
|
280
|
-
/* @__PURE__ */ (0,
|
|
449
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("figure", { className: "my-3", children: [
|
|
450
|
+
entry.label ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.label }) : null,
|
|
451
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("table", { className: "w-full border-collapse text-sm", children: [
|
|
452
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tr", { className: "bg-muted/50", children: entry.columns.map((c) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: c }, c)) }) }),
|
|
453
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tbody", { children: entry.rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tr", { children: row.map((cell, j) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("td", { className: "border-b border-border px-3 py-2 text-foreground", children: cell }, j)) }, i)) })
|
|
281
454
|
] }) })
|
|
282
455
|
] });
|
|
283
456
|
}
|
|
284
457
|
|
|
285
458
|
// src/components/doc/DocLink.tsx
|
|
286
|
-
var
|
|
459
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
287
460
|
function DocLink({ entry }) {
|
|
288
|
-
return /* @__PURE__ */ (0,
|
|
461
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
289
462
|
"a",
|
|
290
463
|
{
|
|
291
464
|
className: "text-sm font-medium text-primary underline underline-offset-2 hover:no-underline",
|
|
@@ -300,28 +473,13 @@ function DocLink({ entry }) {
|
|
|
300
473
|
// src/components/doc/DocSection.tsx
|
|
301
474
|
var import_marked = require("marked");
|
|
302
475
|
|
|
303
|
-
//
|
|
304
|
-
|
|
305
|
-
if (!value) return void 0;
|
|
306
|
-
const trimmed = value.trim();
|
|
307
|
-
const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(trimmed);
|
|
308
|
-
if (scheme && !/^https?$/i.test(scheme[1] ?? "")) return void 0;
|
|
309
|
-
return trimmed;
|
|
310
|
-
}
|
|
311
|
-
function safeImageUrl(value) {
|
|
312
|
-
if (!value) return void 0;
|
|
313
|
-
const trimmed = value.trim();
|
|
314
|
-
if (/^data:image\//i.test(trimmed)) return trimmed;
|
|
315
|
-
return safeUrl(trimmed);
|
|
316
|
-
}
|
|
317
|
-
function isLocalFsPath(value) {
|
|
318
|
-
return /^(?:[/\\]|[A-Za-z]:[/\\])/.test(value);
|
|
319
|
-
}
|
|
476
|
+
// src/lib/url.ts
|
|
477
|
+
var import_url = require("executable-stories-core/utils/url");
|
|
320
478
|
|
|
321
479
|
// src/components/doc/DocSection.tsx
|
|
322
|
-
var
|
|
480
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
323
481
|
function neutralizeUrl(value) {
|
|
324
|
-
return safeUrl(value) ?? "#";
|
|
482
|
+
return (0, import_url.safeUrl)(value) ?? "#";
|
|
325
483
|
}
|
|
326
484
|
function safeMarkdownHtml(markdown) {
|
|
327
485
|
const raw = import_marked.marked.parse(markdown, { async: false });
|
|
@@ -330,12 +488,12 @@ function safeMarkdownHtml(markdown) {
|
|
|
330
488
|
function DocSection({ entry }) {
|
|
331
489
|
const renderers = useBuiltinRenderers();
|
|
332
490
|
if (renderers.section) {
|
|
333
|
-
return /* @__PURE__ */ (0,
|
|
491
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children: renderers.section(entry) });
|
|
334
492
|
}
|
|
335
493
|
const html = safeMarkdownHtml(entry.markdown);
|
|
336
|
-
return /* @__PURE__ */ (0,
|
|
337
|
-
entry.title ? /* @__PURE__ */ (0,
|
|
338
|
-
/* @__PURE__ */ (0,
|
|
494
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("section", { className: "my-3 text-sm", "aria-label": entry.title, children: [
|
|
495
|
+
entry.title ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h4", { className: "mb-1 font-semibold text-foreground", children: entry.title }) : null,
|
|
496
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
339
497
|
"div",
|
|
340
498
|
{
|
|
341
499
|
className: "es-doc-prose prose prose-sm max-w-none",
|
|
@@ -346,11 +504,11 @@ function DocSection({ entry }) {
|
|
|
346
504
|
}
|
|
347
505
|
|
|
348
506
|
// src/components/doc/DocMermaid.tsx
|
|
349
|
-
var
|
|
507
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
350
508
|
function MermaidSource({ entry, ref }) {
|
|
351
|
-
return /* @__PURE__ */ (0,
|
|
352
|
-
entry.title ? /* @__PURE__ */ (0,
|
|
353
|
-
/* @__PURE__ */ (0,
|
|
509
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("figure", { ref, className: "my-3", "aria-label": entry.title ?? "Diagram", children: [
|
|
510
|
+
entry.title ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
|
|
511
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
354
512
|
"pre",
|
|
355
513
|
{
|
|
356
514
|
"data-mermaid": true,
|
|
@@ -364,24 +522,24 @@ function MermaidSource({ entry, ref }) {
|
|
|
364
522
|
function DocMermaid({ entry }) {
|
|
365
523
|
const renderers = useBuiltinRenderers();
|
|
366
524
|
if (renderers.mermaid) {
|
|
367
|
-
return /* @__PURE__ */ (0,
|
|
525
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, { children: renderers.mermaid(entry) });
|
|
368
526
|
}
|
|
369
|
-
return /* @__PURE__ */ (0,
|
|
527
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MermaidSource, { entry });
|
|
370
528
|
}
|
|
371
529
|
|
|
372
530
|
// src/components/doc/DocScreenshot.tsx
|
|
373
|
-
var
|
|
531
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
374
532
|
function DocScreenshot({ entry }) {
|
|
375
|
-
const src = isLocalFsPath(entry.path) ? void 0 : safeImageUrl(entry.path);
|
|
533
|
+
const src = (0, import_url.isLocalFsPath)(entry.path) ? void 0 : (0, import_url.safeImageUrl)(entry.path);
|
|
376
534
|
if (!src) {
|
|
377
|
-
return /* @__PURE__ */ (0,
|
|
378
|
-
/* @__PURE__ */ (0,
|
|
379
|
-
/* @__PURE__ */ (0,
|
|
380
|
-
entry.alt ? /* @__PURE__ */ (0,
|
|
535
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
|
|
536
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "font-medium", children: "Screenshot unavailable" }),
|
|
537
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
|
|
538
|
+
entry.alt ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("figcaption", { className: "mt-1.5 text-xs", children: entry.alt }) : null
|
|
381
539
|
] });
|
|
382
540
|
}
|
|
383
|
-
return /* @__PURE__ */ (0,
|
|
384
|
-
/* @__PURE__ */ (0,
|
|
541
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("figure", { className: "my-3", children: [
|
|
542
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
385
543
|
"img",
|
|
386
544
|
{
|
|
387
545
|
src,
|
|
@@ -390,24 +548,24 @@ function DocScreenshot({ entry }) {
|
|
|
390
548
|
className: "max-w-full rounded-md border border-border"
|
|
391
549
|
}
|
|
392
550
|
),
|
|
393
|
-
entry.alt ? /* @__PURE__ */ (0,
|
|
551
|
+
entry.alt ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("figcaption", { className: "mt-1.5 text-xs text-muted-foreground", children: entry.alt }) : null
|
|
394
552
|
] });
|
|
395
553
|
}
|
|
396
554
|
|
|
397
555
|
// src/components/doc/DocVideo.tsx
|
|
398
|
-
var
|
|
556
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
399
557
|
function DocVideo({ entry }) {
|
|
400
|
-
if (isLocalFsPath(entry.path)) {
|
|
401
|
-
return /* @__PURE__ */ (0,
|
|
402
|
-
/* @__PURE__ */ (0,
|
|
403
|
-
/* @__PURE__ */ (0,
|
|
404
|
-
entry.caption ? /* @__PURE__ */ (0,
|
|
558
|
+
if ((0, import_url.isLocalFsPath)(entry.path)) {
|
|
559
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
|
|
560
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "font-medium", children: "Video unavailable" }),
|
|
561
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
|
|
562
|
+
entry.caption ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("figcaption", { className: "mt-1.5 text-xs", children: entry.caption }) : null
|
|
405
563
|
] });
|
|
406
564
|
}
|
|
407
|
-
const src = safeUrl(entry.path);
|
|
408
|
-
const poster = safeUrl(entry.poster);
|
|
409
|
-
return /* @__PURE__ */ (0,
|
|
410
|
-
/* @__PURE__ */ (0,
|
|
565
|
+
const src = (0, import_url.safeUrl)(entry.path);
|
|
566
|
+
const poster = (0, import_url.safeUrl)(entry.poster);
|
|
567
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figure", { className: "my-3", children: [
|
|
568
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
411
569
|
"video",
|
|
412
570
|
{
|
|
413
571
|
controls: true,
|
|
@@ -417,21 +575,21 @@ function DocVideo({ entry }) {
|
|
|
417
575
|
className: "max-w-full rounded-md border border-border"
|
|
418
576
|
}
|
|
419
577
|
),
|
|
420
|
-
entry.caption ? /* @__PURE__ */ (0,
|
|
578
|
+
entry.caption ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: entry.caption }) : null
|
|
421
579
|
] });
|
|
422
580
|
}
|
|
423
581
|
|
|
424
582
|
// src/components/doc/DocHtml.tsx
|
|
425
|
-
var
|
|
583
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
426
584
|
function DocHtml({ entry }) {
|
|
427
585
|
const height = typeof entry.height === "number" ? `${entry.height}px` : entry.height ?? "400px";
|
|
428
586
|
const title = entry.title ?? "Embedded HTML";
|
|
429
|
-
const safeHref = safeUrl(entry.url ?? entry.path);
|
|
587
|
+
const safeHref = (0, import_url.safeUrl)(entry.url ?? entry.path);
|
|
430
588
|
const frameProps = entry.content !== void 0 ? { srcDoc: entry.content } : { src: safeHref ?? "" };
|
|
431
|
-
return /* @__PURE__ */ (0,
|
|
432
|
-
/* @__PURE__ */ (0,
|
|
433
|
-
/* @__PURE__ */ (0,
|
|
434
|
-
safeHref ? /* @__PURE__ */ (0,
|
|
589
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("figure", { className: "my-3 overflow-hidden rounded-md border border-border", children: [
|
|
590
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("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: [
|
|
591
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: entry.title ?? "HTML" }),
|
|
592
|
+
safeHref ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
435
593
|
"a",
|
|
436
594
|
{
|
|
437
595
|
href: safeHref,
|
|
@@ -444,7 +602,7 @@ function DocHtml({ entry }) {
|
|
|
444
602
|
}
|
|
445
603
|
) : null
|
|
446
604
|
] }),
|
|
447
|
-
/* @__PURE__ */ (0,
|
|
605
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
448
606
|
"iframe",
|
|
449
607
|
{
|
|
450
608
|
...frameProps,
|
|
@@ -459,7 +617,7 @@ function DocHtml({ entry }) {
|
|
|
459
617
|
}
|
|
460
618
|
|
|
461
619
|
// src/components/doc/DocState.tsx
|
|
462
|
-
var
|
|
620
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
463
621
|
function DocState({ entry }) {
|
|
464
622
|
let json;
|
|
465
623
|
try {
|
|
@@ -467,23 +625,23 @@ function DocState({ entry }) {
|
|
|
467
625
|
} catch {
|
|
468
626
|
json = String(entry.value);
|
|
469
627
|
}
|
|
470
|
-
return /* @__PURE__ */ (0,
|
|
628
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(CodeFigure, { label: entry.label ?? "State", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("code", { className: "font-mono text-xs language-json", children: json }) });
|
|
471
629
|
}
|
|
472
630
|
|
|
473
631
|
// src/components/doc/DocCustom.tsx
|
|
474
|
-
var
|
|
632
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
475
633
|
function DocCustom({ entry }) {
|
|
476
634
|
const renderers = useCustomRenderers();
|
|
477
635
|
const renderer = renderers[entry.type];
|
|
478
636
|
if (renderer) {
|
|
479
|
-
return /* @__PURE__ */ (0,
|
|
637
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children: renderer(entry) });
|
|
480
638
|
}
|
|
481
|
-
return /* @__PURE__ */ (0,
|
|
482
|
-
/* @__PURE__ */ (0,
|
|
483
|
-
/* @__PURE__ */ (0,
|
|
639
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "my-2", "data-type": entry.type, children: [
|
|
640
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: entry.type }),
|
|
641
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground", children: safeStringify2(entry.data) })
|
|
484
642
|
] });
|
|
485
643
|
}
|
|
486
|
-
function
|
|
644
|
+
function safeStringify2(value) {
|
|
487
645
|
try {
|
|
488
646
|
return JSON.stringify(value, null, 2);
|
|
489
647
|
} catch {
|
|
@@ -492,47 +650,47 @@ function safeStringify(value) {
|
|
|
492
650
|
}
|
|
493
651
|
|
|
494
652
|
// src/components/doc/DocEntry.tsx
|
|
495
|
-
var
|
|
653
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
496
654
|
function DocEntry({ entry }) {
|
|
497
655
|
switch (entry.kind) {
|
|
498
656
|
case "note":
|
|
499
|
-
return /* @__PURE__ */ (0,
|
|
657
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocNote, { entry });
|
|
500
658
|
case "tag":
|
|
501
|
-
return /* @__PURE__ */ (0,
|
|
659
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocTag, { entry });
|
|
502
660
|
case "kv":
|
|
503
|
-
return /* @__PURE__ */ (0,
|
|
661
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocKv, { entry });
|
|
504
662
|
case "code":
|
|
505
|
-
return /* @__PURE__ */ (0,
|
|
663
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocCode, { entry });
|
|
506
664
|
case "table":
|
|
507
|
-
return /* @__PURE__ */ (0,
|
|
665
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocTable, { entry });
|
|
508
666
|
case "link":
|
|
509
|
-
return /* @__PURE__ */ (0,
|
|
667
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocLink, { entry });
|
|
510
668
|
case "section":
|
|
511
|
-
return /* @__PURE__ */ (0,
|
|
669
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocSection, { entry });
|
|
512
670
|
case "mermaid":
|
|
513
|
-
return /* @__PURE__ */ (0,
|
|
671
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocMermaid, { entry });
|
|
514
672
|
case "screenshot":
|
|
515
|
-
return /* @__PURE__ */ (0,
|
|
673
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocScreenshot, { entry });
|
|
516
674
|
case "video":
|
|
517
|
-
return /* @__PURE__ */ (0,
|
|
675
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocVideo, { entry });
|
|
518
676
|
case "html":
|
|
519
|
-
return /* @__PURE__ */ (0,
|
|
677
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocHtml, { entry });
|
|
520
678
|
case "state":
|
|
521
|
-
return /* @__PURE__ */ (0,
|
|
679
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocState, { entry });
|
|
522
680
|
case "custom":
|
|
523
|
-
return /* @__PURE__ */ (0,
|
|
681
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocCustom, { entry });
|
|
524
682
|
}
|
|
525
683
|
}
|
|
526
684
|
|
|
527
685
|
// src/components/ReportDocEntries.tsx
|
|
528
|
-
var
|
|
686
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
529
687
|
function ReportDocEntries({ entries }) {
|
|
530
688
|
if (entries.length === 0) return null;
|
|
531
|
-
return /* @__PURE__ */ (0,
|
|
689
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_jsx_runtime17.Fragment, { children: entries.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DocEntry, { entry }, i)) });
|
|
532
690
|
}
|
|
533
691
|
|
|
534
692
|
// src/lib/step-params.tsx
|
|
535
|
-
var
|
|
693
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
536
694
|
var STEP_PARAM_PATTERN = /"[^"]*"|(?<![\w.-])\d+(?:\.\d+)?(?![\w.-])/g;
|
|
537
695
|
function highlightStepParams(text) {
|
|
538
696
|
const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));
|
|
@@ -544,7 +702,7 @@ function highlightStepParams(text) {
|
|
|
544
702
|
const end = start + match[0].length;
|
|
545
703
|
if (start > lastIndex) nodes.push(text.slice(lastIndex, start));
|
|
546
704
|
nodes.push(
|
|
547
|
-
/* @__PURE__ */ (0,
|
|
705
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "font-medium text-step-param italic", children: match[0] }, i)
|
|
548
706
|
);
|
|
549
707
|
lastIndex = end;
|
|
550
708
|
});
|
|
@@ -553,7 +711,7 @@ function highlightStepParams(text) {
|
|
|
553
711
|
}
|
|
554
712
|
|
|
555
713
|
// src/components/ReportSteps.tsx
|
|
556
|
-
var
|
|
714
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
557
715
|
var STEP_GLYPH = {
|
|
558
716
|
passed: "\u2713",
|
|
559
717
|
failed: "\u2717",
|
|
@@ -568,21 +726,21 @@ var STEP_GLYPH_COLOR = {
|
|
|
568
726
|
};
|
|
569
727
|
function ReportSteps({ scenario }) {
|
|
570
728
|
if (scenario.steps.length === 0) return null;
|
|
571
|
-
return /* @__PURE__ */ (0,
|
|
729
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("ol", { "data-slot": "steps", className: "flex flex-col", children: scenario.steps.map((step) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ReportStepItem, { step }, step.id)) });
|
|
572
730
|
}
|
|
573
731
|
function ReportStepItem({ step }) {
|
|
574
732
|
const kw = step.keyword.toLowerCase();
|
|
575
733
|
const continuation = kw === "and" || kw === "but";
|
|
576
|
-
return /* @__PURE__ */ (0,
|
|
734
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
577
735
|
"li",
|
|
578
736
|
{
|
|
579
737
|
id: step.id,
|
|
580
738
|
"data-status": step.status,
|
|
581
739
|
className: cn("py-1.5 text-[0.8125rem] leading-normal", continuation && "pl-5"),
|
|
582
740
|
children: [
|
|
583
|
-
/* @__PURE__ */ (0,
|
|
584
|
-
/* @__PURE__ */ (0,
|
|
585
|
-
/* @__PURE__ */ (0,
|
|
741
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-baseline gap-2", children: [
|
|
742
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("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" }),
|
|
743
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
586
744
|
"span",
|
|
587
745
|
{
|
|
588
746
|
className: cn(
|
|
@@ -592,10 +750,10 @@ function ReportStepItem({ step }) {
|
|
|
592
750
|
children: step.keyword
|
|
593
751
|
}
|
|
594
752
|
),
|
|
595
|
-
/* @__PURE__ */ (0,
|
|
596
|
-
step.durationMs > 0 ? /* @__PURE__ */ (0,
|
|
753
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
|
|
754
|
+
step.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: (0, import_duration.formatDuration)(step.durationMs) }) : null
|
|
597
755
|
] }),
|
|
598
|
-
step.errorMessage ? /* @__PURE__ */ (0,
|
|
756
|
+
step.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
599
757
|
"pre",
|
|
600
758
|
{
|
|
601
759
|
role: "alert",
|
|
@@ -603,132 +761,17 @@ function ReportStepItem({ step }) {
|
|
|
603
761
|
children: step.errorMessage
|
|
604
762
|
}
|
|
605
763
|
) : null,
|
|
606
|
-
step.docEntries.length > 0 ? /* @__PURE__ */ (0,
|
|
764
|
+
step.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { "data-es-docs": true, className: "mt-2 ml-6", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ReportDocEntries, { entries: step.docEntries }) }) : null
|
|
607
765
|
]
|
|
608
766
|
}
|
|
609
767
|
);
|
|
610
768
|
}
|
|
611
769
|
|
|
612
|
-
// ../executable-stories-core/dist/state-diff.js
|
|
613
|
-
var isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
614
|
-
function deepEqual(a, b) {
|
|
615
|
-
if (Object.is(a, b)) return true;
|
|
616
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
617
|
-
return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
|
|
618
|
-
}
|
|
619
|
-
if (isPlainObject(a) && isPlainObject(b)) {
|
|
620
|
-
const ak = Object.keys(a);
|
|
621
|
-
const bk = Object.keys(b);
|
|
622
|
-
return ak.length === bk.length && ak.every((k) => k in b && deepEqual(a[k], b[k]));
|
|
623
|
-
}
|
|
624
|
-
return false;
|
|
625
|
-
}
|
|
626
|
-
var joinKey = (path, key) => path === "" ? key : `${path}.${key}`;
|
|
627
|
-
function walk(path, before, after, out) {
|
|
628
|
-
if (Object.is(before, after)) return;
|
|
629
|
-
if (Array.isArray(before) && Array.isArray(after)) {
|
|
630
|
-
const shared = Math.min(before.length, after.length);
|
|
631
|
-
for (let i = 0; i < shared; i++) walk(`${path}[${i}]`, before[i], after[i], out);
|
|
632
|
-
for (let i = shared; i < after.length; i++) out.push({ path: `${path}[${i}]`, kind: "added", after: after[i] });
|
|
633
|
-
for (let i = shared; i < before.length; i++) out.push({ path: `${path}[${i}]`, kind: "removed", before: before[i] });
|
|
634
|
-
return;
|
|
635
|
-
}
|
|
636
|
-
if (isPlainObject(before) && isPlainObject(after)) {
|
|
637
|
-
for (const key of Object.keys(after)) {
|
|
638
|
-
const p = joinKey(path, key);
|
|
639
|
-
if (key in before) walk(p, before[key], after[key], out);
|
|
640
|
-
else out.push({ path: p, kind: "added", after: after[key] });
|
|
641
|
-
}
|
|
642
|
-
for (const key of Object.keys(before)) {
|
|
643
|
-
if (!(key in after)) out.push({ path: joinKey(path, key), kind: "removed", before: before[key] });
|
|
644
|
-
}
|
|
645
|
-
return;
|
|
646
|
-
}
|
|
647
|
-
if (!deepEqual(before, after)) out.push({ path, kind: "changed", before, after });
|
|
648
|
-
}
|
|
649
|
-
function diffStateValues(before, after) {
|
|
650
|
-
const out = [];
|
|
651
|
-
walk("", before, after, out);
|
|
652
|
-
return out;
|
|
653
|
-
}
|
|
654
|
-
function formatStateValue(value, maxLen = 60) {
|
|
655
|
-
const s = value === void 0 ? "undefined" : JSON.stringify(value);
|
|
656
|
-
return s.length > maxLen ? `${s.slice(0, maxLen - 1)}\u2026` : s;
|
|
657
|
-
}
|
|
658
|
-
function summarizeStateChanges(changes) {
|
|
659
|
-
return changes.map((c) => {
|
|
660
|
-
const at = c.path === "" ? "(root)" : c.path;
|
|
661
|
-
switch (c.kind) {
|
|
662
|
-
case "added":
|
|
663
|
-
return `+ ${at}: ${formatStateValue(c.after)}`;
|
|
664
|
-
case "removed":
|
|
665
|
-
return `\u2212 ${at}`;
|
|
666
|
-
case "changed":
|
|
667
|
-
return `${at}: ${formatStateValue(c.before)} \u2192 ${formatStateValue(c.after)}`;
|
|
668
|
-
}
|
|
669
|
-
});
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
// ../executable-stories-core/dist/storyboard.js
|
|
673
|
-
function findScreenshot(entries) {
|
|
674
|
-
for (const entry of entries) {
|
|
675
|
-
if (entry.kind === "screenshot") return entry;
|
|
676
|
-
if (entry.children) {
|
|
677
|
-
const nested = findScreenshot(entry.children);
|
|
678
|
-
if (nested) return nested;
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
return void 0;
|
|
682
|
-
}
|
|
683
|
-
function findStates(entries, out = []) {
|
|
684
|
-
for (const entry of entries) {
|
|
685
|
-
if (entry.kind === "state") out.push(entry);
|
|
686
|
-
if (entry.children) findStates(entry.children, out);
|
|
687
|
-
}
|
|
688
|
-
return out;
|
|
689
|
-
}
|
|
690
|
-
var laneOf = (label) => label ?? "";
|
|
691
|
-
function extractStoryboardFrames(scenario) {
|
|
692
|
-
const frames = [];
|
|
693
|
-
const laneOrder = [];
|
|
694
|
-
const previous = /* @__PURE__ */ new Map();
|
|
695
|
-
for (const step of scenario.steps) {
|
|
696
|
-
const shot = findScreenshot(step.docEntries);
|
|
697
|
-
const stateDocs = findStates(step.docEntries);
|
|
698
|
-
if (!shot && stateDocs.length === 0) continue;
|
|
699
|
-
const byLane = /* @__PURE__ */ new Map();
|
|
700
|
-
for (const doc of stateDocs) {
|
|
701
|
-
const lane = laneOf(doc.label);
|
|
702
|
-
if (!byLane.has(lane) && !laneOrder.includes(lane)) laneOrder.push(lane);
|
|
703
|
-
byLane.set(lane, doc);
|
|
704
|
-
}
|
|
705
|
-
const states = [];
|
|
706
|
-
for (const lane of laneOrder) {
|
|
707
|
-
const doc = byLane.get(lane);
|
|
708
|
-
if (!doc) continue;
|
|
709
|
-
const card = {
|
|
710
|
-
...doc.label !== void 0 && { label: doc.label },
|
|
711
|
-
value: doc.value
|
|
712
|
-
};
|
|
713
|
-
if (previous.has(lane)) card.changes = diffStateValues(previous.get(lane), doc.value);
|
|
714
|
-
previous.set(lane, doc.value);
|
|
715
|
-
states.push(card);
|
|
716
|
-
}
|
|
717
|
-
frames.push({
|
|
718
|
-
stepId: step.id,
|
|
719
|
-
stepIndex: step.index,
|
|
720
|
-
keyword: step.keyword,
|
|
721
|
-
text: step.text,
|
|
722
|
-
status: step.status,
|
|
723
|
-
...shot && { screenshot: { path: shot.path, ...shot.alt !== void 0 && { alt: shot.alt } } },
|
|
724
|
-
states
|
|
725
|
-
});
|
|
726
|
-
}
|
|
727
|
-
return frames;
|
|
728
|
-
}
|
|
729
|
-
|
|
730
770
|
// src/components/ReportStoryboard.tsx
|
|
731
|
-
var
|
|
771
|
+
var import_storyboard = require("executable-stories-core/storyboard");
|
|
772
|
+
var import_state_diff = require("executable-stories-core/state-diff");
|
|
773
|
+
var import_url6 = require("executable-stories-core/utils/url");
|
|
774
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
732
775
|
var FRAME_GLYPH = {
|
|
733
776
|
passed: "\u2713",
|
|
734
777
|
failed: "\u2717",
|
|
@@ -742,48 +785,48 @@ var FRAME_GLYPH_COLOR = {
|
|
|
742
785
|
pending: "text-pend"
|
|
743
786
|
};
|
|
744
787
|
function ReportStoryboard({ scenario }) {
|
|
745
|
-
const frames = extractStoryboardFrames(scenario);
|
|
788
|
+
const frames = (0, import_storyboard.extractStoryboardFrames)(scenario);
|
|
746
789
|
if (frames.length < 2) return null;
|
|
747
|
-
return /* @__PURE__ */ (0,
|
|
748
|
-
/* @__PURE__ */ (0,
|
|
749
|
-
/* @__PURE__ */ (0,
|
|
790
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("section", { "data-slot": "storyboard", "aria-label": "Storyboard", className: "mb-3", children: [
|
|
791
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h4", { className: "mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Storyboard" }),
|
|
792
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("ol", { className: "flex items-start gap-3 overflow-x-auto pb-2", children: frames.map((frame) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(StoryboardFrameItem, { frame }, frame.stepId)) })
|
|
750
793
|
] });
|
|
751
794
|
}
|
|
752
795
|
function StoryboardFrameItem({ frame }) {
|
|
753
796
|
const label = `${frame.keyword} ${frame.text}`;
|
|
754
797
|
const hasStates = frame.states.length > 0;
|
|
755
|
-
const caption = /* @__PURE__ */ (0,
|
|
756
|
-
/* @__PURE__ */ (0,
|
|
757
|
-
/* @__PURE__ */ (0,
|
|
758
|
-
/* @__PURE__ */ (0,
|
|
798
|
+
const caption = /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("p", { className: "mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug", children: [
|
|
799
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { "aria-hidden": true, className: cn("shrink-0", FRAME_GLYPH_COLOR[frame.status]), children: FRAME_GLYPH[frame.status] ?? "\u25CB" }),
|
|
800
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "min-w-0", children: [
|
|
801
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "font-mono font-semibold text-keyword", children: frame.keyword }),
|
|
759
802
|
" ",
|
|
760
|
-
/* @__PURE__ */ (0,
|
|
803
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-muted-foreground", children: frame.screenshot?.alt ?? frame.text })
|
|
761
804
|
] })
|
|
762
805
|
] });
|
|
763
806
|
return (
|
|
764
807
|
// State cards need room for diff rows; screenshot-only frames keep the
|
|
765
808
|
// original narrow film-cell width (and DOM) unchanged.
|
|
766
|
-
/* @__PURE__ */ (0,
|
|
767
|
-
frame.screenshot ? /* @__PURE__ */ (0,
|
|
768
|
-
hasStates ? /* @__PURE__ */ (0,
|
|
809
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("li", { className: cn("shrink-0", hasStates ? "w-64" : "w-40"), children: [
|
|
810
|
+
frame.screenshot ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(FrameScreenshot, { frame, label }) : null,
|
|
811
|
+
hasStates ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: cn("flex flex-col gap-1.5", frame.screenshot && "mt-1.5"), children: frame.states.map((card, i) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(StateCardView, { card }, card.label ?? i)) }) : null,
|
|
769
812
|
frame.screenshot ? caption : (
|
|
770
813
|
// No screenshot means no image anchor, so the caption carries the
|
|
771
814
|
// jump-to-step link instead.
|
|
772
|
-
/* @__PURE__ */ (0,
|
|
815
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("a", { href: `#${frame.stepId}`, "aria-label": `Jump to step: ${label}`, className: "block hover:underline", children: caption })
|
|
773
816
|
)
|
|
774
817
|
] })
|
|
775
818
|
);
|
|
776
819
|
}
|
|
777
820
|
function FrameScreenshot({ frame, label }) {
|
|
778
821
|
const path = frame.screenshot?.path ?? "";
|
|
779
|
-
const src = isLocalFsPath(path) ? void 0 : safeImageUrl(path);
|
|
780
|
-
return /* @__PURE__ */ (0,
|
|
822
|
+
const src = (0, import_url6.isLocalFsPath)(path) ? void 0 : (0, import_url6.safeImageUrl)(path);
|
|
823
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
781
824
|
"a",
|
|
782
825
|
{
|
|
783
826
|
href: `#${frame.stepId}`,
|
|
784
827
|
"aria-label": `Jump to step: ${label}`,
|
|
785
828
|
className: "block overflow-hidden rounded-md border border-border transition-colors hover:border-ring",
|
|
786
|
-
children: src ? /* @__PURE__ */ (0,
|
|
829
|
+
children: src ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
787
830
|
"img",
|
|
788
831
|
{
|
|
789
832
|
src,
|
|
@@ -791,7 +834,7 @@ function FrameScreenshot({ frame, label }) {
|
|
|
791
834
|
loading: "lazy",
|
|
792
835
|
className: "h-24 w-full bg-muted object-cover object-top"
|
|
793
836
|
}
|
|
794
|
-
) : /* @__PURE__ */ (0,
|
|
837
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("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" })
|
|
795
838
|
}
|
|
796
839
|
);
|
|
797
840
|
}
|
|
@@ -810,30 +853,30 @@ function prettyJson(value) {
|
|
|
810
853
|
function StateCardView({ card }) {
|
|
811
854
|
const json = prettyJson(card.value);
|
|
812
855
|
const firstCapture = card.changes === void 0;
|
|
813
|
-
return /* @__PURE__ */ (0,
|
|
814
|
-
/* @__PURE__ */ (0,
|
|
815
|
-
/* @__PURE__ */ (0,
|
|
816
|
-
firstCapture ? /* @__PURE__ */ (0,
|
|
856
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { "data-slot": "state-card", className: "rounded-md border border-border bg-card p-2", children: [
|
|
857
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("p", { className: "flex flex-wrap items-baseline gap-1.5", children: [
|
|
858
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("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" }),
|
|
859
|
+
firstCapture ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-[0.625rem] text-muted-foreground italic", children: "first capture" }) : null
|
|
817
860
|
] }),
|
|
818
|
-
!firstCapture && (card.changes && card.changes.length > 0 ? /* @__PURE__ */ (0,
|
|
861
|
+
!firstCapture && (card.changes && card.changes.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("ul", { className: "mt-1.5 flex flex-col gap-0.5", children: card.changes.map((change, i) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
819
862
|
"li",
|
|
820
863
|
{
|
|
821
864
|
className: cn(
|
|
822
865
|
"rounded-sm px-1.5 py-0.5 font-mono text-[0.625rem] leading-snug break-all",
|
|
823
866
|
CHANGE_TONE[change.kind]
|
|
824
867
|
),
|
|
825
|
-
children: summarizeStateChanges([change])[0]
|
|
868
|
+
children: (0, import_state_diff.summarizeStateChanges)([change])[0]
|
|
826
869
|
},
|
|
827
870
|
i
|
|
828
|
-
)) }) : /* @__PURE__ */ (0,
|
|
829
|
-
/* @__PURE__ */ (0,
|
|
871
|
+
)) }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "mt-1.5 text-[0.625rem] text-muted-foreground", children: "No changes" })),
|
|
872
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
830
873
|
"details",
|
|
831
874
|
{
|
|
832
875
|
open: firstCapture && json.length <= 240,
|
|
833
876
|
className: cn(firstCapture ? "mt-1.5" : "mt-1"),
|
|
834
877
|
children: [
|
|
835
|
-
/* @__PURE__ */ (0,
|
|
836
|
-
/* @__PURE__ */ (0,
|
|
878
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("summary", { className: "cursor-pointer text-[0.625rem] text-muted-foreground hover:text-foreground", children: "Snapshot" }),
|
|
879
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("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 })
|
|
837
880
|
]
|
|
838
881
|
}
|
|
839
882
|
)
|
|
@@ -841,17 +884,17 @@ function StateCardView({ card }) {
|
|
|
841
884
|
}
|
|
842
885
|
|
|
843
886
|
// src/components/ReportAttachments.tsx
|
|
844
|
-
var
|
|
887
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
845
888
|
function ReportAttachments({ attachments }) {
|
|
846
889
|
if (attachments.length === 0) return null;
|
|
847
890
|
return (
|
|
848
891
|
// role="group" (not a labelled <section>) so multiple scenarios' attachment
|
|
849
892
|
// blocks don't create duplicate "Attachments" region landmarks.
|
|
850
|
-
/* @__PURE__ */ (0,
|
|
893
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
|
|
851
894
|
const dataUri = att.contentEncoding === "BASE64" ? `data:${att.mediaType};base64,${att.body}` : `data:${att.mediaType},${encodeURIComponent(att.body)}`;
|
|
852
895
|
const isImage = att.mediaType.startsWith("image/");
|
|
853
|
-
return /* @__PURE__ */ (0,
|
|
854
|
-
/* @__PURE__ */ (0,
|
|
896
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
|
|
897
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
855
898
|
"img",
|
|
856
899
|
{
|
|
857
900
|
src: dataUri,
|
|
@@ -860,8 +903,8 @@ function ReportAttachments({ attachments }) {
|
|
|
860
903
|
className: "max-w-full rounded-md border border-border"
|
|
861
904
|
}
|
|
862
905
|
),
|
|
863
|
-
/* @__PURE__ */ (0,
|
|
864
|
-
] }) : /* @__PURE__ */ (0,
|
|
906
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
|
|
907
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
865
908
|
"a",
|
|
866
909
|
{
|
|
867
910
|
href: dataUri,
|
|
@@ -870,7 +913,7 @@ function ReportAttachments({ attachments }) {
|
|
|
870
913
|
children: [
|
|
871
914
|
att.name,
|
|
872
915
|
" ",
|
|
873
|
-
/* @__PURE__ */ (0,
|
|
916
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "text-muted-foreground", children: [
|
|
874
917
|
"(",
|
|
875
918
|
att.mediaType,
|
|
876
919
|
")"
|
|
@@ -882,6 +925,9 @@ function ReportAttachments({ attachments }) {
|
|
|
882
925
|
);
|
|
883
926
|
}
|
|
884
927
|
|
|
928
|
+
// src/components/ReportTrace.tsx
|
|
929
|
+
var import_duration2 = require("executable-stories-core/utils/duration");
|
|
930
|
+
|
|
885
931
|
// src/lib/trace.ts
|
|
886
932
|
var VALID = /* @__PURE__ */ new Set(["ok", "error", "unset"]);
|
|
887
933
|
var safeStatus = (s) => VALID.has(s) ? s : "unset";
|
|
@@ -934,15 +980,15 @@ function toTraceRows(spans) {
|
|
|
934
980
|
roots.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);
|
|
935
981
|
const rows = [];
|
|
936
982
|
const seen = /* @__PURE__ */ new Set();
|
|
937
|
-
const
|
|
983
|
+
const walk = (node, depth) => {
|
|
938
984
|
if (seen.has(node.span.spanId)) return;
|
|
939
985
|
seen.add(node.span.spanId);
|
|
940
986
|
rows.push({ ...node.span, depth });
|
|
941
|
-
for (const child of node.children)
|
|
987
|
+
for (const child of node.children) walk(child, depth + 1);
|
|
942
988
|
};
|
|
943
|
-
for (const root of roots)
|
|
989
|
+
for (const root of roots) walk(root, 0);
|
|
944
990
|
for (const node of byId.values()) {
|
|
945
|
-
if (!seen.has(node.span.spanId))
|
|
991
|
+
if (!seen.has(node.span.spanId)) walk(node, 0);
|
|
946
992
|
}
|
|
947
993
|
return rows;
|
|
948
994
|
}
|
|
@@ -958,7 +1004,7 @@ function traceWindow(rows) {
|
|
|
958
1004
|
}
|
|
959
1005
|
|
|
960
1006
|
// src/components/ReportTrace.tsx
|
|
961
|
-
var
|
|
1007
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
962
1008
|
var BAR_COLOR = {
|
|
963
1009
|
ok: "bg-pass",
|
|
964
1010
|
error: "bg-fail",
|
|
@@ -969,21 +1015,21 @@ function ReportTrace({ spans }) {
|
|
|
969
1015
|
const rows = toTraceRows(spans);
|
|
970
1016
|
if (rows.length === 0) return null;
|
|
971
1017
|
const { minStartMs, totalMs } = traceWindow(rows);
|
|
972
|
-
return /* @__PURE__ */ (0,
|
|
973
|
-
/* @__PURE__ */ (0,
|
|
1018
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("details", { className: "mt-3 rounded-md border border-border bg-muted/30", children: [
|
|
1019
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("summary", { className: "cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground", children: [
|
|
974
1020
|
"Trace (",
|
|
975
1021
|
rows.length,
|
|
976
1022
|
" span",
|
|
977
1023
|
rows.length === 1 ? "" : "s",
|
|
978
1024
|
", ",
|
|
979
|
-
formatDuration(totalMs),
|
|
1025
|
+
(0, import_duration2.formatDuration)(totalMs),
|
|
980
1026
|
")"
|
|
981
1027
|
] }),
|
|
982
|
-
/* @__PURE__ */ (0,
|
|
1028
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
|
|
983
1029
|
const leftPct = (row.startTimeMs - minStartMs) / totalMs * 100;
|
|
984
1030
|
const widthPct = Math.max(row.durationMs / totalMs * 100, 0.5);
|
|
985
|
-
return /* @__PURE__ */ (0,
|
|
986
|
-
/* @__PURE__ */ (0,
|
|
1031
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("li", { className: "flex items-center gap-2", children: [
|
|
1032
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
987
1033
|
"span",
|
|
988
1034
|
{
|
|
989
1035
|
className: "min-w-0 flex-1 truncate text-foreground",
|
|
@@ -992,14 +1038,14 @@ function ReportTrace({ spans }) {
|
|
|
992
1038
|
children: row.name
|
|
993
1039
|
}
|
|
994
1040
|
),
|
|
995
|
-
/* @__PURE__ */ (0,
|
|
1041
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
996
1042
|
"span",
|
|
997
1043
|
{
|
|
998
1044
|
className: cn("absolute top-0 h-full rounded-sm", BAR_COLOR[row.status]),
|
|
999
1045
|
style: { left: `${leftPct}%`, width: `${widthPct}%` }
|
|
1000
1046
|
}
|
|
1001
1047
|
) }),
|
|
1002
|
-
/* @__PURE__ */ (0,
|
|
1048
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: (0, import_duration2.formatDuration)(row.durationMs) })
|
|
1003
1049
|
] }, `${row.spanId}-${i}`);
|
|
1004
1050
|
}) })
|
|
1005
1051
|
] });
|
|
@@ -1050,7 +1096,7 @@ function flakinessOf(entries) {
|
|
|
1050
1096
|
}
|
|
1051
1097
|
|
|
1052
1098
|
// src/components/ScenarioRunHistory.tsx
|
|
1053
|
-
var
|
|
1099
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
1054
1100
|
var MAX_DOTS = 10;
|
|
1055
1101
|
var DOT_COLOR = {
|
|
1056
1102
|
passed: "bg-pass",
|
|
@@ -1070,16 +1116,16 @@ function ScenarioRunHistory({ scenarioId }) {
|
|
|
1070
1116
|
const recent = entries.slice(-MAX_DOTS);
|
|
1071
1117
|
const flaky = flakinessOf(recent) === "flaky";
|
|
1072
1118
|
const summary = flaky ? `${describeRunHistory(recent)} \xB7 Flaky` : describeRunHistory(recent);
|
|
1073
|
-
return /* @__PURE__ */ (0,
|
|
1074
|
-
flaky ? /* @__PURE__ */ (0,
|
|
1075
|
-
/* @__PURE__ */ (0,
|
|
1119
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
|
|
1120
|
+
flaky ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
|
|
1121
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
1076
1122
|
"span",
|
|
1077
1123
|
{
|
|
1078
1124
|
role: "img",
|
|
1079
1125
|
"aria-label": `Run history: ${summary}`,
|
|
1080
1126
|
title: summary,
|
|
1081
1127
|
className: "flex shrink-0 items-center gap-[3px]",
|
|
1082
|
-
children: recent.map((e, i) => /* @__PURE__ */ (0,
|
|
1128
|
+
children: recent.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
1083
1129
|
"span",
|
|
1084
1130
|
{
|
|
1085
1131
|
"aria-hidden": true,
|
|
@@ -1110,6 +1156,7 @@ function useCollapse() {
|
|
|
1110
1156
|
|
|
1111
1157
|
// src/interactive/scenario-actions.tsx
|
|
1112
1158
|
var import_react7 = require("react");
|
|
1159
|
+
var import_scenario_markdown = require("executable-stories-core/utils/scenario-markdown");
|
|
1113
1160
|
var ScenarioActionsContext = (0, import_react7.createContext)(null);
|
|
1114
1161
|
var ScenarioActionsProvider = ScenarioActionsContext.Provider;
|
|
1115
1162
|
function useScenarioActions() {
|
|
@@ -1118,9 +1165,9 @@ function useScenarioActions() {
|
|
|
1118
1165
|
|
|
1119
1166
|
// src/components/ui/card.tsx
|
|
1120
1167
|
var React2 = require("react");
|
|
1121
|
-
var
|
|
1168
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
1122
1169
|
function Card({ className, ...props }) {
|
|
1123
|
-
return /* @__PURE__ */ (0,
|
|
1170
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1124
1171
|
"div",
|
|
1125
1172
|
{
|
|
1126
1173
|
"data-slot": "card",
|
|
@@ -1133,7 +1180,7 @@ function Card({ className, ...props }) {
|
|
|
1133
1180
|
);
|
|
1134
1181
|
}
|
|
1135
1182
|
function CardHeader({ className, ...props }) {
|
|
1136
|
-
return /* @__PURE__ */ (0,
|
|
1183
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1137
1184
|
"div",
|
|
1138
1185
|
{
|
|
1139
1186
|
"data-slot": "card-header",
|
|
@@ -1146,7 +1193,7 @@ function CardHeader({ className, ...props }) {
|
|
|
1146
1193
|
);
|
|
1147
1194
|
}
|
|
1148
1195
|
function CardContent({ className, ...props }) {
|
|
1149
|
-
return /* @__PURE__ */ (0,
|
|
1196
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1150
1197
|
"div",
|
|
1151
1198
|
{
|
|
1152
1199
|
"data-slot": "card-content",
|
|
@@ -1160,13 +1207,13 @@ function CardContent({ className, ...props }) {
|
|
|
1160
1207
|
var React3 = require("react");
|
|
1161
1208
|
var import_menu = require("@base-ui/react/menu");
|
|
1162
1209
|
var import_lucide_react = require("lucide-react");
|
|
1163
|
-
var
|
|
1210
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1164
1211
|
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";
|
|
1165
1212
|
function DropdownMenu(props) {
|
|
1166
|
-
return /* @__PURE__ */ (0,
|
|
1213
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_menu.Menu.Root, { "data-slot": "dropdown-menu", ...props });
|
|
1167
1214
|
}
|
|
1168
1215
|
function DropdownMenuTrigger(props) {
|
|
1169
|
-
return /* @__PURE__ */ (0,
|
|
1216
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_menu.Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
|
|
1170
1217
|
}
|
|
1171
1218
|
function DropdownMenuContent({
|
|
1172
1219
|
className,
|
|
@@ -1174,14 +1221,14 @@ function DropdownMenuContent({
|
|
|
1174
1221
|
sideOffset = 4,
|
|
1175
1222
|
...props
|
|
1176
1223
|
}) {
|
|
1177
|
-
return /* @__PURE__ */ (0,
|
|
1224
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_menu.Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1178
1225
|
import_menu.Menu.Positioner,
|
|
1179
1226
|
{
|
|
1180
1227
|
"data-slot": "dropdown-menu-positioner",
|
|
1181
1228
|
className: "z-50",
|
|
1182
1229
|
align,
|
|
1183
1230
|
sideOffset,
|
|
1184
|
-
children: /* @__PURE__ */ (0,
|
|
1231
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1185
1232
|
import_menu.Menu.Popup,
|
|
1186
1233
|
{
|
|
1187
1234
|
"data-slot": "dropdown-menu-content",
|
|
@@ -1199,7 +1246,7 @@ function DropdownMenuItem({
|
|
|
1199
1246
|
className,
|
|
1200
1247
|
...props
|
|
1201
1248
|
}) {
|
|
1202
|
-
return /* @__PURE__ */ (0,
|
|
1249
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1203
1250
|
import_menu.Menu.Item,
|
|
1204
1251
|
{
|
|
1205
1252
|
"data-slot": "dropdown-menu-item",
|
|
@@ -1211,7 +1258,7 @@ function DropdownMenuItem({
|
|
|
1211
1258
|
|
|
1212
1259
|
// src/components/ReportScenario.tsx
|
|
1213
1260
|
var import_lucide_react2 = require("lucide-react");
|
|
1214
|
-
var
|
|
1261
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1215
1262
|
var STATUS_META = {
|
|
1216
1263
|
passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
|
|
1217
1264
|
failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
|
|
@@ -1227,7 +1274,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1227
1274
|
const collapsible = collapse !== null && !hideTitle;
|
|
1228
1275
|
const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
|
|
1229
1276
|
const actions = useScenarioActions();
|
|
1230
|
-
return /* @__PURE__ */ (0,
|
|
1277
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
1231
1278
|
Card,
|
|
1232
1279
|
{
|
|
1233
1280
|
id: scenario.id,
|
|
@@ -1235,10 +1282,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1235
1282
|
...hideTitle ? { "aria-label": `${scenario.title}, ${label}` } : { "aria-labelledby": titleId },
|
|
1236
1283
|
className: "gap-0 py-0",
|
|
1237
1284
|
children: [
|
|
1238
|
-
/* @__PURE__ */ (0,
|
|
1239
|
-
/* @__PURE__ */ (0,
|
|
1240
|
-
hideTitle ? null : /* @__PURE__ */ (0,
|
|
1241
|
-
collapsible ? /* @__PURE__ */ (0,
|
|
1285
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(CardHeader, { className: "px-4 py-3", children: [
|
|
1286
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
|
|
1287
|
+
hideTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
|
|
1288
|
+
collapsible ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1242
1289
|
"button",
|
|
1243
1290
|
{
|
|
1244
1291
|
type: "button",
|
|
@@ -1247,49 +1294,49 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1247
1294
|
"aria-controls": bodyId,
|
|
1248
1295
|
"aria-label": `Toggle ${scenario.title}`,
|
|
1249
1296
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
1250
|
-
children: /* @__PURE__ */ (0,
|
|
1297
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
1251
1298
|
}
|
|
1252
1299
|
) : null,
|
|
1253
|
-
/* @__PURE__ */ (0,
|
|
1254
|
-
/* @__PURE__ */ (0,
|
|
1300
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
|
|
1301
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: scenario.title })
|
|
1255
1302
|
] }),
|
|
1256
|
-
/* @__PURE__ */ (0,
|
|
1257
|
-
/* @__PURE__ */ (0,
|
|
1258
|
-
scenario.durationMs > 0 ? /* @__PURE__ */ (0,
|
|
1259
|
-
meta.showPill ? /* @__PURE__ */ (0,
|
|
1260
|
-
actions ? /* @__PURE__ */ (0,
|
|
1261
|
-
/* @__PURE__ */ (0,
|
|
1303
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
1304
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ScenarioRunHistory, { scenarioId: scenario.id }),
|
|
1305
|
+
scenario.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: (0, import_duration3.formatDuration)(scenario.durationMs) }) : null,
|
|
1306
|
+
meta.showPill ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "sr-only", children: `Status: ${label}` }),
|
|
1307
|
+
actions ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DropdownMenu, { children: [
|
|
1308
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1262
1309
|
DropdownMenuTrigger,
|
|
1263
1310
|
{
|
|
1264
1311
|
"aria-label": `Actions for ${scenario.title}`,
|
|
1265
1312
|
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
1266
|
-
children: /* @__PURE__ */ (0,
|
|
1313
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react2.MoreHorizontalIcon, { "aria-hidden": true })
|
|
1267
1314
|
}
|
|
1268
1315
|
),
|
|
1269
|
-
/* @__PURE__ */ (0,
|
|
1270
|
-
/* @__PURE__ */ (0,
|
|
1271
|
-
/* @__PURE__ */ (0,
|
|
1316
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DropdownMenuContent, { align: "end", children: [
|
|
1317
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
|
|
1318
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react2.LinkIcon, {}),
|
|
1272
1319
|
" Copy link"
|
|
1273
1320
|
] }),
|
|
1274
|
-
/* @__PURE__ */ (0,
|
|
1275
|
-
/* @__PURE__ */ (0,
|
|
1321
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
|
|
1322
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react2.FileTextIcon, {}),
|
|
1276
1323
|
" Copy as Markdown"
|
|
1277
1324
|
] }),
|
|
1278
|
-
/* @__PURE__ */ (0,
|
|
1279
|
-
/* @__PURE__ */ (0,
|
|
1325
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
|
|
1326
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react2.SparklesIcon, {}),
|
|
1280
1327
|
" Explain with AI"
|
|
1281
1328
|
] })
|
|
1282
1329
|
] })
|
|
1283
1330
|
] }) : null
|
|
1284
1331
|
] })
|
|
1285
1332
|
] }),
|
|
1286
|
-
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0,
|
|
1287
|
-
scenario.tags.map((t) => /* @__PURE__ */ (0,
|
|
1288
|
-
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0,
|
|
1333
|
+
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
|
|
1334
|
+
scenario.tags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
|
|
1335
|
+
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("li", { children: ticket.url ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
|
|
1289
1336
|
] }) : null
|
|
1290
1337
|
] }),
|
|
1291
|
-
/* @__PURE__ */ (0,
|
|
1292
|
-
scenario.errorMessage ? /* @__PURE__ */ (0,
|
|
1338
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
|
|
1339
|
+
scenario.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1293
1340
|
"pre",
|
|
1294
1341
|
{
|
|
1295
1342
|
role: "alert",
|
|
@@ -1297,11 +1344,11 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1297
1344
|
children: scenario.errorMessage
|
|
1298
1345
|
}
|
|
1299
1346
|
) : null,
|
|
1300
|
-
/* @__PURE__ */ (0,
|
|
1301
|
-
/* @__PURE__ */ (0,
|
|
1302
|
-
scenario.docEntries.length > 0 ? /* @__PURE__ */ (0,
|
|
1303
|
-
/* @__PURE__ */ (0,
|
|
1304
|
-
/* @__PURE__ */ (0,
|
|
1347
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportStoryboard, { scenario }),
|
|
1348
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportSteps, { scenario }),
|
|
1349
|
+
scenario.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
|
|
1350
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportAttachments, { attachments: scenario.attachments }),
|
|
1351
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportTrace, { spans: scenario.otelSpans })
|
|
1305
1352
|
] })
|
|
1306
1353
|
]
|
|
1307
1354
|
}
|
|
@@ -1309,13 +1356,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1309
1356
|
}
|
|
1310
1357
|
|
|
1311
1358
|
// src/components/ReportScenarioList.tsx
|
|
1312
|
-
var
|
|
1359
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1313
1360
|
function ReportScenarioList({ feature }) {
|
|
1314
|
-
return /* @__PURE__ */ (0,
|
|
1361
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_jsx_runtime27.Fragment, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ReportScenario, { scenario }, scenario.id)) });
|
|
1315
1362
|
}
|
|
1316
1363
|
|
|
1317
1364
|
// src/components/ReportFeature.tsx
|
|
1318
|
-
var
|
|
1365
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1319
1366
|
function ReportFeature({ feature }) {
|
|
1320
1367
|
const titleId = `${feature.id}-title`;
|
|
1321
1368
|
const bodyId = `${feature.id}-body`;
|
|
@@ -1326,7 +1373,7 @@ function ReportFeature({ feature }) {
|
|
|
1326
1373
|
return (
|
|
1327
1374
|
// Suite = a section heading + a divider, NOT another bordered card. Drops a
|
|
1328
1375
|
// layer of nesting so the scenario cards below read as the primary unit.
|
|
1329
|
-
/* @__PURE__ */ (0,
|
|
1376
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
1330
1377
|
"section",
|
|
1331
1378
|
{
|
|
1332
1379
|
id: feature.id,
|
|
@@ -1334,9 +1381,9 @@ function ReportFeature({ feature }) {
|
|
|
1334
1381
|
"aria-labelledby": titleId,
|
|
1335
1382
|
className: "flex flex-col gap-3",
|
|
1336
1383
|
children: [
|
|
1337
|
-
/* @__PURE__ */ (0,
|
|
1338
|
-
/* @__PURE__ */ (0,
|
|
1339
|
-
/* @__PURE__ */ (0,
|
|
1384
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
|
|
1385
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "min-w-0", children: [
|
|
1386
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
1340
1387
|
"button",
|
|
1341
1388
|
{
|
|
1342
1389
|
type: "button",
|
|
@@ -1345,31 +1392,31 @@ function ReportFeature({ feature }) {
|
|
|
1345
1392
|
"aria-controls": bodyId,
|
|
1346
1393
|
className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
|
|
1347
1394
|
children: [
|
|
1348
|
-
/* @__PURE__ */ (0,
|
|
1349
|
-
/* @__PURE__ */ (0,
|
|
1395
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
|
|
1396
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "truncate", children: feature.title })
|
|
1350
1397
|
]
|
|
1351
1398
|
}
|
|
1352
1399
|
) : feature.title }),
|
|
1353
|
-
/* @__PURE__ */ (0,
|
|
1400
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
|
|
1354
1401
|
] }),
|
|
1355
|
-
/* @__PURE__ */ (0,
|
|
1402
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
1356
1403
|
"p",
|
|
1357
1404
|
{
|
|
1358
1405
|
className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
|
|
1359
1406
|
"aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
|
|
1360
1407
|
children: [
|
|
1361
|
-
/* @__PURE__ */ (0,
|
|
1408
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { children: [
|
|
1362
1409
|
s.passed,
|
|
1363
1410
|
" passed"
|
|
1364
1411
|
] }),
|
|
1365
|
-
/* @__PURE__ */ (0,
|
|
1366
|
-
/* @__PURE__ */ (0,
|
|
1412
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1413
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
|
|
1367
1414
|
s.failed,
|
|
1368
1415
|
" failed"
|
|
1369
1416
|
] }),
|
|
1370
|
-
skipped > 0 ? /* @__PURE__ */ (0,
|
|
1371
|
-
/* @__PURE__ */ (0,
|
|
1372
|
-
/* @__PURE__ */ (0,
|
|
1417
|
+
skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
|
|
1418
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1419
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { children: [
|
|
1373
1420
|
skipped,
|
|
1374
1421
|
" skipped"
|
|
1375
1422
|
] })
|
|
@@ -1378,7 +1425,7 @@ function ReportFeature({ feature }) {
|
|
|
1378
1425
|
}
|
|
1379
1426
|
)
|
|
1380
1427
|
] }),
|
|
1381
|
-
/* @__PURE__ */ (0,
|
|
1428
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ReportScenarioList, { feature }) })
|
|
1382
1429
|
]
|
|
1383
1430
|
}
|
|
1384
1431
|
)
|
|
@@ -1386,17 +1433,17 @@ function ReportFeature({ feature }) {
|
|
|
1386
1433
|
}
|
|
1387
1434
|
|
|
1388
1435
|
// src/components/ReportFeatureList.tsx
|
|
1389
|
-
var
|
|
1436
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
1390
1437
|
function ReportFeatureList() {
|
|
1391
1438
|
const report = useReport();
|
|
1392
|
-
return /* @__PURE__ */ (0,
|
|
1439
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ReportFeature, { feature }, feature.id)) });
|
|
1393
1440
|
}
|
|
1394
1441
|
|
|
1395
1442
|
// src/components/ui/empty.tsx
|
|
1396
1443
|
var import_class_variance_authority2 = require("class-variance-authority");
|
|
1397
|
-
var
|
|
1444
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
1398
1445
|
function Empty({ className, ...props }) {
|
|
1399
|
-
return /* @__PURE__ */ (0,
|
|
1446
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
1400
1447
|
"div",
|
|
1401
1448
|
{
|
|
1402
1449
|
"data-slot": "empty",
|
|
@@ -1409,7 +1456,7 @@ function Empty({ className, ...props }) {
|
|
|
1409
1456
|
);
|
|
1410
1457
|
}
|
|
1411
1458
|
function EmptyHeader({ className, ...props }) {
|
|
1412
|
-
return /* @__PURE__ */ (0,
|
|
1459
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
1413
1460
|
"div",
|
|
1414
1461
|
{
|
|
1415
1462
|
"data-slot": "empty-header",
|
|
@@ -1436,7 +1483,7 @@ var emptyMediaVariants = (0, import_class_variance_authority2.cva)(
|
|
|
1436
1483
|
}
|
|
1437
1484
|
);
|
|
1438
1485
|
function EmptyTitle({ className, ...props }) {
|
|
1439
|
-
return /* @__PURE__ */ (0,
|
|
1486
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
1440
1487
|
"div",
|
|
1441
1488
|
{
|
|
1442
1489
|
"data-slot": "empty-title",
|
|
@@ -1447,16 +1494,16 @@ function EmptyTitle({ className, ...props }) {
|
|
|
1447
1494
|
}
|
|
1448
1495
|
|
|
1449
1496
|
// src/components/ReportEmpty.tsx
|
|
1450
|
-
var
|
|
1497
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
1451
1498
|
function ReportEmpty({ message }) {
|
|
1452
|
-
return /* @__PURE__ */ (0,
|
|
1499
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(EmptyHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
|
|
1453
1500
|
}
|
|
1454
1501
|
|
|
1455
1502
|
// src/components/ReportSummary.tsx
|
|
1456
|
-
var
|
|
1503
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
1457
1504
|
function ReportSummary({ className }) {
|
|
1458
1505
|
const report = useReport();
|
|
1459
|
-
return /* @__PURE__ */ (0,
|
|
1506
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
1460
1507
|
ReportSummaryView,
|
|
1461
1508
|
{
|
|
1462
1509
|
summary: report.summary,
|
|
@@ -1482,7 +1529,7 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1482
1529
|
if (summary.pending > 0) {
|
|
1483
1530
|
cards.push({ status: "pending", label: "Pending", value: summary.pending });
|
|
1484
1531
|
}
|
|
1485
|
-
return /* @__PURE__ */ (0,
|
|
1532
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
1486
1533
|
"dl",
|
|
1487
1534
|
{
|
|
1488
1535
|
className: cn(
|
|
@@ -1495,17 +1542,17 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1495
1542
|
"aria-label": ariaLabel,
|
|
1496
1543
|
children: cards.map((c) => {
|
|
1497
1544
|
const tone = TONE[c.status];
|
|
1498
|
-
return /* @__PURE__ */ (0,
|
|
1545
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
|
|
1499
1546
|
"div",
|
|
1500
1547
|
{
|
|
1501
1548
|
"data-status": c.status,
|
|
1502
1549
|
className: "rounded-lg border bg-card px-4 py-3",
|
|
1503
1550
|
children: [
|
|
1504
|
-
/* @__PURE__ */ (0,
|
|
1505
|
-
/* @__PURE__ */ (0,
|
|
1551
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
|
|
1552
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
|
|
1506
1553
|
c.label
|
|
1507
1554
|
] }),
|
|
1508
|
-
/* @__PURE__ */ (0,
|
|
1555
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
|
|
1509
1556
|
]
|
|
1510
1557
|
},
|
|
1511
1558
|
c.status
|
|
@@ -1515,6 +1562,9 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1515
1562
|
);
|
|
1516
1563
|
}
|
|
1517
1564
|
|
|
1565
|
+
// src/components/ReportMeta.tsx
|
|
1566
|
+
var import_duration4 = require("executable-stories-core/utils/duration");
|
|
1567
|
+
|
|
1518
1568
|
// src/lib/provenance.ts
|
|
1519
1569
|
function reportLastRunMs(report) {
|
|
1520
1570
|
if (report.finishedAtMs && report.finishedAtMs > 0) return report.finishedAtMs;
|
|
@@ -1565,7 +1615,7 @@ function prUrl(ci) {
|
|
|
1565
1615
|
}
|
|
1566
1616
|
|
|
1567
1617
|
// src/components/ReportMeta.tsx
|
|
1568
|
-
var
|
|
1618
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
1569
1619
|
function ReportMeta() {
|
|
1570
1620
|
const report = useReport();
|
|
1571
1621
|
const items = [];
|
|
@@ -1574,7 +1624,7 @@ function ReportMeta() {
|
|
|
1574
1624
|
items.push({ label: "Started", value: new Date(report.startedAtMs).toLocaleString() });
|
|
1575
1625
|
}
|
|
1576
1626
|
if (report.durationMs) {
|
|
1577
|
-
items.push({ label: "Duration", value: formatDuration(report.durationMs) });
|
|
1627
|
+
items.push({ label: "Duration", value: (0, import_duration4.formatDuration)(report.durationMs) });
|
|
1578
1628
|
}
|
|
1579
1629
|
if (report.packageVersion) {
|
|
1580
1630
|
items.push({ label: "Version", value: report.packageVersion });
|
|
@@ -1588,13 +1638,13 @@ function ReportMeta() {
|
|
|
1588
1638
|
const short = sha.slice(0, 8);
|
|
1589
1639
|
items.push({
|
|
1590
1640
|
label: "Commit",
|
|
1591
|
-
value: url ? /* @__PURE__ */ (0,
|
|
1641
|
+
value: url ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
|
|
1592
1642
|
});
|
|
1593
1643
|
}
|
|
1594
1644
|
if (report.ci) {
|
|
1595
1645
|
items.push({
|
|
1596
1646
|
label: "CI",
|
|
1597
|
-
value: report.ci.url ? /* @__PURE__ */ (0,
|
|
1647
|
+
value: report.ci.url ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
|
|
1598
1648
|
ciDisplayName(report.ci.name),
|
|
1599
1649
|
report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
|
|
1600
1650
|
] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
|
|
@@ -1605,7 +1655,7 @@ function ReportMeta() {
|
|
|
1605
1655
|
const label = `#${report.ci.prNumber}`;
|
|
1606
1656
|
items.push({
|
|
1607
1657
|
label: "PR",
|
|
1608
|
-
value: url ? /* @__PURE__ */ (0,
|
|
1658
|
+
value: url ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
|
|
1609
1659
|
});
|
|
1610
1660
|
}
|
|
1611
1661
|
if (items.length === 0) return null;
|
|
@@ -1613,48 +1663,48 @@ function ReportMeta() {
|
|
|
1613
1663
|
// Run metadata is useful but secondary to "what failed" — tuck it into a
|
|
1614
1664
|
// collapsed disclosure so it doesn't push the result down. Native <details>
|
|
1615
1665
|
// so it works with no JS (the SSR/no-hydration report still toggles).
|
|
1616
|
-
/* @__PURE__ */ (0,
|
|
1617
|
-
/* @__PURE__ */ (0,
|
|
1618
|
-
/* @__PURE__ */ (0,
|
|
1666
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
|
|
1667
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("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: [
|
|
1668
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
|
|
1619
1669
|
"Run details"
|
|
1620
1670
|
] }),
|
|
1621
|
-
/* @__PURE__ */ (0,
|
|
1622
|
-
/* @__PURE__ */ (0,
|
|
1623
|
-
/* @__PURE__ */ (0,
|
|
1671
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("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__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex items-baseline gap-1.5", children: [
|
|
1672
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("dt", { className: "font-medium", children: item.label }),
|
|
1673
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("dd", { className: "font-mono text-foreground", children: item.value })
|
|
1624
1674
|
] }, item.label)) })
|
|
1625
1675
|
] })
|
|
1626
1676
|
);
|
|
1627
1677
|
}
|
|
1628
1678
|
|
|
1629
1679
|
// src/components/ReportSchemaError.tsx
|
|
1630
|
-
var
|
|
1680
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
1631
1681
|
function ReportSchemaError({ error }) {
|
|
1632
|
-
return /* @__PURE__ */ (0,
|
|
1633
|
-
/* @__PURE__ */ (0,
|
|
1634
|
-
/* @__PURE__ */ (0,
|
|
1635
|
-
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0,
|
|
1682
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
|
|
1683
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("strong", { children: "Report could not be displayed." }) }),
|
|
1684
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { children: error.message }),
|
|
1685
|
+
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("p", { children: [
|
|
1636
1686
|
"The report bundle is newer than this version of ",
|
|
1637
|
-
/* @__PURE__ */ (0,
|
|
1687
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("code", { children: "executable-stories-react" }),
|
|
1638
1688
|
". Upgrade the package, or regenerate the report with an older formatters CLI."
|
|
1639
1689
|
] }) : null,
|
|
1640
|
-
error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0,
|
|
1641
|
-
/* @__PURE__ */ (0,
|
|
1690
|
+
error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("details", { children: [
|
|
1691
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("summary", { children: [
|
|
1642
1692
|
error.issues.length,
|
|
1643
1693
|
" validation issue",
|
|
1644
1694
|
error.issues.length === 1 ? "" : "s"
|
|
1645
1695
|
] }),
|
|
1646
|
-
/* @__PURE__ */ (0,
|
|
1696
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
|
|
1647
1697
|
] }) : null
|
|
1648
1698
|
] });
|
|
1649
1699
|
}
|
|
1650
1700
|
|
|
1651
1701
|
// src/components/ReportShell.tsx
|
|
1652
|
-
var
|
|
1702
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
1653
1703
|
function ReportTitleBlock({ title }) {
|
|
1654
|
-
return /* @__PURE__ */ (0,
|
|
1655
|
-
/* @__PURE__ */ (0,
|
|
1656
|
-
/* @__PURE__ */ (0,
|
|
1657
|
-
/* @__PURE__ */ (0,
|
|
1704
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
|
|
1705
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h1", { children: title ?? "Story Report" }),
|
|
1706
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportSummary, {}),
|
|
1707
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportMeta, {})
|
|
1658
1708
|
] });
|
|
1659
1709
|
}
|
|
1660
1710
|
function ReportErrorShell({
|
|
@@ -1663,28 +1713,28 @@ function ReportErrorShell({
|
|
|
1663
1713
|
title,
|
|
1664
1714
|
dataTheme
|
|
1665
1715
|
}) {
|
|
1666
|
-
return /* @__PURE__ */ (0,
|
|
1716
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportSchemaError, { error }) });
|
|
1667
1717
|
}
|
|
1668
1718
|
|
|
1669
1719
|
// src/components/Report.tsx
|
|
1670
|
-
var
|
|
1720
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
1671
1721
|
function Report(props) {
|
|
1672
1722
|
const { report, customRenderers, renderers, className, title, dataTheme } = props;
|
|
1673
1723
|
const result = unwrapReport(report);
|
|
1674
1724
|
if (!result.ok) {
|
|
1675
|
-
return /* @__PURE__ */ (0,
|
|
1725
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
|
|
1676
1726
|
}
|
|
1677
1727
|
const data = result.data;
|
|
1678
1728
|
const hasContent = data.features.length > 0;
|
|
1679
|
-
return /* @__PURE__ */ (0,
|
|
1680
|
-
/* @__PURE__ */ (0,
|
|
1681
|
-
hasContent ? /* @__PURE__ */ (0,
|
|
1729
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
|
|
1730
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("header", { className: "es-report-header", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ReportTitleBlock, { title }) }),
|
|
1731
|
+
hasContent ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ReportFeatureList, {}) : /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ReportEmpty, {})
|
|
1682
1732
|
] }) });
|
|
1683
1733
|
}
|
|
1684
1734
|
|
|
1685
1735
|
// src/components/doc/MermaidView.tsx
|
|
1686
1736
|
var import_react8 = require("react");
|
|
1687
|
-
var
|
|
1737
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
1688
1738
|
function prefersDark(el) {
|
|
1689
1739
|
const themed = el?.closest("[data-theme]");
|
|
1690
1740
|
if (themed?.dataset.theme === "dark") return true;
|
|
@@ -1738,9 +1788,9 @@ function MermaidView({ entry, load }) {
|
|
|
1738
1788
|
};
|
|
1739
1789
|
}, [entry.code, load]);
|
|
1740
1790
|
if (svg) {
|
|
1741
|
-
return /* @__PURE__ */ (0,
|
|
1742
|
-
entry.title ? /* @__PURE__ */ (0,
|
|
1743
|
-
/* @__PURE__ */ (0,
|
|
1791
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("figure", { ref, className: "my-3", children: [
|
|
1792
|
+
entry.title ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
|
|
1793
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
1744
1794
|
"div",
|
|
1745
1795
|
{
|
|
1746
1796
|
role: "img",
|
|
@@ -1751,8 +1801,8 @@ function MermaidView({ entry, load }) {
|
|
|
1751
1801
|
)
|
|
1752
1802
|
] });
|
|
1753
1803
|
}
|
|
1754
|
-
return /* @__PURE__ */ (0,
|
|
1755
|
-
error ? /* @__PURE__ */ (0,
|
|
1804
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_jsx_runtime37.Fragment, { children: [
|
|
1805
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
|
|
1756
1806
|
"p",
|
|
1757
1807
|
{
|
|
1758
1808
|
role: "alert",
|
|
@@ -1764,19 +1814,19 @@ function MermaidView({ entry, load }) {
|
|
|
1764
1814
|
]
|
|
1765
1815
|
}
|
|
1766
1816
|
) : null,
|
|
1767
|
-
/* @__PURE__ */ (0,
|
|
1817
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(MermaidSource, { entry, ref })
|
|
1768
1818
|
] });
|
|
1769
1819
|
}
|
|
1770
1820
|
|
|
1771
1821
|
// src/components/doc/MermaidDiagram.tsx
|
|
1772
|
-
var
|
|
1822
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
1773
1823
|
var mermaidLoader;
|
|
1774
1824
|
function loadMermaid() {
|
|
1775
1825
|
mermaidLoader ??= import("mermaid").then((m) => m.default);
|
|
1776
1826
|
return mermaidLoader;
|
|
1777
1827
|
}
|
|
1778
1828
|
function MermaidDiagram({ entry, load = loadMermaid }) {
|
|
1779
|
-
return /* @__PURE__ */ (0,
|
|
1829
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(MermaidView, { entry, load });
|
|
1780
1830
|
}
|
|
1781
1831
|
|
|
1782
1832
|
// src/components/ScenarioExplorer.tsx
|
|
@@ -1786,12 +1836,12 @@ var import_react9 = require("react");
|
|
|
1786
1836
|
var React4 = require("react");
|
|
1787
1837
|
var import_cmdk = require("cmdk");
|
|
1788
1838
|
var import_lucide_react3 = require("lucide-react");
|
|
1789
|
-
var
|
|
1839
|
+
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
1790
1840
|
function Command({
|
|
1791
1841
|
className,
|
|
1792
1842
|
...props
|
|
1793
1843
|
}) {
|
|
1794
|
-
return /* @__PURE__ */ (0,
|
|
1844
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
1795
1845
|
import_cmdk.Command,
|
|
1796
1846
|
{
|
|
1797
1847
|
"data-slot": "command",
|
|
@@ -1807,14 +1857,14 @@ function CommandInput({
|
|
|
1807
1857
|
className,
|
|
1808
1858
|
...props
|
|
1809
1859
|
}) {
|
|
1810
|
-
return /* @__PURE__ */ (0,
|
|
1860
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
|
|
1811
1861
|
"div",
|
|
1812
1862
|
{
|
|
1813
1863
|
"data-slot": "command-input-wrapper",
|
|
1814
1864
|
className: "flex h-9 items-center gap-2 border-b px-3",
|
|
1815
1865
|
children: [
|
|
1816
|
-
/* @__PURE__ */ (0,
|
|
1817
|
-
/* @__PURE__ */ (0,
|
|
1866
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_lucide_react3.SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
|
|
1867
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
1818
1868
|
import_cmdk.Command.Input,
|
|
1819
1869
|
{
|
|
1820
1870
|
"data-slot": "command-input",
|
|
@@ -1833,7 +1883,7 @@ function CommandList({
|
|
|
1833
1883
|
className,
|
|
1834
1884
|
...props
|
|
1835
1885
|
}) {
|
|
1836
|
-
return /* @__PURE__ */ (0,
|
|
1886
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
1837
1887
|
import_cmdk.Command.List,
|
|
1838
1888
|
{
|
|
1839
1889
|
"data-slot": "command-list",
|
|
@@ -1848,7 +1898,7 @@ function CommandList({
|
|
|
1848
1898
|
function CommandEmpty({
|
|
1849
1899
|
...props
|
|
1850
1900
|
}) {
|
|
1851
|
-
return /* @__PURE__ */ (0,
|
|
1901
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
1852
1902
|
import_cmdk.Command.Empty,
|
|
1853
1903
|
{
|
|
1854
1904
|
"data-slot": "command-empty",
|
|
@@ -1861,7 +1911,7 @@ function CommandGroup({
|
|
|
1861
1911
|
className,
|
|
1862
1912
|
...props
|
|
1863
1913
|
}) {
|
|
1864
|
-
return /* @__PURE__ */ (0,
|
|
1914
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
1865
1915
|
import_cmdk.Command.Group,
|
|
1866
1916
|
{
|
|
1867
1917
|
"data-slot": "command-group",
|
|
@@ -1877,7 +1927,7 @@ function CommandItem({
|
|
|
1877
1927
|
className,
|
|
1878
1928
|
...props
|
|
1879
1929
|
}) {
|
|
1880
|
-
return /* @__PURE__ */ (0,
|
|
1930
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
1881
1931
|
import_cmdk.Command.Item,
|
|
1882
1932
|
{
|
|
1883
1933
|
"data-slot": "command-item",
|
|
@@ -1891,7 +1941,7 @@ function CommandItem({
|
|
|
1891
1941
|
}
|
|
1892
1942
|
|
|
1893
1943
|
// src/components/ScenarioExplorer.tsx
|
|
1894
|
-
var
|
|
1944
|
+
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
1895
1945
|
var STATUS_FILTERS = [
|
|
1896
1946
|
{ value: "all", label: "All" },
|
|
1897
1947
|
{ value: "passed", label: "Passed" },
|
|
@@ -1902,22 +1952,22 @@ var STATUS_FILTERS = [
|
|
|
1902
1952
|
function ScenarioExplorer({ scenarios, summary }) {
|
|
1903
1953
|
const [status, setStatus] = (0, import_react9.useState)("all");
|
|
1904
1954
|
const visible = status === "all" ? scenarios : scenarios.filter((s) => s.status === status);
|
|
1905
|
-
return /* @__PURE__ */ (0,
|
|
1906
|
-
summary ? /* @__PURE__ */ (0,
|
|
1955
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "font-sans text-foreground", children: [
|
|
1956
|
+
summary ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("p", { className: "mb-3 text-sm text-muted-foreground", children: [
|
|
1907
1957
|
summary.total,
|
|
1908
1958
|
" scenarios \xB7 ",
|
|
1909
|
-
/* @__PURE__ */ (0,
|
|
1959
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "text-pass", children: [
|
|
1910
1960
|
summary.passed,
|
|
1911
1961
|
" passed"
|
|
1912
1962
|
] }),
|
|
1913
1963
|
" \xB7",
|
|
1914
1964
|
" ",
|
|
1915
|
-
/* @__PURE__ */ (0,
|
|
1965
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "text-fail", children: [
|
|
1916
1966
|
summary.failed,
|
|
1917
1967
|
" failed"
|
|
1918
1968
|
] })
|
|
1919
1969
|
] }) : null,
|
|
1920
|
-
/* @__PURE__ */ (0,
|
|
1970
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "mb-2 flex flex-wrap gap-1.5", role: "group", "aria-label": "Filter by status", children: STATUS_FILTERS.map((f) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
1921
1971
|
"button",
|
|
1922
1972
|
{
|
|
1923
1973
|
type: "button",
|
|
@@ -1932,26 +1982,26 @@ function ScenarioExplorer({ scenarios, summary }) {
|
|
|
1932
1982
|
},
|
|
1933
1983
|
f.value
|
|
1934
1984
|
)) }),
|
|
1935
|
-
/* @__PURE__ */ (0,
|
|
1985
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
|
|
1936
1986
|
Command,
|
|
1937
1987
|
{
|
|
1938
1988
|
className: "rounded-lg border border-border bg-card",
|
|
1939
1989
|
filter: (value, search) => value.toLowerCase().includes(search.toLowerCase()) ? 1 : 0,
|
|
1940
1990
|
children: [
|
|
1941
|
-
/* @__PURE__ */ (0,
|
|
1942
|
-
/* @__PURE__ */ (0,
|
|
1943
|
-
/* @__PURE__ */ (0,
|
|
1944
|
-
/* @__PURE__ */ (0,
|
|
1991
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(CommandInput, { placeholder: "Search scenarios\u2026" }),
|
|
1992
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(CommandList, { className: "max-h-none", children: [
|
|
1993
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(CommandEmpty, { children: "No scenarios match your filters." }),
|
|
1994
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(CommandGroup, { children: visible.map((s) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
1945
1995
|
CommandItem,
|
|
1946
1996
|
{
|
|
1947
1997
|
value: `${s.title} ${s.feature} ${s.tags.join(" ")}`,
|
|
1948
1998
|
asChild: true,
|
|
1949
1999
|
className: "cursor-pointer",
|
|
1950
|
-
children: /* @__PURE__ */ (0,
|
|
1951
|
-
/* @__PURE__ */ (0,
|
|
1952
|
-
/* @__PURE__ */ (0,
|
|
1953
|
-
s.tags.slice(0, 3).map((t) => /* @__PURE__ */ (0,
|
|
1954
|
-
/* @__PURE__ */ (0,
|
|
2000
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("a", { href: s.href, className: "flex items-center gap-3", children: [
|
|
2001
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Badge, { variant: s.status, children: s.status }),
|
|
2002
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "min-w-0 flex-1 truncate font-medium", children: s.title }),
|
|
2003
|
+
s.tags.slice(0, 3).map((t) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Badge, { variant: "tag", className: "hidden sm:inline-flex", children: t }, t)),
|
|
2004
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("code", { className: "hidden font-mono text-xs text-muted-foreground md:inline", children: s.feature })
|
|
1955
2005
|
] })
|
|
1956
2006
|
},
|
|
1957
2007
|
s.id
|
|
@@ -2974,6 +3024,8 @@ function parseStoryReport(input) {
|
|
|
2974
3024
|
}
|
|
2975
3025
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2976
3026
|
0 && (module.exports = {
|
|
3027
|
+
DATA_MODEL_TYPE,
|
|
3028
|
+
DataModelBlock,
|
|
2977
3029
|
DocCode,
|
|
2978
3030
|
DocCustom,
|
|
2979
3031
|
DocEntry,
|
|
@@ -2987,6 +3039,8 @@ function parseStoryReport(input) {
|
|
|
2987
3039
|
DocTable,
|
|
2988
3040
|
DocTag,
|
|
2989
3041
|
DocVideo,
|
|
3042
|
+
FILE_TREE_TYPE,
|
|
3043
|
+
FileTreeBlock,
|
|
2990
3044
|
MermaidDiagram,
|
|
2991
3045
|
MermaidSource,
|
|
2992
3046
|
Report,
|
|
@@ -3016,7 +3070,10 @@ function parseStoryReport(input) {
|
|
|
3016
3070
|
err,
|
|
3017
3071
|
formatRelativeAge,
|
|
3018
3072
|
isReportStale,
|
|
3073
|
+
narrativeBlockRenderers,
|
|
3019
3074
|
ok,
|
|
3075
|
+
parseDataModel,
|
|
3076
|
+
parseFileTree,
|
|
3020
3077
|
parseStoryReport,
|
|
3021
3078
|
prUrl,
|
|
3022
3079
|
reportLastRunMs,
|