executable-stories-react 0.2.1 → 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 +344 -151
- 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 +328 -144
- package/dist/index.js.map +1 -1
- package/dist/interactive.cjs +532 -238
- 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 +493 -200
- 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 +274 -117
- 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 +271 -114
- 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";
|
|
@@ -538,9 +550,6 @@ function ReportAttachments({ attachments }) {
|
|
|
538
550
|
);
|
|
539
551
|
}
|
|
540
552
|
|
|
541
|
-
// src/components/ReportTrace.tsx
|
|
542
|
-
import { formatDuration as formatDuration2 } from "executable-stories-core/utils/duration";
|
|
543
|
-
|
|
544
553
|
// src/lib/trace.ts
|
|
545
554
|
var VALID = /* @__PURE__ */ new Set(["ok", "error", "unset"]);
|
|
546
555
|
var safeStatus = (s) => VALID.has(s) ? s : "unset";
|
|
@@ -635,7 +644,7 @@ function ReportTrace({ spans }) {
|
|
|
635
644
|
" span",
|
|
636
645
|
rows.length === 1 ? "" : "s",
|
|
637
646
|
", ",
|
|
638
|
-
|
|
647
|
+
formatDuration(totalMs),
|
|
639
648
|
")"
|
|
640
649
|
] }),
|
|
641
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) => {
|
|
@@ -658,33 +667,128 @@ function ReportTrace({ spans }) {
|
|
|
658
667
|
style: { left: `${leftPct}%`, width: `${widthPct}%` }
|
|
659
668
|
}
|
|
660
669
|
) }),
|
|
661
|
-
/* @__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) })
|
|
662
671
|
] }, `${row.spanId}-${i}`);
|
|
663
672
|
}) })
|
|
664
673
|
] });
|
|
665
674
|
}
|
|
666
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
|
+
|
|
667
771
|
// src/interactive/collapse-context.ts
|
|
668
|
-
import { createContext as
|
|
669
|
-
var CollapseContext =
|
|
772
|
+
import { createContext as createContext3, useCallback, useContext as useContext4, useState } from "react";
|
|
773
|
+
var CollapseContext = createContext3(null);
|
|
670
774
|
var CollapseProvider = CollapseContext.Provider;
|
|
671
775
|
function useCollapse() {
|
|
672
|
-
return
|
|
776
|
+
return useContext4(CollapseContext);
|
|
673
777
|
}
|
|
674
778
|
|
|
675
779
|
// src/interactive/scenario-actions.tsx
|
|
676
|
-
import { createContext as
|
|
677
|
-
var ScenarioActionsContext =
|
|
780
|
+
import { createContext as createContext4, useContext as useContext5 } from "react";
|
|
781
|
+
var ScenarioActionsContext = createContext4(null);
|
|
678
782
|
var ScenarioActionsProvider = ScenarioActionsContext.Provider;
|
|
679
783
|
function useScenarioActions() {
|
|
680
|
-
return
|
|
784
|
+
return useContext5(ScenarioActionsContext);
|
|
681
785
|
}
|
|
682
786
|
|
|
683
787
|
// src/components/ui/card.tsx
|
|
684
788
|
import "react";
|
|
685
|
-
import { jsx as
|
|
789
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
686
790
|
function Card({ className, ...props }) {
|
|
687
|
-
return /* @__PURE__ */
|
|
791
|
+
return /* @__PURE__ */ jsx21(
|
|
688
792
|
"div",
|
|
689
793
|
{
|
|
690
794
|
"data-slot": "card",
|
|
@@ -697,7 +801,7 @@ function Card({ className, ...props }) {
|
|
|
697
801
|
);
|
|
698
802
|
}
|
|
699
803
|
function CardHeader({ className, ...props }) {
|
|
700
|
-
return /* @__PURE__ */
|
|
804
|
+
return /* @__PURE__ */ jsx21(
|
|
701
805
|
"div",
|
|
702
806
|
{
|
|
703
807
|
"data-slot": "card-header",
|
|
@@ -710,7 +814,7 @@ function CardHeader({ className, ...props }) {
|
|
|
710
814
|
);
|
|
711
815
|
}
|
|
712
816
|
function CardContent({ className, ...props }) {
|
|
713
|
-
return /* @__PURE__ */
|
|
817
|
+
return /* @__PURE__ */ jsx21(
|
|
714
818
|
"div",
|
|
715
819
|
{
|
|
716
820
|
"data-slot": "card-content",
|
|
@@ -721,7 +825,7 @@ function CardContent({ className, ...props }) {
|
|
|
721
825
|
}
|
|
722
826
|
|
|
723
827
|
// src/components/ReportScenario.tsx
|
|
724
|
-
import { jsx as
|
|
828
|
+
import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
725
829
|
var STATUS_LABEL = {
|
|
726
830
|
passed: "Passed",
|
|
727
831
|
failed: "Failed",
|
|
@@ -749,12 +853,12 @@ var STATUS_BADGE = {
|
|
|
749
853
|
function ReportScenario({ scenario, hideTitle = false }) {
|
|
750
854
|
const titleId = `${scenario.id}-title`;
|
|
751
855
|
const bodyId = `${scenario.id}-body`;
|
|
752
|
-
const label = STATUS_LABEL[scenario.status];
|
|
856
|
+
const label = scenario.planned ? "Planned" : STATUS_LABEL[scenario.status];
|
|
753
857
|
const collapse = useCollapse();
|
|
754
858
|
const collapsible = collapse !== null && !hideTitle;
|
|
755
859
|
const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
|
|
756
860
|
const actions = useScenarioActions();
|
|
757
|
-
return /* @__PURE__ */
|
|
861
|
+
return /* @__PURE__ */ jsxs14(
|
|
758
862
|
Card,
|
|
759
863
|
{
|
|
760
864
|
id: scenario.id,
|
|
@@ -762,10 +866,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
762
866
|
...hideTitle ? { "aria-label": `${scenario.title} \u2014 ${label}` } : { "aria-labelledby": titleId },
|
|
763
867
|
className: "gap-0 py-0",
|
|
764
868
|
children: [
|
|
765
|
-
/* @__PURE__ */
|
|
766
|
-
/* @__PURE__ */
|
|
767
|
-
hideTitle ? null : /* @__PURE__ */
|
|
768
|
-
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(
|
|
769
873
|
"button",
|
|
770
874
|
{
|
|
771
875
|
type: "button",
|
|
@@ -774,17 +878,18 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
774
878
|
"aria-controls": bodyId,
|
|
775
879
|
"aria-label": `Toggle ${scenario.title}`,
|
|
776
880
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
777
|
-
children: /* @__PURE__ */
|
|
881
|
+
children: /* @__PURE__ */ jsx22("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
778
882
|
}
|
|
779
883
|
) : null,
|
|
780
|
-
/* @__PURE__ */
|
|
781
|
-
/* @__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 })
|
|
782
886
|
] }),
|
|
783
|
-
/* @__PURE__ */
|
|
784
|
-
|
|
785
|
-
/* @__PURE__ */
|
|
786
|
-
|
|
787
|
-
|
|
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(
|
|
788
893
|
"button",
|
|
789
894
|
{
|
|
790
895
|
type: "button",
|
|
@@ -795,7 +900,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
795
900
|
children: "link"
|
|
796
901
|
}
|
|
797
902
|
),
|
|
798
|
-
/* @__PURE__ */
|
|
903
|
+
/* @__PURE__ */ jsx22(
|
|
799
904
|
"button",
|
|
800
905
|
{
|
|
801
906
|
type: "button",
|
|
@@ -806,7 +911,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
806
911
|
children: "md"
|
|
807
912
|
}
|
|
808
913
|
),
|
|
809
|
-
/* @__PURE__ */
|
|
914
|
+
/* @__PURE__ */ jsx22(
|
|
810
915
|
"button",
|
|
811
916
|
{
|
|
812
917
|
type: "button",
|
|
@@ -820,13 +925,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
820
925
|
] }) : null
|
|
821
926
|
] })
|
|
822
927
|
] }),
|
|
823
|
-
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */
|
|
824
|
-
scenario.tags.map((t) => /* @__PURE__ */
|
|
825
|
-
(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}`))
|
|
826
931
|
] }) : null
|
|
827
932
|
] }),
|
|
828
|
-
/* @__PURE__ */
|
|
829
|
-
scenario.errorMessage ? /* @__PURE__ */
|
|
933
|
+
/* @__PURE__ */ jsxs14(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
|
|
934
|
+
scenario.errorMessage ? /* @__PURE__ */ jsx22(
|
|
830
935
|
"pre",
|
|
831
936
|
{
|
|
832
937
|
role: "alert",
|
|
@@ -834,10 +939,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
834
939
|
children: scenario.errorMessage
|
|
835
940
|
}
|
|
836
941
|
) : null,
|
|
837
|
-
/* @__PURE__ */
|
|
838
|
-
scenario.docEntries.length > 0 ? /* @__PURE__ */
|
|
839
|
-
/* @__PURE__ */
|
|
840
|
-
/* @__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 })
|
|
841
946
|
] })
|
|
842
947
|
]
|
|
843
948
|
}
|
|
@@ -845,13 +950,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
845
950
|
}
|
|
846
951
|
|
|
847
952
|
// src/components/ReportScenarioList.tsx
|
|
848
|
-
import { Fragment as
|
|
953
|
+
import { Fragment as Fragment8, jsx as jsx23 } from "react/jsx-runtime";
|
|
849
954
|
function ReportScenarioList({ feature }) {
|
|
850
|
-
return /* @__PURE__ */
|
|
955
|
+
return /* @__PURE__ */ jsx23(Fragment8, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ jsx23(ReportScenario, { scenario }, scenario.id)) });
|
|
851
956
|
}
|
|
852
957
|
|
|
853
958
|
// src/components/ReportFeature.tsx
|
|
854
|
-
import { jsx as
|
|
959
|
+
import { jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
855
960
|
function ReportFeature({ feature }) {
|
|
856
961
|
const titleId = `${feature.id}-title`;
|
|
857
962
|
const bodyId = `${feature.id}-body`;
|
|
@@ -859,7 +964,7 @@ function ReportFeature({ feature }) {
|
|
|
859
964
|
const skipped = s.skipped + s.pending;
|
|
860
965
|
const collapse = useCollapse();
|
|
861
966
|
const collapsed = collapse?.isCollapsed(feature.id) ?? false;
|
|
862
|
-
return /* @__PURE__ */
|
|
967
|
+
return /* @__PURE__ */ jsxs15(
|
|
863
968
|
"section",
|
|
864
969
|
{
|
|
865
970
|
id: feature.id,
|
|
@@ -867,9 +972,9 @@ function ReportFeature({ feature }) {
|
|
|
867
972
|
"aria-labelledby": titleId,
|
|
868
973
|
className: "overflow-hidden rounded-xl border border-border bg-card shadow-sm",
|
|
869
974
|
children: [
|
|
870
|
-
/* @__PURE__ */
|
|
871
|
-
/* @__PURE__ */
|
|
872
|
-
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(
|
|
873
978
|
"button",
|
|
874
979
|
{
|
|
875
980
|
type: "button",
|
|
@@ -878,30 +983,30 @@ function ReportFeature({ feature }) {
|
|
|
878
983
|
"aria-controls": bodyId,
|
|
879
984
|
"aria-label": `Toggle ${feature.title}`,
|
|
880
985
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
881
|
-
children: /* @__PURE__ */
|
|
986
|
+
children: /* @__PURE__ */ jsx24("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
882
987
|
}
|
|
883
988
|
) : null,
|
|
884
|
-
/* @__PURE__ */
|
|
885
|
-
/* @__PURE__ */
|
|
886
|
-
/* @__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 })
|
|
887
992
|
] })
|
|
888
993
|
] }),
|
|
889
|
-
/* @__PURE__ */
|
|
994
|
+
/* @__PURE__ */ jsxs15(
|
|
890
995
|
"div",
|
|
891
996
|
{
|
|
892
997
|
role: "img",
|
|
893
998
|
className: "flex shrink-0 items-center gap-2.5 font-mono text-xs font-medium",
|
|
894
999
|
"aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
|
|
895
1000
|
children: [
|
|
896
|
-
/* @__PURE__ */
|
|
1001
|
+
/* @__PURE__ */ jsxs15("span", { "aria-hidden": true, className: "text-pass", children: [
|
|
897
1002
|
"\u2713",
|
|
898
1003
|
s.passed
|
|
899
1004
|
] }),
|
|
900
|
-
/* @__PURE__ */
|
|
1005
|
+
/* @__PURE__ */ jsxs15("span", { "aria-hidden": true, className: "text-fail", children: [
|
|
901
1006
|
"\u2717",
|
|
902
1007
|
s.failed
|
|
903
1008
|
] }),
|
|
904
|
-
/* @__PURE__ */
|
|
1009
|
+
/* @__PURE__ */ jsxs15("span", { "aria-hidden": true, className: "text-skip", children: [
|
|
905
1010
|
"\u25CB",
|
|
906
1011
|
skipped
|
|
907
1012
|
] })
|
|
@@ -909,24 +1014,24 @@ function ReportFeature({ feature }) {
|
|
|
909
1014
|
}
|
|
910
1015
|
)
|
|
911
1016
|
] }),
|
|
912
|
-
/* @__PURE__ */
|
|
1017
|
+
/* @__PURE__ */ jsx24("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-2 p-3", children: /* @__PURE__ */ jsx24(ReportScenarioList, { feature }) })
|
|
913
1018
|
]
|
|
914
1019
|
}
|
|
915
1020
|
);
|
|
916
1021
|
}
|
|
917
1022
|
|
|
918
1023
|
// src/components/ReportFeatureList.tsx
|
|
919
|
-
import { Fragment as
|
|
1024
|
+
import { Fragment as Fragment9, jsx as jsx25 } from "react/jsx-runtime";
|
|
920
1025
|
function ReportFeatureList() {
|
|
921
1026
|
const report = useReport();
|
|
922
|
-
return /* @__PURE__ */
|
|
1027
|
+
return /* @__PURE__ */ jsx25(Fragment9, { children: report.features.map((feature) => /* @__PURE__ */ jsx25(ReportFeature, { feature }, feature.id)) });
|
|
923
1028
|
}
|
|
924
1029
|
|
|
925
1030
|
// src/components/ui/empty.tsx
|
|
926
1031
|
import { cva as cva2 } from "class-variance-authority";
|
|
927
|
-
import { jsx as
|
|
1032
|
+
import { jsx as jsx26 } from "react/jsx-runtime";
|
|
928
1033
|
function Empty({ className, ...props }) {
|
|
929
|
-
return /* @__PURE__ */
|
|
1034
|
+
return /* @__PURE__ */ jsx26(
|
|
930
1035
|
"div",
|
|
931
1036
|
{
|
|
932
1037
|
"data-slot": "empty",
|
|
@@ -939,7 +1044,7 @@ function Empty({ className, ...props }) {
|
|
|
939
1044
|
);
|
|
940
1045
|
}
|
|
941
1046
|
function EmptyHeader({ className, ...props }) {
|
|
942
|
-
return /* @__PURE__ */
|
|
1047
|
+
return /* @__PURE__ */ jsx26(
|
|
943
1048
|
"div",
|
|
944
1049
|
{
|
|
945
1050
|
"data-slot": "empty-header",
|
|
@@ -966,7 +1071,7 @@ var emptyMediaVariants = cva2(
|
|
|
966
1071
|
}
|
|
967
1072
|
);
|
|
968
1073
|
function EmptyTitle({ className, ...props }) {
|
|
969
|
-
return /* @__PURE__ */
|
|
1074
|
+
return /* @__PURE__ */ jsx26(
|
|
970
1075
|
"div",
|
|
971
1076
|
{
|
|
972
1077
|
"data-slot": "empty-title",
|
|
@@ -977,16 +1082,16 @@ function EmptyTitle({ className, ...props }) {
|
|
|
977
1082
|
}
|
|
978
1083
|
|
|
979
1084
|
// src/components/ReportEmpty.tsx
|
|
980
|
-
import { jsx as
|
|
1085
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
981
1086
|
function ReportEmpty({ message }) {
|
|
982
|
-
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." }) }) });
|
|
983
1088
|
}
|
|
984
1089
|
|
|
985
1090
|
// src/components/ReportSummary.tsx
|
|
986
|
-
import { Fragment as
|
|
1091
|
+
import { Fragment as Fragment10, jsx as jsx28, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
987
1092
|
function ReportSummary({ className }) {
|
|
988
1093
|
const report = useReport();
|
|
989
|
-
return /* @__PURE__ */
|
|
1094
|
+
return /* @__PURE__ */ jsx28(
|
|
990
1095
|
ReportSummaryView,
|
|
991
1096
|
{
|
|
992
1097
|
summary: report.summary,
|
|
@@ -996,32 +1101,32 @@ function ReportSummary({ className }) {
|
|
|
996
1101
|
);
|
|
997
1102
|
}
|
|
998
1103
|
function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
999
|
-
return /* @__PURE__ */
|
|
1000
|
-
/* @__PURE__ */
|
|
1001
|
-
/* @__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 }),
|
|
1002
1107
|
" scenario",
|
|
1003
1108
|
summary.total === 1 ? "" : "s"
|
|
1004
1109
|
] }),
|
|
1005
1110
|
" \xB7 ",
|
|
1006
|
-
/* @__PURE__ */
|
|
1111
|
+
/* @__PURE__ */ jsxs16("span", { "data-status": "passed", className: "text-pass", children: [
|
|
1007
1112
|
summary.passed,
|
|
1008
1113
|
" passed"
|
|
1009
1114
|
] }),
|
|
1010
1115
|
" \xB7 ",
|
|
1011
|
-
/* @__PURE__ */
|
|
1116
|
+
/* @__PURE__ */ jsxs16("span", { "data-status": "failed", className: "text-fail", children: [
|
|
1012
1117
|
summary.failed,
|
|
1013
1118
|
" failed"
|
|
1014
1119
|
] }),
|
|
1015
|
-
summary.skipped > 0 ? /* @__PURE__ */
|
|
1120
|
+
summary.skipped > 0 ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
1016
1121
|
" \xB7 ",
|
|
1017
|
-
/* @__PURE__ */
|
|
1122
|
+
/* @__PURE__ */ jsxs16("span", { "data-status": "skipped", className: "text-skip", children: [
|
|
1018
1123
|
summary.skipped,
|
|
1019
1124
|
" skipped"
|
|
1020
1125
|
] })
|
|
1021
1126
|
] }) : null,
|
|
1022
|
-
summary.pending > 0 ? /* @__PURE__ */
|
|
1127
|
+
summary.pending > 0 ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
|
|
1023
1128
|
" \xB7 ",
|
|
1024
|
-
/* @__PURE__ */
|
|
1129
|
+
/* @__PURE__ */ jsxs16("span", { "data-status": "pending", className: "text-pend", children: [
|
|
1025
1130
|
summary.pending,
|
|
1026
1131
|
" pending"
|
|
1027
1132
|
] })
|
|
@@ -1029,69 +1134,116 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1029
1134
|
] });
|
|
1030
1135
|
}
|
|
1031
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
|
+
|
|
1032
1167
|
// src/components/ReportMeta.tsx
|
|
1033
|
-
import {
|
|
1034
|
-
import { jsx as jsx28, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1168
|
+
import { jsx as jsx29, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1035
1169
|
function ReportMeta() {
|
|
1036
1170
|
const report = useReport();
|
|
1037
1171
|
const items = [];
|
|
1172
|
+
const linkClass = "text-primary underline underline-offset-2";
|
|
1038
1173
|
if (report.startedAtMs) {
|
|
1039
1174
|
items.push({ label: "Started", value: new Date(report.startedAtMs).toLocaleString() });
|
|
1040
1175
|
}
|
|
1041
1176
|
if (report.durationMs) {
|
|
1042
|
-
items.push({ label: "Duration", value:
|
|
1177
|
+
items.push({ label: "Duration", value: formatDuration(report.durationMs) });
|
|
1043
1178
|
}
|
|
1044
1179
|
if (report.packageVersion) {
|
|
1045
1180
|
items.push({ label: "Version", value: report.packageVersion });
|
|
1046
1181
|
}
|
|
1047
|
-
if (report.
|
|
1048
|
-
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
|
+
});
|
|
1049
1193
|
}
|
|
1050
1194
|
if (report.ci) {
|
|
1051
1195
|
items.push({
|
|
1052
1196
|
label: "CI",
|
|
1053
|
-
value: report.ci.url ? /* @__PURE__ */
|
|
1054
|
-
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),
|
|
1055
1199
|
report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
|
|
1056
|
-
] }) : `${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
|
|
1057
1209
|
});
|
|
1058
1210
|
}
|
|
1059
1211
|
if (items.length === 0) return null;
|
|
1060
|
-
return /* @__PURE__ */
|
|
1061
|
-
/* @__PURE__ */
|
|
1062
|
-
/* @__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 })
|
|
1063
1215
|
] }, item.label)) });
|
|
1064
1216
|
}
|
|
1065
1217
|
|
|
1066
1218
|
// src/components/ReportSchemaError.tsx
|
|
1067
|
-
import { jsx as
|
|
1219
|
+
import { jsx as jsx30, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1068
1220
|
function ReportSchemaError({ error }) {
|
|
1069
|
-
return /* @__PURE__ */
|
|
1070
|
-
/* @__PURE__ */
|
|
1071
|
-
/* @__PURE__ */
|
|
1072
|
-
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: [
|
|
1073
1225
|
"The report bundle is newer than this version of ",
|
|
1074
|
-
/* @__PURE__ */
|
|
1226
|
+
/* @__PURE__ */ jsx30("code", { children: "executable-stories-react" }),
|
|
1075
1227
|
". Upgrade the package, or regenerate the report with an older formatters CLI."
|
|
1076
1228
|
] }) : null,
|
|
1077
|
-
error.issues && error.issues.length > 0 ? /* @__PURE__ */
|
|
1078
|
-
/* @__PURE__ */
|
|
1229
|
+
error.issues && error.issues.length > 0 ? /* @__PURE__ */ jsxs18("details", { children: [
|
|
1230
|
+
/* @__PURE__ */ jsxs18("summary", { children: [
|
|
1079
1231
|
error.issues.length,
|
|
1080
1232
|
" validation issue",
|
|
1081
1233
|
error.issues.length === 1 ? "" : "s"
|
|
1082
1234
|
] }),
|
|
1083
|
-
/* @__PURE__ */
|
|
1235
|
+
/* @__PURE__ */ jsx30("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
|
|
1084
1236
|
] }) : null
|
|
1085
1237
|
] });
|
|
1086
1238
|
}
|
|
1087
1239
|
|
|
1088
1240
|
// src/components/ReportShell.tsx
|
|
1089
|
-
import { Fragment as
|
|
1241
|
+
import { Fragment as Fragment11, jsx as jsx31, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1090
1242
|
function ReportTitleBlock({ title }) {
|
|
1091
|
-
return /* @__PURE__ */
|
|
1092
|
-
/* @__PURE__ */
|
|
1093
|
-
/* @__PURE__ */
|
|
1094
|
-
/* @__PURE__ */
|
|
1243
|
+
return /* @__PURE__ */ jsxs19(Fragment11, { children: [
|
|
1244
|
+
/* @__PURE__ */ jsx31("h1", { children: title ?? "Story Report" }),
|
|
1245
|
+
/* @__PURE__ */ jsx31(ReportSummary, {}),
|
|
1246
|
+
/* @__PURE__ */ jsx31(ReportMeta, {})
|
|
1095
1247
|
] });
|
|
1096
1248
|
}
|
|
1097
1249
|
function ReportErrorShell({
|
|
@@ -1100,28 +1252,29 @@ function ReportErrorShell({
|
|
|
1100
1252
|
title,
|
|
1101
1253
|
dataTheme
|
|
1102
1254
|
}) {
|
|
1103
|
-
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 }) });
|
|
1104
1256
|
}
|
|
1105
1257
|
|
|
1106
1258
|
// src/components/Report.tsx
|
|
1107
|
-
import { jsx as
|
|
1259
|
+
import { jsx as jsx32, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1108
1260
|
function Report(props) {
|
|
1109
1261
|
const { report, customRenderers, renderers, className, title, dataTheme } = props;
|
|
1110
1262
|
const result = unwrapReport(report);
|
|
1111
1263
|
if (!result.ok) {
|
|
1112
|
-
return /* @__PURE__ */
|
|
1264
|
+
return /* @__PURE__ */ jsx32(ReportErrorShell, { error: result.error, className, title, dataTheme });
|
|
1113
1265
|
}
|
|
1114
1266
|
const data = result.data;
|
|
1115
1267
|
const hasContent = data.features.length > 0;
|
|
1116
|
-
return /* @__PURE__ */
|
|
1117
|
-
/* @__PURE__ */
|
|
1118
|
-
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, {})
|
|
1119
1271
|
] }) });
|
|
1120
1272
|
}
|
|
1121
1273
|
|
|
1122
1274
|
// src/ssr-entry.ts
|
|
1123
1275
|
var ROOT_ID = "es-report-root";
|
|
1124
1276
|
var DATA_ID = "es-report-data";
|
|
1277
|
+
var HISTORY_ID = "es-report-history";
|
|
1125
1278
|
function escapeJsonForScript(json) {
|
|
1126
1279
|
return json.replace(/[<\u2028\u2029]/g, (c) => "\\u" + c.charCodeAt(0).toString(16).padStart(4, "0"));
|
|
1127
1280
|
}
|
|
@@ -1170,7 +1323,9 @@ function renderReportToHtml(report, options = {}) {
|
|
|
1170
1323
|
lang = "en",
|
|
1171
1324
|
syntaxHighlighting = true,
|
|
1172
1325
|
mermaid = true,
|
|
1173
|
-
islandScript = ""
|
|
1326
|
+
islandScript = "",
|
|
1327
|
+
staleAfterDays = 7,
|
|
1328
|
+
scenarioHistory
|
|
1174
1329
|
} = options;
|
|
1175
1330
|
const markup = renderToStaticMarkup(
|
|
1176
1331
|
createElement(Report, { report, title })
|
|
@@ -1180,9 +1335,10 @@ function renderReportToHtml(report, options = {}) {
|
|
|
1180
1335
|
const rawReport = parsed.ok ? parsed.data : void 0;
|
|
1181
1336
|
const interactive = islandScript.length > 0 && rawReport !== void 0;
|
|
1182
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>` : "";
|
|
1183
1339
|
const islandTag = interactive ? `<script>${islandScript}</script>` : "";
|
|
1184
1340
|
const cdnBody = interactive ? "" : cdn.body;
|
|
1185
|
-
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}"` : "";
|
|
1186
1342
|
const rootAttrs = interactive ? ` id="${ROOT_ID}" data-title="${escapeHtml(title)}"${islandConfigAttrs}` : "";
|
|
1187
1343
|
return `<!DOCTYPE html>
|
|
1188
1344
|
<html lang="${escapeHtml(lang)}" data-theme="${theme === "dark" ? "dark" : "light"}">
|
|
@@ -1198,6 +1354,7 @@ ${headExtra}
|
|
|
1198
1354
|
<body>
|
|
1199
1355
|
<div${rootAttrs} class="es-report-island font-sans text-foreground">${markup}</div>
|
|
1200
1356
|
${dataScript}
|
|
1357
|
+
${historyScript}
|
|
1201
1358
|
${bodyExtra}
|
|
1202
1359
|
${cdnBody}
|
|
1203
1360
|
${islandTag}
|