executable-stories-react 0.7.0 → 0.8.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 +418 -226
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -6
- package/dist/index.d.ts +17 -6
- package/dist/index.js +369 -177
- package/dist/index.js.map +1 -1
- package/dist/interactive.cjs +492 -318
- package/dist/interactive.cjs.map +1 -1
- package/dist/interactive.d.cts +10 -1
- package/dist/interactive.d.ts +10 -1
- package/dist/interactive.js +416 -242
- package/dist/interactive.js.map +1 -1
- package/dist/parse.cjs +30 -0
- package/dist/parse.cjs.map +1 -1
- package/dist/parse.d.cts +10 -1
- package/dist/parse.d.ts +10 -1
- package/dist/parse.js +30 -0
- package/dist/parse.js.map +1 -1
- package/dist/report-island.global.js +23 -23
- package/dist/ssr.cjs +356 -194
- package/dist/ssr.cjs.map +1 -1
- package/dist/ssr.d.cts +10 -1
- package/dist/ssr.d.ts +10 -1
- package/dist/ssr.js +316 -154
- package/dist/ssr.js.map +1 -1
- package/dist/tailwind.css +1 -1
- package/package.json +1 -1
package/dist/ssr.cjs
CHANGED
|
@@ -399,17 +399,29 @@ function DocHtml({ entry }) {
|
|
|
399
399
|
] });
|
|
400
400
|
}
|
|
401
401
|
|
|
402
|
-
// src/components/doc/
|
|
402
|
+
// src/components/doc/DocState.tsx
|
|
403
403
|
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
404
|
+
function DocState({ entry }) {
|
|
405
|
+
let json;
|
|
406
|
+
try {
|
|
407
|
+
json = JSON.stringify(entry.value, null, 2) ?? String(entry.value);
|
|
408
|
+
} catch {
|
|
409
|
+
json = String(entry.value);
|
|
410
|
+
}
|
|
411
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CodeFigure, { label: entry.label ?? "State", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("code", { className: "font-mono text-xs language-json", children: json }) });
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// src/components/doc/DocCustom.tsx
|
|
415
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
404
416
|
function DocCustom({ entry }) {
|
|
405
417
|
const renderers = useCustomRenderers();
|
|
406
418
|
const renderer = renderers[entry.type];
|
|
407
419
|
if (renderer) {
|
|
408
|
-
return /* @__PURE__ */ (0,
|
|
420
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_jsx_runtime14.Fragment, { children: renderer(entry) });
|
|
409
421
|
}
|
|
410
|
-
return /* @__PURE__ */ (0,
|
|
411
|
-
/* @__PURE__ */ (0,
|
|
412
|
-
/* @__PURE__ */ (0,
|
|
422
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "my-2", "data-type": entry.type, children: [
|
|
423
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: entry.type }),
|
|
424
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground", children: safeStringify(entry.data) })
|
|
413
425
|
] });
|
|
414
426
|
}
|
|
415
427
|
function safeStringify(value) {
|
|
@@ -421,45 +433,47 @@ function safeStringify(value) {
|
|
|
421
433
|
}
|
|
422
434
|
|
|
423
435
|
// src/components/doc/DocEntry.tsx
|
|
424
|
-
var
|
|
436
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
425
437
|
function DocEntry({ entry }) {
|
|
426
438
|
switch (entry.kind) {
|
|
427
439
|
case "note":
|
|
428
|
-
return /* @__PURE__ */ (0,
|
|
440
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocNote, { entry });
|
|
429
441
|
case "tag":
|
|
430
|
-
return /* @__PURE__ */ (0,
|
|
442
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocTag, { entry });
|
|
431
443
|
case "kv":
|
|
432
|
-
return /* @__PURE__ */ (0,
|
|
444
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocKv, { entry });
|
|
433
445
|
case "code":
|
|
434
|
-
return /* @__PURE__ */ (0,
|
|
446
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocCode, { entry });
|
|
435
447
|
case "table":
|
|
436
|
-
return /* @__PURE__ */ (0,
|
|
448
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocTable, { entry });
|
|
437
449
|
case "link":
|
|
438
|
-
return /* @__PURE__ */ (0,
|
|
450
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocLink, { entry });
|
|
439
451
|
case "section":
|
|
440
|
-
return /* @__PURE__ */ (0,
|
|
452
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocSection, { entry });
|
|
441
453
|
case "mermaid":
|
|
442
|
-
return /* @__PURE__ */ (0,
|
|
454
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocMermaid, { entry });
|
|
443
455
|
case "screenshot":
|
|
444
|
-
return /* @__PURE__ */ (0,
|
|
456
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocScreenshot, { entry });
|
|
445
457
|
case "video":
|
|
446
|
-
return /* @__PURE__ */ (0,
|
|
458
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocVideo, { entry });
|
|
447
459
|
case "html":
|
|
448
|
-
return /* @__PURE__ */ (0,
|
|
460
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocHtml, { entry });
|
|
461
|
+
case "state":
|
|
462
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocState, { entry });
|
|
449
463
|
case "custom":
|
|
450
|
-
return /* @__PURE__ */ (0,
|
|
464
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocCustom, { entry });
|
|
451
465
|
}
|
|
452
466
|
}
|
|
453
467
|
|
|
454
468
|
// src/components/ReportDocEntries.tsx
|
|
455
|
-
var
|
|
469
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
456
470
|
function ReportDocEntries({ entries }) {
|
|
457
471
|
if (entries.length === 0) return null;
|
|
458
|
-
return /* @__PURE__ */ (0,
|
|
472
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children: entries.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocEntry, { entry }, i)) });
|
|
459
473
|
}
|
|
460
474
|
|
|
461
475
|
// src/lib/step-params.tsx
|
|
462
|
-
var
|
|
476
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
463
477
|
var STEP_PARAM_PATTERN = /"[^"]*"|(?<![\w.-])\d+(?:\.\d+)?(?![\w.-])/g;
|
|
464
478
|
function highlightStepParams(text) {
|
|
465
479
|
const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));
|
|
@@ -471,7 +485,7 @@ function highlightStepParams(text) {
|
|
|
471
485
|
const end = start + match[0].length;
|
|
472
486
|
if (start > lastIndex) nodes.push(text.slice(lastIndex, start));
|
|
473
487
|
nodes.push(
|
|
474
|
-
/* @__PURE__ */ (0,
|
|
488
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "font-medium text-step-param italic", children: match[0] }, i)
|
|
475
489
|
);
|
|
476
490
|
lastIndex = end;
|
|
477
491
|
});
|
|
@@ -480,7 +494,7 @@ function highlightStepParams(text) {
|
|
|
480
494
|
}
|
|
481
495
|
|
|
482
496
|
// src/components/ReportSteps.tsx
|
|
483
|
-
var
|
|
497
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
484
498
|
var STEP_GLYPH = {
|
|
485
499
|
passed: "\u2713",
|
|
486
500
|
failed: "\u2717",
|
|
@@ -495,21 +509,21 @@ var STEP_GLYPH_COLOR = {
|
|
|
495
509
|
};
|
|
496
510
|
function ReportSteps({ scenario }) {
|
|
497
511
|
if (scenario.steps.length === 0) return null;
|
|
498
|
-
return /* @__PURE__ */ (0,
|
|
512
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("ol", { "data-slot": "steps", className: "flex flex-col", children: scenario.steps.map((step) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ReportStepItem, { step }, step.id)) });
|
|
499
513
|
}
|
|
500
514
|
function ReportStepItem({ step }) {
|
|
501
515
|
const kw = step.keyword.toLowerCase();
|
|
502
516
|
const continuation = kw === "and" || kw === "but";
|
|
503
|
-
return /* @__PURE__ */ (0,
|
|
517
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
504
518
|
"li",
|
|
505
519
|
{
|
|
506
520
|
id: step.id,
|
|
507
521
|
"data-status": step.status,
|
|
508
522
|
className: cn("py-1.5 text-[0.8125rem] leading-normal", continuation && "pl-5"),
|
|
509
523
|
children: [
|
|
510
|
-
/* @__PURE__ */ (0,
|
|
511
|
-
/* @__PURE__ */ (0,
|
|
512
|
-
/* @__PURE__ */ (0,
|
|
524
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-baseline gap-2", children: [
|
|
525
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.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" }),
|
|
526
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
513
527
|
"span",
|
|
514
528
|
{
|
|
515
529
|
className: cn(
|
|
@@ -519,10 +533,10 @@ function ReportStepItem({ step }) {
|
|
|
519
533
|
children: step.keyword
|
|
520
534
|
}
|
|
521
535
|
),
|
|
522
|
-
/* @__PURE__ */ (0,
|
|
523
|
-
step.durationMs > 0 ? /* @__PURE__ */ (0,
|
|
536
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
|
|
537
|
+
step.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(step.durationMs) }) : null
|
|
524
538
|
] }),
|
|
525
|
-
step.errorMessage ? /* @__PURE__ */ (0,
|
|
539
|
+
step.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
526
540
|
"pre",
|
|
527
541
|
{
|
|
528
542
|
role: "alert",
|
|
@@ -530,12 +544,72 @@ function ReportStepItem({ step }) {
|
|
|
530
544
|
children: step.errorMessage
|
|
531
545
|
}
|
|
532
546
|
) : null,
|
|
533
|
-
step.docEntries.length > 0 ? /* @__PURE__ */ (0,
|
|
547
|
+
step.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { "data-es-docs": true, className: "mt-2 ml-6", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ReportDocEntries, { entries: step.docEntries }) }) : null
|
|
534
548
|
]
|
|
535
549
|
}
|
|
536
550
|
);
|
|
537
551
|
}
|
|
538
552
|
|
|
553
|
+
// ../executable-stories-core/dist/state-diff.js
|
|
554
|
+
var isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
555
|
+
function deepEqual(a, b) {
|
|
556
|
+
if (Object.is(a, b)) return true;
|
|
557
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
558
|
+
return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
|
|
559
|
+
}
|
|
560
|
+
if (isPlainObject(a) && isPlainObject(b)) {
|
|
561
|
+
const ak = Object.keys(a);
|
|
562
|
+
const bk = Object.keys(b);
|
|
563
|
+
return ak.length === bk.length && ak.every((k) => k in b && deepEqual(a[k], b[k]));
|
|
564
|
+
}
|
|
565
|
+
return false;
|
|
566
|
+
}
|
|
567
|
+
var joinKey = (path, key) => path === "" ? key : `${path}.${key}`;
|
|
568
|
+
function walk(path, before, after, out) {
|
|
569
|
+
if (Object.is(before, after)) return;
|
|
570
|
+
if (Array.isArray(before) && Array.isArray(after)) {
|
|
571
|
+
const shared = Math.min(before.length, after.length);
|
|
572
|
+
for (let i = 0; i < shared; i++) walk(`${path}[${i}]`, before[i], after[i], out);
|
|
573
|
+
for (let i = shared; i < after.length; i++) out.push({ path: `${path}[${i}]`, kind: "added", after: after[i] });
|
|
574
|
+
for (let i = shared; i < before.length; i++) out.push({ path: `${path}[${i}]`, kind: "removed", before: before[i] });
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
if (isPlainObject(before) && isPlainObject(after)) {
|
|
578
|
+
for (const key of Object.keys(after)) {
|
|
579
|
+
const p = joinKey(path, key);
|
|
580
|
+
if (key in before) walk(p, before[key], after[key], out);
|
|
581
|
+
else out.push({ path: p, kind: "added", after: after[key] });
|
|
582
|
+
}
|
|
583
|
+
for (const key of Object.keys(before)) {
|
|
584
|
+
if (!(key in after)) out.push({ path: joinKey(path, key), kind: "removed", before: before[key] });
|
|
585
|
+
}
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
if (!deepEqual(before, after)) out.push({ path, kind: "changed", before, after });
|
|
589
|
+
}
|
|
590
|
+
function diffStateValues(before, after) {
|
|
591
|
+
const out = [];
|
|
592
|
+
walk("", before, after, out);
|
|
593
|
+
return out;
|
|
594
|
+
}
|
|
595
|
+
function formatStateValue(value, maxLen = 60) {
|
|
596
|
+
const s = value === void 0 ? "undefined" : JSON.stringify(value);
|
|
597
|
+
return s.length > maxLen ? `${s.slice(0, maxLen - 1)}\u2026` : s;
|
|
598
|
+
}
|
|
599
|
+
function summarizeStateChanges(changes) {
|
|
600
|
+
return changes.map((c) => {
|
|
601
|
+
const at = c.path === "" ? "(root)" : c.path;
|
|
602
|
+
switch (c.kind) {
|
|
603
|
+
case "added":
|
|
604
|
+
return `+ ${at}: ${formatStateValue(c.after)}`;
|
|
605
|
+
case "removed":
|
|
606
|
+
return `\u2212 ${at}`;
|
|
607
|
+
case "changed":
|
|
608
|
+
return `${at}: ${formatStateValue(c.before)} \u2192 ${formatStateValue(c.after)}`;
|
|
609
|
+
}
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
|
|
539
613
|
// ../executable-stories-core/dist/storyboard.js
|
|
540
614
|
function findScreenshot(entries) {
|
|
541
615
|
for (const entry of entries) {
|
|
@@ -547,26 +621,55 @@ function findScreenshot(entries) {
|
|
|
547
621
|
}
|
|
548
622
|
return void 0;
|
|
549
623
|
}
|
|
624
|
+
function findStates(entries, out = []) {
|
|
625
|
+
for (const entry of entries) {
|
|
626
|
+
if (entry.kind === "state") out.push(entry);
|
|
627
|
+
if (entry.children) findStates(entry.children, out);
|
|
628
|
+
}
|
|
629
|
+
return out;
|
|
630
|
+
}
|
|
631
|
+
var laneOf = (label) => label ?? "";
|
|
550
632
|
function extractStoryboardFrames(scenario) {
|
|
551
633
|
const frames = [];
|
|
634
|
+
const laneOrder = [];
|
|
635
|
+
const previous = /* @__PURE__ */ new Map();
|
|
552
636
|
for (const step of scenario.steps) {
|
|
553
637
|
const shot = findScreenshot(step.docEntries);
|
|
554
|
-
|
|
638
|
+
const stateDocs = findStates(step.docEntries);
|
|
639
|
+
if (!shot && stateDocs.length === 0) continue;
|
|
640
|
+
const byLane = /* @__PURE__ */ new Map();
|
|
641
|
+
for (const doc of stateDocs) {
|
|
642
|
+
const lane = laneOf(doc.label);
|
|
643
|
+
if (!byLane.has(lane) && !laneOrder.includes(lane)) laneOrder.push(lane);
|
|
644
|
+
byLane.set(lane, doc);
|
|
645
|
+
}
|
|
646
|
+
const states = [];
|
|
647
|
+
for (const lane of laneOrder) {
|
|
648
|
+
const doc = byLane.get(lane);
|
|
649
|
+
if (!doc) continue;
|
|
650
|
+
const card = {
|
|
651
|
+
...doc.label !== void 0 && { label: doc.label },
|
|
652
|
+
value: doc.value
|
|
653
|
+
};
|
|
654
|
+
if (previous.has(lane)) card.changes = diffStateValues(previous.get(lane), doc.value);
|
|
655
|
+
previous.set(lane, doc.value);
|
|
656
|
+
states.push(card);
|
|
657
|
+
}
|
|
555
658
|
frames.push({
|
|
556
659
|
stepId: step.id,
|
|
557
660
|
stepIndex: step.index,
|
|
558
661
|
keyword: step.keyword,
|
|
559
662
|
text: step.text,
|
|
560
663
|
status: step.status,
|
|
561
|
-
path: shot.path,
|
|
562
|
-
|
|
664
|
+
...shot && { screenshot: { path: shot.path, ...shot.alt !== void 0 && { alt: shot.alt } } },
|
|
665
|
+
states
|
|
563
666
|
});
|
|
564
667
|
}
|
|
565
668
|
return frames;
|
|
566
669
|
}
|
|
567
670
|
|
|
568
671
|
// src/components/ReportStoryboard.tsx
|
|
569
|
-
var
|
|
672
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
570
673
|
var FRAME_GLYPH = {
|
|
571
674
|
passed: "\u2713",
|
|
572
675
|
failed: "\u2717",
|
|
@@ -582,55 +685,114 @@ var FRAME_GLYPH_COLOR = {
|
|
|
582
685
|
function ReportStoryboard({ scenario }) {
|
|
583
686
|
const frames = extractStoryboardFrames(scenario);
|
|
584
687
|
if (frames.length < 2) return null;
|
|
585
|
-
return /* @__PURE__ */ (0,
|
|
586
|
-
/* @__PURE__ */ (0,
|
|
587
|
-
/* @__PURE__ */ (0,
|
|
688
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("section", { "data-slot": "storyboard", "aria-label": "Storyboard", className: "mb-3", children: [
|
|
689
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h4", { className: "mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Storyboard" }),
|
|
690
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("ol", { className: "flex items-start gap-3 overflow-x-auto pb-2", children: frames.map((frame) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(StoryboardFrameItem, { frame }, frame.stepId)) })
|
|
588
691
|
] });
|
|
589
692
|
}
|
|
590
693
|
function StoryboardFrameItem({ frame }) {
|
|
591
|
-
const src = isLocalFsPath(frame.path) ? void 0 : safeImageUrl(frame.path);
|
|
592
694
|
const label = `${frame.keyword} ${frame.text}`;
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
695
|
+
const hasStates = frame.states.length > 0;
|
|
696
|
+
const caption = /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("p", { className: "mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug", children: [
|
|
697
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { "aria-hidden": true, className: cn("shrink-0", FRAME_GLYPH_COLOR[frame.status]), children: FRAME_GLYPH[frame.status] ?? "\u25CB" }),
|
|
698
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "min-w-0", children: [
|
|
699
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "font-mono font-semibold text-keyword", children: frame.keyword }),
|
|
700
|
+
" ",
|
|
701
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-muted-foreground", children: frame.screenshot?.alt ?? frame.text })
|
|
702
|
+
] })
|
|
703
|
+
] });
|
|
704
|
+
return (
|
|
705
|
+
// State cards need room for diff rows; screenshot-only frames keep the
|
|
706
|
+
// original narrow film-cell width (and DOM) unchanged.
|
|
707
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("li", { className: cn("shrink-0", hasStates ? "w-64" : "w-40"), children: [
|
|
708
|
+
frame.screenshot ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(FrameScreenshot, { frame, label }) : null,
|
|
709
|
+
hasStates ? /* @__PURE__ */ (0, import_jsx_runtime19.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_runtime19.jsx)(StateCardView, { card }, card.label ?? i)) }) : null,
|
|
710
|
+
frame.screenshot ? caption : (
|
|
711
|
+
// No screenshot means no image anchor, so the caption carries the
|
|
712
|
+
// jump-to-step link instead.
|
|
713
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("a", { href: `#${frame.stepId}`, "aria-label": `Jump to step: ${label}`, className: "block hover:underline", children: caption })
|
|
714
|
+
)
|
|
715
|
+
] })
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
function FrameScreenshot({ frame, label }) {
|
|
719
|
+
const path = frame.screenshot?.path ?? "";
|
|
720
|
+
const src = isLocalFsPath(path) ? void 0 : safeImageUrl(path);
|
|
721
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
722
|
+
"a",
|
|
723
|
+
{
|
|
724
|
+
href: `#${frame.stepId}`,
|
|
725
|
+
"aria-label": `Jump to step: ${label}`,
|
|
726
|
+
className: "block overflow-hidden rounded-md border border-border transition-colors hover:border-ring",
|
|
727
|
+
children: src ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
728
|
+
"img",
|
|
729
|
+
{
|
|
730
|
+
src,
|
|
731
|
+
alt: frame.screenshot?.alt ?? label,
|
|
732
|
+
loading: "lazy",
|
|
733
|
+
className: "h-24 w-full bg-muted object-cover object-top"
|
|
734
|
+
}
|
|
735
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime19.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" })
|
|
736
|
+
}
|
|
737
|
+
);
|
|
738
|
+
}
|
|
739
|
+
var CHANGE_TONE = {
|
|
740
|
+
added: "bg-pass-bg text-pass",
|
|
741
|
+
removed: "bg-fail-bg text-fail",
|
|
742
|
+
changed: "bg-skip-bg text-skip"
|
|
743
|
+
};
|
|
744
|
+
function prettyJson(value) {
|
|
745
|
+
try {
|
|
746
|
+
return JSON.stringify(value, null, 2) ?? String(value);
|
|
747
|
+
} catch {
|
|
748
|
+
return String(value);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
function StateCardView({ card }) {
|
|
752
|
+
const json = prettyJson(card.value);
|
|
753
|
+
const firstCapture = card.changes === void 0;
|
|
754
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { "data-slot": "state-card", className: "rounded-md border border-border bg-card p-2", children: [
|
|
755
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("p", { className: "flex flex-wrap items-baseline gap-1.5", children: [
|
|
756
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.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" }),
|
|
757
|
+
firstCapture ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-[0.625rem] text-muted-foreground italic", children: "first capture" }) : null
|
|
758
|
+
] }),
|
|
759
|
+
!firstCapture && (card.changes && card.changes.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("ul", { className: "mt-1.5 flex flex-col gap-0.5", children: card.changes.map((change, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
760
|
+
"li",
|
|
596
761
|
{
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
762
|
+
className: cn(
|
|
763
|
+
"rounded-sm px-1.5 py-0.5 font-mono text-[0.625rem] leading-snug break-all",
|
|
764
|
+
CHANGE_TONE[change.kind]
|
|
765
|
+
),
|
|
766
|
+
children: summarizeStateChanges([change])[0]
|
|
767
|
+
},
|
|
768
|
+
i
|
|
769
|
+
)) }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "mt-1.5 text-[0.625rem] text-muted-foreground", children: "No changes" })),
|
|
770
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
771
|
+
"details",
|
|
772
|
+
{
|
|
773
|
+
open: firstCapture && json.length <= 240,
|
|
774
|
+
className: cn(firstCapture ? "mt-1.5" : "mt-1"),
|
|
775
|
+
children: [
|
|
776
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("summary", { className: "cursor-pointer text-[0.625rem] text-muted-foreground hover:text-foreground", children: "Snapshot" }),
|
|
777
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.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 })
|
|
778
|
+
]
|
|
609
779
|
}
|
|
610
|
-
)
|
|
611
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("p", { className: "mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug", children: [
|
|
612
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { "aria-hidden": true, className: cn("shrink-0", FRAME_GLYPH_COLOR[frame.status]), children: FRAME_GLYPH[frame.status] ?? "\u25CB" }),
|
|
613
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "min-w-0", children: [
|
|
614
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "font-mono font-semibold text-keyword", children: frame.keyword }),
|
|
615
|
-
" ",
|
|
616
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-muted-foreground", children: frame.alt ?? frame.text })
|
|
617
|
-
] })
|
|
618
|
-
] })
|
|
780
|
+
)
|
|
619
781
|
] });
|
|
620
782
|
}
|
|
621
783
|
|
|
622
784
|
// src/components/ReportAttachments.tsx
|
|
623
|
-
var
|
|
785
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
624
786
|
function ReportAttachments({ attachments }) {
|
|
625
787
|
if (attachments.length === 0) return null;
|
|
626
788
|
return (
|
|
627
789
|
// role="group" (not a labelled <section>) so multiple scenarios' attachment
|
|
628
790
|
// blocks don't create duplicate "Attachments" region landmarks.
|
|
629
|
-
/* @__PURE__ */ (0,
|
|
791
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
|
|
630
792
|
const dataUri = att.contentEncoding === "BASE64" ? `data:${att.mediaType};base64,${att.body}` : `data:${att.mediaType},${encodeURIComponent(att.body)}`;
|
|
631
793
|
const isImage = att.mediaType.startsWith("image/");
|
|
632
|
-
return /* @__PURE__ */ (0,
|
|
633
|
-
/* @__PURE__ */ (0,
|
|
794
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
|
|
795
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
634
796
|
"img",
|
|
635
797
|
{
|
|
636
798
|
src: dataUri,
|
|
@@ -639,8 +801,8 @@ function ReportAttachments({ attachments }) {
|
|
|
639
801
|
className: "max-w-full rounded-md border border-border"
|
|
640
802
|
}
|
|
641
803
|
),
|
|
642
|
-
/* @__PURE__ */ (0,
|
|
643
|
-
] }) : /* @__PURE__ */ (0,
|
|
804
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
|
|
805
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
644
806
|
"a",
|
|
645
807
|
{
|
|
646
808
|
href: dataUri,
|
|
@@ -649,7 +811,7 @@ function ReportAttachments({ attachments }) {
|
|
|
649
811
|
children: [
|
|
650
812
|
att.name,
|
|
651
813
|
" ",
|
|
652
|
-
/* @__PURE__ */ (0,
|
|
814
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "text-muted-foreground", children: [
|
|
653
815
|
"(",
|
|
654
816
|
att.mediaType,
|
|
655
817
|
")"
|
|
@@ -713,15 +875,15 @@ function toTraceRows(spans) {
|
|
|
713
875
|
roots.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);
|
|
714
876
|
const rows = [];
|
|
715
877
|
const seen = /* @__PURE__ */ new Set();
|
|
716
|
-
const
|
|
878
|
+
const walk2 = (node, depth) => {
|
|
717
879
|
if (seen.has(node.span.spanId)) return;
|
|
718
880
|
seen.add(node.span.spanId);
|
|
719
881
|
rows.push({ ...node.span, depth });
|
|
720
|
-
for (const child of node.children)
|
|
882
|
+
for (const child of node.children) walk2(child, depth + 1);
|
|
721
883
|
};
|
|
722
|
-
for (const root of roots)
|
|
884
|
+
for (const root of roots) walk2(root, 0);
|
|
723
885
|
for (const node of byId.values()) {
|
|
724
|
-
if (!seen.has(node.span.spanId))
|
|
886
|
+
if (!seen.has(node.span.spanId)) walk2(node, 0);
|
|
725
887
|
}
|
|
726
888
|
return rows;
|
|
727
889
|
}
|
|
@@ -737,7 +899,7 @@ function traceWindow(rows) {
|
|
|
737
899
|
}
|
|
738
900
|
|
|
739
901
|
// src/components/ReportTrace.tsx
|
|
740
|
-
var
|
|
902
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
741
903
|
var BAR_COLOR = {
|
|
742
904
|
ok: "bg-pass",
|
|
743
905
|
error: "bg-fail",
|
|
@@ -748,8 +910,8 @@ function ReportTrace({ spans }) {
|
|
|
748
910
|
const rows = toTraceRows(spans);
|
|
749
911
|
if (rows.length === 0) return null;
|
|
750
912
|
const { minStartMs, totalMs } = traceWindow(rows);
|
|
751
|
-
return /* @__PURE__ */ (0,
|
|
752
|
-
/* @__PURE__ */ (0,
|
|
913
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("details", { className: "mt-3 rounded-md border border-border bg-muted/30", children: [
|
|
914
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("summary", { className: "cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground", children: [
|
|
753
915
|
"Trace (",
|
|
754
916
|
rows.length,
|
|
755
917
|
" span",
|
|
@@ -758,11 +920,11 @@ function ReportTrace({ spans }) {
|
|
|
758
920
|
formatDuration(totalMs),
|
|
759
921
|
")"
|
|
760
922
|
] }),
|
|
761
|
-
/* @__PURE__ */ (0,
|
|
923
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
|
|
762
924
|
const leftPct = (row.startTimeMs - minStartMs) / totalMs * 100;
|
|
763
925
|
const widthPct = Math.max(row.durationMs / totalMs * 100, 0.5);
|
|
764
|
-
return /* @__PURE__ */ (0,
|
|
765
|
-
/* @__PURE__ */ (0,
|
|
926
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("li", { className: "flex items-center gap-2", children: [
|
|
927
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
766
928
|
"span",
|
|
767
929
|
{
|
|
768
930
|
className: "min-w-0 flex-1 truncate text-foreground",
|
|
@@ -771,14 +933,14 @@ function ReportTrace({ spans }) {
|
|
|
771
933
|
children: row.name
|
|
772
934
|
}
|
|
773
935
|
),
|
|
774
|
-
/* @__PURE__ */ (0,
|
|
936
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
775
937
|
"span",
|
|
776
938
|
{
|
|
777
939
|
className: cn("absolute top-0 h-full rounded-sm", BAR_COLOR[row.status]),
|
|
778
940
|
style: { left: `${leftPct}%`, width: `${widthPct}%` }
|
|
779
941
|
}
|
|
780
942
|
) }),
|
|
781
|
-
/* @__PURE__ */ (0,
|
|
943
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
|
|
782
944
|
] }, `${row.spanId}-${i}`);
|
|
783
945
|
}) })
|
|
784
946
|
] });
|
|
@@ -829,7 +991,7 @@ function flakinessOf(entries) {
|
|
|
829
991
|
}
|
|
830
992
|
|
|
831
993
|
// src/components/ScenarioRunHistory.tsx
|
|
832
|
-
var
|
|
994
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
833
995
|
var MAX_DOTS = 10;
|
|
834
996
|
var DOT_COLOR = {
|
|
835
997
|
passed: "bg-pass",
|
|
@@ -849,16 +1011,16 @@ function ScenarioRunHistory({ scenarioId }) {
|
|
|
849
1011
|
const recent = entries.slice(-MAX_DOTS);
|
|
850
1012
|
const flaky = flakinessOf(recent) === "flaky";
|
|
851
1013
|
const summary = flaky ? `${describeRunHistory(recent)} \xB7 Flaky` : describeRunHistory(recent);
|
|
852
|
-
return /* @__PURE__ */ (0,
|
|
853
|
-
flaky ? /* @__PURE__ */ (0,
|
|
854
|
-
/* @__PURE__ */ (0,
|
|
1014
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
|
|
1015
|
+
flaky ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
|
|
1016
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
855
1017
|
"span",
|
|
856
1018
|
{
|
|
857
1019
|
role: "img",
|
|
858
1020
|
"aria-label": `Run history: ${summary}`,
|
|
859
1021
|
title: summary,
|
|
860
1022
|
className: "flex shrink-0 items-center gap-[3px]",
|
|
861
|
-
children: recent.map((e, i) => /* @__PURE__ */ (0,
|
|
1023
|
+
children: recent.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
862
1024
|
"span",
|
|
863
1025
|
{
|
|
864
1026
|
"aria-hidden": true,
|
|
@@ -897,9 +1059,9 @@ function useScenarioActions() {
|
|
|
897
1059
|
|
|
898
1060
|
// src/components/ui/card.tsx
|
|
899
1061
|
var React2 = require("react");
|
|
900
|
-
var
|
|
1062
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
901
1063
|
function Card({ className, ...props }) {
|
|
902
|
-
return /* @__PURE__ */ (0,
|
|
1064
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
903
1065
|
"div",
|
|
904
1066
|
{
|
|
905
1067
|
"data-slot": "card",
|
|
@@ -912,7 +1074,7 @@ function Card({ className, ...props }) {
|
|
|
912
1074
|
);
|
|
913
1075
|
}
|
|
914
1076
|
function CardHeader({ className, ...props }) {
|
|
915
|
-
return /* @__PURE__ */ (0,
|
|
1077
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
916
1078
|
"div",
|
|
917
1079
|
{
|
|
918
1080
|
"data-slot": "card-header",
|
|
@@ -925,7 +1087,7 @@ function CardHeader({ className, ...props }) {
|
|
|
925
1087
|
);
|
|
926
1088
|
}
|
|
927
1089
|
function CardContent({ className, ...props }) {
|
|
928
|
-
return /* @__PURE__ */ (0,
|
|
1090
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
929
1091
|
"div",
|
|
930
1092
|
{
|
|
931
1093
|
"data-slot": "card-content",
|
|
@@ -939,13 +1101,13 @@ function CardContent({ className, ...props }) {
|
|
|
939
1101
|
var React3 = require("react");
|
|
940
1102
|
var import_menu = require("@base-ui/react/menu");
|
|
941
1103
|
var import_lucide_react = require("lucide-react");
|
|
942
|
-
var
|
|
1104
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
943
1105
|
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";
|
|
944
1106
|
function DropdownMenu(props) {
|
|
945
|
-
return /* @__PURE__ */ (0,
|
|
1107
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_menu.Menu.Root, { "data-slot": "dropdown-menu", ...props });
|
|
946
1108
|
}
|
|
947
1109
|
function DropdownMenuTrigger(props) {
|
|
948
|
-
return /* @__PURE__ */ (0,
|
|
1110
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_menu.Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
|
|
949
1111
|
}
|
|
950
1112
|
function DropdownMenuContent({
|
|
951
1113
|
className,
|
|
@@ -953,14 +1115,14 @@ function DropdownMenuContent({
|
|
|
953
1115
|
sideOffset = 4,
|
|
954
1116
|
...props
|
|
955
1117
|
}) {
|
|
956
|
-
return /* @__PURE__ */ (0,
|
|
1118
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_menu.Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
957
1119
|
import_menu.Menu.Positioner,
|
|
958
1120
|
{
|
|
959
1121
|
"data-slot": "dropdown-menu-positioner",
|
|
960
1122
|
className: "z-50",
|
|
961
1123
|
align,
|
|
962
1124
|
sideOffset,
|
|
963
|
-
children: /* @__PURE__ */ (0,
|
|
1125
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
964
1126
|
import_menu.Menu.Popup,
|
|
965
1127
|
{
|
|
966
1128
|
"data-slot": "dropdown-menu-content",
|
|
@@ -978,7 +1140,7 @@ function DropdownMenuItem({
|
|
|
978
1140
|
className,
|
|
979
1141
|
...props
|
|
980
1142
|
}) {
|
|
981
|
-
return /* @__PURE__ */ (0,
|
|
1143
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
982
1144
|
import_menu.Menu.Item,
|
|
983
1145
|
{
|
|
984
1146
|
"data-slot": "dropdown-menu-item",
|
|
@@ -990,7 +1152,7 @@ function DropdownMenuItem({
|
|
|
990
1152
|
|
|
991
1153
|
// src/components/ReportScenario.tsx
|
|
992
1154
|
var import_lucide_react2 = require("lucide-react");
|
|
993
|
-
var
|
|
1155
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
994
1156
|
var STATUS_META = {
|
|
995
1157
|
passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
|
|
996
1158
|
failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
|
|
@@ -1006,7 +1168,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1006
1168
|
const collapsible = collapse !== null && !hideTitle;
|
|
1007
1169
|
const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
|
|
1008
1170
|
const actions = useScenarioActions();
|
|
1009
|
-
return /* @__PURE__ */ (0,
|
|
1171
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
1010
1172
|
Card,
|
|
1011
1173
|
{
|
|
1012
1174
|
id: scenario.id,
|
|
@@ -1014,10 +1176,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1014
1176
|
...hideTitle ? { "aria-label": `${scenario.title}, ${label}` } : { "aria-labelledby": titleId },
|
|
1015
1177
|
className: "gap-0 py-0",
|
|
1016
1178
|
children: [
|
|
1017
|
-
/* @__PURE__ */ (0,
|
|
1018
|
-
/* @__PURE__ */ (0,
|
|
1019
|
-
hideTitle ? null : /* @__PURE__ */ (0,
|
|
1020
|
-
collapsible ? /* @__PURE__ */ (0,
|
|
1179
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(CardHeader, { className: "px-4 py-3", children: [
|
|
1180
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
|
|
1181
|
+
hideTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
|
|
1182
|
+
collapsible ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1021
1183
|
"button",
|
|
1022
1184
|
{
|
|
1023
1185
|
type: "button",
|
|
@@ -1026,49 +1188,49 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1026
1188
|
"aria-controls": bodyId,
|
|
1027
1189
|
"aria-label": `Toggle ${scenario.title}`,
|
|
1028
1190
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
1029
|
-
children: /* @__PURE__ */ (0,
|
|
1191
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
1030
1192
|
}
|
|
1031
1193
|
) : null,
|
|
1032
|
-
/* @__PURE__ */ (0,
|
|
1033
|
-
/* @__PURE__ */ (0,
|
|
1194
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
|
|
1195
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: scenario.title })
|
|
1034
1196
|
] }),
|
|
1035
|
-
/* @__PURE__ */ (0,
|
|
1036
|
-
/* @__PURE__ */ (0,
|
|
1037
|
-
scenario.durationMs > 0 ? /* @__PURE__ */ (0,
|
|
1038
|
-
meta.showPill ? /* @__PURE__ */ (0,
|
|
1039
|
-
actions ? /* @__PURE__ */ (0,
|
|
1040
|
-
/* @__PURE__ */ (0,
|
|
1197
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
1198
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ScenarioRunHistory, { scenarioId: scenario.id }),
|
|
1199
|
+
scenario.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
|
|
1200
|
+
meta.showPill ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "sr-only", children: `Status: ${label}` }),
|
|
1201
|
+
actions ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenu, { children: [
|
|
1202
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1041
1203
|
DropdownMenuTrigger,
|
|
1042
1204
|
{
|
|
1043
1205
|
"aria-label": `Actions for ${scenario.title}`,
|
|
1044
1206
|
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
1045
|
-
children: /* @__PURE__ */ (0,
|
|
1207
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react2.MoreHorizontalIcon, { "aria-hidden": true })
|
|
1046
1208
|
}
|
|
1047
1209
|
),
|
|
1048
|
-
/* @__PURE__ */ (0,
|
|
1049
|
-
/* @__PURE__ */ (0,
|
|
1050
|
-
/* @__PURE__ */ (0,
|
|
1210
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenuContent, { align: "end", children: [
|
|
1211
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
|
|
1212
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react2.LinkIcon, {}),
|
|
1051
1213
|
" Copy link"
|
|
1052
1214
|
] }),
|
|
1053
|
-
/* @__PURE__ */ (0,
|
|
1054
|
-
/* @__PURE__ */ (0,
|
|
1215
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
|
|
1216
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react2.FileTextIcon, {}),
|
|
1055
1217
|
" Copy as Markdown"
|
|
1056
1218
|
] }),
|
|
1057
|
-
/* @__PURE__ */ (0,
|
|
1058
|
-
/* @__PURE__ */ (0,
|
|
1219
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
|
|
1220
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react2.SparklesIcon, {}),
|
|
1059
1221
|
" Explain with AI"
|
|
1060
1222
|
] })
|
|
1061
1223
|
] })
|
|
1062
1224
|
] }) : null
|
|
1063
1225
|
] })
|
|
1064
1226
|
] }),
|
|
1065
|
-
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0,
|
|
1066
|
-
scenario.tags.map((t) => /* @__PURE__ */ (0,
|
|
1067
|
-
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0,
|
|
1227
|
+
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
|
|
1228
|
+
scenario.tags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
|
|
1229
|
+
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("li", { children: ticket.url ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
|
|
1068
1230
|
] }) : null
|
|
1069
1231
|
] }),
|
|
1070
|
-
/* @__PURE__ */ (0,
|
|
1071
|
-
scenario.errorMessage ? /* @__PURE__ */ (0,
|
|
1232
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
|
|
1233
|
+
scenario.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1072
1234
|
"pre",
|
|
1073
1235
|
{
|
|
1074
1236
|
role: "alert",
|
|
@@ -1076,11 +1238,11 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1076
1238
|
children: scenario.errorMessage
|
|
1077
1239
|
}
|
|
1078
1240
|
) : null,
|
|
1079
|
-
/* @__PURE__ */ (0,
|
|
1080
|
-
/* @__PURE__ */ (0,
|
|
1081
|
-
scenario.docEntries.length > 0 ? /* @__PURE__ */ (0,
|
|
1082
|
-
/* @__PURE__ */ (0,
|
|
1083
|
-
/* @__PURE__ */ (0,
|
|
1241
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportStoryboard, { scenario }),
|
|
1242
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportSteps, { scenario }),
|
|
1243
|
+
scenario.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
|
|
1244
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportAttachments, { attachments: scenario.attachments }),
|
|
1245
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportTrace, { spans: scenario.otelSpans })
|
|
1084
1246
|
] })
|
|
1085
1247
|
]
|
|
1086
1248
|
}
|
|
@@ -1088,13 +1250,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1088
1250
|
}
|
|
1089
1251
|
|
|
1090
1252
|
// src/components/ReportScenarioList.tsx
|
|
1091
|
-
var
|
|
1253
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1092
1254
|
function ReportScenarioList({ feature }) {
|
|
1093
|
-
return /* @__PURE__ */ (0,
|
|
1255
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_jsx_runtime26.Fragment, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportScenario, { scenario }, scenario.id)) });
|
|
1094
1256
|
}
|
|
1095
1257
|
|
|
1096
1258
|
// src/components/ReportFeature.tsx
|
|
1097
|
-
var
|
|
1259
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1098
1260
|
function ReportFeature({ feature }) {
|
|
1099
1261
|
const titleId = `${feature.id}-title`;
|
|
1100
1262
|
const bodyId = `${feature.id}-body`;
|
|
@@ -1105,7 +1267,7 @@ function ReportFeature({ feature }) {
|
|
|
1105
1267
|
return (
|
|
1106
1268
|
// Suite = a section heading + a divider, NOT another bordered card. Drops a
|
|
1107
1269
|
// layer of nesting so the scenario cards below read as the primary unit.
|
|
1108
|
-
/* @__PURE__ */ (0,
|
|
1270
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
1109
1271
|
"section",
|
|
1110
1272
|
{
|
|
1111
1273
|
id: feature.id,
|
|
@@ -1113,9 +1275,9 @@ function ReportFeature({ feature }) {
|
|
|
1113
1275
|
"aria-labelledby": titleId,
|
|
1114
1276
|
className: "flex flex-col gap-3",
|
|
1115
1277
|
children: [
|
|
1116
|
-
/* @__PURE__ */ (0,
|
|
1117
|
-
/* @__PURE__ */ (0,
|
|
1118
|
-
/* @__PURE__ */ (0,
|
|
1278
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
|
|
1279
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "min-w-0", children: [
|
|
1280
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
1119
1281
|
"button",
|
|
1120
1282
|
{
|
|
1121
1283
|
type: "button",
|
|
@@ -1124,31 +1286,31 @@ function ReportFeature({ feature }) {
|
|
|
1124
1286
|
"aria-controls": bodyId,
|
|
1125
1287
|
className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
|
|
1126
1288
|
children: [
|
|
1127
|
-
/* @__PURE__ */ (0,
|
|
1128
|
-
/* @__PURE__ */ (0,
|
|
1289
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
|
|
1290
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "truncate", children: feature.title })
|
|
1129
1291
|
]
|
|
1130
1292
|
}
|
|
1131
1293
|
) : feature.title }),
|
|
1132
|
-
/* @__PURE__ */ (0,
|
|
1294
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
|
|
1133
1295
|
] }),
|
|
1134
|
-
/* @__PURE__ */ (0,
|
|
1296
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
1135
1297
|
"p",
|
|
1136
1298
|
{
|
|
1137
1299
|
className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
|
|
1138
1300
|
"aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
|
|
1139
1301
|
children: [
|
|
1140
|
-
/* @__PURE__ */ (0,
|
|
1302
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { children: [
|
|
1141
1303
|
s.passed,
|
|
1142
1304
|
" passed"
|
|
1143
1305
|
] }),
|
|
1144
|
-
/* @__PURE__ */ (0,
|
|
1145
|
-
/* @__PURE__ */ (0,
|
|
1306
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1307
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
|
|
1146
1308
|
s.failed,
|
|
1147
1309
|
" failed"
|
|
1148
1310
|
] }),
|
|
1149
|
-
skipped > 0 ? /* @__PURE__ */ (0,
|
|
1150
|
-
/* @__PURE__ */ (0,
|
|
1151
|
-
/* @__PURE__ */ (0,
|
|
1311
|
+
skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
|
|
1312
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1313
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { children: [
|
|
1152
1314
|
skipped,
|
|
1153
1315
|
" skipped"
|
|
1154
1316
|
] })
|
|
@@ -1157,7 +1319,7 @@ function ReportFeature({ feature }) {
|
|
|
1157
1319
|
}
|
|
1158
1320
|
)
|
|
1159
1321
|
] }),
|
|
1160
|
-
/* @__PURE__ */ (0,
|
|
1322
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ReportScenarioList, { feature }) })
|
|
1161
1323
|
]
|
|
1162
1324
|
}
|
|
1163
1325
|
)
|
|
@@ -1165,17 +1327,17 @@ function ReportFeature({ feature }) {
|
|
|
1165
1327
|
}
|
|
1166
1328
|
|
|
1167
1329
|
// src/components/ReportFeatureList.tsx
|
|
1168
|
-
var
|
|
1330
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1169
1331
|
function ReportFeatureList() {
|
|
1170
1332
|
const report = useReport();
|
|
1171
|
-
return /* @__PURE__ */ (0,
|
|
1333
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ReportFeature, { feature }, feature.id)) });
|
|
1172
1334
|
}
|
|
1173
1335
|
|
|
1174
1336
|
// src/components/ui/empty.tsx
|
|
1175
1337
|
var import_class_variance_authority2 = require("class-variance-authority");
|
|
1176
|
-
var
|
|
1338
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
1177
1339
|
function Empty({ className, ...props }) {
|
|
1178
|
-
return /* @__PURE__ */ (0,
|
|
1340
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
1179
1341
|
"div",
|
|
1180
1342
|
{
|
|
1181
1343
|
"data-slot": "empty",
|
|
@@ -1188,7 +1350,7 @@ function Empty({ className, ...props }) {
|
|
|
1188
1350
|
);
|
|
1189
1351
|
}
|
|
1190
1352
|
function EmptyHeader({ className, ...props }) {
|
|
1191
|
-
return /* @__PURE__ */ (0,
|
|
1353
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
1192
1354
|
"div",
|
|
1193
1355
|
{
|
|
1194
1356
|
"data-slot": "empty-header",
|
|
@@ -1215,7 +1377,7 @@ var emptyMediaVariants = (0, import_class_variance_authority2.cva)(
|
|
|
1215
1377
|
}
|
|
1216
1378
|
);
|
|
1217
1379
|
function EmptyTitle({ className, ...props }) {
|
|
1218
|
-
return /* @__PURE__ */ (0,
|
|
1380
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
1219
1381
|
"div",
|
|
1220
1382
|
{
|
|
1221
1383
|
"data-slot": "empty-title",
|
|
@@ -1226,16 +1388,16 @@ function EmptyTitle({ className, ...props }) {
|
|
|
1226
1388
|
}
|
|
1227
1389
|
|
|
1228
1390
|
// src/components/ReportEmpty.tsx
|
|
1229
|
-
var
|
|
1391
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
1230
1392
|
function ReportEmpty({ message }) {
|
|
1231
|
-
return /* @__PURE__ */ (0,
|
|
1393
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(EmptyHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
|
|
1232
1394
|
}
|
|
1233
1395
|
|
|
1234
1396
|
// src/components/ReportSummary.tsx
|
|
1235
|
-
var
|
|
1397
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
1236
1398
|
function ReportSummary({ className }) {
|
|
1237
1399
|
const report = useReport();
|
|
1238
|
-
return /* @__PURE__ */ (0,
|
|
1400
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
1239
1401
|
ReportSummaryView,
|
|
1240
1402
|
{
|
|
1241
1403
|
summary: report.summary,
|
|
@@ -1261,7 +1423,7 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1261
1423
|
if (summary.pending > 0) {
|
|
1262
1424
|
cards.push({ status: "pending", label: "Pending", value: summary.pending });
|
|
1263
1425
|
}
|
|
1264
|
-
return /* @__PURE__ */ (0,
|
|
1426
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
1265
1427
|
"dl",
|
|
1266
1428
|
{
|
|
1267
1429
|
className: cn(
|
|
@@ -1274,17 +1436,17 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1274
1436
|
"aria-label": ariaLabel,
|
|
1275
1437
|
children: cards.map((c) => {
|
|
1276
1438
|
const tone = TONE[c.status];
|
|
1277
|
-
return /* @__PURE__ */ (0,
|
|
1439
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
|
|
1278
1440
|
"div",
|
|
1279
1441
|
{
|
|
1280
1442
|
"data-status": c.status,
|
|
1281
1443
|
className: "rounded-lg border bg-card px-4 py-3",
|
|
1282
1444
|
children: [
|
|
1283
|
-
/* @__PURE__ */ (0,
|
|
1284
|
-
/* @__PURE__ */ (0,
|
|
1445
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
|
|
1446
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
|
|
1285
1447
|
c.label
|
|
1286
1448
|
] }),
|
|
1287
|
-
/* @__PURE__ */ (0,
|
|
1449
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
|
|
1288
1450
|
]
|
|
1289
1451
|
},
|
|
1290
1452
|
c.status
|
|
@@ -1325,7 +1487,7 @@ function prUrl(ci) {
|
|
|
1325
1487
|
}
|
|
1326
1488
|
|
|
1327
1489
|
// src/components/ReportMeta.tsx
|
|
1328
|
-
var
|
|
1490
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
1329
1491
|
function ReportMeta() {
|
|
1330
1492
|
const report = useReport();
|
|
1331
1493
|
const items = [];
|
|
@@ -1348,13 +1510,13 @@ function ReportMeta() {
|
|
|
1348
1510
|
const short = sha.slice(0, 8);
|
|
1349
1511
|
items.push({
|
|
1350
1512
|
label: "Commit",
|
|
1351
|
-
value: url ? /* @__PURE__ */ (0,
|
|
1513
|
+
value: url ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
|
|
1352
1514
|
});
|
|
1353
1515
|
}
|
|
1354
1516
|
if (report.ci) {
|
|
1355
1517
|
items.push({
|
|
1356
1518
|
label: "CI",
|
|
1357
|
-
value: report.ci.url ? /* @__PURE__ */ (0,
|
|
1519
|
+
value: report.ci.url ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
|
|
1358
1520
|
ciDisplayName(report.ci.name),
|
|
1359
1521
|
report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
|
|
1360
1522
|
] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
|
|
@@ -1365,7 +1527,7 @@ function ReportMeta() {
|
|
|
1365
1527
|
const label = `#${report.ci.prNumber}`;
|
|
1366
1528
|
items.push({
|
|
1367
1529
|
label: "PR",
|
|
1368
|
-
value: url ? /* @__PURE__ */ (0,
|
|
1530
|
+
value: url ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
|
|
1369
1531
|
});
|
|
1370
1532
|
}
|
|
1371
1533
|
if (items.length === 0) return null;
|
|
@@ -1373,48 +1535,48 @@ function ReportMeta() {
|
|
|
1373
1535
|
// Run metadata is useful but secondary to "what failed" — tuck it into a
|
|
1374
1536
|
// collapsed disclosure so it doesn't push the result down. Native <details>
|
|
1375
1537
|
// so it works with no JS (the SSR/no-hydration report still toggles).
|
|
1376
|
-
/* @__PURE__ */ (0,
|
|
1377
|
-
/* @__PURE__ */ (0,
|
|
1378
|
-
/* @__PURE__ */ (0,
|
|
1538
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
|
|
1539
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.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: [
|
|
1540
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
|
|
1379
1541
|
"Run details"
|
|
1380
1542
|
] }),
|
|
1381
|
-
/* @__PURE__ */ (0,
|
|
1382
|
-
/* @__PURE__ */ (0,
|
|
1383
|
-
/* @__PURE__ */ (0,
|
|
1543
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.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_runtime32.jsxs)("div", { className: "flex items-baseline gap-1.5", children: [
|
|
1544
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("dt", { className: "font-medium", children: item.label }),
|
|
1545
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("dd", { className: "font-mono text-foreground", children: item.value })
|
|
1384
1546
|
] }, item.label)) })
|
|
1385
1547
|
] })
|
|
1386
1548
|
);
|
|
1387
1549
|
}
|
|
1388
1550
|
|
|
1389
1551
|
// src/components/ReportSchemaError.tsx
|
|
1390
|
-
var
|
|
1552
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
1391
1553
|
function ReportSchemaError({ error }) {
|
|
1392
|
-
return /* @__PURE__ */ (0,
|
|
1393
|
-
/* @__PURE__ */ (0,
|
|
1394
|
-
/* @__PURE__ */ (0,
|
|
1395
|
-
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0,
|
|
1554
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
|
|
1555
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("strong", { children: "Report could not be displayed." }) }),
|
|
1556
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { children: error.message }),
|
|
1557
|
+
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("p", { children: [
|
|
1396
1558
|
"The report bundle is newer than this version of ",
|
|
1397
|
-
/* @__PURE__ */ (0,
|
|
1559
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("code", { children: "executable-stories-react" }),
|
|
1398
1560
|
". Upgrade the package, or regenerate the report with an older formatters CLI."
|
|
1399
1561
|
] }) : null,
|
|
1400
|
-
error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0,
|
|
1401
|
-
/* @__PURE__ */ (0,
|
|
1562
|
+
error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("details", { children: [
|
|
1563
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("summary", { children: [
|
|
1402
1564
|
error.issues.length,
|
|
1403
1565
|
" validation issue",
|
|
1404
1566
|
error.issues.length === 1 ? "" : "s"
|
|
1405
1567
|
] }),
|
|
1406
|
-
/* @__PURE__ */ (0,
|
|
1568
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
|
|
1407
1569
|
] }) : null
|
|
1408
1570
|
] });
|
|
1409
1571
|
}
|
|
1410
1572
|
|
|
1411
1573
|
// src/components/ReportShell.tsx
|
|
1412
|
-
var
|
|
1574
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
1413
1575
|
function ReportTitleBlock({ title }) {
|
|
1414
|
-
return /* @__PURE__ */ (0,
|
|
1415
|
-
/* @__PURE__ */ (0,
|
|
1416
|
-
/* @__PURE__ */ (0,
|
|
1417
|
-
/* @__PURE__ */ (0,
|
|
1576
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
|
|
1577
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("h1", { children: title ?? "Story Report" }),
|
|
1578
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportSummary, {}),
|
|
1579
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportMeta, {})
|
|
1418
1580
|
] });
|
|
1419
1581
|
}
|
|
1420
1582
|
function ReportErrorShell({
|
|
@@ -1423,22 +1585,22 @@ function ReportErrorShell({
|
|
|
1423
1585
|
title,
|
|
1424
1586
|
dataTheme
|
|
1425
1587
|
}) {
|
|
1426
|
-
return /* @__PURE__ */ (0,
|
|
1588
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportSchemaError, { error }) });
|
|
1427
1589
|
}
|
|
1428
1590
|
|
|
1429
1591
|
// src/components/Report.tsx
|
|
1430
|
-
var
|
|
1592
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
1431
1593
|
function Report(props) {
|
|
1432
1594
|
const { report, customRenderers, renderers, className, title, dataTheme } = props;
|
|
1433
1595
|
const result = unwrapReport(report);
|
|
1434
1596
|
if (!result.ok) {
|
|
1435
|
-
return /* @__PURE__ */ (0,
|
|
1597
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
|
|
1436
1598
|
}
|
|
1437
1599
|
const data = result.data;
|
|
1438
1600
|
const hasContent = data.features.length > 0;
|
|
1439
|
-
return /* @__PURE__ */ (0,
|
|
1440
|
-
/* @__PURE__ */ (0,
|
|
1441
|
-
hasContent ? /* @__PURE__ */ (0,
|
|
1601
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
|
|
1602
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("header", { className: "es-report-header", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportTitleBlock, { title }) }),
|
|
1603
|
+
hasContent ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportFeatureList, {}) : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportEmpty, {})
|
|
1442
1604
|
] }) });
|
|
1443
1605
|
}
|
|
1444
1606
|
|