executable-stories-react 0.10.1 → 0.12.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 +482 -451
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -2
- package/dist/index.d.ts +14 -2
- package/dist/index.js +440 -407
- package/dist/index.js.map +1 -1
- package/dist/interactive.cjs +1430 -1246
- package/dist/interactive.cjs.map +1 -1
- package/dist/interactive.d.cts +32 -32
- package/dist/interactive.d.ts +32 -32
- package/dist/interactive.js +1473 -1286
- package/dist/interactive.js.map +1 -1
- package/dist/parse.cjs +65 -139
- package/dist/parse.cjs.map +1 -1
- package/dist/parse.js +65 -139
- package/dist/parse.js.map +1 -1
- package/dist/report-island.global.js +30 -28
- package/dist/ssr.cjs +367 -254
- package/dist/ssr.cjs.map +1 -1
- package/dist/ssr.js +325 -209
- package/dist/ssr.js.map +1 -1
- package/dist/tailwind.css +1 -1
- package/package.json +2 -2
package/dist/ssr.cjs
CHANGED
|
@@ -23,7 +23,7 @@ __export(ssr_entry_exports, {
|
|
|
23
23
|
renderReportToHtml: () => renderReportToHtml
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(ssr_entry_exports);
|
|
26
|
-
var
|
|
26
|
+
var import_react10 = require("react");
|
|
27
27
|
var import_server = require("react-dom/server");
|
|
28
28
|
|
|
29
29
|
// src/result.ts
|
|
@@ -314,23 +314,45 @@ function useReport() {
|
|
|
314
314
|
// src/components/ReportScenario.tsx
|
|
315
315
|
var import_duration3 = require("executable-stories-core/utils/duration");
|
|
316
316
|
|
|
317
|
+
// src/lib/step-params.tsx
|
|
318
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
319
|
+
var STEP_PARAM_PATTERN = /"[^"]*"|(?<![\w.-])\d+(?:\.\d+)?(?![\w.-])/g;
|
|
320
|
+
function highlightStepParams(text) {
|
|
321
|
+
const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));
|
|
322
|
+
if (matches.length === 0) return text;
|
|
323
|
+
const nodes = [];
|
|
324
|
+
let lastIndex = 0;
|
|
325
|
+
matches.forEach((match, i) => {
|
|
326
|
+
const start = match.index;
|
|
327
|
+
const end = start + match[0].length;
|
|
328
|
+
if (start > lastIndex) nodes.push(text.slice(lastIndex, start));
|
|
329
|
+
nodes.push(
|
|
330
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "font-medium text-step-param italic", children: match[0] }, i)
|
|
331
|
+
);
|
|
332
|
+
lastIndex = end;
|
|
333
|
+
});
|
|
334
|
+
if (lastIndex < text.length) nodes.push(text.slice(lastIndex));
|
|
335
|
+
return nodes;
|
|
336
|
+
}
|
|
337
|
+
|
|
317
338
|
// src/components/ReportSteps.tsx
|
|
339
|
+
var import_assertive_steps = require("executable-stories-core/utils/assertive-steps");
|
|
318
340
|
var import_duration = require("executable-stories-core/utils/duration");
|
|
319
341
|
|
|
320
342
|
// src/components/doc/DocNote.tsx
|
|
321
|
-
var
|
|
343
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
322
344
|
function DocNote({ entry }) {
|
|
323
|
-
return /* @__PURE__ */ (0,
|
|
345
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "my-2 text-sm text-muted-foreground", children: entry.text });
|
|
324
346
|
}
|
|
325
347
|
|
|
326
348
|
// src/components/doc/DocTag.tsx
|
|
327
|
-
var
|
|
349
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
328
350
|
function DocTag({ entry }) {
|
|
329
|
-
return /* @__PURE__ */ (0,
|
|
351
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ul", { className: "my-2 flex flex-wrap gap-1.5", "aria-label": "Tags", children: entry.names.map((n) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Badge, { variant: "tag", children: n }) }, n)) });
|
|
330
352
|
}
|
|
331
353
|
|
|
332
354
|
// src/components/doc/DocKv.tsx
|
|
333
|
-
var
|
|
355
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
334
356
|
function formatValue(value) {
|
|
335
357
|
if (value === null) return "null";
|
|
336
358
|
if (typeof value === "string") return value;
|
|
@@ -342,9 +364,9 @@ function formatValue(value) {
|
|
|
342
364
|
}
|
|
343
365
|
}
|
|
344
366
|
function DocKv({ entry }) {
|
|
345
|
-
return /* @__PURE__ */ (0,
|
|
346
|
-
/* @__PURE__ */ (0,
|
|
347
|
-
/* @__PURE__ */ (0,
|
|
367
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("dl", { className: "my-2 flex flex-wrap items-baseline gap-x-2 text-sm", children: [
|
|
368
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("dt", { className: "font-semibold text-muted-foreground", children: entry.label }),
|
|
369
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("dd", { className: "font-mono text-foreground", children: formatValue(entry.value) })
|
|
348
370
|
] });
|
|
349
371
|
}
|
|
350
372
|
|
|
@@ -362,37 +384,37 @@ function useBuiltinRenderers() {
|
|
|
362
384
|
}
|
|
363
385
|
|
|
364
386
|
// src/components/doc/DocCode.tsx
|
|
365
|
-
var
|
|
387
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
366
388
|
function CodeFigure({ label, children }) {
|
|
367
|
-
return /* @__PURE__ */ (0,
|
|
368
|
-
label ? /* @__PURE__ */ (0,
|
|
369
|
-
/* @__PURE__ */ (0,
|
|
389
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("figure", { className: "my-3", children: [
|
|
390
|
+
label ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: label }) : null,
|
|
391
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3", children })
|
|
370
392
|
] });
|
|
371
393
|
}
|
|
372
394
|
function DocCode({ entry }) {
|
|
373
395
|
const renderers = useBuiltinRenderers();
|
|
374
396
|
if (renderers.code) {
|
|
375
|
-
return /* @__PURE__ */ (0,
|
|
397
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: renderers.code(entry) });
|
|
376
398
|
}
|
|
377
|
-
return /* @__PURE__ */ (0,
|
|
399
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CodeFigure, { label: entry.label, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
|
|
378
400
|
}
|
|
379
401
|
|
|
380
402
|
// src/components/doc/DocTable.tsx
|
|
381
|
-
var
|
|
403
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
382
404
|
function DocTable({ entry }) {
|
|
383
|
-
return /* @__PURE__ */ (0,
|
|
384
|
-
entry.label ? /* @__PURE__ */ (0,
|
|
385
|
-
/* @__PURE__ */ (0,
|
|
386
|
-
/* @__PURE__ */ (0,
|
|
387
|
-
/* @__PURE__ */ (0,
|
|
405
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("figure", { className: "my-3", children: [
|
|
406
|
+
entry.label ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.label }) : null,
|
|
407
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("table", { className: "w-full border-collapse text-sm", children: [
|
|
408
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("tr", { className: "bg-muted/50", children: entry.columns.map((c) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: c }, c)) }) }),
|
|
409
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("tbody", { children: entry.rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("tr", { children: row.map((cell, j) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { className: "border-b border-border px-3 py-2 text-foreground", children: cell }, j)) }, i)) })
|
|
388
410
|
] }) })
|
|
389
411
|
] });
|
|
390
412
|
}
|
|
391
413
|
|
|
392
414
|
// src/components/doc/DocLink.tsx
|
|
393
|
-
var
|
|
415
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
394
416
|
function DocLink({ entry }) {
|
|
395
|
-
return /* @__PURE__ */ (0,
|
|
417
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
396
418
|
"a",
|
|
397
419
|
{
|
|
398
420
|
className: "text-sm font-medium text-primary underline underline-offset-2 hover:no-underline",
|
|
@@ -404,30 +426,38 @@ function DocLink({ entry }) {
|
|
|
404
426
|
);
|
|
405
427
|
}
|
|
406
428
|
|
|
407
|
-
// src/
|
|
429
|
+
// src/lib/markdown.ts
|
|
408
430
|
var import_marked = require("marked");
|
|
409
431
|
|
|
410
432
|
// src/lib/url.ts
|
|
411
433
|
var import_url = require("executable-stories-core/utils/url");
|
|
412
434
|
|
|
413
|
-
// src/
|
|
414
|
-
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
415
|
-
function neutralizeUrl(value) {
|
|
416
|
-
return (0, import_url.safeUrl)(value) ?? "#";
|
|
417
|
-
}
|
|
435
|
+
// src/lib/markdown.ts
|
|
418
436
|
function safeMarkdownHtml(markdown) {
|
|
419
437
|
const raw = import_marked.marked.parse(markdown, { async: false });
|
|
420
438
|
return raw.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, "").replace(/<\/?(?:iframe|object|embed|form|base)\b[^>]*>/gi, "").replace(/\son[a-z]+\s*=\s*"[^"]*"/gi, "").replace(/\son[a-z]+\s*=\s*'[^']*'/gi, "").replace(/\son[a-z]+\s*=\s*[^\s>]+/gi, "").replace(/(href|src)\s*=\s*"([^"]*)"/gi, (_m, attr, val) => `${attr}="${neutralizeUrl(val)}"`).replace(/(href|src)\s*=\s*'([^']*)'/gi, (_m, attr, val) => `${attr}='${neutralizeUrl(val)}'`);
|
|
421
439
|
}
|
|
440
|
+
function dedent(text) {
|
|
441
|
+
const lines = text.replace(/\t/g, " ").split("\n");
|
|
442
|
+
const indents = lines.filter((line) => line.trim().length > 0).map((line) => line.length - line.trimStart().length);
|
|
443
|
+
const shortest = indents.length > 0 ? Math.min(...indents) : 0;
|
|
444
|
+
return lines.map((line) => line.slice(shortest)).join("\n").trim();
|
|
445
|
+
}
|
|
446
|
+
function neutralizeUrl(value) {
|
|
447
|
+
return (0, import_url.safeUrl)(value) ?? "#";
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// src/components/doc/DocSection.tsx
|
|
451
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
422
452
|
function DocSection({ entry }) {
|
|
423
453
|
const renderers = useBuiltinRenderers();
|
|
424
454
|
if (renderers.section) {
|
|
425
|
-
return /* @__PURE__ */ (0,
|
|
455
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, { children: renderers.section(entry) });
|
|
426
456
|
}
|
|
427
457
|
const html = safeMarkdownHtml(entry.markdown);
|
|
428
|
-
return /* @__PURE__ */ (0,
|
|
429
|
-
entry.title ? /* @__PURE__ */ (0,
|
|
430
|
-
/* @__PURE__ */ (0,
|
|
458
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("section", { className: "my-3 text-sm", "aria-label": entry.title, children: [
|
|
459
|
+
entry.title ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h4", { className: "mb-1 font-semibold text-foreground", children: entry.title }) : null,
|
|
460
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
431
461
|
"div",
|
|
432
462
|
{
|
|
433
463
|
className: "es-doc-prose prose prose-sm max-w-none",
|
|
@@ -438,11 +468,11 @@ function DocSection({ entry }) {
|
|
|
438
468
|
}
|
|
439
469
|
|
|
440
470
|
// src/components/doc/DocMermaid.tsx
|
|
441
|
-
var
|
|
471
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
442
472
|
function MermaidSource({ entry, ref }) {
|
|
443
|
-
return /* @__PURE__ */ (0,
|
|
444
|
-
entry.title ? /* @__PURE__ */ (0,
|
|
445
|
-
/* @__PURE__ */ (0,
|
|
473
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("figure", { ref, className: "my-3", "aria-label": entry.title ?? "Diagram", children: [
|
|
474
|
+
entry.title ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
|
|
475
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
446
476
|
"pre",
|
|
447
477
|
{
|
|
448
478
|
"data-mermaid": true,
|
|
@@ -456,24 +486,24 @@ function MermaidSource({ entry, ref }) {
|
|
|
456
486
|
function DocMermaid({ entry }) {
|
|
457
487
|
const renderers = useBuiltinRenderers();
|
|
458
488
|
if (renderers.mermaid) {
|
|
459
|
-
return /* @__PURE__ */ (0,
|
|
489
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, { children: renderers.mermaid(entry) });
|
|
460
490
|
}
|
|
461
|
-
return /* @__PURE__ */ (0,
|
|
491
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(MermaidSource, { entry });
|
|
462
492
|
}
|
|
463
493
|
|
|
464
494
|
// src/components/doc/DocScreenshot.tsx
|
|
465
|
-
var
|
|
495
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
466
496
|
function DocScreenshot({ entry }) {
|
|
467
497
|
const src = (0, import_url.isLocalFsPath)(entry.path) ? void 0 : (0, import_url.safeImageUrl)(entry.path);
|
|
468
498
|
if (!src) {
|
|
469
|
-
return /* @__PURE__ */ (0,
|
|
470
|
-
/* @__PURE__ */ (0,
|
|
471
|
-
/* @__PURE__ */ (0,
|
|
472
|
-
entry.alt ? /* @__PURE__ */ (0,
|
|
499
|
+
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: [
|
|
500
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "font-medium", children: "Screenshot unavailable" }),
|
|
501
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
|
|
502
|
+
entry.alt ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("figcaption", { className: "mt-1.5 text-xs", children: entry.alt }) : null
|
|
473
503
|
] });
|
|
474
504
|
}
|
|
475
|
-
return /* @__PURE__ */ (0,
|
|
476
|
-
/* @__PURE__ */ (0,
|
|
505
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figure", { className: "my-3", children: [
|
|
506
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
477
507
|
"img",
|
|
478
508
|
{
|
|
479
509
|
src,
|
|
@@ -482,24 +512,24 @@ function DocScreenshot({ entry }) {
|
|
|
482
512
|
className: "max-w-full rounded-md border border-border"
|
|
483
513
|
}
|
|
484
514
|
),
|
|
485
|
-
entry.alt ? /* @__PURE__ */ (0,
|
|
515
|
+
entry.alt ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("figcaption", { className: "mt-1.5 text-xs text-muted-foreground", children: entry.alt }) : null
|
|
486
516
|
] });
|
|
487
517
|
}
|
|
488
518
|
|
|
489
519
|
// src/components/doc/DocVideo.tsx
|
|
490
|
-
var
|
|
520
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
491
521
|
function DocVideo({ entry }) {
|
|
492
522
|
if ((0, import_url.isLocalFsPath)(entry.path)) {
|
|
493
|
-
return /* @__PURE__ */ (0,
|
|
494
|
-
/* @__PURE__ */ (0,
|
|
495
|
-
/* @__PURE__ */ (0,
|
|
496
|
-
entry.caption ? /* @__PURE__ */ (0,
|
|
523
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
|
|
524
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "font-medium", children: "Video unavailable" }),
|
|
525
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
|
|
526
|
+
entry.caption ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("figcaption", { className: "mt-1.5 text-xs", children: entry.caption }) : null
|
|
497
527
|
] });
|
|
498
528
|
}
|
|
499
529
|
const src = (0, import_url.safeUrl)(entry.path);
|
|
500
530
|
const poster = (0, import_url.safeUrl)(entry.poster);
|
|
501
|
-
return /* @__PURE__ */ (0,
|
|
502
|
-
/* @__PURE__ */ (0,
|
|
531
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("figure", { className: "my-3", children: [
|
|
532
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
503
533
|
"video",
|
|
504
534
|
{
|
|
505
535
|
controls: true,
|
|
@@ -509,21 +539,21 @@ function DocVideo({ entry }) {
|
|
|
509
539
|
className: "max-w-full rounded-md border border-border"
|
|
510
540
|
}
|
|
511
541
|
),
|
|
512
|
-
entry.caption ? /* @__PURE__ */ (0,
|
|
542
|
+
entry.caption ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: entry.caption }) : null
|
|
513
543
|
] });
|
|
514
544
|
}
|
|
515
545
|
|
|
516
546
|
// src/components/doc/DocHtml.tsx
|
|
517
|
-
var
|
|
547
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
518
548
|
function DocHtml({ entry }) {
|
|
519
549
|
const height = typeof entry.height === "number" ? `${entry.height}px` : entry.height ?? "400px";
|
|
520
550
|
const title = entry.title ?? "Embedded HTML";
|
|
521
551
|
const safeHref = (0, import_url.safeUrl)(entry.url ?? entry.path);
|
|
522
552
|
const frameProps = entry.content !== void 0 ? { srcDoc: entry.content } : { src: safeHref ?? "" };
|
|
523
|
-
return /* @__PURE__ */ (0,
|
|
524
|
-
/* @__PURE__ */ (0,
|
|
525
|
-
/* @__PURE__ */ (0,
|
|
526
|
-
safeHref ? /* @__PURE__ */ (0,
|
|
553
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("figure", { className: "my-3 overflow-hidden rounded-md border border-border", children: [
|
|
554
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.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: [
|
|
555
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: entry.title ?? "HTML" }),
|
|
556
|
+
safeHref ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
527
557
|
"a",
|
|
528
558
|
{
|
|
529
559
|
href: safeHref,
|
|
@@ -536,7 +566,7 @@ function DocHtml({ entry }) {
|
|
|
536
566
|
}
|
|
537
567
|
) : null
|
|
538
568
|
] }),
|
|
539
|
-
/* @__PURE__ */ (0,
|
|
569
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
540
570
|
"iframe",
|
|
541
571
|
{
|
|
542
572
|
...frameProps,
|
|
@@ -551,7 +581,7 @@ function DocHtml({ entry }) {
|
|
|
551
581
|
}
|
|
552
582
|
|
|
553
583
|
// src/components/doc/DocState.tsx
|
|
554
|
-
var
|
|
584
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
555
585
|
function DocState({ entry }) {
|
|
556
586
|
let json;
|
|
557
587
|
try {
|
|
@@ -559,20 +589,20 @@ function DocState({ entry }) {
|
|
|
559
589
|
} catch {
|
|
560
590
|
json = String(entry.value);
|
|
561
591
|
}
|
|
562
|
-
return /* @__PURE__ */ (0,
|
|
592
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(CodeFigure, { label: entry.label ?? "State", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("code", { className: "font-mono text-xs language-json", children: json }) });
|
|
563
593
|
}
|
|
564
594
|
|
|
565
595
|
// src/components/doc/DocCustom.tsx
|
|
566
|
-
var
|
|
596
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
567
597
|
function DocCustom({ entry }) {
|
|
568
598
|
const renderers = useCustomRenderers();
|
|
569
599
|
const renderer = renderers[entry.type];
|
|
570
600
|
if (renderer) {
|
|
571
|
-
return /* @__PURE__ */ (0,
|
|
601
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children: renderer(entry) });
|
|
572
602
|
}
|
|
573
|
-
return /* @__PURE__ */ (0,
|
|
574
|
-
/* @__PURE__ */ (0,
|
|
575
|
-
/* @__PURE__ */ (0,
|
|
603
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "my-2", "data-type": entry.type, children: [
|
|
604
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: entry.type }),
|
|
605
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground", children: safeStringify2(entry.data) })
|
|
576
606
|
] });
|
|
577
607
|
}
|
|
578
608
|
function safeStringify2(value) {
|
|
@@ -584,64 +614,43 @@ function safeStringify2(value) {
|
|
|
584
614
|
}
|
|
585
615
|
|
|
586
616
|
// src/components/doc/DocEntry.tsx
|
|
587
|
-
var
|
|
617
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
588
618
|
function DocEntry({ entry }) {
|
|
589
619
|
switch (entry.kind) {
|
|
590
620
|
case "note":
|
|
591
|
-
return /* @__PURE__ */ (0,
|
|
621
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DocNote, { entry });
|
|
592
622
|
case "tag":
|
|
593
|
-
return /* @__PURE__ */ (0,
|
|
623
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DocTag, { entry });
|
|
594
624
|
case "kv":
|
|
595
|
-
return /* @__PURE__ */ (0,
|
|
625
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DocKv, { entry });
|
|
596
626
|
case "code":
|
|
597
|
-
return /* @__PURE__ */ (0,
|
|
627
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DocCode, { entry });
|
|
598
628
|
case "table":
|
|
599
|
-
return /* @__PURE__ */ (0,
|
|
629
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DocTable, { entry });
|
|
600
630
|
case "link":
|
|
601
|
-
return /* @__PURE__ */ (0,
|
|
631
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DocLink, { entry });
|
|
602
632
|
case "section":
|
|
603
|
-
return /* @__PURE__ */ (0,
|
|
633
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DocSection, { entry });
|
|
604
634
|
case "mermaid":
|
|
605
|
-
return /* @__PURE__ */ (0,
|
|
635
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DocMermaid, { entry });
|
|
606
636
|
case "screenshot":
|
|
607
|
-
return /* @__PURE__ */ (0,
|
|
637
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DocScreenshot, { entry });
|
|
608
638
|
case "video":
|
|
609
|
-
return /* @__PURE__ */ (0,
|
|
639
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DocVideo, { entry });
|
|
610
640
|
case "html":
|
|
611
|
-
return /* @__PURE__ */ (0,
|
|
641
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DocHtml, { entry });
|
|
612
642
|
case "state":
|
|
613
|
-
return /* @__PURE__ */ (0,
|
|
643
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DocState, { entry });
|
|
614
644
|
case "custom":
|
|
615
|
-
return /* @__PURE__ */ (0,
|
|
645
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DocCustom, { entry });
|
|
616
646
|
}
|
|
617
647
|
}
|
|
618
648
|
|
|
619
649
|
// src/components/ReportDocEntries.tsx
|
|
620
|
-
var
|
|
650
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
621
651
|
function ReportDocEntries({ entries }) {
|
|
622
652
|
if (entries.length === 0) return null;
|
|
623
|
-
return /* @__PURE__ */ (0,
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
// src/lib/step-params.tsx
|
|
627
|
-
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
628
|
-
var STEP_PARAM_PATTERN = /"[^"]*"|(?<![\w.-])\d+(?:\.\d+)?(?![\w.-])/g;
|
|
629
|
-
function highlightStepParams(text) {
|
|
630
|
-
const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));
|
|
631
|
-
if (matches.length === 0) return text;
|
|
632
|
-
const nodes = [];
|
|
633
|
-
let lastIndex = 0;
|
|
634
|
-
matches.forEach((match, i) => {
|
|
635
|
-
const start = match.index;
|
|
636
|
-
const end = start + match[0].length;
|
|
637
|
-
if (start > lastIndex) nodes.push(text.slice(lastIndex, start));
|
|
638
|
-
nodes.push(
|
|
639
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "font-medium text-step-param italic", children: match[0] }, i)
|
|
640
|
-
);
|
|
641
|
-
lastIndex = end;
|
|
642
|
-
});
|
|
643
|
-
if (lastIndex < text.length) nodes.push(text.slice(lastIndex));
|
|
644
|
-
return nodes;
|
|
653
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_jsx_runtime18.Fragment, { children: entries.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DocEntry, { entry }, i)) });
|
|
645
654
|
}
|
|
646
655
|
|
|
647
656
|
// src/components/ReportSteps.tsx
|
|
@@ -660,9 +669,22 @@ var STEP_GLYPH_COLOR = {
|
|
|
660
669
|
};
|
|
661
670
|
function ReportSteps({ scenario }) {
|
|
662
671
|
if (scenario.steps.length === 0) return null;
|
|
663
|
-
|
|
672
|
+
const unasserted = new Set(
|
|
673
|
+
(0, import_assertive_steps.assertionState)(scenario.steps) === "unasserted" ? (0, import_assertive_steps.assertiveSteps)(scenario.steps).map((step) => step.id) : []
|
|
674
|
+
);
|
|
675
|
+
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)(
|
|
676
|
+
ReportStepItem,
|
|
677
|
+
{
|
|
678
|
+
step,
|
|
679
|
+
unasserted: unasserted.has(step.id)
|
|
680
|
+
},
|
|
681
|
+
step.id
|
|
682
|
+
)) });
|
|
664
683
|
}
|
|
665
|
-
function ReportStepItem({
|
|
684
|
+
function ReportStepItem({
|
|
685
|
+
step,
|
|
686
|
+
unasserted = false
|
|
687
|
+
}) {
|
|
666
688
|
const kw = step.keyword.toLowerCase();
|
|
667
689
|
const continuation = kw === "and" || kw === "but";
|
|
668
690
|
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
@@ -670,10 +692,23 @@ function ReportStepItem({ step }) {
|
|
|
670
692
|
{
|
|
671
693
|
id: step.id,
|
|
672
694
|
"data-status": step.status,
|
|
673
|
-
className: cn(
|
|
695
|
+
className: cn(
|
|
696
|
+
"py-1.5 text-[0.8125rem] leading-normal",
|
|
697
|
+
continuation && "pl-5"
|
|
698
|
+
),
|
|
674
699
|
children: [
|
|
675
700
|
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-baseline gap-2", children: [
|
|
676
|
-
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
701
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
702
|
+
"span",
|
|
703
|
+
{
|
|
704
|
+
"aria-hidden": true,
|
|
705
|
+
className: cn(
|
|
706
|
+
"w-4 shrink-0 text-center text-xs",
|
|
707
|
+
STEP_GLYPH_COLOR[step.status]
|
|
708
|
+
),
|
|
709
|
+
children: STEP_GLYPH[step.status] ?? "\u25CB"
|
|
710
|
+
}
|
|
711
|
+
),
|
|
677
712
|
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
678
713
|
"span",
|
|
679
714
|
{
|
|
@@ -685,6 +720,7 @@ function ReportStepItem({ step }) {
|
|
|
685
720
|
}
|
|
686
721
|
),
|
|
687
722
|
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
|
|
723
|
+
unasserted ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "shrink-0 rounded-full border border-pend-border bg-pend-bg px-2 py-0.5 text-[0.6875rem] font-medium text-pend", children: "No assertion" }) : null,
|
|
688
724
|
step.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: (0, import_duration.formatDuration)(step.durationMs) }) : null
|
|
689
725
|
] }),
|
|
690
726
|
step.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
@@ -1080,28 +1116,102 @@ function ScenarioRunHistory({ scenarioId }) {
|
|
|
1080
1116
|
] });
|
|
1081
1117
|
}
|
|
1082
1118
|
|
|
1083
|
-
// src/
|
|
1119
|
+
// src/components/ScenarioStaleness.tsx
|
|
1120
|
+
var import_react7 = require("react");
|
|
1121
|
+
|
|
1122
|
+
// src/lib/provenance.ts
|
|
1123
|
+
function formatRelativeAge(thenMs, nowMs) {
|
|
1124
|
+
const deltaMs = Math.max(0, nowMs - thenMs);
|
|
1125
|
+
const minutes = Math.floor(deltaMs / 6e4);
|
|
1126
|
+
if (minutes < 1) return "just now";
|
|
1127
|
+
if (minutes < 60) return `${minutes} minute${minutes === 1 ? "" : "s"} ago`;
|
|
1128
|
+
const hours = Math.floor(minutes / 60);
|
|
1129
|
+
if (hours < 24) return `${hours} hour${hours === 1 ? "" : "s"} ago`;
|
|
1130
|
+
const days = Math.floor(hours / 24);
|
|
1131
|
+
return `${days} day${days === 1 ? "" : "s"} ago`;
|
|
1132
|
+
}
|
|
1133
|
+
function isReportStale(lastRunMs, staleAfterDays, nowMs) {
|
|
1134
|
+
if (lastRunMs === void 0 || staleAfterDays <= 0) return false;
|
|
1135
|
+
return nowMs - lastRunMs >= staleAfterDays * 864e5;
|
|
1136
|
+
}
|
|
1137
|
+
var CI_DISPLAY_NAMES = {
|
|
1138
|
+
github: "GitHub Actions",
|
|
1139
|
+
gitlab: "GitLab CI",
|
|
1140
|
+
circleci: "CircleCI",
|
|
1141
|
+
jenkins: "Jenkins",
|
|
1142
|
+
azure: "Azure DevOps",
|
|
1143
|
+
buildkite: "Buildkite",
|
|
1144
|
+
travis: "Travis CI",
|
|
1145
|
+
ci: "CI"
|
|
1146
|
+
};
|
|
1147
|
+
function ciDisplayName(name) {
|
|
1148
|
+
return CI_DISPLAY_NAMES[name] ?? name;
|
|
1149
|
+
}
|
|
1150
|
+
function commitUrl(ci, sha) {
|
|
1151
|
+
const commitSha = ci?.commitSha ?? sha;
|
|
1152
|
+
if (!ci?.url || !commitSha) return void 0;
|
|
1153
|
+
const github = ci.url.match(/^(https?:\/\/[^/]+\/[^/]+\/[^/]+)\/actions\/runs\//);
|
|
1154
|
+
if (github) return `${github[1]}/commit/${commitSha}`;
|
|
1155
|
+
const gitlab = ci.url.match(/^(https?:\/\/.+)\/-\/pipelines\//);
|
|
1156
|
+
if (gitlab) return `${gitlab[1]}/-/commit/${commitSha}`;
|
|
1157
|
+
return void 0;
|
|
1158
|
+
}
|
|
1159
|
+
function prUrl(ci) {
|
|
1160
|
+
if (!ci?.url || !ci.prNumber) return void 0;
|
|
1161
|
+
const github = ci.url.match(/^(https?:\/\/[^/]+\/[^/]+\/[^/]+)\/actions\/runs\//);
|
|
1162
|
+
if (github) return `${github[1]}/pull/${ci.prNumber}`;
|
|
1163
|
+
return void 0;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
// src/interactive/scenario-freshness-context.tsx
|
|
1084
1167
|
var import_react6 = require("react");
|
|
1085
|
-
var
|
|
1168
|
+
var ScenarioFreshnessContext = (0, import_react6.createContext)(null);
|
|
1169
|
+
var ScenarioFreshnessProvider = ScenarioFreshnessContext.Provider;
|
|
1170
|
+
function useScenarioFreshness() {
|
|
1171
|
+
return (0, import_react6.useContext)(ScenarioFreshnessContext);
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
// src/components/ScenarioStaleness.tsx
|
|
1175
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
1176
|
+
function ScenarioStaleness({ scenario }) {
|
|
1177
|
+
const freshness = useScenarioFreshness();
|
|
1178
|
+
const fixedNow = freshness?.nowMs;
|
|
1179
|
+
const [now, setNow] = (0, import_react7.useState)(fixedNow);
|
|
1180
|
+
(0, import_react7.useEffect)(() => {
|
|
1181
|
+
if (fixedNow === void 0) setNow(Date.now());
|
|
1182
|
+
}, [fixedNow]);
|
|
1183
|
+
if (!freshness || now === void 0) return null;
|
|
1184
|
+
const lastRunAtMs = scenario.lastRunAtMs;
|
|
1185
|
+
if (!lastRunAtMs || lastRunAtMs <= 0) return null;
|
|
1186
|
+
if (!isReportStale(lastRunAtMs, freshness.staleAfterDays, now)) return null;
|
|
1187
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(Badge, { variant: "outline", "aria-label": "Scenario freshness", children: [
|
|
1188
|
+
"Last ran ",
|
|
1189
|
+
formatRelativeAge(lastRunAtMs, now)
|
|
1190
|
+
] });
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
// src/interactive/collapse-context.ts
|
|
1194
|
+
var import_react8 = require("react");
|
|
1195
|
+
var CollapseContext = (0, import_react8.createContext)(null);
|
|
1086
1196
|
var CollapseProvider = CollapseContext.Provider;
|
|
1087
1197
|
function useCollapse() {
|
|
1088
|
-
return (0,
|
|
1198
|
+
return (0, import_react8.useContext)(CollapseContext);
|
|
1089
1199
|
}
|
|
1090
1200
|
|
|
1091
1201
|
// src/interactive/scenario-actions.tsx
|
|
1092
|
-
var
|
|
1202
|
+
var import_react9 = require("react");
|
|
1093
1203
|
var import_scenario_markdown = require("executable-stories-core/utils/scenario-markdown");
|
|
1094
|
-
var ScenarioActionsContext = (0,
|
|
1204
|
+
var ScenarioActionsContext = (0, import_react9.createContext)(null);
|
|
1095
1205
|
var ScenarioActionsProvider = ScenarioActionsContext.Provider;
|
|
1096
1206
|
function useScenarioActions() {
|
|
1097
|
-
return (0,
|
|
1207
|
+
return (0, import_react9.useContext)(ScenarioActionsContext);
|
|
1098
1208
|
}
|
|
1099
1209
|
|
|
1100
1210
|
// src/components/ui/card.tsx
|
|
1101
1211
|
var React2 = require("react");
|
|
1102
|
-
var
|
|
1212
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1103
1213
|
function Card({ className, ...props }) {
|
|
1104
|
-
return /* @__PURE__ */ (0,
|
|
1214
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1105
1215
|
"div",
|
|
1106
1216
|
{
|
|
1107
1217
|
"data-slot": "card",
|
|
@@ -1114,7 +1224,7 @@ function Card({ className, ...props }) {
|
|
|
1114
1224
|
);
|
|
1115
1225
|
}
|
|
1116
1226
|
function CardHeader({ className, ...props }) {
|
|
1117
|
-
return /* @__PURE__ */ (0,
|
|
1227
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1118
1228
|
"div",
|
|
1119
1229
|
{
|
|
1120
1230
|
"data-slot": "card-header",
|
|
@@ -1127,7 +1237,7 @@ function CardHeader({ className, ...props }) {
|
|
|
1127
1237
|
);
|
|
1128
1238
|
}
|
|
1129
1239
|
function CardContent({ className, ...props }) {
|
|
1130
|
-
return /* @__PURE__ */ (0,
|
|
1240
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1131
1241
|
"div",
|
|
1132
1242
|
{
|
|
1133
1243
|
"data-slot": "card-content",
|
|
@@ -1141,13 +1251,13 @@ function CardContent({ className, ...props }) {
|
|
|
1141
1251
|
var React3 = require("react");
|
|
1142
1252
|
var import_menu = require("@base-ui/react/menu");
|
|
1143
1253
|
var import_lucide_react = require("lucide-react");
|
|
1144
|
-
var
|
|
1254
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1145
1255
|
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";
|
|
1146
1256
|
function DropdownMenu(props) {
|
|
1147
|
-
return /* @__PURE__ */ (0,
|
|
1257
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_menu.Menu.Root, { "data-slot": "dropdown-menu", ...props });
|
|
1148
1258
|
}
|
|
1149
1259
|
function DropdownMenuTrigger(props) {
|
|
1150
|
-
return /* @__PURE__ */ (0,
|
|
1260
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_menu.Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
|
|
1151
1261
|
}
|
|
1152
1262
|
function DropdownMenuContent({
|
|
1153
1263
|
className,
|
|
@@ -1155,14 +1265,14 @@ function DropdownMenuContent({
|
|
|
1155
1265
|
sideOffset = 4,
|
|
1156
1266
|
...props
|
|
1157
1267
|
}) {
|
|
1158
|
-
return /* @__PURE__ */ (0,
|
|
1268
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_menu.Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1159
1269
|
import_menu.Menu.Positioner,
|
|
1160
1270
|
{
|
|
1161
1271
|
"data-slot": "dropdown-menu-positioner",
|
|
1162
1272
|
className: "z-50",
|
|
1163
1273
|
align,
|
|
1164
1274
|
sideOffset,
|
|
1165
|
-
children: /* @__PURE__ */ (0,
|
|
1275
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1166
1276
|
import_menu.Menu.Popup,
|
|
1167
1277
|
{
|
|
1168
1278
|
"data-slot": "dropdown-menu-content",
|
|
@@ -1180,7 +1290,7 @@ function DropdownMenuItem({
|
|
|
1180
1290
|
className,
|
|
1181
1291
|
...props
|
|
1182
1292
|
}) {
|
|
1183
|
-
return /* @__PURE__ */ (0,
|
|
1293
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1184
1294
|
import_menu.Menu.Item,
|
|
1185
1295
|
{
|
|
1186
1296
|
"data-slot": "dropdown-menu-item",
|
|
@@ -1192,7 +1302,7 @@ function DropdownMenuItem({
|
|
|
1192
1302
|
|
|
1193
1303
|
// src/components/ReportScenario.tsx
|
|
1194
1304
|
var import_lucide_react2 = require("lucide-react");
|
|
1195
|
-
var
|
|
1305
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1196
1306
|
var STATUS_META = {
|
|
1197
1307
|
passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
|
|
1198
1308
|
failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
|
|
@@ -1208,7 +1318,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1208
1318
|
const collapsible = collapse !== null && !hideTitle;
|
|
1209
1319
|
const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
|
|
1210
1320
|
const actions = useScenarioActions();
|
|
1211
|
-
return /* @__PURE__ */ (0,
|
|
1321
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
1212
1322
|
Card,
|
|
1213
1323
|
{
|
|
1214
1324
|
id: scenario.id,
|
|
@@ -1216,10 +1326,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1216
1326
|
...hideTitle ? { "aria-label": `${scenario.title}, ${label}` } : { "aria-labelledby": titleId },
|
|
1217
1327
|
className: "gap-0 py-0",
|
|
1218
1328
|
children: [
|
|
1219
|
-
/* @__PURE__ */ (0,
|
|
1220
|
-
/* @__PURE__ */ (0,
|
|
1221
|
-
hideTitle ? null : /* @__PURE__ */ (0,
|
|
1222
|
-
collapsible ? /* @__PURE__ */ (0,
|
|
1329
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(CardHeader, { className: "px-4 py-3", children: [
|
|
1330
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
|
|
1331
|
+
hideTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
|
|
1332
|
+
collapsible ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1223
1333
|
"button",
|
|
1224
1334
|
{
|
|
1225
1335
|
type: "button",
|
|
@@ -1228,49 +1338,50 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1228
1338
|
"aria-controls": bodyId,
|
|
1229
1339
|
"aria-label": `Toggle ${scenario.title}`,
|
|
1230
1340
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
1231
|
-
children: /* @__PURE__ */ (0,
|
|
1341
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
1232
1342
|
}
|
|
1233
1343
|
) : null,
|
|
1234
|
-
/* @__PURE__ */ (0,
|
|
1235
|
-
/* @__PURE__ */ (0,
|
|
1344
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
|
|
1345
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { children: scenario.title })
|
|
1236
1346
|
] }),
|
|
1237
|
-
/* @__PURE__ */ (0,
|
|
1238
|
-
/* @__PURE__ */ (0,
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1347
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
1348
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ScenarioRunHistory, { scenarioId: scenario.id }),
|
|
1349
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ScenarioStaleness, { scenario }),
|
|
1350
|
+
scenario.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: (0, import_duration3.formatDuration)(scenario.durationMs) }) : null,
|
|
1351
|
+
meta.showPill ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "sr-only", children: `Status: ${label}` }),
|
|
1352
|
+
actions ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(DropdownMenu, { children: [
|
|
1353
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1243
1354
|
DropdownMenuTrigger,
|
|
1244
1355
|
{
|
|
1245
1356
|
"aria-label": `Actions for ${scenario.title}`,
|
|
1246
1357
|
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
1247
|
-
children: /* @__PURE__ */ (0,
|
|
1358
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react2.MoreHorizontalIcon, { "aria-hidden": true })
|
|
1248
1359
|
}
|
|
1249
1360
|
),
|
|
1250
|
-
/* @__PURE__ */ (0,
|
|
1251
|
-
/* @__PURE__ */ (0,
|
|
1252
|
-
/* @__PURE__ */ (0,
|
|
1361
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(DropdownMenuContent, { align: "end", children: [
|
|
1362
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
|
|
1363
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react2.LinkIcon, {}),
|
|
1253
1364
|
" Copy link"
|
|
1254
1365
|
] }),
|
|
1255
|
-
/* @__PURE__ */ (0,
|
|
1256
|
-
/* @__PURE__ */ (0,
|
|
1366
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
|
|
1367
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react2.FileTextIcon, {}),
|
|
1257
1368
|
" Copy as Markdown"
|
|
1258
1369
|
] }),
|
|
1259
|
-
/* @__PURE__ */ (0,
|
|
1260
|
-
/* @__PURE__ */ (0,
|
|
1370
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
|
|
1371
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react2.SparklesIcon, {}),
|
|
1261
1372
|
" Explain with AI"
|
|
1262
1373
|
] })
|
|
1263
1374
|
] })
|
|
1264
1375
|
] }) : null
|
|
1265
1376
|
] })
|
|
1266
1377
|
] }),
|
|
1267
|
-
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0,
|
|
1268
|
-
scenario.tags.map((t) => /* @__PURE__ */ (0,
|
|
1269
|
-
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0,
|
|
1378
|
+
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
|
|
1379
|
+
scenario.tags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
|
|
1380
|
+
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("li", { children: ticket.url ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
|
|
1270
1381
|
] }) : null
|
|
1271
1382
|
] }),
|
|
1272
|
-
/* @__PURE__ */ (0,
|
|
1273
|
-
scenario.errorMessage ? /* @__PURE__ */ (0,
|
|
1383
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
|
|
1384
|
+
scenario.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1274
1385
|
"pre",
|
|
1275
1386
|
{
|
|
1276
1387
|
role: "alert",
|
|
@@ -1278,11 +1389,11 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1278
1389
|
children: scenario.errorMessage
|
|
1279
1390
|
}
|
|
1280
1391
|
) : null,
|
|
1281
|
-
/* @__PURE__ */ (0,
|
|
1282
|
-
/* @__PURE__ */ (0,
|
|
1283
|
-
scenario.docEntries.length > 0 ? /* @__PURE__ */ (0,
|
|
1284
|
-
/* @__PURE__ */ (0,
|
|
1285
|
-
/* @__PURE__ */ (0,
|
|
1392
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ReportStoryboard, { scenario }),
|
|
1393
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ReportSteps, { scenario }),
|
|
1394
|
+
scenario.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
|
|
1395
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ReportAttachments, { attachments: scenario.attachments }),
|
|
1396
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ReportTrace, { spans: scenario.otelSpans })
|
|
1286
1397
|
] })
|
|
1287
1398
|
]
|
|
1288
1399
|
}
|
|
@@ -1290,13 +1401,40 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1290
1401
|
}
|
|
1291
1402
|
|
|
1292
1403
|
// src/components/ReportScenarioList.tsx
|
|
1293
|
-
var
|
|
1404
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1294
1405
|
function ReportScenarioList({ feature }) {
|
|
1295
|
-
return /* @__PURE__ */ (0,
|
|
1406
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_jsx_runtime28.Fragment, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ReportScenario, { scenario }, scenario.id)) });
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
// src/components/ReportFeatureIntro.tsx
|
|
1410
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
1411
|
+
function ReportFeatureIntro({ feature }) {
|
|
1412
|
+
const hasNarrative = Boolean(feature.narrative?.trim());
|
|
1413
|
+
const hasGlossary = Boolean(feature.glossary?.length);
|
|
1414
|
+
if (!hasNarrative && !hasGlossary) return null;
|
|
1415
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-3 border-l-2 border-border pl-4 text-sm", children: [
|
|
1416
|
+
hasNarrative ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
1417
|
+
"div",
|
|
1418
|
+
{
|
|
1419
|
+
className: "es-doc-prose prose prose-sm max-w-none text-muted-foreground",
|
|
1420
|
+
dangerouslySetInnerHTML: { __html: safeMarkdownHtml(dedent(feature.narrative)) }
|
|
1421
|
+
}
|
|
1422
|
+
) : null,
|
|
1423
|
+
hasGlossary ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("dl", { className: "grid gap-1.5", "aria-label": "Glossary", children: feature.glossary.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-wrap gap-x-2 text-xs", children: [
|
|
1424
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("dt", { className: "font-medium text-foreground", children: entry.term }),
|
|
1425
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("dd", { className: "flex-1 text-muted-foreground", children: entry.definition })
|
|
1426
|
+
] }, entry.term)) }) : null
|
|
1427
|
+
] });
|
|
1428
|
+
}
|
|
1429
|
+
function featureKindLabel(kind) {
|
|
1430
|
+
if (kind === "ability") return "Ability";
|
|
1431
|
+
if (kind === "business-need") return "Business need";
|
|
1432
|
+
if (kind === "feature") return "Feature";
|
|
1433
|
+
return null;
|
|
1296
1434
|
}
|
|
1297
1435
|
|
|
1298
1436
|
// src/components/ReportFeature.tsx
|
|
1299
|
-
var
|
|
1437
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
1300
1438
|
function ReportFeature({ feature }) {
|
|
1301
1439
|
const titleId = `${feature.id}-title`;
|
|
1302
1440
|
const bodyId = `${feature.id}-body`;
|
|
@@ -1304,10 +1442,11 @@ function ReportFeature({ feature }) {
|
|
|
1304
1442
|
const skipped = s.skipped + s.pending;
|
|
1305
1443
|
const collapse = useCollapse();
|
|
1306
1444
|
const collapsed = collapse?.isCollapsed(feature.id) ?? false;
|
|
1445
|
+
const kindLabel = featureKindLabel(feature.kind);
|
|
1307
1446
|
return (
|
|
1308
1447
|
// Suite = a section heading + a divider, NOT another bordered card. Drops a
|
|
1309
1448
|
// layer of nesting so the scenario cards below read as the primary unit.
|
|
1310
|
-
/* @__PURE__ */ (0,
|
|
1449
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
|
|
1311
1450
|
"section",
|
|
1312
1451
|
{
|
|
1313
1452
|
id: feature.id,
|
|
@@ -1315,9 +1454,9 @@ function ReportFeature({ feature }) {
|
|
|
1315
1454
|
"aria-labelledby": titleId,
|
|
1316
1455
|
className: "flex flex-col gap-3",
|
|
1317
1456
|
children: [
|
|
1318
|
-
/* @__PURE__ */ (0,
|
|
1319
|
-
/* @__PURE__ */ (0,
|
|
1320
|
-
/* @__PURE__ */ (0,
|
|
1457
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
|
|
1458
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "min-w-0", children: [
|
|
1459
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
|
|
1321
1460
|
"button",
|
|
1322
1461
|
{
|
|
1323
1462
|
type: "button",
|
|
@@ -1326,31 +1465,34 @@ function ReportFeature({ feature }) {
|
|
|
1326
1465
|
"aria-controls": bodyId,
|
|
1327
1466
|
className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
|
|
1328
1467
|
children: [
|
|
1329
|
-
/* @__PURE__ */ (0,
|
|
1330
|
-
/* @__PURE__ */ (0,
|
|
1468
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
|
|
1469
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "truncate", children: feature.title })
|
|
1331
1470
|
]
|
|
1332
1471
|
}
|
|
1333
1472
|
) : feature.title }),
|
|
1334
|
-
/* @__PURE__ */ (0,
|
|
1473
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("p", { className: cn("mt-0.5 flex items-center gap-2 text-xs text-muted-foreground", collapse && "pl-5"), children: [
|
|
1474
|
+
kindLabel ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "shrink-0 rounded-sm bg-muted px-1.5 py-0.5 font-medium text-foreground", children: kindLabel }) : null,
|
|
1475
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "truncate font-mono", children: feature.sourceFile })
|
|
1476
|
+
] })
|
|
1335
1477
|
] }),
|
|
1336
|
-
/* @__PURE__ */ (0,
|
|
1478
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
|
|
1337
1479
|
"p",
|
|
1338
1480
|
{
|
|
1339
1481
|
className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
|
|
1340
1482
|
"aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
|
|
1341
1483
|
children: [
|
|
1342
|
-
/* @__PURE__ */ (0,
|
|
1484
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { children: [
|
|
1343
1485
|
s.passed,
|
|
1344
1486
|
" passed"
|
|
1345
1487
|
] }),
|
|
1346
|
-
/* @__PURE__ */ (0,
|
|
1347
|
-
/* @__PURE__ */ (0,
|
|
1488
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1489
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
|
|
1348
1490
|
s.failed,
|
|
1349
1491
|
" failed"
|
|
1350
1492
|
] }),
|
|
1351
|
-
skipped > 0 ? /* @__PURE__ */ (0,
|
|
1352
|
-
/* @__PURE__ */ (0,
|
|
1353
|
-
/* @__PURE__ */ (0,
|
|
1493
|
+
skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_jsx_runtime30.Fragment, { children: [
|
|
1494
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1495
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("span", { children: [
|
|
1354
1496
|
skipped,
|
|
1355
1497
|
" skipped"
|
|
1356
1498
|
] })
|
|
@@ -1359,7 +1501,10 @@ function ReportFeature({ feature }) {
|
|
|
1359
1501
|
}
|
|
1360
1502
|
)
|
|
1361
1503
|
] }),
|
|
1362
|
-
/* @__PURE__ */ (0,
|
|
1504
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: [
|
|
1505
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ReportFeatureIntro, { feature }),
|
|
1506
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ReportScenarioList, { feature })
|
|
1507
|
+
] })
|
|
1363
1508
|
]
|
|
1364
1509
|
}
|
|
1365
1510
|
)
|
|
@@ -1367,17 +1512,17 @@ function ReportFeature({ feature }) {
|
|
|
1367
1512
|
}
|
|
1368
1513
|
|
|
1369
1514
|
// src/components/ReportFeatureList.tsx
|
|
1370
|
-
var
|
|
1515
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
1371
1516
|
function ReportFeatureList() {
|
|
1372
1517
|
const report = useReport();
|
|
1373
|
-
return /* @__PURE__ */ (0,
|
|
1518
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ReportFeature, { feature }, feature.id)) });
|
|
1374
1519
|
}
|
|
1375
1520
|
|
|
1376
1521
|
// src/components/ui/empty.tsx
|
|
1377
1522
|
var import_class_variance_authority2 = require("class-variance-authority");
|
|
1378
|
-
var
|
|
1523
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
1379
1524
|
function Empty({ className, ...props }) {
|
|
1380
|
-
return /* @__PURE__ */ (0,
|
|
1525
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
1381
1526
|
"div",
|
|
1382
1527
|
{
|
|
1383
1528
|
"data-slot": "empty",
|
|
@@ -1390,7 +1535,7 @@ function Empty({ className, ...props }) {
|
|
|
1390
1535
|
);
|
|
1391
1536
|
}
|
|
1392
1537
|
function EmptyHeader({ className, ...props }) {
|
|
1393
|
-
return /* @__PURE__ */ (0,
|
|
1538
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
1394
1539
|
"div",
|
|
1395
1540
|
{
|
|
1396
1541
|
"data-slot": "empty-header",
|
|
@@ -1417,7 +1562,7 @@ var emptyMediaVariants = (0, import_class_variance_authority2.cva)(
|
|
|
1417
1562
|
}
|
|
1418
1563
|
);
|
|
1419
1564
|
function EmptyTitle({ className, ...props }) {
|
|
1420
|
-
return /* @__PURE__ */ (0,
|
|
1565
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
1421
1566
|
"div",
|
|
1422
1567
|
{
|
|
1423
1568
|
"data-slot": "empty-title",
|
|
@@ -1428,16 +1573,16 @@ function EmptyTitle({ className, ...props }) {
|
|
|
1428
1573
|
}
|
|
1429
1574
|
|
|
1430
1575
|
// src/components/ReportEmpty.tsx
|
|
1431
|
-
var
|
|
1576
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
1432
1577
|
function ReportEmpty({ message }) {
|
|
1433
|
-
return /* @__PURE__ */ (0,
|
|
1578
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(EmptyHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
|
|
1434
1579
|
}
|
|
1435
1580
|
|
|
1436
1581
|
// src/components/ReportSummary.tsx
|
|
1437
|
-
var
|
|
1582
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
1438
1583
|
function ReportSummary({ className }) {
|
|
1439
1584
|
const report = useReport();
|
|
1440
|
-
return /* @__PURE__ */ (0,
|
|
1585
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
1441
1586
|
ReportSummaryView,
|
|
1442
1587
|
{
|
|
1443
1588
|
summary: report.summary,
|
|
@@ -1463,7 +1608,7 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1463
1608
|
if (summary.pending > 0) {
|
|
1464
1609
|
cards.push({ status: "pending", label: "Pending", value: summary.pending });
|
|
1465
1610
|
}
|
|
1466
|
-
return /* @__PURE__ */ (0,
|
|
1611
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
1467
1612
|
"dl",
|
|
1468
1613
|
{
|
|
1469
1614
|
className: cn(
|
|
@@ -1476,17 +1621,17 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1476
1621
|
"aria-label": ariaLabel,
|
|
1477
1622
|
children: cards.map((c) => {
|
|
1478
1623
|
const tone = TONE[c.status];
|
|
1479
|
-
return /* @__PURE__ */ (0,
|
|
1624
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
1480
1625
|
"div",
|
|
1481
1626
|
{
|
|
1482
1627
|
"data-status": c.status,
|
|
1483
1628
|
className: "rounded-lg border bg-card px-4 py-3",
|
|
1484
1629
|
children: [
|
|
1485
|
-
/* @__PURE__ */ (0,
|
|
1486
|
-
/* @__PURE__ */ (0,
|
|
1630
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
|
|
1631
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
|
|
1487
1632
|
c.label
|
|
1488
1633
|
] }),
|
|
1489
|
-
/* @__PURE__ */ (0,
|
|
1634
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
|
|
1490
1635
|
]
|
|
1491
1636
|
},
|
|
1492
1637
|
c.status
|
|
@@ -1498,39 +1643,7 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1498
1643
|
|
|
1499
1644
|
// src/components/ReportMeta.tsx
|
|
1500
1645
|
var import_duration4 = require("executable-stories-core/utils/duration");
|
|
1501
|
-
|
|
1502
|
-
// src/lib/provenance.ts
|
|
1503
|
-
var CI_DISPLAY_NAMES = {
|
|
1504
|
-
github: "GitHub Actions",
|
|
1505
|
-
gitlab: "GitLab CI",
|
|
1506
|
-
circleci: "CircleCI",
|
|
1507
|
-
jenkins: "Jenkins",
|
|
1508
|
-
azure: "Azure DevOps",
|
|
1509
|
-
buildkite: "Buildkite",
|
|
1510
|
-
travis: "Travis CI",
|
|
1511
|
-
ci: "CI"
|
|
1512
|
-
};
|
|
1513
|
-
function ciDisplayName(name) {
|
|
1514
|
-
return CI_DISPLAY_NAMES[name] ?? name;
|
|
1515
|
-
}
|
|
1516
|
-
function commitUrl(ci, sha) {
|
|
1517
|
-
const commitSha = ci?.commitSha ?? sha;
|
|
1518
|
-
if (!ci?.url || !commitSha) return void 0;
|
|
1519
|
-
const github = ci.url.match(/^(https?:\/\/[^/]+\/[^/]+\/[^/]+)\/actions\/runs\//);
|
|
1520
|
-
if (github) return `${github[1]}/commit/${commitSha}`;
|
|
1521
|
-
const gitlab = ci.url.match(/^(https?:\/\/.+)\/-\/pipelines\//);
|
|
1522
|
-
if (gitlab) return `${gitlab[1]}/-/commit/${commitSha}`;
|
|
1523
|
-
return void 0;
|
|
1524
|
-
}
|
|
1525
|
-
function prUrl(ci) {
|
|
1526
|
-
if (!ci?.url || !ci.prNumber) return void 0;
|
|
1527
|
-
const github = ci.url.match(/^(https?:\/\/[^/]+\/[^/]+\/[^/]+)\/actions\/runs\//);
|
|
1528
|
-
if (github) return `${github[1]}/pull/${ci.prNumber}`;
|
|
1529
|
-
return void 0;
|
|
1530
|
-
}
|
|
1531
|
-
|
|
1532
|
-
// src/components/ReportMeta.tsx
|
|
1533
|
-
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
1646
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
1534
1647
|
function ReportMeta() {
|
|
1535
1648
|
const report = useReport();
|
|
1536
1649
|
const items = [];
|
|
@@ -1553,13 +1666,13 @@ function ReportMeta() {
|
|
|
1553
1666
|
const short = sha.slice(0, 8);
|
|
1554
1667
|
items.push({
|
|
1555
1668
|
label: "Commit",
|
|
1556
|
-
value: url ? /* @__PURE__ */ (0,
|
|
1669
|
+
value: url ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
|
|
1557
1670
|
});
|
|
1558
1671
|
}
|
|
1559
1672
|
if (report.ci) {
|
|
1560
1673
|
items.push({
|
|
1561
1674
|
label: "CI",
|
|
1562
|
-
value: report.ci.url ? /* @__PURE__ */ (0,
|
|
1675
|
+
value: report.ci.url ? /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
|
|
1563
1676
|
ciDisplayName(report.ci.name),
|
|
1564
1677
|
report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
|
|
1565
1678
|
] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
|
|
@@ -1570,7 +1683,7 @@ function ReportMeta() {
|
|
|
1570
1683
|
const label = `#${report.ci.prNumber}`;
|
|
1571
1684
|
items.push({
|
|
1572
1685
|
label: "PR",
|
|
1573
|
-
value: url ? /* @__PURE__ */ (0,
|
|
1686
|
+
value: url ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
|
|
1574
1687
|
});
|
|
1575
1688
|
}
|
|
1576
1689
|
if (items.length === 0) return null;
|
|
@@ -1578,48 +1691,48 @@ function ReportMeta() {
|
|
|
1578
1691
|
// Run metadata is useful but secondary to "what failed" — tuck it into a
|
|
1579
1692
|
// collapsed disclosure so it doesn't push the result down. Native <details>
|
|
1580
1693
|
// so it works with no JS (the SSR/no-hydration report still toggles).
|
|
1581
|
-
/* @__PURE__ */ (0,
|
|
1582
|
-
/* @__PURE__ */ (0,
|
|
1583
|
-
/* @__PURE__ */ (0,
|
|
1694
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
|
|
1695
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.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: [
|
|
1696
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
|
|
1584
1697
|
"Run details"
|
|
1585
1698
|
] }),
|
|
1586
|
-
/* @__PURE__ */ (0,
|
|
1587
|
-
/* @__PURE__ */ (0,
|
|
1588
|
-
/* @__PURE__ */ (0,
|
|
1699
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.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_runtime35.jsxs)("div", { className: "flex items-baseline gap-1.5", children: [
|
|
1700
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("dt", { className: "font-medium", children: item.label }),
|
|
1701
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("dd", { className: "font-mono text-foreground", children: item.value })
|
|
1589
1702
|
] }, item.label)) })
|
|
1590
1703
|
] })
|
|
1591
1704
|
);
|
|
1592
1705
|
}
|
|
1593
1706
|
|
|
1594
1707
|
// src/components/ReportSchemaError.tsx
|
|
1595
|
-
var
|
|
1708
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
1596
1709
|
function ReportSchemaError({ error }) {
|
|
1597
|
-
return /* @__PURE__ */ (0,
|
|
1598
|
-
/* @__PURE__ */ (0,
|
|
1599
|
-
/* @__PURE__ */ (0,
|
|
1600
|
-
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0,
|
|
1710
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
|
|
1711
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("strong", { children: "Report could not be displayed." }) }),
|
|
1712
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { children: error.message }),
|
|
1713
|
+
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("p", { children: [
|
|
1601
1714
|
"The report bundle is newer than this version of ",
|
|
1602
|
-
/* @__PURE__ */ (0,
|
|
1715
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("code", { children: "executable-stories-react" }),
|
|
1603
1716
|
". Upgrade the package, or regenerate the report with an older formatters CLI."
|
|
1604
1717
|
] }) : null,
|
|
1605
|
-
error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0,
|
|
1606
|
-
/* @__PURE__ */ (0,
|
|
1718
|
+
error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("details", { children: [
|
|
1719
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("summary", { children: [
|
|
1607
1720
|
error.issues.length,
|
|
1608
1721
|
" validation issue",
|
|
1609
1722
|
error.issues.length === 1 ? "" : "s"
|
|
1610
1723
|
] }),
|
|
1611
|
-
/* @__PURE__ */ (0,
|
|
1724
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
|
|
1612
1725
|
] }) : null
|
|
1613
1726
|
] });
|
|
1614
1727
|
}
|
|
1615
1728
|
|
|
1616
1729
|
// src/components/ReportShell.tsx
|
|
1617
|
-
var
|
|
1730
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
1618
1731
|
function ReportTitleBlock({ title }) {
|
|
1619
|
-
return /* @__PURE__ */ (0,
|
|
1620
|
-
/* @__PURE__ */ (0,
|
|
1621
|
-
/* @__PURE__ */ (0,
|
|
1622
|
-
/* @__PURE__ */ (0,
|
|
1732
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_jsx_runtime37.Fragment, { children: [
|
|
1733
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("h1", { children: title ?? "Story Report" }),
|
|
1734
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ReportSummary, {}),
|
|
1735
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ReportMeta, {})
|
|
1623
1736
|
] });
|
|
1624
1737
|
}
|
|
1625
1738
|
function ReportErrorShell({
|
|
@@ -1628,22 +1741,22 @@ function ReportErrorShell({
|
|
|
1628
1741
|
title,
|
|
1629
1742
|
dataTheme
|
|
1630
1743
|
}) {
|
|
1631
|
-
return /* @__PURE__ */ (0,
|
|
1744
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ReportSchemaError, { error }) });
|
|
1632
1745
|
}
|
|
1633
1746
|
|
|
1634
1747
|
// src/components/Report.tsx
|
|
1635
|
-
var
|
|
1748
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
1636
1749
|
function Report(props) {
|
|
1637
1750
|
const { report, customRenderers, renderers, className, title, dataTheme } = props;
|
|
1638
1751
|
const result = unwrapReport(report);
|
|
1639
1752
|
if (!result.ok) {
|
|
1640
|
-
return /* @__PURE__ */ (0,
|
|
1753
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
|
|
1641
1754
|
}
|
|
1642
1755
|
const data = result.data;
|
|
1643
1756
|
const hasContent = data.features.length > 0;
|
|
1644
|
-
return /* @__PURE__ */ (0,
|
|
1645
|
-
/* @__PURE__ */ (0,
|
|
1646
|
-
hasContent ? /* @__PURE__ */ (0,
|
|
1757
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
|
|
1758
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("header", { className: "es-report-header", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ReportTitleBlock, { title }) }),
|
|
1759
|
+
hasContent ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ReportFeatureList, {}) : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ReportEmpty, {})
|
|
1647
1760
|
] }) });
|
|
1648
1761
|
}
|
|
1649
1762
|
|
|
@@ -1704,7 +1817,7 @@ function renderReportToHtml(report, options = {}) {
|
|
|
1704
1817
|
scenarioHistory
|
|
1705
1818
|
} = options;
|
|
1706
1819
|
const markup = (0, import_server.renderToStaticMarkup)(
|
|
1707
|
-
(0,
|
|
1820
|
+
(0, import_react10.createElement)(Report, { report, title })
|
|
1708
1821
|
);
|
|
1709
1822
|
const cdn = cdnAssets(syntaxHighlighting, mermaid);
|
|
1710
1823
|
const parsed = unwrapReport(report);
|