executable-stories-react 0.5.0 → 0.7.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 +244 -158
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -1
- package/dist/index.d.ts +18 -1
- package/dist/index.js +243 -158
- package/dist/index.js.map +1 -1
- package/dist/interactive.cjs +469 -258
- package/dist/interactive.cjs.map +1 -1
- package/dist/interactive.js +469 -258
- package/dist/interactive.js.map +1 -1
- package/dist/report-island.global.js +29 -24
- package/dist/ssr.cjs +210 -126
- package/dist/ssr.cjs.map +1 -1
- package/dist/ssr.js +210 -126
- package/dist/ssr.js.map +1 -1
- package/dist/tailwind.css +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -59,6 +59,7 @@ __export(src_exports, {
|
|
|
59
59
|
ReportSchemaError: () => ReportSchemaError,
|
|
60
60
|
ReportStepItem: () => ReportStepItem,
|
|
61
61
|
ReportSteps: () => ReportSteps,
|
|
62
|
+
ReportStoryboard: () => ReportStoryboard,
|
|
62
63
|
ReportSummary: () => ReportSummary,
|
|
63
64
|
ReportSummaryView: () => ReportSummaryView,
|
|
64
65
|
ReportTrace: () => ReportTrace,
|
|
@@ -299,7 +300,7 @@ function DocLink({ entry }) {
|
|
|
299
300
|
// src/components/doc/DocSection.tsx
|
|
300
301
|
var import_marked = require("marked");
|
|
301
302
|
|
|
302
|
-
//
|
|
303
|
+
// ../executable-stories-core/dist/utils/url.js
|
|
303
304
|
function safeUrl(value) {
|
|
304
305
|
if (!value) return void 0;
|
|
305
306
|
const trimmed = value.trim();
|
|
@@ -594,18 +595,101 @@ function ReportStepItem({ step }) {
|
|
|
594
595
|
);
|
|
595
596
|
}
|
|
596
597
|
|
|
597
|
-
//
|
|
598
|
+
// ../executable-stories-core/dist/storyboard.js
|
|
599
|
+
function findScreenshot(entries) {
|
|
600
|
+
for (const entry of entries) {
|
|
601
|
+
if (entry.kind === "screenshot") return entry;
|
|
602
|
+
if (entry.children) {
|
|
603
|
+
const nested = findScreenshot(entry.children);
|
|
604
|
+
if (nested) return nested;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
return void 0;
|
|
608
|
+
}
|
|
609
|
+
function extractStoryboardFrames(scenario) {
|
|
610
|
+
const frames = [];
|
|
611
|
+
for (const step of scenario.steps) {
|
|
612
|
+
const shot = findScreenshot(step.docEntries);
|
|
613
|
+
if (!shot) continue;
|
|
614
|
+
frames.push({
|
|
615
|
+
stepId: step.id,
|
|
616
|
+
stepIndex: step.index,
|
|
617
|
+
keyword: step.keyword,
|
|
618
|
+
text: step.text,
|
|
619
|
+
status: step.status,
|
|
620
|
+
path: shot.path,
|
|
621
|
+
...shot.alt !== void 0 && { alt: shot.alt }
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
return frames;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
// src/components/ReportStoryboard.tsx
|
|
598
628
|
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
629
|
+
var FRAME_GLYPH = {
|
|
630
|
+
passed: "\u2713",
|
|
631
|
+
failed: "\u2717",
|
|
632
|
+
skipped: "\u25CB",
|
|
633
|
+
pending: "\u25CB"
|
|
634
|
+
};
|
|
635
|
+
var FRAME_GLYPH_COLOR = {
|
|
636
|
+
passed: "text-pass",
|
|
637
|
+
failed: "text-fail",
|
|
638
|
+
skipped: "text-skip",
|
|
639
|
+
pending: "text-pend"
|
|
640
|
+
};
|
|
641
|
+
function ReportStoryboard({ scenario }) {
|
|
642
|
+
const frames = extractStoryboardFrames(scenario);
|
|
643
|
+
if (frames.length < 2) return null;
|
|
644
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("section", { "data-slot": "storyboard", "aria-label": "Storyboard", className: "mb-3", children: [
|
|
645
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h4", { className: "mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Storyboard" }),
|
|
646
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("ol", { className: "flex gap-3 overflow-x-auto pb-2", children: frames.map((frame) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(StoryboardFrameItem, { frame }, frame.stepId)) })
|
|
647
|
+
] });
|
|
648
|
+
}
|
|
649
|
+
function StoryboardFrameItem({ frame }) {
|
|
650
|
+
const src = isLocalFsPath(frame.path) ? void 0 : safeImageUrl(frame.path);
|
|
651
|
+
const label = `${frame.keyword} ${frame.text}`;
|
|
652
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("li", { className: "w-40 shrink-0", children: [
|
|
653
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
654
|
+
"a",
|
|
655
|
+
{
|
|
656
|
+
href: `#${frame.stepId}`,
|
|
657
|
+
"aria-label": `Jump to step: ${label}`,
|
|
658
|
+
className: "block overflow-hidden rounded-md border border-border transition-colors hover:border-ring",
|
|
659
|
+
children: src ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
660
|
+
"img",
|
|
661
|
+
{
|
|
662
|
+
src,
|
|
663
|
+
alt: frame.alt ?? label,
|
|
664
|
+
loading: "lazy",
|
|
665
|
+
className: "h-24 w-full bg-muted object-cover object-top"
|
|
666
|
+
}
|
|
667
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "flex h-24 w-full items-center justify-center border-b border-dashed border-border bg-muted px-2 text-center text-[0.6875rem] text-muted-foreground", children: "Screenshot unavailable" })
|
|
668
|
+
}
|
|
669
|
+
),
|
|
670
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("p", { className: "mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug", children: [
|
|
671
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { "aria-hidden": true, className: cn("shrink-0", FRAME_GLYPH_COLOR[frame.status]), children: FRAME_GLYPH[frame.status] ?? "\u25CB" }),
|
|
672
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "min-w-0", children: [
|
|
673
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "font-mono font-semibold text-keyword", children: frame.keyword }),
|
|
674
|
+
" ",
|
|
675
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-muted-foreground", children: frame.alt ?? frame.text })
|
|
676
|
+
] })
|
|
677
|
+
] })
|
|
678
|
+
] });
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// src/components/ReportAttachments.tsx
|
|
682
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
599
683
|
function ReportAttachments({ attachments }) {
|
|
600
684
|
if (attachments.length === 0) return null;
|
|
601
685
|
return (
|
|
602
686
|
// role="group" (not a labelled <section>) so multiple scenarios' attachment
|
|
603
687
|
// blocks don't create duplicate "Attachments" region landmarks.
|
|
604
|
-
/* @__PURE__ */ (0,
|
|
688
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
|
|
605
689
|
const dataUri = att.contentEncoding === "BASE64" ? `data:${att.mediaType};base64,${att.body}` : `data:${att.mediaType},${encodeURIComponent(att.body)}`;
|
|
606
690
|
const isImage = att.mediaType.startsWith("image/");
|
|
607
|
-
return /* @__PURE__ */ (0,
|
|
608
|
-
/* @__PURE__ */ (0,
|
|
691
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
692
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
609
693
|
"img",
|
|
610
694
|
{
|
|
611
695
|
src: dataUri,
|
|
@@ -614,8 +698,8 @@ function ReportAttachments({ attachments }) {
|
|
|
614
698
|
className: "max-w-full rounded-md border border-border"
|
|
615
699
|
}
|
|
616
700
|
),
|
|
617
|
-
/* @__PURE__ */ (0,
|
|
618
|
-
] }) : /* @__PURE__ */ (0,
|
|
701
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
|
|
702
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
619
703
|
"a",
|
|
620
704
|
{
|
|
621
705
|
href: dataUri,
|
|
@@ -624,7 +708,7 @@ function ReportAttachments({ attachments }) {
|
|
|
624
708
|
children: [
|
|
625
709
|
att.name,
|
|
626
710
|
" ",
|
|
627
|
-
/* @__PURE__ */ (0,
|
|
711
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "text-muted-foreground", children: [
|
|
628
712
|
"(",
|
|
629
713
|
att.mediaType,
|
|
630
714
|
")"
|
|
@@ -712,7 +796,7 @@ function traceWindow(rows) {
|
|
|
712
796
|
}
|
|
713
797
|
|
|
714
798
|
// src/components/ReportTrace.tsx
|
|
715
|
-
var
|
|
799
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
716
800
|
var BAR_COLOR = {
|
|
717
801
|
ok: "bg-pass",
|
|
718
802
|
error: "bg-fail",
|
|
@@ -723,8 +807,8 @@ function ReportTrace({ spans }) {
|
|
|
723
807
|
const rows = toTraceRows(spans);
|
|
724
808
|
if (rows.length === 0) return null;
|
|
725
809
|
const { minStartMs, totalMs } = traceWindow(rows);
|
|
726
|
-
return /* @__PURE__ */ (0,
|
|
727
|
-
/* @__PURE__ */ (0,
|
|
810
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("details", { className: "mt-3 rounded-md border border-border bg-muted/30", children: [
|
|
811
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("summary", { className: "cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground", children: [
|
|
728
812
|
"Trace (",
|
|
729
813
|
rows.length,
|
|
730
814
|
" span",
|
|
@@ -733,11 +817,11 @@ function ReportTrace({ spans }) {
|
|
|
733
817
|
formatDuration(totalMs),
|
|
734
818
|
")"
|
|
735
819
|
] }),
|
|
736
|
-
/* @__PURE__ */ (0,
|
|
820
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
|
|
737
821
|
const leftPct = (row.startTimeMs - minStartMs) / totalMs * 100;
|
|
738
822
|
const widthPct = Math.max(row.durationMs / totalMs * 100, 0.5);
|
|
739
|
-
return /* @__PURE__ */ (0,
|
|
740
|
-
/* @__PURE__ */ (0,
|
|
823
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("li", { className: "flex items-center gap-2", children: [
|
|
824
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
741
825
|
"span",
|
|
742
826
|
{
|
|
743
827
|
className: "min-w-0 flex-1 truncate text-foreground",
|
|
@@ -746,14 +830,14 @@ function ReportTrace({ spans }) {
|
|
|
746
830
|
children: row.name
|
|
747
831
|
}
|
|
748
832
|
),
|
|
749
|
-
/* @__PURE__ */ (0,
|
|
833
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
750
834
|
"span",
|
|
751
835
|
{
|
|
752
836
|
className: cn("absolute top-0 h-full rounded-sm", BAR_COLOR[row.status]),
|
|
753
837
|
style: { left: `${leftPct}%`, width: `${widthPct}%` }
|
|
754
838
|
}
|
|
755
839
|
) }),
|
|
756
|
-
/* @__PURE__ */ (0,
|
|
840
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
|
|
757
841
|
] }, `${row.spanId}-${i}`);
|
|
758
842
|
}) })
|
|
759
843
|
] });
|
|
@@ -804,7 +888,7 @@ function flakinessOf(entries) {
|
|
|
804
888
|
}
|
|
805
889
|
|
|
806
890
|
// src/components/ScenarioRunHistory.tsx
|
|
807
|
-
var
|
|
891
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
808
892
|
var MAX_DOTS = 10;
|
|
809
893
|
var DOT_COLOR = {
|
|
810
894
|
passed: "bg-pass",
|
|
@@ -824,16 +908,16 @@ function ScenarioRunHistory({ scenarioId }) {
|
|
|
824
908
|
const recent = entries.slice(-MAX_DOTS);
|
|
825
909
|
const flaky = flakinessOf(recent) === "flaky";
|
|
826
910
|
const summary = flaky ? `${describeRunHistory(recent)} \xB7 Flaky` : describeRunHistory(recent);
|
|
827
|
-
return /* @__PURE__ */ (0,
|
|
828
|
-
flaky ? /* @__PURE__ */ (0,
|
|
829
|
-
/* @__PURE__ */ (0,
|
|
911
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
|
|
912
|
+
flaky ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
|
|
913
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
830
914
|
"span",
|
|
831
915
|
{
|
|
832
916
|
role: "img",
|
|
833
917
|
"aria-label": `Run history: ${summary}`,
|
|
834
918
|
title: summary,
|
|
835
919
|
className: "flex shrink-0 items-center gap-[3px]",
|
|
836
|
-
children: recent.map((e, i) => /* @__PURE__ */ (0,
|
|
920
|
+
children: recent.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
837
921
|
"span",
|
|
838
922
|
{
|
|
839
923
|
"aria-hidden": true,
|
|
@@ -872,9 +956,9 @@ function useScenarioActions() {
|
|
|
872
956
|
|
|
873
957
|
// src/components/ui/card.tsx
|
|
874
958
|
var React2 = require("react");
|
|
875
|
-
var
|
|
959
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
876
960
|
function Card({ className, ...props }) {
|
|
877
|
-
return /* @__PURE__ */ (0,
|
|
961
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
878
962
|
"div",
|
|
879
963
|
{
|
|
880
964
|
"data-slot": "card",
|
|
@@ -887,7 +971,7 @@ function Card({ className, ...props }) {
|
|
|
887
971
|
);
|
|
888
972
|
}
|
|
889
973
|
function CardHeader({ className, ...props }) {
|
|
890
|
-
return /* @__PURE__ */ (0,
|
|
974
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
891
975
|
"div",
|
|
892
976
|
{
|
|
893
977
|
"data-slot": "card-header",
|
|
@@ -900,7 +984,7 @@ function CardHeader({ className, ...props }) {
|
|
|
900
984
|
);
|
|
901
985
|
}
|
|
902
986
|
function CardContent({ className, ...props }) {
|
|
903
|
-
return /* @__PURE__ */ (0,
|
|
987
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
904
988
|
"div",
|
|
905
989
|
{
|
|
906
990
|
"data-slot": "card-content",
|
|
@@ -914,13 +998,13 @@ function CardContent({ className, ...props }) {
|
|
|
914
998
|
var React3 = require("react");
|
|
915
999
|
var import_menu = require("@base-ui/react/menu");
|
|
916
1000
|
var import_lucide_react = require("lucide-react");
|
|
917
|
-
var
|
|
1001
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
918
1002
|
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";
|
|
919
1003
|
function DropdownMenu(props) {
|
|
920
|
-
return /* @__PURE__ */ (0,
|
|
1004
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_menu.Menu.Root, { "data-slot": "dropdown-menu", ...props });
|
|
921
1005
|
}
|
|
922
1006
|
function DropdownMenuTrigger(props) {
|
|
923
|
-
return /* @__PURE__ */ (0,
|
|
1007
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_menu.Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
|
|
924
1008
|
}
|
|
925
1009
|
function DropdownMenuContent({
|
|
926
1010
|
className,
|
|
@@ -928,14 +1012,14 @@ function DropdownMenuContent({
|
|
|
928
1012
|
sideOffset = 4,
|
|
929
1013
|
...props
|
|
930
1014
|
}) {
|
|
931
|
-
return /* @__PURE__ */ (0,
|
|
1015
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_menu.Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
932
1016
|
import_menu.Menu.Positioner,
|
|
933
1017
|
{
|
|
934
1018
|
"data-slot": "dropdown-menu-positioner",
|
|
935
1019
|
className: "z-50",
|
|
936
1020
|
align,
|
|
937
1021
|
sideOffset,
|
|
938
|
-
children: /* @__PURE__ */ (0,
|
|
1022
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
939
1023
|
import_menu.Menu.Popup,
|
|
940
1024
|
{
|
|
941
1025
|
"data-slot": "dropdown-menu-content",
|
|
@@ -953,7 +1037,7 @@ function DropdownMenuItem({
|
|
|
953
1037
|
className,
|
|
954
1038
|
...props
|
|
955
1039
|
}) {
|
|
956
|
-
return /* @__PURE__ */ (0,
|
|
1040
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
957
1041
|
import_menu.Menu.Item,
|
|
958
1042
|
{
|
|
959
1043
|
"data-slot": "dropdown-menu-item",
|
|
@@ -965,7 +1049,7 @@ function DropdownMenuItem({
|
|
|
965
1049
|
|
|
966
1050
|
// src/components/ReportScenario.tsx
|
|
967
1051
|
var import_lucide_react2 = require("lucide-react");
|
|
968
|
-
var
|
|
1052
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
969
1053
|
var STATUS_META = {
|
|
970
1054
|
passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
|
|
971
1055
|
failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
|
|
@@ -981,7 +1065,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
981
1065
|
const collapsible = collapse !== null && !hideTitle;
|
|
982
1066
|
const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
|
|
983
1067
|
const actions = useScenarioActions();
|
|
984
|
-
return /* @__PURE__ */ (0,
|
|
1068
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
985
1069
|
Card,
|
|
986
1070
|
{
|
|
987
1071
|
id: scenario.id,
|
|
@@ -989,10 +1073,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
989
1073
|
...hideTitle ? { "aria-label": `${scenario.title}, ${label}` } : { "aria-labelledby": titleId },
|
|
990
1074
|
className: "gap-0 py-0",
|
|
991
1075
|
children: [
|
|
992
|
-
/* @__PURE__ */ (0,
|
|
993
|
-
/* @__PURE__ */ (0,
|
|
994
|
-
hideTitle ? null : /* @__PURE__ */ (0,
|
|
995
|
-
collapsible ? /* @__PURE__ */ (0,
|
|
1076
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(CardHeader, { className: "px-4 py-3", children: [
|
|
1077
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
|
|
1078
|
+
hideTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
|
|
1079
|
+
collapsible ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
996
1080
|
"button",
|
|
997
1081
|
{
|
|
998
1082
|
type: "button",
|
|
@@ -1001,49 +1085,49 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1001
1085
|
"aria-controls": bodyId,
|
|
1002
1086
|
"aria-label": `Toggle ${scenario.title}`,
|
|
1003
1087
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
1004
|
-
children: /* @__PURE__ */ (0,
|
|
1088
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
1005
1089
|
}
|
|
1006
1090
|
) : null,
|
|
1007
|
-
/* @__PURE__ */ (0,
|
|
1008
|
-
/* @__PURE__ */ (0,
|
|
1091
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
|
|
1092
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children: scenario.title })
|
|
1009
1093
|
] }),
|
|
1010
|
-
/* @__PURE__ */ (0,
|
|
1011
|
-
/* @__PURE__ */ (0,
|
|
1012
|
-
scenario.durationMs > 0 ? /* @__PURE__ */ (0,
|
|
1013
|
-
meta.showPill ? /* @__PURE__ */ (0,
|
|
1014
|
-
actions ? /* @__PURE__ */ (0,
|
|
1015
|
-
/* @__PURE__ */ (0,
|
|
1094
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
1095
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ScenarioRunHistory, { scenarioId: scenario.id }),
|
|
1096
|
+
scenario.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
|
|
1097
|
+
meta.showPill ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "sr-only", children: `Status: ${label}` }),
|
|
1098
|
+
actions ? /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(DropdownMenu, { children: [
|
|
1099
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1016
1100
|
DropdownMenuTrigger,
|
|
1017
1101
|
{
|
|
1018
1102
|
"aria-label": `Actions for ${scenario.title}`,
|
|
1019
1103
|
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
1020
|
-
children: /* @__PURE__ */ (0,
|
|
1104
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react2.MoreHorizontalIcon, { "aria-hidden": true })
|
|
1021
1105
|
}
|
|
1022
1106
|
),
|
|
1023
|
-
/* @__PURE__ */ (0,
|
|
1024
|
-
/* @__PURE__ */ (0,
|
|
1025
|
-
/* @__PURE__ */ (0,
|
|
1107
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(DropdownMenuContent, { align: "end", children: [
|
|
1108
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
|
|
1109
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react2.LinkIcon, {}),
|
|
1026
1110
|
" Copy link"
|
|
1027
1111
|
] }),
|
|
1028
|
-
/* @__PURE__ */ (0,
|
|
1029
|
-
/* @__PURE__ */ (0,
|
|
1112
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
|
|
1113
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react2.FileTextIcon, {}),
|
|
1030
1114
|
" Copy as Markdown"
|
|
1031
1115
|
] }),
|
|
1032
|
-
/* @__PURE__ */ (0,
|
|
1033
|
-
/* @__PURE__ */ (0,
|
|
1116
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
|
|
1117
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react2.SparklesIcon, {}),
|
|
1034
1118
|
" Explain with AI"
|
|
1035
1119
|
] })
|
|
1036
1120
|
] })
|
|
1037
1121
|
] }) : null
|
|
1038
1122
|
] })
|
|
1039
1123
|
] }),
|
|
1040
|
-
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0,
|
|
1041
|
-
scenario.tags.map((t) => /* @__PURE__ */ (0,
|
|
1042
|
-
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0,
|
|
1124
|
+
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
|
|
1125
|
+
scenario.tags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
|
|
1126
|
+
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("li", { children: ticket.url ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
|
|
1043
1127
|
] }) : null
|
|
1044
1128
|
] }),
|
|
1045
|
-
/* @__PURE__ */ (0,
|
|
1046
|
-
scenario.errorMessage ? /* @__PURE__ */ (0,
|
|
1129
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
|
|
1130
|
+
scenario.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1047
1131
|
"pre",
|
|
1048
1132
|
{
|
|
1049
1133
|
role: "alert",
|
|
@@ -1051,10 +1135,11 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1051
1135
|
children: scenario.errorMessage
|
|
1052
1136
|
}
|
|
1053
1137
|
) : null,
|
|
1054
|
-
/* @__PURE__ */ (0,
|
|
1055
|
-
|
|
1056
|
-
/* @__PURE__ */ (0,
|
|
1057
|
-
/* @__PURE__ */ (0,
|
|
1138
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ReportStoryboard, { scenario }),
|
|
1139
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ReportSteps, { scenario }),
|
|
1140
|
+
scenario.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
|
|
1141
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ReportAttachments, { attachments: scenario.attachments }),
|
|
1142
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ReportTrace, { spans: scenario.otelSpans })
|
|
1058
1143
|
] })
|
|
1059
1144
|
]
|
|
1060
1145
|
}
|
|
@@ -1062,13 +1147,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1062
1147
|
}
|
|
1063
1148
|
|
|
1064
1149
|
// src/components/ReportScenarioList.tsx
|
|
1065
|
-
var
|
|
1150
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1066
1151
|
function ReportScenarioList({ feature }) {
|
|
1067
|
-
return /* @__PURE__ */ (0,
|
|
1152
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_jsx_runtime25.Fragment, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportScenario, { scenario }, scenario.id)) });
|
|
1068
1153
|
}
|
|
1069
1154
|
|
|
1070
1155
|
// src/components/ReportFeature.tsx
|
|
1071
|
-
var
|
|
1156
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1072
1157
|
function ReportFeature({ feature }) {
|
|
1073
1158
|
const titleId = `${feature.id}-title`;
|
|
1074
1159
|
const bodyId = `${feature.id}-body`;
|
|
@@ -1079,7 +1164,7 @@ function ReportFeature({ feature }) {
|
|
|
1079
1164
|
return (
|
|
1080
1165
|
// Suite = a section heading + a divider, NOT another bordered card. Drops a
|
|
1081
1166
|
// layer of nesting so the scenario cards below read as the primary unit.
|
|
1082
|
-
/* @__PURE__ */ (0,
|
|
1167
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
1083
1168
|
"section",
|
|
1084
1169
|
{
|
|
1085
1170
|
id: feature.id,
|
|
@@ -1087,9 +1172,9 @@ function ReportFeature({ feature }) {
|
|
|
1087
1172
|
"aria-labelledby": titleId,
|
|
1088
1173
|
className: "flex flex-col gap-3",
|
|
1089
1174
|
children: [
|
|
1090
|
-
/* @__PURE__ */ (0,
|
|
1091
|
-
/* @__PURE__ */ (0,
|
|
1092
|
-
/* @__PURE__ */ (0,
|
|
1175
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
|
|
1176
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "min-w-0", children: [
|
|
1177
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
1093
1178
|
"button",
|
|
1094
1179
|
{
|
|
1095
1180
|
type: "button",
|
|
@@ -1098,31 +1183,31 @@ function ReportFeature({ feature }) {
|
|
|
1098
1183
|
"aria-controls": bodyId,
|
|
1099
1184
|
className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
|
|
1100
1185
|
children: [
|
|
1101
|
-
/* @__PURE__ */ (0,
|
|
1102
|
-
/* @__PURE__ */ (0,
|
|
1186
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
|
|
1187
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "truncate", children: feature.title })
|
|
1103
1188
|
]
|
|
1104
1189
|
}
|
|
1105
1190
|
) : feature.title }),
|
|
1106
|
-
/* @__PURE__ */ (0,
|
|
1191
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
|
|
1107
1192
|
] }),
|
|
1108
|
-
/* @__PURE__ */ (0,
|
|
1193
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
1109
1194
|
"p",
|
|
1110
1195
|
{
|
|
1111
1196
|
className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
|
|
1112
1197
|
"aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
|
|
1113
1198
|
children: [
|
|
1114
|
-
/* @__PURE__ */ (0,
|
|
1199
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { children: [
|
|
1115
1200
|
s.passed,
|
|
1116
1201
|
" passed"
|
|
1117
1202
|
] }),
|
|
1118
|
-
/* @__PURE__ */ (0,
|
|
1119
|
-
/* @__PURE__ */ (0,
|
|
1203
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1204
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
|
|
1120
1205
|
s.failed,
|
|
1121
1206
|
" failed"
|
|
1122
1207
|
] }),
|
|
1123
|
-
skipped > 0 ? /* @__PURE__ */ (0,
|
|
1124
|
-
/* @__PURE__ */ (0,
|
|
1125
|
-
/* @__PURE__ */ (0,
|
|
1208
|
+
skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
|
|
1209
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1210
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("span", { children: [
|
|
1126
1211
|
skipped,
|
|
1127
1212
|
" skipped"
|
|
1128
1213
|
] })
|
|
@@ -1131,7 +1216,7 @@ function ReportFeature({ feature }) {
|
|
|
1131
1216
|
}
|
|
1132
1217
|
)
|
|
1133
1218
|
] }),
|
|
1134
|
-
/* @__PURE__ */ (0,
|
|
1219
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportScenarioList, { feature }) })
|
|
1135
1220
|
]
|
|
1136
1221
|
}
|
|
1137
1222
|
)
|
|
@@ -1139,17 +1224,17 @@ function ReportFeature({ feature }) {
|
|
|
1139
1224
|
}
|
|
1140
1225
|
|
|
1141
1226
|
// src/components/ReportFeatureList.tsx
|
|
1142
|
-
var
|
|
1227
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1143
1228
|
function ReportFeatureList() {
|
|
1144
1229
|
const report = useReport();
|
|
1145
|
-
return /* @__PURE__ */ (0,
|
|
1230
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ReportFeature, { feature }, feature.id)) });
|
|
1146
1231
|
}
|
|
1147
1232
|
|
|
1148
1233
|
// src/components/ui/empty.tsx
|
|
1149
1234
|
var import_class_variance_authority2 = require("class-variance-authority");
|
|
1150
|
-
var
|
|
1235
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1151
1236
|
function Empty({ className, ...props }) {
|
|
1152
|
-
return /* @__PURE__ */ (0,
|
|
1237
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
1153
1238
|
"div",
|
|
1154
1239
|
{
|
|
1155
1240
|
"data-slot": "empty",
|
|
@@ -1162,7 +1247,7 @@ function Empty({ className, ...props }) {
|
|
|
1162
1247
|
);
|
|
1163
1248
|
}
|
|
1164
1249
|
function EmptyHeader({ className, ...props }) {
|
|
1165
|
-
return /* @__PURE__ */ (0,
|
|
1250
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
1166
1251
|
"div",
|
|
1167
1252
|
{
|
|
1168
1253
|
"data-slot": "empty-header",
|
|
@@ -1189,7 +1274,7 @@ var emptyMediaVariants = (0, import_class_variance_authority2.cva)(
|
|
|
1189
1274
|
}
|
|
1190
1275
|
);
|
|
1191
1276
|
function EmptyTitle({ className, ...props }) {
|
|
1192
|
-
return /* @__PURE__ */ (0,
|
|
1277
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
1193
1278
|
"div",
|
|
1194
1279
|
{
|
|
1195
1280
|
"data-slot": "empty-title",
|
|
@@ -1200,16 +1285,16 @@ function EmptyTitle({ className, ...props }) {
|
|
|
1200
1285
|
}
|
|
1201
1286
|
|
|
1202
1287
|
// src/components/ReportEmpty.tsx
|
|
1203
|
-
var
|
|
1288
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
1204
1289
|
function ReportEmpty({ message }) {
|
|
1205
|
-
return /* @__PURE__ */ (0,
|
|
1290
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(EmptyHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
|
|
1206
1291
|
}
|
|
1207
1292
|
|
|
1208
1293
|
// src/components/ReportSummary.tsx
|
|
1209
|
-
var
|
|
1294
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
1210
1295
|
function ReportSummary({ className }) {
|
|
1211
1296
|
const report = useReport();
|
|
1212
|
-
return /* @__PURE__ */ (0,
|
|
1297
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
1213
1298
|
ReportSummaryView,
|
|
1214
1299
|
{
|
|
1215
1300
|
summary: report.summary,
|
|
@@ -1235,7 +1320,7 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1235
1320
|
if (summary.pending > 0) {
|
|
1236
1321
|
cards.push({ status: "pending", label: "Pending", value: summary.pending });
|
|
1237
1322
|
}
|
|
1238
|
-
return /* @__PURE__ */ (0,
|
|
1323
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
1239
1324
|
"dl",
|
|
1240
1325
|
{
|
|
1241
1326
|
className: cn(
|
|
@@ -1248,17 +1333,17 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1248
1333
|
"aria-label": ariaLabel,
|
|
1249
1334
|
children: cards.map((c) => {
|
|
1250
1335
|
const tone = TONE[c.status];
|
|
1251
|
-
return /* @__PURE__ */ (0,
|
|
1336
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
|
|
1252
1337
|
"div",
|
|
1253
1338
|
{
|
|
1254
1339
|
"data-status": c.status,
|
|
1255
1340
|
className: "rounded-lg border bg-card px-4 py-3",
|
|
1256
1341
|
children: [
|
|
1257
|
-
/* @__PURE__ */ (0,
|
|
1258
|
-
/* @__PURE__ */ (0,
|
|
1342
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
|
|
1343
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
|
|
1259
1344
|
c.label
|
|
1260
1345
|
] }),
|
|
1261
|
-
/* @__PURE__ */ (0,
|
|
1346
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
|
|
1262
1347
|
]
|
|
1263
1348
|
},
|
|
1264
1349
|
c.status
|
|
@@ -1318,7 +1403,7 @@ function prUrl(ci) {
|
|
|
1318
1403
|
}
|
|
1319
1404
|
|
|
1320
1405
|
// src/components/ReportMeta.tsx
|
|
1321
|
-
var
|
|
1406
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
1322
1407
|
function ReportMeta() {
|
|
1323
1408
|
const report = useReport();
|
|
1324
1409
|
const items = [];
|
|
@@ -1341,13 +1426,13 @@ function ReportMeta() {
|
|
|
1341
1426
|
const short = sha.slice(0, 8);
|
|
1342
1427
|
items.push({
|
|
1343
1428
|
label: "Commit",
|
|
1344
|
-
value: url ? /* @__PURE__ */ (0,
|
|
1429
|
+
value: url ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
|
|
1345
1430
|
});
|
|
1346
1431
|
}
|
|
1347
1432
|
if (report.ci) {
|
|
1348
1433
|
items.push({
|
|
1349
1434
|
label: "CI",
|
|
1350
|
-
value: report.ci.url ? /* @__PURE__ */ (0,
|
|
1435
|
+
value: report.ci.url ? /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
|
|
1351
1436
|
ciDisplayName(report.ci.name),
|
|
1352
1437
|
report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
|
|
1353
1438
|
] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
|
|
@@ -1358,7 +1443,7 @@ function ReportMeta() {
|
|
|
1358
1443
|
const label = `#${report.ci.prNumber}`;
|
|
1359
1444
|
items.push({
|
|
1360
1445
|
label: "PR",
|
|
1361
|
-
value: url ? /* @__PURE__ */ (0,
|
|
1446
|
+
value: url ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
|
|
1362
1447
|
});
|
|
1363
1448
|
}
|
|
1364
1449
|
if (items.length === 0) return null;
|
|
@@ -1366,48 +1451,48 @@ function ReportMeta() {
|
|
|
1366
1451
|
// Run metadata is useful but secondary to "what failed" — tuck it into a
|
|
1367
1452
|
// collapsed disclosure so it doesn't push the result down. Native <details>
|
|
1368
1453
|
// so it works with no JS (the SSR/no-hydration report still toggles).
|
|
1369
|
-
/* @__PURE__ */ (0,
|
|
1370
|
-
/* @__PURE__ */ (0,
|
|
1371
|
-
/* @__PURE__ */ (0,
|
|
1454
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
|
|
1455
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("summary", { className: "flex cursor-pointer list-none select-none items-center gap-1.5 px-4 py-2 font-medium text-muted-foreground [&::-webkit-details-marker]:hidden", children: [
|
|
1456
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
|
|
1372
1457
|
"Run details"
|
|
1373
1458
|
] }),
|
|
1374
|
-
/* @__PURE__ */ (0,
|
|
1375
|
-
/* @__PURE__ */ (0,
|
|
1376
|
-
/* @__PURE__ */ (0,
|
|
1459
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("dl", { className: "flex flex-wrap gap-x-5 gap-y-2 border-t border-border px-4 py-3 text-muted-foreground", "aria-label": "Run metadata", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex items-baseline gap-1.5", children: [
|
|
1460
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("dt", { className: "font-medium", children: item.label }),
|
|
1461
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("dd", { className: "font-mono text-foreground", children: item.value })
|
|
1377
1462
|
] }, item.label)) })
|
|
1378
1463
|
] })
|
|
1379
1464
|
);
|
|
1380
1465
|
}
|
|
1381
1466
|
|
|
1382
1467
|
// src/components/ReportSchemaError.tsx
|
|
1383
|
-
var
|
|
1468
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
1384
1469
|
function ReportSchemaError({ error }) {
|
|
1385
|
-
return /* @__PURE__ */ (0,
|
|
1386
|
-
/* @__PURE__ */ (0,
|
|
1387
|
-
/* @__PURE__ */ (0,
|
|
1388
|
-
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0,
|
|
1470
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
|
|
1471
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("strong", { children: "Report could not be displayed." }) }),
|
|
1472
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { children: error.message }),
|
|
1473
|
+
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("p", { children: [
|
|
1389
1474
|
"The report bundle is newer than this version of ",
|
|
1390
|
-
/* @__PURE__ */ (0,
|
|
1475
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("code", { children: "executable-stories-react" }),
|
|
1391
1476
|
". Upgrade the package, or regenerate the report with an older formatters CLI."
|
|
1392
1477
|
] }) : null,
|
|
1393
|
-
error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0,
|
|
1394
|
-
/* @__PURE__ */ (0,
|
|
1478
|
+
error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("details", { children: [
|
|
1479
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("summary", { children: [
|
|
1395
1480
|
error.issues.length,
|
|
1396
1481
|
" validation issue",
|
|
1397
1482
|
error.issues.length === 1 ? "" : "s"
|
|
1398
1483
|
] }),
|
|
1399
|
-
/* @__PURE__ */ (0,
|
|
1484
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
|
|
1400
1485
|
] }) : null
|
|
1401
1486
|
] });
|
|
1402
1487
|
}
|
|
1403
1488
|
|
|
1404
1489
|
// src/components/ReportShell.tsx
|
|
1405
|
-
var
|
|
1490
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
1406
1491
|
function ReportTitleBlock({ title }) {
|
|
1407
|
-
return /* @__PURE__ */ (0,
|
|
1408
|
-
/* @__PURE__ */ (0,
|
|
1409
|
-
/* @__PURE__ */ (0,
|
|
1410
|
-
/* @__PURE__ */ (0,
|
|
1492
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
|
|
1493
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("h1", { children: title ?? "Story Report" }),
|
|
1494
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ReportSummary, {}),
|
|
1495
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ReportMeta, {})
|
|
1411
1496
|
] });
|
|
1412
1497
|
}
|
|
1413
1498
|
function ReportErrorShell({
|
|
@@ -1416,28 +1501,28 @@ function ReportErrorShell({
|
|
|
1416
1501
|
title,
|
|
1417
1502
|
dataTheme
|
|
1418
1503
|
}) {
|
|
1419
|
-
return /* @__PURE__ */ (0,
|
|
1504
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ReportSchemaError, { error }) });
|
|
1420
1505
|
}
|
|
1421
1506
|
|
|
1422
1507
|
// src/components/Report.tsx
|
|
1423
|
-
var
|
|
1508
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
1424
1509
|
function Report(props) {
|
|
1425
1510
|
const { report, customRenderers, renderers, className, title, dataTheme } = props;
|
|
1426
1511
|
const result = unwrapReport(report);
|
|
1427
1512
|
if (!result.ok) {
|
|
1428
|
-
return /* @__PURE__ */ (0,
|
|
1513
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
|
|
1429
1514
|
}
|
|
1430
1515
|
const data = result.data;
|
|
1431
1516
|
const hasContent = data.features.length > 0;
|
|
1432
|
-
return /* @__PURE__ */ (0,
|
|
1433
|
-
/* @__PURE__ */ (0,
|
|
1434
|
-
hasContent ? /* @__PURE__ */ (0,
|
|
1517
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
|
|
1518
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("header", { className: "es-report-header", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportTitleBlock, { title }) }),
|
|
1519
|
+
hasContent ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportFeatureList, {}) : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportEmpty, {})
|
|
1435
1520
|
] }) });
|
|
1436
1521
|
}
|
|
1437
1522
|
|
|
1438
1523
|
// src/components/doc/MermaidView.tsx
|
|
1439
1524
|
var import_react8 = require("react");
|
|
1440
|
-
var
|
|
1525
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
1441
1526
|
function prefersDark(el) {
|
|
1442
1527
|
const themed = el?.closest("[data-theme]");
|
|
1443
1528
|
if (themed?.dataset.theme === "dark") return true;
|
|
@@ -1474,9 +1559,9 @@ function MermaidView({ entry, load }) {
|
|
|
1474
1559
|
};
|
|
1475
1560
|
}, [entry.code, load]);
|
|
1476
1561
|
if (svg) {
|
|
1477
|
-
return /* @__PURE__ */ (0,
|
|
1478
|
-
entry.title ? /* @__PURE__ */ (0,
|
|
1479
|
-
/* @__PURE__ */ (0,
|
|
1562
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("figure", { ref, className: "my-3", children: [
|
|
1563
|
+
entry.title ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
|
|
1564
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
1480
1565
|
"div",
|
|
1481
1566
|
{
|
|
1482
1567
|
role: "img",
|
|
@@ -1487,18 +1572,18 @@ function MermaidView({ entry, load }) {
|
|
|
1487
1572
|
)
|
|
1488
1573
|
] });
|
|
1489
1574
|
}
|
|
1490
|
-
return /* @__PURE__ */ (0,
|
|
1575
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(MermaidSource, { entry, ref });
|
|
1491
1576
|
}
|
|
1492
1577
|
|
|
1493
1578
|
// src/components/doc/MermaidDiagram.tsx
|
|
1494
|
-
var
|
|
1579
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
1495
1580
|
var mermaidLoader;
|
|
1496
1581
|
function loadMermaid() {
|
|
1497
1582
|
mermaidLoader ??= import("mermaid").then((m) => m.default);
|
|
1498
1583
|
return mermaidLoader;
|
|
1499
1584
|
}
|
|
1500
1585
|
function MermaidDiagram({ entry, load = loadMermaid }) {
|
|
1501
|
-
return /* @__PURE__ */ (0,
|
|
1586
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(MermaidView, { entry, load });
|
|
1502
1587
|
}
|
|
1503
1588
|
|
|
1504
1589
|
// src/components/ScenarioExplorer.tsx
|
|
@@ -1508,12 +1593,12 @@ var import_react9 = require("react");
|
|
|
1508
1593
|
var React4 = require("react");
|
|
1509
1594
|
var import_cmdk = require("cmdk");
|
|
1510
1595
|
var import_lucide_react3 = require("lucide-react");
|
|
1511
|
-
var
|
|
1596
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
1512
1597
|
function Command({
|
|
1513
1598
|
className,
|
|
1514
1599
|
...props
|
|
1515
1600
|
}) {
|
|
1516
|
-
return /* @__PURE__ */ (0,
|
|
1601
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
1517
1602
|
import_cmdk.Command,
|
|
1518
1603
|
{
|
|
1519
1604
|
"data-slot": "command",
|
|
@@ -1529,14 +1614,14 @@ function CommandInput({
|
|
|
1529
1614
|
className,
|
|
1530
1615
|
...props
|
|
1531
1616
|
}) {
|
|
1532
|
-
return /* @__PURE__ */ (0,
|
|
1617
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
|
|
1533
1618
|
"div",
|
|
1534
1619
|
{
|
|
1535
1620
|
"data-slot": "command-input-wrapper",
|
|
1536
1621
|
className: "flex h-9 items-center gap-2 border-b px-3",
|
|
1537
1622
|
children: [
|
|
1538
|
-
/* @__PURE__ */ (0,
|
|
1539
|
-
/* @__PURE__ */ (0,
|
|
1623
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react3.SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
|
|
1624
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
1540
1625
|
import_cmdk.Command.Input,
|
|
1541
1626
|
{
|
|
1542
1627
|
"data-slot": "command-input",
|
|
@@ -1555,7 +1640,7 @@ function CommandList({
|
|
|
1555
1640
|
className,
|
|
1556
1641
|
...props
|
|
1557
1642
|
}) {
|
|
1558
|
-
return /* @__PURE__ */ (0,
|
|
1643
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
1559
1644
|
import_cmdk.Command.List,
|
|
1560
1645
|
{
|
|
1561
1646
|
"data-slot": "command-list",
|
|
@@ -1570,7 +1655,7 @@ function CommandList({
|
|
|
1570
1655
|
function CommandEmpty({
|
|
1571
1656
|
...props
|
|
1572
1657
|
}) {
|
|
1573
|
-
return /* @__PURE__ */ (0,
|
|
1658
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
1574
1659
|
import_cmdk.Command.Empty,
|
|
1575
1660
|
{
|
|
1576
1661
|
"data-slot": "command-empty",
|
|
@@ -1583,7 +1668,7 @@ function CommandGroup({
|
|
|
1583
1668
|
className,
|
|
1584
1669
|
...props
|
|
1585
1670
|
}) {
|
|
1586
|
-
return /* @__PURE__ */ (0,
|
|
1671
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
1587
1672
|
import_cmdk.Command.Group,
|
|
1588
1673
|
{
|
|
1589
1674
|
"data-slot": "command-group",
|
|
@@ -1599,7 +1684,7 @@ function CommandItem({
|
|
|
1599
1684
|
className,
|
|
1600
1685
|
...props
|
|
1601
1686
|
}) {
|
|
1602
|
-
return /* @__PURE__ */ (0,
|
|
1687
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
1603
1688
|
import_cmdk.Command.Item,
|
|
1604
1689
|
{
|
|
1605
1690
|
"data-slot": "command-item",
|
|
@@ -1613,7 +1698,7 @@ function CommandItem({
|
|
|
1613
1698
|
}
|
|
1614
1699
|
|
|
1615
1700
|
// src/components/ScenarioExplorer.tsx
|
|
1616
|
-
var
|
|
1701
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
1617
1702
|
var STATUS_FILTERS = [
|
|
1618
1703
|
{ value: "all", label: "All" },
|
|
1619
1704
|
{ value: "passed", label: "Passed" },
|
|
@@ -1624,22 +1709,22 @@ var STATUS_FILTERS = [
|
|
|
1624
1709
|
function ScenarioExplorer({ scenarios, summary }) {
|
|
1625
1710
|
const [status, setStatus] = (0, import_react9.useState)("all");
|
|
1626
1711
|
const visible = status === "all" ? scenarios : scenarios.filter((s) => s.status === status);
|
|
1627
|
-
return /* @__PURE__ */ (0,
|
|
1628
|
-
summary ? /* @__PURE__ */ (0,
|
|
1712
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "font-sans text-foreground", children: [
|
|
1713
|
+
summary ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("p", { className: "mb-3 text-sm text-muted-foreground", children: [
|
|
1629
1714
|
summary.total,
|
|
1630
1715
|
" scenarios \xB7 ",
|
|
1631
|
-
/* @__PURE__ */ (0,
|
|
1716
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { className: "text-pass", children: [
|
|
1632
1717
|
summary.passed,
|
|
1633
1718
|
" passed"
|
|
1634
1719
|
] }),
|
|
1635
1720
|
" \xB7",
|
|
1636
1721
|
" ",
|
|
1637
|
-
/* @__PURE__ */ (0,
|
|
1722
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { className: "text-fail", children: [
|
|
1638
1723
|
summary.failed,
|
|
1639
1724
|
" failed"
|
|
1640
1725
|
] })
|
|
1641
1726
|
] }) : null,
|
|
1642
|
-
/* @__PURE__ */ (0,
|
|
1727
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "mb-2 flex flex-wrap gap-1.5", role: "group", "aria-label": "Filter by status", children: STATUS_FILTERS.map((f) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
1643
1728
|
"button",
|
|
1644
1729
|
{
|
|
1645
1730
|
type: "button",
|
|
@@ -1654,26 +1739,26 @@ function ScenarioExplorer({ scenarios, summary }) {
|
|
|
1654
1739
|
},
|
|
1655
1740
|
f.value
|
|
1656
1741
|
)) }),
|
|
1657
|
-
/* @__PURE__ */ (0,
|
|
1742
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
|
|
1658
1743
|
Command,
|
|
1659
1744
|
{
|
|
1660
1745
|
className: "rounded-lg border border-border bg-card",
|
|
1661
1746
|
filter: (value, search) => value.toLowerCase().includes(search.toLowerCase()) ? 1 : 0,
|
|
1662
1747
|
children: [
|
|
1663
|
-
/* @__PURE__ */ (0,
|
|
1664
|
-
/* @__PURE__ */ (0,
|
|
1665
|
-
/* @__PURE__ */ (0,
|
|
1666
|
-
/* @__PURE__ */ (0,
|
|
1748
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(CommandInput, { placeholder: "Search scenarios\u2026" }),
|
|
1749
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(CommandList, { className: "max-h-none", children: [
|
|
1750
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(CommandEmpty, { children: "No scenarios match your filters." }),
|
|
1751
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(CommandGroup, { children: visible.map((s) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
1667
1752
|
CommandItem,
|
|
1668
1753
|
{
|
|
1669
1754
|
value: `${s.title} ${s.feature} ${s.tags.join(" ")}`,
|
|
1670
1755
|
asChild: true,
|
|
1671
1756
|
className: "cursor-pointer",
|
|
1672
|
-
children: /* @__PURE__ */ (0,
|
|
1673
|
-
/* @__PURE__ */ (0,
|
|
1674
|
-
/* @__PURE__ */ (0,
|
|
1675
|
-
s.tags.slice(0, 3).map((t) => /* @__PURE__ */ (0,
|
|
1676
|
-
/* @__PURE__ */ (0,
|
|
1757
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("a", { href: s.href, className: "flex items-center gap-3", children: [
|
|
1758
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Badge, { variant: s.status, children: s.status }),
|
|
1759
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "min-w-0 flex-1 truncate font-medium", children: s.title }),
|
|
1760
|
+
s.tags.slice(0, 3).map((t) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Badge, { variant: "tag", className: "hidden sm:inline-flex", children: t }, t)),
|
|
1761
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("code", { className: "hidden font-mono text-xs text-muted-foreground md:inline", children: s.feature })
|
|
1677
1762
|
] })
|
|
1678
1763
|
},
|
|
1679
1764
|
s.id
|
|
@@ -2694,6 +2779,7 @@ function parseStoryReport(input) {
|
|
|
2694
2779
|
ReportSchemaError,
|
|
2695
2780
|
ReportStepItem,
|
|
2696
2781
|
ReportSteps,
|
|
2782
|
+
ReportStoryboard,
|
|
2697
2783
|
ReportSummary,
|
|
2698
2784
|
ReportSummaryView,
|
|
2699
2785
|
ReportTrace,
|