executable-stories-react 0.7.0 → 0.9.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 +453 -230
- 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 +404 -181
- package/dist/index.js.map +1 -1
- package/dist/interactive.cjs +669 -377
- package/dist/interactive.cjs.map +1 -1
- package/dist/interactive.d.cts +35 -4
- package/dist/interactive.d.ts +35 -4
- package/dist/interactive.js +583 -291
- 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 +26 -26
- 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/interactive.js
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
// src/interactive/ReportInteractive.tsx
|
|
4
4
|
import {
|
|
5
|
-
useCallback as
|
|
5
|
+
useCallback as useCallback5,
|
|
6
6
|
useDeferredValue,
|
|
7
7
|
useId as useId2,
|
|
8
8
|
useMemo as useMemo3,
|
|
9
|
-
useRef as
|
|
10
|
-
useState as
|
|
9
|
+
useRef as useRef5,
|
|
10
|
+
useState as useState8
|
|
11
11
|
} from "react";
|
|
12
12
|
|
|
13
13
|
// src/result.ts
|
|
@@ -383,17 +383,29 @@ function DocHtml({ entry }) {
|
|
|
383
383
|
] });
|
|
384
384
|
}
|
|
385
385
|
|
|
386
|
+
// src/components/doc/DocState.tsx
|
|
387
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
388
|
+
function DocState({ entry }) {
|
|
389
|
+
let json;
|
|
390
|
+
try {
|
|
391
|
+
json = JSON.stringify(entry.value, null, 2) ?? String(entry.value);
|
|
392
|
+
} catch {
|
|
393
|
+
json = String(entry.value);
|
|
394
|
+
}
|
|
395
|
+
return /* @__PURE__ */ jsx13(CodeFigure, { label: entry.label ?? "State", children: /* @__PURE__ */ jsx13("code", { className: "font-mono text-xs language-json", children: json }) });
|
|
396
|
+
}
|
|
397
|
+
|
|
386
398
|
// src/components/doc/DocCustom.tsx
|
|
387
|
-
import { Fragment as Fragment4, jsx as
|
|
399
|
+
import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
388
400
|
function DocCustom({ entry }) {
|
|
389
401
|
const renderers = useCustomRenderers();
|
|
390
402
|
const renderer = renderers[entry.type];
|
|
391
403
|
if (renderer) {
|
|
392
|
-
return /* @__PURE__ */
|
|
404
|
+
return /* @__PURE__ */ jsx14(Fragment4, { children: renderer(entry) });
|
|
393
405
|
}
|
|
394
406
|
return /* @__PURE__ */ jsxs9("div", { className: "my-2", "data-type": entry.type, children: [
|
|
395
|
-
/* @__PURE__ */
|
|
396
|
-
/* @__PURE__ */
|
|
407
|
+
/* @__PURE__ */ jsx14("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: entry.type }),
|
|
408
|
+
/* @__PURE__ */ jsx14("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground", children: safeStringify(entry.data) })
|
|
397
409
|
] });
|
|
398
410
|
}
|
|
399
411
|
function safeStringify(value) {
|
|
@@ -405,45 +417,47 @@ function safeStringify(value) {
|
|
|
405
417
|
}
|
|
406
418
|
|
|
407
419
|
// src/components/doc/DocEntry.tsx
|
|
408
|
-
import { jsx as
|
|
420
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
409
421
|
function DocEntry({ entry }) {
|
|
410
422
|
switch (entry.kind) {
|
|
411
423
|
case "note":
|
|
412
|
-
return /* @__PURE__ */
|
|
424
|
+
return /* @__PURE__ */ jsx15(DocNote, { entry });
|
|
413
425
|
case "tag":
|
|
414
|
-
return /* @__PURE__ */
|
|
426
|
+
return /* @__PURE__ */ jsx15(DocTag, { entry });
|
|
415
427
|
case "kv":
|
|
416
|
-
return /* @__PURE__ */
|
|
428
|
+
return /* @__PURE__ */ jsx15(DocKv, { entry });
|
|
417
429
|
case "code":
|
|
418
|
-
return /* @__PURE__ */
|
|
430
|
+
return /* @__PURE__ */ jsx15(DocCode, { entry });
|
|
419
431
|
case "table":
|
|
420
|
-
return /* @__PURE__ */
|
|
432
|
+
return /* @__PURE__ */ jsx15(DocTable, { entry });
|
|
421
433
|
case "link":
|
|
422
|
-
return /* @__PURE__ */
|
|
434
|
+
return /* @__PURE__ */ jsx15(DocLink, { entry });
|
|
423
435
|
case "section":
|
|
424
|
-
return /* @__PURE__ */
|
|
436
|
+
return /* @__PURE__ */ jsx15(DocSection, { entry });
|
|
425
437
|
case "mermaid":
|
|
426
|
-
return /* @__PURE__ */
|
|
438
|
+
return /* @__PURE__ */ jsx15(DocMermaid, { entry });
|
|
427
439
|
case "screenshot":
|
|
428
|
-
return /* @__PURE__ */
|
|
440
|
+
return /* @__PURE__ */ jsx15(DocScreenshot, { entry });
|
|
429
441
|
case "video":
|
|
430
|
-
return /* @__PURE__ */
|
|
442
|
+
return /* @__PURE__ */ jsx15(DocVideo, { entry });
|
|
431
443
|
case "html":
|
|
432
|
-
return /* @__PURE__ */
|
|
444
|
+
return /* @__PURE__ */ jsx15(DocHtml, { entry });
|
|
445
|
+
case "state":
|
|
446
|
+
return /* @__PURE__ */ jsx15(DocState, { entry });
|
|
433
447
|
case "custom":
|
|
434
|
-
return /* @__PURE__ */
|
|
448
|
+
return /* @__PURE__ */ jsx15(DocCustom, { entry });
|
|
435
449
|
}
|
|
436
450
|
}
|
|
437
451
|
|
|
438
452
|
// src/components/ReportDocEntries.tsx
|
|
439
|
-
import { Fragment as Fragment5, jsx as
|
|
453
|
+
import { Fragment as Fragment5, jsx as jsx16 } from "react/jsx-runtime";
|
|
440
454
|
function ReportDocEntries({ entries }) {
|
|
441
455
|
if (entries.length === 0) return null;
|
|
442
|
-
return /* @__PURE__ */
|
|
456
|
+
return /* @__PURE__ */ jsx16(Fragment5, { children: entries.map((entry, i) => /* @__PURE__ */ jsx16(DocEntry, { entry }, i)) });
|
|
443
457
|
}
|
|
444
458
|
|
|
445
459
|
// src/lib/step-params.tsx
|
|
446
|
-
import { jsx as
|
|
460
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
447
461
|
var STEP_PARAM_PATTERN = /"[^"]*"|(?<![\w.-])\d+(?:\.\d+)?(?![\w.-])/g;
|
|
448
462
|
function highlightStepParams(text) {
|
|
449
463
|
const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));
|
|
@@ -455,7 +469,7 @@ function highlightStepParams(text) {
|
|
|
455
469
|
const end = start + match[0].length;
|
|
456
470
|
if (start > lastIndex) nodes.push(text.slice(lastIndex, start));
|
|
457
471
|
nodes.push(
|
|
458
|
-
/* @__PURE__ */
|
|
472
|
+
/* @__PURE__ */ jsx17("span", { className: "font-medium text-step-param italic", children: match[0] }, i)
|
|
459
473
|
);
|
|
460
474
|
lastIndex = end;
|
|
461
475
|
});
|
|
@@ -464,7 +478,7 @@ function highlightStepParams(text) {
|
|
|
464
478
|
}
|
|
465
479
|
|
|
466
480
|
// src/components/ReportSteps.tsx
|
|
467
|
-
import { jsx as
|
|
481
|
+
import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
468
482
|
var STEP_GLYPH = {
|
|
469
483
|
passed: "\u2713",
|
|
470
484
|
failed: "\u2717",
|
|
@@ -479,7 +493,7 @@ var STEP_GLYPH_COLOR = {
|
|
|
479
493
|
};
|
|
480
494
|
function ReportSteps({ scenario }) {
|
|
481
495
|
if (scenario.steps.length === 0) return null;
|
|
482
|
-
return /* @__PURE__ */
|
|
496
|
+
return /* @__PURE__ */ jsx18("ol", { "data-slot": "steps", className: "flex flex-col", children: scenario.steps.map((step) => /* @__PURE__ */ jsx18(ReportStepItem, { step }, step.id)) });
|
|
483
497
|
}
|
|
484
498
|
function ReportStepItem({ step }) {
|
|
485
499
|
const kw = step.keyword.toLowerCase();
|
|
@@ -492,8 +506,8 @@ function ReportStepItem({ step }) {
|
|
|
492
506
|
className: cn("py-1.5 text-[0.8125rem] leading-normal", continuation && "pl-5"),
|
|
493
507
|
children: [
|
|
494
508
|
/* @__PURE__ */ jsxs10("div", { className: "flex items-baseline gap-2", children: [
|
|
495
|
-
/* @__PURE__ */
|
|
496
|
-
/* @__PURE__ */
|
|
509
|
+
/* @__PURE__ */ jsx18("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" }),
|
|
510
|
+
/* @__PURE__ */ jsx18(
|
|
497
511
|
"span",
|
|
498
512
|
{
|
|
499
513
|
className: cn(
|
|
@@ -503,10 +517,10 @@ function ReportStepItem({ step }) {
|
|
|
503
517
|
children: step.keyword
|
|
504
518
|
}
|
|
505
519
|
),
|
|
506
|
-
/* @__PURE__ */
|
|
507
|
-
step.durationMs > 0 ? /* @__PURE__ */
|
|
520
|
+
/* @__PURE__ */ jsx18("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
|
|
521
|
+
step.durationMs > 0 ? /* @__PURE__ */ jsx18("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(step.durationMs) }) : null
|
|
508
522
|
] }),
|
|
509
|
-
step.errorMessage ? /* @__PURE__ */
|
|
523
|
+
step.errorMessage ? /* @__PURE__ */ jsx18(
|
|
510
524
|
"pre",
|
|
511
525
|
{
|
|
512
526
|
role: "alert",
|
|
@@ -514,12 +528,72 @@ function ReportStepItem({ step }) {
|
|
|
514
528
|
children: step.errorMessage
|
|
515
529
|
}
|
|
516
530
|
) : null,
|
|
517
|
-
step.docEntries.length > 0 ? /* @__PURE__ */
|
|
531
|
+
step.docEntries.length > 0 ? /* @__PURE__ */ jsx18("div", { "data-es-docs": true, className: "mt-2 ml-6", children: /* @__PURE__ */ jsx18(ReportDocEntries, { entries: step.docEntries }) }) : null
|
|
518
532
|
]
|
|
519
533
|
}
|
|
520
534
|
);
|
|
521
535
|
}
|
|
522
536
|
|
|
537
|
+
// ../executable-stories-core/dist/state-diff.js
|
|
538
|
+
var isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
539
|
+
function deepEqual(a, b) {
|
|
540
|
+
if (Object.is(a, b)) return true;
|
|
541
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
542
|
+
return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
|
|
543
|
+
}
|
|
544
|
+
if (isPlainObject(a) && isPlainObject(b)) {
|
|
545
|
+
const ak = Object.keys(a);
|
|
546
|
+
const bk = Object.keys(b);
|
|
547
|
+
return ak.length === bk.length && ak.every((k) => k in b && deepEqual(a[k], b[k]));
|
|
548
|
+
}
|
|
549
|
+
return false;
|
|
550
|
+
}
|
|
551
|
+
var joinKey = (path, key) => path === "" ? key : `${path}.${key}`;
|
|
552
|
+
function walk(path, before, after, out) {
|
|
553
|
+
if (Object.is(before, after)) return;
|
|
554
|
+
if (Array.isArray(before) && Array.isArray(after)) {
|
|
555
|
+
const shared = Math.min(before.length, after.length);
|
|
556
|
+
for (let i = 0; i < shared; i++) walk(`${path}[${i}]`, before[i], after[i], out);
|
|
557
|
+
for (let i = shared; i < after.length; i++) out.push({ path: `${path}[${i}]`, kind: "added", after: after[i] });
|
|
558
|
+
for (let i = shared; i < before.length; i++) out.push({ path: `${path}[${i}]`, kind: "removed", before: before[i] });
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
if (isPlainObject(before) && isPlainObject(after)) {
|
|
562
|
+
for (const key of Object.keys(after)) {
|
|
563
|
+
const p = joinKey(path, key);
|
|
564
|
+
if (key in before) walk(p, before[key], after[key], out);
|
|
565
|
+
else out.push({ path: p, kind: "added", after: after[key] });
|
|
566
|
+
}
|
|
567
|
+
for (const key of Object.keys(before)) {
|
|
568
|
+
if (!(key in after)) out.push({ path: joinKey(path, key), kind: "removed", before: before[key] });
|
|
569
|
+
}
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
if (!deepEqual(before, after)) out.push({ path, kind: "changed", before, after });
|
|
573
|
+
}
|
|
574
|
+
function diffStateValues(before, after) {
|
|
575
|
+
const out = [];
|
|
576
|
+
walk("", before, after, out);
|
|
577
|
+
return out;
|
|
578
|
+
}
|
|
579
|
+
function formatStateValue(value, maxLen = 60) {
|
|
580
|
+
const s = value === void 0 ? "undefined" : JSON.stringify(value);
|
|
581
|
+
return s.length > maxLen ? `${s.slice(0, maxLen - 1)}\u2026` : s;
|
|
582
|
+
}
|
|
583
|
+
function summarizeStateChanges(changes) {
|
|
584
|
+
return changes.map((c) => {
|
|
585
|
+
const at = c.path === "" ? "(root)" : c.path;
|
|
586
|
+
switch (c.kind) {
|
|
587
|
+
case "added":
|
|
588
|
+
return `+ ${at}: ${formatStateValue(c.after)}`;
|
|
589
|
+
case "removed":
|
|
590
|
+
return `\u2212 ${at}`;
|
|
591
|
+
case "changed":
|
|
592
|
+
return `${at}: ${formatStateValue(c.before)} \u2192 ${formatStateValue(c.after)}`;
|
|
593
|
+
}
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
|
|
523
597
|
// ../executable-stories-core/dist/storyboard.js
|
|
524
598
|
function findScreenshot(entries) {
|
|
525
599
|
for (const entry of entries) {
|
|
@@ -531,26 +605,55 @@ function findScreenshot(entries) {
|
|
|
531
605
|
}
|
|
532
606
|
return void 0;
|
|
533
607
|
}
|
|
608
|
+
function findStates(entries, out = []) {
|
|
609
|
+
for (const entry of entries) {
|
|
610
|
+
if (entry.kind === "state") out.push(entry);
|
|
611
|
+
if (entry.children) findStates(entry.children, out);
|
|
612
|
+
}
|
|
613
|
+
return out;
|
|
614
|
+
}
|
|
615
|
+
var laneOf = (label) => label ?? "";
|
|
534
616
|
function extractStoryboardFrames(scenario) {
|
|
535
617
|
const frames = [];
|
|
618
|
+
const laneOrder = [];
|
|
619
|
+
const previous = /* @__PURE__ */ new Map();
|
|
536
620
|
for (const step of scenario.steps) {
|
|
537
621
|
const shot = findScreenshot(step.docEntries);
|
|
538
|
-
|
|
622
|
+
const stateDocs = findStates(step.docEntries);
|
|
623
|
+
if (!shot && stateDocs.length === 0) continue;
|
|
624
|
+
const byLane = /* @__PURE__ */ new Map();
|
|
625
|
+
for (const doc of stateDocs) {
|
|
626
|
+
const lane = laneOf(doc.label);
|
|
627
|
+
if (!byLane.has(lane) && !laneOrder.includes(lane)) laneOrder.push(lane);
|
|
628
|
+
byLane.set(lane, doc);
|
|
629
|
+
}
|
|
630
|
+
const states = [];
|
|
631
|
+
for (const lane of laneOrder) {
|
|
632
|
+
const doc = byLane.get(lane);
|
|
633
|
+
if (!doc) continue;
|
|
634
|
+
const card = {
|
|
635
|
+
...doc.label !== void 0 && { label: doc.label },
|
|
636
|
+
value: doc.value
|
|
637
|
+
};
|
|
638
|
+
if (previous.has(lane)) card.changes = diffStateValues(previous.get(lane), doc.value);
|
|
639
|
+
previous.set(lane, doc.value);
|
|
640
|
+
states.push(card);
|
|
641
|
+
}
|
|
539
642
|
frames.push({
|
|
540
643
|
stepId: step.id,
|
|
541
644
|
stepIndex: step.index,
|
|
542
645
|
keyword: step.keyword,
|
|
543
646
|
text: step.text,
|
|
544
647
|
status: step.status,
|
|
545
|
-
path: shot.path,
|
|
546
|
-
|
|
648
|
+
...shot && { screenshot: { path: shot.path, ...shot.alt !== void 0 && { alt: shot.alt } } },
|
|
649
|
+
states
|
|
547
650
|
});
|
|
548
651
|
}
|
|
549
652
|
return frames;
|
|
550
653
|
}
|
|
551
654
|
|
|
552
655
|
// src/components/ReportStoryboard.tsx
|
|
553
|
-
import { jsx as
|
|
656
|
+
import { jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
554
657
|
var FRAME_GLYPH = {
|
|
555
658
|
passed: "\u2713",
|
|
556
659
|
failed: "\u2717",
|
|
@@ -567,54 +670,113 @@ function ReportStoryboard({ scenario }) {
|
|
|
567
670
|
const frames = extractStoryboardFrames(scenario);
|
|
568
671
|
if (frames.length < 2) return null;
|
|
569
672
|
return /* @__PURE__ */ jsxs11("section", { "data-slot": "storyboard", "aria-label": "Storyboard", className: "mb-3", children: [
|
|
570
|
-
/* @__PURE__ */
|
|
571
|
-
/* @__PURE__ */
|
|
673
|
+
/* @__PURE__ */ jsx19("h4", { className: "mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Storyboard" }),
|
|
674
|
+
/* @__PURE__ */ jsx19("ol", { className: "flex items-start gap-3 overflow-x-auto pb-2", children: frames.map((frame) => /* @__PURE__ */ jsx19(StoryboardFrameItem, { frame }, frame.stepId)) })
|
|
572
675
|
] });
|
|
573
676
|
}
|
|
574
677
|
function StoryboardFrameItem({ frame }) {
|
|
575
|
-
const src = isLocalFsPath(frame.path) ? void 0 : safeImageUrl(frame.path);
|
|
576
678
|
const label = `${frame.keyword} ${frame.text}`;
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
679
|
+
const hasStates = frame.states.length > 0;
|
|
680
|
+
const caption = /* @__PURE__ */ jsxs11("p", { className: "mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug", children: [
|
|
681
|
+
/* @__PURE__ */ jsx19("span", { "aria-hidden": true, className: cn("shrink-0", FRAME_GLYPH_COLOR[frame.status]), children: FRAME_GLYPH[frame.status] ?? "\u25CB" }),
|
|
682
|
+
/* @__PURE__ */ jsxs11("span", { className: "min-w-0", children: [
|
|
683
|
+
/* @__PURE__ */ jsx19("span", { className: "font-mono font-semibold text-keyword", children: frame.keyword }),
|
|
684
|
+
" ",
|
|
685
|
+
/* @__PURE__ */ jsx19("span", { className: "text-muted-foreground", children: frame.screenshot?.alt ?? frame.text })
|
|
686
|
+
] })
|
|
687
|
+
] });
|
|
688
|
+
return (
|
|
689
|
+
// State cards need room for diff rows; screenshot-only frames keep the
|
|
690
|
+
// original narrow film-cell width (and DOM) unchanged.
|
|
691
|
+
/* @__PURE__ */ jsxs11("li", { className: cn("shrink-0", hasStates ? "w-64" : "w-40"), children: [
|
|
692
|
+
frame.screenshot ? /* @__PURE__ */ jsx19(FrameScreenshot, { frame, label }) : null,
|
|
693
|
+
hasStates ? /* @__PURE__ */ jsx19("div", { className: cn("flex flex-col gap-1.5", frame.screenshot && "mt-1.5"), children: frame.states.map((card, i) => /* @__PURE__ */ jsx19(StateCardView, { card }, card.label ?? i)) }) : null,
|
|
694
|
+
frame.screenshot ? caption : (
|
|
695
|
+
// No screenshot means no image anchor, so the caption carries the
|
|
696
|
+
// jump-to-step link instead.
|
|
697
|
+
/* @__PURE__ */ jsx19("a", { href: `#${frame.stepId}`, "aria-label": `Jump to step: ${label}`, className: "block hover:underline", children: caption })
|
|
698
|
+
)
|
|
699
|
+
] })
|
|
700
|
+
);
|
|
701
|
+
}
|
|
702
|
+
function FrameScreenshot({ frame, label }) {
|
|
703
|
+
const path = frame.screenshot?.path ?? "";
|
|
704
|
+
const src = isLocalFsPath(path) ? void 0 : safeImageUrl(path);
|
|
705
|
+
return /* @__PURE__ */ jsx19(
|
|
706
|
+
"a",
|
|
707
|
+
{
|
|
708
|
+
href: `#${frame.stepId}`,
|
|
709
|
+
"aria-label": `Jump to step: ${label}`,
|
|
710
|
+
className: "block overflow-hidden rounded-md border border-border transition-colors hover:border-ring",
|
|
711
|
+
children: src ? /* @__PURE__ */ jsx19(
|
|
712
|
+
"img",
|
|
713
|
+
{
|
|
714
|
+
src,
|
|
715
|
+
alt: frame.screenshot?.alt ?? label,
|
|
716
|
+
loading: "lazy",
|
|
717
|
+
className: "h-24 w-full bg-muted object-cover object-top"
|
|
718
|
+
}
|
|
719
|
+
) : /* @__PURE__ */ jsx19("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" })
|
|
720
|
+
}
|
|
721
|
+
);
|
|
722
|
+
}
|
|
723
|
+
var CHANGE_TONE = {
|
|
724
|
+
added: "bg-pass-bg text-pass",
|
|
725
|
+
removed: "bg-fail-bg text-fail",
|
|
726
|
+
changed: "bg-skip-bg text-skip"
|
|
727
|
+
};
|
|
728
|
+
function prettyJson(value) {
|
|
729
|
+
try {
|
|
730
|
+
return JSON.stringify(value, null, 2) ?? String(value);
|
|
731
|
+
} catch {
|
|
732
|
+
return String(value);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
function StateCardView({ card }) {
|
|
736
|
+
const json = prettyJson(card.value);
|
|
737
|
+
const firstCapture = card.changes === void 0;
|
|
738
|
+
return /* @__PURE__ */ jsxs11("div", { "data-slot": "state-card", className: "rounded-md border border-border bg-card p-2", children: [
|
|
739
|
+
/* @__PURE__ */ jsxs11("p", { className: "flex flex-wrap items-baseline gap-1.5", children: [
|
|
740
|
+
/* @__PURE__ */ jsx19("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" }),
|
|
741
|
+
firstCapture ? /* @__PURE__ */ jsx19("span", { className: "text-[0.625rem] text-muted-foreground italic", children: "first capture" }) : null
|
|
742
|
+
] }),
|
|
743
|
+
!firstCapture && (card.changes && card.changes.length > 0 ? /* @__PURE__ */ jsx19("ul", { className: "mt-1.5 flex flex-col gap-0.5", children: card.changes.map((change, i) => /* @__PURE__ */ jsx19(
|
|
744
|
+
"li",
|
|
580
745
|
{
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
746
|
+
className: cn(
|
|
747
|
+
"rounded-sm px-1.5 py-0.5 font-mono text-[0.625rem] leading-snug break-all",
|
|
748
|
+
CHANGE_TONE[change.kind]
|
|
749
|
+
),
|
|
750
|
+
children: summarizeStateChanges([change])[0]
|
|
751
|
+
},
|
|
752
|
+
i
|
|
753
|
+
)) }) : /* @__PURE__ */ jsx19("p", { className: "mt-1.5 text-[0.625rem] text-muted-foreground", children: "No changes" })),
|
|
754
|
+
/* @__PURE__ */ jsxs11(
|
|
755
|
+
"details",
|
|
756
|
+
{
|
|
757
|
+
open: firstCapture && json.length <= 240,
|
|
758
|
+
className: cn(firstCapture ? "mt-1.5" : "mt-1"),
|
|
759
|
+
children: [
|
|
760
|
+
/* @__PURE__ */ jsx19("summary", { className: "cursor-pointer text-[0.625rem] text-muted-foreground hover:text-foreground", children: "Snapshot" }),
|
|
761
|
+
/* @__PURE__ */ jsx19("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 })
|
|
762
|
+
]
|
|
593
763
|
}
|
|
594
|
-
)
|
|
595
|
-
/* @__PURE__ */ jsxs11("p", { className: "mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug", children: [
|
|
596
|
-
/* @__PURE__ */ jsx18("span", { "aria-hidden": true, className: cn("shrink-0", FRAME_GLYPH_COLOR[frame.status]), children: FRAME_GLYPH[frame.status] ?? "\u25CB" }),
|
|
597
|
-
/* @__PURE__ */ jsxs11("span", { className: "min-w-0", children: [
|
|
598
|
-
/* @__PURE__ */ jsx18("span", { className: "font-mono font-semibold text-keyword", children: frame.keyword }),
|
|
599
|
-
" ",
|
|
600
|
-
/* @__PURE__ */ jsx18("span", { className: "text-muted-foreground", children: frame.alt ?? frame.text })
|
|
601
|
-
] })
|
|
602
|
-
] })
|
|
764
|
+
)
|
|
603
765
|
] });
|
|
604
766
|
}
|
|
605
767
|
|
|
606
768
|
// src/components/ReportAttachments.tsx
|
|
607
|
-
import { Fragment as Fragment6, jsx as
|
|
769
|
+
import { Fragment as Fragment6, jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
608
770
|
function ReportAttachments({ attachments }) {
|
|
609
771
|
if (attachments.length === 0) return null;
|
|
610
772
|
return (
|
|
611
773
|
// role="group" (not a labelled <section>) so multiple scenarios' attachment
|
|
612
774
|
// blocks don't create duplicate "Attachments" region landmarks.
|
|
613
|
-
/* @__PURE__ */
|
|
775
|
+
/* @__PURE__ */ jsx20("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
|
|
614
776
|
const dataUri = att.contentEncoding === "BASE64" ? `data:${att.mediaType};base64,${att.body}` : `data:${att.mediaType},${encodeURIComponent(att.body)}`;
|
|
615
777
|
const isImage = att.mediaType.startsWith("image/");
|
|
616
|
-
return /* @__PURE__ */
|
|
617
|
-
/* @__PURE__ */
|
|
778
|
+
return /* @__PURE__ */ jsx20("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ jsxs12(Fragment6, { children: [
|
|
779
|
+
/* @__PURE__ */ jsx20(
|
|
618
780
|
"img",
|
|
619
781
|
{
|
|
620
782
|
src: dataUri,
|
|
@@ -623,7 +785,7 @@ function ReportAttachments({ attachments }) {
|
|
|
623
785
|
className: "max-w-full rounded-md border border-border"
|
|
624
786
|
}
|
|
625
787
|
),
|
|
626
|
-
/* @__PURE__ */
|
|
788
|
+
/* @__PURE__ */ jsx20("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
|
|
627
789
|
] }) : /* @__PURE__ */ jsxs12(
|
|
628
790
|
"a",
|
|
629
791
|
{
|
|
@@ -697,15 +859,15 @@ function toTraceRows(spans) {
|
|
|
697
859
|
roots.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);
|
|
698
860
|
const rows = [];
|
|
699
861
|
const seen = /* @__PURE__ */ new Set();
|
|
700
|
-
const
|
|
862
|
+
const walk2 = (node, depth) => {
|
|
701
863
|
if (seen.has(node.span.spanId)) return;
|
|
702
864
|
seen.add(node.span.spanId);
|
|
703
865
|
rows.push({ ...node.span, depth });
|
|
704
|
-
for (const child of node.children)
|
|
866
|
+
for (const child of node.children) walk2(child, depth + 1);
|
|
705
867
|
};
|
|
706
|
-
for (const root of roots)
|
|
868
|
+
for (const root of roots) walk2(root, 0);
|
|
707
869
|
for (const node of byId.values()) {
|
|
708
|
-
if (!seen.has(node.span.spanId))
|
|
870
|
+
if (!seen.has(node.span.spanId)) walk2(node, 0);
|
|
709
871
|
}
|
|
710
872
|
return rows;
|
|
711
873
|
}
|
|
@@ -721,7 +883,7 @@ function traceWindow(rows) {
|
|
|
721
883
|
}
|
|
722
884
|
|
|
723
885
|
// src/components/ReportTrace.tsx
|
|
724
|
-
import { jsx as
|
|
886
|
+
import { jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
725
887
|
var BAR_COLOR = {
|
|
726
888
|
ok: "bg-pass",
|
|
727
889
|
error: "bg-fail",
|
|
@@ -742,11 +904,11 @@ function ReportTrace({ spans }) {
|
|
|
742
904
|
formatDuration(totalMs),
|
|
743
905
|
")"
|
|
744
906
|
] }),
|
|
745
|
-
/* @__PURE__ */
|
|
907
|
+
/* @__PURE__ */ jsx21("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
|
|
746
908
|
const leftPct = (row.startTimeMs - minStartMs) / totalMs * 100;
|
|
747
909
|
const widthPct = Math.max(row.durationMs / totalMs * 100, 0.5);
|
|
748
910
|
return /* @__PURE__ */ jsxs13("li", { className: "flex items-center gap-2", children: [
|
|
749
|
-
/* @__PURE__ */
|
|
911
|
+
/* @__PURE__ */ jsx21(
|
|
750
912
|
"span",
|
|
751
913
|
{
|
|
752
914
|
className: "min-w-0 flex-1 truncate text-foreground",
|
|
@@ -755,14 +917,14 @@ function ReportTrace({ spans }) {
|
|
|
755
917
|
children: row.name
|
|
756
918
|
}
|
|
757
919
|
),
|
|
758
|
-
/* @__PURE__ */
|
|
920
|
+
/* @__PURE__ */ jsx21("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ jsx21(
|
|
759
921
|
"span",
|
|
760
922
|
{
|
|
761
923
|
className: cn("absolute top-0 h-full rounded-sm", BAR_COLOR[row.status]),
|
|
762
924
|
style: { left: `${leftPct}%`, width: `${widthPct}%` }
|
|
763
925
|
}
|
|
764
926
|
) }),
|
|
765
|
-
/* @__PURE__ */
|
|
927
|
+
/* @__PURE__ */ jsx21("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
|
|
766
928
|
] }, `${row.spanId}-${i}`);
|
|
767
929
|
}) })
|
|
768
930
|
] });
|
|
@@ -811,11 +973,11 @@ function flakinessOf(entries) {
|
|
|
811
973
|
if (transitionScore > 0.2 || failureRate > 0.3) return "unstable";
|
|
812
974
|
return "stable";
|
|
813
975
|
}
|
|
814
|
-
function diffSinceLastRun(
|
|
976
|
+
function diffSinceLastRun(history, scenarios) {
|
|
815
977
|
let hasPreviousRun = false;
|
|
816
978
|
const delta = { newlyFailing: [], newlyPassing: [], added: [] };
|
|
817
979
|
for (const scenario of scenarios) {
|
|
818
|
-
const entries =
|
|
980
|
+
const entries = history[scenario.id];
|
|
819
981
|
if (!entries || entries.length === 0) continue;
|
|
820
982
|
const last = entries[entries.length - 1];
|
|
821
983
|
const prev = entries[entries.length - 2];
|
|
@@ -831,7 +993,7 @@ function diffSinceLastRun(history2, scenarios) {
|
|
|
831
993
|
}
|
|
832
994
|
|
|
833
995
|
// src/components/ScenarioRunHistory.tsx
|
|
834
|
-
import { Fragment as Fragment7, jsx as
|
|
996
|
+
import { Fragment as Fragment7, jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
835
997
|
var MAX_DOTS = 10;
|
|
836
998
|
var DOT_COLOR = {
|
|
837
999
|
passed: "bg-pass",
|
|
@@ -845,22 +1007,22 @@ function dotTitle(e) {
|
|
|
845
1007
|
return parts.join(" \xB7 ");
|
|
846
1008
|
}
|
|
847
1009
|
function ScenarioRunHistory({ scenarioId }) {
|
|
848
|
-
const
|
|
849
|
-
const entries =
|
|
1010
|
+
const history = useScenarioHistory();
|
|
1011
|
+
const entries = history?.[scenarioId];
|
|
850
1012
|
if (!entries || entries.length < 2) return null;
|
|
851
1013
|
const recent = entries.slice(-MAX_DOTS);
|
|
852
1014
|
const flaky = flakinessOf(recent) === "flaky";
|
|
853
1015
|
const summary = flaky ? `${describeRunHistory(recent)} \xB7 Flaky` : describeRunHistory(recent);
|
|
854
1016
|
return /* @__PURE__ */ jsxs14(Fragment7, { children: [
|
|
855
|
-
flaky ? /* @__PURE__ */
|
|
856
|
-
/* @__PURE__ */
|
|
1017
|
+
flaky ? /* @__PURE__ */ jsx22(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
|
|
1018
|
+
/* @__PURE__ */ jsx22(
|
|
857
1019
|
"span",
|
|
858
1020
|
{
|
|
859
1021
|
role: "img",
|
|
860
1022
|
"aria-label": `Run history: ${summary}`,
|
|
861
1023
|
title: summary,
|
|
862
1024
|
className: "flex shrink-0 items-center gap-[3px]",
|
|
863
|
-
children: recent.map((e, i) => /* @__PURE__ */
|
|
1025
|
+
children: recent.map((e, i) => /* @__PURE__ */ jsx22(
|
|
864
1026
|
"span",
|
|
865
1027
|
{
|
|
866
1028
|
"aria-hidden": true,
|
|
@@ -951,7 +1113,7 @@ function stringify(value) {
|
|
|
951
1113
|
return String(value);
|
|
952
1114
|
}
|
|
953
1115
|
}
|
|
954
|
-
function docEntryToMarkdown(entry) {
|
|
1116
|
+
function docEntryToMarkdown(entry, stateLanes) {
|
|
955
1117
|
const lines = [];
|
|
956
1118
|
switch (entry.kind) {
|
|
957
1119
|
case "note":
|
|
@@ -1003,13 +1165,24 @@ function docEntryToMarkdown(entry) {
|
|
|
1003
1165
|
case "custom":
|
|
1004
1166
|
lines.push(`**${entry.type}**`, "", "```json", stringify(entry.data), "```");
|
|
1005
1167
|
break;
|
|
1168
|
+
case "state": {
|
|
1169
|
+
const lane = entry.label ?? "";
|
|
1170
|
+
lines.push(`**${entry.label ?? "State"}**`);
|
|
1171
|
+
if (stateLanes?.has(lane)) {
|
|
1172
|
+
const summary = summarizeStateChanges(diffStateValues(stateLanes.get(lane), entry.value));
|
|
1173
|
+
if (summary.length > 0) lines.push("", ...summary.map((l) => `- ${l}`));
|
|
1174
|
+
}
|
|
1175
|
+
stateLanes?.set(lane, entry.value);
|
|
1176
|
+
lines.push("", "<details>", "<summary>snapshot</summary>", "", "```json", stringify(entry.value ?? null), "```", "", "</details>");
|
|
1177
|
+
break;
|
|
1178
|
+
}
|
|
1006
1179
|
}
|
|
1007
1180
|
for (const child of entry.children ?? []) {
|
|
1008
|
-
lines.push("", ...docEntryToMarkdown(child));
|
|
1181
|
+
lines.push("", ...docEntryToMarkdown(child, stateLanes));
|
|
1009
1182
|
}
|
|
1010
1183
|
return lines;
|
|
1011
1184
|
}
|
|
1012
|
-
function stepLines(step, ordinal, full) {
|
|
1185
|
+
function stepLines(step, ordinal, full, stateLanes) {
|
|
1013
1186
|
const status = step.status === "passed" ? "" : ` \u2014 **${step.status}**`;
|
|
1014
1187
|
const lines = [`${ordinal}. **${step.keyword}** ${step.text}${status}`];
|
|
1015
1188
|
if (!full) return lines;
|
|
@@ -1017,7 +1190,7 @@ function stepLines(step, ordinal, full) {
|
|
|
1017
1190
|
lines.push(...step.errorMessage.split("\n").map((l) => ` > ${l}`));
|
|
1018
1191
|
}
|
|
1019
1192
|
for (const entry of step.docEntries) {
|
|
1020
|
-
lines.push("", ...docEntryToMarkdown(entry).map((l) => l === "" ? l : ` ${l}`));
|
|
1193
|
+
lines.push("", ...docEntryToMarkdown(entry, stateLanes).map((l) => l === "" ? l : ` ${l}`));
|
|
1021
1194
|
}
|
|
1022
1195
|
return lines;
|
|
1023
1196
|
}
|
|
@@ -1026,9 +1199,10 @@ function scenarioToMarkdown(scenario, options = {}) {
|
|
|
1026
1199
|
const full = variant === "full";
|
|
1027
1200
|
const lines = full ? [`# ${scenario.title}`, ""] : [`## ${scenario.title} _(${scenario.status})_`, ""];
|
|
1028
1201
|
if (full && meta.length > 0) lines.push(...meta);
|
|
1202
|
+
const stateLanes = /* @__PURE__ */ new Map();
|
|
1029
1203
|
if (scenario.steps.length > 0) {
|
|
1030
1204
|
if (full) lines.push("", "## Steps", "");
|
|
1031
|
-
scenario.steps.forEach((step, i) => lines.push(...stepLines(step, i + 1, full)));
|
|
1205
|
+
scenario.steps.forEach((step, i) => lines.push(...stepLines(step, i + 1, full, stateLanes)));
|
|
1032
1206
|
}
|
|
1033
1207
|
if (scenario.errorMessage) {
|
|
1034
1208
|
if (full) lines.push("", "## Failure", "");
|
|
@@ -1037,7 +1211,7 @@ function scenarioToMarkdown(scenario, options = {}) {
|
|
|
1037
1211
|
}
|
|
1038
1212
|
if (full && scenario.docEntries.length > 0) {
|
|
1039
1213
|
lines.push("", "## Docs", "");
|
|
1040
|
-
for (const entry of scenario.docEntries) lines.push(...docEntryToMarkdown(entry), "");
|
|
1214
|
+
for (const entry of scenario.docEntries) lines.push(...docEntryToMarkdown(entry, stateLanes), "");
|
|
1041
1215
|
}
|
|
1042
1216
|
return lines.join("\n").replaceAll(/\n{3,}/g, "\n\n").trimEnd() + (full ? "\n" : "");
|
|
1043
1217
|
}
|
|
@@ -1077,9 +1251,9 @@ function scenarioPermalink(scenario) {
|
|
|
1077
1251
|
|
|
1078
1252
|
// src/components/ui/card.tsx
|
|
1079
1253
|
import "react";
|
|
1080
|
-
import { jsx as
|
|
1254
|
+
import { jsx as jsx23 } from "react/jsx-runtime";
|
|
1081
1255
|
function Card({ className, ...props }) {
|
|
1082
|
-
return /* @__PURE__ */
|
|
1256
|
+
return /* @__PURE__ */ jsx23(
|
|
1083
1257
|
"div",
|
|
1084
1258
|
{
|
|
1085
1259
|
"data-slot": "card",
|
|
@@ -1092,7 +1266,7 @@ function Card({ className, ...props }) {
|
|
|
1092
1266
|
);
|
|
1093
1267
|
}
|
|
1094
1268
|
function CardHeader({ className, ...props }) {
|
|
1095
|
-
return /* @__PURE__ */
|
|
1269
|
+
return /* @__PURE__ */ jsx23(
|
|
1096
1270
|
"div",
|
|
1097
1271
|
{
|
|
1098
1272
|
"data-slot": "card-header",
|
|
@@ -1105,7 +1279,7 @@ function CardHeader({ className, ...props }) {
|
|
|
1105
1279
|
);
|
|
1106
1280
|
}
|
|
1107
1281
|
function CardContent({ className, ...props }) {
|
|
1108
|
-
return /* @__PURE__ */
|
|
1282
|
+
return /* @__PURE__ */ jsx23(
|
|
1109
1283
|
"div",
|
|
1110
1284
|
{
|
|
1111
1285
|
"data-slot": "card-content",
|
|
@@ -1119,13 +1293,13 @@ function CardContent({ className, ...props }) {
|
|
|
1119
1293
|
import "react";
|
|
1120
1294
|
import { Menu as MenuPrimitive } from "@base-ui/react/menu";
|
|
1121
1295
|
import { CheckIcon } from "lucide-react";
|
|
1122
|
-
import { jsx as
|
|
1296
|
+
import { jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1123
1297
|
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";
|
|
1124
1298
|
function DropdownMenu(props) {
|
|
1125
|
-
return /* @__PURE__ */
|
|
1299
|
+
return /* @__PURE__ */ jsx24(MenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
|
|
1126
1300
|
}
|
|
1127
1301
|
function DropdownMenuTrigger(props) {
|
|
1128
|
-
return /* @__PURE__ */
|
|
1302
|
+
return /* @__PURE__ */ jsx24(MenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
|
|
1129
1303
|
}
|
|
1130
1304
|
function DropdownMenuContent({
|
|
1131
1305
|
className,
|
|
@@ -1133,14 +1307,14 @@ function DropdownMenuContent({
|
|
|
1133
1307
|
sideOffset = 4,
|
|
1134
1308
|
...props
|
|
1135
1309
|
}) {
|
|
1136
|
-
return /* @__PURE__ */
|
|
1310
|
+
return /* @__PURE__ */ jsx24(MenuPrimitive.Portal, { children: /* @__PURE__ */ jsx24(
|
|
1137
1311
|
MenuPrimitive.Positioner,
|
|
1138
1312
|
{
|
|
1139
1313
|
"data-slot": "dropdown-menu-positioner",
|
|
1140
1314
|
className: "z-50",
|
|
1141
1315
|
align,
|
|
1142
1316
|
sideOffset,
|
|
1143
|
-
children: /* @__PURE__ */
|
|
1317
|
+
children: /* @__PURE__ */ jsx24(
|
|
1144
1318
|
MenuPrimitive.Popup,
|
|
1145
1319
|
{
|
|
1146
1320
|
"data-slot": "dropdown-menu-content",
|
|
@@ -1158,7 +1332,7 @@ function DropdownMenuItem({
|
|
|
1158
1332
|
className,
|
|
1159
1333
|
...props
|
|
1160
1334
|
}) {
|
|
1161
|
-
return /* @__PURE__ */
|
|
1335
|
+
return /* @__PURE__ */ jsx24(
|
|
1162
1336
|
MenuPrimitive.Item,
|
|
1163
1337
|
{
|
|
1164
1338
|
"data-slot": "dropdown-menu-item",
|
|
@@ -1170,7 +1344,7 @@ function DropdownMenuItem({
|
|
|
1170
1344
|
|
|
1171
1345
|
// src/components/ReportScenario.tsx
|
|
1172
1346
|
import { LinkIcon, FileTextIcon, SparklesIcon, MoreHorizontalIcon } from "lucide-react";
|
|
1173
|
-
import { jsx as
|
|
1347
|
+
import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1174
1348
|
var STATUS_META = {
|
|
1175
1349
|
passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
|
|
1176
1350
|
failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
|
|
@@ -1197,7 +1371,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1197
1371
|
/* @__PURE__ */ jsxs16(CardHeader, { className: "px-4 py-3", children: [
|
|
1198
1372
|
/* @__PURE__ */ jsxs16("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
|
|
1199
1373
|
hideTitle ? null : /* @__PURE__ */ jsxs16("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
|
|
1200
|
-
collapsible ? /* @__PURE__ */
|
|
1374
|
+
collapsible ? /* @__PURE__ */ jsx25(
|
|
1201
1375
|
"button",
|
|
1202
1376
|
{
|
|
1203
1377
|
type: "button",
|
|
@@ -1206,36 +1380,36 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1206
1380
|
"aria-controls": bodyId,
|
|
1207
1381
|
"aria-label": `Toggle ${scenario.title}`,
|
|
1208
1382
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
1209
|
-
children: /* @__PURE__ */
|
|
1383
|
+
children: /* @__PURE__ */ jsx25("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
1210
1384
|
}
|
|
1211
1385
|
) : null,
|
|
1212
|
-
/* @__PURE__ */
|
|
1213
|
-
/* @__PURE__ */
|
|
1386
|
+
/* @__PURE__ */ jsx25("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
|
|
1387
|
+
/* @__PURE__ */ jsx25("span", { children: scenario.title })
|
|
1214
1388
|
] }),
|
|
1215
1389
|
/* @__PURE__ */ jsxs16("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
1216
|
-
/* @__PURE__ */
|
|
1217
|
-
scenario.durationMs > 0 ? /* @__PURE__ */
|
|
1218
|
-
meta.showPill ? /* @__PURE__ */
|
|
1390
|
+
/* @__PURE__ */ jsx25(ScenarioRunHistory, { scenarioId: scenario.id }),
|
|
1391
|
+
scenario.durationMs > 0 ? /* @__PURE__ */ jsx25("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
|
|
1392
|
+
meta.showPill ? /* @__PURE__ */ jsx25(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ jsx25("span", { className: "sr-only", children: `Status: ${label}` }),
|
|
1219
1393
|
actions ? /* @__PURE__ */ jsxs16(DropdownMenu, { children: [
|
|
1220
|
-
/* @__PURE__ */
|
|
1394
|
+
/* @__PURE__ */ jsx25(
|
|
1221
1395
|
DropdownMenuTrigger,
|
|
1222
1396
|
{
|
|
1223
1397
|
"aria-label": `Actions for ${scenario.title}`,
|
|
1224
1398
|
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
1225
|
-
children: /* @__PURE__ */
|
|
1399
|
+
children: /* @__PURE__ */ jsx25(MoreHorizontalIcon, { "aria-hidden": true })
|
|
1226
1400
|
}
|
|
1227
1401
|
),
|
|
1228
1402
|
/* @__PURE__ */ jsxs16(DropdownMenuContent, { align: "end", children: [
|
|
1229
1403
|
/* @__PURE__ */ jsxs16(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
|
|
1230
|
-
/* @__PURE__ */
|
|
1404
|
+
/* @__PURE__ */ jsx25(LinkIcon, {}),
|
|
1231
1405
|
" Copy link"
|
|
1232
1406
|
] }),
|
|
1233
1407
|
/* @__PURE__ */ jsxs16(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
|
|
1234
|
-
/* @__PURE__ */
|
|
1408
|
+
/* @__PURE__ */ jsx25(FileTextIcon, {}),
|
|
1235
1409
|
" Copy as Markdown"
|
|
1236
1410
|
] }),
|
|
1237
1411
|
/* @__PURE__ */ jsxs16(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
|
|
1238
|
-
/* @__PURE__ */
|
|
1412
|
+
/* @__PURE__ */ jsx25(SparklesIcon, {}),
|
|
1239
1413
|
" Explain with AI"
|
|
1240
1414
|
] })
|
|
1241
1415
|
] })
|
|
@@ -1243,12 +1417,12 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1243
1417
|
] })
|
|
1244
1418
|
] }),
|
|
1245
1419
|
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs16("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
|
|
1246
|
-
scenario.tags.map((t) => /* @__PURE__ */
|
|
1247
|
-
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */
|
|
1420
|
+
scenario.tags.map((t) => /* @__PURE__ */ jsx25("li", { children: /* @__PURE__ */ jsx25(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
|
|
1421
|
+
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ jsx25("li", { children: ticket.url ? /* @__PURE__ */ jsx25("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ jsx25(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ jsx25(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
|
|
1248
1422
|
] }) : null
|
|
1249
1423
|
] }),
|
|
1250
1424
|
/* @__PURE__ */ jsxs16(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
|
|
1251
|
-
scenario.errorMessage ? /* @__PURE__ */
|
|
1425
|
+
scenario.errorMessage ? /* @__PURE__ */ jsx25(
|
|
1252
1426
|
"pre",
|
|
1253
1427
|
{
|
|
1254
1428
|
role: "alert",
|
|
@@ -1256,11 +1430,11 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1256
1430
|
children: scenario.errorMessage
|
|
1257
1431
|
}
|
|
1258
1432
|
) : null,
|
|
1259
|
-
/* @__PURE__ */
|
|
1260
|
-
/* @__PURE__ */
|
|
1261
|
-
scenario.docEntries.length > 0 ? /* @__PURE__ */
|
|
1262
|
-
/* @__PURE__ */
|
|
1263
|
-
/* @__PURE__ */
|
|
1433
|
+
/* @__PURE__ */ jsx25(ReportStoryboard, { scenario }),
|
|
1434
|
+
/* @__PURE__ */ jsx25(ReportSteps, { scenario }),
|
|
1435
|
+
scenario.docEntries.length > 0 ? /* @__PURE__ */ jsx25("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ jsx25(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
|
|
1436
|
+
/* @__PURE__ */ jsx25(ReportAttachments, { attachments: scenario.attachments }),
|
|
1437
|
+
/* @__PURE__ */ jsx25(ReportTrace, { spans: scenario.otelSpans })
|
|
1264
1438
|
] })
|
|
1265
1439
|
]
|
|
1266
1440
|
}
|
|
@@ -1268,13 +1442,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1268
1442
|
}
|
|
1269
1443
|
|
|
1270
1444
|
// src/components/ReportScenarioList.tsx
|
|
1271
|
-
import { Fragment as Fragment8, jsx as
|
|
1445
|
+
import { Fragment as Fragment8, jsx as jsx26 } from "react/jsx-runtime";
|
|
1272
1446
|
function ReportScenarioList({ feature }) {
|
|
1273
|
-
return /* @__PURE__ */
|
|
1447
|
+
return /* @__PURE__ */ jsx26(Fragment8, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ jsx26(ReportScenario, { scenario }, scenario.id)) });
|
|
1274
1448
|
}
|
|
1275
1449
|
|
|
1276
1450
|
// src/components/ReportFeature.tsx
|
|
1277
|
-
import { Fragment as Fragment9, jsx as
|
|
1451
|
+
import { Fragment as Fragment9, jsx as jsx27, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1278
1452
|
function ReportFeature({ feature }) {
|
|
1279
1453
|
const titleId = `${feature.id}-title`;
|
|
1280
1454
|
const bodyId = `${feature.id}-body`;
|
|
@@ -1295,7 +1469,7 @@ function ReportFeature({ feature }) {
|
|
|
1295
1469
|
children: [
|
|
1296
1470
|
/* @__PURE__ */ jsxs17("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
|
|
1297
1471
|
/* @__PURE__ */ jsxs17("div", { className: "min-w-0", children: [
|
|
1298
|
-
/* @__PURE__ */
|
|
1472
|
+
/* @__PURE__ */ jsx27("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ jsxs17(
|
|
1299
1473
|
"button",
|
|
1300
1474
|
{
|
|
1301
1475
|
type: "button",
|
|
@@ -1304,12 +1478,12 @@ function ReportFeature({ feature }) {
|
|
|
1304
1478
|
"aria-controls": bodyId,
|
|
1305
1479
|
className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
|
|
1306
1480
|
children: [
|
|
1307
|
-
/* @__PURE__ */
|
|
1308
|
-
/* @__PURE__ */
|
|
1481
|
+
/* @__PURE__ */ jsx27("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
|
|
1482
|
+
/* @__PURE__ */ jsx27("span", { className: "truncate", children: feature.title })
|
|
1309
1483
|
]
|
|
1310
1484
|
}
|
|
1311
1485
|
) : feature.title }),
|
|
1312
|
-
/* @__PURE__ */
|
|
1486
|
+
/* @__PURE__ */ jsx27("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
|
|
1313
1487
|
] }),
|
|
1314
1488
|
/* @__PURE__ */ jsxs17(
|
|
1315
1489
|
"p",
|
|
@@ -1321,13 +1495,13 @@ function ReportFeature({ feature }) {
|
|
|
1321
1495
|
s.passed,
|
|
1322
1496
|
" passed"
|
|
1323
1497
|
] }),
|
|
1324
|
-
/* @__PURE__ */
|
|
1498
|
+
/* @__PURE__ */ jsx27("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1325
1499
|
/* @__PURE__ */ jsxs17("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
|
|
1326
1500
|
s.failed,
|
|
1327
1501
|
" failed"
|
|
1328
1502
|
] }),
|
|
1329
1503
|
skipped > 0 ? /* @__PURE__ */ jsxs17(Fragment9, { children: [
|
|
1330
|
-
/* @__PURE__ */
|
|
1504
|
+
/* @__PURE__ */ jsx27("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1331
1505
|
/* @__PURE__ */ jsxs17("span", { children: [
|
|
1332
1506
|
skipped,
|
|
1333
1507
|
" skipped"
|
|
@@ -1337,7 +1511,7 @@ function ReportFeature({ feature }) {
|
|
|
1337
1511
|
}
|
|
1338
1512
|
)
|
|
1339
1513
|
] }),
|
|
1340
|
-
/* @__PURE__ */
|
|
1514
|
+
/* @__PURE__ */ jsx27("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ jsx27(ReportScenarioList, { feature }) })
|
|
1341
1515
|
]
|
|
1342
1516
|
}
|
|
1343
1517
|
)
|
|
@@ -1345,17 +1519,17 @@ function ReportFeature({ feature }) {
|
|
|
1345
1519
|
}
|
|
1346
1520
|
|
|
1347
1521
|
// src/components/ReportFeatureList.tsx
|
|
1348
|
-
import { jsx as
|
|
1522
|
+
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
1349
1523
|
function ReportFeatureList() {
|
|
1350
1524
|
const report = useReport();
|
|
1351
|
-
return /* @__PURE__ */
|
|
1525
|
+
return /* @__PURE__ */ jsx28("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ jsx28(ReportFeature, { feature }, feature.id)) });
|
|
1352
1526
|
}
|
|
1353
1527
|
|
|
1354
1528
|
// src/components/ui/empty.tsx
|
|
1355
1529
|
import { cva as cva2 } from "class-variance-authority";
|
|
1356
|
-
import { jsx as
|
|
1530
|
+
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
1357
1531
|
function Empty({ className, ...props }) {
|
|
1358
|
-
return /* @__PURE__ */
|
|
1532
|
+
return /* @__PURE__ */ jsx29(
|
|
1359
1533
|
"div",
|
|
1360
1534
|
{
|
|
1361
1535
|
"data-slot": "empty",
|
|
@@ -1368,7 +1542,7 @@ function Empty({ className, ...props }) {
|
|
|
1368
1542
|
);
|
|
1369
1543
|
}
|
|
1370
1544
|
function EmptyHeader({ className, ...props }) {
|
|
1371
|
-
return /* @__PURE__ */
|
|
1545
|
+
return /* @__PURE__ */ jsx29(
|
|
1372
1546
|
"div",
|
|
1373
1547
|
{
|
|
1374
1548
|
"data-slot": "empty-header",
|
|
@@ -1395,7 +1569,7 @@ var emptyMediaVariants = cva2(
|
|
|
1395
1569
|
}
|
|
1396
1570
|
);
|
|
1397
1571
|
function EmptyTitle({ className, ...props }) {
|
|
1398
|
-
return /* @__PURE__ */
|
|
1572
|
+
return /* @__PURE__ */ jsx29(
|
|
1399
1573
|
"div",
|
|
1400
1574
|
{
|
|
1401
1575
|
"data-slot": "empty-title",
|
|
@@ -1406,16 +1580,16 @@ function EmptyTitle({ className, ...props }) {
|
|
|
1406
1580
|
}
|
|
1407
1581
|
|
|
1408
1582
|
// src/components/ReportEmpty.tsx
|
|
1409
|
-
import { jsx as
|
|
1583
|
+
import { jsx as jsx30 } from "react/jsx-runtime";
|
|
1410
1584
|
function ReportEmpty({ message }) {
|
|
1411
|
-
return /* @__PURE__ */
|
|
1585
|
+
return /* @__PURE__ */ jsx30(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ jsx30(EmptyHeader, { children: /* @__PURE__ */ jsx30(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
|
|
1412
1586
|
}
|
|
1413
1587
|
|
|
1414
1588
|
// src/components/ReportSummary.tsx
|
|
1415
|
-
import { jsx as
|
|
1589
|
+
import { jsx as jsx31, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1416
1590
|
function ReportSummary({ className }) {
|
|
1417
1591
|
const report = useReport();
|
|
1418
|
-
return /* @__PURE__ */
|
|
1592
|
+
return /* @__PURE__ */ jsx31(
|
|
1419
1593
|
ReportSummaryView,
|
|
1420
1594
|
{
|
|
1421
1595
|
summary: report.summary,
|
|
@@ -1441,7 +1615,7 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1441
1615
|
if (summary.pending > 0) {
|
|
1442
1616
|
cards.push({ status: "pending", label: "Pending", value: summary.pending });
|
|
1443
1617
|
}
|
|
1444
|
-
return /* @__PURE__ */
|
|
1618
|
+
return /* @__PURE__ */ jsx31(
|
|
1445
1619
|
"dl",
|
|
1446
1620
|
{
|
|
1447
1621
|
className: cn(
|
|
@@ -1461,10 +1635,10 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1461
1635
|
className: "rounded-lg border bg-card px-4 py-3",
|
|
1462
1636
|
children: [
|
|
1463
1637
|
/* @__PURE__ */ jsxs18("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
|
|
1464
|
-
/* @__PURE__ */
|
|
1638
|
+
/* @__PURE__ */ jsx31("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
|
|
1465
1639
|
c.label
|
|
1466
1640
|
] }),
|
|
1467
|
-
/* @__PURE__ */
|
|
1641
|
+
/* @__PURE__ */ jsx31("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
|
|
1468
1642
|
]
|
|
1469
1643
|
},
|
|
1470
1644
|
c.status
|
|
@@ -1524,7 +1698,7 @@ function prUrl(ci) {
|
|
|
1524
1698
|
}
|
|
1525
1699
|
|
|
1526
1700
|
// src/components/ReportMeta.tsx
|
|
1527
|
-
import { jsx as
|
|
1701
|
+
import { jsx as jsx32, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1528
1702
|
function ReportMeta() {
|
|
1529
1703
|
const report = useReport();
|
|
1530
1704
|
const items = [];
|
|
@@ -1547,7 +1721,7 @@ function ReportMeta() {
|
|
|
1547
1721
|
const short = sha.slice(0, 8);
|
|
1548
1722
|
items.push({
|
|
1549
1723
|
label: "Commit",
|
|
1550
|
-
value: url ? /* @__PURE__ */
|
|
1724
|
+
value: url ? /* @__PURE__ */ jsx32("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
|
|
1551
1725
|
});
|
|
1552
1726
|
}
|
|
1553
1727
|
if (report.ci) {
|
|
@@ -1564,7 +1738,7 @@ function ReportMeta() {
|
|
|
1564
1738
|
const label = `#${report.ci.prNumber}`;
|
|
1565
1739
|
items.push({
|
|
1566
1740
|
label: "PR",
|
|
1567
|
-
value: url ? /* @__PURE__ */
|
|
1741
|
+
value: url ? /* @__PURE__ */ jsx32("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
|
|
1568
1742
|
});
|
|
1569
1743
|
}
|
|
1570
1744
|
if (items.length === 0) return null;
|
|
@@ -1574,26 +1748,26 @@ function ReportMeta() {
|
|
|
1574
1748
|
// so it works with no JS (the SSR/no-hydration report still toggles).
|
|
1575
1749
|
/* @__PURE__ */ jsxs19("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
|
|
1576
1750
|
/* @__PURE__ */ jsxs19("summary", { className: "flex cursor-pointer list-none select-none items-center gap-1.5 px-4 py-2 font-medium text-muted-foreground [&::-webkit-details-marker]:hidden", children: [
|
|
1577
|
-
/* @__PURE__ */
|
|
1751
|
+
/* @__PURE__ */ jsx32("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
|
|
1578
1752
|
"Run details"
|
|
1579
1753
|
] }),
|
|
1580
|
-
/* @__PURE__ */
|
|
1581
|
-
/* @__PURE__ */
|
|
1582
|
-
/* @__PURE__ */
|
|
1754
|
+
/* @__PURE__ */ jsx32("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__ */ jsxs19("div", { className: "flex items-baseline gap-1.5", children: [
|
|
1755
|
+
/* @__PURE__ */ jsx32("dt", { className: "font-medium", children: item.label }),
|
|
1756
|
+
/* @__PURE__ */ jsx32("dd", { className: "font-mono text-foreground", children: item.value })
|
|
1583
1757
|
] }, item.label)) })
|
|
1584
1758
|
] })
|
|
1585
1759
|
);
|
|
1586
1760
|
}
|
|
1587
1761
|
|
|
1588
1762
|
// src/components/ReportSchemaError.tsx
|
|
1589
|
-
import { jsx as
|
|
1763
|
+
import { jsx as jsx33, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1590
1764
|
function ReportSchemaError({ error }) {
|
|
1591
1765
|
return /* @__PURE__ */ jsxs20("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
|
|
1592
|
-
/* @__PURE__ */
|
|
1593
|
-
/* @__PURE__ */
|
|
1766
|
+
/* @__PURE__ */ jsx33("p", { children: /* @__PURE__ */ jsx33("strong", { children: "Report could not be displayed." }) }),
|
|
1767
|
+
/* @__PURE__ */ jsx33("p", { children: error.message }),
|
|
1594
1768
|
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ jsxs20("p", { children: [
|
|
1595
1769
|
"The report bundle is newer than this version of ",
|
|
1596
|
-
/* @__PURE__ */
|
|
1770
|
+
/* @__PURE__ */ jsx33("code", { children: "executable-stories-react" }),
|
|
1597
1771
|
". Upgrade the package, or regenerate the report with an older formatters CLI."
|
|
1598
1772
|
] }) : null,
|
|
1599
1773
|
error.issues && error.issues.length > 0 ? /* @__PURE__ */ jsxs20("details", { children: [
|
|
@@ -1602,20 +1776,20 @@ function ReportSchemaError({ error }) {
|
|
|
1602
1776
|
" validation issue",
|
|
1603
1777
|
error.issues.length === 1 ? "" : "s"
|
|
1604
1778
|
] }),
|
|
1605
|
-
/* @__PURE__ */
|
|
1779
|
+
/* @__PURE__ */ jsx33("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
|
|
1606
1780
|
] }) : null
|
|
1607
1781
|
] });
|
|
1608
1782
|
}
|
|
1609
1783
|
|
|
1610
1784
|
// src/components/ReportShell.tsx
|
|
1611
|
-
import { Fragment as Fragment10, jsx as
|
|
1785
|
+
import { Fragment as Fragment10, jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1612
1786
|
function ReportErrorShell({
|
|
1613
1787
|
error,
|
|
1614
1788
|
className,
|
|
1615
1789
|
title,
|
|
1616
1790
|
dataTheme
|
|
1617
1791
|
}) {
|
|
1618
|
-
return /* @__PURE__ */
|
|
1792
|
+
return /* @__PURE__ */ jsx34("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ jsx34(ReportSchemaError, { error }) });
|
|
1619
1793
|
}
|
|
1620
1794
|
|
|
1621
1795
|
// src/interactive/ReportInteractive.tsx
|
|
@@ -1624,12 +1798,12 @@ import { Monitor, Moon, Sun } from "lucide-react";
|
|
|
1624
1798
|
// src/components/ui/switch.tsx
|
|
1625
1799
|
import "react";
|
|
1626
1800
|
import { Switch as SwitchPrimitive } from "@base-ui/react/switch";
|
|
1627
|
-
import { jsx as
|
|
1801
|
+
import { jsx as jsx35 } from "react/jsx-runtime";
|
|
1628
1802
|
function Switch({
|
|
1629
1803
|
className,
|
|
1630
1804
|
...props
|
|
1631
1805
|
}) {
|
|
1632
|
-
return /* @__PURE__ */
|
|
1806
|
+
return /* @__PURE__ */ jsx35(
|
|
1633
1807
|
SwitchPrimitive.Root,
|
|
1634
1808
|
{
|
|
1635
1809
|
"data-slot": "switch",
|
|
@@ -1638,7 +1812,7 @@ function Switch({
|
|
|
1638
1812
|
className
|
|
1639
1813
|
),
|
|
1640
1814
|
...props,
|
|
1641
|
-
children: /* @__PURE__ */
|
|
1815
|
+
children: /* @__PURE__ */ jsx35(
|
|
1642
1816
|
SwitchPrimitive.Thumb,
|
|
1643
1817
|
{
|
|
1644
1818
|
"data-slot": "switch-thumb",
|
|
@@ -1654,7 +1828,7 @@ import * as React5 from "react";
|
|
|
1654
1828
|
import { ToggleGroup as ToggleGroupPrimitive } from "@base-ui/react/toggle-group";
|
|
1655
1829
|
import { Toggle as TogglePrimitive } from "@base-ui/react/toggle";
|
|
1656
1830
|
import { cva as cva3 } from "class-variance-authority";
|
|
1657
|
-
import { jsx as
|
|
1831
|
+
import { jsx as jsx36 } from "react/jsx-runtime";
|
|
1658
1832
|
var toggleItemVariants = cva3(
|
|
1659
1833
|
"inline-flex items-center justify-center gap-1.5 rounded-md font-medium whitespace-nowrap text-muted-foreground transition-[color,background-color,box-shadow] outline-none hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 data-[pressed]:bg-background data-[pressed]:text-foreground data-[pressed]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
1660
1834
|
{
|
|
@@ -1676,13 +1850,13 @@ function ToggleGroup({
|
|
|
1676
1850
|
children,
|
|
1677
1851
|
...props
|
|
1678
1852
|
}) {
|
|
1679
|
-
return /* @__PURE__ */
|
|
1853
|
+
return /* @__PURE__ */ jsx36(
|
|
1680
1854
|
ToggleGroupPrimitive,
|
|
1681
1855
|
{
|
|
1682
1856
|
"data-slot": "toggle-group",
|
|
1683
1857
|
className: cn("flex w-fit items-center gap-0.5 rounded-lg bg-muted p-0.5", className),
|
|
1684
1858
|
...props,
|
|
1685
|
-
children: /* @__PURE__ */
|
|
1859
|
+
children: /* @__PURE__ */ jsx36(ToggleGroupContext.Provider, { value: { size }, children })
|
|
1686
1860
|
}
|
|
1687
1861
|
);
|
|
1688
1862
|
}
|
|
@@ -1693,7 +1867,7 @@ function ToggleGroupItem({
|
|
|
1693
1867
|
...props
|
|
1694
1868
|
}) {
|
|
1695
1869
|
const context = React5.useContext(ToggleGroupContext);
|
|
1696
|
-
return /* @__PURE__ */
|
|
1870
|
+
return /* @__PURE__ */ jsx36(
|
|
1697
1871
|
TogglePrimitive,
|
|
1698
1872
|
{
|
|
1699
1873
|
"data-slot": "toggle-group-item",
|
|
@@ -1713,9 +1887,9 @@ import { Search } from "lucide-react";
|
|
|
1713
1887
|
|
|
1714
1888
|
// src/components/ui/input.tsx
|
|
1715
1889
|
import "react";
|
|
1716
|
-
import { jsx as
|
|
1890
|
+
import { jsx as jsx37 } from "react/jsx-runtime";
|
|
1717
1891
|
function Input({ className, type, ...props }) {
|
|
1718
|
-
return /* @__PURE__ */
|
|
1892
|
+
return /* @__PURE__ */ jsx37(
|
|
1719
1893
|
"input",
|
|
1720
1894
|
{
|
|
1721
1895
|
type,
|
|
@@ -1732,7 +1906,7 @@ function Input({ className, type, ...props }) {
|
|
|
1732
1906
|
}
|
|
1733
1907
|
|
|
1734
1908
|
// src/interactive/ReportSearch.tsx
|
|
1735
|
-
import { jsx as
|
|
1909
|
+
import { jsx as jsx38, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1736
1910
|
var ReportSearch = forwardRef(
|
|
1737
1911
|
function ReportSearch2(props, ref) {
|
|
1738
1912
|
const {
|
|
@@ -1755,16 +1929,16 @@ var ReportSearch = forwardRef(
|
|
|
1755
1929
|
}
|
|
1756
1930
|
}
|
|
1757
1931
|
return /* @__PURE__ */ jsxs22("div", { className: cn("es-search flex flex-col gap-1", className), children: [
|
|
1758
|
-
/* @__PURE__ */
|
|
1932
|
+
/* @__PURE__ */ jsx38("label", { htmlFor: inputId, className: "sr-only", children: "Search" }),
|
|
1759
1933
|
/* @__PURE__ */ jsxs22("div", { className: "relative w-full sm:w-72", children: [
|
|
1760
|
-
/* @__PURE__ */
|
|
1934
|
+
/* @__PURE__ */ jsx38(
|
|
1761
1935
|
Search,
|
|
1762
1936
|
{
|
|
1763
1937
|
"aria-hidden": true,
|
|
1764
1938
|
className: "pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground"
|
|
1765
1939
|
}
|
|
1766
1940
|
),
|
|
1767
|
-
/* @__PURE__ */
|
|
1941
|
+
/* @__PURE__ */ jsx38(
|
|
1768
1942
|
Input,
|
|
1769
1943
|
{
|
|
1770
1944
|
ref,
|
|
@@ -1801,6 +1975,54 @@ var ReportSearch = forwardRef(
|
|
|
1801
1975
|
// src/interactive/ReportFailureBanner.tsx
|
|
1802
1976
|
import { useCallback as useCallback2 } from "react";
|
|
1803
1977
|
|
|
1978
|
+
// src/lib/hash-state.ts
|
|
1979
|
+
var DEFAULT_URL_STATE = {
|
|
1980
|
+
query: "",
|
|
1981
|
+
status: "all",
|
|
1982
|
+
tags: [],
|
|
1983
|
+
detail: "full"
|
|
1984
|
+
};
|
|
1985
|
+
var STATUSES = ["all", "passed", "failed", "skipped", "pending"];
|
|
1986
|
+
function splitHash(hash) {
|
|
1987
|
+
const raw = hash.replace(/^#/, "");
|
|
1988
|
+
const split = raw.indexOf("?");
|
|
1989
|
+
if (split === -1) return { anchor: raw, params: new URLSearchParams() };
|
|
1990
|
+
return { anchor: raw.slice(0, split), params: new URLSearchParams(raw.slice(split + 1)) };
|
|
1991
|
+
}
|
|
1992
|
+
function decodeUrlState(params) {
|
|
1993
|
+
const status = params.get("status");
|
|
1994
|
+
const tags = params.get("tags");
|
|
1995
|
+
return {
|
|
1996
|
+
query: params.get("q") ?? DEFAULT_URL_STATE.query,
|
|
1997
|
+
status: STATUSES.includes(status) ? status : DEFAULT_URL_STATE.status,
|
|
1998
|
+
tags: tags ? tags.split(",").filter(Boolean) : [],
|
|
1999
|
+
detail: params.get("docs") === "0" ? "minimal" : "full"
|
|
2000
|
+
};
|
|
2001
|
+
}
|
|
2002
|
+
function encodeUrlState(state) {
|
|
2003
|
+
const params = new URLSearchParams();
|
|
2004
|
+
if (state.query) params.set("q", state.query);
|
|
2005
|
+
if (state.status !== "all") params.set("status", state.status);
|
|
2006
|
+
if (state.tags.length > 0) params.set("tags", state.tags.join(","));
|
|
2007
|
+
if (state.detail === "minimal") params.set("docs", "0");
|
|
2008
|
+
return params.toString();
|
|
2009
|
+
}
|
|
2010
|
+
function formatHash(anchor, params) {
|
|
2011
|
+
if (params) return `#${anchor}?${params}`;
|
|
2012
|
+
return anchor ? `#${anchor}` : "";
|
|
2013
|
+
}
|
|
2014
|
+
function writeHash(anchor, params) {
|
|
2015
|
+
if (typeof window === "undefined") return;
|
|
2016
|
+
const next = formatHash(anchor, params);
|
|
2017
|
+
if (next === window.location.hash) return;
|
|
2018
|
+
const url = next || window.location.href.split("#")[0];
|
|
2019
|
+
try {
|
|
2020
|
+
window.history.replaceState(window.history.state, "", url);
|
|
2021
|
+
} catch {
|
|
2022
|
+
window.location.hash = next.slice(1);
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
|
|
1804
2026
|
// src/lib/scroll.ts
|
|
1805
2027
|
function prefersReducedMotion() {
|
|
1806
2028
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
@@ -1816,13 +2038,13 @@ function scrollToScenarioId(scenarioId, options = {}) {
|
|
|
1816
2038
|
behavior: prefersReducedMotion() ? "auto" : "smooth",
|
|
1817
2039
|
block: "start"
|
|
1818
2040
|
});
|
|
1819
|
-
if (options.updateHash !== false
|
|
1820
|
-
|
|
2041
|
+
if (options.updateHash !== false) {
|
|
2042
|
+
writeHash(scenarioId, splitHash(window.location.hash).params.toString());
|
|
1821
2043
|
}
|
|
1822
2044
|
}
|
|
1823
2045
|
|
|
1824
2046
|
// src/interactive/ReportFailureBanner.tsx
|
|
1825
|
-
import { jsx as
|
|
2047
|
+
import { jsx as jsx39, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1826
2048
|
function ReportFailureBanner({ failures }) {
|
|
1827
2049
|
const first = failures[0];
|
|
1828
2050
|
const jumpToFirst = useCallback2(() => {
|
|
@@ -1839,12 +2061,12 @@ function ReportFailureBanner({ failures }) {
|
|
|
1839
2061
|
"aria-label": "Failure summary",
|
|
1840
2062
|
children: [
|
|
1841
2063
|
/* @__PURE__ */ jsxs23("span", { className: "es-failure-banner-text", children: [
|
|
1842
|
-
/* @__PURE__ */
|
|
2064
|
+
/* @__PURE__ */ jsx39("strong", { children: failures.length }),
|
|
1843
2065
|
" ",
|
|
1844
2066
|
"failure",
|
|
1845
2067
|
failures.length === 1 ? "" : "s"
|
|
1846
2068
|
] }),
|
|
1847
|
-
/* @__PURE__ */
|
|
2069
|
+
/* @__PURE__ */ jsx39(
|
|
1848
2070
|
"button",
|
|
1849
2071
|
{
|
|
1850
2072
|
type: "button",
|
|
@@ -1861,7 +2083,7 @@ function ReportFailureBanner({ failures }) {
|
|
|
1861
2083
|
|
|
1862
2084
|
// src/interactive/ReportFreshness.tsx
|
|
1863
2085
|
import { useEffect, useState as useState2 } from "react";
|
|
1864
|
-
import { Fragment as Fragment11, jsx as
|
|
2086
|
+
import { Fragment as Fragment11, jsx as jsx40, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
1865
2087
|
function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
1866
2088
|
const [now, setNow] = useState2(nowMs);
|
|
1867
2089
|
useEffect(() => {
|
|
@@ -1869,7 +2091,7 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
1869
2091
|
}, [nowMs]);
|
|
1870
2092
|
if (lastRunMs === void 0 || now === void 0) return null;
|
|
1871
2093
|
const age = formatRelativeAge(lastRunMs, now);
|
|
1872
|
-
const runLink = ciUrl ? /* @__PURE__ */
|
|
2094
|
+
const runLink = ciUrl ? /* @__PURE__ */ jsx40(
|
|
1873
2095
|
"a",
|
|
1874
2096
|
{
|
|
1875
2097
|
href: ciUrl,
|
|
@@ -1903,13 +2125,13 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
1903
2125
|
}
|
|
1904
2126
|
|
|
1905
2127
|
// src/interactive/ReportLastRunDelta.tsx
|
|
1906
|
-
import { Fragment as Fragment12, jsx as
|
|
2128
|
+
import { Fragment as Fragment12, jsx as jsx41, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
1907
2129
|
var MAX_LINKS = 5;
|
|
1908
2130
|
function ScenarioLinks({ scenarios, tone }) {
|
|
1909
2131
|
return /* @__PURE__ */ jsxs25(Fragment12, { children: [
|
|
1910
2132
|
scenarios.slice(0, MAX_LINKS).map((s, i) => /* @__PURE__ */ jsxs25("span", { children: [
|
|
1911
2133
|
i > 0 ? ", " : "",
|
|
1912
|
-
/* @__PURE__ */
|
|
2134
|
+
/* @__PURE__ */ jsx41("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
|
|
1913
2135
|
] }, s.id)),
|
|
1914
2136
|
scenarios.length > MAX_LINKS ? /* @__PURE__ */ jsxs25("span", { children: [
|
|
1915
2137
|
" and ",
|
|
@@ -1919,29 +2141,29 @@ function ScenarioLinks({ scenarios, tone }) {
|
|
|
1919
2141
|
] });
|
|
1920
2142
|
}
|
|
1921
2143
|
function ReportLastRunDelta({
|
|
1922
|
-
history
|
|
2144
|
+
history,
|
|
1923
2145
|
report
|
|
1924
2146
|
}) {
|
|
1925
|
-
if (!
|
|
2147
|
+
if (!history) return null;
|
|
1926
2148
|
const scenarios = report.features.flatMap((f) => f.scenarios.map((s) => ({ id: s.id, title: s.title })));
|
|
1927
|
-
const delta = diffSinceLastRun(
|
|
2149
|
+
const delta = diffSinceLastRun(history, scenarios);
|
|
1928
2150
|
if (!delta) return null;
|
|
1929
2151
|
const { newlyFailing, newlyPassing, added } = delta;
|
|
1930
2152
|
if (newlyFailing.length === 0 && newlyPassing.length === 0 && added.length === 0) {
|
|
1931
|
-
return /* @__PURE__ */
|
|
2153
|
+
return /* @__PURE__ */ jsx41("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: "Since last run: no behavior changes." });
|
|
1932
2154
|
}
|
|
1933
2155
|
return /* @__PURE__ */ jsxs25("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: [
|
|
1934
|
-
/* @__PURE__ */
|
|
2156
|
+
/* @__PURE__ */ jsx41("span", { className: "font-medium text-foreground", children: "Since last run:" }),
|
|
1935
2157
|
newlyFailing.length > 0 ? /* @__PURE__ */ jsxs25("span", { className: "ml-2 text-fail", children: [
|
|
1936
2158
|
newlyFailing.length,
|
|
1937
2159
|
" newly failing (",
|
|
1938
|
-
/* @__PURE__ */
|
|
2160
|
+
/* @__PURE__ */ jsx41(ScenarioLinks, { scenarios: newlyFailing, tone: "text-fail" }),
|
|
1939
2161
|
")"
|
|
1940
2162
|
] }) : null,
|
|
1941
2163
|
newlyPassing.length > 0 ? /* @__PURE__ */ jsxs25("span", { className: "ml-2 text-pass", children: [
|
|
1942
2164
|
newlyPassing.length,
|
|
1943
2165
|
" fixed (",
|
|
1944
|
-
/* @__PURE__ */
|
|
2166
|
+
/* @__PURE__ */ jsx41(ScenarioLinks, { scenarios: newlyPassing, tone: "text-pass" }),
|
|
1945
2167
|
")"
|
|
1946
2168
|
] }) : null,
|
|
1947
2169
|
added.length > 0 ? /* @__PURE__ */ jsxs25("span", { className: "ml-2", children: [
|
|
@@ -2008,7 +2230,7 @@ function Button({
|
|
|
2008
2230
|
}
|
|
2009
2231
|
|
|
2010
2232
|
// src/interactive/ReportShortcutsHelp.tsx
|
|
2011
|
-
import { jsx as
|
|
2233
|
+
import { jsx as jsx42, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2012
2234
|
var SHORTCUTS = [
|
|
2013
2235
|
{ keys: "/", description: "Focus search" },
|
|
2014
2236
|
{ keys: "f", description: "Jump to next failure" },
|
|
@@ -2020,9 +2242,9 @@ var SHORTCUTS = [
|
|
|
2020
2242
|
];
|
|
2021
2243
|
function Keys({ keys }) {
|
|
2022
2244
|
const parts = keys.split(" ");
|
|
2023
|
-
return /* @__PURE__ */
|
|
2024
|
-
i > 0 ? /* @__PURE__ */
|
|
2025
|
-
/* @__PURE__ */
|
|
2245
|
+
return /* @__PURE__ */ jsx42("span", { className: "inline-flex items-center gap-1", children: parts.map((k, i) => /* @__PURE__ */ jsxs26("span", { className: "inline-flex items-center gap-1", children: [
|
|
2246
|
+
i > 0 ? /* @__PURE__ */ jsx42("span", { className: "text-xs text-muted-foreground", children: "+" }) : null,
|
|
2247
|
+
/* @__PURE__ */ jsx42("kbd", { className: "inline-flex h-6 min-w-6 items-center justify-center rounded border border-border bg-muted px-1.5 font-mono text-xs font-medium text-muted-foreground", children: k })
|
|
2026
2248
|
] }, k)) });
|
|
2027
2249
|
}
|
|
2028
2250
|
function ReportShortcutsHelp({ open, onClose }) {
|
|
@@ -2041,12 +2263,12 @@ function ReportShortcutsHelp({ open, onClose }) {
|
|
|
2041
2263
|
"aria-label": "Keyboard shortcuts",
|
|
2042
2264
|
onClose,
|
|
2043
2265
|
children: [
|
|
2044
|
-
/* @__PURE__ */
|
|
2045
|
-
/* @__PURE__ */
|
|
2046
|
-
/* @__PURE__ */
|
|
2047
|
-
/* @__PURE__ */
|
|
2266
|
+
/* @__PURE__ */ jsx42("h2", { className: "text-base font-semibold", children: "Keyboard shortcuts" }),
|
|
2267
|
+
/* @__PURE__ */ jsx42("dl", { className: "mt-4 grid grid-cols-[auto_1fr] items-center gap-x-4 gap-y-2.5", children: SHORTCUTS.map((s) => /* @__PURE__ */ jsxs26("div", { className: "col-span-2 grid grid-cols-subgrid items-center", children: [
|
|
2268
|
+
/* @__PURE__ */ jsx42("dt", { className: "justify-self-start", children: /* @__PURE__ */ jsx42(Keys, { keys: s.keys }) }),
|
|
2269
|
+
/* @__PURE__ */ jsx42("dd", { className: "text-sm text-muted-foreground", children: s.description })
|
|
2048
2270
|
] }, s.keys)) }),
|
|
2049
|
-
/* @__PURE__ */
|
|
2271
|
+
/* @__PURE__ */ jsx42("form", { method: "dialog", className: "mt-6", children: /* @__PURE__ */ jsx42(Button, { type: "submit", variant: "outline", size: "sm", children: "Close" }) })
|
|
2050
2272
|
]
|
|
2051
2273
|
}
|
|
2052
2274
|
);
|
|
@@ -2108,14 +2330,16 @@ function useKeyboardShortcuts(handlers) {
|
|
|
2108
2330
|
}
|
|
2109
2331
|
|
|
2110
2332
|
// src/interactive/use-deep-link-scroll.ts
|
|
2111
|
-
import { useEffect as useEffect4 } from "react";
|
|
2333
|
+
import { useEffect as useEffect4, useRef as useRef3 } from "react";
|
|
2112
2334
|
function useDeepLinkScroll() {
|
|
2335
|
+
const lastAnchor = useRef3(null);
|
|
2113
2336
|
useEffect4(() => {
|
|
2114
2337
|
function scrollToHash() {
|
|
2115
|
-
const
|
|
2116
|
-
if (!
|
|
2338
|
+
const { anchor } = splitHash(window.location.hash);
|
|
2339
|
+
if (!anchor || anchor === lastAnchor.current) return;
|
|
2340
|
+
lastAnchor.current = anchor;
|
|
2117
2341
|
requestAnimationFrame(() => {
|
|
2118
|
-
scrollToScenarioId(
|
|
2342
|
+
scrollToScenarioId(anchor, { updateHash: false });
|
|
2119
2343
|
});
|
|
2120
2344
|
}
|
|
2121
2345
|
scrollToHash();
|
|
@@ -2247,7 +2471,7 @@ function failuresFirst(report) {
|
|
|
2247
2471
|
|
|
2248
2472
|
// src/interactive/ReportFilters.tsx
|
|
2249
2473
|
import { useState as useState3 } from "react";
|
|
2250
|
-
import { jsx as
|
|
2474
|
+
import { jsx as jsx43, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2251
2475
|
var TAG_LIMIT = 12;
|
|
2252
2476
|
function ReportFilters({
|
|
2253
2477
|
statuses,
|
|
@@ -2262,7 +2486,7 @@ function ReportFilters({
|
|
|
2262
2486
|
const tagsCollapsed = tags.length > TAG_LIMIT && !showAllTags;
|
|
2263
2487
|
const visibleTags = tagsCollapsed ? tags.slice(0, TAG_LIMIT) : tags;
|
|
2264
2488
|
return /* @__PURE__ */ jsxs27("div", { className: "flex flex-col gap-2", children: [
|
|
2265
|
-
statuses.length > 0 ? /* @__PURE__ */
|
|
2489
|
+
statuses.length > 0 ? /* @__PURE__ */ jsx43("div", { role: "group", "aria-label": "Filter by status", className: "flex flex-wrap gap-1", children: statuses.map((opt) => {
|
|
2266
2490
|
const active = status === opt.key;
|
|
2267
2491
|
return /* @__PURE__ */ jsxs27(
|
|
2268
2492
|
"button",
|
|
@@ -2276,7 +2500,7 @@ function ReportFilters({
|
|
|
2276
2500
|
),
|
|
2277
2501
|
children: [
|
|
2278
2502
|
opt.label,
|
|
2279
|
-
/* @__PURE__ */
|
|
2503
|
+
/* @__PURE__ */ jsx43("span", { className: "ml-1 font-mono opacity-70", children: opt.count })
|
|
2280
2504
|
]
|
|
2281
2505
|
},
|
|
2282
2506
|
opt.key
|
|
@@ -2285,14 +2509,14 @@ function ReportFilters({
|
|
|
2285
2509
|
tags.length > 0 ? /* @__PURE__ */ jsxs27("ul", { "aria-label": "Filter by tag", className: "flex flex-wrap items-center gap-1.5", children: [
|
|
2286
2510
|
visibleTags.map((tag) => {
|
|
2287
2511
|
const active = activeTags.includes(tag);
|
|
2288
|
-
return /* @__PURE__ */
|
|
2512
|
+
return /* @__PURE__ */ jsx43("li", { children: /* @__PURE__ */ jsx43(
|
|
2289
2513
|
"button",
|
|
2290
2514
|
{
|
|
2291
2515
|
type: "button",
|
|
2292
2516
|
"aria-pressed": active,
|
|
2293
2517
|
onClick: () => onToggleTag(tag),
|
|
2294
2518
|
className: "cursor-pointer",
|
|
2295
|
-
children: /* @__PURE__ */
|
|
2519
|
+
children: /* @__PURE__ */ jsx43(
|
|
2296
2520
|
Badge,
|
|
2297
2521
|
{
|
|
2298
2522
|
variant: "tag",
|
|
@@ -2305,7 +2529,7 @@ function ReportFilters({
|
|
|
2305
2529
|
}
|
|
2306
2530
|
) }, tag);
|
|
2307
2531
|
}),
|
|
2308
|
-
tags.length > TAG_LIMIT ? /* @__PURE__ */
|
|
2532
|
+
tags.length > TAG_LIMIT ? /* @__PURE__ */ jsx43("li", { children: /* @__PURE__ */ jsx43(
|
|
2309
2533
|
"button",
|
|
2310
2534
|
{
|
|
2311
2535
|
type: "button",
|
|
@@ -2321,7 +2545,7 @@ function ReportFilters({
|
|
|
2321
2545
|
|
|
2322
2546
|
// src/interactive/ReportToc.tsx
|
|
2323
2547
|
import { useEffect as useEffect5, useMemo as useMemo2, useState as useState4 } from "react";
|
|
2324
|
-
import { jsx as
|
|
2548
|
+
import { jsx as jsx44, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
2325
2549
|
var DOT = {
|
|
2326
2550
|
passed: "bg-pass",
|
|
2327
2551
|
failed: "bg-fail",
|
|
@@ -2350,11 +2574,11 @@ function TocContent({ onNavigate }) {
|
|
|
2350
2574
|
return () => observer.disconnect();
|
|
2351
2575
|
}, [scenarioIds]);
|
|
2352
2576
|
if (report.features.length === 0) return null;
|
|
2353
|
-
return /* @__PURE__ */
|
|
2354
|
-
/* @__PURE__ */
|
|
2355
|
-
/* @__PURE__ */
|
|
2577
|
+
return /* @__PURE__ */ jsx44("ul", { className: "flex list-none flex-col gap-4 pl-0", children: report.features.map((feature) => /* @__PURE__ */ jsxs28("li", { children: [
|
|
2578
|
+
/* @__PURE__ */ jsx44("p", { className: "mb-1.5 font-semibold leading-snug text-foreground", children: feature.title }),
|
|
2579
|
+
/* @__PURE__ */ jsx44("ul", { className: "flex list-none flex-col gap-0.5 pl-0", children: feature.scenarios.map((scenario) => {
|
|
2356
2580
|
const active = activeId === scenario.id;
|
|
2357
|
-
return /* @__PURE__ */
|
|
2581
|
+
return /* @__PURE__ */ jsx44("li", { children: /* @__PURE__ */ jsxs28(
|
|
2358
2582
|
"a",
|
|
2359
2583
|
{
|
|
2360
2584
|
href: `#${scenario.id}`,
|
|
@@ -2369,14 +2593,14 @@ function TocContent({ onNavigate }) {
|
|
|
2369
2593
|
active ? "border-primary font-medium text-foreground" : "border-border text-muted-foreground"
|
|
2370
2594
|
),
|
|
2371
2595
|
children: [
|
|
2372
|
-
/* @__PURE__ */
|
|
2596
|
+
/* @__PURE__ */ jsx44(
|
|
2373
2597
|
"span",
|
|
2374
2598
|
{
|
|
2375
2599
|
"aria-hidden": true,
|
|
2376
2600
|
className: cn("mt-1 size-1.5 shrink-0 rounded-full", DOT[scenario.status])
|
|
2377
2601
|
}
|
|
2378
2602
|
),
|
|
2379
|
-
/* @__PURE__ */
|
|
2603
|
+
/* @__PURE__ */ jsx44("span", { className: "break-words", children: scenario.title })
|
|
2380
2604
|
]
|
|
2381
2605
|
}
|
|
2382
2606
|
) }, scenario.id);
|
|
@@ -2392,8 +2616,8 @@ function ReportToc() {
|
|
|
2392
2616
|
"aria-label": "Table of contents",
|
|
2393
2617
|
className: "sticky top-4 hidden h-fit w-64 shrink-0 self-start text-xs lg:block",
|
|
2394
2618
|
children: [
|
|
2395
|
-
/* @__PURE__ */
|
|
2396
|
-
/* @__PURE__ */
|
|
2619
|
+
/* @__PURE__ */ jsx44("p", { className: "mb-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Contents" }),
|
|
2620
|
+
/* @__PURE__ */ jsx44(TocContent, {})
|
|
2397
2621
|
]
|
|
2398
2622
|
}
|
|
2399
2623
|
);
|
|
@@ -2403,31 +2627,31 @@ function ReportToc() {
|
|
|
2403
2627
|
import { useState as useState5 } from "react";
|
|
2404
2628
|
import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
|
|
2405
2629
|
import { ListIcon, XIcon } from "lucide-react";
|
|
2406
|
-
import { jsx as
|
|
2630
|
+
import { jsx as jsx45, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
2407
2631
|
function ReportTocDrawer() {
|
|
2408
2632
|
const report = useReport();
|
|
2409
2633
|
const [open, setOpen] = useState5(false);
|
|
2410
2634
|
if (report.features.length === 0) return null;
|
|
2411
2635
|
return /* @__PURE__ */ jsxs29(DialogPrimitive.Root, { open, onOpenChange: setOpen, children: [
|
|
2412
2636
|
/* @__PURE__ */ jsxs29(DialogPrimitive.Trigger, { className: "flex cursor-pointer items-center gap-1 rounded-md border border-border px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground lg:hidden [&_svg]:size-3.5", children: [
|
|
2413
|
-
/* @__PURE__ */
|
|
2637
|
+
/* @__PURE__ */ jsx45(ListIcon, { "aria-hidden": true }),
|
|
2414
2638
|
" Contents"
|
|
2415
2639
|
] }),
|
|
2416
2640
|
/* @__PURE__ */ jsxs29(DialogPrimitive.Portal, { children: [
|
|
2417
|
-
/* @__PURE__ */
|
|
2641
|
+
/* @__PURE__ */ jsx45(DialogPrimitive.Backdrop, { className: "fixed inset-0 z-50 bg-black/50 transition-opacity duration-200 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0" }),
|
|
2418
2642
|
/* @__PURE__ */ jsxs29(DialogPrimitive.Popup, { className: "fixed inset-y-0 left-0 z-50 flex w-72 max-w-[80vw] flex-col gap-3 overflow-y-auto border-r border-border bg-background p-4 font-sans text-xs shadow-lg outline-none transition-transform duration-200 data-[ending-style]:-translate-x-full data-[starting-style]:-translate-x-full", children: [
|
|
2419
2643
|
/* @__PURE__ */ jsxs29("div", { className: "flex items-center justify-between", children: [
|
|
2420
|
-
/* @__PURE__ */
|
|
2421
|
-
/* @__PURE__ */
|
|
2644
|
+
/* @__PURE__ */ jsx45(DialogPrimitive.Title, { className: "text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Contents" }),
|
|
2645
|
+
/* @__PURE__ */ jsx45(
|
|
2422
2646
|
DialogPrimitive.Close,
|
|
2423
2647
|
{
|
|
2424
2648
|
"aria-label": "Close contents",
|
|
2425
2649
|
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
2426
|
-
children: /* @__PURE__ */
|
|
2650
|
+
children: /* @__PURE__ */ jsx45(XIcon, { "aria-hidden": true })
|
|
2427
2651
|
}
|
|
2428
2652
|
)
|
|
2429
2653
|
] }),
|
|
2430
|
-
/* @__PURE__ */
|
|
2654
|
+
/* @__PURE__ */ jsx45(TocContent, { onNavigate: () => setOpen(false) })
|
|
2431
2655
|
] })
|
|
2432
2656
|
] })
|
|
2433
2657
|
] });
|
|
@@ -2481,15 +2705,43 @@ function useTheme() {
|
|
|
2481
2705
|
return { pref, setPref };
|
|
2482
2706
|
}
|
|
2483
2707
|
|
|
2708
|
+
// src/interactive/use-url-state.ts
|
|
2709
|
+
import { useCallback as useCallback4, useEffect as useEffect7, useRef as useRef4, useState as useState7 } from "react";
|
|
2710
|
+
var WRITE_DELAY_MS = 250;
|
|
2711
|
+
function useUrlState() {
|
|
2712
|
+
const [state, setState] = useState7(DEFAULT_URL_STATE);
|
|
2713
|
+
const ready = useRef4(false);
|
|
2714
|
+
useEffect7(() => {
|
|
2715
|
+
const read = () => setState(decodeUrlState(splitHash(window.location.hash).params));
|
|
2716
|
+
read();
|
|
2717
|
+
ready.current = true;
|
|
2718
|
+
window.addEventListener("hashchange", read);
|
|
2719
|
+
return () => window.removeEventListener("hashchange", read);
|
|
2720
|
+
}, []);
|
|
2721
|
+
useEffect7(() => {
|
|
2722
|
+
if (!ready.current) return;
|
|
2723
|
+
const timer = setTimeout(
|
|
2724
|
+
() => writeHash(splitHash(window.location.hash).anchor, encodeUrlState(state)),
|
|
2725
|
+
WRITE_DELAY_MS
|
|
2726
|
+
);
|
|
2727
|
+
return () => clearTimeout(timer);
|
|
2728
|
+
}, [state]);
|
|
2729
|
+
const update = useCallback4(
|
|
2730
|
+
(patch) => setState((prev) => ({ ...prev, ...patch })),
|
|
2731
|
+
[]
|
|
2732
|
+
);
|
|
2733
|
+
return [state, update];
|
|
2734
|
+
}
|
|
2735
|
+
|
|
2484
2736
|
// src/interactive/ReportInteractive.tsx
|
|
2485
|
-
import { Fragment as Fragment13, jsx as
|
|
2737
|
+
import { Fragment as Fragment13, jsx as jsx46, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
2486
2738
|
function ReportInteractive(props) {
|
|
2487
2739
|
const { report, className, title, dataTheme } = props;
|
|
2488
2740
|
const result = unwrapReport(report);
|
|
2489
2741
|
if (!result.ok) {
|
|
2490
|
-
return /* @__PURE__ */
|
|
2742
|
+
return /* @__PURE__ */ jsx46(ReportErrorShell, { error: result.error, className, title, dataTheme });
|
|
2491
2743
|
}
|
|
2492
|
-
return /* @__PURE__ */
|
|
2744
|
+
return /* @__PURE__ */ jsx46(ReportInteractiveView, { ...props, report: result.data });
|
|
2493
2745
|
}
|
|
2494
2746
|
var THEME_OPTIONS = [
|
|
2495
2747
|
{ value: "light", label: "Light", Icon: Sun },
|
|
@@ -2497,7 +2749,7 @@ var THEME_OPTIONS = [
|
|
|
2497
2749
|
{ value: "dark", label: "Dark", Icon: Moon }
|
|
2498
2750
|
];
|
|
2499
2751
|
function ThemeSegment({ pref, onPref }) {
|
|
2500
|
-
return /* @__PURE__ */
|
|
2752
|
+
return /* @__PURE__ */ jsx46(
|
|
2501
2753
|
ToggleGroup,
|
|
2502
2754
|
{
|
|
2503
2755
|
size: "sm",
|
|
@@ -2507,7 +2759,7 @@ function ThemeSegment({ pref, onPref }) {
|
|
|
2507
2759
|
if (next) onPref(next);
|
|
2508
2760
|
},
|
|
2509
2761
|
"aria-label": "Color theme",
|
|
2510
|
-
children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */
|
|
2762
|
+
children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */ jsx46(ToggleGroupItem, { value, "aria-label": label, title: label, className: "px-2", children: /* @__PURE__ */ jsx46(Icon, {}) }, value))
|
|
2511
2763
|
}
|
|
2512
2764
|
);
|
|
2513
2765
|
}
|
|
@@ -2523,13 +2775,20 @@ function ReportInteractiveView({
|
|
|
2523
2775
|
staleAfterDays = 7,
|
|
2524
2776
|
scenarioHistory
|
|
2525
2777
|
}) {
|
|
2526
|
-
const [
|
|
2527
|
-
const
|
|
2528
|
-
const
|
|
2529
|
-
const
|
|
2530
|
-
|
|
2778
|
+
const [urlState, setUrlState] = useUrlState();
|
|
2779
|
+
const { query, status: statusFilter, tags: activeTags, detail } = urlState;
|
|
2780
|
+
const setQuery = useCallback5((next) => setUrlState({ query: next }), [setUrlState]);
|
|
2781
|
+
const setStatusFilter = useCallback5(
|
|
2782
|
+
(next) => setUrlState({ status: next }),
|
|
2783
|
+
[setUrlState]
|
|
2784
|
+
);
|
|
2785
|
+
const setDetail = useCallback5(
|
|
2786
|
+
(next) => setUrlState({ detail: next }),
|
|
2787
|
+
[setUrlState]
|
|
2788
|
+
);
|
|
2789
|
+
const [helpOpen, setHelpOpen] = useState8(false);
|
|
2531
2790
|
const { pref: themePref, setPref: setThemePref } = useTheme();
|
|
2532
|
-
const searchRef =
|
|
2791
|
+
const searchRef = useRef5(null);
|
|
2533
2792
|
const expandId = useId2();
|
|
2534
2793
|
const docsId = useId2();
|
|
2535
2794
|
const deferredQuery = useDeferredValue(query);
|
|
@@ -2553,18 +2812,20 @@ function ReportInteractiveView({
|
|
|
2553
2812
|
return opts;
|
|
2554
2813
|
}, [report]);
|
|
2555
2814
|
const tagOptions = useMemo3(() => allTags(report), [report]);
|
|
2556
|
-
const toggleTag =
|
|
2557
|
-
(tag) =>
|
|
2558
|
-
|
|
2815
|
+
const toggleTag = useCallback5(
|
|
2816
|
+
(tag) => setUrlState({
|
|
2817
|
+
tags: activeTags.includes(tag) ? activeTags.filter((t) => t !== tag) : [...activeTags, tag]
|
|
2818
|
+
}),
|
|
2819
|
+
[activeTags, setUrlState]
|
|
2559
2820
|
);
|
|
2560
|
-
const [toast, setToast] =
|
|
2561
|
-
const toastTimer =
|
|
2562
|
-
const showToast =
|
|
2821
|
+
const [toast, setToast] = useState8(null);
|
|
2822
|
+
const toastTimer = useRef5(null);
|
|
2823
|
+
const showToast = useCallback5((msg) => {
|
|
2563
2824
|
setToast(msg);
|
|
2564
2825
|
if (toastTimer.current) clearTimeout(toastTimer.current);
|
|
2565
2826
|
toastTimer.current = setTimeout(() => setToast(null), 1800);
|
|
2566
2827
|
}, []);
|
|
2567
|
-
const copy =
|
|
2828
|
+
const copy = useCallback5(
|
|
2568
2829
|
(text, msg) => {
|
|
2569
2830
|
if (typeof navigator !== "undefined" && navigator.clipboard) {
|
|
2570
2831
|
navigator.clipboard.writeText(text).then(() => showToast(msg), () => showToast("Copy failed"));
|
|
@@ -2580,15 +2841,15 @@ function ReportInteractiveView({
|
|
|
2580
2841
|
}),
|
|
2581
2842
|
[copy]
|
|
2582
2843
|
);
|
|
2583
|
-
const failureIndexRef =
|
|
2844
|
+
const failureIndexRef = useRef5(0);
|
|
2584
2845
|
const allCollapsibleIds = useMemo3(
|
|
2585
2846
|
() => report.features.flatMap((f) => [f.id, ...f.scenarios.map((s) => s.id)]),
|
|
2586
2847
|
[report]
|
|
2587
2848
|
);
|
|
2588
|
-
const collapse = useCollapseState(
|
|
2589
|
-
const collapseAll =
|
|
2590
|
-
const [expandedAll, setExpandedAll] =
|
|
2591
|
-
const setExpanded =
|
|
2849
|
+
const collapse = useCollapseState(useCallback5(() => defaultCollapsedIds(report), [report]));
|
|
2850
|
+
const collapseAll = useCallback5(() => collapse.collapseAll(allCollapsibleIds), [collapse, allCollapsibleIds]);
|
|
2851
|
+
const [expandedAll, setExpandedAll] = useState8(() => report.summary.failed === 0);
|
|
2852
|
+
const setExpanded = useCallback5(
|
|
2592
2853
|
(expanded) => {
|
|
2593
2854
|
if (expanded) collapse.expandAll();
|
|
2594
2855
|
else collapseAll();
|
|
@@ -2596,10 +2857,10 @@ function ReportInteractiveView({
|
|
|
2596
2857
|
},
|
|
2597
2858
|
[collapse, collapseAll]
|
|
2598
2859
|
);
|
|
2599
|
-
const focusSearch =
|
|
2860
|
+
const focusSearch = useCallback5(() => {
|
|
2600
2861
|
searchRef.current?.focus();
|
|
2601
2862
|
}, []);
|
|
2602
|
-
const stepFailure =
|
|
2863
|
+
const stepFailure = useCallback5(
|
|
2603
2864
|
(direction) => {
|
|
2604
2865
|
if (failures.length === 0) return;
|
|
2605
2866
|
failureIndexRef.current = (failureIndexRef.current + direction + failures.length) % failures.length;
|
|
@@ -2608,10 +2869,10 @@ function ReportInteractiveView({
|
|
|
2608
2869
|
},
|
|
2609
2870
|
[failures]
|
|
2610
2871
|
);
|
|
2611
|
-
const toggleHelp =
|
|
2872
|
+
const toggleHelp = useCallback5(() => {
|
|
2612
2873
|
setHelpOpen((v) => !v);
|
|
2613
2874
|
}, []);
|
|
2614
|
-
const escape =
|
|
2875
|
+
const escape = useCallback5(() => {
|
|
2615
2876
|
if (helpOpen) setHelpOpen(false);
|
|
2616
2877
|
else if (query !== "") setQuery("");
|
|
2617
2878
|
}, [helpOpen, query]);
|
|
@@ -2629,7 +2890,7 @@ function ReportInteractiveView({
|
|
|
2629
2890
|
const totalScenarios = report.summary.total;
|
|
2630
2891
|
const matchedScenarios = filtered.summary.total;
|
|
2631
2892
|
const showToc = !hideToc && totalScenarios > 3;
|
|
2632
|
-
return /* @__PURE__ */
|
|
2893
|
+
return /* @__PURE__ */ jsx46(CollapseProvider, { value: collapse.api, children: /* @__PURE__ */ jsx46(ScenarioActionsProvider, { value: scenarioActions, children: /* @__PURE__ */ jsx46(ScenarioHistoryProvider, { value: scenarioHistory ?? null, children: /* @__PURE__ */ jsx46(
|
|
2633
2894
|
ReportRoot,
|
|
2634
2895
|
{
|
|
2635
2896
|
report: filtered,
|
|
@@ -2654,9 +2915,9 @@ function ReportInteractiveView({
|
|
|
2654
2915
|
hideHeader ? "justify-end" : "justify-between"
|
|
2655
2916
|
),
|
|
2656
2917
|
children: [
|
|
2657
|
-
hideHeader ? null : /* @__PURE__ */
|
|
2918
|
+
hideHeader ? null : /* @__PURE__ */ jsx46("h1", { className: "min-w-0", children: title ?? "Story Report" }),
|
|
2658
2919
|
/* @__PURE__ */ jsxs30("div", { className: "flex items-center gap-2", children: [
|
|
2659
|
-
/* @__PURE__ */
|
|
2920
|
+
/* @__PURE__ */ jsx46(
|
|
2660
2921
|
ReportSearch,
|
|
2661
2922
|
{
|
|
2662
2923
|
ref: searchRef,
|
|
@@ -2666,16 +2927,16 @@ function ReportInteractiveView({
|
|
|
2666
2927
|
totalCount: totalScenarios
|
|
2667
2928
|
}
|
|
2668
2929
|
),
|
|
2669
|
-
/* @__PURE__ */
|
|
2930
|
+
/* @__PURE__ */ jsx46(ThemeSegment, { pref: themePref, onPref: setThemePref })
|
|
2670
2931
|
] })
|
|
2671
2932
|
]
|
|
2672
2933
|
}
|
|
2673
2934
|
),
|
|
2674
2935
|
hideHeader ? null : /* @__PURE__ */ jsxs30(Fragment13, { children: [
|
|
2675
|
-
/* @__PURE__ */
|
|
2676
|
-
/* @__PURE__ */
|
|
2936
|
+
/* @__PURE__ */ jsx46(ReportSummary, {}),
|
|
2937
|
+
/* @__PURE__ */ jsx46(ReportMeta, {})
|
|
2677
2938
|
] }),
|
|
2678
|
-
/* @__PURE__ */
|
|
2939
|
+
/* @__PURE__ */ jsx46(
|
|
2679
2940
|
ReportFreshness,
|
|
2680
2941
|
{
|
|
2681
2942
|
lastRunMs: reportLastRunMs(report),
|
|
@@ -2683,8 +2944,8 @@ function ReportInteractiveView({
|
|
|
2683
2944
|
staleAfterDays
|
|
2684
2945
|
}
|
|
2685
2946
|
),
|
|
2686
|
-
/* @__PURE__ */
|
|
2687
|
-
/* @__PURE__ */
|
|
2947
|
+
/* @__PURE__ */ jsx46(ReportLastRunDelta, { history: scenarioHistory, report }),
|
|
2948
|
+
/* @__PURE__ */ jsx46(
|
|
2688
2949
|
ReportFilters,
|
|
2689
2950
|
{
|
|
2690
2951
|
statuses: statusOptions,
|
|
@@ -2696,13 +2957,13 @@ function ReportInteractiveView({
|
|
|
2696
2957
|
}
|
|
2697
2958
|
),
|
|
2698
2959
|
/* @__PURE__ */ jsxs30("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-2 border-t border-border/60 pt-3", children: [
|
|
2699
|
-
showToc ? /* @__PURE__ */
|
|
2960
|
+
showToc ? /* @__PURE__ */ jsx46(ReportTocDrawer, {}) : null,
|
|
2700
2961
|
/* @__PURE__ */ jsxs30("div", { className: "flex items-center gap-2", children: [
|
|
2701
|
-
/* @__PURE__ */
|
|
2702
|
-
/* @__PURE__ */
|
|
2962
|
+
/* @__PURE__ */ jsx46(Switch, { id: expandId, checked: expandedAll, onCheckedChange: setExpanded }),
|
|
2963
|
+
/* @__PURE__ */ jsx46("label", { htmlFor: expandId, className: "cursor-pointer text-sm text-muted-foreground select-none", children: "Expand all" })
|
|
2703
2964
|
] }),
|
|
2704
2965
|
/* @__PURE__ */ jsxs30("div", { className: "flex items-center gap-2", children: [
|
|
2705
|
-
/* @__PURE__ */
|
|
2966
|
+
/* @__PURE__ */ jsx46(
|
|
2706
2967
|
Switch,
|
|
2707
2968
|
{
|
|
2708
2969
|
id: docsId,
|
|
@@ -2710,16 +2971,16 @@ function ReportInteractiveView({
|
|
|
2710
2971
|
onCheckedChange: (checked) => setDetail(checked ? "full" : "minimal")
|
|
2711
2972
|
}
|
|
2712
2973
|
),
|
|
2713
|
-
/* @__PURE__ */
|
|
2974
|
+
/* @__PURE__ */ jsx46("label", { htmlFor: docsId, className: "cursor-pointer text-sm text-muted-foreground select-none", children: "Show documentation" })
|
|
2714
2975
|
] })
|
|
2715
2976
|
] })
|
|
2716
2977
|
] }),
|
|
2717
|
-
/* @__PURE__ */
|
|
2978
|
+
/* @__PURE__ */ jsx46(ReportFailureBanner, { failures }),
|
|
2718
2979
|
hasContent ? showToc ? /* @__PURE__ */ jsxs30("div", { className: "flex gap-6", children: [
|
|
2719
|
-
/* @__PURE__ */
|
|
2720
|
-
/* @__PURE__ */
|
|
2721
|
-
] }) : /* @__PURE__ */
|
|
2722
|
-
/* @__PURE__ */
|
|
2980
|
+
/* @__PURE__ */ jsx46(ReportToc, {}),
|
|
2981
|
+
/* @__PURE__ */ jsx46("div", { className: "flex min-w-0 flex-1 flex-col gap-4", children: /* @__PURE__ */ jsx46(ReportFeatureList, {}) })
|
|
2982
|
+
] }) : /* @__PURE__ */ jsx46("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ jsx46(ReportFeatureList, {}) }) : /* @__PURE__ */ jsx46(ReportEmpty, { message: query ? "No scenarios match the search." : void 0 }),
|
|
2983
|
+
/* @__PURE__ */ jsx46(
|
|
2723
2984
|
"button",
|
|
2724
2985
|
{
|
|
2725
2986
|
type: "button",
|
|
@@ -2730,8 +2991,8 @@ function ReportInteractiveView({
|
|
|
2730
2991
|
children: "?"
|
|
2731
2992
|
}
|
|
2732
2993
|
),
|
|
2733
|
-
/* @__PURE__ */
|
|
2734
|
-
toast ? /* @__PURE__ */
|
|
2994
|
+
/* @__PURE__ */ jsx46(ReportShortcutsHelp, { open: helpOpen, onClose: () => setHelpOpen(false) }),
|
|
2995
|
+
toast ? /* @__PURE__ */ jsx46(
|
|
2735
2996
|
"div",
|
|
2736
2997
|
{
|
|
2737
2998
|
role: "status",
|
|
@@ -2751,11 +3012,11 @@ function ReportInteractiveView({
|
|
|
2751
3012
|
import { useMemo as useMemo4 } from "react";
|
|
2752
3013
|
|
|
2753
3014
|
// src/interactive/island-renderers.tsx
|
|
2754
|
-
import { createElement, useEffect as
|
|
3015
|
+
import { createElement, useEffect as useEffect9, useState as useState10 } from "react";
|
|
2755
3016
|
|
|
2756
3017
|
// src/components/doc/MermaidView.tsx
|
|
2757
|
-
import { useEffect as
|
|
2758
|
-
import { jsx as
|
|
3018
|
+
import { useEffect as useEffect8, useRef as useRef6, useState as useState9 } from "react";
|
|
3019
|
+
import { Fragment as Fragment14, jsx as jsx47, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
2759
3020
|
function prefersDark(el) {
|
|
2760
3021
|
const themed = el?.closest("[data-theme]");
|
|
2761
3022
|
if (themed?.dataset.theme === "dark") return true;
|
|
@@ -2763,23 +3024,40 @@ function prefersDark(el) {
|
|
|
2763
3024
|
return typeof window !== "undefined" && !!window.matchMedia?.("(prefers-color-scheme: dark)").matches;
|
|
2764
3025
|
}
|
|
2765
3026
|
function MermaidView({ entry, load }) {
|
|
2766
|
-
const ref =
|
|
2767
|
-
const [svg, setSvg] =
|
|
2768
|
-
|
|
3027
|
+
const ref = useRef6(null);
|
|
3028
|
+
const [svg, setSvg] = useState9(null);
|
|
3029
|
+
const [error, setError] = useState9(null);
|
|
3030
|
+
useEffect8(() => {
|
|
2769
3031
|
let cancelled = false;
|
|
2770
3032
|
const draw = async () => {
|
|
3033
|
+
let mermaid;
|
|
3034
|
+
try {
|
|
3035
|
+
mermaid = await load();
|
|
3036
|
+
} catch {
|
|
3037
|
+
if (!cancelled) {
|
|
3038
|
+
setSvg(null);
|
|
3039
|
+
setError(null);
|
|
3040
|
+
}
|
|
3041
|
+
return;
|
|
3042
|
+
}
|
|
2771
3043
|
try {
|
|
2772
|
-
const mermaid = await load();
|
|
2773
3044
|
mermaid.initialize({
|
|
2774
3045
|
startOnLoad: false,
|
|
2775
3046
|
securityLevel: "strict",
|
|
2776
3047
|
theme: prefersDark(ref.current) ? "dark" : "default"
|
|
2777
3048
|
});
|
|
3049
|
+
await mermaid.parse(entry.code);
|
|
2778
3050
|
const id = `es-mermaid-${Math.random().toString(36).slice(2)}`;
|
|
2779
3051
|
const { svg: rendered } = await mermaid.render(id, entry.code);
|
|
2780
|
-
if (!cancelled)
|
|
2781
|
-
|
|
2782
|
-
|
|
3052
|
+
if (!cancelled) {
|
|
3053
|
+
setSvg(rendered);
|
|
3054
|
+
setError(null);
|
|
3055
|
+
}
|
|
3056
|
+
} catch (err) {
|
|
3057
|
+
if (!cancelled) {
|
|
3058
|
+
setSvg(null);
|
|
3059
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
3060
|
+
}
|
|
2783
3061
|
}
|
|
2784
3062
|
};
|
|
2785
3063
|
void draw();
|
|
@@ -2793,8 +3071,8 @@ function MermaidView({ entry, load }) {
|
|
|
2793
3071
|
}, [entry.code, load]);
|
|
2794
3072
|
if (svg) {
|
|
2795
3073
|
return /* @__PURE__ */ jsxs31("figure", { ref, className: "my-3", children: [
|
|
2796
|
-
entry.title ? /* @__PURE__ */
|
|
2797
|
-
/* @__PURE__ */
|
|
3074
|
+
entry.title ? /* @__PURE__ */ jsx47("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
|
|
3075
|
+
/* @__PURE__ */ jsx47(
|
|
2798
3076
|
"div",
|
|
2799
3077
|
{
|
|
2800
3078
|
role: "img",
|
|
@@ -2805,11 +3083,25 @@ function MermaidView({ entry, load }) {
|
|
|
2805
3083
|
)
|
|
2806
3084
|
] });
|
|
2807
3085
|
}
|
|
2808
|
-
return /* @__PURE__ */
|
|
3086
|
+
return /* @__PURE__ */ jsxs31(Fragment14, { children: [
|
|
3087
|
+
error ? /* @__PURE__ */ jsxs31(
|
|
3088
|
+
"p",
|
|
3089
|
+
{
|
|
3090
|
+
role: "alert",
|
|
3091
|
+
"data-es-mermaid-error": true,
|
|
3092
|
+
className: "mt-3 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive",
|
|
3093
|
+
children: [
|
|
3094
|
+
"Diagram failed to render: ",
|
|
3095
|
+
error
|
|
3096
|
+
]
|
|
3097
|
+
}
|
|
3098
|
+
) : null,
|
|
3099
|
+
/* @__PURE__ */ jsx47(MermaidSource, { entry, ref })
|
|
3100
|
+
] });
|
|
2809
3101
|
}
|
|
2810
3102
|
|
|
2811
3103
|
// src/interactive/island-renderers.tsx
|
|
2812
|
-
import { jsx as
|
|
3104
|
+
import { jsx as jsx48 } from "react/jsx-runtime";
|
|
2813
3105
|
var HLJS_ESM = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/highlight.min.js";
|
|
2814
3106
|
var MERMAID_ESM = "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
|
|
2815
3107
|
function cachedCdnModule(url) {
|
|
@@ -2826,8 +3118,8 @@ function cachedCdnModule(url) {
|
|
|
2826
3118
|
var loadMermaidFromCdn = cachedCdnModule(MERMAID_ESM);
|
|
2827
3119
|
var loadHljs = cachedCdnModule(HLJS_ESM);
|
|
2828
3120
|
function CdnHighlightedCode({ entry }) {
|
|
2829
|
-
const [html, setHtml] =
|
|
2830
|
-
|
|
3121
|
+
const [html, setHtml] = useState10(null);
|
|
3122
|
+
useEffect9(() => {
|
|
2831
3123
|
let cancelled = false;
|
|
2832
3124
|
void (async () => {
|
|
2833
3125
|
try {
|
|
@@ -2843,13 +3135,13 @@ function CdnHighlightedCode({ entry }) {
|
|
|
2843
3135
|
cancelled = true;
|
|
2844
3136
|
};
|
|
2845
3137
|
}, [entry.content, entry.lang]);
|
|
2846
|
-
return /* @__PURE__ */
|
|
3138
|
+
return /* @__PURE__ */ jsx48(CodeFigure, { label: entry.label, children: html !== null ? /* @__PURE__ */ jsx48(
|
|
2847
3139
|
"code",
|
|
2848
3140
|
{
|
|
2849
3141
|
className: cn("hljs font-mono text-xs", entry.lang && `language-${entry.lang}`),
|
|
2850
3142
|
dangerouslySetInnerHTML: { __html: html }
|
|
2851
3143
|
}
|
|
2852
|
-
) : /* @__PURE__ */
|
|
3144
|
+
) : /* @__PURE__ */ jsx48("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
|
|
2853
3145
|
}
|
|
2854
3146
|
function buildIslandRenderers(opts) {
|
|
2855
3147
|
const renderers = {};
|
|
@@ -2863,7 +3155,7 @@ function buildIslandRenderers(opts) {
|
|
|
2863
3155
|
}
|
|
2864
3156
|
|
|
2865
3157
|
// src/interactive/ReportInteractiveIsland.tsx
|
|
2866
|
-
import { jsx as
|
|
3158
|
+
import { jsx as jsx49 } from "react/jsx-runtime";
|
|
2867
3159
|
function ReportInteractiveIsland({
|
|
2868
3160
|
report,
|
|
2869
3161
|
title,
|
|
@@ -2877,7 +3169,7 @@ function ReportInteractiveIsland({
|
|
|
2877
3169
|
() => buildIslandRenderers({ syntaxHighlighting, mermaid }),
|
|
2878
3170
|
[syntaxHighlighting, mermaid]
|
|
2879
3171
|
);
|
|
2880
|
-
return /* @__PURE__ */
|
|
3172
|
+
return /* @__PURE__ */ jsx49(
|
|
2881
3173
|
ReportInteractive,
|
|
2882
3174
|
{
|
|
2883
3175
|
report,
|