executable-stories-react 0.2.1 → 0.4.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 +345 -152
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +295 -9
- package/dist/index.d.ts +295 -9
- package/dist/index.js +329 -145
- package/dist/index.js.map +1 -1
- package/dist/interactive.cjs +533 -239
- package/dist/interactive.cjs.map +1 -1
- package/dist/interactive.d.cts +269 -2
- package/dist/interactive.d.ts +269 -2
- package/dist/interactive.js +494 -201
- package/dist/interactive.js.map +1 -1
- package/dist/parse.cjs +4 -0
- package/dist/parse.cjs.map +1 -1
- package/dist/parse.d.cts +225 -3
- package/dist/parse.d.ts +225 -3
- package/dist/parse.js +4 -0
- package/dist/parse.js.map +1 -1
- package/dist/report-island.global.js +32 -32
- package/dist/ssr.cjs +275 -118
- package/dist/ssr.cjs.map +1 -1
- package/dist/ssr.d.cts +250 -2
- package/dist/ssr.d.ts +250 -2
- package/dist/ssr.js +272 -115
- package/dist/ssr.js.map +1 -1
- package/dist/styles.css +26 -0
- package/dist/tailwind.css +1 -1
- package/package.json +7 -6
package/dist/ssr.cjs
CHANGED
|
@@ -23,7 +23,7 @@ __export(ssr_entry_exports, {
|
|
|
23
23
|
renderReportToHtml: () => renderReportToHtml
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(ssr_entry_exports);
|
|
26
|
-
var
|
|
26
|
+
var import_react8 = require("react");
|
|
27
27
|
var import_server = require("react-dom/server");
|
|
28
28
|
|
|
29
29
|
// src/result.ts
|
|
@@ -75,11 +75,23 @@ function useReport() {
|
|
|
75
75
|
return ctx.report;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
//
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
78
|
+
// ../executable-stories-core/dist/utils/duration.js
|
|
79
|
+
function formatDuration(ms) {
|
|
80
|
+
if (ms < 1e3) {
|
|
81
|
+
return `${Math.round(ms)} ms`;
|
|
82
|
+
}
|
|
83
|
+
if (ms < 6e4) {
|
|
84
|
+
return `${(ms / 1e3).toFixed(2)} s`;
|
|
85
|
+
}
|
|
86
|
+
const minutes = Math.floor(ms / 6e4);
|
|
87
|
+
const seconds = Math.floor(ms % 6e4 / 1e3);
|
|
88
|
+
if (minutes < 60) {
|
|
89
|
+
return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
|
|
90
|
+
}
|
|
91
|
+
const hours = Math.floor(minutes / 60);
|
|
92
|
+
const remainingMinutes = minutes % 60;
|
|
93
|
+
return `${hours}h ${remainingMinutes}m`;
|
|
94
|
+
}
|
|
83
95
|
|
|
84
96
|
// src/components/doc/DocNote.tsx
|
|
85
97
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
@@ -263,7 +275,7 @@ function DocSection({ entry }) {
|
|
|
263
275
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
264
276
|
"div",
|
|
265
277
|
{
|
|
266
|
-
className: "es-doc-prose
|
|
278
|
+
className: "es-doc-prose prose prose-sm max-w-none",
|
|
267
279
|
dangerouslySetInnerHTML: { __html: html }
|
|
268
280
|
}
|
|
269
281
|
)
|
|
@@ -504,7 +516,7 @@ function ReportStepItem({ step }) {
|
|
|
504
516
|
}
|
|
505
517
|
),
|
|
506
518
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
|
|
507
|
-
step.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children:
|
|
519
|
+
step.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(step.durationMs) }) : null
|
|
508
520
|
] }),
|
|
509
521
|
step.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
510
522
|
"pre",
|
|
@@ -562,9 +574,6 @@ function ReportAttachments({ attachments }) {
|
|
|
562
574
|
);
|
|
563
575
|
}
|
|
564
576
|
|
|
565
|
-
// src/components/ReportTrace.tsx
|
|
566
|
-
var import_duration2 = require("executable-stories-core/utils/duration");
|
|
567
|
-
|
|
568
577
|
// src/lib/trace.ts
|
|
569
578
|
var VALID = /* @__PURE__ */ new Set(["ok", "error", "unset"]);
|
|
570
579
|
var safeStatus = (s) => VALID.has(s) ? s : "unset";
|
|
@@ -659,7 +668,7 @@ function ReportTrace({ spans }) {
|
|
|
659
668
|
" span",
|
|
660
669
|
rows.length === 1 ? "" : "s",
|
|
661
670
|
", ",
|
|
662
|
-
|
|
671
|
+
formatDuration(totalMs),
|
|
663
672
|
")"
|
|
664
673
|
] }),
|
|
665
674
|
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
|
|
@@ -682,33 +691,128 @@ function ReportTrace({ spans }) {
|
|
|
682
691
|
style: { left: `${leftPct}%`, width: `${widthPct}%` }
|
|
683
692
|
}
|
|
684
693
|
) }),
|
|
685
|
-
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children:
|
|
694
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
|
|
686
695
|
] }, `${row.spanId}-${i}`);
|
|
687
696
|
}) })
|
|
688
697
|
] });
|
|
689
698
|
}
|
|
690
699
|
|
|
691
|
-
// src/interactive/
|
|
700
|
+
// src/interactive/scenario-history-context.ts
|
|
692
701
|
var import_react5 = require("react");
|
|
693
|
-
var
|
|
702
|
+
var ScenarioHistoryContext = (0, import_react5.createContext)(null);
|
|
703
|
+
var ScenarioHistoryProvider = ScenarioHistoryContext.Provider;
|
|
704
|
+
function useScenarioHistory() {
|
|
705
|
+
return (0, import_react5.useContext)(ScenarioHistoryContext);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
// src/lib/run-history.ts
|
|
709
|
+
function currentStreak(entries) {
|
|
710
|
+
const last = entries[entries.length - 1];
|
|
711
|
+
if (!last) return void 0;
|
|
712
|
+
let count = 0;
|
|
713
|
+
for (let i = entries.length - 1; i >= 0 && entries[i].status === last.status; i--) count++;
|
|
714
|
+
return { status: last.status, count };
|
|
715
|
+
}
|
|
716
|
+
var STREAK_VERB = {
|
|
717
|
+
passed: "Passing",
|
|
718
|
+
failed: "Failing",
|
|
719
|
+
skipped: "Skipped",
|
|
720
|
+
pending: "Pending"
|
|
721
|
+
};
|
|
722
|
+
function describeRunHistory(entries) {
|
|
723
|
+
const passed = entries.filter((e) => e.status === "passed").length;
|
|
724
|
+
const base = `${passed}/${entries.length} runs passed`;
|
|
725
|
+
const streak = currentStreak(entries);
|
|
726
|
+
if (!streak || entries.length < 2) return base;
|
|
727
|
+
return `${base} \xB7 ${STREAK_VERB[streak.status]} for the last ${streak.count === 1 ? "run" : `${streak.count} runs`}`;
|
|
728
|
+
}
|
|
729
|
+
var MIN_FLAKINESS_SAMPLES = 3;
|
|
730
|
+
function flakinessOf(entries) {
|
|
731
|
+
const countable = entries.filter((e) => e.status === "passed" || e.status === "failed");
|
|
732
|
+
if (countable.length < MIN_FLAKINESS_SAMPLES) return "stable";
|
|
733
|
+
let transitions = 0;
|
|
734
|
+
for (let i = 1; i < countable.length; i++) {
|
|
735
|
+
if (countable[i].status !== countable[i - 1].status) transitions++;
|
|
736
|
+
}
|
|
737
|
+
const transitionScore = transitions / (countable.length - 1);
|
|
738
|
+
const failureRate = countable.filter((e) => e.status === "failed").length / countable.length;
|
|
739
|
+
if (transitionScore > 0.5 || transitionScore > 0.3 && failureRate > 0.2) return "flaky";
|
|
740
|
+
if (transitionScore > 0.2 || failureRate > 0.3) return "unstable";
|
|
741
|
+
return "stable";
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
// src/components/ScenarioRunHistory.tsx
|
|
745
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
746
|
+
var MAX_DOTS = 10;
|
|
747
|
+
var DOT_COLOR = {
|
|
748
|
+
passed: "bg-pass",
|
|
749
|
+
failed: "bg-fail",
|
|
750
|
+
skipped: "bg-skip",
|
|
751
|
+
pending: "bg-pend"
|
|
752
|
+
};
|
|
753
|
+
function dotTitle(e) {
|
|
754
|
+
const parts = [new Date(e.timestamp).toLocaleString(), e.status];
|
|
755
|
+
if (e.commitSha) parts.push(e.commitSha.slice(0, 8));
|
|
756
|
+
return parts.join(" \xB7 ");
|
|
757
|
+
}
|
|
758
|
+
function ScenarioRunHistory({ scenarioId }) {
|
|
759
|
+
const history = useScenarioHistory();
|
|
760
|
+
const entries = history?.[scenarioId];
|
|
761
|
+
if (!entries || entries.length < 2) return null;
|
|
762
|
+
const recent = entries.slice(-MAX_DOTS);
|
|
763
|
+
const flaky = flakinessOf(recent) === "flaky";
|
|
764
|
+
const summary = flaky ? `${describeRunHistory(recent)} \xB7 Flaky` : describeRunHistory(recent);
|
|
765
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
|
|
766
|
+
flaky ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
|
|
767
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
768
|
+
"span",
|
|
769
|
+
{
|
|
770
|
+
role: "img",
|
|
771
|
+
"aria-label": `Run history: ${summary}`,
|
|
772
|
+
title: summary,
|
|
773
|
+
className: "flex shrink-0 items-center gap-[3px]",
|
|
774
|
+
children: recent.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
775
|
+
"span",
|
|
776
|
+
{
|
|
777
|
+
"aria-hidden": true,
|
|
778
|
+
title: dotTitle(e),
|
|
779
|
+
className: cn(
|
|
780
|
+
"inline-block size-1.5 rounded-full",
|
|
781
|
+
DOT_COLOR[e.status],
|
|
782
|
+
// The newest run (rightmost dot) is the one the card's status
|
|
783
|
+
// badge already describes; ring it so the timeline reads as
|
|
784
|
+
// "…leading up to now".
|
|
785
|
+
i === recent.length - 1 && "ring-1 ring-border ring-offset-1 ring-offset-card"
|
|
786
|
+
)
|
|
787
|
+
},
|
|
788
|
+
`${e.timestamp}-${i}`
|
|
789
|
+
))
|
|
790
|
+
}
|
|
791
|
+
)
|
|
792
|
+
] });
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// src/interactive/collapse-context.ts
|
|
796
|
+
var import_react6 = require("react");
|
|
797
|
+
var CollapseContext = (0, import_react6.createContext)(null);
|
|
694
798
|
var CollapseProvider = CollapseContext.Provider;
|
|
695
799
|
function useCollapse() {
|
|
696
|
-
return (0,
|
|
800
|
+
return (0, import_react6.useContext)(CollapseContext);
|
|
697
801
|
}
|
|
698
802
|
|
|
699
803
|
// src/interactive/scenario-actions.tsx
|
|
700
|
-
var
|
|
701
|
-
var ScenarioActionsContext = (0,
|
|
804
|
+
var import_react7 = require("react");
|
|
805
|
+
var ScenarioActionsContext = (0, import_react7.createContext)(null);
|
|
702
806
|
var ScenarioActionsProvider = ScenarioActionsContext.Provider;
|
|
703
807
|
function useScenarioActions() {
|
|
704
|
-
return (0,
|
|
808
|
+
return (0, import_react7.useContext)(ScenarioActionsContext);
|
|
705
809
|
}
|
|
706
810
|
|
|
707
811
|
// src/components/ui/card.tsx
|
|
708
812
|
var React2 = require("react");
|
|
709
|
-
var
|
|
813
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
710
814
|
function Card({ className, ...props }) {
|
|
711
|
-
return /* @__PURE__ */ (0,
|
|
815
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
712
816
|
"div",
|
|
713
817
|
{
|
|
714
818
|
"data-slot": "card",
|
|
@@ -721,7 +825,7 @@ function Card({ className, ...props }) {
|
|
|
721
825
|
);
|
|
722
826
|
}
|
|
723
827
|
function CardHeader({ className, ...props }) {
|
|
724
|
-
return /* @__PURE__ */ (0,
|
|
828
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
725
829
|
"div",
|
|
726
830
|
{
|
|
727
831
|
"data-slot": "card-header",
|
|
@@ -734,7 +838,7 @@ function CardHeader({ className, ...props }) {
|
|
|
734
838
|
);
|
|
735
839
|
}
|
|
736
840
|
function CardContent({ className, ...props }) {
|
|
737
|
-
return /* @__PURE__ */ (0,
|
|
841
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
738
842
|
"div",
|
|
739
843
|
{
|
|
740
844
|
"data-slot": "card-content",
|
|
@@ -745,7 +849,7 @@ function CardContent({ className, ...props }) {
|
|
|
745
849
|
}
|
|
746
850
|
|
|
747
851
|
// src/components/ReportScenario.tsx
|
|
748
|
-
var
|
|
852
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
749
853
|
var STATUS_LABEL = {
|
|
750
854
|
passed: "Passed",
|
|
751
855
|
failed: "Failed",
|
|
@@ -773,12 +877,12 @@ var STATUS_BADGE = {
|
|
|
773
877
|
function ReportScenario({ scenario, hideTitle = false }) {
|
|
774
878
|
const titleId = `${scenario.id}-title`;
|
|
775
879
|
const bodyId = `${scenario.id}-body`;
|
|
776
|
-
const label = STATUS_LABEL[scenario.status];
|
|
880
|
+
const label = scenario.planned ? "Planned" : STATUS_LABEL[scenario.status];
|
|
777
881
|
const collapse = useCollapse();
|
|
778
882
|
const collapsible = collapse !== null && !hideTitle;
|
|
779
883
|
const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
|
|
780
884
|
const actions = useScenarioActions();
|
|
781
|
-
return /* @__PURE__ */ (0,
|
|
885
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
782
886
|
Card,
|
|
783
887
|
{
|
|
784
888
|
id: scenario.id,
|
|
@@ -786,10 +890,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
786
890
|
...hideTitle ? { "aria-label": `${scenario.title} \u2014 ${label}` } : { "aria-labelledby": titleId },
|
|
787
891
|
className: "gap-0 py-0",
|
|
788
892
|
children: [
|
|
789
|
-
/* @__PURE__ */ (0,
|
|
790
|
-
/* @__PURE__ */ (0,
|
|
791
|
-
hideTitle ? null : /* @__PURE__ */ (0,
|
|
792
|
-
collapsible ? /* @__PURE__ */ (0,
|
|
893
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(CardHeader, { className: "px-4 py-3", children: [
|
|
894
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
|
|
895
|
+
hideTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
|
|
896
|
+
collapsible ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
793
897
|
"button",
|
|
794
898
|
{
|
|
795
899
|
type: "button",
|
|
@@ -798,17 +902,18 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
798
902
|
"aria-controls": bodyId,
|
|
799
903
|
"aria-label": `Toggle ${scenario.title}`,
|
|
800
904
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
801
|
-
children: /* @__PURE__ */ (0,
|
|
905
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
802
906
|
}
|
|
803
907
|
) : null,
|
|
804
|
-
/* @__PURE__ */ (0,
|
|
805
|
-
/* @__PURE__ */ (0,
|
|
908
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { "aria-hidden": true, className: cn("text-sm leading-none", STATUS_GLYPH_COLOR[scenario.status]), children: STATUS_GLYPH[scenario.status] }),
|
|
909
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: scenario.title })
|
|
806
910
|
] }),
|
|
807
|
-
/* @__PURE__ */ (0,
|
|
808
|
-
|
|
809
|
-
/* @__PURE__ */ (0,
|
|
810
|
-
|
|
811
|
-
|
|
911
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
912
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ScenarioRunHistory, { scenarioId: scenario.id }),
|
|
913
|
+
scenario.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
|
|
914
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Badge, { variant: STATUS_BADGE[scenario.status], "aria-label": `Status: ${label}`, children: label }),
|
|
915
|
+
actions ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center gap-0.5", children: [
|
|
916
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
812
917
|
"button",
|
|
813
918
|
{
|
|
814
919
|
type: "button",
|
|
@@ -819,7 +924,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
819
924
|
children: "link"
|
|
820
925
|
}
|
|
821
926
|
),
|
|
822
|
-
/* @__PURE__ */ (0,
|
|
927
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
823
928
|
"button",
|
|
824
929
|
{
|
|
825
930
|
type: "button",
|
|
@@ -830,7 +935,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
830
935
|
children: "md"
|
|
831
936
|
}
|
|
832
937
|
),
|
|
833
|
-
/* @__PURE__ */ (0,
|
|
938
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
834
939
|
"button",
|
|
835
940
|
{
|
|
836
941
|
type: "button",
|
|
@@ -844,13 +949,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
844
949
|
] }) : null
|
|
845
950
|
] })
|
|
846
951
|
] }),
|
|
847
|
-
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0,
|
|
848
|
-
scenario.tags.map((t) => /* @__PURE__ */ (0,
|
|
849
|
-
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0,
|
|
952
|
+
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
|
|
953
|
+
scenario.tags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
|
|
954
|
+
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("li", { children: ticket.url ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
|
|
850
955
|
] }) : null
|
|
851
956
|
] }),
|
|
852
|
-
/* @__PURE__ */ (0,
|
|
853
|
-
scenario.errorMessage ? /* @__PURE__ */ (0,
|
|
957
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
|
|
958
|
+
scenario.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
854
959
|
"pre",
|
|
855
960
|
{
|
|
856
961
|
role: "alert",
|
|
@@ -858,10 +963,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
858
963
|
children: scenario.errorMessage
|
|
859
964
|
}
|
|
860
965
|
) : null,
|
|
861
|
-
/* @__PURE__ */ (0,
|
|
862
|
-
scenario.docEntries.length > 0 ? /* @__PURE__ */ (0,
|
|
863
|
-
/* @__PURE__ */ (0,
|
|
864
|
-
/* @__PURE__ */ (0,
|
|
966
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ReportSteps, { scenario }),
|
|
967
|
+
scenario.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
|
|
968
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ReportAttachments, { attachments: scenario.attachments }),
|
|
969
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ReportTrace, { spans: scenario.otelSpans })
|
|
865
970
|
] })
|
|
866
971
|
]
|
|
867
972
|
}
|
|
@@ -869,13 +974,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
869
974
|
}
|
|
870
975
|
|
|
871
976
|
// src/components/ReportScenarioList.tsx
|
|
872
|
-
var
|
|
977
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
873
978
|
function ReportScenarioList({ feature }) {
|
|
874
|
-
return /* @__PURE__ */ (0,
|
|
979
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_jsx_runtime23.Fragment, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportScenario, { scenario }, scenario.id)) });
|
|
875
980
|
}
|
|
876
981
|
|
|
877
982
|
// src/components/ReportFeature.tsx
|
|
878
|
-
var
|
|
983
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
879
984
|
function ReportFeature({ feature }) {
|
|
880
985
|
const titleId = `${feature.id}-title`;
|
|
881
986
|
const bodyId = `${feature.id}-body`;
|
|
@@ -883,7 +988,7 @@ function ReportFeature({ feature }) {
|
|
|
883
988
|
const skipped = s.skipped + s.pending;
|
|
884
989
|
const collapse = useCollapse();
|
|
885
990
|
const collapsed = collapse?.isCollapsed(feature.id) ?? false;
|
|
886
|
-
return /* @__PURE__ */ (0,
|
|
991
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
887
992
|
"section",
|
|
888
993
|
{
|
|
889
994
|
id: feature.id,
|
|
@@ -891,9 +996,9 @@ function ReportFeature({ feature }) {
|
|
|
891
996
|
"aria-labelledby": titleId,
|
|
892
997
|
className: "overflow-hidden rounded-xl border border-border bg-card shadow-sm",
|
|
893
998
|
children: [
|
|
894
|
-
/* @__PURE__ */ (0,
|
|
895
|
-
/* @__PURE__ */ (0,
|
|
896
|
-
collapse ? /* @__PURE__ */ (0,
|
|
999
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex items-center justify-between gap-4 border-b border-border bg-muted/40 px-4 py-3", children: [
|
|
1000
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
1001
|
+
collapse ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
897
1002
|
"button",
|
|
898
1003
|
{
|
|
899
1004
|
type: "button",
|
|
@@ -902,30 +1007,30 @@ function ReportFeature({ feature }) {
|
|
|
902
1007
|
"aria-controls": bodyId,
|
|
903
1008
|
"aria-label": `Toggle ${feature.title}`,
|
|
904
1009
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
905
|
-
children: /* @__PURE__ */ (0,
|
|
1010
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
906
1011
|
}
|
|
907
1012
|
) : null,
|
|
908
|
-
/* @__PURE__ */ (0,
|
|
909
|
-
/* @__PURE__ */ (0,
|
|
910
|
-
/* @__PURE__ */ (0,
|
|
1013
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "min-w-0", children: [
|
|
1014
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h2", { id: titleId, className: "text-sm font-semibold tracking-tight text-foreground", children: feature.title }),
|
|
1015
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "mt-0.5 truncate font-mono text-xs text-muted-foreground", children: feature.sourceFile })
|
|
911
1016
|
] })
|
|
912
1017
|
] }),
|
|
913
|
-
/* @__PURE__ */ (0,
|
|
1018
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
914
1019
|
"div",
|
|
915
1020
|
{
|
|
916
1021
|
role: "img",
|
|
917
1022
|
className: "flex shrink-0 items-center gap-2.5 font-mono text-xs font-medium",
|
|
918
1023
|
"aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
|
|
919
1024
|
children: [
|
|
920
|
-
/* @__PURE__ */ (0,
|
|
1025
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { "aria-hidden": true, className: "text-pass", children: [
|
|
921
1026
|
"\u2713",
|
|
922
1027
|
s.passed
|
|
923
1028
|
] }),
|
|
924
|
-
/* @__PURE__ */ (0,
|
|
1029
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { "aria-hidden": true, className: "text-fail", children: [
|
|
925
1030
|
"\u2717",
|
|
926
1031
|
s.failed
|
|
927
1032
|
] }),
|
|
928
|
-
/* @__PURE__ */ (0,
|
|
1033
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { "aria-hidden": true, className: "text-skip", children: [
|
|
929
1034
|
"\u25CB",
|
|
930
1035
|
skipped
|
|
931
1036
|
] })
|
|
@@ -933,24 +1038,24 @@ function ReportFeature({ feature }) {
|
|
|
933
1038
|
}
|
|
934
1039
|
)
|
|
935
1040
|
] }),
|
|
936
|
-
/* @__PURE__ */ (0,
|
|
1041
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-2 p-3", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ReportScenarioList, { feature }) })
|
|
937
1042
|
]
|
|
938
1043
|
}
|
|
939
1044
|
);
|
|
940
1045
|
}
|
|
941
1046
|
|
|
942
1047
|
// src/components/ReportFeatureList.tsx
|
|
943
|
-
var
|
|
1048
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
944
1049
|
function ReportFeatureList() {
|
|
945
1050
|
const report = useReport();
|
|
946
|
-
return /* @__PURE__ */ (0,
|
|
1051
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_jsx_runtime25.Fragment, { children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportFeature, { feature }, feature.id)) });
|
|
947
1052
|
}
|
|
948
1053
|
|
|
949
1054
|
// src/components/ui/empty.tsx
|
|
950
1055
|
var import_class_variance_authority2 = require("class-variance-authority");
|
|
951
|
-
var
|
|
1056
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
952
1057
|
function Empty({ className, ...props }) {
|
|
953
|
-
return /* @__PURE__ */ (0,
|
|
1058
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
954
1059
|
"div",
|
|
955
1060
|
{
|
|
956
1061
|
"data-slot": "empty",
|
|
@@ -963,7 +1068,7 @@ function Empty({ className, ...props }) {
|
|
|
963
1068
|
);
|
|
964
1069
|
}
|
|
965
1070
|
function EmptyHeader({ className, ...props }) {
|
|
966
|
-
return /* @__PURE__ */ (0,
|
|
1071
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
967
1072
|
"div",
|
|
968
1073
|
{
|
|
969
1074
|
"data-slot": "empty-header",
|
|
@@ -990,7 +1095,7 @@ var emptyMediaVariants = (0, import_class_variance_authority2.cva)(
|
|
|
990
1095
|
}
|
|
991
1096
|
);
|
|
992
1097
|
function EmptyTitle({ className, ...props }) {
|
|
993
|
-
return /* @__PURE__ */ (0,
|
|
1098
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
994
1099
|
"div",
|
|
995
1100
|
{
|
|
996
1101
|
"data-slot": "empty-title",
|
|
@@ -1001,16 +1106,16 @@ function EmptyTitle({ className, ...props }) {
|
|
|
1001
1106
|
}
|
|
1002
1107
|
|
|
1003
1108
|
// src/components/ReportEmpty.tsx
|
|
1004
|
-
var
|
|
1109
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1005
1110
|
function ReportEmpty({ message }) {
|
|
1006
|
-
return /* @__PURE__ */ (0,
|
|
1111
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(EmptyHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
|
|
1007
1112
|
}
|
|
1008
1113
|
|
|
1009
1114
|
// src/components/ReportSummary.tsx
|
|
1010
|
-
var
|
|
1115
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1011
1116
|
function ReportSummary({ className }) {
|
|
1012
1117
|
const report = useReport();
|
|
1013
|
-
return /* @__PURE__ */ (0,
|
|
1118
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
1014
1119
|
ReportSummaryView,
|
|
1015
1120
|
{
|
|
1016
1121
|
summary: report.summary,
|
|
@@ -1020,32 +1125,32 @@ function ReportSummary({ className }) {
|
|
|
1020
1125
|
);
|
|
1021
1126
|
}
|
|
1022
1127
|
function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
1023
|
-
return /* @__PURE__ */ (0,
|
|
1024
|
-
/* @__PURE__ */ (0,
|
|
1025
|
-
/* @__PURE__ */ (0,
|
|
1128
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("p", { className: cn("text-sm text-muted-foreground", className), "aria-label": ariaLabel, children: [
|
|
1129
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { children: [
|
|
1130
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("strong", { className: "font-semibold text-foreground", children: summary.total }),
|
|
1026
1131
|
" scenario",
|
|
1027
1132
|
summary.total === 1 ? "" : "s"
|
|
1028
1133
|
] }),
|
|
1029
1134
|
" \xB7 ",
|
|
1030
|
-
/* @__PURE__ */ (0,
|
|
1135
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { "data-status": "passed", className: "text-pass", children: [
|
|
1031
1136
|
summary.passed,
|
|
1032
1137
|
" passed"
|
|
1033
1138
|
] }),
|
|
1034
1139
|
" \xB7 ",
|
|
1035
|
-
/* @__PURE__ */ (0,
|
|
1140
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { "data-status": "failed", className: "text-fail", children: [
|
|
1036
1141
|
summary.failed,
|
|
1037
1142
|
" failed"
|
|
1038
1143
|
] }),
|
|
1039
|
-
summary.skipped > 0 ? /* @__PURE__ */ (0,
|
|
1144
|
+
summary.skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
|
|
1040
1145
|
" \xB7 ",
|
|
1041
|
-
/* @__PURE__ */ (0,
|
|
1146
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { "data-status": "skipped", className: "text-skip", children: [
|
|
1042
1147
|
summary.skipped,
|
|
1043
1148
|
" skipped"
|
|
1044
1149
|
] })
|
|
1045
1150
|
] }) : null,
|
|
1046
|
-
summary.pending > 0 ? /* @__PURE__ */ (0,
|
|
1151
|
+
summary.pending > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
|
|
1047
1152
|
" \xB7 ",
|
|
1048
|
-
/* @__PURE__ */ (0,
|
|
1153
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { "data-status": "pending", className: "text-pend", children: [
|
|
1049
1154
|
summary.pending,
|
|
1050
1155
|
" pending"
|
|
1051
1156
|
] })
|
|
@@ -1053,69 +1158,116 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1053
1158
|
] });
|
|
1054
1159
|
}
|
|
1055
1160
|
|
|
1161
|
+
// src/lib/provenance.ts
|
|
1162
|
+
var CI_DISPLAY_NAMES = {
|
|
1163
|
+
github: "GitHub Actions",
|
|
1164
|
+
gitlab: "GitLab CI",
|
|
1165
|
+
circleci: "CircleCI",
|
|
1166
|
+
jenkins: "Jenkins",
|
|
1167
|
+
azure: "Azure DevOps",
|
|
1168
|
+
buildkite: "Buildkite",
|
|
1169
|
+
travis: "Travis CI",
|
|
1170
|
+
ci: "CI"
|
|
1171
|
+
};
|
|
1172
|
+
function ciDisplayName(name) {
|
|
1173
|
+
return CI_DISPLAY_NAMES[name] ?? name;
|
|
1174
|
+
}
|
|
1175
|
+
function commitUrl(ci, sha) {
|
|
1176
|
+
const commitSha = ci?.commitSha ?? sha;
|
|
1177
|
+
if (!ci?.url || !commitSha) return void 0;
|
|
1178
|
+
const github = ci.url.match(/^(https?:\/\/[^/]+\/[^/]+\/[^/]+)\/actions\/runs\//);
|
|
1179
|
+
if (github) return `${github[1]}/commit/${commitSha}`;
|
|
1180
|
+
const gitlab = ci.url.match(/^(https?:\/\/.+)\/-\/pipelines\//);
|
|
1181
|
+
if (gitlab) return `${gitlab[1]}/-/commit/${commitSha}`;
|
|
1182
|
+
return void 0;
|
|
1183
|
+
}
|
|
1184
|
+
function prUrl(ci) {
|
|
1185
|
+
if (!ci?.url || !ci.prNumber) return void 0;
|
|
1186
|
+
const github = ci.url.match(/^(https?:\/\/[^/]+\/[^/]+\/[^/]+)\/actions\/runs\//);
|
|
1187
|
+
if (github) return `${github[1]}/pull/${ci.prNumber}`;
|
|
1188
|
+
return void 0;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1056
1191
|
// src/components/ReportMeta.tsx
|
|
1057
|
-
var
|
|
1058
|
-
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1192
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
1059
1193
|
function ReportMeta() {
|
|
1060
1194
|
const report = useReport();
|
|
1061
1195
|
const items = [];
|
|
1196
|
+
const linkClass = "text-primary underline underline-offset-2";
|
|
1062
1197
|
if (report.startedAtMs) {
|
|
1063
1198
|
items.push({ label: "Started", value: new Date(report.startedAtMs).toLocaleString() });
|
|
1064
1199
|
}
|
|
1065
1200
|
if (report.durationMs) {
|
|
1066
|
-
items.push({ label: "Duration", value:
|
|
1201
|
+
items.push({ label: "Duration", value: formatDuration(report.durationMs) });
|
|
1067
1202
|
}
|
|
1068
1203
|
if (report.packageVersion) {
|
|
1069
1204
|
items.push({ label: "Version", value: report.packageVersion });
|
|
1070
1205
|
}
|
|
1071
|
-
if (report.
|
|
1072
|
-
items.push({ label: "
|
|
1206
|
+
if (report.ci?.branch) {
|
|
1207
|
+
items.push({ label: "Branch", value: report.ci.branch });
|
|
1208
|
+
}
|
|
1209
|
+
const sha = report.ci?.commitSha ?? report.gitSha;
|
|
1210
|
+
if (sha) {
|
|
1211
|
+
const url = commitUrl(report.ci, report.gitSha);
|
|
1212
|
+
const short = sha.slice(0, 8);
|
|
1213
|
+
items.push({
|
|
1214
|
+
label: "Commit",
|
|
1215
|
+
value: url ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
|
|
1216
|
+
});
|
|
1073
1217
|
}
|
|
1074
1218
|
if (report.ci) {
|
|
1075
1219
|
items.push({
|
|
1076
1220
|
label: "CI",
|
|
1077
|
-
value: report.ci.url ? /* @__PURE__ */ (0,
|
|
1078
|
-
report.ci.name,
|
|
1221
|
+
value: report.ci.url ? /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
|
|
1222
|
+
ciDisplayName(report.ci.name),
|
|
1079
1223
|
report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
|
|
1080
|
-
] }) : `${report.ci.name}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
|
|
1224
|
+
] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
|
|
1225
|
+
});
|
|
1226
|
+
}
|
|
1227
|
+
if (report.ci?.prNumber) {
|
|
1228
|
+
const url = prUrl(report.ci);
|
|
1229
|
+
const label = `#${report.ci.prNumber}`;
|
|
1230
|
+
items.push({
|
|
1231
|
+
label: "PR",
|
|
1232
|
+
value: url ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
|
|
1081
1233
|
});
|
|
1082
1234
|
}
|
|
1083
1235
|
if (items.length === 0) return null;
|
|
1084
|
-
return /* @__PURE__ */ (0,
|
|
1085
|
-
/* @__PURE__ */ (0,
|
|
1086
|
-
/* @__PURE__ */ (0,
|
|
1236
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("dl", { "aria-label": "Run metadata", className: "flex flex-wrap gap-x-6 gap-y-1 text-xs text-muted-foreground", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex gap-1.5", children: [
|
|
1237
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("dt", { className: "font-medium", children: item.label }),
|
|
1238
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("dd", { className: "font-mono text-foreground", children: item.value })
|
|
1087
1239
|
] }, item.label)) });
|
|
1088
1240
|
}
|
|
1089
1241
|
|
|
1090
1242
|
// src/components/ReportSchemaError.tsx
|
|
1091
|
-
var
|
|
1243
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
1092
1244
|
function ReportSchemaError({ error }) {
|
|
1093
|
-
return /* @__PURE__ */ (0,
|
|
1094
|
-
/* @__PURE__ */ (0,
|
|
1095
|
-
/* @__PURE__ */ (0,
|
|
1096
|
-
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0,
|
|
1245
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
|
|
1246
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("strong", { children: "Report could not be displayed." }) }),
|
|
1247
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { children: error.message }),
|
|
1248
|
+
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("p", { children: [
|
|
1097
1249
|
"The report bundle is newer than this version of ",
|
|
1098
|
-
/* @__PURE__ */ (0,
|
|
1250
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("code", { children: "executable-stories-react" }),
|
|
1099
1251
|
". Upgrade the package, or regenerate the report with an older formatters CLI."
|
|
1100
1252
|
] }) : null,
|
|
1101
|
-
error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0,
|
|
1102
|
-
/* @__PURE__ */ (0,
|
|
1253
|
+
error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("details", { children: [
|
|
1254
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("summary", { children: [
|
|
1103
1255
|
error.issues.length,
|
|
1104
1256
|
" validation issue",
|
|
1105
1257
|
error.issues.length === 1 ? "" : "s"
|
|
1106
1258
|
] }),
|
|
1107
|
-
/* @__PURE__ */ (0,
|
|
1259
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
|
|
1108
1260
|
] }) : null
|
|
1109
1261
|
] });
|
|
1110
1262
|
}
|
|
1111
1263
|
|
|
1112
1264
|
// src/components/ReportShell.tsx
|
|
1113
|
-
var
|
|
1265
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
1114
1266
|
function ReportTitleBlock({ title }) {
|
|
1115
|
-
return /* @__PURE__ */ (0,
|
|
1116
|
-
/* @__PURE__ */ (0,
|
|
1117
|
-
/* @__PURE__ */ (0,
|
|
1118
|
-
/* @__PURE__ */ (0,
|
|
1267
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_jsx_runtime31.Fragment, { children: [
|
|
1268
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("h1", { children: title ?? "Story Report" }),
|
|
1269
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ReportSummary, {}),
|
|
1270
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ReportMeta, {})
|
|
1119
1271
|
] });
|
|
1120
1272
|
}
|
|
1121
1273
|
function ReportErrorShell({
|
|
@@ -1124,28 +1276,29 @@ function ReportErrorShell({
|
|
|
1124
1276
|
title,
|
|
1125
1277
|
dataTheme
|
|
1126
1278
|
}) {
|
|
1127
|
-
return /* @__PURE__ */ (0,
|
|
1279
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ReportSchemaError, { error }) });
|
|
1128
1280
|
}
|
|
1129
1281
|
|
|
1130
1282
|
// src/components/Report.tsx
|
|
1131
|
-
var
|
|
1283
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
1132
1284
|
function Report(props) {
|
|
1133
1285
|
const { report, customRenderers, renderers, className, title, dataTheme } = props;
|
|
1134
1286
|
const result = unwrapReport(report);
|
|
1135
1287
|
if (!result.ok) {
|
|
1136
|
-
return /* @__PURE__ */ (0,
|
|
1288
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
|
|
1137
1289
|
}
|
|
1138
1290
|
const data = result.data;
|
|
1139
1291
|
const hasContent = data.features.length > 0;
|
|
1140
|
-
return /* @__PURE__ */ (0,
|
|
1141
|
-
/* @__PURE__ */ (0,
|
|
1142
|
-
hasContent ? /* @__PURE__ */ (0,
|
|
1292
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
|
|
1293
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("header", { className: "es-report-header", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ReportTitleBlock, { title }) }),
|
|
1294
|
+
hasContent ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ReportFeatureList, {}) : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ReportEmpty, {})
|
|
1143
1295
|
] }) });
|
|
1144
1296
|
}
|
|
1145
1297
|
|
|
1146
1298
|
// src/ssr-entry.ts
|
|
1147
1299
|
var ROOT_ID = "es-report-root";
|
|
1148
1300
|
var DATA_ID = "es-report-data";
|
|
1301
|
+
var HISTORY_ID = "es-report-history";
|
|
1149
1302
|
function escapeJsonForScript(json) {
|
|
1150
1303
|
return json.replace(/[<\u2028\u2029]/g, (c) => "\\u" + c.charCodeAt(0).toString(16).padStart(4, "0"));
|
|
1151
1304
|
}
|
|
@@ -1194,19 +1347,22 @@ function renderReportToHtml(report, options = {}) {
|
|
|
1194
1347
|
lang = "en",
|
|
1195
1348
|
syntaxHighlighting = true,
|
|
1196
1349
|
mermaid = true,
|
|
1197
|
-
islandScript = ""
|
|
1350
|
+
islandScript = "",
|
|
1351
|
+
staleAfterDays = 7,
|
|
1352
|
+
scenarioHistory
|
|
1198
1353
|
} = options;
|
|
1199
1354
|
const markup = (0, import_server.renderToStaticMarkup)(
|
|
1200
|
-
(0,
|
|
1355
|
+
(0, import_react8.createElement)(Report, { report, title })
|
|
1201
1356
|
);
|
|
1202
1357
|
const cdn = cdnAssets(syntaxHighlighting, mermaid);
|
|
1203
1358
|
const parsed = unwrapReport(report);
|
|
1204
1359
|
const rawReport = parsed.ok ? parsed.data : void 0;
|
|
1205
1360
|
const interactive = islandScript.length > 0 && rawReport !== void 0;
|
|
1206
1361
|
const dataScript = interactive ? `<script type="application/json" id="${DATA_ID}">${escapeJsonForScript(JSON.stringify(rawReport))}</script>` : "";
|
|
1362
|
+
const historyScript = interactive && scenarioHistory && Object.keys(scenarioHistory).length > 0 ? `<script type="application/json" id="${HISTORY_ID}">${escapeJsonForScript(JSON.stringify(scenarioHistory))}</script>` : "";
|
|
1207
1363
|
const islandTag = interactive ? `<script>${islandScript}</script>` : "";
|
|
1208
1364
|
const cdnBody = interactive ? "" : cdn.body;
|
|
1209
|
-
const islandConfigAttrs = interactive ? ` data-es-syntax="${syntaxHighlighting ? "true" : "false"}" data-es-mermaid="${mermaid ? "true" : "false"}"` : "";
|
|
1365
|
+
const islandConfigAttrs = interactive ? ` data-es-syntax="${syntaxHighlighting ? "true" : "false"}" data-es-mermaid="${mermaid ? "true" : "false"}" data-es-stale-days="${Number.isFinite(staleAfterDays) && staleAfterDays >= 0 ? staleAfterDays : 7}"` : "";
|
|
1210
1366
|
const rootAttrs = interactive ? ` id="${ROOT_ID}" data-title="${escapeHtml(title)}"${islandConfigAttrs}` : "";
|
|
1211
1367
|
return `<!DOCTYPE html>
|
|
1212
1368
|
<html lang="${escapeHtml(lang)}" data-theme="${theme === "dark" ? "dark" : "light"}">
|
|
@@ -1222,6 +1378,7 @@ ${headExtra}
|
|
|
1222
1378
|
<body>
|
|
1223
1379
|
<div${rootAttrs} class="es-report-island font-sans text-foreground">${markup}</div>
|
|
1224
1380
|
${dataScript}
|
|
1381
|
+
${historyScript}
|
|
1225
1382
|
${bodyExtra}
|
|
1226
1383
|
${cdnBody}
|
|
1227
1384
|
${islandTag}
|