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.js
CHANGED
|
@@ -51,11 +51,23 @@ function useReport() {
|
|
|
51
51
|
return ctx.report;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
// ../executable-stories-core/dist/utils/duration.js
|
|
55
|
+
function formatDuration(ms) {
|
|
56
|
+
if (ms < 1e3) {
|
|
57
|
+
return `${Math.round(ms)} ms`;
|
|
58
|
+
}
|
|
59
|
+
if (ms < 6e4) {
|
|
60
|
+
return `${(ms / 1e3).toFixed(2)} s`;
|
|
61
|
+
}
|
|
62
|
+
const minutes = Math.floor(ms / 6e4);
|
|
63
|
+
const seconds = Math.floor(ms % 6e4 / 1e3);
|
|
64
|
+
if (minutes < 60) {
|
|
65
|
+
return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
|
|
66
|
+
}
|
|
67
|
+
const hours = Math.floor(minutes / 60);
|
|
68
|
+
const remainingMinutes = minutes % 60;
|
|
69
|
+
return `${hours}h ${remainingMinutes}m`;
|
|
70
|
+
}
|
|
59
71
|
|
|
60
72
|
// src/components/doc/DocNote.tsx
|
|
61
73
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
@@ -209,6 +221,15 @@ function safeUrl(value) {
|
|
|
209
221
|
if (scheme && !/^https?$/i.test(scheme[1] ?? "")) return void 0;
|
|
210
222
|
return trimmed;
|
|
211
223
|
}
|
|
224
|
+
function safeImageUrl(value) {
|
|
225
|
+
if (!value) return void 0;
|
|
226
|
+
const trimmed = value.trim();
|
|
227
|
+
if (/^data:image\//i.test(trimmed)) return trimmed;
|
|
228
|
+
return safeUrl(trimmed);
|
|
229
|
+
}
|
|
230
|
+
function isLocalFsPath(value) {
|
|
231
|
+
return /^(?:[/\\]|[A-Za-z]:[/\\])/.test(value);
|
|
232
|
+
}
|
|
212
233
|
|
|
213
234
|
// src/components/doc/DocSection.tsx
|
|
214
235
|
import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
@@ -264,11 +285,19 @@ function DocMermaid({ entry }) {
|
|
|
264
285
|
// src/components/doc/DocScreenshot.tsx
|
|
265
286
|
import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
266
287
|
function DocScreenshot({ entry }) {
|
|
288
|
+
const src = isLocalFsPath(entry.path) ? void 0 : safeImageUrl(entry.path);
|
|
289
|
+
if (!src) {
|
|
290
|
+
return /* @__PURE__ */ jsxs6("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
|
|
291
|
+
/* @__PURE__ */ jsx10("div", { className: "font-medium", children: "Screenshot unavailable" }),
|
|
292
|
+
/* @__PURE__ */ jsx10("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
|
|
293
|
+
entry.alt ? /* @__PURE__ */ jsx10("figcaption", { className: "mt-1.5 text-xs", children: entry.alt }) : null
|
|
294
|
+
] });
|
|
295
|
+
}
|
|
267
296
|
return /* @__PURE__ */ jsxs6("figure", { className: "my-3", children: [
|
|
268
297
|
/* @__PURE__ */ jsx10(
|
|
269
298
|
"img",
|
|
270
299
|
{
|
|
271
|
-
src
|
|
300
|
+
src,
|
|
272
301
|
alt: entry.alt ?? "",
|
|
273
302
|
loading: "lazy",
|
|
274
303
|
className: "max-w-full rounded-md border border-border"
|
|
@@ -281,6 +310,13 @@ function DocScreenshot({ entry }) {
|
|
|
281
310
|
// src/components/doc/DocVideo.tsx
|
|
282
311
|
import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
283
312
|
function DocVideo({ entry }) {
|
|
313
|
+
if (isLocalFsPath(entry.path)) {
|
|
314
|
+
return /* @__PURE__ */ jsxs7("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
|
|
315
|
+
/* @__PURE__ */ jsx11("div", { className: "font-medium", children: "Video unavailable" }),
|
|
316
|
+
/* @__PURE__ */ jsx11("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
|
|
317
|
+
entry.caption ? /* @__PURE__ */ jsx11("figcaption", { className: "mt-1.5 text-xs", children: entry.caption }) : null
|
|
318
|
+
] });
|
|
319
|
+
}
|
|
284
320
|
const src = safeUrl(entry.path);
|
|
285
321
|
const poster = safeUrl(entry.poster);
|
|
286
322
|
return /* @__PURE__ */ jsxs7("figure", { className: "my-3", children: [
|
|
@@ -514,9 +550,6 @@ function ReportAttachments({ attachments }) {
|
|
|
514
550
|
);
|
|
515
551
|
}
|
|
516
552
|
|
|
517
|
-
// src/components/ReportTrace.tsx
|
|
518
|
-
import { formatDuration as formatDuration2 } from "executable-stories-core/utils/duration";
|
|
519
|
-
|
|
520
553
|
// src/lib/trace.ts
|
|
521
554
|
var VALID = /* @__PURE__ */ new Set(["ok", "error", "unset"]);
|
|
522
555
|
var safeStatus = (s) => VALID.has(s) ? s : "unset";
|
|
@@ -611,7 +644,7 @@ function ReportTrace({ spans }) {
|
|
|
611
644
|
" span",
|
|
612
645
|
rows.length === 1 ? "" : "s",
|
|
613
646
|
", ",
|
|
614
|
-
|
|
647
|
+
formatDuration(totalMs),
|
|
615
648
|
")"
|
|
616
649
|
] }),
|
|
617
650
|
/* @__PURE__ */ jsx19("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
|
|
@@ -634,33 +667,128 @@ function ReportTrace({ spans }) {
|
|
|
634
667
|
style: { left: `${leftPct}%`, width: `${widthPct}%` }
|
|
635
668
|
}
|
|
636
669
|
) }),
|
|
637
|
-
/* @__PURE__ */ jsx19("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children:
|
|
670
|
+
/* @__PURE__ */ jsx19("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
|
|
638
671
|
] }, `${row.spanId}-${i}`);
|
|
639
672
|
}) })
|
|
640
673
|
] });
|
|
641
674
|
}
|
|
642
675
|
|
|
676
|
+
// src/interactive/scenario-history-context.ts
|
|
677
|
+
import { createContext as createContext2, useContext as useContext3 } from "react";
|
|
678
|
+
var ScenarioHistoryContext = createContext2(null);
|
|
679
|
+
var ScenarioHistoryProvider = ScenarioHistoryContext.Provider;
|
|
680
|
+
function useScenarioHistory() {
|
|
681
|
+
return useContext3(ScenarioHistoryContext);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// src/lib/run-history.ts
|
|
685
|
+
function currentStreak(entries) {
|
|
686
|
+
const last = entries[entries.length - 1];
|
|
687
|
+
if (!last) return void 0;
|
|
688
|
+
let count = 0;
|
|
689
|
+
for (let i = entries.length - 1; i >= 0 && entries[i].status === last.status; i--) count++;
|
|
690
|
+
return { status: last.status, count };
|
|
691
|
+
}
|
|
692
|
+
var STREAK_VERB = {
|
|
693
|
+
passed: "Passing",
|
|
694
|
+
failed: "Failing",
|
|
695
|
+
skipped: "Skipped",
|
|
696
|
+
pending: "Pending"
|
|
697
|
+
};
|
|
698
|
+
function describeRunHistory(entries) {
|
|
699
|
+
const passed = entries.filter((e) => e.status === "passed").length;
|
|
700
|
+
const base = `${passed}/${entries.length} runs passed`;
|
|
701
|
+
const streak = currentStreak(entries);
|
|
702
|
+
if (!streak || entries.length < 2) return base;
|
|
703
|
+
return `${base} \xB7 ${STREAK_VERB[streak.status]} for the last ${streak.count === 1 ? "run" : `${streak.count} runs`}`;
|
|
704
|
+
}
|
|
705
|
+
var MIN_FLAKINESS_SAMPLES = 3;
|
|
706
|
+
function flakinessOf(entries) {
|
|
707
|
+
const countable = entries.filter((e) => e.status === "passed" || e.status === "failed");
|
|
708
|
+
if (countable.length < MIN_FLAKINESS_SAMPLES) return "stable";
|
|
709
|
+
let transitions = 0;
|
|
710
|
+
for (let i = 1; i < countable.length; i++) {
|
|
711
|
+
if (countable[i].status !== countable[i - 1].status) transitions++;
|
|
712
|
+
}
|
|
713
|
+
const transitionScore = transitions / (countable.length - 1);
|
|
714
|
+
const failureRate = countable.filter((e) => e.status === "failed").length / countable.length;
|
|
715
|
+
if (transitionScore > 0.5 || transitionScore > 0.3 && failureRate > 0.2) return "flaky";
|
|
716
|
+
if (transitionScore > 0.2 || failureRate > 0.3) return "unstable";
|
|
717
|
+
return "stable";
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
// src/components/ScenarioRunHistory.tsx
|
|
721
|
+
import { Fragment as Fragment7, jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
722
|
+
var MAX_DOTS = 10;
|
|
723
|
+
var DOT_COLOR = {
|
|
724
|
+
passed: "bg-pass",
|
|
725
|
+
failed: "bg-fail",
|
|
726
|
+
skipped: "bg-skip",
|
|
727
|
+
pending: "bg-pend"
|
|
728
|
+
};
|
|
729
|
+
function dotTitle(e) {
|
|
730
|
+
const parts = [new Date(e.timestamp).toLocaleString(), e.status];
|
|
731
|
+
if (e.commitSha) parts.push(e.commitSha.slice(0, 8));
|
|
732
|
+
return parts.join(" \xB7 ");
|
|
733
|
+
}
|
|
734
|
+
function ScenarioRunHistory({ scenarioId }) {
|
|
735
|
+
const history = useScenarioHistory();
|
|
736
|
+
const entries = history?.[scenarioId];
|
|
737
|
+
if (!entries || entries.length < 2) return null;
|
|
738
|
+
const recent = entries.slice(-MAX_DOTS);
|
|
739
|
+
const flaky = flakinessOf(recent) === "flaky";
|
|
740
|
+
const summary = flaky ? `${describeRunHistory(recent)} \xB7 Flaky` : describeRunHistory(recent);
|
|
741
|
+
return /* @__PURE__ */ jsxs13(Fragment7, { children: [
|
|
742
|
+
flaky ? /* @__PURE__ */ jsx20(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
|
|
743
|
+
/* @__PURE__ */ jsx20(
|
|
744
|
+
"span",
|
|
745
|
+
{
|
|
746
|
+
role: "img",
|
|
747
|
+
"aria-label": `Run history: ${summary}`,
|
|
748
|
+
title: summary,
|
|
749
|
+
className: "flex shrink-0 items-center gap-[3px]",
|
|
750
|
+
children: recent.map((e, i) => /* @__PURE__ */ jsx20(
|
|
751
|
+
"span",
|
|
752
|
+
{
|
|
753
|
+
"aria-hidden": true,
|
|
754
|
+
title: dotTitle(e),
|
|
755
|
+
className: cn(
|
|
756
|
+
"inline-block size-1.5 rounded-full",
|
|
757
|
+
DOT_COLOR[e.status],
|
|
758
|
+
// The newest run (rightmost dot) is the one the card's status
|
|
759
|
+
// badge already describes; ring it so the timeline reads as
|
|
760
|
+
// "…leading up to now".
|
|
761
|
+
i === recent.length - 1 && "ring-1 ring-border ring-offset-1 ring-offset-card"
|
|
762
|
+
)
|
|
763
|
+
},
|
|
764
|
+
`${e.timestamp}-${i}`
|
|
765
|
+
))
|
|
766
|
+
}
|
|
767
|
+
)
|
|
768
|
+
] });
|
|
769
|
+
}
|
|
770
|
+
|
|
643
771
|
// src/interactive/collapse-context.ts
|
|
644
|
-
import { createContext as
|
|
645
|
-
var CollapseContext =
|
|
772
|
+
import { createContext as createContext3, useCallback, useContext as useContext4, useState } from "react";
|
|
773
|
+
var CollapseContext = createContext3(null);
|
|
646
774
|
var CollapseProvider = CollapseContext.Provider;
|
|
647
775
|
function useCollapse() {
|
|
648
|
-
return
|
|
776
|
+
return useContext4(CollapseContext);
|
|
649
777
|
}
|
|
650
778
|
|
|
651
779
|
// src/interactive/scenario-actions.tsx
|
|
652
|
-
import { createContext as
|
|
653
|
-
var ScenarioActionsContext =
|
|
780
|
+
import { createContext as createContext4, useContext as useContext5 } from "react";
|
|
781
|
+
var ScenarioActionsContext = createContext4(null);
|
|
654
782
|
var ScenarioActionsProvider = ScenarioActionsContext.Provider;
|
|
655
783
|
function useScenarioActions() {
|
|
656
|
-
return
|
|
784
|
+
return useContext5(ScenarioActionsContext);
|
|
657
785
|
}
|
|
658
786
|
|
|
659
787
|
// src/components/ui/card.tsx
|
|
660
788
|
import "react";
|
|
661
|
-
import { jsx as
|
|
789
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
662
790
|
function Card({ className, ...props }) {
|
|
663
|
-
return /* @__PURE__ */
|
|
791
|
+
return /* @__PURE__ */ jsx21(
|
|
664
792
|
"div",
|
|
665
793
|
{
|
|
666
794
|
"data-slot": "card",
|
|
@@ -673,7 +801,7 @@ function Card({ className, ...props }) {
|
|
|
673
801
|
);
|
|
674
802
|
}
|
|
675
803
|
function CardHeader({ className, ...props }) {
|
|
676
|
-
return /* @__PURE__ */
|
|
804
|
+
return /* @__PURE__ */ jsx21(
|
|
677
805
|
"div",
|
|
678
806
|
{
|
|
679
807
|
"data-slot": "card-header",
|
|
@@ -686,7 +814,7 @@ function CardHeader({ className, ...props }) {
|
|
|
686
814
|
);
|
|
687
815
|
}
|
|
688
816
|
function CardContent({ className, ...props }) {
|
|
689
|
-
return /* @__PURE__ */
|
|
817
|
+
return /* @__PURE__ */ jsx21(
|
|
690
818
|
"div",
|
|
691
819
|
{
|
|
692
820
|
"data-slot": "card-content",
|
|
@@ -697,7 +825,7 @@ function CardContent({ className, ...props }) {
|
|
|
697
825
|
}
|
|
698
826
|
|
|
699
827
|
// src/components/ReportScenario.tsx
|
|
700
|
-
import { jsx as
|
|
828
|
+
import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
701
829
|
var STATUS_LABEL = {
|
|
702
830
|
passed: "Passed",
|
|
703
831
|
failed: "Failed",
|
|
@@ -725,12 +853,12 @@ var STATUS_BADGE = {
|
|
|
725
853
|
function ReportScenario({ scenario, hideTitle = false }) {
|
|
726
854
|
const titleId = `${scenario.id}-title`;
|
|
727
855
|
const bodyId = `${scenario.id}-body`;
|
|
728
|
-
const label = STATUS_LABEL[scenario.status];
|
|
856
|
+
const label = scenario.planned ? "Planned" : STATUS_LABEL[scenario.status];
|
|
729
857
|
const collapse = useCollapse();
|
|
730
858
|
const collapsible = collapse !== null && !hideTitle;
|
|
731
859
|
const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
|
|
732
860
|
const actions = useScenarioActions();
|
|
733
|
-
return /* @__PURE__ */
|
|
861
|
+
return /* @__PURE__ */ jsxs14(
|
|
734
862
|
Card,
|
|
735
863
|
{
|
|
736
864
|
id: scenario.id,
|
|
@@ -738,10 +866,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
738
866
|
...hideTitle ? { "aria-label": `${scenario.title} \u2014 ${label}` } : { "aria-labelledby": titleId },
|
|
739
867
|
className: "gap-0 py-0",
|
|
740
868
|
children: [
|
|
741
|
-
/* @__PURE__ */
|
|
742
|
-
/* @__PURE__ */
|
|
743
|
-
hideTitle ? null : /* @__PURE__ */
|
|
744
|
-
collapsible ? /* @__PURE__ */
|
|
869
|
+
/* @__PURE__ */ jsxs14(CardHeader, { className: "px-4 py-3", children: [
|
|
870
|
+
/* @__PURE__ */ jsxs14("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
|
|
871
|
+
hideTitle ? null : /* @__PURE__ */ jsxs14("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
|
|
872
|
+
collapsible ? /* @__PURE__ */ jsx22(
|
|
745
873
|
"button",
|
|
746
874
|
{
|
|
747
875
|
type: "button",
|
|
@@ -750,17 +878,18 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
750
878
|
"aria-controls": bodyId,
|
|
751
879
|
"aria-label": `Toggle ${scenario.title}`,
|
|
752
880
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
753
|
-
children: /* @__PURE__ */
|
|
881
|
+
children: /* @__PURE__ */ jsx22("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
754
882
|
}
|
|
755
883
|
) : null,
|
|
756
|
-
/* @__PURE__ */
|
|
757
|
-
/* @__PURE__ */
|
|
884
|
+
/* @__PURE__ */ jsx22("span", { "aria-hidden": true, className: cn("text-sm leading-none", STATUS_GLYPH_COLOR[scenario.status]), children: STATUS_GLYPH[scenario.status] }),
|
|
885
|
+
/* @__PURE__ */ jsx22("span", { children: scenario.title })
|
|
758
886
|
] }),
|
|
759
|
-
/* @__PURE__ */
|
|
760
|
-
|
|
761
|
-
/* @__PURE__ */
|
|
762
|
-
|
|
763
|
-
|
|
887
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
888
|
+
/* @__PURE__ */ jsx22(ScenarioRunHistory, { scenarioId: scenario.id }),
|
|
889
|
+
scenario.durationMs > 0 ? /* @__PURE__ */ jsx22("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
|
|
890
|
+
/* @__PURE__ */ jsx22(Badge, { variant: STATUS_BADGE[scenario.status], "aria-label": `Status: ${label}`, children: label }),
|
|
891
|
+
actions ? /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-0.5", children: [
|
|
892
|
+
/* @__PURE__ */ jsx22(
|
|
764
893
|
"button",
|
|
765
894
|
{
|
|
766
895
|
type: "button",
|
|
@@ -771,7 +900,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
771
900
|
children: "link"
|
|
772
901
|
}
|
|
773
902
|
),
|
|
774
|
-
/* @__PURE__ */
|
|
903
|
+
/* @__PURE__ */ jsx22(
|
|
775
904
|
"button",
|
|
776
905
|
{
|
|
777
906
|
type: "button",
|
|
@@ -782,7 +911,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
782
911
|
children: "md"
|
|
783
912
|
}
|
|
784
913
|
),
|
|
785
|
-
/* @__PURE__ */
|
|
914
|
+
/* @__PURE__ */ jsx22(
|
|
786
915
|
"button",
|
|
787
916
|
{
|
|
788
917
|
type: "button",
|
|
@@ -796,13 +925,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
796
925
|
] }) : null
|
|
797
926
|
] })
|
|
798
927
|
] }),
|
|
799
|
-
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */
|
|
800
|
-
scenario.tags.map((t) => /* @__PURE__ */
|
|
801
|
-
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */
|
|
928
|
+
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs14("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
|
|
929
|
+
scenario.tags.map((t) => /* @__PURE__ */ jsx22("li", { children: /* @__PURE__ */ jsx22(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
|
|
930
|
+
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ jsx22("li", { children: ticket.url ? /* @__PURE__ */ jsx22("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ jsx22(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ jsx22(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
|
|
802
931
|
] }) : null
|
|
803
932
|
] }),
|
|
804
|
-
/* @__PURE__ */
|
|
805
|
-
scenario.errorMessage ? /* @__PURE__ */
|
|
933
|
+
/* @__PURE__ */ jsxs14(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
|
|
934
|
+
scenario.errorMessage ? /* @__PURE__ */ jsx22(
|
|
806
935
|
"pre",
|
|
807
936
|
{
|
|
808
937
|
role: "alert",
|
|
@@ -810,10 +939,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
810
939
|
children: scenario.errorMessage
|
|
811
940
|
}
|
|
812
941
|
) : null,
|
|
813
|
-
/* @__PURE__ */
|
|
814
|
-
scenario.docEntries.length > 0 ? /* @__PURE__ */
|
|
815
|
-
/* @__PURE__ */
|
|
816
|
-
/* @__PURE__ */
|
|
942
|
+
/* @__PURE__ */ jsx22(ReportSteps, { scenario }),
|
|
943
|
+
scenario.docEntries.length > 0 ? /* @__PURE__ */ jsx22("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ jsx22(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
|
|
944
|
+
/* @__PURE__ */ jsx22(ReportAttachments, { attachments: scenario.attachments }),
|
|
945
|
+
/* @__PURE__ */ jsx22(ReportTrace, { spans: scenario.otelSpans })
|
|
817
946
|
] })
|
|
818
947
|
]
|
|
819
948
|
}
|
|
@@ -821,13 +950,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
821
950
|
}
|
|
822
951
|
|
|
823
952
|
// src/components/ReportScenarioList.tsx
|
|
824
|
-
import { Fragment as
|
|
953
|
+
import { Fragment as Fragment8, jsx as jsx23 } from "react/jsx-runtime";
|
|
825
954
|
function ReportScenarioList({ feature }) {
|
|
826
|
-
return /* @__PURE__ */
|
|
955
|
+
return /* @__PURE__ */ jsx23(Fragment8, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ jsx23(ReportScenario, { scenario }, scenario.id)) });
|
|
827
956
|
}
|
|
828
957
|
|
|
829
958
|
// src/components/ReportFeature.tsx
|
|
830
|
-
import { jsx as
|
|
959
|
+
import { jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
831
960
|
function ReportFeature({ feature }) {
|
|
832
961
|
const titleId = `${feature.id}-title`;
|
|
833
962
|
const bodyId = `${feature.id}-body`;
|
|
@@ -835,7 +964,7 @@ function ReportFeature({ feature }) {
|
|
|
835
964
|
const skipped = s.skipped + s.pending;
|
|
836
965
|
const collapse = useCollapse();
|
|
837
966
|
const collapsed = collapse?.isCollapsed(feature.id) ?? false;
|
|
838
|
-
return /* @__PURE__ */
|
|
967
|
+
return /* @__PURE__ */ jsxs15(
|
|
839
968
|
"section",
|
|
840
969
|
{
|
|
841
970
|
id: feature.id,
|
|
@@ -843,9 +972,9 @@ function ReportFeature({ feature }) {
|
|
|
843
972
|
"aria-labelledby": titleId,
|
|
844
973
|
className: "overflow-hidden rounded-xl border border-border bg-card shadow-sm",
|
|
845
974
|
children: [
|
|
846
|
-
/* @__PURE__ */
|
|
847
|
-
/* @__PURE__ */
|
|
848
|
-
collapse ? /* @__PURE__ */
|
|
975
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex items-center justify-between gap-4 border-b border-border bg-muted/40 px-4 py-3", children: [
|
|
976
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
977
|
+
collapse ? /* @__PURE__ */ jsx24(
|
|
849
978
|
"button",
|
|
850
979
|
{
|
|
851
980
|
type: "button",
|
|
@@ -854,30 +983,30 @@ function ReportFeature({ feature }) {
|
|
|
854
983
|
"aria-controls": bodyId,
|
|
855
984
|
"aria-label": `Toggle ${feature.title}`,
|
|
856
985
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
857
|
-
children: /* @__PURE__ */
|
|
986
|
+
children: /* @__PURE__ */ jsx24("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
858
987
|
}
|
|
859
988
|
) : null,
|
|
860
|
-
/* @__PURE__ */
|
|
861
|
-
/* @__PURE__ */
|
|
862
|
-
/* @__PURE__ */
|
|
989
|
+
/* @__PURE__ */ jsxs15("div", { className: "min-w-0", children: [
|
|
990
|
+
/* @__PURE__ */ jsx24("h2", { id: titleId, className: "text-sm font-semibold tracking-tight text-foreground", children: feature.title }),
|
|
991
|
+
/* @__PURE__ */ jsx24("p", { className: "mt-0.5 truncate font-mono text-xs text-muted-foreground", children: feature.sourceFile })
|
|
863
992
|
] })
|
|
864
993
|
] }),
|
|
865
|
-
/* @__PURE__ */
|
|
994
|
+
/* @__PURE__ */ jsxs15(
|
|
866
995
|
"div",
|
|
867
996
|
{
|
|
868
997
|
role: "img",
|
|
869
998
|
className: "flex shrink-0 items-center gap-2.5 font-mono text-xs font-medium",
|
|
870
999
|
"aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
|
|
871
1000
|
children: [
|
|
872
|
-
/* @__PURE__ */
|
|
1001
|
+
/* @__PURE__ */ jsxs15("span", { "aria-hidden": true, className: "text-pass", children: [
|
|
873
1002
|
"\u2713",
|
|
874
1003
|
s.passed
|
|
875
1004
|
] }),
|
|
876
|
-
/* @__PURE__ */
|
|
1005
|
+
/* @__PURE__ */ jsxs15("span", { "aria-hidden": true, className: "text-fail", children: [
|
|
877
1006
|
"\u2717",
|
|
878
1007
|
s.failed
|
|
879
1008
|
] }),
|
|
880
|
-
/* @__PURE__ */
|
|
1009
|
+
/* @__PURE__ */ jsxs15("span", { "aria-hidden": true, className: "text-skip", children: [
|
|
881
1010
|
"\u25CB",
|
|
882
1011
|
skipped
|
|
883
1012
|
] })
|
|
@@ -885,24 +1014,24 @@ function ReportFeature({ feature }) {
|
|
|
885
1014
|
}
|
|
886
1015
|
)
|
|
887
1016
|
] }),
|
|
888
|
-
/* @__PURE__ */
|
|
1017
|
+
/* @__PURE__ */ jsx24("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-2 p-3", children: /* @__PURE__ */ jsx24(ReportScenarioList, { feature }) })
|
|
889
1018
|
]
|
|
890
1019
|
}
|
|
891
1020
|
);
|
|
892
1021
|
}
|
|
893
1022
|
|
|
894
1023
|
// src/components/ReportFeatureList.tsx
|
|
895
|
-
import { Fragment as
|
|
1024
|
+
import { Fragment as Fragment9, jsx as jsx25 } from "react/jsx-runtime";
|
|
896
1025
|
function ReportFeatureList() {
|
|
897
1026
|
const report = useReport();
|
|
898
|
-
return /* @__PURE__ */
|
|
1027
|
+
return /* @__PURE__ */ jsx25(Fragment9, { children: report.features.map((feature) => /* @__PURE__ */ jsx25(ReportFeature, { feature }, feature.id)) });
|
|
899
1028
|
}
|
|
900
1029
|
|
|
901
1030
|
// src/components/ui/empty.tsx
|
|
902
1031
|
import { cva as cva2 } from "class-variance-authority";
|
|
903
|
-
import { jsx as
|
|
1032
|
+
import { jsx as jsx26 } from "react/jsx-runtime";
|
|
904
1033
|
function Empty({ className, ...props }) {
|
|
905
|
-
return /* @__PURE__ */
|
|
1034
|
+
return /* @__PURE__ */ jsx26(
|
|
906
1035
|
"div",
|
|
907
1036
|
{
|
|
908
1037
|
"data-slot": "empty",
|
|
@@ -915,7 +1044,7 @@ function Empty({ className, ...props }) {
|
|
|
915
1044
|
);
|
|
916
1045
|
}
|
|
917
1046
|
function EmptyHeader({ className, ...props }) {
|
|
918
|
-
return /* @__PURE__ */
|
|
1047
|
+
return /* @__PURE__ */ jsx26(
|
|
919
1048
|
"div",
|
|
920
1049
|
{
|
|
921
1050
|
"data-slot": "empty-header",
|
|
@@ -942,7 +1071,7 @@ var emptyMediaVariants = cva2(
|
|
|
942
1071
|
}
|
|
943
1072
|
);
|
|
944
1073
|
function EmptyTitle({ className, ...props }) {
|
|
945
|
-
return /* @__PURE__ */
|
|
1074
|
+
return /* @__PURE__ */ jsx26(
|
|
946
1075
|
"div",
|
|
947
1076
|
{
|
|
948
1077
|
"data-slot": "empty-title",
|
|
@@ -953,16 +1082,16 @@ function EmptyTitle({ className, ...props }) {
|
|
|
953
1082
|
}
|
|
954
1083
|
|
|
955
1084
|
// src/components/ReportEmpty.tsx
|
|
956
|
-
import { jsx as
|
|
1085
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
957
1086
|
function ReportEmpty({ message }) {
|
|
958
|
-
return /* @__PURE__ */
|
|
1087
|
+
return /* @__PURE__ */ jsx27(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ jsx27(EmptyHeader, { children: /* @__PURE__ */ jsx27(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
|
|
959
1088
|
}
|
|
960
1089
|
|
|
961
1090
|
// src/components/ReportSummary.tsx
|
|
962
|
-
import { Fragment as
|
|
1091
|
+
import { Fragment as Fragment10, jsx as jsx28, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
963
1092
|
function ReportSummary({ className }) {
|
|
964
1093
|
const report = useReport();
|
|
965
|
-
return /* @__PURE__ */
|
|
1094
|
+
return /* @__PURE__ */ jsx28(
|
|
966
1095
|
ReportSummaryView,
|
|
967
1096
|
{
|
|
968
1097
|
summary: report.summary,
|
|
@@ -972,32 +1101,32 @@ function ReportSummary({ className }) {
|
|
|
972
1101
|
);
|
|
973
1102
|
}
|
|
974
1103
|
function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
975
|
-
return /* @__PURE__ */
|
|
976
|
-
/* @__PURE__ */
|
|
977
|
-
/* @__PURE__ */
|
|
1104
|
+
return /* @__PURE__ */ jsxs16("p", { className: cn("text-sm text-muted-foreground", className), "aria-label": ariaLabel, children: [
|
|
1105
|
+
/* @__PURE__ */ jsxs16("span", { children: [
|
|
1106
|
+
/* @__PURE__ */ jsx28("strong", { className: "font-semibold text-foreground", children: summary.total }),
|
|
978
1107
|
" scenario",
|
|
979
1108
|
summary.total === 1 ? "" : "s"
|
|
980
1109
|
] }),
|
|
981
1110
|
" \xB7 ",
|
|
982
|
-
/* @__PURE__ */
|
|
1111
|
+
/* @__PURE__ */ jsxs16("span", { "data-status": "passed", className: "text-pass", children: [
|
|
983
1112
|
summary.passed,
|
|
984
1113
|
" passed"
|
|
985
1114
|
] }),
|
|
986
1115
|
" \xB7 ",
|
|
987
|
-
/* @__PURE__ */
|
|
1116
|
+
/* @__PURE__ */ jsxs16("span", { "data-status": "failed", className: "text-fail", children: [
|
|
988
1117
|
summary.failed,
|
|
989
1118
|
" failed"
|
|
990
1119
|
] }),
|
|
991
|
-
summary.skipped > 0 ? /* @__PURE__ */
|
|
1120
|
+
summary.skipped > 0 ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
992
1121
|
" \xB7 ",
|
|
993
|
-
/* @__PURE__ */
|
|
1122
|
+
/* @__PURE__ */ jsxs16("span", { "data-status": "skipped", className: "text-skip", children: [
|
|
994
1123
|
summary.skipped,
|
|
995
1124
|
" skipped"
|
|
996
1125
|
] })
|
|
997
1126
|
] }) : null,
|
|
998
|
-
summary.pending > 0 ? /* @__PURE__ */
|
|
1127
|
+
summary.pending > 0 ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
999
1128
|
" \xB7 ",
|
|
1000
|
-
/* @__PURE__ */
|
|
1129
|
+
/* @__PURE__ */ jsxs16("span", { "data-status": "pending", className: "text-pend", children: [
|
|
1001
1130
|
summary.pending,
|
|
1002
1131
|
" pending"
|
|
1003
1132
|
] })
|
|
@@ -1005,69 +1134,116 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1005
1134
|
] });
|
|
1006
1135
|
}
|
|
1007
1136
|
|
|
1137
|
+
// src/lib/provenance.ts
|
|
1138
|
+
var CI_DISPLAY_NAMES = {
|
|
1139
|
+
github: "GitHub Actions",
|
|
1140
|
+
gitlab: "GitLab CI",
|
|
1141
|
+
circleci: "CircleCI",
|
|
1142
|
+
jenkins: "Jenkins",
|
|
1143
|
+
azure: "Azure DevOps",
|
|
1144
|
+
buildkite: "Buildkite",
|
|
1145
|
+
travis: "Travis CI",
|
|
1146
|
+
ci: "CI"
|
|
1147
|
+
};
|
|
1148
|
+
function ciDisplayName(name) {
|
|
1149
|
+
return CI_DISPLAY_NAMES[name] ?? name;
|
|
1150
|
+
}
|
|
1151
|
+
function commitUrl(ci, sha) {
|
|
1152
|
+
const commitSha = ci?.commitSha ?? sha;
|
|
1153
|
+
if (!ci?.url || !commitSha) return void 0;
|
|
1154
|
+
const github = ci.url.match(/^(https?:\/\/[^/]+\/[^/]+\/[^/]+)\/actions\/runs\//);
|
|
1155
|
+
if (github) return `${github[1]}/commit/${commitSha}`;
|
|
1156
|
+
const gitlab = ci.url.match(/^(https?:\/\/.+)\/-\/pipelines\//);
|
|
1157
|
+
if (gitlab) return `${gitlab[1]}/-/commit/${commitSha}`;
|
|
1158
|
+
return void 0;
|
|
1159
|
+
}
|
|
1160
|
+
function prUrl(ci) {
|
|
1161
|
+
if (!ci?.url || !ci.prNumber) return void 0;
|
|
1162
|
+
const github = ci.url.match(/^(https?:\/\/[^/]+\/[^/]+\/[^/]+)\/actions\/runs\//);
|
|
1163
|
+
if (github) return `${github[1]}/pull/${ci.prNumber}`;
|
|
1164
|
+
return void 0;
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1008
1167
|
// src/components/ReportMeta.tsx
|
|
1009
|
-
import {
|
|
1010
|
-
import { jsx as jsx28, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1168
|
+
import { jsx as jsx29, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1011
1169
|
function ReportMeta() {
|
|
1012
1170
|
const report = useReport();
|
|
1013
1171
|
const items = [];
|
|
1172
|
+
const linkClass = "text-primary underline underline-offset-2";
|
|
1014
1173
|
if (report.startedAtMs) {
|
|
1015
1174
|
items.push({ label: "Started", value: new Date(report.startedAtMs).toLocaleString() });
|
|
1016
1175
|
}
|
|
1017
1176
|
if (report.durationMs) {
|
|
1018
|
-
items.push({ label: "Duration", value:
|
|
1177
|
+
items.push({ label: "Duration", value: formatDuration(report.durationMs) });
|
|
1019
1178
|
}
|
|
1020
1179
|
if (report.packageVersion) {
|
|
1021
1180
|
items.push({ label: "Version", value: report.packageVersion });
|
|
1022
1181
|
}
|
|
1023
|
-
if (report.
|
|
1024
|
-
items.push({ label: "
|
|
1182
|
+
if (report.ci?.branch) {
|
|
1183
|
+
items.push({ label: "Branch", value: report.ci.branch });
|
|
1184
|
+
}
|
|
1185
|
+
const sha = report.ci?.commitSha ?? report.gitSha;
|
|
1186
|
+
if (sha) {
|
|
1187
|
+
const url = commitUrl(report.ci, report.gitSha);
|
|
1188
|
+
const short = sha.slice(0, 8);
|
|
1189
|
+
items.push({
|
|
1190
|
+
label: "Commit",
|
|
1191
|
+
value: url ? /* @__PURE__ */ jsx29("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
|
|
1192
|
+
});
|
|
1025
1193
|
}
|
|
1026
1194
|
if (report.ci) {
|
|
1027
1195
|
items.push({
|
|
1028
1196
|
label: "CI",
|
|
1029
|
-
value: report.ci.url ? /* @__PURE__ */
|
|
1030
|
-
report.ci.name,
|
|
1197
|
+
value: report.ci.url ? /* @__PURE__ */ jsxs17("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
|
|
1198
|
+
ciDisplayName(report.ci.name),
|
|
1031
1199
|
report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
|
|
1032
|
-
] }) : `${report.ci.name}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
|
|
1200
|
+
] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
if (report.ci?.prNumber) {
|
|
1204
|
+
const url = prUrl(report.ci);
|
|
1205
|
+
const label = `#${report.ci.prNumber}`;
|
|
1206
|
+
items.push({
|
|
1207
|
+
label: "PR",
|
|
1208
|
+
value: url ? /* @__PURE__ */ jsx29("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
|
|
1033
1209
|
});
|
|
1034
1210
|
}
|
|
1035
1211
|
if (items.length === 0) return null;
|
|
1036
|
-
return /* @__PURE__ */
|
|
1037
|
-
/* @__PURE__ */
|
|
1038
|
-
/* @__PURE__ */
|
|
1212
|
+
return /* @__PURE__ */ jsx29("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__ */ jsxs17("div", { className: "flex gap-1.5", children: [
|
|
1213
|
+
/* @__PURE__ */ jsx29("dt", { className: "font-medium", children: item.label }),
|
|
1214
|
+
/* @__PURE__ */ jsx29("dd", { className: "font-mono text-foreground", children: item.value })
|
|
1039
1215
|
] }, item.label)) });
|
|
1040
1216
|
}
|
|
1041
1217
|
|
|
1042
1218
|
// src/components/ReportSchemaError.tsx
|
|
1043
|
-
import { jsx as
|
|
1219
|
+
import { jsx as jsx30, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1044
1220
|
function ReportSchemaError({ error }) {
|
|
1045
|
-
return /* @__PURE__ */
|
|
1046
|
-
/* @__PURE__ */
|
|
1047
|
-
/* @__PURE__ */
|
|
1048
|
-
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */
|
|
1221
|
+
return /* @__PURE__ */ jsxs18("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
|
|
1222
|
+
/* @__PURE__ */ jsx30("p", { children: /* @__PURE__ */ jsx30("strong", { children: "Report could not be displayed." }) }),
|
|
1223
|
+
/* @__PURE__ */ jsx30("p", { children: error.message }),
|
|
1224
|
+
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ jsxs18("p", { children: [
|
|
1049
1225
|
"The report bundle is newer than this version of ",
|
|
1050
|
-
/* @__PURE__ */
|
|
1226
|
+
/* @__PURE__ */ jsx30("code", { children: "executable-stories-react" }),
|
|
1051
1227
|
". Upgrade the package, or regenerate the report with an older formatters CLI."
|
|
1052
1228
|
] }) : null,
|
|
1053
|
-
error.issues && error.issues.length > 0 ? /* @__PURE__ */
|
|
1054
|
-
/* @__PURE__ */
|
|
1229
|
+
error.issues && error.issues.length > 0 ? /* @__PURE__ */ jsxs18("details", { children: [
|
|
1230
|
+
/* @__PURE__ */ jsxs18("summary", { children: [
|
|
1055
1231
|
error.issues.length,
|
|
1056
1232
|
" validation issue",
|
|
1057
1233
|
error.issues.length === 1 ? "" : "s"
|
|
1058
1234
|
] }),
|
|
1059
|
-
/* @__PURE__ */
|
|
1235
|
+
/* @__PURE__ */ jsx30("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
|
|
1060
1236
|
] }) : null
|
|
1061
1237
|
] });
|
|
1062
1238
|
}
|
|
1063
1239
|
|
|
1064
1240
|
// src/components/ReportShell.tsx
|
|
1065
|
-
import { Fragment as
|
|
1241
|
+
import { Fragment as Fragment11, jsx as jsx31, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1066
1242
|
function ReportTitleBlock({ title }) {
|
|
1067
|
-
return /* @__PURE__ */
|
|
1068
|
-
/* @__PURE__ */
|
|
1069
|
-
/* @__PURE__ */
|
|
1070
|
-
/* @__PURE__ */
|
|
1243
|
+
return /* @__PURE__ */ jsxs19(Fragment11, { children: [
|
|
1244
|
+
/* @__PURE__ */ jsx31("h1", { children: title ?? "Story Report" }),
|
|
1245
|
+
/* @__PURE__ */ jsx31(ReportSummary, {}),
|
|
1246
|
+
/* @__PURE__ */ jsx31(ReportMeta, {})
|
|
1071
1247
|
] });
|
|
1072
1248
|
}
|
|
1073
1249
|
function ReportErrorShell({
|
|
@@ -1076,28 +1252,29 @@ function ReportErrorShell({
|
|
|
1076
1252
|
title,
|
|
1077
1253
|
dataTheme
|
|
1078
1254
|
}) {
|
|
1079
|
-
return /* @__PURE__ */
|
|
1255
|
+
return /* @__PURE__ */ jsx31("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ jsx31(ReportSchemaError, { error }) });
|
|
1080
1256
|
}
|
|
1081
1257
|
|
|
1082
1258
|
// src/components/Report.tsx
|
|
1083
|
-
import { jsx as
|
|
1259
|
+
import { jsx as jsx32, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1084
1260
|
function Report(props) {
|
|
1085
1261
|
const { report, customRenderers, renderers, className, title, dataTheme } = props;
|
|
1086
1262
|
const result = unwrapReport(report);
|
|
1087
1263
|
if (!result.ok) {
|
|
1088
|
-
return /* @__PURE__ */
|
|
1264
|
+
return /* @__PURE__ */ jsx32(ReportErrorShell, { error: result.error, className, title, dataTheme });
|
|
1089
1265
|
}
|
|
1090
1266
|
const data = result.data;
|
|
1091
1267
|
const hasContent = data.features.length > 0;
|
|
1092
|
-
return /* @__PURE__ */
|
|
1093
|
-
/* @__PURE__ */
|
|
1094
|
-
hasContent ? /* @__PURE__ */
|
|
1268
|
+
return /* @__PURE__ */ jsx32(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ jsxs20("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
|
|
1269
|
+
/* @__PURE__ */ jsx32("header", { className: "es-report-header", children: /* @__PURE__ */ jsx32(ReportTitleBlock, { title }) }),
|
|
1270
|
+
hasContent ? /* @__PURE__ */ jsx32(ReportFeatureList, {}) : /* @__PURE__ */ jsx32(ReportEmpty, {})
|
|
1095
1271
|
] }) });
|
|
1096
1272
|
}
|
|
1097
1273
|
|
|
1098
1274
|
// src/ssr-entry.ts
|
|
1099
1275
|
var ROOT_ID = "es-report-root";
|
|
1100
1276
|
var DATA_ID = "es-report-data";
|
|
1277
|
+
var HISTORY_ID = "es-report-history";
|
|
1101
1278
|
function escapeJsonForScript(json) {
|
|
1102
1279
|
return json.replace(/[<\u2028\u2029]/g, (c) => "\\u" + c.charCodeAt(0).toString(16).padStart(4, "0"));
|
|
1103
1280
|
}
|
|
@@ -1146,7 +1323,9 @@ function renderReportToHtml(report, options = {}) {
|
|
|
1146
1323
|
lang = "en",
|
|
1147
1324
|
syntaxHighlighting = true,
|
|
1148
1325
|
mermaid = true,
|
|
1149
|
-
islandScript = ""
|
|
1326
|
+
islandScript = "",
|
|
1327
|
+
staleAfterDays = 7,
|
|
1328
|
+
scenarioHistory
|
|
1150
1329
|
} = options;
|
|
1151
1330
|
const markup = renderToStaticMarkup(
|
|
1152
1331
|
createElement(Report, { report, title })
|
|
@@ -1156,9 +1335,10 @@ function renderReportToHtml(report, options = {}) {
|
|
|
1156
1335
|
const rawReport = parsed.ok ? parsed.data : void 0;
|
|
1157
1336
|
const interactive = islandScript.length > 0 && rawReport !== void 0;
|
|
1158
1337
|
const dataScript = interactive ? `<script type="application/json" id="${DATA_ID}">${escapeJsonForScript(JSON.stringify(rawReport))}</script>` : "";
|
|
1338
|
+
const historyScript = interactive && scenarioHistory && Object.keys(scenarioHistory).length > 0 ? `<script type="application/json" id="${HISTORY_ID}">${escapeJsonForScript(JSON.stringify(scenarioHistory))}</script>` : "";
|
|
1159
1339
|
const islandTag = interactive ? `<script>${islandScript}</script>` : "";
|
|
1160
1340
|
const cdnBody = interactive ? "" : cdn.body;
|
|
1161
|
-
const islandConfigAttrs = interactive ? ` data-es-syntax="${syntaxHighlighting ? "true" : "false"}" data-es-mermaid="${mermaid ? "true" : "false"}"` : "";
|
|
1341
|
+
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}"` : "";
|
|
1162
1342
|
const rootAttrs = interactive ? ` id="${ROOT_ID}" data-title="${escapeHtml(title)}"${islandConfigAttrs}` : "";
|
|
1163
1343
|
return `<!DOCTYPE html>
|
|
1164
1344
|
<html lang="${escapeHtml(lang)}" data-theme="${theme === "dark" ? "dark" : "light"}">
|
|
@@ -1174,6 +1354,7 @@ ${headExtra}
|
|
|
1174
1354
|
<body>
|
|
1175
1355
|
<div${rootAttrs} class="es-report-island font-sans text-foreground">${markup}</div>
|
|
1176
1356
|
${dataScript}
|
|
1357
|
+
${historyScript}
|
|
1177
1358
|
${bodyExtra}
|
|
1178
1359
|
${cdnBody}
|
|
1179
1360
|
${islandTag}
|