executable-stories-react 0.2.0 → 0.3.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 +369 -152
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +307 -9
- package/dist/index.d.ts +307 -9
- package/dist/index.js +353 -145
- package/dist/index.js.map +1 -1
- package/dist/interactive.cjs +557 -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 +518 -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 +299 -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 +296 -115
- package/dist/ssr.js.map +1 -1
- package/dist/styles.css +26 -0
- package/dist/tailwind.css +1 -1
- package/package.json +4 -4
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");
|
|
@@ -233,6 +245,15 @@ function safeUrl(value) {
|
|
|
233
245
|
if (scheme && !/^https?$/i.test(scheme[1] ?? "")) return void 0;
|
|
234
246
|
return trimmed;
|
|
235
247
|
}
|
|
248
|
+
function safeImageUrl(value) {
|
|
249
|
+
if (!value) return void 0;
|
|
250
|
+
const trimmed = value.trim();
|
|
251
|
+
if (/^data:image\//i.test(trimmed)) return trimmed;
|
|
252
|
+
return safeUrl(trimmed);
|
|
253
|
+
}
|
|
254
|
+
function isLocalFsPath(value) {
|
|
255
|
+
return /^(?:[/\\]|[A-Za-z]:[/\\])/.test(value);
|
|
256
|
+
}
|
|
236
257
|
|
|
237
258
|
// src/components/doc/DocSection.tsx
|
|
238
259
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
@@ -288,11 +309,19 @@ function DocMermaid({ entry }) {
|
|
|
288
309
|
// src/components/doc/DocScreenshot.tsx
|
|
289
310
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
290
311
|
function DocScreenshot({ entry }) {
|
|
312
|
+
const src = isLocalFsPath(entry.path) ? void 0 : safeImageUrl(entry.path);
|
|
313
|
+
if (!src) {
|
|
314
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
|
|
315
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "font-medium", children: "Screenshot unavailable" }),
|
|
316
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
|
|
317
|
+
entry.alt ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("figcaption", { className: "mt-1.5 text-xs", children: entry.alt }) : null
|
|
318
|
+
] });
|
|
319
|
+
}
|
|
291
320
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("figure", { className: "my-3", children: [
|
|
292
321
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
293
322
|
"img",
|
|
294
323
|
{
|
|
295
|
-
src
|
|
324
|
+
src,
|
|
296
325
|
alt: entry.alt ?? "",
|
|
297
326
|
loading: "lazy",
|
|
298
327
|
className: "max-w-full rounded-md border border-border"
|
|
@@ -305,6 +334,13 @@ function DocScreenshot({ entry }) {
|
|
|
305
334
|
// src/components/doc/DocVideo.tsx
|
|
306
335
|
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
307
336
|
function DocVideo({ entry }) {
|
|
337
|
+
if (isLocalFsPath(entry.path)) {
|
|
338
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
|
|
339
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "font-medium", children: "Video unavailable" }),
|
|
340
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
|
|
341
|
+
entry.caption ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("figcaption", { className: "mt-1.5 text-xs", children: entry.caption }) : null
|
|
342
|
+
] });
|
|
343
|
+
}
|
|
308
344
|
const src = safeUrl(entry.path);
|
|
309
345
|
const poster = safeUrl(entry.poster);
|
|
310
346
|
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("figure", { className: "my-3", children: [
|
|
@@ -480,7 +516,7 @@ function ReportStepItem({ step }) {
|
|
|
480
516
|
}
|
|
481
517
|
),
|
|
482
518
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
|
|
483
|
-
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
|
|
484
520
|
] }),
|
|
485
521
|
step.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
486
522
|
"pre",
|
|
@@ -538,9 +574,6 @@ function ReportAttachments({ attachments }) {
|
|
|
538
574
|
);
|
|
539
575
|
}
|
|
540
576
|
|
|
541
|
-
// src/components/ReportTrace.tsx
|
|
542
|
-
var import_duration2 = require("executable-stories-core/utils/duration");
|
|
543
|
-
|
|
544
577
|
// src/lib/trace.ts
|
|
545
578
|
var VALID = /* @__PURE__ */ new Set(["ok", "error", "unset"]);
|
|
546
579
|
var safeStatus = (s) => VALID.has(s) ? s : "unset";
|
|
@@ -635,7 +668,7 @@ function ReportTrace({ spans }) {
|
|
|
635
668
|
" span",
|
|
636
669
|
rows.length === 1 ? "" : "s",
|
|
637
670
|
", ",
|
|
638
|
-
|
|
671
|
+
formatDuration(totalMs),
|
|
639
672
|
")"
|
|
640
673
|
] }),
|
|
641
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) => {
|
|
@@ -658,33 +691,128 @@ function ReportTrace({ spans }) {
|
|
|
658
691
|
style: { left: `${leftPct}%`, width: `${widthPct}%` }
|
|
659
692
|
}
|
|
660
693
|
) }),
|
|
661
|
-
/* @__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) })
|
|
662
695
|
] }, `${row.spanId}-${i}`);
|
|
663
696
|
}) })
|
|
664
697
|
] });
|
|
665
698
|
}
|
|
666
699
|
|
|
667
|
-
// src/interactive/
|
|
700
|
+
// src/interactive/scenario-history-context.ts
|
|
668
701
|
var import_react5 = require("react");
|
|
669
|
-
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);
|
|
670
798
|
var CollapseProvider = CollapseContext.Provider;
|
|
671
799
|
function useCollapse() {
|
|
672
|
-
return (0,
|
|
800
|
+
return (0, import_react6.useContext)(CollapseContext);
|
|
673
801
|
}
|
|
674
802
|
|
|
675
803
|
// src/interactive/scenario-actions.tsx
|
|
676
|
-
var
|
|
677
|
-
var ScenarioActionsContext = (0,
|
|
804
|
+
var import_react7 = require("react");
|
|
805
|
+
var ScenarioActionsContext = (0, import_react7.createContext)(null);
|
|
678
806
|
var ScenarioActionsProvider = ScenarioActionsContext.Provider;
|
|
679
807
|
function useScenarioActions() {
|
|
680
|
-
return (0,
|
|
808
|
+
return (0, import_react7.useContext)(ScenarioActionsContext);
|
|
681
809
|
}
|
|
682
810
|
|
|
683
811
|
// src/components/ui/card.tsx
|
|
684
812
|
var React2 = require("react");
|
|
685
|
-
var
|
|
813
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
686
814
|
function Card({ className, ...props }) {
|
|
687
|
-
return /* @__PURE__ */ (0,
|
|
815
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
688
816
|
"div",
|
|
689
817
|
{
|
|
690
818
|
"data-slot": "card",
|
|
@@ -697,7 +825,7 @@ function Card({ className, ...props }) {
|
|
|
697
825
|
);
|
|
698
826
|
}
|
|
699
827
|
function CardHeader({ className, ...props }) {
|
|
700
|
-
return /* @__PURE__ */ (0,
|
|
828
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
701
829
|
"div",
|
|
702
830
|
{
|
|
703
831
|
"data-slot": "card-header",
|
|
@@ -710,7 +838,7 @@ function CardHeader({ className, ...props }) {
|
|
|
710
838
|
);
|
|
711
839
|
}
|
|
712
840
|
function CardContent({ className, ...props }) {
|
|
713
|
-
return /* @__PURE__ */ (0,
|
|
841
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
714
842
|
"div",
|
|
715
843
|
{
|
|
716
844
|
"data-slot": "card-content",
|
|
@@ -721,7 +849,7 @@ function CardContent({ className, ...props }) {
|
|
|
721
849
|
}
|
|
722
850
|
|
|
723
851
|
// src/components/ReportScenario.tsx
|
|
724
|
-
var
|
|
852
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
725
853
|
var STATUS_LABEL = {
|
|
726
854
|
passed: "Passed",
|
|
727
855
|
failed: "Failed",
|
|
@@ -749,12 +877,12 @@ var STATUS_BADGE = {
|
|
|
749
877
|
function ReportScenario({ scenario, hideTitle = false }) {
|
|
750
878
|
const titleId = `${scenario.id}-title`;
|
|
751
879
|
const bodyId = `${scenario.id}-body`;
|
|
752
|
-
const label = STATUS_LABEL[scenario.status];
|
|
880
|
+
const label = scenario.planned ? "Planned" : STATUS_LABEL[scenario.status];
|
|
753
881
|
const collapse = useCollapse();
|
|
754
882
|
const collapsible = collapse !== null && !hideTitle;
|
|
755
883
|
const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
|
|
756
884
|
const actions = useScenarioActions();
|
|
757
|
-
return /* @__PURE__ */ (0,
|
|
885
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
758
886
|
Card,
|
|
759
887
|
{
|
|
760
888
|
id: scenario.id,
|
|
@@ -762,10 +890,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
762
890
|
...hideTitle ? { "aria-label": `${scenario.title} \u2014 ${label}` } : { "aria-labelledby": titleId },
|
|
763
891
|
className: "gap-0 py-0",
|
|
764
892
|
children: [
|
|
765
|
-
/* @__PURE__ */ (0,
|
|
766
|
-
/* @__PURE__ */ (0,
|
|
767
|
-
hideTitle ? null : /* @__PURE__ */ (0,
|
|
768
|
-
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)(
|
|
769
897
|
"button",
|
|
770
898
|
{
|
|
771
899
|
type: "button",
|
|
@@ -774,17 +902,18 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
774
902
|
"aria-controls": bodyId,
|
|
775
903
|
"aria-label": `Toggle ${scenario.title}`,
|
|
776
904
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
777
|
-
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" })
|
|
778
906
|
}
|
|
779
907
|
) : null,
|
|
780
|
-
/* @__PURE__ */ (0,
|
|
781
|
-
/* @__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 })
|
|
782
910
|
] }),
|
|
783
|
-
/* @__PURE__ */ (0,
|
|
784
|
-
|
|
785
|
-
/* @__PURE__ */ (0,
|
|
786
|
-
|
|
787
|
-
|
|
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)(
|
|
788
917
|
"button",
|
|
789
918
|
{
|
|
790
919
|
type: "button",
|
|
@@ -795,7 +924,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
795
924
|
children: "link"
|
|
796
925
|
}
|
|
797
926
|
),
|
|
798
|
-
/* @__PURE__ */ (0,
|
|
927
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
799
928
|
"button",
|
|
800
929
|
{
|
|
801
930
|
type: "button",
|
|
@@ -806,7 +935,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
806
935
|
children: "md"
|
|
807
936
|
}
|
|
808
937
|
),
|
|
809
|
-
/* @__PURE__ */ (0,
|
|
938
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
810
939
|
"button",
|
|
811
940
|
{
|
|
812
941
|
type: "button",
|
|
@@ -820,13 +949,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
820
949
|
] }) : null
|
|
821
950
|
] })
|
|
822
951
|
] }),
|
|
823
|
-
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0,
|
|
824
|
-
scenario.tags.map((t) => /* @__PURE__ */ (0,
|
|
825
|
-
(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}`))
|
|
826
955
|
] }) : null
|
|
827
956
|
] }),
|
|
828
|
-
/* @__PURE__ */ (0,
|
|
829
|
-
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)(
|
|
830
959
|
"pre",
|
|
831
960
|
{
|
|
832
961
|
role: "alert",
|
|
@@ -834,10 +963,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
834
963
|
children: scenario.errorMessage
|
|
835
964
|
}
|
|
836
965
|
) : null,
|
|
837
|
-
/* @__PURE__ */ (0,
|
|
838
|
-
scenario.docEntries.length > 0 ? /* @__PURE__ */ (0,
|
|
839
|
-
/* @__PURE__ */ (0,
|
|
840
|
-
/* @__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 })
|
|
841
970
|
] })
|
|
842
971
|
]
|
|
843
972
|
}
|
|
@@ -845,13 +974,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
845
974
|
}
|
|
846
975
|
|
|
847
976
|
// src/components/ReportScenarioList.tsx
|
|
848
|
-
var
|
|
977
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
849
978
|
function ReportScenarioList({ feature }) {
|
|
850
|
-
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)) });
|
|
851
980
|
}
|
|
852
981
|
|
|
853
982
|
// src/components/ReportFeature.tsx
|
|
854
|
-
var
|
|
983
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
855
984
|
function ReportFeature({ feature }) {
|
|
856
985
|
const titleId = `${feature.id}-title`;
|
|
857
986
|
const bodyId = `${feature.id}-body`;
|
|
@@ -859,7 +988,7 @@ function ReportFeature({ feature }) {
|
|
|
859
988
|
const skipped = s.skipped + s.pending;
|
|
860
989
|
const collapse = useCollapse();
|
|
861
990
|
const collapsed = collapse?.isCollapsed(feature.id) ?? false;
|
|
862
|
-
return /* @__PURE__ */ (0,
|
|
991
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
863
992
|
"section",
|
|
864
993
|
{
|
|
865
994
|
id: feature.id,
|
|
@@ -867,9 +996,9 @@ function ReportFeature({ feature }) {
|
|
|
867
996
|
"aria-labelledby": titleId,
|
|
868
997
|
className: "overflow-hidden rounded-xl border border-border bg-card shadow-sm",
|
|
869
998
|
children: [
|
|
870
|
-
/* @__PURE__ */ (0,
|
|
871
|
-
/* @__PURE__ */ (0,
|
|
872
|
-
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)(
|
|
873
1002
|
"button",
|
|
874
1003
|
{
|
|
875
1004
|
type: "button",
|
|
@@ -878,30 +1007,30 @@ function ReportFeature({ feature }) {
|
|
|
878
1007
|
"aria-controls": bodyId,
|
|
879
1008
|
"aria-label": `Toggle ${feature.title}`,
|
|
880
1009
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
881
|
-
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" })
|
|
882
1011
|
}
|
|
883
1012
|
) : null,
|
|
884
|
-
/* @__PURE__ */ (0,
|
|
885
|
-
/* @__PURE__ */ (0,
|
|
886
|
-
/* @__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 })
|
|
887
1016
|
] })
|
|
888
1017
|
] }),
|
|
889
|
-
/* @__PURE__ */ (0,
|
|
1018
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
890
1019
|
"div",
|
|
891
1020
|
{
|
|
892
1021
|
role: "img",
|
|
893
1022
|
className: "flex shrink-0 items-center gap-2.5 font-mono text-xs font-medium",
|
|
894
1023
|
"aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
|
|
895
1024
|
children: [
|
|
896
|
-
/* @__PURE__ */ (0,
|
|
1025
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { "aria-hidden": true, className: "text-pass", children: [
|
|
897
1026
|
"\u2713",
|
|
898
1027
|
s.passed
|
|
899
1028
|
] }),
|
|
900
|
-
/* @__PURE__ */ (0,
|
|
1029
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { "aria-hidden": true, className: "text-fail", children: [
|
|
901
1030
|
"\u2717",
|
|
902
1031
|
s.failed
|
|
903
1032
|
] }),
|
|
904
|
-
/* @__PURE__ */ (0,
|
|
1033
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { "aria-hidden": true, className: "text-skip", children: [
|
|
905
1034
|
"\u25CB",
|
|
906
1035
|
skipped
|
|
907
1036
|
] })
|
|
@@ -909,24 +1038,24 @@ function ReportFeature({ feature }) {
|
|
|
909
1038
|
}
|
|
910
1039
|
)
|
|
911
1040
|
] }),
|
|
912
|
-
/* @__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 }) })
|
|
913
1042
|
]
|
|
914
1043
|
}
|
|
915
1044
|
);
|
|
916
1045
|
}
|
|
917
1046
|
|
|
918
1047
|
// src/components/ReportFeatureList.tsx
|
|
919
|
-
var
|
|
1048
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
920
1049
|
function ReportFeatureList() {
|
|
921
1050
|
const report = useReport();
|
|
922
|
-
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)) });
|
|
923
1052
|
}
|
|
924
1053
|
|
|
925
1054
|
// src/components/ui/empty.tsx
|
|
926
1055
|
var import_class_variance_authority2 = require("class-variance-authority");
|
|
927
|
-
var
|
|
1056
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
928
1057
|
function Empty({ className, ...props }) {
|
|
929
|
-
return /* @__PURE__ */ (0,
|
|
1058
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
930
1059
|
"div",
|
|
931
1060
|
{
|
|
932
1061
|
"data-slot": "empty",
|
|
@@ -939,7 +1068,7 @@ function Empty({ className, ...props }) {
|
|
|
939
1068
|
);
|
|
940
1069
|
}
|
|
941
1070
|
function EmptyHeader({ className, ...props }) {
|
|
942
|
-
return /* @__PURE__ */ (0,
|
|
1071
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
943
1072
|
"div",
|
|
944
1073
|
{
|
|
945
1074
|
"data-slot": "empty-header",
|
|
@@ -966,7 +1095,7 @@ var emptyMediaVariants = (0, import_class_variance_authority2.cva)(
|
|
|
966
1095
|
}
|
|
967
1096
|
);
|
|
968
1097
|
function EmptyTitle({ className, ...props }) {
|
|
969
|
-
return /* @__PURE__ */ (0,
|
|
1098
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
970
1099
|
"div",
|
|
971
1100
|
{
|
|
972
1101
|
"data-slot": "empty-title",
|
|
@@ -977,16 +1106,16 @@ function EmptyTitle({ className, ...props }) {
|
|
|
977
1106
|
}
|
|
978
1107
|
|
|
979
1108
|
// src/components/ReportEmpty.tsx
|
|
980
|
-
var
|
|
1109
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
981
1110
|
function ReportEmpty({ message }) {
|
|
982
|
-
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." }) }) });
|
|
983
1112
|
}
|
|
984
1113
|
|
|
985
1114
|
// src/components/ReportSummary.tsx
|
|
986
|
-
var
|
|
1115
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
987
1116
|
function ReportSummary({ className }) {
|
|
988
1117
|
const report = useReport();
|
|
989
|
-
return /* @__PURE__ */ (0,
|
|
1118
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
990
1119
|
ReportSummaryView,
|
|
991
1120
|
{
|
|
992
1121
|
summary: report.summary,
|
|
@@ -996,32 +1125,32 @@ function ReportSummary({ className }) {
|
|
|
996
1125
|
);
|
|
997
1126
|
}
|
|
998
1127
|
function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
999
|
-
return /* @__PURE__ */ (0,
|
|
1000
|
-
/* @__PURE__ */ (0,
|
|
1001
|
-
/* @__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 }),
|
|
1002
1131
|
" scenario",
|
|
1003
1132
|
summary.total === 1 ? "" : "s"
|
|
1004
1133
|
] }),
|
|
1005
1134
|
" \xB7 ",
|
|
1006
|
-
/* @__PURE__ */ (0,
|
|
1135
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { "data-status": "passed", className: "text-pass", children: [
|
|
1007
1136
|
summary.passed,
|
|
1008
1137
|
" passed"
|
|
1009
1138
|
] }),
|
|
1010
1139
|
" \xB7 ",
|
|
1011
|
-
/* @__PURE__ */ (0,
|
|
1140
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { "data-status": "failed", className: "text-fail", children: [
|
|
1012
1141
|
summary.failed,
|
|
1013
1142
|
" failed"
|
|
1014
1143
|
] }),
|
|
1015
|
-
summary.skipped > 0 ? /* @__PURE__ */ (0,
|
|
1144
|
+
summary.skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
|
|
1016
1145
|
" \xB7 ",
|
|
1017
|
-
/* @__PURE__ */ (0,
|
|
1146
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { "data-status": "skipped", className: "text-skip", children: [
|
|
1018
1147
|
summary.skipped,
|
|
1019
1148
|
" skipped"
|
|
1020
1149
|
] })
|
|
1021
1150
|
] }) : null,
|
|
1022
|
-
summary.pending > 0 ? /* @__PURE__ */ (0,
|
|
1151
|
+
summary.pending > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
|
|
1023
1152
|
" \xB7 ",
|
|
1024
|
-
/* @__PURE__ */ (0,
|
|
1153
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { "data-status": "pending", className: "text-pend", children: [
|
|
1025
1154
|
summary.pending,
|
|
1026
1155
|
" pending"
|
|
1027
1156
|
] })
|
|
@@ -1029,69 +1158,116 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1029
1158
|
] });
|
|
1030
1159
|
}
|
|
1031
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
|
+
|
|
1032
1191
|
// src/components/ReportMeta.tsx
|
|
1033
|
-
var
|
|
1034
|
-
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1192
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
1035
1193
|
function ReportMeta() {
|
|
1036
1194
|
const report = useReport();
|
|
1037
1195
|
const items = [];
|
|
1196
|
+
const linkClass = "text-primary underline underline-offset-2";
|
|
1038
1197
|
if (report.startedAtMs) {
|
|
1039
1198
|
items.push({ label: "Started", value: new Date(report.startedAtMs).toLocaleString() });
|
|
1040
1199
|
}
|
|
1041
1200
|
if (report.durationMs) {
|
|
1042
|
-
items.push({ label: "Duration", value:
|
|
1201
|
+
items.push({ label: "Duration", value: formatDuration(report.durationMs) });
|
|
1043
1202
|
}
|
|
1044
1203
|
if (report.packageVersion) {
|
|
1045
1204
|
items.push({ label: "Version", value: report.packageVersion });
|
|
1046
1205
|
}
|
|
1047
|
-
if (report.
|
|
1048
|
-
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
|
+
});
|
|
1049
1217
|
}
|
|
1050
1218
|
if (report.ci) {
|
|
1051
1219
|
items.push({
|
|
1052
1220
|
label: "CI",
|
|
1053
|
-
value: report.ci.url ? /* @__PURE__ */ (0,
|
|
1054
|
-
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),
|
|
1055
1223
|
report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
|
|
1056
|
-
] }) : `${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
|
|
1057
1233
|
});
|
|
1058
1234
|
}
|
|
1059
1235
|
if (items.length === 0) return null;
|
|
1060
|
-
return /* @__PURE__ */ (0,
|
|
1061
|
-
/* @__PURE__ */ (0,
|
|
1062
|
-
/* @__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 })
|
|
1063
1239
|
] }, item.label)) });
|
|
1064
1240
|
}
|
|
1065
1241
|
|
|
1066
1242
|
// src/components/ReportSchemaError.tsx
|
|
1067
|
-
var
|
|
1243
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
1068
1244
|
function ReportSchemaError({ error }) {
|
|
1069
|
-
return /* @__PURE__ */ (0,
|
|
1070
|
-
/* @__PURE__ */ (0,
|
|
1071
|
-
/* @__PURE__ */ (0,
|
|
1072
|
-
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: [
|
|
1073
1249
|
"The report bundle is newer than this version of ",
|
|
1074
|
-
/* @__PURE__ */ (0,
|
|
1250
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("code", { children: "executable-stories-react" }),
|
|
1075
1251
|
". Upgrade the package, or regenerate the report with an older formatters CLI."
|
|
1076
1252
|
] }) : null,
|
|
1077
|
-
error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0,
|
|
1078
|
-
/* @__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: [
|
|
1079
1255
|
error.issues.length,
|
|
1080
1256
|
" validation issue",
|
|
1081
1257
|
error.issues.length === 1 ? "" : "s"
|
|
1082
1258
|
] }),
|
|
1083
|
-
/* @__PURE__ */ (0,
|
|
1259
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
|
|
1084
1260
|
] }) : null
|
|
1085
1261
|
] });
|
|
1086
1262
|
}
|
|
1087
1263
|
|
|
1088
1264
|
// src/components/ReportShell.tsx
|
|
1089
|
-
var
|
|
1265
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
1090
1266
|
function ReportTitleBlock({ title }) {
|
|
1091
|
-
return /* @__PURE__ */ (0,
|
|
1092
|
-
/* @__PURE__ */ (0,
|
|
1093
|
-
/* @__PURE__ */ (0,
|
|
1094
|
-
/* @__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, {})
|
|
1095
1271
|
] });
|
|
1096
1272
|
}
|
|
1097
1273
|
function ReportErrorShell({
|
|
@@ -1100,28 +1276,29 @@ function ReportErrorShell({
|
|
|
1100
1276
|
title,
|
|
1101
1277
|
dataTheme
|
|
1102
1278
|
}) {
|
|
1103
|
-
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 }) });
|
|
1104
1280
|
}
|
|
1105
1281
|
|
|
1106
1282
|
// src/components/Report.tsx
|
|
1107
|
-
var
|
|
1283
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
1108
1284
|
function Report(props) {
|
|
1109
1285
|
const { report, customRenderers, renderers, className, title, dataTheme } = props;
|
|
1110
1286
|
const result = unwrapReport(report);
|
|
1111
1287
|
if (!result.ok) {
|
|
1112
|
-
return /* @__PURE__ */ (0,
|
|
1288
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
|
|
1113
1289
|
}
|
|
1114
1290
|
const data = result.data;
|
|
1115
1291
|
const hasContent = data.features.length > 0;
|
|
1116
|
-
return /* @__PURE__ */ (0,
|
|
1117
|
-
/* @__PURE__ */ (0,
|
|
1118
|
-
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, {})
|
|
1119
1295
|
] }) });
|
|
1120
1296
|
}
|
|
1121
1297
|
|
|
1122
1298
|
// src/ssr-entry.ts
|
|
1123
1299
|
var ROOT_ID = "es-report-root";
|
|
1124
1300
|
var DATA_ID = "es-report-data";
|
|
1301
|
+
var HISTORY_ID = "es-report-history";
|
|
1125
1302
|
function escapeJsonForScript(json) {
|
|
1126
1303
|
return json.replace(/[<\u2028\u2029]/g, (c) => "\\u" + c.charCodeAt(0).toString(16).padStart(4, "0"));
|
|
1127
1304
|
}
|
|
@@ -1170,19 +1347,22 @@ function renderReportToHtml(report, options = {}) {
|
|
|
1170
1347
|
lang = "en",
|
|
1171
1348
|
syntaxHighlighting = true,
|
|
1172
1349
|
mermaid = true,
|
|
1173
|
-
islandScript = ""
|
|
1350
|
+
islandScript = "",
|
|
1351
|
+
staleAfterDays = 7,
|
|
1352
|
+
scenarioHistory
|
|
1174
1353
|
} = options;
|
|
1175
1354
|
const markup = (0, import_server.renderToStaticMarkup)(
|
|
1176
|
-
(0,
|
|
1355
|
+
(0, import_react8.createElement)(Report, { report, title })
|
|
1177
1356
|
);
|
|
1178
1357
|
const cdn = cdnAssets(syntaxHighlighting, mermaid);
|
|
1179
1358
|
const parsed = unwrapReport(report);
|
|
1180
1359
|
const rawReport = parsed.ok ? parsed.data : void 0;
|
|
1181
1360
|
const interactive = islandScript.length > 0 && rawReport !== void 0;
|
|
1182
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>` : "";
|
|
1183
1363
|
const islandTag = interactive ? `<script>${islandScript}</script>` : "";
|
|
1184
1364
|
const cdnBody = interactive ? "" : cdn.body;
|
|
1185
|
-
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}"` : "";
|
|
1186
1366
|
const rootAttrs = interactive ? ` id="${ROOT_ID}" data-title="${escapeHtml(title)}"${islandConfigAttrs}` : "";
|
|
1187
1367
|
return `<!DOCTYPE html>
|
|
1188
1368
|
<html lang="${escapeHtml(lang)}" data-theme="${theme === "dark" ? "dark" : "light"}">
|
|
@@ -1198,6 +1378,7 @@ ${headExtra}
|
|
|
1198
1378
|
<body>
|
|
1199
1379
|
<div${rootAttrs} class="es-report-island font-sans text-foreground">${markup}</div>
|
|
1200
1380
|
${dataScript}
|
|
1381
|
+
${historyScript}
|
|
1201
1382
|
${bodyExtra}
|
|
1202
1383
|
${cdnBody}
|
|
1203
1384
|
${islandTag}
|