executable-stories-react 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +558 -335
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +45 -1
- package/dist/index.d.ts +45 -1
- package/dist/index.js +551 -335
- package/dist/index.js.map +1 -1
- package/dist/interactive.cjs +772 -476
- package/dist/interactive.cjs.map +1 -1
- package/dist/interactive.d.cts +25 -3
- package/dist/interactive.d.ts +25 -3
- package/dist/interactive.js +762 -466
- package/dist/interactive.js.map +1 -1
- package/dist/report-island.global.js +28 -28
- package/dist/ssr.cjs +477 -299
- package/dist/ssr.cjs.map +1 -1
- package/dist/ssr.js +477 -299
- package/dist/ssr.js.map +1 -1
- package/dist/tailwind.css +1 -1
- package/package.json +1 -1
package/dist/interactive.cjs
CHANGED
|
@@ -47,7 +47,7 @@ __export(interactive_exports, {
|
|
|
47
47
|
module.exports = __toCommonJS(interactive_exports);
|
|
48
48
|
|
|
49
49
|
// src/interactive/ReportInteractive.tsx
|
|
50
|
-
var
|
|
50
|
+
var import_react19 = require("react");
|
|
51
51
|
|
|
52
52
|
// src/result.ts
|
|
53
53
|
var ok = (data) => ({ ok: true, data });
|
|
@@ -65,63 +65,6 @@ var import_react2 = require("react");
|
|
|
65
65
|
var import_react = require("react");
|
|
66
66
|
var ReportContext = (0, import_react.createContext)(null);
|
|
67
67
|
|
|
68
|
-
// src/context/ReportRoot.tsx
|
|
69
|
-
var import_jsx_runtime = require("react/jsx-runtime");
|
|
70
|
-
var EMPTY_CUSTOM = {};
|
|
71
|
-
var EMPTY_RENDERERS = {};
|
|
72
|
-
function ReportRoot({
|
|
73
|
-
report,
|
|
74
|
-
customRenderers,
|
|
75
|
-
renderers,
|
|
76
|
-
children
|
|
77
|
-
}) {
|
|
78
|
-
const value = (0, import_react2.useMemo)(
|
|
79
|
-
() => ({
|
|
80
|
-
report,
|
|
81
|
-
customRenderers: customRenderers ?? EMPTY_CUSTOM,
|
|
82
|
-
renderers: renderers ?? EMPTY_RENDERERS
|
|
83
|
-
}),
|
|
84
|
-
[report, customRenderers, renderers]
|
|
85
|
-
);
|
|
86
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ReportContext.Provider, { value, children });
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// src/hooks/useReport.ts
|
|
90
|
-
var import_react3 = require("react");
|
|
91
|
-
function useReport() {
|
|
92
|
-
const ctx = (0, import_react3.useContext)(ReportContext);
|
|
93
|
-
if (!ctx) {
|
|
94
|
-
throw new Error(
|
|
95
|
-
"useReport must be used inside <ReportRoot> or <Report>. Wrap your tree with one of those."
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
return ctx.report;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// ../executable-stories-core/dist/utils/duration.js
|
|
102
|
-
function formatDuration(ms) {
|
|
103
|
-
if (ms < 1e3) {
|
|
104
|
-
return `${Math.round(ms)} ms`;
|
|
105
|
-
}
|
|
106
|
-
if (ms < 6e4) {
|
|
107
|
-
return `${(ms / 1e3).toFixed(2)} s`;
|
|
108
|
-
}
|
|
109
|
-
const minutes = Math.floor(ms / 6e4);
|
|
110
|
-
const seconds = Math.floor(ms % 6e4 / 1e3);
|
|
111
|
-
if (minutes < 60) {
|
|
112
|
-
return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
|
|
113
|
-
}
|
|
114
|
-
const hours = Math.floor(minutes / 60);
|
|
115
|
-
const remainingMinutes = minutes % 60;
|
|
116
|
-
return `${hours}h ${remainingMinutes}m`;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// src/components/doc/DocNote.tsx
|
|
120
|
-
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
121
|
-
function DocNote({ entry }) {
|
|
122
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "my-2 text-sm text-muted-foreground", children: entry.text });
|
|
123
|
-
}
|
|
124
|
-
|
|
125
68
|
// src/components/ui/badge.tsx
|
|
126
69
|
var React = require("react");
|
|
127
70
|
var import_class_variance_authority = require("class-variance-authority");
|
|
@@ -180,14 +123,249 @@ function Badge({
|
|
|
180
123
|
});
|
|
181
124
|
}
|
|
182
125
|
|
|
183
|
-
// src/components/doc/
|
|
126
|
+
// src/components/doc/NarrativeBlocks.tsx
|
|
127
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
128
|
+
var FILE_TREE_TYPE = "file-tree";
|
|
129
|
+
var DATA_MODEL_TYPE = "data-model";
|
|
130
|
+
function isChangeKind(value) {
|
|
131
|
+
return value === "added" || value === "modified" || value === "removed" || value === "renamed";
|
|
132
|
+
}
|
|
133
|
+
function isRecord(value) {
|
|
134
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
135
|
+
}
|
|
136
|
+
function str(value) {
|
|
137
|
+
return typeof value === "string" && value !== "" ? value : void 0;
|
|
138
|
+
}
|
|
139
|
+
function AuthoredMarker({ authored }) {
|
|
140
|
+
if (authored !== "agent") return null;
|
|
141
|
+
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" });
|
|
142
|
+
}
|
|
143
|
+
function BlockFrame({
|
|
144
|
+
title,
|
|
145
|
+
authored,
|
|
146
|
+
children
|
|
147
|
+
}) {
|
|
148
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("figure", { className: "my-3", children: [
|
|
149
|
+
title || authored === "agent" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("figcaption", { className: "mb-1.5 flex flex-wrap items-center gap-2", children: [
|
|
150
|
+
title ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-xs font-medium text-muted-foreground", children: title }) : null,
|
|
151
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AuthoredMarker, { authored })
|
|
152
|
+
] }) : null,
|
|
153
|
+
children
|
|
154
|
+
] });
|
|
155
|
+
}
|
|
156
|
+
function ChangeBadge({ change }) {
|
|
157
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge, { variant: "tag", className: "text-[10px]", children: change });
|
|
158
|
+
}
|
|
159
|
+
function parseFileTree(data) {
|
|
160
|
+
if (!isRecord(data) || !Array.isArray(data.files)) return void 0;
|
|
161
|
+
const files = [];
|
|
162
|
+
for (const raw of data.files) {
|
|
163
|
+
if (typeof raw === "string") {
|
|
164
|
+
if (raw) files.push({ path: raw });
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (!isRecord(raw)) continue;
|
|
168
|
+
const path = str(raw.path);
|
|
169
|
+
if (!path) continue;
|
|
170
|
+
files.push({
|
|
171
|
+
path,
|
|
172
|
+
change: isChangeKind(raw.change) ? raw.change : void 0,
|
|
173
|
+
note: str(raw.note)
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
if (files.length === 0) return void 0;
|
|
177
|
+
return { title: str(data.title), authored: str(data.authored), files };
|
|
178
|
+
}
|
|
179
|
+
function buildTree(files) {
|
|
180
|
+
const root = { name: "", children: /* @__PURE__ */ new Map() };
|
|
181
|
+
for (const file of files) {
|
|
182
|
+
const segments = file.path.split("/").filter(Boolean);
|
|
183
|
+
let node = root;
|
|
184
|
+
segments.forEach((segment, index) => {
|
|
185
|
+
let child = node.children.get(segment);
|
|
186
|
+
if (!child) {
|
|
187
|
+
child = { name: segment, children: /* @__PURE__ */ new Map() };
|
|
188
|
+
node.children.set(segment, child);
|
|
189
|
+
}
|
|
190
|
+
if (index === segments.length - 1) child.file = file;
|
|
191
|
+
node = child;
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
return root;
|
|
195
|
+
}
|
|
196
|
+
function sortedChildren(node) {
|
|
197
|
+
return [...node.children.values()].sort((a, b) => {
|
|
198
|
+
const aDir = a.children.size > 0;
|
|
199
|
+
const bDir = b.children.size > 0;
|
|
200
|
+
if (aDir !== bDir) return aDir ? -1 : 1;
|
|
201
|
+
return a.name.localeCompare(b.name);
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
function TreeBranch({ node, depth }) {
|
|
205
|
+
const children = sortedChildren(node);
|
|
206
|
+
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) => {
|
|
207
|
+
const isDir = child.children.size > 0;
|
|
208
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { children: [
|
|
209
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-wrap items-baseline gap-2", children: [
|
|
210
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
211
|
+
"span",
|
|
212
|
+
{
|
|
213
|
+
className: cn(
|
|
214
|
+
"font-mono text-xs",
|
|
215
|
+
isDir ? "text-muted-foreground" : "text-foreground"
|
|
216
|
+
),
|
|
217
|
+
children: isDir ? `${child.name}/` : child.name
|
|
218
|
+
}
|
|
219
|
+
),
|
|
220
|
+
child.file?.change ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChangeBadge, { change: child.file.change }) : null,
|
|
221
|
+
child.file?.note ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-xs text-muted-foreground", children: child.file.note }) : null
|
|
222
|
+
] }),
|
|
223
|
+
isDir ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TreeBranch, { node: child, depth: depth + 1 }) : null
|
|
224
|
+
] }, child.name);
|
|
225
|
+
}) });
|
|
226
|
+
}
|
|
227
|
+
function FileTreeBlock({ entry }) {
|
|
228
|
+
const data = parseFileTree(entry.data);
|
|
229
|
+
if (!data) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UnreadableBlock, { entry });
|
|
230
|
+
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 }) }) });
|
|
231
|
+
}
|
|
232
|
+
function parseDataModel(data) {
|
|
233
|
+
if (!isRecord(data) || !Array.isArray(data.fields)) return void 0;
|
|
234
|
+
const fields = [];
|
|
235
|
+
for (const raw of data.fields) {
|
|
236
|
+
if (!isRecord(raw)) continue;
|
|
237
|
+
const name = str(raw.name);
|
|
238
|
+
if (!name) continue;
|
|
239
|
+
fields.push({
|
|
240
|
+
name,
|
|
241
|
+
type: str(raw.type),
|
|
242
|
+
note: str(raw.note),
|
|
243
|
+
change: isChangeKind(raw.change) ? raw.change : void 0
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
if (fields.length === 0) return void 0;
|
|
247
|
+
return {
|
|
248
|
+
title: str(data.title),
|
|
249
|
+
authored: str(data.authored),
|
|
250
|
+
name: str(data.name),
|
|
251
|
+
fields
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
function DataModelBlock({ entry }) {
|
|
255
|
+
const data = parseDataModel(entry.data);
|
|
256
|
+
if (!data) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UnreadableBlock, { entry });
|
|
257
|
+
const hasNotes = data.fields.some((f) => f.note);
|
|
258
|
+
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: [
|
|
259
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { className: "bg-muted/50", children: [
|
|
260
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Field" }),
|
|
261
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: "Type" }),
|
|
262
|
+
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
|
|
263
|
+
] }) }),
|
|
264
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: data.fields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
|
|
265
|
+
/* @__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: [
|
|
266
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-mono text-xs text-foreground", children: field.name }),
|
|
267
|
+
field.change ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChangeBadge, { change: field.change }) : null
|
|
268
|
+
] }) }),
|
|
269
|
+
/* @__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 ?? "" }),
|
|
270
|
+
hasNotes ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: "border-b border-border px-3 py-2 text-foreground", children: field.note ?? "" }) : null
|
|
271
|
+
] }, field.name)) })
|
|
272
|
+
] }) }) });
|
|
273
|
+
}
|
|
274
|
+
function UnreadableBlock({ entry }) {
|
|
275
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "my-2", "data-type": entry.type, children: [
|
|
276
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: [
|
|
277
|
+
entry.type,
|
|
278
|
+
" (unrecognised shape)"
|
|
279
|
+
] }),
|
|
280
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
281
|
+
"pre",
|
|
282
|
+
{
|
|
283
|
+
tabIndex: 0,
|
|
284
|
+
className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground",
|
|
285
|
+
children: safeStringify(entry.data)
|
|
286
|
+
}
|
|
287
|
+
)
|
|
288
|
+
] });
|
|
289
|
+
}
|
|
290
|
+
function safeStringify(value) {
|
|
291
|
+
try {
|
|
292
|
+
return JSON.stringify(value, null, 2);
|
|
293
|
+
} catch {
|
|
294
|
+
return String(value);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
var narrativeBlockRenderers = {
|
|
298
|
+
[FILE_TREE_TYPE]: (entry) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileTreeBlock, { entry }),
|
|
299
|
+
[DATA_MODEL_TYPE]: (entry) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DataModelBlock, { entry })
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
// src/context/ReportRoot.tsx
|
|
303
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
304
|
+
var EMPTY_RENDERERS = {};
|
|
305
|
+
function ReportRoot({
|
|
306
|
+
report,
|
|
307
|
+
customRenderers,
|
|
308
|
+
renderers,
|
|
309
|
+
children
|
|
310
|
+
}) {
|
|
311
|
+
const value = (0, import_react2.useMemo)(
|
|
312
|
+
() => ({
|
|
313
|
+
report,
|
|
314
|
+
// Narrative blocks render everywhere the report does (static SSR, the
|
|
315
|
+
// island, Astro) without every host wiring them up. A host renderer for
|
|
316
|
+
// the same type still wins.
|
|
317
|
+
customRenderers: { ...narrativeBlockRenderers, ...customRenderers },
|
|
318
|
+
renderers: renderers ?? EMPTY_RENDERERS
|
|
319
|
+
}),
|
|
320
|
+
[report, customRenderers, renderers]
|
|
321
|
+
);
|
|
322
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ReportContext.Provider, { value, children });
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// src/hooks/useReport.ts
|
|
326
|
+
var import_react3 = require("react");
|
|
327
|
+
function useReport() {
|
|
328
|
+
const ctx = (0, import_react3.useContext)(ReportContext);
|
|
329
|
+
if (!ctx) {
|
|
330
|
+
throw new Error(
|
|
331
|
+
"useReport must be used inside <ReportRoot> or <Report>. Wrap your tree with one of those."
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
return ctx.report;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// ../executable-stories-core/dist/utils/duration.js
|
|
338
|
+
function formatDuration(ms) {
|
|
339
|
+
if (ms < 1e3) {
|
|
340
|
+
return `${Math.round(ms)} ms`;
|
|
341
|
+
}
|
|
342
|
+
if (ms < 6e4) {
|
|
343
|
+
return `${(ms / 1e3).toFixed(2)} s`;
|
|
344
|
+
}
|
|
345
|
+
const minutes = Math.floor(ms / 6e4);
|
|
346
|
+
const seconds = Math.floor(ms % 6e4 / 1e3);
|
|
347
|
+
if (minutes < 60) {
|
|
348
|
+
return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
|
|
349
|
+
}
|
|
350
|
+
const hours = Math.floor(minutes / 60);
|
|
351
|
+
const remainingMinutes = minutes % 60;
|
|
352
|
+
return `${hours}h ${remainingMinutes}m`;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// src/components/doc/DocNote.tsx
|
|
184
356
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
357
|
+
function DocNote({ entry }) {
|
|
358
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "my-2 text-sm text-muted-foreground", children: entry.text });
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// src/components/doc/DocTag.tsx
|
|
362
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
185
363
|
function DocTag({ entry }) {
|
|
186
|
-
return /* @__PURE__ */ (0,
|
|
364
|
+
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)) });
|
|
187
365
|
}
|
|
188
366
|
|
|
189
367
|
// src/components/doc/DocKv.tsx
|
|
190
|
-
var
|
|
368
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
191
369
|
function formatValue(value) {
|
|
192
370
|
if (value === null) return "null";
|
|
193
371
|
if (typeof value === "string") return value;
|
|
@@ -199,19 +377,19 @@ function formatValue(value) {
|
|
|
199
377
|
}
|
|
200
378
|
}
|
|
201
379
|
function DocKv({ entry }) {
|
|
202
|
-
return /* @__PURE__ */ (0,
|
|
203
|
-
/* @__PURE__ */ (0,
|
|
204
|
-
/* @__PURE__ */ (0,
|
|
380
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("dl", { className: "my-2 flex flex-wrap items-baseline gap-x-2 text-sm", children: [
|
|
381
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { className: "font-semibold text-muted-foreground", children: entry.label }),
|
|
382
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { className: "font-mono text-foreground", children: formatValue(entry.value) })
|
|
205
383
|
] });
|
|
206
384
|
}
|
|
207
385
|
|
|
208
386
|
// src/hooks/useRenderers.ts
|
|
209
387
|
var import_react4 = require("react");
|
|
210
|
-
var
|
|
388
|
+
var EMPTY_CUSTOM = {};
|
|
211
389
|
var EMPTY_RENDERERS2 = {};
|
|
212
390
|
function useCustomRenderers() {
|
|
213
391
|
const ctx = (0, import_react4.useContext)(ReportContext);
|
|
214
|
-
return ctx?.customRenderers ??
|
|
392
|
+
return ctx?.customRenderers ?? EMPTY_CUSTOM;
|
|
215
393
|
}
|
|
216
394
|
function useBuiltinRenderers() {
|
|
217
395
|
const ctx = (0, import_react4.useContext)(ReportContext);
|
|
@@ -219,37 +397,37 @@ function useBuiltinRenderers() {
|
|
|
219
397
|
}
|
|
220
398
|
|
|
221
399
|
// src/components/doc/DocCode.tsx
|
|
222
|
-
var
|
|
400
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
223
401
|
function CodeFigure({ label, children }) {
|
|
224
|
-
return /* @__PURE__ */ (0,
|
|
225
|
-
label ? /* @__PURE__ */ (0,
|
|
226
|
-
/* @__PURE__ */ (0,
|
|
402
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("figure", { className: "my-3", children: [
|
|
403
|
+
label ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: label }) : null,
|
|
404
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3", children })
|
|
227
405
|
] });
|
|
228
406
|
}
|
|
229
407
|
function DocCode({ entry }) {
|
|
230
408
|
const renderers = useBuiltinRenderers();
|
|
231
409
|
if (renderers.code) {
|
|
232
|
-
return /* @__PURE__ */ (0,
|
|
410
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: renderers.code(entry) });
|
|
233
411
|
}
|
|
234
|
-
return /* @__PURE__ */ (0,
|
|
412
|
+
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 }) });
|
|
235
413
|
}
|
|
236
414
|
|
|
237
415
|
// src/components/doc/DocTable.tsx
|
|
238
|
-
var
|
|
416
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
239
417
|
function DocTable({ entry }) {
|
|
240
|
-
return /* @__PURE__ */ (0,
|
|
241
|
-
entry.label ? /* @__PURE__ */ (0,
|
|
242
|
-
/* @__PURE__ */ (0,
|
|
243
|
-
/* @__PURE__ */ (0,
|
|
244
|
-
/* @__PURE__ */ (0,
|
|
418
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("figure", { className: "my-3", children: [
|
|
419
|
+
entry.label ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.label }) : null,
|
|
420
|
+
/* @__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: [
|
|
421
|
+
/* @__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)) }) }),
|
|
422
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tbody", { children: entry.rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tr", { children: row.map((cell2, j) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("td", { className: "border-b border-border px-3 py-2 text-foreground", children: cell2 }, j)) }, i)) })
|
|
245
423
|
] }) })
|
|
246
424
|
] });
|
|
247
425
|
}
|
|
248
426
|
|
|
249
427
|
// src/components/doc/DocLink.tsx
|
|
250
|
-
var
|
|
428
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
251
429
|
function DocLink({ entry }) {
|
|
252
|
-
return /* @__PURE__ */ (0,
|
|
430
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
253
431
|
"a",
|
|
254
432
|
{
|
|
255
433
|
className: "text-sm font-medium text-primary underline underline-offset-2 hover:no-underline",
|
|
@@ -283,7 +461,7 @@ function isLocalFsPath(value) {
|
|
|
283
461
|
}
|
|
284
462
|
|
|
285
463
|
// src/components/doc/DocSection.tsx
|
|
286
|
-
var
|
|
464
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
287
465
|
function neutralizeUrl(value) {
|
|
288
466
|
return safeUrl(value) ?? "#";
|
|
289
467
|
}
|
|
@@ -294,12 +472,12 @@ function safeMarkdownHtml(markdown) {
|
|
|
294
472
|
function DocSection({ entry }) {
|
|
295
473
|
const renderers = useBuiltinRenderers();
|
|
296
474
|
if (renderers.section) {
|
|
297
|
-
return /* @__PURE__ */ (0,
|
|
475
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children: renderers.section(entry) });
|
|
298
476
|
}
|
|
299
477
|
const html = safeMarkdownHtml(entry.markdown);
|
|
300
|
-
return /* @__PURE__ */ (0,
|
|
301
|
-
entry.title ? /* @__PURE__ */ (0,
|
|
302
|
-
/* @__PURE__ */ (0,
|
|
478
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("section", { className: "my-3 text-sm", "aria-label": entry.title, children: [
|
|
479
|
+
entry.title ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h4", { className: "mb-1 font-semibold text-foreground", children: entry.title }) : null,
|
|
480
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
303
481
|
"div",
|
|
304
482
|
{
|
|
305
483
|
className: "es-doc-prose prose prose-sm max-w-none",
|
|
@@ -310,11 +488,11 @@ function DocSection({ entry }) {
|
|
|
310
488
|
}
|
|
311
489
|
|
|
312
490
|
// src/components/doc/DocMermaid.tsx
|
|
313
|
-
var
|
|
491
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
314
492
|
function MermaidSource({ entry, ref }) {
|
|
315
|
-
return /* @__PURE__ */ (0,
|
|
316
|
-
entry.title ? /* @__PURE__ */ (0,
|
|
317
|
-
/* @__PURE__ */ (0,
|
|
493
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("figure", { ref, className: "my-3", "aria-label": entry.title ?? "Diagram", children: [
|
|
494
|
+
entry.title ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
|
|
495
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
318
496
|
"pre",
|
|
319
497
|
{
|
|
320
498
|
"data-mermaid": true,
|
|
@@ -328,24 +506,24 @@ function MermaidSource({ entry, ref }) {
|
|
|
328
506
|
function DocMermaid({ entry }) {
|
|
329
507
|
const renderers = useBuiltinRenderers();
|
|
330
508
|
if (renderers.mermaid) {
|
|
331
|
-
return /* @__PURE__ */ (0,
|
|
509
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, { children: renderers.mermaid(entry) });
|
|
332
510
|
}
|
|
333
|
-
return /* @__PURE__ */ (0,
|
|
511
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MermaidSource, { entry });
|
|
334
512
|
}
|
|
335
513
|
|
|
336
514
|
// src/components/doc/DocScreenshot.tsx
|
|
337
|
-
var
|
|
515
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
338
516
|
function DocScreenshot({ entry }) {
|
|
339
517
|
const src = isLocalFsPath(entry.path) ? void 0 : safeImageUrl(entry.path);
|
|
340
518
|
if (!src) {
|
|
341
|
-
return /* @__PURE__ */ (0,
|
|
342
|
-
/* @__PURE__ */ (0,
|
|
343
|
-
/* @__PURE__ */ (0,
|
|
344
|
-
entry.alt ? /* @__PURE__ */ (0,
|
|
519
|
+
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: [
|
|
520
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "font-medium", children: "Screenshot unavailable" }),
|
|
521
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
|
|
522
|
+
entry.alt ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("figcaption", { className: "mt-1.5 text-xs", children: entry.alt }) : null
|
|
345
523
|
] });
|
|
346
524
|
}
|
|
347
|
-
return /* @__PURE__ */ (0,
|
|
348
|
-
/* @__PURE__ */ (0,
|
|
525
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("figure", { className: "my-3", children: [
|
|
526
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
349
527
|
"img",
|
|
350
528
|
{
|
|
351
529
|
src,
|
|
@@ -354,24 +532,24 @@ function DocScreenshot({ entry }) {
|
|
|
354
532
|
className: "max-w-full rounded-md border border-border"
|
|
355
533
|
}
|
|
356
534
|
),
|
|
357
|
-
entry.alt ? /* @__PURE__ */ (0,
|
|
535
|
+
entry.alt ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("figcaption", { className: "mt-1.5 text-xs text-muted-foreground", children: entry.alt }) : null
|
|
358
536
|
] });
|
|
359
537
|
}
|
|
360
538
|
|
|
361
539
|
// src/components/doc/DocVideo.tsx
|
|
362
|
-
var
|
|
540
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
363
541
|
function DocVideo({ entry }) {
|
|
364
542
|
if (isLocalFsPath(entry.path)) {
|
|
365
|
-
return /* @__PURE__ */ (0,
|
|
366
|
-
/* @__PURE__ */ (0,
|
|
367
|
-
/* @__PURE__ */ (0,
|
|
368
|
-
entry.caption ? /* @__PURE__ */ (0,
|
|
543
|
+
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: [
|
|
544
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "font-medium", children: "Video unavailable" }),
|
|
545
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
|
|
546
|
+
entry.caption ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("figcaption", { className: "mt-1.5 text-xs", children: entry.caption }) : null
|
|
369
547
|
] });
|
|
370
548
|
}
|
|
371
549
|
const src = safeUrl(entry.path);
|
|
372
550
|
const poster = safeUrl(entry.poster);
|
|
373
|
-
return /* @__PURE__ */ (0,
|
|
374
|
-
/* @__PURE__ */ (0,
|
|
551
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figure", { className: "my-3", children: [
|
|
552
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
375
553
|
"video",
|
|
376
554
|
{
|
|
377
555
|
controls: true,
|
|
@@ -381,21 +559,21 @@ function DocVideo({ entry }) {
|
|
|
381
559
|
className: "max-w-full rounded-md border border-border"
|
|
382
560
|
}
|
|
383
561
|
),
|
|
384
|
-
entry.caption ? /* @__PURE__ */ (0,
|
|
562
|
+
entry.caption ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: entry.caption }) : null
|
|
385
563
|
] });
|
|
386
564
|
}
|
|
387
565
|
|
|
388
566
|
// src/components/doc/DocHtml.tsx
|
|
389
|
-
var
|
|
567
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
390
568
|
function DocHtml({ entry }) {
|
|
391
569
|
const height = typeof entry.height === "number" ? `${entry.height}px` : entry.height ?? "400px";
|
|
392
570
|
const title = entry.title ?? "Embedded HTML";
|
|
393
571
|
const safeHref = safeUrl(entry.url ?? entry.path);
|
|
394
572
|
const frameProps = entry.content !== void 0 ? { srcDoc: entry.content } : { src: safeHref ?? "" };
|
|
395
|
-
return /* @__PURE__ */ (0,
|
|
396
|
-
/* @__PURE__ */ (0,
|
|
397
|
-
/* @__PURE__ */ (0,
|
|
398
|
-
safeHref ? /* @__PURE__ */ (0,
|
|
573
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("figure", { className: "my-3 overflow-hidden rounded-md border border-border", children: [
|
|
574
|
+
/* @__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: [
|
|
575
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: entry.title ?? "HTML" }),
|
|
576
|
+
safeHref ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
399
577
|
"a",
|
|
400
578
|
{
|
|
401
579
|
href: safeHref,
|
|
@@ -408,7 +586,7 @@ function DocHtml({ entry }) {
|
|
|
408
586
|
}
|
|
409
587
|
) : null
|
|
410
588
|
] }),
|
|
411
|
-
/* @__PURE__ */ (0,
|
|
589
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
412
590
|
"iframe",
|
|
413
591
|
{
|
|
414
592
|
...frameProps,
|
|
@@ -423,7 +601,7 @@ function DocHtml({ entry }) {
|
|
|
423
601
|
}
|
|
424
602
|
|
|
425
603
|
// src/components/doc/DocState.tsx
|
|
426
|
-
var
|
|
604
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
427
605
|
function DocState({ entry }) {
|
|
428
606
|
let json;
|
|
429
607
|
try {
|
|
@@ -431,23 +609,23 @@ function DocState({ entry }) {
|
|
|
431
609
|
} catch {
|
|
432
610
|
json = String(entry.value);
|
|
433
611
|
}
|
|
434
|
-
return /* @__PURE__ */ (0,
|
|
612
|
+
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 }) });
|
|
435
613
|
}
|
|
436
614
|
|
|
437
615
|
// src/components/doc/DocCustom.tsx
|
|
438
|
-
var
|
|
616
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
439
617
|
function DocCustom({ entry }) {
|
|
440
618
|
const renderers = useCustomRenderers();
|
|
441
619
|
const renderer = renderers[entry.type];
|
|
442
620
|
if (renderer) {
|
|
443
|
-
return /* @__PURE__ */ (0,
|
|
621
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children: renderer(entry) });
|
|
444
622
|
}
|
|
445
|
-
return /* @__PURE__ */ (0,
|
|
446
|
-
/* @__PURE__ */ (0,
|
|
447
|
-
/* @__PURE__ */ (0,
|
|
623
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "my-2", "data-type": entry.type, children: [
|
|
624
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: entry.type }),
|
|
625
|
+
/* @__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) })
|
|
448
626
|
] });
|
|
449
627
|
}
|
|
450
|
-
function
|
|
628
|
+
function safeStringify2(value) {
|
|
451
629
|
try {
|
|
452
630
|
return JSON.stringify(value, null, 2);
|
|
453
631
|
} catch {
|
|
@@ -456,47 +634,47 @@ function safeStringify(value) {
|
|
|
456
634
|
}
|
|
457
635
|
|
|
458
636
|
// src/components/doc/DocEntry.tsx
|
|
459
|
-
var
|
|
637
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
460
638
|
function DocEntry({ entry }) {
|
|
461
639
|
switch (entry.kind) {
|
|
462
640
|
case "note":
|
|
463
|
-
return /* @__PURE__ */ (0,
|
|
641
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocNote, { entry });
|
|
464
642
|
case "tag":
|
|
465
|
-
return /* @__PURE__ */ (0,
|
|
643
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocTag, { entry });
|
|
466
644
|
case "kv":
|
|
467
|
-
return /* @__PURE__ */ (0,
|
|
645
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocKv, { entry });
|
|
468
646
|
case "code":
|
|
469
|
-
return /* @__PURE__ */ (0,
|
|
647
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocCode, { entry });
|
|
470
648
|
case "table":
|
|
471
|
-
return /* @__PURE__ */ (0,
|
|
649
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocTable, { entry });
|
|
472
650
|
case "link":
|
|
473
|
-
return /* @__PURE__ */ (0,
|
|
651
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocLink, { entry });
|
|
474
652
|
case "section":
|
|
475
|
-
return /* @__PURE__ */ (0,
|
|
653
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocSection, { entry });
|
|
476
654
|
case "mermaid":
|
|
477
|
-
return /* @__PURE__ */ (0,
|
|
655
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocMermaid, { entry });
|
|
478
656
|
case "screenshot":
|
|
479
|
-
return /* @__PURE__ */ (0,
|
|
657
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocScreenshot, { entry });
|
|
480
658
|
case "video":
|
|
481
|
-
return /* @__PURE__ */ (0,
|
|
659
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocVideo, { entry });
|
|
482
660
|
case "html":
|
|
483
|
-
return /* @__PURE__ */ (0,
|
|
661
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocHtml, { entry });
|
|
484
662
|
case "state":
|
|
485
|
-
return /* @__PURE__ */ (0,
|
|
663
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocState, { entry });
|
|
486
664
|
case "custom":
|
|
487
|
-
return /* @__PURE__ */ (0,
|
|
665
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocCustom, { entry });
|
|
488
666
|
}
|
|
489
667
|
}
|
|
490
668
|
|
|
491
669
|
// src/components/ReportDocEntries.tsx
|
|
492
|
-
var
|
|
670
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
493
671
|
function ReportDocEntries({ entries }) {
|
|
494
672
|
if (entries.length === 0) return null;
|
|
495
|
-
return /* @__PURE__ */ (0,
|
|
673
|
+
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)) });
|
|
496
674
|
}
|
|
497
675
|
|
|
498
676
|
// src/lib/step-params.tsx
|
|
499
|
-
var
|
|
677
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
500
678
|
var STEP_PARAM_PATTERN = /"[^"]*"|(?<![\w.-])\d+(?:\.\d+)?(?![\w.-])/g;
|
|
501
679
|
function highlightStepParams(text) {
|
|
502
680
|
const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));
|
|
@@ -508,7 +686,7 @@ function highlightStepParams(text) {
|
|
|
508
686
|
const end = start + match[0].length;
|
|
509
687
|
if (start > lastIndex) nodes.push(text.slice(lastIndex, start));
|
|
510
688
|
nodes.push(
|
|
511
|
-
/* @__PURE__ */ (0,
|
|
689
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "font-medium text-step-param italic", children: match[0] }, i)
|
|
512
690
|
);
|
|
513
691
|
lastIndex = end;
|
|
514
692
|
});
|
|
@@ -517,7 +695,7 @@ function highlightStepParams(text) {
|
|
|
517
695
|
}
|
|
518
696
|
|
|
519
697
|
// src/components/ReportSteps.tsx
|
|
520
|
-
var
|
|
698
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
521
699
|
var STEP_GLYPH = {
|
|
522
700
|
passed: "\u2713",
|
|
523
701
|
failed: "\u2717",
|
|
@@ -532,21 +710,21 @@ var STEP_GLYPH_COLOR = {
|
|
|
532
710
|
};
|
|
533
711
|
function ReportSteps({ scenario }) {
|
|
534
712
|
if (scenario.steps.length === 0) return null;
|
|
535
|
-
return /* @__PURE__ */ (0,
|
|
713
|
+
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)) });
|
|
536
714
|
}
|
|
537
715
|
function ReportStepItem({ step }) {
|
|
538
716
|
const kw = step.keyword.toLowerCase();
|
|
539
717
|
const continuation = kw === "and" || kw === "but";
|
|
540
|
-
return /* @__PURE__ */ (0,
|
|
718
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
541
719
|
"li",
|
|
542
720
|
{
|
|
543
721
|
id: step.id,
|
|
544
722
|
"data-status": step.status,
|
|
545
723
|
className: cn("py-1.5 text-[0.8125rem] leading-normal", continuation && "pl-5"),
|
|
546
724
|
children: [
|
|
547
|
-
/* @__PURE__ */ (0,
|
|
548
|
-
/* @__PURE__ */ (0,
|
|
549
|
-
/* @__PURE__ */ (0,
|
|
725
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-baseline gap-2", children: [
|
|
726
|
+
/* @__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" }),
|
|
727
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
550
728
|
"span",
|
|
551
729
|
{
|
|
552
730
|
className: cn(
|
|
@@ -556,10 +734,10 @@ function ReportStepItem({ step }) {
|
|
|
556
734
|
children: step.keyword
|
|
557
735
|
}
|
|
558
736
|
),
|
|
559
|
-
/* @__PURE__ */ (0,
|
|
560
|
-
step.durationMs > 0 ? /* @__PURE__ */ (0,
|
|
737
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
|
|
738
|
+
step.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(step.durationMs) }) : null
|
|
561
739
|
] }),
|
|
562
|
-
step.errorMessage ? /* @__PURE__ */ (0,
|
|
740
|
+
step.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
563
741
|
"pre",
|
|
564
742
|
{
|
|
565
743
|
role: "alert",
|
|
@@ -567,7 +745,7 @@ function ReportStepItem({ step }) {
|
|
|
567
745
|
children: step.errorMessage
|
|
568
746
|
}
|
|
569
747
|
) : null,
|
|
570
|
-
step.docEntries.length > 0 ? /* @__PURE__ */ (0,
|
|
748
|
+
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
|
|
571
749
|
]
|
|
572
750
|
}
|
|
573
751
|
);
|
|
@@ -692,7 +870,7 @@ function extractStoryboardFrames(scenario) {
|
|
|
692
870
|
}
|
|
693
871
|
|
|
694
872
|
// src/components/ReportStoryboard.tsx
|
|
695
|
-
var
|
|
873
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
696
874
|
var FRAME_GLYPH = {
|
|
697
875
|
passed: "\u2713",
|
|
698
876
|
failed: "\u2717",
|
|
@@ -708,32 +886,32 @@ var FRAME_GLYPH_COLOR = {
|
|
|
708
886
|
function ReportStoryboard({ scenario }) {
|
|
709
887
|
const frames = extractStoryboardFrames(scenario);
|
|
710
888
|
if (frames.length < 2) return null;
|
|
711
|
-
return /* @__PURE__ */ (0,
|
|
712
|
-
/* @__PURE__ */ (0,
|
|
713
|
-
/* @__PURE__ */ (0,
|
|
889
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("section", { "data-slot": "storyboard", "aria-label": "Storyboard", className: "mb-3", children: [
|
|
890
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h4", { className: "mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Storyboard" }),
|
|
891
|
+
/* @__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)) })
|
|
714
892
|
] });
|
|
715
893
|
}
|
|
716
894
|
function StoryboardFrameItem({ frame }) {
|
|
717
895
|
const label = `${frame.keyword} ${frame.text}`;
|
|
718
896
|
const hasStates = frame.states.length > 0;
|
|
719
|
-
const caption = /* @__PURE__ */ (0,
|
|
720
|
-
/* @__PURE__ */ (0,
|
|
721
|
-
/* @__PURE__ */ (0,
|
|
722
|
-
/* @__PURE__ */ (0,
|
|
897
|
+
const caption = /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("p", { className: "mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug", children: [
|
|
898
|
+
/* @__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" }),
|
|
899
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "min-w-0", children: [
|
|
900
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "font-mono font-semibold text-keyword", children: frame.keyword }),
|
|
723
901
|
" ",
|
|
724
|
-
/* @__PURE__ */ (0,
|
|
902
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-muted-foreground", children: frame.screenshot?.alt ?? frame.text })
|
|
725
903
|
] })
|
|
726
904
|
] });
|
|
727
905
|
return (
|
|
728
906
|
// State cards need room for diff rows; screenshot-only frames keep the
|
|
729
907
|
// original narrow film-cell width (and DOM) unchanged.
|
|
730
|
-
/* @__PURE__ */ (0,
|
|
731
|
-
frame.screenshot ? /* @__PURE__ */ (0,
|
|
732
|
-
hasStates ? /* @__PURE__ */ (0,
|
|
908
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("li", { className: cn("shrink-0", hasStates ? "w-64" : "w-40"), children: [
|
|
909
|
+
frame.screenshot ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(FrameScreenshot, { frame, label }) : null,
|
|
910
|
+
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,
|
|
733
911
|
frame.screenshot ? caption : (
|
|
734
912
|
// No screenshot means no image anchor, so the caption carries the
|
|
735
913
|
// jump-to-step link instead.
|
|
736
|
-
/* @__PURE__ */ (0,
|
|
914
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("a", { href: `#${frame.stepId}`, "aria-label": `Jump to step: ${label}`, className: "block hover:underline", children: caption })
|
|
737
915
|
)
|
|
738
916
|
] })
|
|
739
917
|
);
|
|
@@ -741,13 +919,13 @@ function StoryboardFrameItem({ frame }) {
|
|
|
741
919
|
function FrameScreenshot({ frame, label }) {
|
|
742
920
|
const path = frame.screenshot?.path ?? "";
|
|
743
921
|
const src = isLocalFsPath(path) ? void 0 : safeImageUrl(path);
|
|
744
|
-
return /* @__PURE__ */ (0,
|
|
922
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
745
923
|
"a",
|
|
746
924
|
{
|
|
747
925
|
href: `#${frame.stepId}`,
|
|
748
926
|
"aria-label": `Jump to step: ${label}`,
|
|
749
927
|
className: "block overflow-hidden rounded-md border border-border transition-colors hover:border-ring",
|
|
750
|
-
children: src ? /* @__PURE__ */ (0,
|
|
928
|
+
children: src ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
751
929
|
"img",
|
|
752
930
|
{
|
|
753
931
|
src,
|
|
@@ -755,7 +933,7 @@ function FrameScreenshot({ frame, label }) {
|
|
|
755
933
|
loading: "lazy",
|
|
756
934
|
className: "h-24 w-full bg-muted object-cover object-top"
|
|
757
935
|
}
|
|
758
|
-
) : /* @__PURE__ */ (0,
|
|
936
|
+
) : /* @__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" })
|
|
759
937
|
}
|
|
760
938
|
);
|
|
761
939
|
}
|
|
@@ -774,12 +952,12 @@ function prettyJson(value) {
|
|
|
774
952
|
function StateCardView({ card }) {
|
|
775
953
|
const json = prettyJson(card.value);
|
|
776
954
|
const firstCapture = card.changes === void 0;
|
|
777
|
-
return /* @__PURE__ */ (0,
|
|
778
|
-
/* @__PURE__ */ (0,
|
|
779
|
-
/* @__PURE__ */ (0,
|
|
780
|
-
firstCapture ? /* @__PURE__ */ (0,
|
|
955
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { "data-slot": "state-card", className: "rounded-md border border-border bg-card p-2", children: [
|
|
956
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("p", { className: "flex flex-wrap items-baseline gap-1.5", children: [
|
|
957
|
+
/* @__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" }),
|
|
958
|
+
firstCapture ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-[0.625rem] text-muted-foreground italic", children: "first capture" }) : null
|
|
781
959
|
] }),
|
|
782
|
-
!firstCapture && (card.changes && card.changes.length > 0 ? /* @__PURE__ */ (0,
|
|
960
|
+
!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)(
|
|
783
961
|
"li",
|
|
784
962
|
{
|
|
785
963
|
className: cn(
|
|
@@ -789,15 +967,15 @@ function StateCardView({ card }) {
|
|
|
789
967
|
children: summarizeStateChanges([change])[0]
|
|
790
968
|
},
|
|
791
969
|
i
|
|
792
|
-
)) }) : /* @__PURE__ */ (0,
|
|
793
|
-
/* @__PURE__ */ (0,
|
|
970
|
+
)) }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "mt-1.5 text-[0.625rem] text-muted-foreground", children: "No changes" })),
|
|
971
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
794
972
|
"details",
|
|
795
973
|
{
|
|
796
974
|
open: firstCapture && json.length <= 240,
|
|
797
975
|
className: cn(firstCapture ? "mt-1.5" : "mt-1"),
|
|
798
976
|
children: [
|
|
799
|
-
/* @__PURE__ */ (0,
|
|
800
|
-
/* @__PURE__ */ (0,
|
|
977
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("summary", { className: "cursor-pointer text-[0.625rem] text-muted-foreground hover:text-foreground", children: "Snapshot" }),
|
|
978
|
+
/* @__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 })
|
|
801
979
|
]
|
|
802
980
|
}
|
|
803
981
|
)
|
|
@@ -805,17 +983,17 @@ function StateCardView({ card }) {
|
|
|
805
983
|
}
|
|
806
984
|
|
|
807
985
|
// src/components/ReportAttachments.tsx
|
|
808
|
-
var
|
|
986
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
809
987
|
function ReportAttachments({ attachments }) {
|
|
810
988
|
if (attachments.length === 0) return null;
|
|
811
989
|
return (
|
|
812
990
|
// role="group" (not a labelled <section>) so multiple scenarios' attachment
|
|
813
991
|
// blocks don't create duplicate "Attachments" region landmarks.
|
|
814
|
-
/* @__PURE__ */ (0,
|
|
992
|
+
/* @__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) => {
|
|
815
993
|
const dataUri = att.contentEncoding === "BASE64" ? `data:${att.mediaType};base64,${att.body}` : `data:${att.mediaType},${encodeURIComponent(att.body)}`;
|
|
816
994
|
const isImage = att.mediaType.startsWith("image/");
|
|
817
|
-
return /* @__PURE__ */ (0,
|
|
818
|
-
/* @__PURE__ */ (0,
|
|
995
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
|
|
996
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
819
997
|
"img",
|
|
820
998
|
{
|
|
821
999
|
src: dataUri,
|
|
@@ -824,8 +1002,8 @@ function ReportAttachments({ attachments }) {
|
|
|
824
1002
|
className: "max-w-full rounded-md border border-border"
|
|
825
1003
|
}
|
|
826
1004
|
),
|
|
827
|
-
/* @__PURE__ */ (0,
|
|
828
|
-
] }) : /* @__PURE__ */ (0,
|
|
1005
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
|
|
1006
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
829
1007
|
"a",
|
|
830
1008
|
{
|
|
831
1009
|
href: dataUri,
|
|
@@ -834,7 +1012,7 @@ function ReportAttachments({ attachments }) {
|
|
|
834
1012
|
children: [
|
|
835
1013
|
att.name,
|
|
836
1014
|
" ",
|
|
837
|
-
/* @__PURE__ */ (0,
|
|
1015
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "text-muted-foreground", children: [
|
|
838
1016
|
"(",
|
|
839
1017
|
att.mediaType,
|
|
840
1018
|
")"
|
|
@@ -922,7 +1100,7 @@ function traceWindow(rows) {
|
|
|
922
1100
|
}
|
|
923
1101
|
|
|
924
1102
|
// src/components/ReportTrace.tsx
|
|
925
|
-
var
|
|
1103
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
926
1104
|
var BAR_COLOR = {
|
|
927
1105
|
ok: "bg-pass",
|
|
928
1106
|
error: "bg-fail",
|
|
@@ -933,8 +1111,8 @@ function ReportTrace({ spans }) {
|
|
|
933
1111
|
const rows = toTraceRows(spans);
|
|
934
1112
|
if (rows.length === 0) return null;
|
|
935
1113
|
const { minStartMs, totalMs } = traceWindow(rows);
|
|
936
|
-
return /* @__PURE__ */ (0,
|
|
937
|
-
/* @__PURE__ */ (0,
|
|
1114
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("details", { className: "mt-3 rounded-md border border-border bg-muted/30", children: [
|
|
1115
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("summary", { className: "cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground", children: [
|
|
938
1116
|
"Trace (",
|
|
939
1117
|
rows.length,
|
|
940
1118
|
" span",
|
|
@@ -943,11 +1121,11 @@ function ReportTrace({ spans }) {
|
|
|
943
1121
|
formatDuration(totalMs),
|
|
944
1122
|
")"
|
|
945
1123
|
] }),
|
|
946
|
-
/* @__PURE__ */ (0,
|
|
1124
|
+
/* @__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) => {
|
|
947
1125
|
const leftPct = (row.startTimeMs - minStartMs) / totalMs * 100;
|
|
948
1126
|
const widthPct = Math.max(row.durationMs / totalMs * 100, 0.5);
|
|
949
|
-
return /* @__PURE__ */ (0,
|
|
950
|
-
/* @__PURE__ */ (0,
|
|
1127
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("li", { className: "flex items-center gap-2", children: [
|
|
1128
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
951
1129
|
"span",
|
|
952
1130
|
{
|
|
953
1131
|
className: "min-w-0 flex-1 truncate text-foreground",
|
|
@@ -956,14 +1134,14 @@ function ReportTrace({ spans }) {
|
|
|
956
1134
|
children: row.name
|
|
957
1135
|
}
|
|
958
1136
|
),
|
|
959
|
-
/* @__PURE__ */ (0,
|
|
1137
|
+
/* @__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)(
|
|
960
1138
|
"span",
|
|
961
1139
|
{
|
|
962
1140
|
className: cn("absolute top-0 h-full rounded-sm", BAR_COLOR[row.status]),
|
|
963
1141
|
style: { left: `${leftPct}%`, width: `${widthPct}%` }
|
|
964
1142
|
}
|
|
965
1143
|
) }),
|
|
966
|
-
/* @__PURE__ */ (0,
|
|
1144
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
|
|
967
1145
|
] }, `${row.spanId}-${i}`);
|
|
968
1146
|
}) })
|
|
969
1147
|
] });
|
|
@@ -1012,11 +1190,11 @@ function flakinessOf(entries) {
|
|
|
1012
1190
|
if (transitionScore > 0.2 || failureRate > 0.3) return "unstable";
|
|
1013
1191
|
return "stable";
|
|
1014
1192
|
}
|
|
1015
|
-
function diffSinceLastRun(
|
|
1193
|
+
function diffSinceLastRun(history, scenarios) {
|
|
1016
1194
|
let hasPreviousRun = false;
|
|
1017
1195
|
const delta = { newlyFailing: [], newlyPassing: [], added: [] };
|
|
1018
1196
|
for (const scenario of scenarios) {
|
|
1019
|
-
const entries =
|
|
1197
|
+
const entries = history[scenario.id];
|
|
1020
1198
|
if (!entries || entries.length === 0) continue;
|
|
1021
1199
|
const last = entries[entries.length - 1];
|
|
1022
1200
|
const prev = entries[entries.length - 2];
|
|
@@ -1032,7 +1210,7 @@ function diffSinceLastRun(history2, scenarios) {
|
|
|
1032
1210
|
}
|
|
1033
1211
|
|
|
1034
1212
|
// src/components/ScenarioRunHistory.tsx
|
|
1035
|
-
var
|
|
1213
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
1036
1214
|
var MAX_DOTS = 10;
|
|
1037
1215
|
var DOT_COLOR = {
|
|
1038
1216
|
passed: "bg-pass",
|
|
@@ -1046,22 +1224,22 @@ function dotTitle(e) {
|
|
|
1046
1224
|
return parts.join(" \xB7 ");
|
|
1047
1225
|
}
|
|
1048
1226
|
function ScenarioRunHistory({ scenarioId }) {
|
|
1049
|
-
const
|
|
1050
|
-
const entries =
|
|
1227
|
+
const history = useScenarioHistory();
|
|
1228
|
+
const entries = history?.[scenarioId];
|
|
1051
1229
|
if (!entries || entries.length < 2) return null;
|
|
1052
1230
|
const recent = entries.slice(-MAX_DOTS);
|
|
1053
1231
|
const flaky = flakinessOf(recent) === "flaky";
|
|
1054
1232
|
const summary = flaky ? `${describeRunHistory(recent)} \xB7 Flaky` : describeRunHistory(recent);
|
|
1055
|
-
return /* @__PURE__ */ (0,
|
|
1056
|
-
flaky ? /* @__PURE__ */ (0,
|
|
1057
|
-
/* @__PURE__ */ (0,
|
|
1233
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
|
|
1234
|
+
flaky ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
|
|
1235
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
1058
1236
|
"span",
|
|
1059
1237
|
{
|
|
1060
1238
|
role: "img",
|
|
1061
1239
|
"aria-label": `Run history: ${summary}`,
|
|
1062
1240
|
title: summary,
|
|
1063
1241
|
className: "flex shrink-0 items-center gap-[3px]",
|
|
1064
|
-
children: recent.map((e, i) => /* @__PURE__ */ (0,
|
|
1242
|
+
children: recent.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
1065
1243
|
"span",
|
|
1066
1244
|
{
|
|
1067
1245
|
"aria-hidden": true,
|
|
@@ -1290,9 +1468,9 @@ function scenarioPermalink(scenario) {
|
|
|
1290
1468
|
|
|
1291
1469
|
// src/components/ui/card.tsx
|
|
1292
1470
|
var React2 = require("react");
|
|
1293
|
-
var
|
|
1471
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
1294
1472
|
function Card({ className, ...props }) {
|
|
1295
|
-
return /* @__PURE__ */ (0,
|
|
1473
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1296
1474
|
"div",
|
|
1297
1475
|
{
|
|
1298
1476
|
"data-slot": "card",
|
|
@@ -1305,7 +1483,7 @@ function Card({ className, ...props }) {
|
|
|
1305
1483
|
);
|
|
1306
1484
|
}
|
|
1307
1485
|
function CardHeader({ className, ...props }) {
|
|
1308
|
-
return /* @__PURE__ */ (0,
|
|
1486
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1309
1487
|
"div",
|
|
1310
1488
|
{
|
|
1311
1489
|
"data-slot": "card-header",
|
|
@@ -1318,7 +1496,7 @@ function CardHeader({ className, ...props }) {
|
|
|
1318
1496
|
);
|
|
1319
1497
|
}
|
|
1320
1498
|
function CardContent({ className, ...props }) {
|
|
1321
|
-
return /* @__PURE__ */ (0,
|
|
1499
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1322
1500
|
"div",
|
|
1323
1501
|
{
|
|
1324
1502
|
"data-slot": "card-content",
|
|
@@ -1332,13 +1510,13 @@ function CardContent({ className, ...props }) {
|
|
|
1332
1510
|
var React3 = require("react");
|
|
1333
1511
|
var import_menu = require("@base-ui/react/menu");
|
|
1334
1512
|
var import_lucide_react = require("lucide-react");
|
|
1335
|
-
var
|
|
1513
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1336
1514
|
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";
|
|
1337
1515
|
function DropdownMenu(props) {
|
|
1338
|
-
return /* @__PURE__ */ (0,
|
|
1516
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_menu.Menu.Root, { "data-slot": "dropdown-menu", ...props });
|
|
1339
1517
|
}
|
|
1340
1518
|
function DropdownMenuTrigger(props) {
|
|
1341
|
-
return /* @__PURE__ */ (0,
|
|
1519
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_menu.Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
|
|
1342
1520
|
}
|
|
1343
1521
|
function DropdownMenuContent({
|
|
1344
1522
|
className,
|
|
@@ -1346,14 +1524,14 @@ function DropdownMenuContent({
|
|
|
1346
1524
|
sideOffset = 4,
|
|
1347
1525
|
...props
|
|
1348
1526
|
}) {
|
|
1349
|
-
return /* @__PURE__ */ (0,
|
|
1527
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_menu.Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1350
1528
|
import_menu.Menu.Positioner,
|
|
1351
1529
|
{
|
|
1352
1530
|
"data-slot": "dropdown-menu-positioner",
|
|
1353
1531
|
className: "z-50",
|
|
1354
1532
|
align,
|
|
1355
1533
|
sideOffset,
|
|
1356
|
-
children: /* @__PURE__ */ (0,
|
|
1534
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1357
1535
|
import_menu.Menu.Popup,
|
|
1358
1536
|
{
|
|
1359
1537
|
"data-slot": "dropdown-menu-content",
|
|
@@ -1371,7 +1549,7 @@ function DropdownMenuItem({
|
|
|
1371
1549
|
className,
|
|
1372
1550
|
...props
|
|
1373
1551
|
}) {
|
|
1374
|
-
return /* @__PURE__ */ (0,
|
|
1552
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1375
1553
|
import_menu.Menu.Item,
|
|
1376
1554
|
{
|
|
1377
1555
|
"data-slot": "dropdown-menu-item",
|
|
@@ -1383,7 +1561,7 @@ function DropdownMenuItem({
|
|
|
1383
1561
|
|
|
1384
1562
|
// src/components/ReportScenario.tsx
|
|
1385
1563
|
var import_lucide_react2 = require("lucide-react");
|
|
1386
|
-
var
|
|
1564
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1387
1565
|
var STATUS_META = {
|
|
1388
1566
|
passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
|
|
1389
1567
|
failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
|
|
@@ -1399,7 +1577,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1399
1577
|
const collapsible = collapse !== null && !hideTitle;
|
|
1400
1578
|
const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
|
|
1401
1579
|
const actions = useScenarioActions();
|
|
1402
|
-
return /* @__PURE__ */ (0,
|
|
1580
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
1403
1581
|
Card,
|
|
1404
1582
|
{
|
|
1405
1583
|
id: scenario.id,
|
|
@@ -1407,10 +1585,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1407
1585
|
...hideTitle ? { "aria-label": `${scenario.title}, ${label}` } : { "aria-labelledby": titleId },
|
|
1408
1586
|
className: "gap-0 py-0",
|
|
1409
1587
|
children: [
|
|
1410
|
-
/* @__PURE__ */ (0,
|
|
1411
|
-
/* @__PURE__ */ (0,
|
|
1412
|
-
hideTitle ? null : /* @__PURE__ */ (0,
|
|
1413
|
-
collapsible ? /* @__PURE__ */ (0,
|
|
1588
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(CardHeader, { className: "px-4 py-3", children: [
|
|
1589
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
|
|
1590
|
+
hideTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
|
|
1591
|
+
collapsible ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1414
1592
|
"button",
|
|
1415
1593
|
{
|
|
1416
1594
|
type: "button",
|
|
@@ -1419,49 +1597,49 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1419
1597
|
"aria-controls": bodyId,
|
|
1420
1598
|
"aria-label": `Toggle ${scenario.title}`,
|
|
1421
1599
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
1422
|
-
children: /* @__PURE__ */ (0,
|
|
1600
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
1423
1601
|
}
|
|
1424
1602
|
) : null,
|
|
1425
|
-
/* @__PURE__ */ (0,
|
|
1426
|
-
/* @__PURE__ */ (0,
|
|
1603
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
|
|
1604
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: scenario.title })
|
|
1427
1605
|
] }),
|
|
1428
|
-
/* @__PURE__ */ (0,
|
|
1429
|
-
/* @__PURE__ */ (0,
|
|
1430
|
-
scenario.durationMs > 0 ? /* @__PURE__ */ (0,
|
|
1431
|
-
meta.showPill ? /* @__PURE__ */ (0,
|
|
1432
|
-
actions ? /* @__PURE__ */ (0,
|
|
1433
|
-
/* @__PURE__ */ (0,
|
|
1606
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
1607
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ScenarioRunHistory, { scenarioId: scenario.id }),
|
|
1608
|
+
scenario.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
|
|
1609
|
+
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}` }),
|
|
1610
|
+
actions ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DropdownMenu, { children: [
|
|
1611
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1434
1612
|
DropdownMenuTrigger,
|
|
1435
1613
|
{
|
|
1436
1614
|
"aria-label": `Actions for ${scenario.title}`,
|
|
1437
1615
|
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
1438
|
-
children: /* @__PURE__ */ (0,
|
|
1616
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react2.MoreHorizontalIcon, { "aria-hidden": true })
|
|
1439
1617
|
}
|
|
1440
1618
|
),
|
|
1441
|
-
/* @__PURE__ */ (0,
|
|
1442
|
-
/* @__PURE__ */ (0,
|
|
1443
|
-
/* @__PURE__ */ (0,
|
|
1619
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DropdownMenuContent, { align: "end", children: [
|
|
1620
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
|
|
1621
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react2.LinkIcon, {}),
|
|
1444
1622
|
" Copy link"
|
|
1445
1623
|
] }),
|
|
1446
|
-
/* @__PURE__ */ (0,
|
|
1447
|
-
/* @__PURE__ */ (0,
|
|
1624
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
|
|
1625
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react2.FileTextIcon, {}),
|
|
1448
1626
|
" Copy as Markdown"
|
|
1449
1627
|
] }),
|
|
1450
|
-
/* @__PURE__ */ (0,
|
|
1451
|
-
/* @__PURE__ */ (0,
|
|
1628
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
|
|
1629
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react2.SparklesIcon, {}),
|
|
1452
1630
|
" Explain with AI"
|
|
1453
1631
|
] })
|
|
1454
1632
|
] })
|
|
1455
1633
|
] }) : null
|
|
1456
1634
|
] })
|
|
1457
1635
|
] }),
|
|
1458
|
-
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0,
|
|
1459
|
-
scenario.tags.map((t) => /* @__PURE__ */ (0,
|
|
1460
|
-
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0,
|
|
1636
|
+
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: [
|
|
1637
|
+
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}`)),
|
|
1638
|
+
(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}`))
|
|
1461
1639
|
] }) : null
|
|
1462
1640
|
] }),
|
|
1463
|
-
/* @__PURE__ */ (0,
|
|
1464
|
-
scenario.errorMessage ? /* @__PURE__ */ (0,
|
|
1641
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
|
|
1642
|
+
scenario.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1465
1643
|
"pre",
|
|
1466
1644
|
{
|
|
1467
1645
|
role: "alert",
|
|
@@ -1469,11 +1647,11 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1469
1647
|
children: scenario.errorMessage
|
|
1470
1648
|
}
|
|
1471
1649
|
) : null,
|
|
1472
|
-
/* @__PURE__ */ (0,
|
|
1473
|
-
/* @__PURE__ */ (0,
|
|
1474
|
-
scenario.docEntries.length > 0 ? /* @__PURE__ */ (0,
|
|
1475
|
-
/* @__PURE__ */ (0,
|
|
1476
|
-
/* @__PURE__ */ (0,
|
|
1650
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportStoryboard, { scenario }),
|
|
1651
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportSteps, { scenario }),
|
|
1652
|
+
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,
|
|
1653
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportAttachments, { attachments: scenario.attachments }),
|
|
1654
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportTrace, { spans: scenario.otelSpans })
|
|
1477
1655
|
] })
|
|
1478
1656
|
]
|
|
1479
1657
|
}
|
|
@@ -1481,13 +1659,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1481
1659
|
}
|
|
1482
1660
|
|
|
1483
1661
|
// src/components/ReportScenarioList.tsx
|
|
1484
|
-
var
|
|
1662
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1485
1663
|
function ReportScenarioList({ feature }) {
|
|
1486
|
-
return /* @__PURE__ */ (0,
|
|
1664
|
+
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)) });
|
|
1487
1665
|
}
|
|
1488
1666
|
|
|
1489
1667
|
// src/components/ReportFeature.tsx
|
|
1490
|
-
var
|
|
1668
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1491
1669
|
function ReportFeature({ feature }) {
|
|
1492
1670
|
const titleId = `${feature.id}-title`;
|
|
1493
1671
|
const bodyId = `${feature.id}-body`;
|
|
@@ -1498,7 +1676,7 @@ function ReportFeature({ feature }) {
|
|
|
1498
1676
|
return (
|
|
1499
1677
|
// Suite = a section heading + a divider, NOT another bordered card. Drops a
|
|
1500
1678
|
// layer of nesting so the scenario cards below read as the primary unit.
|
|
1501
|
-
/* @__PURE__ */ (0,
|
|
1679
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
1502
1680
|
"section",
|
|
1503
1681
|
{
|
|
1504
1682
|
id: feature.id,
|
|
@@ -1506,9 +1684,9 @@ function ReportFeature({ feature }) {
|
|
|
1506
1684
|
"aria-labelledby": titleId,
|
|
1507
1685
|
className: "flex flex-col gap-3",
|
|
1508
1686
|
children: [
|
|
1509
|
-
/* @__PURE__ */ (0,
|
|
1510
|
-
/* @__PURE__ */ (0,
|
|
1511
|
-
/* @__PURE__ */ (0,
|
|
1687
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
|
|
1688
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "min-w-0", children: [
|
|
1689
|
+
/* @__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)(
|
|
1512
1690
|
"button",
|
|
1513
1691
|
{
|
|
1514
1692
|
type: "button",
|
|
@@ -1517,31 +1695,31 @@ function ReportFeature({ feature }) {
|
|
|
1517
1695
|
"aria-controls": bodyId,
|
|
1518
1696
|
className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
|
|
1519
1697
|
children: [
|
|
1520
|
-
/* @__PURE__ */ (0,
|
|
1521
|
-
/* @__PURE__ */ (0,
|
|
1698
|
+
/* @__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" }),
|
|
1699
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "truncate", children: feature.title })
|
|
1522
1700
|
]
|
|
1523
1701
|
}
|
|
1524
1702
|
) : feature.title }),
|
|
1525
|
-
/* @__PURE__ */ (0,
|
|
1703
|
+
/* @__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 })
|
|
1526
1704
|
] }),
|
|
1527
|
-
/* @__PURE__ */ (0,
|
|
1705
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
1528
1706
|
"p",
|
|
1529
1707
|
{
|
|
1530
1708
|
className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
|
|
1531
1709
|
"aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
|
|
1532
1710
|
children: [
|
|
1533
|
-
/* @__PURE__ */ (0,
|
|
1711
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { children: [
|
|
1534
1712
|
s.passed,
|
|
1535
1713
|
" passed"
|
|
1536
1714
|
] }),
|
|
1537
|
-
/* @__PURE__ */ (0,
|
|
1538
|
-
/* @__PURE__ */ (0,
|
|
1715
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1716
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
|
|
1539
1717
|
s.failed,
|
|
1540
1718
|
" failed"
|
|
1541
1719
|
] }),
|
|
1542
|
-
skipped > 0 ? /* @__PURE__ */ (0,
|
|
1543
|
-
/* @__PURE__ */ (0,
|
|
1544
|
-
/* @__PURE__ */ (0,
|
|
1720
|
+
skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
|
|
1721
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1722
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { children: [
|
|
1545
1723
|
skipped,
|
|
1546
1724
|
" skipped"
|
|
1547
1725
|
] })
|
|
@@ -1550,7 +1728,7 @@ function ReportFeature({ feature }) {
|
|
|
1550
1728
|
}
|
|
1551
1729
|
)
|
|
1552
1730
|
] }),
|
|
1553
|
-
/* @__PURE__ */ (0,
|
|
1731
|
+
/* @__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 }) })
|
|
1554
1732
|
]
|
|
1555
1733
|
}
|
|
1556
1734
|
)
|
|
@@ -1558,17 +1736,17 @@ function ReportFeature({ feature }) {
|
|
|
1558
1736
|
}
|
|
1559
1737
|
|
|
1560
1738
|
// src/components/ReportFeatureList.tsx
|
|
1561
|
-
var
|
|
1739
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
1562
1740
|
function ReportFeatureList() {
|
|
1563
1741
|
const report = useReport();
|
|
1564
|
-
return /* @__PURE__ */ (0,
|
|
1742
|
+
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)) });
|
|
1565
1743
|
}
|
|
1566
1744
|
|
|
1567
1745
|
// src/components/ui/empty.tsx
|
|
1568
1746
|
var import_class_variance_authority2 = require("class-variance-authority");
|
|
1569
|
-
var
|
|
1747
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
1570
1748
|
function Empty({ className, ...props }) {
|
|
1571
|
-
return /* @__PURE__ */ (0,
|
|
1749
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
1572
1750
|
"div",
|
|
1573
1751
|
{
|
|
1574
1752
|
"data-slot": "empty",
|
|
@@ -1581,7 +1759,7 @@ function Empty({ className, ...props }) {
|
|
|
1581
1759
|
);
|
|
1582
1760
|
}
|
|
1583
1761
|
function EmptyHeader({ className, ...props }) {
|
|
1584
|
-
return /* @__PURE__ */ (0,
|
|
1762
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
1585
1763
|
"div",
|
|
1586
1764
|
{
|
|
1587
1765
|
"data-slot": "empty-header",
|
|
@@ -1608,7 +1786,7 @@ var emptyMediaVariants = (0, import_class_variance_authority2.cva)(
|
|
|
1608
1786
|
}
|
|
1609
1787
|
);
|
|
1610
1788
|
function EmptyTitle({ className, ...props }) {
|
|
1611
|
-
return /* @__PURE__ */ (0,
|
|
1789
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
1612
1790
|
"div",
|
|
1613
1791
|
{
|
|
1614
1792
|
"data-slot": "empty-title",
|
|
@@ -1619,16 +1797,16 @@ function EmptyTitle({ className, ...props }) {
|
|
|
1619
1797
|
}
|
|
1620
1798
|
|
|
1621
1799
|
// src/components/ReportEmpty.tsx
|
|
1622
|
-
var
|
|
1800
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
1623
1801
|
function ReportEmpty({ message }) {
|
|
1624
|
-
return /* @__PURE__ */ (0,
|
|
1802
|
+
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." }) }) });
|
|
1625
1803
|
}
|
|
1626
1804
|
|
|
1627
1805
|
// src/components/ReportSummary.tsx
|
|
1628
|
-
var
|
|
1806
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
1629
1807
|
function ReportSummary({ className }) {
|
|
1630
1808
|
const report = useReport();
|
|
1631
|
-
return /* @__PURE__ */ (0,
|
|
1809
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
1632
1810
|
ReportSummaryView,
|
|
1633
1811
|
{
|
|
1634
1812
|
summary: report.summary,
|
|
@@ -1654,7 +1832,7 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1654
1832
|
if (summary.pending > 0) {
|
|
1655
1833
|
cards.push({ status: "pending", label: "Pending", value: summary.pending });
|
|
1656
1834
|
}
|
|
1657
|
-
return /* @__PURE__ */ (0,
|
|
1835
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
1658
1836
|
"dl",
|
|
1659
1837
|
{
|
|
1660
1838
|
className: cn(
|
|
@@ -1667,17 +1845,17 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1667
1845
|
"aria-label": ariaLabel,
|
|
1668
1846
|
children: cards.map((c) => {
|
|
1669
1847
|
const tone = TONE[c.status];
|
|
1670
|
-
return /* @__PURE__ */ (0,
|
|
1848
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
|
|
1671
1849
|
"div",
|
|
1672
1850
|
{
|
|
1673
1851
|
"data-status": c.status,
|
|
1674
1852
|
className: "rounded-lg border bg-card px-4 py-3",
|
|
1675
1853
|
children: [
|
|
1676
|
-
/* @__PURE__ */ (0,
|
|
1677
|
-
/* @__PURE__ */ (0,
|
|
1854
|
+
/* @__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: [
|
|
1855
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
|
|
1678
1856
|
c.label
|
|
1679
1857
|
] }),
|
|
1680
|
-
/* @__PURE__ */ (0,
|
|
1858
|
+
/* @__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 })
|
|
1681
1859
|
]
|
|
1682
1860
|
},
|
|
1683
1861
|
c.status
|
|
@@ -1737,7 +1915,7 @@ function prUrl(ci) {
|
|
|
1737
1915
|
}
|
|
1738
1916
|
|
|
1739
1917
|
// src/components/ReportMeta.tsx
|
|
1740
|
-
var
|
|
1918
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
1741
1919
|
function ReportMeta() {
|
|
1742
1920
|
const report = useReport();
|
|
1743
1921
|
const items = [];
|
|
@@ -1760,13 +1938,13 @@ function ReportMeta() {
|
|
|
1760
1938
|
const short = sha.slice(0, 8);
|
|
1761
1939
|
items.push({
|
|
1762
1940
|
label: "Commit",
|
|
1763
|
-
value: url ? /* @__PURE__ */ (0,
|
|
1941
|
+
value: url ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
|
|
1764
1942
|
});
|
|
1765
1943
|
}
|
|
1766
1944
|
if (report.ci) {
|
|
1767
1945
|
items.push({
|
|
1768
1946
|
label: "CI",
|
|
1769
|
-
value: report.ci.url ? /* @__PURE__ */ (0,
|
|
1947
|
+
value: report.ci.url ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
|
|
1770
1948
|
ciDisplayName(report.ci.name),
|
|
1771
1949
|
report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
|
|
1772
1950
|
] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
|
|
@@ -1777,7 +1955,7 @@ function ReportMeta() {
|
|
|
1777
1955
|
const label = `#${report.ci.prNumber}`;
|
|
1778
1956
|
items.push({
|
|
1779
1957
|
label: "PR",
|
|
1780
|
-
value: url ? /* @__PURE__ */ (0,
|
|
1958
|
+
value: url ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
|
|
1781
1959
|
});
|
|
1782
1960
|
}
|
|
1783
1961
|
if (items.length === 0) return null;
|
|
@@ -1785,50 +1963,50 @@ function ReportMeta() {
|
|
|
1785
1963
|
// Run metadata is useful but secondary to "what failed" — tuck it into a
|
|
1786
1964
|
// collapsed disclosure so it doesn't push the result down. Native <details>
|
|
1787
1965
|
// so it works with no JS (the SSR/no-hydration report still toggles).
|
|
1788
|
-
/* @__PURE__ */ (0,
|
|
1789
|
-
/* @__PURE__ */ (0,
|
|
1790
|
-
/* @__PURE__ */ (0,
|
|
1966
|
+
/* @__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: [
|
|
1967
|
+
/* @__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: [
|
|
1968
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
|
|
1791
1969
|
"Run details"
|
|
1792
1970
|
] }),
|
|
1793
|
-
/* @__PURE__ */ (0,
|
|
1794
|
-
/* @__PURE__ */ (0,
|
|
1795
|
-
/* @__PURE__ */ (0,
|
|
1971
|
+
/* @__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: [
|
|
1972
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("dt", { className: "font-medium", children: item.label }),
|
|
1973
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("dd", { className: "font-mono text-foreground", children: item.value })
|
|
1796
1974
|
] }, item.label)) })
|
|
1797
1975
|
] })
|
|
1798
1976
|
);
|
|
1799
1977
|
}
|
|
1800
1978
|
|
|
1801
1979
|
// src/components/ReportSchemaError.tsx
|
|
1802
|
-
var
|
|
1980
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
1803
1981
|
function ReportSchemaError({ error }) {
|
|
1804
|
-
return /* @__PURE__ */ (0,
|
|
1805
|
-
/* @__PURE__ */ (0,
|
|
1806
|
-
/* @__PURE__ */ (0,
|
|
1807
|
-
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0,
|
|
1982
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
|
|
1983
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("strong", { children: "Report could not be displayed." }) }),
|
|
1984
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { children: error.message }),
|
|
1985
|
+
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("p", { children: [
|
|
1808
1986
|
"The report bundle is newer than this version of ",
|
|
1809
|
-
/* @__PURE__ */ (0,
|
|
1987
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("code", { children: "executable-stories-react" }),
|
|
1810
1988
|
". Upgrade the package, or regenerate the report with an older formatters CLI."
|
|
1811
1989
|
] }) : null,
|
|
1812
|
-
error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0,
|
|
1813
|
-
/* @__PURE__ */ (0,
|
|
1990
|
+
error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("details", { children: [
|
|
1991
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("summary", { children: [
|
|
1814
1992
|
error.issues.length,
|
|
1815
1993
|
" validation issue",
|
|
1816
1994
|
error.issues.length === 1 ? "" : "s"
|
|
1817
1995
|
] }),
|
|
1818
|
-
/* @__PURE__ */ (0,
|
|
1996
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
|
|
1819
1997
|
] }) : null
|
|
1820
1998
|
] });
|
|
1821
1999
|
}
|
|
1822
2000
|
|
|
1823
2001
|
// src/components/ReportShell.tsx
|
|
1824
|
-
var
|
|
2002
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
1825
2003
|
function ReportErrorShell({
|
|
1826
2004
|
error,
|
|
1827
2005
|
className,
|
|
1828
2006
|
title,
|
|
1829
2007
|
dataTheme
|
|
1830
2008
|
}) {
|
|
1831
|
-
return /* @__PURE__ */ (0,
|
|
2009
|
+
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 }) });
|
|
1832
2010
|
}
|
|
1833
2011
|
|
|
1834
2012
|
// src/interactive/ReportInteractive.tsx
|
|
@@ -1837,12 +2015,12 @@ var import_lucide_react5 = require("lucide-react");
|
|
|
1837
2015
|
// src/components/ui/switch.tsx
|
|
1838
2016
|
var React4 = require("react");
|
|
1839
2017
|
var import_switch = require("@base-ui/react/switch");
|
|
1840
|
-
var
|
|
2018
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
1841
2019
|
function Switch({
|
|
1842
2020
|
className,
|
|
1843
2021
|
...props
|
|
1844
2022
|
}) {
|
|
1845
|
-
return /* @__PURE__ */ (0,
|
|
2023
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
1846
2024
|
import_switch.Switch.Root,
|
|
1847
2025
|
{
|
|
1848
2026
|
"data-slot": "switch",
|
|
@@ -1851,7 +2029,7 @@ function Switch({
|
|
|
1851
2029
|
className
|
|
1852
2030
|
),
|
|
1853
2031
|
...props,
|
|
1854
|
-
children: /* @__PURE__ */ (0,
|
|
2032
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
1855
2033
|
import_switch.Switch.Thumb,
|
|
1856
2034
|
{
|
|
1857
2035
|
"data-slot": "switch-thumb",
|
|
@@ -1867,7 +2045,7 @@ var React5 = __toESM(require("react"), 1);
|
|
|
1867
2045
|
var import_toggle_group = require("@base-ui/react/toggle-group");
|
|
1868
2046
|
var import_toggle = require("@base-ui/react/toggle");
|
|
1869
2047
|
var import_class_variance_authority3 = require("class-variance-authority");
|
|
1870
|
-
var
|
|
2048
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
1871
2049
|
var toggleItemVariants = (0, import_class_variance_authority3.cva)(
|
|
1872
2050
|
"inline-flex items-center justify-center gap-1.5 rounded-md font-medium whitespace-nowrap text-muted-foreground transition-[color,background-color,box-shadow] outline-none hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 data-[pressed]:bg-background data-[pressed]:text-foreground data-[pressed]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
1873
2051
|
{
|
|
@@ -1889,13 +2067,13 @@ function ToggleGroup({
|
|
|
1889
2067
|
children,
|
|
1890
2068
|
...props
|
|
1891
2069
|
}) {
|
|
1892
|
-
return /* @__PURE__ */ (0,
|
|
2070
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
1893
2071
|
import_toggle_group.ToggleGroup,
|
|
1894
2072
|
{
|
|
1895
2073
|
"data-slot": "toggle-group",
|
|
1896
2074
|
className: cn("flex w-fit items-center gap-0.5 rounded-lg bg-muted p-0.5", className),
|
|
1897
2075
|
...props,
|
|
1898
|
-
children: /* @__PURE__ */ (0,
|
|
2076
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ToggleGroupContext.Provider, { value: { size }, children })
|
|
1899
2077
|
}
|
|
1900
2078
|
);
|
|
1901
2079
|
}
|
|
@@ -1906,7 +2084,7 @@ function ToggleGroupItem({
|
|
|
1906
2084
|
...props
|
|
1907
2085
|
}) {
|
|
1908
2086
|
const context = React5.useContext(ToggleGroupContext);
|
|
1909
|
-
return /* @__PURE__ */ (0,
|
|
2087
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
1910
2088
|
import_toggle.Toggle,
|
|
1911
2089
|
{
|
|
1912
2090
|
"data-slot": "toggle-group-item",
|
|
@@ -1923,9 +2101,9 @@ var import_lucide_react3 = require("lucide-react");
|
|
|
1923
2101
|
|
|
1924
2102
|
// src/components/ui/input.tsx
|
|
1925
2103
|
var React6 = require("react");
|
|
1926
|
-
var
|
|
2104
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
1927
2105
|
function Input({ className, type, ...props }) {
|
|
1928
|
-
return /* @__PURE__ */ (0,
|
|
2106
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
1929
2107
|
"input",
|
|
1930
2108
|
{
|
|
1931
2109
|
type,
|
|
@@ -1942,7 +2120,7 @@ function Input({ className, type, ...props }) {
|
|
|
1942
2120
|
}
|
|
1943
2121
|
|
|
1944
2122
|
// src/interactive/ReportSearch.tsx
|
|
1945
|
-
var
|
|
2123
|
+
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
1946
2124
|
var ReportSearch = (0, import_react8.forwardRef)(
|
|
1947
2125
|
function ReportSearch2(props, ref) {
|
|
1948
2126
|
const {
|
|
@@ -1964,17 +2142,17 @@ var ReportSearch = (0, import_react8.forwardRef)(
|
|
|
1964
2142
|
e.preventDefault();
|
|
1965
2143
|
}
|
|
1966
2144
|
}
|
|
1967
|
-
return /* @__PURE__ */ (0,
|
|
1968
|
-
/* @__PURE__ */ (0,
|
|
1969
|
-
/* @__PURE__ */ (0,
|
|
1970
|
-
/* @__PURE__ */ (0,
|
|
2145
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: cn("es-search flex flex-col gap-1", className), children: [
|
|
2146
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("label", { htmlFor: inputId, className: "sr-only", children: "Search" }),
|
|
2147
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "relative w-full sm:w-72", children: [
|
|
2148
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
1971
2149
|
import_lucide_react3.Search,
|
|
1972
2150
|
{
|
|
1973
2151
|
"aria-hidden": true,
|
|
1974
2152
|
className: "pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground"
|
|
1975
2153
|
}
|
|
1976
2154
|
),
|
|
1977
|
-
/* @__PURE__ */ (0,
|
|
2155
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
1978
2156
|
Input,
|
|
1979
2157
|
{
|
|
1980
2158
|
ref,
|
|
@@ -1991,7 +2169,7 @@ var ReportSearch = (0, import_react8.forwardRef)(
|
|
|
1991
2169
|
}
|
|
1992
2170
|
)
|
|
1993
2171
|
] }),
|
|
1994
|
-
showCounts ? /* @__PURE__ */ (0,
|
|
2172
|
+
showCounts ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
|
|
1995
2173
|
"span",
|
|
1996
2174
|
{
|
|
1997
2175
|
className: "text-xs tabular-nums text-muted-foreground",
|
|
@@ -2011,6 +2189,54 @@ var ReportSearch = (0, import_react8.forwardRef)(
|
|
|
2011
2189
|
// src/interactive/ReportFailureBanner.tsx
|
|
2012
2190
|
var import_react9 = require("react");
|
|
2013
2191
|
|
|
2192
|
+
// src/lib/hash-state.ts
|
|
2193
|
+
var DEFAULT_URL_STATE = {
|
|
2194
|
+
query: "",
|
|
2195
|
+
status: "all",
|
|
2196
|
+
tags: [],
|
|
2197
|
+
detail: "full"
|
|
2198
|
+
};
|
|
2199
|
+
var STATUSES = ["all", "passed", "failed", "skipped", "pending"];
|
|
2200
|
+
function splitHash(hash) {
|
|
2201
|
+
const raw = hash.replace(/^#/, "");
|
|
2202
|
+
const split = raw.indexOf("?");
|
|
2203
|
+
if (split === -1) return { anchor: raw, params: new URLSearchParams() };
|
|
2204
|
+
return { anchor: raw.slice(0, split), params: new URLSearchParams(raw.slice(split + 1)) };
|
|
2205
|
+
}
|
|
2206
|
+
function decodeUrlState(params) {
|
|
2207
|
+
const status = params.get("status");
|
|
2208
|
+
const tags = params.get("tags");
|
|
2209
|
+
return {
|
|
2210
|
+
query: params.get("q") ?? DEFAULT_URL_STATE.query,
|
|
2211
|
+
status: STATUSES.includes(status) ? status : DEFAULT_URL_STATE.status,
|
|
2212
|
+
tags: tags ? tags.split(",").filter(Boolean) : [],
|
|
2213
|
+
detail: params.get("docs") === "0" ? "minimal" : "full"
|
|
2214
|
+
};
|
|
2215
|
+
}
|
|
2216
|
+
function encodeUrlState(state) {
|
|
2217
|
+
const params = new URLSearchParams();
|
|
2218
|
+
if (state.query) params.set("q", state.query);
|
|
2219
|
+
if (state.status !== "all") params.set("status", state.status);
|
|
2220
|
+
if (state.tags.length > 0) params.set("tags", state.tags.join(","));
|
|
2221
|
+
if (state.detail === "minimal") params.set("docs", "0");
|
|
2222
|
+
return params.toString();
|
|
2223
|
+
}
|
|
2224
|
+
function formatHash(anchor, params) {
|
|
2225
|
+
if (params) return `#${anchor}?${params}`;
|
|
2226
|
+
return anchor ? `#${anchor}` : "";
|
|
2227
|
+
}
|
|
2228
|
+
function writeHash(anchor, params) {
|
|
2229
|
+
if (typeof window === "undefined") return;
|
|
2230
|
+
const next = formatHash(anchor, params);
|
|
2231
|
+
if (next === window.location.hash) return;
|
|
2232
|
+
const url = next || window.location.href.split("#")[0];
|
|
2233
|
+
try {
|
|
2234
|
+
window.history.replaceState(window.history.state, "", url);
|
|
2235
|
+
} catch {
|
|
2236
|
+
window.location.hash = next.slice(1);
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
|
|
2014
2240
|
// src/lib/scroll.ts
|
|
2015
2241
|
function prefersReducedMotion() {
|
|
2016
2242
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
@@ -2026,13 +2252,13 @@ function scrollToScenarioId(scenarioId, options = {}) {
|
|
|
2026
2252
|
behavior: prefersReducedMotion() ? "auto" : "smooth",
|
|
2027
2253
|
block: "start"
|
|
2028
2254
|
});
|
|
2029
|
-
if (options.updateHash !== false
|
|
2030
|
-
|
|
2255
|
+
if (options.updateHash !== false) {
|
|
2256
|
+
writeHash(scenarioId, splitHash(window.location.hash).params.toString());
|
|
2031
2257
|
}
|
|
2032
2258
|
}
|
|
2033
2259
|
|
|
2034
2260
|
// src/interactive/ReportFailureBanner.tsx
|
|
2035
|
-
var
|
|
2261
|
+
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
2036
2262
|
function ReportFailureBanner({ failures }) {
|
|
2037
2263
|
const first = failures[0];
|
|
2038
2264
|
const jumpToFirst = (0, import_react9.useCallback)(() => {
|
|
@@ -2040,7 +2266,7 @@ function ReportFailureBanner({ failures }) {
|
|
|
2040
2266
|
scrollToScenarioId(first.scenarioId);
|
|
2041
2267
|
}, [first]);
|
|
2042
2268
|
if (failures.length === 0) return null;
|
|
2043
|
-
return /* @__PURE__ */ (0,
|
|
2269
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
|
|
2044
2270
|
"div",
|
|
2045
2271
|
{
|
|
2046
2272
|
className: "es-failure-banner",
|
|
@@ -2048,13 +2274,13 @@ function ReportFailureBanner({ failures }) {
|
|
|
2048
2274
|
"aria-live": "polite",
|
|
2049
2275
|
"aria-label": "Failure summary",
|
|
2050
2276
|
children: [
|
|
2051
|
-
/* @__PURE__ */ (0,
|
|
2052
|
-
/* @__PURE__ */ (0,
|
|
2277
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "es-failure-banner-text", children: [
|
|
2278
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("strong", { children: failures.length }),
|
|
2053
2279
|
" ",
|
|
2054
2280
|
"failure",
|
|
2055
2281
|
failures.length === 1 ? "" : "s"
|
|
2056
2282
|
] }),
|
|
2057
|
-
/* @__PURE__ */ (0,
|
|
2283
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
2058
2284
|
"button",
|
|
2059
2285
|
{
|
|
2060
2286
|
type: "button",
|
|
@@ -2071,7 +2297,7 @@ function ReportFailureBanner({ failures }) {
|
|
|
2071
2297
|
|
|
2072
2298
|
// src/interactive/ReportFreshness.tsx
|
|
2073
2299
|
var import_react10 = require("react");
|
|
2074
|
-
var
|
|
2300
|
+
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
2075
2301
|
function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
2076
2302
|
const [now, setNow] = (0, import_react10.useState)(nowMs);
|
|
2077
2303
|
(0, import_react10.useEffect)(() => {
|
|
@@ -2079,7 +2305,7 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
2079
2305
|
}, [nowMs]);
|
|
2080
2306
|
if (lastRunMs === void 0 || now === void 0) return null;
|
|
2081
2307
|
const age = formatRelativeAge(lastRunMs, now);
|
|
2082
|
-
const runLink = ciUrl ? /* @__PURE__ */ (0,
|
|
2308
|
+
const runLink = ciUrl ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
2083
2309
|
"a",
|
|
2084
2310
|
{
|
|
2085
2311
|
href: ciUrl,
|
|
@@ -2090,9 +2316,9 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
2090
2316
|
}
|
|
2091
2317
|
) : null;
|
|
2092
2318
|
if (isReportStale(lastRunMs, staleAfterDays, now)) {
|
|
2093
|
-
return /* @__PURE__ */ (0,
|
|
2094
|
-
/* @__PURE__ */ (0,
|
|
2095
|
-
/* @__PURE__ */ (0,
|
|
2319
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "es-stale-banner", role: "status", "aria-label": "Report freshness", children: [
|
|
2320
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { children: [
|
|
2321
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("strong", { children: [
|
|
2096
2322
|
"Last verified ",
|
|
2097
2323
|
age,
|
|
2098
2324
|
"."
|
|
@@ -2102,10 +2328,10 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
2102
2328
|
runLink
|
|
2103
2329
|
] });
|
|
2104
2330
|
}
|
|
2105
|
-
return /* @__PURE__ */ (0,
|
|
2331
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("p", { className: "es-freshness", "aria-label": "Report freshness", children: [
|
|
2106
2332
|
"Verified ",
|
|
2107
2333
|
age,
|
|
2108
|
-
runLink ? /* @__PURE__ */ (0,
|
|
2334
|
+
runLink ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
|
|
2109
2335
|
" \xB7 ",
|
|
2110
2336
|
runLink
|
|
2111
2337
|
] }) : null
|
|
@@ -2113,15 +2339,15 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
2113
2339
|
}
|
|
2114
2340
|
|
|
2115
2341
|
// src/interactive/ReportLastRunDelta.tsx
|
|
2116
|
-
var
|
|
2342
|
+
var import_jsx_runtime42 = require("react/jsx-runtime");
|
|
2117
2343
|
var MAX_LINKS = 5;
|
|
2118
2344
|
function ScenarioLinks({ scenarios, tone }) {
|
|
2119
|
-
return /* @__PURE__ */ (0,
|
|
2120
|
-
scenarios.slice(0, MAX_LINKS).map((s, i) => /* @__PURE__ */ (0,
|
|
2345
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
|
|
2346
|
+
scenarios.slice(0, MAX_LINKS).map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { children: [
|
|
2121
2347
|
i > 0 ? ", " : "",
|
|
2122
|
-
/* @__PURE__ */ (0,
|
|
2348
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
|
|
2123
2349
|
] }, s.id)),
|
|
2124
|
-
scenarios.length > MAX_LINKS ? /* @__PURE__ */ (0,
|
|
2350
|
+
scenarios.length > MAX_LINKS ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { children: [
|
|
2125
2351
|
" and ",
|
|
2126
2352
|
scenarios.length - MAX_LINKS,
|
|
2127
2353
|
" more"
|
|
@@ -2129,32 +2355,32 @@ function ScenarioLinks({ scenarios, tone }) {
|
|
|
2129
2355
|
] });
|
|
2130
2356
|
}
|
|
2131
2357
|
function ReportLastRunDelta({
|
|
2132
|
-
history
|
|
2358
|
+
history,
|
|
2133
2359
|
report
|
|
2134
2360
|
}) {
|
|
2135
|
-
if (!
|
|
2361
|
+
if (!history) return null;
|
|
2136
2362
|
const scenarios = report.features.flatMap((f) => f.scenarios.map((s) => ({ id: s.id, title: s.title })));
|
|
2137
|
-
const delta = diffSinceLastRun(
|
|
2363
|
+
const delta = diffSinceLastRun(history, scenarios);
|
|
2138
2364
|
if (!delta) return null;
|
|
2139
2365
|
const { newlyFailing, newlyPassing, added } = delta;
|
|
2140
2366
|
if (newlyFailing.length === 0 && newlyPassing.length === 0 && added.length === 0) {
|
|
2141
|
-
return /* @__PURE__ */ (0,
|
|
2367
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: "Since last run: no behavior changes." });
|
|
2142
2368
|
}
|
|
2143
|
-
return /* @__PURE__ */ (0,
|
|
2144
|
-
/* @__PURE__ */ (0,
|
|
2145
|
-
newlyFailing.length > 0 ? /* @__PURE__ */ (0,
|
|
2369
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: [
|
|
2370
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "font-medium text-foreground", children: "Since last run:" }),
|
|
2371
|
+
newlyFailing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "ml-2 text-fail", children: [
|
|
2146
2372
|
newlyFailing.length,
|
|
2147
2373
|
" newly failing (",
|
|
2148
|
-
/* @__PURE__ */ (0,
|
|
2374
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ScenarioLinks, { scenarios: newlyFailing, tone: "text-fail" }),
|
|
2149
2375
|
")"
|
|
2150
2376
|
] }) : null,
|
|
2151
|
-
newlyPassing.length > 0 ? /* @__PURE__ */ (0,
|
|
2377
|
+
newlyPassing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "ml-2 text-pass", children: [
|
|
2152
2378
|
newlyPassing.length,
|
|
2153
2379
|
" fixed (",
|
|
2154
|
-
/* @__PURE__ */ (0,
|
|
2380
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ScenarioLinks, { scenarios: newlyPassing, tone: "text-pass" }),
|
|
2155
2381
|
")"
|
|
2156
2382
|
] }) : null,
|
|
2157
|
-
added.length > 0 ? /* @__PURE__ */ (0,
|
|
2383
|
+
added.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "ml-2", children: [
|
|
2158
2384
|
added.length,
|
|
2159
2385
|
" new"
|
|
2160
2386
|
] }) : null
|
|
@@ -2218,7 +2444,7 @@ function Button({
|
|
|
2218
2444
|
}
|
|
2219
2445
|
|
|
2220
2446
|
// src/interactive/ReportShortcutsHelp.tsx
|
|
2221
|
-
var
|
|
2447
|
+
var import_jsx_runtime43 = require("react/jsx-runtime");
|
|
2222
2448
|
var SHORTCUTS = [
|
|
2223
2449
|
{ keys: "/", description: "Focus search" },
|
|
2224
2450
|
{ keys: "f", description: "Jump to next failure" },
|
|
@@ -2230,9 +2456,9 @@ var SHORTCUTS = [
|
|
|
2230
2456
|
];
|
|
2231
2457
|
function Keys({ keys }) {
|
|
2232
2458
|
const parts = keys.split(" ");
|
|
2233
|
-
return /* @__PURE__ */ (0,
|
|
2234
|
-
i > 0 ? /* @__PURE__ */ (0,
|
|
2235
|
-
/* @__PURE__ */ (0,
|
|
2459
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "inline-flex items-center gap-1", children: parts.map((k, i) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
|
|
2460
|
+
i > 0 ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "text-xs text-muted-foreground", children: "+" }) : null,
|
|
2461
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("kbd", { className: "inline-flex h-6 min-w-6 items-center justify-center rounded border border-border bg-muted px-1.5 font-mono text-xs font-medium text-muted-foreground", children: k })
|
|
2236
2462
|
] }, k)) });
|
|
2237
2463
|
}
|
|
2238
2464
|
function ReportShortcutsHelp({ open, onClose }) {
|
|
@@ -2243,7 +2469,7 @@ function ReportShortcutsHelp({ open, onClose }) {
|
|
|
2243
2469
|
if (open && !dialog.open) dialog.showModal();
|
|
2244
2470
|
else if (!open && dialog.open) dialog.close();
|
|
2245
2471
|
}, [open]);
|
|
2246
|
-
return /* @__PURE__ */ (0,
|
|
2472
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
|
|
2247
2473
|
"dialog",
|
|
2248
2474
|
{
|
|
2249
2475
|
ref: dialogRef,
|
|
@@ -2251,12 +2477,12 @@ function ReportShortcutsHelp({ open, onClose }) {
|
|
|
2251
2477
|
"aria-label": "Keyboard shortcuts",
|
|
2252
2478
|
onClose,
|
|
2253
2479
|
children: [
|
|
2254
|
-
/* @__PURE__ */ (0,
|
|
2255
|
-
/* @__PURE__ */ (0,
|
|
2256
|
-
/* @__PURE__ */ (0,
|
|
2257
|
-
/* @__PURE__ */ (0,
|
|
2480
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("h2", { className: "text-base font-semibold", children: "Keyboard shortcuts" }),
|
|
2481
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("dl", { className: "mt-4 grid grid-cols-[auto_1fr] items-center gap-x-4 gap-y-2.5", children: SHORTCUTS.map((s) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "col-span-2 grid grid-cols-subgrid items-center", children: [
|
|
2482
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("dt", { className: "justify-self-start", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Keys, { keys: s.keys }) }),
|
|
2483
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("dd", { className: "text-sm text-muted-foreground", children: s.description })
|
|
2258
2484
|
] }, s.keys)) }),
|
|
2259
|
-
/* @__PURE__ */ (0,
|
|
2485
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("form", { method: "dialog", className: "mt-6", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Button, { type: "submit", variant: "outline", size: "sm", children: "Close" }) })
|
|
2260
2486
|
]
|
|
2261
2487
|
}
|
|
2262
2488
|
);
|
|
@@ -2320,12 +2546,14 @@ function useKeyboardShortcuts(handlers) {
|
|
|
2320
2546
|
// src/interactive/use-deep-link-scroll.ts
|
|
2321
2547
|
var import_react13 = require("react");
|
|
2322
2548
|
function useDeepLinkScroll() {
|
|
2549
|
+
const lastAnchor = (0, import_react13.useRef)(null);
|
|
2323
2550
|
(0, import_react13.useEffect)(() => {
|
|
2324
2551
|
function scrollToHash() {
|
|
2325
|
-
const
|
|
2326
|
-
if (!
|
|
2552
|
+
const { anchor } = splitHash(window.location.hash);
|
|
2553
|
+
if (!anchor || anchor === lastAnchor.current) return;
|
|
2554
|
+
lastAnchor.current = anchor;
|
|
2327
2555
|
requestAnimationFrame(() => {
|
|
2328
|
-
scrollToScenarioId(
|
|
2556
|
+
scrollToScenarioId(anchor, { updateHash: false });
|
|
2329
2557
|
});
|
|
2330
2558
|
}
|
|
2331
2559
|
scrollToHash();
|
|
@@ -2457,7 +2685,7 @@ function failuresFirst(report) {
|
|
|
2457
2685
|
|
|
2458
2686
|
// src/interactive/ReportFilters.tsx
|
|
2459
2687
|
var import_react14 = require("react");
|
|
2460
|
-
var
|
|
2688
|
+
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
2461
2689
|
var TAG_LIMIT = 12;
|
|
2462
2690
|
function ReportFilters({
|
|
2463
2691
|
statuses,
|
|
@@ -2471,10 +2699,10 @@ function ReportFilters({
|
|
|
2471
2699
|
if (statuses.length === 0 && tags.length === 0) return null;
|
|
2472
2700
|
const tagsCollapsed = tags.length > TAG_LIMIT && !showAllTags;
|
|
2473
2701
|
const visibleTags = tagsCollapsed ? tags.slice(0, TAG_LIMIT) : tags;
|
|
2474
|
-
return /* @__PURE__ */ (0,
|
|
2475
|
-
statuses.length > 0 ? /* @__PURE__ */ (0,
|
|
2702
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
2703
|
+
statuses.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { role: "group", "aria-label": "Filter by status", className: "flex flex-wrap gap-1", children: statuses.map((opt) => {
|
|
2476
2704
|
const active = status === opt.key;
|
|
2477
|
-
return /* @__PURE__ */ (0,
|
|
2705
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
|
|
2478
2706
|
"button",
|
|
2479
2707
|
{
|
|
2480
2708
|
type: "button",
|
|
@@ -2486,23 +2714,23 @@ function ReportFilters({
|
|
|
2486
2714
|
),
|
|
2487
2715
|
children: [
|
|
2488
2716
|
opt.label,
|
|
2489
|
-
/* @__PURE__ */ (0,
|
|
2717
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "ml-1 font-mono opacity-70", children: opt.count })
|
|
2490
2718
|
]
|
|
2491
2719
|
},
|
|
2492
2720
|
opt.key
|
|
2493
2721
|
);
|
|
2494
2722
|
}) }) : null,
|
|
2495
|
-
tags.length > 0 ? /* @__PURE__ */ (0,
|
|
2723
|
+
tags.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("ul", { "aria-label": "Filter by tag", className: "flex flex-wrap items-center gap-1.5", children: [
|
|
2496
2724
|
visibleTags.map((tag) => {
|
|
2497
2725
|
const active = activeTags.includes(tag);
|
|
2498
|
-
return /* @__PURE__ */ (0,
|
|
2726
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2499
2727
|
"button",
|
|
2500
2728
|
{
|
|
2501
2729
|
type: "button",
|
|
2502
2730
|
"aria-pressed": active,
|
|
2503
2731
|
onClick: () => onToggleTag(tag),
|
|
2504
2732
|
className: "cursor-pointer",
|
|
2505
|
-
children: /* @__PURE__ */ (0,
|
|
2733
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2506
2734
|
Badge,
|
|
2507
2735
|
{
|
|
2508
2736
|
variant: "tag",
|
|
@@ -2515,7 +2743,7 @@ function ReportFilters({
|
|
|
2515
2743
|
}
|
|
2516
2744
|
) }, tag);
|
|
2517
2745
|
}),
|
|
2518
|
-
tags.length > TAG_LIMIT ? /* @__PURE__ */ (0,
|
|
2746
|
+
tags.length > TAG_LIMIT ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2519
2747
|
"button",
|
|
2520
2748
|
{
|
|
2521
2749
|
type: "button",
|
|
@@ -2531,7 +2759,7 @@ function ReportFilters({
|
|
|
2531
2759
|
|
|
2532
2760
|
// src/interactive/ReportToc.tsx
|
|
2533
2761
|
var import_react15 = require("react");
|
|
2534
|
-
var
|
|
2762
|
+
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
2535
2763
|
var DOT = {
|
|
2536
2764
|
passed: "bg-pass",
|
|
2537
2765
|
failed: "bg-fail",
|
|
@@ -2560,11 +2788,11 @@ function TocContent({ onNavigate }) {
|
|
|
2560
2788
|
return () => observer.disconnect();
|
|
2561
2789
|
}, [scenarioIds]);
|
|
2562
2790
|
if (report.features.length === 0) return null;
|
|
2563
|
-
return /* @__PURE__ */ (0,
|
|
2564
|
-
/* @__PURE__ */ (0,
|
|
2565
|
-
/* @__PURE__ */ (0,
|
|
2791
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("ul", { className: "flex list-none flex-col gap-4 pl-0", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("li", { children: [
|
|
2792
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "mb-1.5 font-semibold leading-snug text-foreground", children: feature.title }),
|
|
2793
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("ul", { className: "flex list-none flex-col gap-0.5 pl-0", children: feature.scenarios.map((scenario) => {
|
|
2566
2794
|
const active = activeId === scenario.id;
|
|
2567
|
-
return /* @__PURE__ */ (0,
|
|
2795
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
2568
2796
|
"a",
|
|
2569
2797
|
{
|
|
2570
2798
|
href: `#${scenario.id}`,
|
|
@@ -2579,14 +2807,14 @@ function TocContent({ onNavigate }) {
|
|
|
2579
2807
|
active ? "border-primary font-medium text-foreground" : "border-border text-muted-foreground"
|
|
2580
2808
|
),
|
|
2581
2809
|
children: [
|
|
2582
|
-
/* @__PURE__ */ (0,
|
|
2810
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
2583
2811
|
"span",
|
|
2584
2812
|
{
|
|
2585
2813
|
"aria-hidden": true,
|
|
2586
2814
|
className: cn("mt-1 size-1.5 shrink-0 rounded-full", DOT[scenario.status])
|
|
2587
2815
|
}
|
|
2588
2816
|
),
|
|
2589
|
-
/* @__PURE__ */ (0,
|
|
2817
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "break-words", children: scenario.title })
|
|
2590
2818
|
]
|
|
2591
2819
|
}
|
|
2592
2820
|
) }, scenario.id);
|
|
@@ -2596,14 +2824,14 @@ function TocContent({ onNavigate }) {
|
|
|
2596
2824
|
function ReportToc() {
|
|
2597
2825
|
const report = useReport();
|
|
2598
2826
|
if (report.features.length === 0) return null;
|
|
2599
|
-
return /* @__PURE__ */ (0,
|
|
2827
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
2600
2828
|
"nav",
|
|
2601
2829
|
{
|
|
2602
2830
|
"aria-label": "Table of contents",
|
|
2603
2831
|
className: "sticky top-4 hidden h-fit w-64 shrink-0 self-start text-xs lg:block",
|
|
2604
2832
|
children: [
|
|
2605
|
-
/* @__PURE__ */ (0,
|
|
2606
|
-
/* @__PURE__ */ (0,
|
|
2833
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "mb-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Contents" }),
|
|
2834
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(TocContent, {})
|
|
2607
2835
|
]
|
|
2608
2836
|
}
|
|
2609
2837
|
);
|
|
@@ -2613,31 +2841,31 @@ function ReportToc() {
|
|
|
2613
2841
|
var import_react16 = require("react");
|
|
2614
2842
|
var import_dialog = require("@base-ui/react/dialog");
|
|
2615
2843
|
var import_lucide_react4 = require("lucide-react");
|
|
2616
|
-
var
|
|
2844
|
+
var import_jsx_runtime46 = require("react/jsx-runtime");
|
|
2617
2845
|
function ReportTocDrawer() {
|
|
2618
2846
|
const report = useReport();
|
|
2619
2847
|
const [open, setOpen] = (0, import_react16.useState)(false);
|
|
2620
2848
|
if (report.features.length === 0) return null;
|
|
2621
|
-
return /* @__PURE__ */ (0,
|
|
2622
|
-
/* @__PURE__ */ (0,
|
|
2623
|
-
/* @__PURE__ */ (0,
|
|
2849
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_dialog.Dialog.Root, { open, onOpenChange: setOpen, children: [
|
|
2850
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_dialog.Dialog.Trigger, { className: "flex cursor-pointer items-center gap-1 rounded-md border border-border px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground lg:hidden [&_svg]:size-3.5", children: [
|
|
2851
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_lucide_react4.ListIcon, { "aria-hidden": true }),
|
|
2624
2852
|
" Contents"
|
|
2625
2853
|
] }),
|
|
2626
|
-
/* @__PURE__ */ (0,
|
|
2627
|
-
/* @__PURE__ */ (0,
|
|
2628
|
-
/* @__PURE__ */ (0,
|
|
2629
|
-
/* @__PURE__ */ (0,
|
|
2630
|
-
/* @__PURE__ */ (0,
|
|
2631
|
-
/* @__PURE__ */ (0,
|
|
2854
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_dialog.Dialog.Portal, { children: [
|
|
2855
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_dialog.Dialog.Backdrop, { className: "fixed inset-0 z-50 bg-black/50 transition-opacity duration-200 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0" }),
|
|
2856
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_dialog.Dialog.Popup, { className: "fixed inset-y-0 left-0 z-50 flex w-72 max-w-[80vw] flex-col gap-3 overflow-y-auto border-r border-border bg-background p-4 font-sans text-xs shadow-lg outline-none transition-transform duration-200 data-[ending-style]:-translate-x-full data-[starting-style]:-translate-x-full", children: [
|
|
2857
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
2858
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_dialog.Dialog.Title, { className: "text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Contents" }),
|
|
2859
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
2632
2860
|
import_dialog.Dialog.Close,
|
|
2633
2861
|
{
|
|
2634
2862
|
"aria-label": "Close contents",
|
|
2635
2863
|
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
2636
|
-
children: /* @__PURE__ */ (0,
|
|
2864
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_lucide_react4.XIcon, { "aria-hidden": true })
|
|
2637
2865
|
}
|
|
2638
2866
|
)
|
|
2639
2867
|
] }),
|
|
2640
|
-
/* @__PURE__ */ (0,
|
|
2868
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(TocContent, { onNavigate: () => setOpen(false) })
|
|
2641
2869
|
] })
|
|
2642
2870
|
] })
|
|
2643
2871
|
] });
|
|
@@ -2691,15 +2919,43 @@ function useTheme() {
|
|
|
2691
2919
|
return { pref, setPref };
|
|
2692
2920
|
}
|
|
2693
2921
|
|
|
2922
|
+
// src/interactive/use-url-state.ts
|
|
2923
|
+
var import_react18 = require("react");
|
|
2924
|
+
var WRITE_DELAY_MS = 250;
|
|
2925
|
+
function useUrlState() {
|
|
2926
|
+
const [state, setState] = (0, import_react18.useState)(DEFAULT_URL_STATE);
|
|
2927
|
+
const ready = (0, import_react18.useRef)(false);
|
|
2928
|
+
(0, import_react18.useEffect)(() => {
|
|
2929
|
+
const read = () => setState(decodeUrlState(splitHash(window.location.hash).params));
|
|
2930
|
+
read();
|
|
2931
|
+
ready.current = true;
|
|
2932
|
+
window.addEventListener("hashchange", read);
|
|
2933
|
+
return () => window.removeEventListener("hashchange", read);
|
|
2934
|
+
}, []);
|
|
2935
|
+
(0, import_react18.useEffect)(() => {
|
|
2936
|
+
if (!ready.current) return;
|
|
2937
|
+
const timer = setTimeout(
|
|
2938
|
+
() => writeHash(splitHash(window.location.hash).anchor, encodeUrlState(state)),
|
|
2939
|
+
WRITE_DELAY_MS
|
|
2940
|
+
);
|
|
2941
|
+
return () => clearTimeout(timer);
|
|
2942
|
+
}, [state]);
|
|
2943
|
+
const update = (0, import_react18.useCallback)(
|
|
2944
|
+
(patch) => setState((prev) => ({ ...prev, ...patch })),
|
|
2945
|
+
[]
|
|
2946
|
+
);
|
|
2947
|
+
return [state, update];
|
|
2948
|
+
}
|
|
2949
|
+
|
|
2694
2950
|
// src/interactive/ReportInteractive.tsx
|
|
2695
|
-
var
|
|
2951
|
+
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
2696
2952
|
function ReportInteractive(props) {
|
|
2697
2953
|
const { report, className, title, dataTheme } = props;
|
|
2698
2954
|
const result = unwrapReport(report);
|
|
2699
2955
|
if (!result.ok) {
|
|
2700
|
-
return /* @__PURE__ */ (0,
|
|
2956
|
+
return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
|
|
2701
2957
|
}
|
|
2702
|
-
return /* @__PURE__ */ (0,
|
|
2958
|
+
return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ReportInteractiveView, { ...props, report: result.data });
|
|
2703
2959
|
}
|
|
2704
2960
|
var THEME_OPTIONS = [
|
|
2705
2961
|
{ value: "light", label: "Light", Icon: import_lucide_react5.Sun },
|
|
@@ -2707,7 +2963,7 @@ var THEME_OPTIONS = [
|
|
|
2707
2963
|
{ value: "dark", label: "Dark", Icon: import_lucide_react5.Moon }
|
|
2708
2964
|
];
|
|
2709
2965
|
function ThemeSegment({ pref, onPref }) {
|
|
2710
|
-
return /* @__PURE__ */ (0,
|
|
2966
|
+
return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
2711
2967
|
ToggleGroup,
|
|
2712
2968
|
{
|
|
2713
2969
|
size: "sm",
|
|
@@ -2717,7 +2973,7 @@ function ThemeSegment({ pref, onPref }) {
|
|
|
2717
2973
|
if (next) onPref(next);
|
|
2718
2974
|
},
|
|
2719
2975
|
"aria-label": "Color theme",
|
|
2720
|
-
children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */ (0,
|
|
2976
|
+
children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ToggleGroupItem, { value, "aria-label": label, title: label, className: "px-2", children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(Icon, {}) }, value))
|
|
2721
2977
|
}
|
|
2722
2978
|
);
|
|
2723
2979
|
}
|
|
@@ -2733,25 +2989,32 @@ function ReportInteractiveView({
|
|
|
2733
2989
|
staleAfterDays = 7,
|
|
2734
2990
|
scenarioHistory
|
|
2735
2991
|
}) {
|
|
2736
|
-
const [
|
|
2737
|
-
const
|
|
2738
|
-
const
|
|
2739
|
-
const
|
|
2740
|
-
|
|
2992
|
+
const [urlState, setUrlState] = useUrlState();
|
|
2993
|
+
const { query, status: statusFilter, tags: activeTags, detail } = urlState;
|
|
2994
|
+
const setQuery = (0, import_react19.useCallback)((next) => setUrlState({ query: next }), [setUrlState]);
|
|
2995
|
+
const setStatusFilter = (0, import_react19.useCallback)(
|
|
2996
|
+
(next) => setUrlState({ status: next }),
|
|
2997
|
+
[setUrlState]
|
|
2998
|
+
);
|
|
2999
|
+
const setDetail = (0, import_react19.useCallback)(
|
|
3000
|
+
(next) => setUrlState({ detail: next }),
|
|
3001
|
+
[setUrlState]
|
|
3002
|
+
);
|
|
3003
|
+
const [helpOpen, setHelpOpen] = (0, import_react19.useState)(false);
|
|
2741
3004
|
const { pref: themePref, setPref: setThemePref } = useTheme();
|
|
2742
|
-
const searchRef = (0,
|
|
2743
|
-
const expandId = (0,
|
|
2744
|
-
const docsId = (0,
|
|
2745
|
-
const deferredQuery = (0,
|
|
2746
|
-
const failures = (0,
|
|
2747
|
-
const filtered = (0,
|
|
3005
|
+
const searchRef = (0, import_react19.useRef)(null);
|
|
3006
|
+
const expandId = (0, import_react19.useId)();
|
|
3007
|
+
const docsId = (0, import_react19.useId)();
|
|
3008
|
+
const deferredQuery = (0, import_react19.useDeferredValue)(query);
|
|
3009
|
+
const failures = (0, import_react19.useMemo)(() => listFailures(report), [report]);
|
|
3010
|
+
const filtered = (0, import_react19.useMemo)(
|
|
2748
3011
|
// Features carrying failures float to the top so the first thing on screen
|
|
2749
3012
|
// is the thing that needs attention; an all-green run keeps source order.
|
|
2750
3013
|
() => failuresFirst(filterReport(report, { query: deferredQuery, status: statusFilter, tags: activeTags })),
|
|
2751
3014
|
[report, deferredQuery, statusFilter, activeTags]
|
|
2752
3015
|
);
|
|
2753
3016
|
const isFiltering = query !== deferredQuery;
|
|
2754
|
-
const statusOptions = (0,
|
|
3017
|
+
const statusOptions = (0, import_react19.useMemo)(() => {
|
|
2755
3018
|
const s = report.summary;
|
|
2756
3019
|
const opts = [
|
|
2757
3020
|
{ key: "all", label: "All", count: s.total }
|
|
@@ -2762,19 +3025,21 @@ function ReportInteractiveView({
|
|
|
2762
3025
|
if (s.pending) opts.push({ key: "pending", label: "Pending", count: s.pending });
|
|
2763
3026
|
return opts;
|
|
2764
3027
|
}, [report]);
|
|
2765
|
-
const tagOptions = (0,
|
|
2766
|
-
const toggleTag = (0,
|
|
2767
|
-
(tag) =>
|
|
2768
|
-
|
|
3028
|
+
const tagOptions = (0, import_react19.useMemo)(() => allTags(report), [report]);
|
|
3029
|
+
const toggleTag = (0, import_react19.useCallback)(
|
|
3030
|
+
(tag) => setUrlState({
|
|
3031
|
+
tags: activeTags.includes(tag) ? activeTags.filter((t) => t !== tag) : [...activeTags, tag]
|
|
3032
|
+
}),
|
|
3033
|
+
[activeTags, setUrlState]
|
|
2769
3034
|
);
|
|
2770
|
-
const [toast, setToast] = (0,
|
|
2771
|
-
const toastTimer = (0,
|
|
2772
|
-
const showToast = (0,
|
|
3035
|
+
const [toast, setToast] = (0, import_react19.useState)(null);
|
|
3036
|
+
const toastTimer = (0, import_react19.useRef)(null);
|
|
3037
|
+
const showToast = (0, import_react19.useCallback)((msg) => {
|
|
2773
3038
|
setToast(msg);
|
|
2774
3039
|
if (toastTimer.current) clearTimeout(toastTimer.current);
|
|
2775
3040
|
toastTimer.current = setTimeout(() => setToast(null), 1800);
|
|
2776
3041
|
}, []);
|
|
2777
|
-
const copy = (0,
|
|
3042
|
+
const copy = (0, import_react19.useCallback)(
|
|
2778
3043
|
(text, msg) => {
|
|
2779
3044
|
if (typeof navigator !== "undefined" && navigator.clipboard) {
|
|
2780
3045
|
navigator.clipboard.writeText(text).then(() => showToast(msg), () => showToast("Copy failed"));
|
|
@@ -2782,7 +3047,7 @@ function ReportInteractiveView({
|
|
|
2782
3047
|
},
|
|
2783
3048
|
[showToast]
|
|
2784
3049
|
);
|
|
2785
|
-
const scenarioActions = (0,
|
|
3050
|
+
const scenarioActions = (0, import_react19.useMemo)(
|
|
2786
3051
|
() => ({
|
|
2787
3052
|
copyLink: (s) => copy(scenarioPermalink(s), "Link copied"),
|
|
2788
3053
|
copyMarkdown: (s) => copy(scenarioToMarkdown2(s), "Markdown copied"),
|
|
@@ -2790,15 +3055,15 @@ function ReportInteractiveView({
|
|
|
2790
3055
|
}),
|
|
2791
3056
|
[copy]
|
|
2792
3057
|
);
|
|
2793
|
-
const failureIndexRef = (0,
|
|
2794
|
-
const allCollapsibleIds = (0,
|
|
3058
|
+
const failureIndexRef = (0, import_react19.useRef)(0);
|
|
3059
|
+
const allCollapsibleIds = (0, import_react19.useMemo)(
|
|
2795
3060
|
() => report.features.flatMap((f) => [f.id, ...f.scenarios.map((s) => s.id)]),
|
|
2796
3061
|
[report]
|
|
2797
3062
|
);
|
|
2798
|
-
const collapse = useCollapseState((0,
|
|
2799
|
-
const collapseAll = (0,
|
|
2800
|
-
const [expandedAll, setExpandedAll] = (0,
|
|
2801
|
-
const setExpanded = (0,
|
|
3063
|
+
const collapse = useCollapseState((0, import_react19.useCallback)(() => defaultCollapsedIds(report), [report]));
|
|
3064
|
+
const collapseAll = (0, import_react19.useCallback)(() => collapse.collapseAll(allCollapsibleIds), [collapse, allCollapsibleIds]);
|
|
3065
|
+
const [expandedAll, setExpandedAll] = (0, import_react19.useState)(() => report.summary.failed === 0);
|
|
3066
|
+
const setExpanded = (0, import_react19.useCallback)(
|
|
2802
3067
|
(expanded) => {
|
|
2803
3068
|
if (expanded) collapse.expandAll();
|
|
2804
3069
|
else collapseAll();
|
|
@@ -2806,10 +3071,10 @@ function ReportInteractiveView({
|
|
|
2806
3071
|
},
|
|
2807
3072
|
[collapse, collapseAll]
|
|
2808
3073
|
);
|
|
2809
|
-
const focusSearch = (0,
|
|
3074
|
+
const focusSearch = (0, import_react19.useCallback)(() => {
|
|
2810
3075
|
searchRef.current?.focus();
|
|
2811
3076
|
}, []);
|
|
2812
|
-
const stepFailure = (0,
|
|
3077
|
+
const stepFailure = (0, import_react19.useCallback)(
|
|
2813
3078
|
(direction) => {
|
|
2814
3079
|
if (failures.length === 0) return;
|
|
2815
3080
|
failureIndexRef.current = (failureIndexRef.current + direction + failures.length) % failures.length;
|
|
@@ -2818,10 +3083,10 @@ function ReportInteractiveView({
|
|
|
2818
3083
|
},
|
|
2819
3084
|
[failures]
|
|
2820
3085
|
);
|
|
2821
|
-
const toggleHelp = (0,
|
|
3086
|
+
const toggleHelp = (0, import_react19.useCallback)(() => {
|
|
2822
3087
|
setHelpOpen((v) => !v);
|
|
2823
3088
|
}, []);
|
|
2824
|
-
const escape = (0,
|
|
3089
|
+
const escape = (0, import_react19.useCallback)(() => {
|
|
2825
3090
|
if (helpOpen) setHelpOpen(false);
|
|
2826
3091
|
else if (query !== "") setQuery("");
|
|
2827
3092
|
}, [helpOpen, query]);
|
|
@@ -2839,13 +3104,13 @@ function ReportInteractiveView({
|
|
|
2839
3104
|
const totalScenarios = report.summary.total;
|
|
2840
3105
|
const matchedScenarios = filtered.summary.total;
|
|
2841
3106
|
const showToc = !hideToc && totalScenarios > 3;
|
|
2842
|
-
return /* @__PURE__ */ (0,
|
|
3107
|
+
return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(CollapseProvider, { value: collapse.api, children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ScenarioActionsProvider, { value: scenarioActions, children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ScenarioHistoryProvider, { value: scenarioHistory ?? null, children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
2843
3108
|
ReportRoot,
|
|
2844
3109
|
{
|
|
2845
3110
|
report: filtered,
|
|
2846
3111
|
customRenderers,
|
|
2847
3112
|
renderers,
|
|
2848
|
-
children: /* @__PURE__ */ (0,
|
|
3113
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
|
|
2849
3114
|
"main",
|
|
2850
3115
|
{
|
|
2851
3116
|
className: cn("es-report", "es-report-interactive", className),
|
|
@@ -2854,8 +3119,8 @@ function ReportInteractiveView({
|
|
|
2854
3119
|
"data-theme": dataTheme,
|
|
2855
3120
|
"data-detail-level": detail,
|
|
2856
3121
|
children: [
|
|
2857
|
-
/* @__PURE__ */ (0,
|
|
2858
|
-
/* @__PURE__ */ (0,
|
|
3122
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("header", { className: "es-report-header", children: [
|
|
3123
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
|
|
2859
3124
|
"div",
|
|
2860
3125
|
{
|
|
2861
3126
|
"data-es-navbar": true,
|
|
@@ -2864,9 +3129,9 @@ function ReportInteractiveView({
|
|
|
2864
3129
|
hideHeader ? "justify-end" : "justify-between"
|
|
2865
3130
|
),
|
|
2866
3131
|
children: [
|
|
2867
|
-
hideHeader ? null : /* @__PURE__ */ (0,
|
|
2868
|
-
/* @__PURE__ */ (0,
|
|
2869
|
-
/* @__PURE__ */ (0,
|
|
3132
|
+
hideHeader ? null : /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("h1", { className: "min-w-0", children: title ?? "Story Report" }),
|
|
3133
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3134
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
2870
3135
|
ReportSearch,
|
|
2871
3136
|
{
|
|
2872
3137
|
ref: searchRef,
|
|
@@ -2876,16 +3141,16 @@ function ReportInteractiveView({
|
|
|
2876
3141
|
totalCount: totalScenarios
|
|
2877
3142
|
}
|
|
2878
3143
|
),
|
|
2879
|
-
/* @__PURE__ */ (0,
|
|
3144
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ThemeSegment, { pref: themePref, onPref: setThemePref })
|
|
2880
3145
|
] })
|
|
2881
3146
|
]
|
|
2882
3147
|
}
|
|
2883
3148
|
),
|
|
2884
|
-
hideHeader ? null : /* @__PURE__ */ (0,
|
|
2885
|
-
/* @__PURE__ */ (0,
|
|
2886
|
-
/* @__PURE__ */ (0,
|
|
3149
|
+
hideHeader ? null : /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_jsx_runtime47.Fragment, { children: [
|
|
3150
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ReportSummary, {}),
|
|
3151
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ReportMeta, {})
|
|
2887
3152
|
] }),
|
|
2888
|
-
/* @__PURE__ */ (0,
|
|
3153
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
2889
3154
|
ReportFreshness,
|
|
2890
3155
|
{
|
|
2891
3156
|
lastRunMs: reportLastRunMs(report),
|
|
@@ -2893,8 +3158,8 @@ function ReportInteractiveView({
|
|
|
2893
3158
|
staleAfterDays
|
|
2894
3159
|
}
|
|
2895
3160
|
),
|
|
2896
|
-
/* @__PURE__ */ (0,
|
|
2897
|
-
/* @__PURE__ */ (0,
|
|
3161
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ReportLastRunDelta, { history: scenarioHistory, report }),
|
|
3162
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
2898
3163
|
ReportFilters,
|
|
2899
3164
|
{
|
|
2900
3165
|
statuses: statusOptions,
|
|
@@ -2905,14 +3170,14 @@ function ReportInteractiveView({
|
|
|
2905
3170
|
onToggleTag: toggleTag
|
|
2906
3171
|
}
|
|
2907
3172
|
),
|
|
2908
|
-
/* @__PURE__ */ (0,
|
|
2909
|
-
showToc ? /* @__PURE__ */ (0,
|
|
2910
|
-
/* @__PURE__ */ (0,
|
|
2911
|
-
/* @__PURE__ */ (0,
|
|
2912
|
-
/* @__PURE__ */ (0,
|
|
3173
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-2 border-t border-border/60 pt-3", children: [
|
|
3174
|
+
showToc ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ReportTocDrawer, {}) : null,
|
|
3175
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3176
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(Switch, { id: expandId, checked: expandedAll, onCheckedChange: setExpanded }),
|
|
3177
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("label", { htmlFor: expandId, className: "cursor-pointer text-sm text-muted-foreground select-none", children: "Expand all" })
|
|
2913
3178
|
] }),
|
|
2914
|
-
/* @__PURE__ */ (0,
|
|
2915
|
-
/* @__PURE__ */ (0,
|
|
3179
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3180
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
2916
3181
|
Switch,
|
|
2917
3182
|
{
|
|
2918
3183
|
id: docsId,
|
|
@@ -2920,16 +3185,16 @@ function ReportInteractiveView({
|
|
|
2920
3185
|
onCheckedChange: (checked) => setDetail(checked ? "full" : "minimal")
|
|
2921
3186
|
}
|
|
2922
3187
|
),
|
|
2923
|
-
/* @__PURE__ */ (0,
|
|
3188
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("label", { htmlFor: docsId, className: "cursor-pointer text-sm text-muted-foreground select-none", children: "Show documentation" })
|
|
2924
3189
|
] })
|
|
2925
3190
|
] })
|
|
2926
3191
|
] }),
|
|
2927
|
-
/* @__PURE__ */ (0,
|
|
2928
|
-
hasContent ? showToc ? /* @__PURE__ */ (0,
|
|
2929
|
-
/* @__PURE__ */ (0,
|
|
2930
|
-
/* @__PURE__ */ (0,
|
|
2931
|
-
] }) : /* @__PURE__ */ (0,
|
|
2932
|
-
/* @__PURE__ */ (0,
|
|
3192
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ReportFailureBanner, { failures }),
|
|
3193
|
+
hasContent ? showToc ? /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "flex gap-6", children: [
|
|
3194
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ReportToc, {}),
|
|
3195
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "flex min-w-0 flex-1 flex-col gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ReportFeatureList, {}) })
|
|
3196
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ReportFeatureList, {}) }) : /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ReportEmpty, { message: query ? "No scenarios match the search." : void 0 }),
|
|
3197
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
2933
3198
|
"button",
|
|
2934
3199
|
{
|
|
2935
3200
|
type: "button",
|
|
@@ -2940,8 +3205,8 @@ function ReportInteractiveView({
|
|
|
2940
3205
|
children: "?"
|
|
2941
3206
|
}
|
|
2942
3207
|
),
|
|
2943
|
-
/* @__PURE__ */ (0,
|
|
2944
|
-
toast ? /* @__PURE__ */ (0,
|
|
3208
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ReportShortcutsHelp, { open: helpOpen, onClose: () => setHelpOpen(false) }),
|
|
3209
|
+
toast ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
2945
3210
|
"div",
|
|
2946
3211
|
{
|
|
2947
3212
|
role: "status",
|
|
@@ -2958,14 +3223,14 @@ function ReportInteractiveView({
|
|
|
2958
3223
|
}
|
|
2959
3224
|
|
|
2960
3225
|
// src/interactive/ReportInteractiveIsland.tsx
|
|
2961
|
-
var
|
|
3226
|
+
var import_react22 = require("react");
|
|
2962
3227
|
|
|
2963
3228
|
// src/interactive/island-renderers.tsx
|
|
2964
|
-
var
|
|
3229
|
+
var import_react21 = require("react");
|
|
2965
3230
|
|
|
2966
3231
|
// src/components/doc/MermaidView.tsx
|
|
2967
|
-
var
|
|
2968
|
-
var
|
|
3232
|
+
var import_react20 = require("react");
|
|
3233
|
+
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
2969
3234
|
function prefersDark(el) {
|
|
2970
3235
|
const themed = el?.closest("[data-theme]");
|
|
2971
3236
|
if (themed?.dataset.theme === "dark") return true;
|
|
@@ -2973,23 +3238,40 @@ function prefersDark(el) {
|
|
|
2973
3238
|
return typeof window !== "undefined" && !!window.matchMedia?.("(prefers-color-scheme: dark)").matches;
|
|
2974
3239
|
}
|
|
2975
3240
|
function MermaidView({ entry, load }) {
|
|
2976
|
-
const ref = (0,
|
|
2977
|
-
const [svg, setSvg] = (0,
|
|
2978
|
-
(0,
|
|
3241
|
+
const ref = (0, import_react20.useRef)(null);
|
|
3242
|
+
const [svg, setSvg] = (0, import_react20.useState)(null);
|
|
3243
|
+
const [error, setError] = (0, import_react20.useState)(null);
|
|
3244
|
+
(0, import_react20.useEffect)(() => {
|
|
2979
3245
|
let cancelled = false;
|
|
2980
3246
|
const draw = async () => {
|
|
3247
|
+
let mermaid;
|
|
3248
|
+
try {
|
|
3249
|
+
mermaid = await load();
|
|
3250
|
+
} catch {
|
|
3251
|
+
if (!cancelled) {
|
|
3252
|
+
setSvg(null);
|
|
3253
|
+
setError(null);
|
|
3254
|
+
}
|
|
3255
|
+
return;
|
|
3256
|
+
}
|
|
2981
3257
|
try {
|
|
2982
|
-
const mermaid = await load();
|
|
2983
3258
|
mermaid.initialize({
|
|
2984
3259
|
startOnLoad: false,
|
|
2985
3260
|
securityLevel: "strict",
|
|
2986
3261
|
theme: prefersDark(ref.current) ? "dark" : "default"
|
|
2987
3262
|
});
|
|
3263
|
+
await mermaid.parse(entry.code);
|
|
2988
3264
|
const id = `es-mermaid-${Math.random().toString(36).slice(2)}`;
|
|
2989
3265
|
const { svg: rendered } = await mermaid.render(id, entry.code);
|
|
2990
|
-
if (!cancelled)
|
|
2991
|
-
|
|
2992
|
-
|
|
3266
|
+
if (!cancelled) {
|
|
3267
|
+
setSvg(rendered);
|
|
3268
|
+
setError(null);
|
|
3269
|
+
}
|
|
3270
|
+
} catch (err) {
|
|
3271
|
+
if (!cancelled) {
|
|
3272
|
+
setSvg(null);
|
|
3273
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
3274
|
+
}
|
|
2993
3275
|
}
|
|
2994
3276
|
};
|
|
2995
3277
|
void draw();
|
|
@@ -3002,9 +3284,9 @@ function MermaidView({ entry, load }) {
|
|
|
3002
3284
|
};
|
|
3003
3285
|
}, [entry.code, load]);
|
|
3004
3286
|
if (svg) {
|
|
3005
|
-
return /* @__PURE__ */ (0,
|
|
3006
|
-
entry.title ? /* @__PURE__ */ (0,
|
|
3007
|
-
/* @__PURE__ */ (0,
|
|
3287
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("figure", { ref, className: "my-3", children: [
|
|
3288
|
+
entry.title ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
|
|
3289
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
3008
3290
|
"div",
|
|
3009
3291
|
{
|
|
3010
3292
|
role: "img",
|
|
@@ -3015,11 +3297,25 @@ function MermaidView({ entry, load }) {
|
|
|
3015
3297
|
)
|
|
3016
3298
|
] });
|
|
3017
3299
|
}
|
|
3018
|
-
return /* @__PURE__ */ (0,
|
|
3300
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
|
|
3301
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
|
|
3302
|
+
"p",
|
|
3303
|
+
{
|
|
3304
|
+
role: "alert",
|
|
3305
|
+
"data-es-mermaid-error": true,
|
|
3306
|
+
className: "mt-3 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive",
|
|
3307
|
+
children: [
|
|
3308
|
+
"Diagram failed to render: ",
|
|
3309
|
+
error
|
|
3310
|
+
]
|
|
3311
|
+
}
|
|
3312
|
+
) : null,
|
|
3313
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(MermaidSource, { entry, ref })
|
|
3314
|
+
] });
|
|
3019
3315
|
}
|
|
3020
3316
|
|
|
3021
3317
|
// src/interactive/island-renderers.tsx
|
|
3022
|
-
var
|
|
3318
|
+
var import_jsx_runtime49 = require("react/jsx-runtime");
|
|
3023
3319
|
var HLJS_ESM = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/highlight.min.js";
|
|
3024
3320
|
var MERMAID_ESM = "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
|
|
3025
3321
|
function cachedCdnModule(url) {
|
|
@@ -3036,8 +3332,8 @@ function cachedCdnModule(url) {
|
|
|
3036
3332
|
var loadMermaidFromCdn = cachedCdnModule(MERMAID_ESM);
|
|
3037
3333
|
var loadHljs = cachedCdnModule(HLJS_ESM);
|
|
3038
3334
|
function CdnHighlightedCode({ entry }) {
|
|
3039
|
-
const [html, setHtml] = (0,
|
|
3040
|
-
(0,
|
|
3335
|
+
const [html, setHtml] = (0, import_react21.useState)(null);
|
|
3336
|
+
(0, import_react21.useEffect)(() => {
|
|
3041
3337
|
let cancelled = false;
|
|
3042
3338
|
void (async () => {
|
|
3043
3339
|
try {
|
|
@@ -3053,27 +3349,27 @@ function CdnHighlightedCode({ entry }) {
|
|
|
3053
3349
|
cancelled = true;
|
|
3054
3350
|
};
|
|
3055
3351
|
}, [entry.content, entry.lang]);
|
|
3056
|
-
return /* @__PURE__ */ (0,
|
|
3352
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(CodeFigure, { label: entry.label, children: html !== null ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
3057
3353
|
"code",
|
|
3058
3354
|
{
|
|
3059
3355
|
className: cn("hljs font-mono text-xs", entry.lang && `language-${entry.lang}`),
|
|
3060
3356
|
dangerouslySetInnerHTML: { __html: html }
|
|
3061
3357
|
}
|
|
3062
|
-
) : /* @__PURE__ */ (0,
|
|
3358
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
|
|
3063
3359
|
}
|
|
3064
3360
|
function buildIslandRenderers(opts) {
|
|
3065
3361
|
const renderers = {};
|
|
3066
3362
|
if (opts.mermaid) {
|
|
3067
|
-
renderers.mermaid = (entry) => (0,
|
|
3363
|
+
renderers.mermaid = (entry) => (0, import_react21.createElement)(MermaidView, { entry, load: loadMermaidFromCdn });
|
|
3068
3364
|
}
|
|
3069
3365
|
if (opts.syntaxHighlighting) {
|
|
3070
|
-
renderers.code = (entry) => (0,
|
|
3366
|
+
renderers.code = (entry) => (0, import_react21.createElement)(CdnHighlightedCode, { entry });
|
|
3071
3367
|
}
|
|
3072
3368
|
return renderers;
|
|
3073
3369
|
}
|
|
3074
3370
|
|
|
3075
3371
|
// src/interactive/ReportInteractiveIsland.tsx
|
|
3076
|
-
var
|
|
3372
|
+
var import_jsx_runtime50 = require("react/jsx-runtime");
|
|
3077
3373
|
function ReportInteractiveIsland({
|
|
3078
3374
|
report,
|
|
3079
3375
|
title,
|
|
@@ -3083,11 +3379,11 @@ function ReportInteractiveIsland({
|
|
|
3083
3379
|
syntaxHighlighting = true,
|
|
3084
3380
|
mermaid = true
|
|
3085
3381
|
}) {
|
|
3086
|
-
const renderers = (0,
|
|
3382
|
+
const renderers = (0, import_react22.useMemo)(
|
|
3087
3383
|
() => buildIslandRenderers({ syntaxHighlighting, mermaid }),
|
|
3088
3384
|
[syntaxHighlighting, mermaid]
|
|
3089
3385
|
);
|
|
3090
|
-
return /* @__PURE__ */ (0,
|
|
3386
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
3091
3387
|
ReportInteractive,
|
|
3092
3388
|
{
|
|
3093
3389
|
report,
|