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/interactive.cjs
CHANGED
|
@@ -22,6 +22,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
22
22
|
var interactive_exports = {};
|
|
23
23
|
__export(interactive_exports, {
|
|
24
24
|
ReportFailureBanner: () => ReportFailureBanner,
|
|
25
|
+
ReportFreshness: () => ReportFreshness,
|
|
25
26
|
ReportInteractive: () => ReportInteractive,
|
|
26
27
|
ReportInteractiveIsland: () => ReportInteractiveIsland,
|
|
27
28
|
ReportSearch: () => ReportSearch,
|
|
@@ -36,7 +37,7 @@ __export(interactive_exports, {
|
|
|
36
37
|
module.exports = __toCommonJS(interactive_exports);
|
|
37
38
|
|
|
38
39
|
// src/interactive/ReportInteractive.tsx
|
|
39
|
-
var
|
|
40
|
+
var import_react16 = require("react");
|
|
40
41
|
|
|
41
42
|
// src/result.ts
|
|
42
43
|
var ok = (data) => ({ ok: true, data });
|
|
@@ -87,11 +88,23 @@ function useReport() {
|
|
|
87
88
|
return ctx.report;
|
|
88
89
|
}
|
|
89
90
|
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
91
|
+
// ../executable-stories-core/dist/utils/duration.js
|
|
92
|
+
function formatDuration(ms) {
|
|
93
|
+
if (ms < 1e3) {
|
|
94
|
+
return `${Math.round(ms)} ms`;
|
|
95
|
+
}
|
|
96
|
+
if (ms < 6e4) {
|
|
97
|
+
return `${(ms / 1e3).toFixed(2)} s`;
|
|
98
|
+
}
|
|
99
|
+
const minutes = Math.floor(ms / 6e4);
|
|
100
|
+
const seconds = Math.floor(ms % 6e4 / 1e3);
|
|
101
|
+
if (minutes < 60) {
|
|
102
|
+
return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
|
|
103
|
+
}
|
|
104
|
+
const hours = Math.floor(minutes / 60);
|
|
105
|
+
const remainingMinutes = minutes % 60;
|
|
106
|
+
return `${hours}h ${remainingMinutes}m`;
|
|
107
|
+
}
|
|
95
108
|
|
|
96
109
|
// src/components/doc/DocNote.tsx
|
|
97
110
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
@@ -516,7 +529,7 @@ function ReportStepItem({ step }) {
|
|
|
516
529
|
}
|
|
517
530
|
),
|
|
518
531
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
|
|
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:
|
|
532
|
+
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
|
|
520
533
|
] }),
|
|
521
534
|
step.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
522
535
|
"pre",
|
|
@@ -574,9 +587,6 @@ function ReportAttachments({ attachments }) {
|
|
|
574
587
|
);
|
|
575
588
|
}
|
|
576
589
|
|
|
577
|
-
// src/components/ReportTrace.tsx
|
|
578
|
-
var import_duration2 = require("executable-stories-core/utils/duration");
|
|
579
|
-
|
|
580
590
|
// src/lib/trace.ts
|
|
581
591
|
var VALID = /* @__PURE__ */ new Set(["ok", "error", "unset"]);
|
|
582
592
|
var safeStatus = (s) => VALID.has(s) ? s : "unset";
|
|
@@ -671,7 +681,7 @@ function ReportTrace({ spans }) {
|
|
|
671
681
|
" span",
|
|
672
682
|
rows.length === 1 ? "" : "s",
|
|
673
683
|
", ",
|
|
674
|
-
|
|
684
|
+
formatDuration(totalMs),
|
|
675
685
|
")"
|
|
676
686
|
] }),
|
|
677
687
|
/* @__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) => {
|
|
@@ -694,18 +704,131 @@ function ReportTrace({ spans }) {
|
|
|
694
704
|
style: { left: `${leftPct}%`, width: `${widthPct}%` }
|
|
695
705
|
}
|
|
696
706
|
) }),
|
|
697
|
-
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children:
|
|
707
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
|
|
698
708
|
] }, `${row.spanId}-${i}`);
|
|
699
709
|
}) })
|
|
700
710
|
] });
|
|
701
711
|
}
|
|
702
712
|
|
|
703
|
-
// src/interactive/
|
|
713
|
+
// src/interactive/scenario-history-context.ts
|
|
704
714
|
var import_react5 = require("react");
|
|
705
|
-
var
|
|
715
|
+
var ScenarioHistoryContext = (0, import_react5.createContext)(null);
|
|
716
|
+
var ScenarioHistoryProvider = ScenarioHistoryContext.Provider;
|
|
717
|
+
function useScenarioHistory() {
|
|
718
|
+
return (0, import_react5.useContext)(ScenarioHistoryContext);
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
// src/lib/run-history.ts
|
|
722
|
+
function currentStreak(entries) {
|
|
723
|
+
const last = entries[entries.length - 1];
|
|
724
|
+
if (!last) return void 0;
|
|
725
|
+
let count = 0;
|
|
726
|
+
for (let i = entries.length - 1; i >= 0 && entries[i].status === last.status; i--) count++;
|
|
727
|
+
return { status: last.status, count };
|
|
728
|
+
}
|
|
729
|
+
var STREAK_VERB = {
|
|
730
|
+
passed: "Passing",
|
|
731
|
+
failed: "Failing",
|
|
732
|
+
skipped: "Skipped",
|
|
733
|
+
pending: "Pending"
|
|
734
|
+
};
|
|
735
|
+
function describeRunHistory(entries) {
|
|
736
|
+
const passed = entries.filter((e) => e.status === "passed").length;
|
|
737
|
+
const base = `${passed}/${entries.length} runs passed`;
|
|
738
|
+
const streak = currentStreak(entries);
|
|
739
|
+
if (!streak || entries.length < 2) return base;
|
|
740
|
+
return `${base} \xB7 ${STREAK_VERB[streak.status]} for the last ${streak.count === 1 ? "run" : `${streak.count} runs`}`;
|
|
741
|
+
}
|
|
742
|
+
var MIN_FLAKINESS_SAMPLES = 3;
|
|
743
|
+
function flakinessOf(entries) {
|
|
744
|
+
const countable = entries.filter((e) => e.status === "passed" || e.status === "failed");
|
|
745
|
+
if (countable.length < MIN_FLAKINESS_SAMPLES) return "stable";
|
|
746
|
+
let transitions = 0;
|
|
747
|
+
for (let i = 1; i < countable.length; i++) {
|
|
748
|
+
if (countable[i].status !== countable[i - 1].status) transitions++;
|
|
749
|
+
}
|
|
750
|
+
const transitionScore = transitions / (countable.length - 1);
|
|
751
|
+
const failureRate = countable.filter((e) => e.status === "failed").length / countable.length;
|
|
752
|
+
if (transitionScore > 0.5 || transitionScore > 0.3 && failureRate > 0.2) return "flaky";
|
|
753
|
+
if (transitionScore > 0.2 || failureRate > 0.3) return "unstable";
|
|
754
|
+
return "stable";
|
|
755
|
+
}
|
|
756
|
+
function diffSinceLastRun(history2, scenarios) {
|
|
757
|
+
let hasPreviousRun = false;
|
|
758
|
+
const delta = { newlyFailing: [], newlyPassing: [], added: [] };
|
|
759
|
+
for (const scenario of scenarios) {
|
|
760
|
+
const entries = history2[scenario.id];
|
|
761
|
+
if (!entries || entries.length === 0) continue;
|
|
762
|
+
const last = entries[entries.length - 1];
|
|
763
|
+
const prev = entries[entries.length - 2];
|
|
764
|
+
if (!prev) {
|
|
765
|
+
delta.added.push(scenario);
|
|
766
|
+
continue;
|
|
767
|
+
}
|
|
768
|
+
hasPreviousRun = true;
|
|
769
|
+
if (last.status === "failed" && prev.status !== "failed") delta.newlyFailing.push(scenario);
|
|
770
|
+
else if (last.status === "passed" && prev.status === "failed") delta.newlyPassing.push(scenario);
|
|
771
|
+
}
|
|
772
|
+
return hasPreviousRun ? delta : void 0;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// src/components/ScenarioRunHistory.tsx
|
|
776
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
777
|
+
var MAX_DOTS = 10;
|
|
778
|
+
var DOT_COLOR = {
|
|
779
|
+
passed: "bg-pass",
|
|
780
|
+
failed: "bg-fail",
|
|
781
|
+
skipped: "bg-skip",
|
|
782
|
+
pending: "bg-pend"
|
|
783
|
+
};
|
|
784
|
+
function dotTitle(e) {
|
|
785
|
+
const parts = [new Date(e.timestamp).toLocaleString(), e.status];
|
|
786
|
+
if (e.commitSha) parts.push(e.commitSha.slice(0, 8));
|
|
787
|
+
return parts.join(" \xB7 ");
|
|
788
|
+
}
|
|
789
|
+
function ScenarioRunHistory({ scenarioId }) {
|
|
790
|
+
const history2 = useScenarioHistory();
|
|
791
|
+
const entries = history2?.[scenarioId];
|
|
792
|
+
if (!entries || entries.length < 2) return null;
|
|
793
|
+
const recent = entries.slice(-MAX_DOTS);
|
|
794
|
+
const flaky = flakinessOf(recent) === "flaky";
|
|
795
|
+
const summary = flaky ? `${describeRunHistory(recent)} \xB7 Flaky` : describeRunHistory(recent);
|
|
796
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
|
|
797
|
+
flaky ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
|
|
798
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
799
|
+
"span",
|
|
800
|
+
{
|
|
801
|
+
role: "img",
|
|
802
|
+
"aria-label": `Run history: ${summary}`,
|
|
803
|
+
title: summary,
|
|
804
|
+
className: "flex shrink-0 items-center gap-[3px]",
|
|
805
|
+
children: recent.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
806
|
+
"span",
|
|
807
|
+
{
|
|
808
|
+
"aria-hidden": true,
|
|
809
|
+
title: dotTitle(e),
|
|
810
|
+
className: cn(
|
|
811
|
+
"inline-block size-1.5 rounded-full",
|
|
812
|
+
DOT_COLOR[e.status],
|
|
813
|
+
// The newest run (rightmost dot) is the one the card's status
|
|
814
|
+
// badge already describes; ring it so the timeline reads as
|
|
815
|
+
// "…leading up to now".
|
|
816
|
+
i === recent.length - 1 && "ring-1 ring-border ring-offset-1 ring-offset-card"
|
|
817
|
+
)
|
|
818
|
+
},
|
|
819
|
+
`${e.timestamp}-${i}`
|
|
820
|
+
))
|
|
821
|
+
}
|
|
822
|
+
)
|
|
823
|
+
] });
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
// src/interactive/collapse-context.ts
|
|
827
|
+
var import_react6 = require("react");
|
|
828
|
+
var CollapseContext = (0, import_react6.createContext)(null);
|
|
706
829
|
var CollapseProvider = CollapseContext.Provider;
|
|
707
830
|
function useCollapse() {
|
|
708
|
-
return (0,
|
|
831
|
+
return (0, import_react6.useContext)(CollapseContext);
|
|
709
832
|
}
|
|
710
833
|
var STORAGE_KEY = "es-collapsed-ids";
|
|
711
834
|
function readPersisted() {
|
|
@@ -725,9 +848,9 @@ function persist(ids) {
|
|
|
725
848
|
}
|
|
726
849
|
}
|
|
727
850
|
function useCollapseState() {
|
|
728
|
-
const [collapsed, setCollapsed] = (0,
|
|
729
|
-
const isCollapsed = (0,
|
|
730
|
-
const toggle = (0,
|
|
851
|
+
const [collapsed, setCollapsed] = (0, import_react6.useState)(readPersisted);
|
|
852
|
+
const isCollapsed = (0, import_react6.useCallback)((id) => collapsed.has(id), [collapsed]);
|
|
853
|
+
const toggle = (0, import_react6.useCallback)((id) => {
|
|
731
854
|
setCollapsed((prev) => {
|
|
732
855
|
const next = new Set(prev);
|
|
733
856
|
if (next.has(id)) next.delete(id);
|
|
@@ -736,14 +859,14 @@ function useCollapseState() {
|
|
|
736
859
|
return next;
|
|
737
860
|
});
|
|
738
861
|
}, []);
|
|
739
|
-
const collapseAll = (0,
|
|
862
|
+
const collapseAll = (0, import_react6.useCallback)((ids) => {
|
|
740
863
|
setCollapsed(() => {
|
|
741
864
|
const next = new Set(ids);
|
|
742
865
|
persist(next);
|
|
743
866
|
return next;
|
|
744
867
|
});
|
|
745
868
|
}, []);
|
|
746
|
-
const expandAll = (0,
|
|
869
|
+
const expandAll = (0, import_react6.useCallback)(() => {
|
|
747
870
|
setCollapsed(() => {
|
|
748
871
|
const next = /* @__PURE__ */ new Set();
|
|
749
872
|
persist(next);
|
|
@@ -754,11 +877,11 @@ function useCollapseState() {
|
|
|
754
877
|
}
|
|
755
878
|
|
|
756
879
|
// src/interactive/scenario-actions.tsx
|
|
757
|
-
var
|
|
758
|
-
var ScenarioActionsContext = (0,
|
|
880
|
+
var import_react7 = require("react");
|
|
881
|
+
var ScenarioActionsContext = (0, import_react7.createContext)(null);
|
|
759
882
|
var ScenarioActionsProvider = ScenarioActionsContext.Provider;
|
|
760
883
|
function useScenarioActions() {
|
|
761
|
-
return (0,
|
|
884
|
+
return (0, import_react7.useContext)(ScenarioActionsContext);
|
|
762
885
|
}
|
|
763
886
|
function scenarioToMarkdown(scenario) {
|
|
764
887
|
const lines = [`## ${scenario.title} _(${scenario.status})_`, ""];
|
|
@@ -796,9 +919,9 @@ function scenarioPermalink(scenario) {
|
|
|
796
919
|
|
|
797
920
|
// src/components/ui/card.tsx
|
|
798
921
|
var React2 = require("react");
|
|
799
|
-
var
|
|
922
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
800
923
|
function Card({ className, ...props }) {
|
|
801
|
-
return /* @__PURE__ */ (0,
|
|
924
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
802
925
|
"div",
|
|
803
926
|
{
|
|
804
927
|
"data-slot": "card",
|
|
@@ -811,7 +934,7 @@ function Card({ className, ...props }) {
|
|
|
811
934
|
);
|
|
812
935
|
}
|
|
813
936
|
function CardHeader({ className, ...props }) {
|
|
814
|
-
return /* @__PURE__ */ (0,
|
|
937
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
815
938
|
"div",
|
|
816
939
|
{
|
|
817
940
|
"data-slot": "card-header",
|
|
@@ -824,7 +947,7 @@ function CardHeader({ className, ...props }) {
|
|
|
824
947
|
);
|
|
825
948
|
}
|
|
826
949
|
function CardContent({ className, ...props }) {
|
|
827
|
-
return /* @__PURE__ */ (0,
|
|
950
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
828
951
|
"div",
|
|
829
952
|
{
|
|
830
953
|
"data-slot": "card-content",
|
|
@@ -835,7 +958,7 @@ function CardContent({ className, ...props }) {
|
|
|
835
958
|
}
|
|
836
959
|
|
|
837
960
|
// src/components/ReportScenario.tsx
|
|
838
|
-
var
|
|
961
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
839
962
|
var STATUS_LABEL = {
|
|
840
963
|
passed: "Passed",
|
|
841
964
|
failed: "Failed",
|
|
@@ -863,12 +986,12 @@ var STATUS_BADGE = {
|
|
|
863
986
|
function ReportScenario({ scenario, hideTitle = false }) {
|
|
864
987
|
const titleId = `${scenario.id}-title`;
|
|
865
988
|
const bodyId = `${scenario.id}-body`;
|
|
866
|
-
const label = STATUS_LABEL[scenario.status];
|
|
989
|
+
const label = scenario.planned ? "Planned" : STATUS_LABEL[scenario.status];
|
|
867
990
|
const collapse = useCollapse();
|
|
868
991
|
const collapsible = collapse !== null && !hideTitle;
|
|
869
992
|
const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
|
|
870
993
|
const actions = useScenarioActions();
|
|
871
|
-
return /* @__PURE__ */ (0,
|
|
994
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
872
995
|
Card,
|
|
873
996
|
{
|
|
874
997
|
id: scenario.id,
|
|
@@ -876,10 +999,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
876
999
|
...hideTitle ? { "aria-label": `${scenario.title} \u2014 ${label}` } : { "aria-labelledby": titleId },
|
|
877
1000
|
className: "gap-0 py-0",
|
|
878
1001
|
children: [
|
|
879
|
-
/* @__PURE__ */ (0,
|
|
880
|
-
/* @__PURE__ */ (0,
|
|
881
|
-
hideTitle ? null : /* @__PURE__ */ (0,
|
|
882
|
-
collapsible ? /* @__PURE__ */ (0,
|
|
1002
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(CardHeader, { className: "px-4 py-3", children: [
|
|
1003
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
|
|
1004
|
+
hideTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
|
|
1005
|
+
collapsible ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
883
1006
|
"button",
|
|
884
1007
|
{
|
|
885
1008
|
type: "button",
|
|
@@ -888,17 +1011,18 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
888
1011
|
"aria-controls": bodyId,
|
|
889
1012
|
"aria-label": `Toggle ${scenario.title}`,
|
|
890
1013
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
891
|
-
children: /* @__PURE__ */ (0,
|
|
1014
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
892
1015
|
}
|
|
893
1016
|
) : null,
|
|
894
|
-
/* @__PURE__ */ (0,
|
|
895
|
-
/* @__PURE__ */ (0,
|
|
1017
|
+
/* @__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] }),
|
|
1018
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: scenario.title })
|
|
896
1019
|
] }),
|
|
897
|
-
/* @__PURE__ */ (0,
|
|
898
|
-
|
|
899
|
-
/* @__PURE__ */ (0,
|
|
900
|
-
|
|
901
|
-
|
|
1020
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
1021
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ScenarioRunHistory, { scenarioId: scenario.id }),
|
|
1022
|
+
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,
|
|
1023
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Badge, { variant: STATUS_BADGE[scenario.status], "aria-label": `Status: ${label}`, children: label }),
|
|
1024
|
+
actions ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex items-center gap-0.5", children: [
|
|
1025
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
902
1026
|
"button",
|
|
903
1027
|
{
|
|
904
1028
|
type: "button",
|
|
@@ -909,7 +1033,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
909
1033
|
children: "link"
|
|
910
1034
|
}
|
|
911
1035
|
),
|
|
912
|
-
/* @__PURE__ */ (0,
|
|
1036
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
913
1037
|
"button",
|
|
914
1038
|
{
|
|
915
1039
|
type: "button",
|
|
@@ -920,7 +1044,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
920
1044
|
children: "md"
|
|
921
1045
|
}
|
|
922
1046
|
),
|
|
923
|
-
/* @__PURE__ */ (0,
|
|
1047
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
924
1048
|
"button",
|
|
925
1049
|
{
|
|
926
1050
|
type: "button",
|
|
@@ -934,13 +1058,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
934
1058
|
] }) : null
|
|
935
1059
|
] })
|
|
936
1060
|
] }),
|
|
937
|
-
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0,
|
|
938
|
-
scenario.tags.map((t) => /* @__PURE__ */ (0,
|
|
939
|
-
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0,
|
|
1061
|
+
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: [
|
|
1062
|
+
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}`)),
|
|
1063
|
+
(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}`))
|
|
940
1064
|
] }) : null
|
|
941
1065
|
] }),
|
|
942
|
-
/* @__PURE__ */ (0,
|
|
943
|
-
scenario.errorMessage ? /* @__PURE__ */ (0,
|
|
1066
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
|
|
1067
|
+
scenario.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
944
1068
|
"pre",
|
|
945
1069
|
{
|
|
946
1070
|
role: "alert",
|
|
@@ -948,10 +1072,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
948
1072
|
children: scenario.errorMessage
|
|
949
1073
|
}
|
|
950
1074
|
) : null,
|
|
951
|
-
/* @__PURE__ */ (0,
|
|
952
|
-
scenario.docEntries.length > 0 ? /* @__PURE__ */ (0,
|
|
953
|
-
/* @__PURE__ */ (0,
|
|
954
|
-
/* @__PURE__ */ (0,
|
|
1075
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ReportSteps, { scenario }),
|
|
1076
|
+
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,
|
|
1077
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ReportAttachments, { attachments: scenario.attachments }),
|
|
1078
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ReportTrace, { spans: scenario.otelSpans })
|
|
955
1079
|
] })
|
|
956
1080
|
]
|
|
957
1081
|
}
|
|
@@ -959,13 +1083,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
959
1083
|
}
|
|
960
1084
|
|
|
961
1085
|
// src/components/ReportScenarioList.tsx
|
|
962
|
-
var
|
|
1086
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
963
1087
|
function ReportScenarioList({ feature }) {
|
|
964
|
-
return /* @__PURE__ */ (0,
|
|
1088
|
+
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)) });
|
|
965
1089
|
}
|
|
966
1090
|
|
|
967
1091
|
// src/components/ReportFeature.tsx
|
|
968
|
-
var
|
|
1092
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
969
1093
|
function ReportFeature({ feature }) {
|
|
970
1094
|
const titleId = `${feature.id}-title`;
|
|
971
1095
|
const bodyId = `${feature.id}-body`;
|
|
@@ -973,7 +1097,7 @@ function ReportFeature({ feature }) {
|
|
|
973
1097
|
const skipped = s.skipped + s.pending;
|
|
974
1098
|
const collapse = useCollapse();
|
|
975
1099
|
const collapsed = collapse?.isCollapsed(feature.id) ?? false;
|
|
976
|
-
return /* @__PURE__ */ (0,
|
|
1100
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
977
1101
|
"section",
|
|
978
1102
|
{
|
|
979
1103
|
id: feature.id,
|
|
@@ -981,9 +1105,9 @@ function ReportFeature({ feature }) {
|
|
|
981
1105
|
"aria-labelledby": titleId,
|
|
982
1106
|
className: "overflow-hidden rounded-xl border border-border bg-card shadow-sm",
|
|
983
1107
|
children: [
|
|
984
|
-
/* @__PURE__ */ (0,
|
|
985
|
-
/* @__PURE__ */ (0,
|
|
986
|
-
collapse ? /* @__PURE__ */ (0,
|
|
1108
|
+
/* @__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: [
|
|
1109
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
1110
|
+
collapse ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
987
1111
|
"button",
|
|
988
1112
|
{
|
|
989
1113
|
type: "button",
|
|
@@ -992,30 +1116,30 @@ function ReportFeature({ feature }) {
|
|
|
992
1116
|
"aria-controls": bodyId,
|
|
993
1117
|
"aria-label": `Toggle ${feature.title}`,
|
|
994
1118
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
995
|
-
children: /* @__PURE__ */ (0,
|
|
1119
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
996
1120
|
}
|
|
997
1121
|
) : null,
|
|
998
|
-
/* @__PURE__ */ (0,
|
|
999
|
-
/* @__PURE__ */ (0,
|
|
1000
|
-
/* @__PURE__ */ (0,
|
|
1122
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "min-w-0", children: [
|
|
1123
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h2", { id: titleId, className: "text-sm font-semibold tracking-tight text-foreground", children: feature.title }),
|
|
1124
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "mt-0.5 truncate font-mono text-xs text-muted-foreground", children: feature.sourceFile })
|
|
1001
1125
|
] })
|
|
1002
1126
|
] }),
|
|
1003
|
-
/* @__PURE__ */ (0,
|
|
1127
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
1004
1128
|
"div",
|
|
1005
1129
|
{
|
|
1006
1130
|
role: "img",
|
|
1007
1131
|
className: "flex shrink-0 items-center gap-2.5 font-mono text-xs font-medium",
|
|
1008
1132
|
"aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
|
|
1009
1133
|
children: [
|
|
1010
|
-
/* @__PURE__ */ (0,
|
|
1134
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { "aria-hidden": true, className: "text-pass", children: [
|
|
1011
1135
|
"\u2713",
|
|
1012
1136
|
s.passed
|
|
1013
1137
|
] }),
|
|
1014
|
-
/* @__PURE__ */ (0,
|
|
1138
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { "aria-hidden": true, className: "text-fail", children: [
|
|
1015
1139
|
"\u2717",
|
|
1016
1140
|
s.failed
|
|
1017
1141
|
] }),
|
|
1018
|
-
/* @__PURE__ */ (0,
|
|
1142
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { "aria-hidden": true, className: "text-skip", children: [
|
|
1019
1143
|
"\u25CB",
|
|
1020
1144
|
skipped
|
|
1021
1145
|
] })
|
|
@@ -1023,24 +1147,24 @@ function ReportFeature({ feature }) {
|
|
|
1023
1147
|
}
|
|
1024
1148
|
)
|
|
1025
1149
|
] }),
|
|
1026
|
-
/* @__PURE__ */ (0,
|
|
1150
|
+
/* @__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 }) })
|
|
1027
1151
|
]
|
|
1028
1152
|
}
|
|
1029
1153
|
);
|
|
1030
1154
|
}
|
|
1031
1155
|
|
|
1032
1156
|
// src/components/ReportFeatureList.tsx
|
|
1033
|
-
var
|
|
1157
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1034
1158
|
function ReportFeatureList() {
|
|
1035
1159
|
const report = useReport();
|
|
1036
|
-
return /* @__PURE__ */ (0,
|
|
1160
|
+
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)) });
|
|
1037
1161
|
}
|
|
1038
1162
|
|
|
1039
1163
|
// src/components/ui/empty.tsx
|
|
1040
1164
|
var import_class_variance_authority2 = require("class-variance-authority");
|
|
1041
|
-
var
|
|
1165
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1042
1166
|
function Empty({ className, ...props }) {
|
|
1043
|
-
return /* @__PURE__ */ (0,
|
|
1167
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1044
1168
|
"div",
|
|
1045
1169
|
{
|
|
1046
1170
|
"data-slot": "empty",
|
|
@@ -1053,7 +1177,7 @@ function Empty({ className, ...props }) {
|
|
|
1053
1177
|
);
|
|
1054
1178
|
}
|
|
1055
1179
|
function EmptyHeader({ className, ...props }) {
|
|
1056
|
-
return /* @__PURE__ */ (0,
|
|
1180
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1057
1181
|
"div",
|
|
1058
1182
|
{
|
|
1059
1183
|
"data-slot": "empty-header",
|
|
@@ -1080,7 +1204,7 @@ var emptyMediaVariants = (0, import_class_variance_authority2.cva)(
|
|
|
1080
1204
|
}
|
|
1081
1205
|
);
|
|
1082
1206
|
function EmptyTitle({ className, ...props }) {
|
|
1083
|
-
return /* @__PURE__ */ (0,
|
|
1207
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1084
1208
|
"div",
|
|
1085
1209
|
{
|
|
1086
1210
|
"data-slot": "empty-title",
|
|
@@ -1091,16 +1215,16 @@ function EmptyTitle({ className, ...props }) {
|
|
|
1091
1215
|
}
|
|
1092
1216
|
|
|
1093
1217
|
// src/components/ReportEmpty.tsx
|
|
1094
|
-
var
|
|
1218
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1095
1219
|
function ReportEmpty({ message }) {
|
|
1096
|
-
return /* @__PURE__ */ (0,
|
|
1220
|
+
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." }) }) });
|
|
1097
1221
|
}
|
|
1098
1222
|
|
|
1099
1223
|
// src/components/ReportSummary.tsx
|
|
1100
|
-
var
|
|
1224
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1101
1225
|
function ReportSummary({ className }) {
|
|
1102
1226
|
const report = useReport();
|
|
1103
|
-
return /* @__PURE__ */ (0,
|
|
1227
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
1104
1228
|
ReportSummaryView,
|
|
1105
1229
|
{
|
|
1106
1230
|
summary: report.summary,
|
|
@@ -1110,32 +1234,32 @@ function ReportSummary({ className }) {
|
|
|
1110
1234
|
);
|
|
1111
1235
|
}
|
|
1112
1236
|
function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
1113
|
-
return /* @__PURE__ */ (0,
|
|
1114
|
-
/* @__PURE__ */ (0,
|
|
1115
|
-
/* @__PURE__ */ (0,
|
|
1237
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("p", { className: cn("text-sm text-muted-foreground", className), "aria-label": ariaLabel, children: [
|
|
1238
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { children: [
|
|
1239
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("strong", { className: "font-semibold text-foreground", children: summary.total }),
|
|
1116
1240
|
" scenario",
|
|
1117
1241
|
summary.total === 1 ? "" : "s"
|
|
1118
1242
|
] }),
|
|
1119
1243
|
" \xB7 ",
|
|
1120
|
-
/* @__PURE__ */ (0,
|
|
1244
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { "data-status": "passed", className: "text-pass", children: [
|
|
1121
1245
|
summary.passed,
|
|
1122
1246
|
" passed"
|
|
1123
1247
|
] }),
|
|
1124
1248
|
" \xB7 ",
|
|
1125
|
-
/* @__PURE__ */ (0,
|
|
1249
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { "data-status": "failed", className: "text-fail", children: [
|
|
1126
1250
|
summary.failed,
|
|
1127
1251
|
" failed"
|
|
1128
1252
|
] }),
|
|
1129
|
-
summary.skipped > 0 ? /* @__PURE__ */ (0,
|
|
1253
|
+
summary.skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
|
|
1130
1254
|
" \xB7 ",
|
|
1131
|
-
/* @__PURE__ */ (0,
|
|
1255
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { "data-status": "skipped", className: "text-skip", children: [
|
|
1132
1256
|
summary.skipped,
|
|
1133
1257
|
" skipped"
|
|
1134
1258
|
] })
|
|
1135
1259
|
] }) : null,
|
|
1136
|
-
summary.pending > 0 ? /* @__PURE__ */ (0,
|
|
1260
|
+
summary.pending > 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
|
|
1137
1261
|
" \xB7 ",
|
|
1138
|
-
/* @__PURE__ */ (0,
|
|
1262
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { "data-status": "pending", className: "text-pend", children: [
|
|
1139
1263
|
summary.pending,
|
|
1140
1264
|
" pending"
|
|
1141
1265
|
] })
|
|
@@ -1143,69 +1267,135 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1143
1267
|
] });
|
|
1144
1268
|
}
|
|
1145
1269
|
|
|
1270
|
+
// src/lib/provenance.ts
|
|
1271
|
+
function reportLastRunMs(report) {
|
|
1272
|
+
if (report.finishedAtMs && report.finishedAtMs > 0) return report.finishedAtMs;
|
|
1273
|
+
if (report.startedAtMs && report.startedAtMs > 0) return report.startedAtMs;
|
|
1274
|
+
return void 0;
|
|
1275
|
+
}
|
|
1276
|
+
function formatRelativeAge(thenMs, nowMs) {
|
|
1277
|
+
const deltaMs = Math.max(0, nowMs - thenMs);
|
|
1278
|
+
const minutes = Math.floor(deltaMs / 6e4);
|
|
1279
|
+
if (minutes < 1) return "just now";
|
|
1280
|
+
if (minutes < 60) return `${minutes} minute${minutes === 1 ? "" : "s"} ago`;
|
|
1281
|
+
const hours = Math.floor(minutes / 60);
|
|
1282
|
+
if (hours < 24) return `${hours} hour${hours === 1 ? "" : "s"} ago`;
|
|
1283
|
+
const days = Math.floor(hours / 24);
|
|
1284
|
+
return `${days} day${days === 1 ? "" : "s"} ago`;
|
|
1285
|
+
}
|
|
1286
|
+
function isReportStale(lastRunMs, staleAfterDays, nowMs) {
|
|
1287
|
+
if (lastRunMs === void 0 || staleAfterDays <= 0) return false;
|
|
1288
|
+
return nowMs - lastRunMs >= staleAfterDays * 864e5;
|
|
1289
|
+
}
|
|
1290
|
+
var CI_DISPLAY_NAMES = {
|
|
1291
|
+
github: "GitHub Actions",
|
|
1292
|
+
gitlab: "GitLab CI",
|
|
1293
|
+
circleci: "CircleCI",
|
|
1294
|
+
jenkins: "Jenkins",
|
|
1295
|
+
azure: "Azure DevOps",
|
|
1296
|
+
buildkite: "Buildkite",
|
|
1297
|
+
travis: "Travis CI",
|
|
1298
|
+
ci: "CI"
|
|
1299
|
+
};
|
|
1300
|
+
function ciDisplayName(name) {
|
|
1301
|
+
return CI_DISPLAY_NAMES[name] ?? name;
|
|
1302
|
+
}
|
|
1303
|
+
function commitUrl(ci, sha) {
|
|
1304
|
+
const commitSha = ci?.commitSha ?? sha;
|
|
1305
|
+
if (!ci?.url || !commitSha) return void 0;
|
|
1306
|
+
const github = ci.url.match(/^(https?:\/\/[^/]+\/[^/]+\/[^/]+)\/actions\/runs\//);
|
|
1307
|
+
if (github) return `${github[1]}/commit/${commitSha}`;
|
|
1308
|
+
const gitlab = ci.url.match(/^(https?:\/\/.+)\/-\/pipelines\//);
|
|
1309
|
+
if (gitlab) return `${gitlab[1]}/-/commit/${commitSha}`;
|
|
1310
|
+
return void 0;
|
|
1311
|
+
}
|
|
1312
|
+
function prUrl(ci) {
|
|
1313
|
+
if (!ci?.url || !ci.prNumber) return void 0;
|
|
1314
|
+
const github = ci.url.match(/^(https?:\/\/[^/]+\/[^/]+\/[^/]+)\/actions\/runs\//);
|
|
1315
|
+
if (github) return `${github[1]}/pull/${ci.prNumber}`;
|
|
1316
|
+
return void 0;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1146
1319
|
// src/components/ReportMeta.tsx
|
|
1147
|
-
var
|
|
1148
|
-
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1320
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
1149
1321
|
function ReportMeta() {
|
|
1150
1322
|
const report = useReport();
|
|
1151
1323
|
const items = [];
|
|
1324
|
+
const linkClass = "text-primary underline underline-offset-2";
|
|
1152
1325
|
if (report.startedAtMs) {
|
|
1153
1326
|
items.push({ label: "Started", value: new Date(report.startedAtMs).toLocaleString() });
|
|
1154
1327
|
}
|
|
1155
1328
|
if (report.durationMs) {
|
|
1156
|
-
items.push({ label: "Duration", value:
|
|
1329
|
+
items.push({ label: "Duration", value: formatDuration(report.durationMs) });
|
|
1157
1330
|
}
|
|
1158
1331
|
if (report.packageVersion) {
|
|
1159
1332
|
items.push({ label: "Version", value: report.packageVersion });
|
|
1160
1333
|
}
|
|
1161
|
-
if (report.
|
|
1162
|
-
items.push({ label: "
|
|
1334
|
+
if (report.ci?.branch) {
|
|
1335
|
+
items.push({ label: "Branch", value: report.ci.branch });
|
|
1336
|
+
}
|
|
1337
|
+
const sha = report.ci?.commitSha ?? report.gitSha;
|
|
1338
|
+
if (sha) {
|
|
1339
|
+
const url = commitUrl(report.ci, report.gitSha);
|
|
1340
|
+
const short = sha.slice(0, 8);
|
|
1341
|
+
items.push({
|
|
1342
|
+
label: "Commit",
|
|
1343
|
+
value: url ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
|
|
1344
|
+
});
|
|
1163
1345
|
}
|
|
1164
1346
|
if (report.ci) {
|
|
1165
1347
|
items.push({
|
|
1166
1348
|
label: "CI",
|
|
1167
|
-
value: report.ci.url ? /* @__PURE__ */ (0,
|
|
1168
|
-
report.ci.name,
|
|
1349
|
+
value: report.ci.url ? /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
|
|
1350
|
+
ciDisplayName(report.ci.name),
|
|
1169
1351
|
report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
|
|
1170
|
-
] }) : `${report.ci.name}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
|
|
1352
|
+
] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
|
|
1353
|
+
});
|
|
1354
|
+
}
|
|
1355
|
+
if (report.ci?.prNumber) {
|
|
1356
|
+
const url = prUrl(report.ci);
|
|
1357
|
+
const label = `#${report.ci.prNumber}`;
|
|
1358
|
+
items.push({
|
|
1359
|
+
label: "PR",
|
|
1360
|
+
value: url ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
|
|
1171
1361
|
});
|
|
1172
1362
|
}
|
|
1173
1363
|
if (items.length === 0) return null;
|
|
1174
|
-
return /* @__PURE__ */ (0,
|
|
1175
|
-
/* @__PURE__ */ (0,
|
|
1176
|
-
/* @__PURE__ */ (0,
|
|
1364
|
+
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: [
|
|
1365
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("dt", { className: "font-medium", children: item.label }),
|
|
1366
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("dd", { className: "font-mono text-foreground", children: item.value })
|
|
1177
1367
|
] }, item.label)) });
|
|
1178
1368
|
}
|
|
1179
1369
|
|
|
1180
1370
|
// src/components/ReportSchemaError.tsx
|
|
1181
|
-
var
|
|
1371
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
1182
1372
|
function ReportSchemaError({ error }) {
|
|
1183
|
-
return /* @__PURE__ */ (0,
|
|
1184
|
-
/* @__PURE__ */ (0,
|
|
1185
|
-
/* @__PURE__ */ (0,
|
|
1186
|
-
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0,
|
|
1373
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
|
|
1374
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("strong", { children: "Report could not be displayed." }) }),
|
|
1375
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { children: error.message }),
|
|
1376
|
+
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("p", { children: [
|
|
1187
1377
|
"The report bundle is newer than this version of ",
|
|
1188
|
-
/* @__PURE__ */ (0,
|
|
1378
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("code", { children: "executable-stories-react" }),
|
|
1189
1379
|
". Upgrade the package, or regenerate the report with an older formatters CLI."
|
|
1190
1380
|
] }) : null,
|
|
1191
|
-
error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0,
|
|
1192
|
-
/* @__PURE__ */ (0,
|
|
1381
|
+
error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("details", { children: [
|
|
1382
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("summary", { children: [
|
|
1193
1383
|
error.issues.length,
|
|
1194
1384
|
" validation issue",
|
|
1195
1385
|
error.issues.length === 1 ? "" : "s"
|
|
1196
1386
|
] }),
|
|
1197
|
-
/* @__PURE__ */ (0,
|
|
1387
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
|
|
1198
1388
|
] }) : null
|
|
1199
1389
|
] });
|
|
1200
1390
|
}
|
|
1201
1391
|
|
|
1202
1392
|
// src/components/ReportShell.tsx
|
|
1203
|
-
var
|
|
1393
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
1204
1394
|
function ReportTitleBlock({ title }) {
|
|
1205
|
-
return /* @__PURE__ */ (0,
|
|
1206
|
-
/* @__PURE__ */ (0,
|
|
1207
|
-
/* @__PURE__ */ (0,
|
|
1208
|
-
/* @__PURE__ */ (0,
|
|
1395
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_jsx_runtime31.Fragment, { children: [
|
|
1396
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("h1", { children: title ?? "Story Report" }),
|
|
1397
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ReportSummary, {}),
|
|
1398
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ReportMeta, {})
|
|
1209
1399
|
] });
|
|
1210
1400
|
}
|
|
1211
1401
|
function ReportErrorShell({
|
|
@@ -1214,13 +1404,13 @@ function ReportErrorShell({
|
|
|
1214
1404
|
title,
|
|
1215
1405
|
dataTheme
|
|
1216
1406
|
}) {
|
|
1217
|
-
return /* @__PURE__ */ (0,
|
|
1407
|
+
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 }) });
|
|
1218
1408
|
}
|
|
1219
1409
|
|
|
1220
1410
|
// src/interactive/ReportSearch.tsx
|
|
1221
|
-
var
|
|
1222
|
-
var
|
|
1223
|
-
var ReportSearch = (0,
|
|
1411
|
+
var import_react8 = require("react");
|
|
1412
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
1413
|
+
var ReportSearch = (0, import_react8.forwardRef)(
|
|
1224
1414
|
function ReportSearch2(props, ref) {
|
|
1225
1415
|
const {
|
|
1226
1416
|
value,
|
|
@@ -1230,7 +1420,7 @@ var ReportSearch = (0, import_react7.forwardRef)(
|
|
|
1230
1420
|
placeholder = "Search scenarios, tags, or step text\u2026",
|
|
1231
1421
|
className
|
|
1232
1422
|
} = props;
|
|
1233
|
-
const inputId = (0,
|
|
1423
|
+
const inputId = (0, import_react8.useId)();
|
|
1234
1424
|
const showCounts = typeof matchedCount === "number" && typeof totalCount === "number";
|
|
1235
1425
|
function handleChange(e) {
|
|
1236
1426
|
onChange(e.target.value);
|
|
@@ -1241,9 +1431,9 @@ var ReportSearch = (0, import_react7.forwardRef)(
|
|
|
1241
1431
|
e.preventDefault();
|
|
1242
1432
|
}
|
|
1243
1433
|
}
|
|
1244
|
-
return /* @__PURE__ */ (0,
|
|
1245
|
-
/* @__PURE__ */ (0,
|
|
1246
|
-
/* @__PURE__ */ (0,
|
|
1434
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: ["es-search", className].filter(Boolean).join(" "), children: [
|
|
1435
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("label", { htmlFor: inputId, className: "es-search-label", children: "Search" }),
|
|
1436
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
1247
1437
|
"input",
|
|
1248
1438
|
{
|
|
1249
1439
|
ref,
|
|
@@ -1258,13 +1448,13 @@ var ReportSearch = (0, import_react7.forwardRef)(
|
|
|
1258
1448
|
"aria-keyshortcuts": "/"
|
|
1259
1449
|
}
|
|
1260
1450
|
),
|
|
1261
|
-
showCounts ? /* @__PURE__ */ (0,
|
|
1451
|
+
showCounts ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "es-search-counts", "aria-live": "polite", children: value ? `${matchedCount} of ${totalCount}` : `${totalCount} total` }) : null
|
|
1262
1452
|
] });
|
|
1263
1453
|
}
|
|
1264
1454
|
);
|
|
1265
1455
|
|
|
1266
1456
|
// src/interactive/ReportFailureBanner.tsx
|
|
1267
|
-
var
|
|
1457
|
+
var import_react9 = require("react");
|
|
1268
1458
|
|
|
1269
1459
|
// src/lib/scroll.ts
|
|
1270
1460
|
function prefersReducedMotion() {
|
|
@@ -1287,15 +1477,15 @@ function scrollToScenarioId(scenarioId, options = {}) {
|
|
|
1287
1477
|
}
|
|
1288
1478
|
|
|
1289
1479
|
// src/interactive/ReportFailureBanner.tsx
|
|
1290
|
-
var
|
|
1480
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
1291
1481
|
function ReportFailureBanner({ failures }) {
|
|
1292
1482
|
const first = failures[0];
|
|
1293
|
-
const jumpToFirst = (0,
|
|
1483
|
+
const jumpToFirst = (0, import_react9.useCallback)(() => {
|
|
1294
1484
|
if (!first) return;
|
|
1295
1485
|
scrollToScenarioId(first.scenarioId);
|
|
1296
1486
|
}, [first]);
|
|
1297
1487
|
if (failures.length === 0) return null;
|
|
1298
|
-
return /* @__PURE__ */ (0,
|
|
1488
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
|
|
1299
1489
|
"div",
|
|
1300
1490
|
{
|
|
1301
1491
|
className: "es-failure-banner",
|
|
@@ -1303,13 +1493,13 @@ function ReportFailureBanner({ failures }) {
|
|
|
1303
1493
|
"aria-live": "polite",
|
|
1304
1494
|
"aria-label": "Failure summary",
|
|
1305
1495
|
children: [
|
|
1306
|
-
/* @__PURE__ */ (0,
|
|
1307
|
-
/* @__PURE__ */ (0,
|
|
1496
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: "es-failure-banner-text", children: [
|
|
1497
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("strong", { children: failures.length }),
|
|
1308
1498
|
" ",
|
|
1309
1499
|
"failure",
|
|
1310
1500
|
failures.length === 1 ? "" : "s"
|
|
1311
1501
|
] }),
|
|
1312
|
-
/* @__PURE__ */ (0,
|
|
1502
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
1313
1503
|
"button",
|
|
1314
1504
|
{
|
|
1315
1505
|
type: "button",
|
|
@@ -1324,9 +1514,101 @@ function ReportFailureBanner({ failures }) {
|
|
|
1324
1514
|
);
|
|
1325
1515
|
}
|
|
1326
1516
|
|
|
1517
|
+
// src/interactive/ReportFreshness.tsx
|
|
1518
|
+
var import_react10 = require("react");
|
|
1519
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
1520
|
+
function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
1521
|
+
const [now, setNow] = (0, import_react10.useState)(nowMs);
|
|
1522
|
+
(0, import_react10.useEffect)(() => {
|
|
1523
|
+
if (nowMs === void 0) setNow(Date.now());
|
|
1524
|
+
}, [nowMs]);
|
|
1525
|
+
if (lastRunMs === void 0 || now === void 0) return null;
|
|
1526
|
+
const age = formatRelativeAge(lastRunMs, now);
|
|
1527
|
+
const runLink = ciUrl ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
1528
|
+
"a",
|
|
1529
|
+
{
|
|
1530
|
+
href: ciUrl,
|
|
1531
|
+
target: "_blank",
|
|
1532
|
+
rel: "noreferrer noopener",
|
|
1533
|
+
className: "underline underline-offset-2",
|
|
1534
|
+
children: "View CI run"
|
|
1535
|
+
}
|
|
1536
|
+
) : null;
|
|
1537
|
+
if (isReportStale(lastRunMs, staleAfterDays, now)) {
|
|
1538
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "es-stale-banner", role: "status", "aria-label": "Report freshness", children: [
|
|
1539
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { children: [
|
|
1540
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("strong", { children: [
|
|
1541
|
+
"Last verified ",
|
|
1542
|
+
age,
|
|
1543
|
+
"."
|
|
1544
|
+
] }),
|
|
1545
|
+
" This report may no longer match the current behavior \u2014 look for a newer run."
|
|
1546
|
+
] }),
|
|
1547
|
+
runLink
|
|
1548
|
+
] });
|
|
1549
|
+
}
|
|
1550
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("p", { className: "es-freshness", "aria-label": "Report freshness", children: [
|
|
1551
|
+
"Verified ",
|
|
1552
|
+
age,
|
|
1553
|
+
runLink ? /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
|
|
1554
|
+
" \xB7 ",
|
|
1555
|
+
runLink
|
|
1556
|
+
] }) : null
|
|
1557
|
+
] });
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
// src/interactive/ReportLastRunDelta.tsx
|
|
1561
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
1562
|
+
var MAX_LINKS = 5;
|
|
1563
|
+
function ScenarioLinks({ scenarios, tone }) {
|
|
1564
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
|
|
1565
|
+
scenarios.slice(0, MAX_LINKS).map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { children: [
|
|
1566
|
+
i > 0 ? ", " : "",
|
|
1567
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
|
|
1568
|
+
] }, s.id)),
|
|
1569
|
+
scenarios.length > MAX_LINKS ? /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { children: [
|
|
1570
|
+
" and ",
|
|
1571
|
+
scenarios.length - MAX_LINKS,
|
|
1572
|
+
" more"
|
|
1573
|
+
] }) : null
|
|
1574
|
+
] });
|
|
1575
|
+
}
|
|
1576
|
+
function ReportLastRunDelta({
|
|
1577
|
+
history: history2,
|
|
1578
|
+
report
|
|
1579
|
+
}) {
|
|
1580
|
+
if (!history2) return null;
|
|
1581
|
+
const scenarios = report.features.flatMap((f) => f.scenarios.map((s) => ({ id: s.id, title: s.title })));
|
|
1582
|
+
const delta = diffSinceLastRun(history2, scenarios);
|
|
1583
|
+
if (!delta) return null;
|
|
1584
|
+
const { newlyFailing, newlyPassing, added } = delta;
|
|
1585
|
+
if (newlyFailing.length === 0 && newlyPassing.length === 0 && added.length === 0) {
|
|
1586
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: "Since last run: no behavior changes." });
|
|
1587
|
+
}
|
|
1588
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: [
|
|
1589
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "font-medium text-foreground", children: "Since last run:" }),
|
|
1590
|
+
newlyFailing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "ml-2 text-fail", children: [
|
|
1591
|
+
newlyFailing.length,
|
|
1592
|
+
" newly failing (",
|
|
1593
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ScenarioLinks, { scenarios: newlyFailing, tone: "text-fail" }),
|
|
1594
|
+
")"
|
|
1595
|
+
] }) : null,
|
|
1596
|
+
newlyPassing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "ml-2 text-pass", children: [
|
|
1597
|
+
newlyPassing.length,
|
|
1598
|
+
" fixed (",
|
|
1599
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ScenarioLinks, { scenarios: newlyPassing, tone: "text-pass" }),
|
|
1600
|
+
")"
|
|
1601
|
+
] }) : null,
|
|
1602
|
+
added.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "ml-2", children: [
|
|
1603
|
+
added.length,
|
|
1604
|
+
" new"
|
|
1605
|
+
] }) : null
|
|
1606
|
+
] });
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1327
1609
|
// src/interactive/ReportShortcutsHelp.tsx
|
|
1328
|
-
var
|
|
1329
|
-
var
|
|
1610
|
+
var import_react11 = require("react");
|
|
1611
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
1330
1612
|
var SHORTCUTS = [
|
|
1331
1613
|
{ keys: "/", description: "Focus search" },
|
|
1332
1614
|
{ keys: "f", description: "Jump to next failure" },
|
|
@@ -1335,14 +1617,14 @@ var SHORTCUTS = [
|
|
|
1335
1617
|
{ keys: "?", description: "Toggle this help" }
|
|
1336
1618
|
];
|
|
1337
1619
|
function ReportShortcutsHelp({ open, onClose }) {
|
|
1338
|
-
const dialogRef = (0,
|
|
1339
|
-
(0,
|
|
1620
|
+
const dialogRef = (0, import_react11.useRef)(null);
|
|
1621
|
+
(0, import_react11.useEffect)(() => {
|
|
1340
1622
|
const dialog = dialogRef.current;
|
|
1341
1623
|
if (!dialog) return;
|
|
1342
1624
|
if (open && !dialog.open) dialog.showModal();
|
|
1343
1625
|
else if (!open && dialog.open) dialog.close();
|
|
1344
1626
|
}, [open]);
|
|
1345
|
-
return /* @__PURE__ */ (0,
|
|
1627
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
1346
1628
|
"dialog",
|
|
1347
1629
|
{
|
|
1348
1630
|
ref: dialogRef,
|
|
@@ -1350,19 +1632,19 @@ function ReportShortcutsHelp({ open, onClose }) {
|
|
|
1350
1632
|
"aria-label": "Keyboard shortcuts",
|
|
1351
1633
|
onClose,
|
|
1352
1634
|
children: [
|
|
1353
|
-
/* @__PURE__ */ (0,
|
|
1354
|
-
/* @__PURE__ */ (0,
|
|
1355
|
-
/* @__PURE__ */ (0,
|
|
1356
|
-
/* @__PURE__ */ (0,
|
|
1635
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("h2", { children: "Keyboard shortcuts" }),
|
|
1636
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("dl", { children: SHORTCUTS.map((s) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { children: [
|
|
1637
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("dt", { children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("kbd", { children: s.keys }) }),
|
|
1638
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("dd", { children: s.description })
|
|
1357
1639
|
] }, s.keys)) }),
|
|
1358
|
-
/* @__PURE__ */ (0,
|
|
1640
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("form", { method: "dialog", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("button", { type: "submit", className: "es-shortcuts-close", children: "Close" }) })
|
|
1359
1641
|
]
|
|
1360
1642
|
}
|
|
1361
1643
|
);
|
|
1362
1644
|
}
|
|
1363
1645
|
|
|
1364
1646
|
// src/interactive/use-keyboard-shortcuts.ts
|
|
1365
|
-
var
|
|
1647
|
+
var import_react12 = require("react");
|
|
1366
1648
|
function isEditableTarget(target) {
|
|
1367
1649
|
if (!(target instanceof HTMLElement)) return false;
|
|
1368
1650
|
const tag = target.tagName;
|
|
@@ -1371,9 +1653,9 @@ function isEditableTarget(target) {
|
|
|
1371
1653
|
return false;
|
|
1372
1654
|
}
|
|
1373
1655
|
function useKeyboardShortcuts(handlers) {
|
|
1374
|
-
const ref = (0,
|
|
1656
|
+
const ref = (0, import_react12.useRef)(handlers);
|
|
1375
1657
|
ref.current = handlers;
|
|
1376
|
-
(0,
|
|
1658
|
+
(0, import_react12.useEffect)(() => {
|
|
1377
1659
|
function onKeyDown(e) {
|
|
1378
1660
|
const h = ref.current;
|
|
1379
1661
|
if (e.key === "Escape") {
|
|
@@ -1417,9 +1699,9 @@ function useKeyboardShortcuts(handlers) {
|
|
|
1417
1699
|
}
|
|
1418
1700
|
|
|
1419
1701
|
// src/interactive/use-deep-link-scroll.ts
|
|
1420
|
-
var
|
|
1702
|
+
var import_react13 = require("react");
|
|
1421
1703
|
function useDeepLinkScroll() {
|
|
1422
|
-
(0,
|
|
1704
|
+
(0, import_react13.useEffect)(() => {
|
|
1423
1705
|
function scrollToHash() {
|
|
1424
1706
|
const hash = window.location.hash.replace(/^#/, "");
|
|
1425
1707
|
if (!hash) return;
|
|
@@ -1528,7 +1810,7 @@ function listFailures(report) {
|
|
|
1528
1810
|
}
|
|
1529
1811
|
|
|
1530
1812
|
// src/interactive/ReportFilters.tsx
|
|
1531
|
-
var
|
|
1813
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
1532
1814
|
function ReportFilters({
|
|
1533
1815
|
statuses,
|
|
1534
1816
|
status,
|
|
@@ -1538,10 +1820,10 @@ function ReportFilters({
|
|
|
1538
1820
|
onToggleTag
|
|
1539
1821
|
}) {
|
|
1540
1822
|
if (statuses.length === 0 && tags.length === 0) return null;
|
|
1541
|
-
return /* @__PURE__ */ (0,
|
|
1542
|
-
statuses.length > 0 ? /* @__PURE__ */ (0,
|
|
1823
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
1824
|
+
statuses.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { role: "group", "aria-label": "Filter by status", className: "flex flex-wrap gap-1", children: statuses.map((opt) => {
|
|
1543
1825
|
const active = status === opt.key;
|
|
1544
|
-
return /* @__PURE__ */ (0,
|
|
1826
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
|
|
1545
1827
|
"button",
|
|
1546
1828
|
{
|
|
1547
1829
|
type: "button",
|
|
@@ -1553,22 +1835,22 @@ function ReportFilters({
|
|
|
1553
1835
|
),
|
|
1554
1836
|
children: [
|
|
1555
1837
|
opt.label,
|
|
1556
|
-
/* @__PURE__ */ (0,
|
|
1838
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "ml-1 font-mono opacity-70", children: opt.count })
|
|
1557
1839
|
]
|
|
1558
1840
|
},
|
|
1559
1841
|
opt.key
|
|
1560
1842
|
);
|
|
1561
1843
|
}) }) : null,
|
|
1562
|
-
tags.length > 0 ? /* @__PURE__ */ (0,
|
|
1844
|
+
tags.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("ul", { "aria-label": "Filter by tag", className: "flex flex-wrap gap-1.5", children: tags.map((tag) => {
|
|
1563
1845
|
const active = activeTags.includes(tag);
|
|
1564
|
-
return /* @__PURE__ */ (0,
|
|
1846
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
1565
1847
|
"button",
|
|
1566
1848
|
{
|
|
1567
1849
|
type: "button",
|
|
1568
1850
|
"aria-pressed": active,
|
|
1569
1851
|
onClick: () => onToggleTag(tag),
|
|
1570
1852
|
className: "cursor-pointer",
|
|
1571
|
-
children: /* @__PURE__ */ (0,
|
|
1853
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Badge, { variant: active ? "default" : "tag", children: tag })
|
|
1572
1854
|
}
|
|
1573
1855
|
) }, tag);
|
|
1574
1856
|
}) }) : null
|
|
@@ -1576,8 +1858,8 @@ function ReportFilters({
|
|
|
1576
1858
|
}
|
|
1577
1859
|
|
|
1578
1860
|
// src/interactive/ReportToc.tsx
|
|
1579
|
-
var
|
|
1580
|
-
var
|
|
1861
|
+
var import_react14 = require("react");
|
|
1862
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
1581
1863
|
var DOT = {
|
|
1582
1864
|
passed: "text-pass",
|
|
1583
1865
|
failed: "text-fail",
|
|
@@ -1586,12 +1868,12 @@ var DOT = {
|
|
|
1586
1868
|
};
|
|
1587
1869
|
function ReportToc() {
|
|
1588
1870
|
const report = useReport();
|
|
1589
|
-
const [activeId, setActiveId] = (0,
|
|
1590
|
-
const scenarioIds = (0,
|
|
1871
|
+
const [activeId, setActiveId] = (0, import_react14.useState)(null);
|
|
1872
|
+
const scenarioIds = (0, import_react14.useMemo)(
|
|
1591
1873
|
() => report.features.flatMap((f) => f.scenarios.map((s) => s.id)),
|
|
1592
1874
|
[report]
|
|
1593
1875
|
);
|
|
1594
|
-
(0,
|
|
1876
|
+
(0, import_react14.useEffect)(() => {
|
|
1595
1877
|
if (typeof IntersectionObserver === "undefined") return;
|
|
1596
1878
|
const els = scenarioIds.map((id) => document.getElementById(id)).filter((el) => el !== null);
|
|
1597
1879
|
if (els.length === 0) return;
|
|
@@ -1606,16 +1888,16 @@ function ReportToc() {
|
|
|
1606
1888
|
return () => observer.disconnect();
|
|
1607
1889
|
}, [scenarioIds]);
|
|
1608
1890
|
if (report.features.length === 0) return null;
|
|
1609
|
-
return /* @__PURE__ */ (0,
|
|
1891
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
1610
1892
|
"nav",
|
|
1611
1893
|
{
|
|
1612
1894
|
"aria-label": "Table of contents",
|
|
1613
1895
|
className: "sticky top-4 hidden h-fit w-56 shrink-0 self-start text-xs lg:block",
|
|
1614
|
-
children: /* @__PURE__ */ (0,
|
|
1615
|
-
/* @__PURE__ */ (0,
|
|
1616
|
-
/* @__PURE__ */ (0,
|
|
1896
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("ul", { className: "flex flex-col gap-3", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("li", { children: [
|
|
1897
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { className: "mb-1 truncate font-semibold text-foreground", children: feature.title }),
|
|
1898
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("ul", { className: "flex flex-col", children: feature.scenarios.map((scenario) => {
|
|
1617
1899
|
const active = activeId === scenario.id;
|
|
1618
|
-
return /* @__PURE__ */ (0,
|
|
1900
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
|
|
1619
1901
|
"a",
|
|
1620
1902
|
{
|
|
1621
1903
|
href: `#${scenario.id}`,
|
|
@@ -1629,8 +1911,8 @@ function ReportToc() {
|
|
|
1629
1911
|
active ? "border-primary font-medium text-foreground" : "border-border text-muted-foreground"
|
|
1630
1912
|
),
|
|
1631
1913
|
children: [
|
|
1632
|
-
/* @__PURE__ */ (0,
|
|
1633
|
-
/* @__PURE__ */ (0,
|
|
1914
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { "aria-hidden": true, className: cn("shrink-0", DOT[scenario.status]), children: "\u2022" }),
|
|
1915
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "truncate", children: scenario.title })
|
|
1634
1916
|
]
|
|
1635
1917
|
}
|
|
1636
1918
|
) }, scenario.id);
|
|
@@ -1641,7 +1923,7 @@ function ReportToc() {
|
|
|
1641
1923
|
}
|
|
1642
1924
|
|
|
1643
1925
|
// src/interactive/use-theme.ts
|
|
1644
|
-
var
|
|
1926
|
+
var import_react15 = require("react");
|
|
1645
1927
|
var KEY = "es-theme";
|
|
1646
1928
|
function applyTheme(theme) {
|
|
1647
1929
|
if (typeof document !== "undefined") {
|
|
@@ -1662,13 +1944,13 @@ function initialTheme() {
|
|
|
1662
1944
|
return "light";
|
|
1663
1945
|
}
|
|
1664
1946
|
function useTheme() {
|
|
1665
|
-
const [theme, setTheme] = (0,
|
|
1666
|
-
(0,
|
|
1947
|
+
const [theme, setTheme] = (0, import_react15.useState)("light");
|
|
1948
|
+
(0, import_react15.useEffect)(() => {
|
|
1667
1949
|
const t = initialTheme();
|
|
1668
1950
|
setTheme(t);
|
|
1669
1951
|
applyTheme(t);
|
|
1670
1952
|
}, []);
|
|
1671
|
-
const toggle = (0,
|
|
1953
|
+
const toggle = (0, import_react15.useCallback)(() => {
|
|
1672
1954
|
setTheme((prev) => {
|
|
1673
1955
|
const next = prev === "dark" ? "light" : "dark";
|
|
1674
1956
|
applyTheme(next);
|
|
@@ -1683,14 +1965,14 @@ function useTheme() {
|
|
|
1683
1965
|
}
|
|
1684
1966
|
|
|
1685
1967
|
// src/interactive/ReportInteractive.tsx
|
|
1686
|
-
var
|
|
1968
|
+
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
1687
1969
|
function ReportInteractive(props) {
|
|
1688
1970
|
const { report, className, title, dataTheme } = props;
|
|
1689
1971
|
const result = unwrapReport(report);
|
|
1690
1972
|
if (!result.ok) {
|
|
1691
|
-
return /* @__PURE__ */ (0,
|
|
1973
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
|
|
1692
1974
|
}
|
|
1693
|
-
return /* @__PURE__ */ (0,
|
|
1975
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ReportInteractiveView, { ...props, report: result.data });
|
|
1694
1976
|
}
|
|
1695
1977
|
function ReportInteractiveView({
|
|
1696
1978
|
report,
|
|
@@ -1699,23 +1981,25 @@ function ReportInteractiveView({
|
|
|
1699
1981
|
className,
|
|
1700
1982
|
title,
|
|
1701
1983
|
dataTheme,
|
|
1702
|
-
hideHeader = false
|
|
1984
|
+
hideHeader = false,
|
|
1985
|
+
staleAfterDays = 7,
|
|
1986
|
+
scenarioHistory
|
|
1703
1987
|
}) {
|
|
1704
|
-
const [query, setQuery] = (0,
|
|
1705
|
-
const [statusFilter, setStatusFilter] = (0,
|
|
1706
|
-
const [activeTags, setActiveTags] = (0,
|
|
1707
|
-
const [detail, setDetail] = (0,
|
|
1708
|
-
const [helpOpen, setHelpOpen] = (0,
|
|
1988
|
+
const [query, setQuery] = (0, import_react16.useState)("");
|
|
1989
|
+
const [statusFilter, setStatusFilter] = (0, import_react16.useState)("all");
|
|
1990
|
+
const [activeTags, setActiveTags] = (0, import_react16.useState)([]);
|
|
1991
|
+
const [detail, setDetail] = (0, import_react16.useState)("full");
|
|
1992
|
+
const [helpOpen, setHelpOpen] = (0, import_react16.useState)(false);
|
|
1709
1993
|
const { theme, toggle: toggleTheme } = useTheme();
|
|
1710
|
-
const searchRef = (0,
|
|
1711
|
-
const deferredQuery = (0,
|
|
1712
|
-
const failures = (0,
|
|
1713
|
-
const filtered = (0,
|
|
1994
|
+
const searchRef = (0, import_react16.useRef)(null);
|
|
1995
|
+
const deferredQuery = (0, import_react16.useDeferredValue)(query);
|
|
1996
|
+
const failures = (0, import_react16.useMemo)(() => listFailures(report), [report]);
|
|
1997
|
+
const filtered = (0, import_react16.useMemo)(
|
|
1714
1998
|
() => filterReport(report, { query: deferredQuery, status: statusFilter, tags: activeTags }),
|
|
1715
1999
|
[report, deferredQuery, statusFilter, activeTags]
|
|
1716
2000
|
);
|
|
1717
2001
|
const isFiltering = query !== deferredQuery;
|
|
1718
|
-
const statusOptions = (0,
|
|
2002
|
+
const statusOptions = (0, import_react16.useMemo)(() => {
|
|
1719
2003
|
const s = report.summary;
|
|
1720
2004
|
const opts = [
|
|
1721
2005
|
{ key: "all", label: "All", count: s.total }
|
|
@@ -1726,19 +2010,19 @@ function ReportInteractiveView({
|
|
|
1726
2010
|
if (s.pending) opts.push({ key: "pending", label: "Pending", count: s.pending });
|
|
1727
2011
|
return opts;
|
|
1728
2012
|
}, [report]);
|
|
1729
|
-
const tagOptions = (0,
|
|
1730
|
-
const toggleTag = (0,
|
|
2013
|
+
const tagOptions = (0, import_react16.useMemo)(() => allTags(report), [report]);
|
|
2014
|
+
const toggleTag = (0, import_react16.useCallback)(
|
|
1731
2015
|
(tag) => setActiveTags((prev) => prev.includes(tag) ? prev.filter((t) => t !== tag) : [...prev, tag]),
|
|
1732
2016
|
[]
|
|
1733
2017
|
);
|
|
1734
|
-
const [toast, setToast] = (0,
|
|
1735
|
-
const toastTimer = (0,
|
|
1736
|
-
const showToast = (0,
|
|
2018
|
+
const [toast, setToast] = (0, import_react16.useState)(null);
|
|
2019
|
+
const toastTimer = (0, import_react16.useRef)(null);
|
|
2020
|
+
const showToast = (0, import_react16.useCallback)((msg) => {
|
|
1737
2021
|
setToast(msg);
|
|
1738
2022
|
if (toastTimer.current) clearTimeout(toastTimer.current);
|
|
1739
2023
|
toastTimer.current = setTimeout(() => setToast(null), 1800);
|
|
1740
2024
|
}, []);
|
|
1741
|
-
const copy = (0,
|
|
2025
|
+
const copy = (0, import_react16.useCallback)(
|
|
1742
2026
|
(text, msg) => {
|
|
1743
2027
|
if (typeof navigator !== "undefined" && navigator.clipboard) {
|
|
1744
2028
|
navigator.clipboard.writeText(text).then(() => showToast(msg), () => showToast("Copy failed"));
|
|
@@ -1746,7 +2030,7 @@ function ReportInteractiveView({
|
|
|
1746
2030
|
},
|
|
1747
2031
|
[showToast]
|
|
1748
2032
|
);
|
|
1749
|
-
const scenarioActions = (0,
|
|
2033
|
+
const scenarioActions = (0, import_react16.useMemo)(
|
|
1750
2034
|
() => ({
|
|
1751
2035
|
copyLink: (s) => copy(scenarioPermalink(s), "Link copied"),
|
|
1752
2036
|
copyMarkdown: (s) => copy(scenarioToMarkdown(s), "Markdown copied"),
|
|
@@ -1754,17 +2038,17 @@ function ReportInteractiveView({
|
|
|
1754
2038
|
}),
|
|
1755
2039
|
[copy]
|
|
1756
2040
|
);
|
|
1757
|
-
const failureIndexRef = (0,
|
|
2041
|
+
const failureIndexRef = (0, import_react16.useRef)(0);
|
|
1758
2042
|
const collapse = useCollapseState();
|
|
1759
|
-
const allCollapsibleIds = (0,
|
|
2043
|
+
const allCollapsibleIds = (0, import_react16.useMemo)(
|
|
1760
2044
|
() => report.features.flatMap((f) => [f.id, ...f.scenarios.map((s) => s.id)]),
|
|
1761
2045
|
[report]
|
|
1762
2046
|
);
|
|
1763
|
-
const collapseAll = (0,
|
|
1764
|
-
const focusSearch = (0,
|
|
2047
|
+
const collapseAll = (0, import_react16.useCallback)(() => collapse.collapseAll(allCollapsibleIds), [collapse, allCollapsibleIds]);
|
|
2048
|
+
const focusSearch = (0, import_react16.useCallback)(() => {
|
|
1765
2049
|
searchRef.current?.focus();
|
|
1766
2050
|
}, []);
|
|
1767
|
-
const stepFailure = (0,
|
|
2051
|
+
const stepFailure = (0, import_react16.useCallback)(
|
|
1768
2052
|
(direction) => {
|
|
1769
2053
|
if (failures.length === 0) return;
|
|
1770
2054
|
failureIndexRef.current = (failureIndexRef.current + direction + failures.length) % failures.length;
|
|
@@ -1773,10 +2057,10 @@ function ReportInteractiveView({
|
|
|
1773
2057
|
},
|
|
1774
2058
|
[failures]
|
|
1775
2059
|
);
|
|
1776
|
-
const toggleHelp = (0,
|
|
2060
|
+
const toggleHelp = (0, import_react16.useCallback)(() => {
|
|
1777
2061
|
setHelpOpen((v) => !v);
|
|
1778
2062
|
}, []);
|
|
1779
|
-
const escape = (0,
|
|
2063
|
+
const escape = (0, import_react16.useCallback)(() => {
|
|
1780
2064
|
if (helpOpen) setHelpOpen(false);
|
|
1781
2065
|
else if (query !== "") setQuery("");
|
|
1782
2066
|
}, [helpOpen, query]);
|
|
@@ -1793,13 +2077,13 @@ function ReportInteractiveView({
|
|
|
1793
2077
|
const hasContent = filtered.features.length > 0;
|
|
1794
2078
|
const totalScenarios = report.summary.total;
|
|
1795
2079
|
const matchedScenarios = filtered.summary.total;
|
|
1796
|
-
return /* @__PURE__ */ (0,
|
|
2080
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(CollapseProvider, { value: collapse.api, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ScenarioActionsProvider, { value: scenarioActions, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ScenarioHistoryProvider, { value: scenarioHistory ?? null, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
1797
2081
|
ReportRoot,
|
|
1798
2082
|
{
|
|
1799
2083
|
report: filtered,
|
|
1800
2084
|
customRenderers,
|
|
1801
2085
|
renderers,
|
|
1802
|
-
children: /* @__PURE__ */ (0,
|
|
2086
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
|
|
1803
2087
|
"main",
|
|
1804
2088
|
{
|
|
1805
2089
|
className: cn("es-report", "es-report-interactive", className),
|
|
@@ -1808,10 +2092,19 @@ function ReportInteractiveView({
|
|
|
1808
2092
|
"data-theme": dataTheme,
|
|
1809
2093
|
"data-detail-level": detail,
|
|
1810
2094
|
children: [
|
|
1811
|
-
/* @__PURE__ */ (0,
|
|
1812
|
-
hideHeader ? null : /* @__PURE__ */ (0,
|
|
1813
|
-
/* @__PURE__ */ (0,
|
|
1814
|
-
|
|
2095
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("header", { className: "es-report-header", children: [
|
|
2096
|
+
hideHeader ? null : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ReportTitleBlock, { title }),
|
|
2097
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
2098
|
+
ReportFreshness,
|
|
2099
|
+
{
|
|
2100
|
+
lastRunMs: reportLastRunMs(report),
|
|
2101
|
+
ciUrl: report.ci?.url,
|
|
2102
|
+
staleAfterDays
|
|
2103
|
+
}
|
|
2104
|
+
),
|
|
2105
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ReportLastRunDelta, { history: scenarioHistory, report }),
|
|
2106
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
2107
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
1815
2108
|
ReportSearch,
|
|
1816
2109
|
{
|
|
1817
2110
|
ref: searchRef,
|
|
@@ -1821,8 +2114,8 @@ function ReportInteractiveView({
|
|
|
1821
2114
|
totalCount: totalScenarios
|
|
1822
2115
|
}
|
|
1823
2116
|
),
|
|
1824
|
-
/* @__PURE__ */ (0,
|
|
1825
|
-
/* @__PURE__ */ (0,
|
|
2117
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex shrink-0 gap-1", children: [
|
|
2118
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
1826
2119
|
"button",
|
|
1827
2120
|
{
|
|
1828
2121
|
type: "button",
|
|
@@ -1832,7 +2125,7 @@ function ReportInteractiveView({
|
|
|
1832
2125
|
children: "Expand all"
|
|
1833
2126
|
}
|
|
1834
2127
|
),
|
|
1835
|
-
/* @__PURE__ */ (0,
|
|
2128
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
1836
2129
|
"button",
|
|
1837
2130
|
{
|
|
1838
2131
|
type: "button",
|
|
@@ -1842,7 +2135,7 @@ function ReportInteractiveView({
|
|
|
1842
2135
|
children: "Collapse all"
|
|
1843
2136
|
}
|
|
1844
2137
|
),
|
|
1845
|
-
/* @__PURE__ */ (0,
|
|
2138
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
1846
2139
|
"button",
|
|
1847
2140
|
{
|
|
1848
2141
|
type: "button",
|
|
@@ -1852,7 +2145,7 @@ function ReportInteractiveView({
|
|
|
1852
2145
|
children: detail === "full" ? "Hide docs" : "Show docs"
|
|
1853
2146
|
}
|
|
1854
2147
|
),
|
|
1855
|
-
/* @__PURE__ */ (0,
|
|
2148
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
1856
2149
|
"button",
|
|
1857
2150
|
{
|
|
1858
2151
|
type: "button",
|
|
@@ -1864,7 +2157,7 @@ function ReportInteractiveView({
|
|
|
1864
2157
|
)
|
|
1865
2158
|
] })
|
|
1866
2159
|
] }),
|
|
1867
|
-
/* @__PURE__ */ (0,
|
|
2160
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
1868
2161
|
ReportFilters,
|
|
1869
2162
|
{
|
|
1870
2163
|
statuses: statusOptions,
|
|
@@ -1876,12 +2169,12 @@ function ReportInteractiveView({
|
|
|
1876
2169
|
}
|
|
1877
2170
|
)
|
|
1878
2171
|
] }),
|
|
1879
|
-
/* @__PURE__ */ (0,
|
|
1880
|
-
hasContent ? /* @__PURE__ */ (0,
|
|
1881
|
-
/* @__PURE__ */ (0,
|
|
1882
|
-
/* @__PURE__ */ (0,
|
|
1883
|
-
] }) : /* @__PURE__ */ (0,
|
|
1884
|
-
/* @__PURE__ */ (0,
|
|
2172
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ReportFailureBanner, { failures }),
|
|
2173
|
+
hasContent ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex gap-6", children: [
|
|
2174
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ReportToc, {}),
|
|
2175
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "flex min-w-0 flex-1 flex-col gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ReportFeatureList, {}) })
|
|
2176
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ReportEmpty, { message: query ? "No scenarios match the search." : void 0 }),
|
|
2177
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
1885
2178
|
"button",
|
|
1886
2179
|
{
|
|
1887
2180
|
type: "button",
|
|
@@ -1892,8 +2185,8 @@ function ReportInteractiveView({
|
|
|
1892
2185
|
children: "?"
|
|
1893
2186
|
}
|
|
1894
2187
|
),
|
|
1895
|
-
/* @__PURE__ */ (0,
|
|
1896
|
-
toast ? /* @__PURE__ */ (0,
|
|
2188
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ReportShortcutsHelp, { open: helpOpen, onClose: () => setHelpOpen(false) }),
|
|
2189
|
+
toast ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
1897
2190
|
"div",
|
|
1898
2191
|
{
|
|
1899
2192
|
role: "status",
|
|
@@ -1906,18 +2199,18 @@ function ReportInteractiveView({
|
|
|
1906
2199
|
}
|
|
1907
2200
|
)
|
|
1908
2201
|
}
|
|
1909
|
-
) }) });
|
|
2202
|
+
) }) }) });
|
|
1910
2203
|
}
|
|
1911
2204
|
|
|
1912
2205
|
// src/interactive/ReportInteractiveIsland.tsx
|
|
1913
|
-
var
|
|
2206
|
+
var import_react19 = require("react");
|
|
1914
2207
|
|
|
1915
2208
|
// src/interactive/island-renderers.tsx
|
|
1916
|
-
var
|
|
2209
|
+
var import_react18 = require("react");
|
|
1917
2210
|
|
|
1918
2211
|
// src/components/doc/MermaidView.tsx
|
|
1919
|
-
var
|
|
1920
|
-
var
|
|
2212
|
+
var import_react17 = require("react");
|
|
2213
|
+
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
1921
2214
|
function prefersDark(el) {
|
|
1922
2215
|
const themed = el?.closest("[data-theme]");
|
|
1923
2216
|
if (themed?.dataset.theme === "dark") return true;
|
|
@@ -1925,9 +2218,9 @@ function prefersDark(el) {
|
|
|
1925
2218
|
return typeof window !== "undefined" && !!window.matchMedia?.("(prefers-color-scheme: dark)").matches;
|
|
1926
2219
|
}
|
|
1927
2220
|
function MermaidView({ entry, load }) {
|
|
1928
|
-
const ref = (0,
|
|
1929
|
-
const [svg, setSvg] = (0,
|
|
1930
|
-
(0,
|
|
2221
|
+
const ref = (0, import_react17.useRef)(null);
|
|
2222
|
+
const [svg, setSvg] = (0, import_react17.useState)(null);
|
|
2223
|
+
(0, import_react17.useEffect)(() => {
|
|
1931
2224
|
let cancelled = false;
|
|
1932
2225
|
const draw = async () => {
|
|
1933
2226
|
try {
|
|
@@ -1954,9 +2247,9 @@ function MermaidView({ entry, load }) {
|
|
|
1954
2247
|
};
|
|
1955
2248
|
}, [entry.code, load]);
|
|
1956
2249
|
if (svg) {
|
|
1957
|
-
return /* @__PURE__ */ (0,
|
|
1958
|
-
entry.title ? /* @__PURE__ */ (0,
|
|
1959
|
-
/* @__PURE__ */ (0,
|
|
2250
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("figure", { ref, className: "my-3", children: [
|
|
2251
|
+
entry.title ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
|
|
2252
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
1960
2253
|
"div",
|
|
1961
2254
|
{
|
|
1962
2255
|
role: "img",
|
|
@@ -1967,11 +2260,11 @@ function MermaidView({ entry, load }) {
|
|
|
1967
2260
|
)
|
|
1968
2261
|
] });
|
|
1969
2262
|
}
|
|
1970
|
-
return /* @__PURE__ */ (0,
|
|
2263
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(MermaidSource, { entry, ref });
|
|
1971
2264
|
}
|
|
1972
2265
|
|
|
1973
2266
|
// src/interactive/island-renderers.tsx
|
|
1974
|
-
var
|
|
2267
|
+
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
1975
2268
|
var HLJS_ESM = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/highlight.min.js";
|
|
1976
2269
|
var MERMAID_ESM = "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
|
|
1977
2270
|
function cachedCdnModule(url) {
|
|
@@ -1988,8 +2281,8 @@ function cachedCdnModule(url) {
|
|
|
1988
2281
|
var loadMermaidFromCdn = cachedCdnModule(MERMAID_ESM);
|
|
1989
2282
|
var loadHljs = cachedCdnModule(HLJS_ESM);
|
|
1990
2283
|
function CdnHighlightedCode({ entry }) {
|
|
1991
|
-
const [html, setHtml] = (0,
|
|
1992
|
-
(0,
|
|
2284
|
+
const [html, setHtml] = (0, import_react18.useState)(null);
|
|
2285
|
+
(0, import_react18.useEffect)(() => {
|
|
1993
2286
|
let cancelled = false;
|
|
1994
2287
|
void (async () => {
|
|
1995
2288
|
try {
|
|
@@ -2005,27 +2298,27 @@ function CdnHighlightedCode({ entry }) {
|
|
|
2005
2298
|
cancelled = true;
|
|
2006
2299
|
};
|
|
2007
2300
|
}, [entry.content, entry.lang]);
|
|
2008
|
-
return /* @__PURE__ */ (0,
|
|
2301
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(CodeFigure, { label: entry.label, children: html !== null ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
2009
2302
|
"code",
|
|
2010
2303
|
{
|
|
2011
2304
|
className: cn("hljs font-mono text-xs", entry.lang && `language-${entry.lang}`),
|
|
2012
2305
|
dangerouslySetInnerHTML: { __html: html }
|
|
2013
2306
|
}
|
|
2014
|
-
) : /* @__PURE__ */ (0,
|
|
2307
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
|
|
2015
2308
|
}
|
|
2016
2309
|
function buildIslandRenderers(opts) {
|
|
2017
2310
|
const renderers = {};
|
|
2018
2311
|
if (opts.mermaid) {
|
|
2019
|
-
renderers.mermaid = (entry) => (0,
|
|
2312
|
+
renderers.mermaid = (entry) => (0, import_react18.createElement)(MermaidView, { entry, load: loadMermaidFromCdn });
|
|
2020
2313
|
}
|
|
2021
2314
|
if (opts.syntaxHighlighting) {
|
|
2022
|
-
renderers.code = (entry) => (0,
|
|
2315
|
+
renderers.code = (entry) => (0, import_react18.createElement)(CdnHighlightedCode, { entry });
|
|
2023
2316
|
}
|
|
2024
2317
|
return renderers;
|
|
2025
2318
|
}
|
|
2026
2319
|
|
|
2027
2320
|
// src/interactive/ReportInteractiveIsland.tsx
|
|
2028
|
-
var
|
|
2321
|
+
var import_jsx_runtime42 = require("react/jsx-runtime");
|
|
2029
2322
|
function ReportInteractiveIsland({
|
|
2030
2323
|
report,
|
|
2031
2324
|
title,
|
|
@@ -2034,11 +2327,11 @@ function ReportInteractiveIsland({
|
|
|
2034
2327
|
syntaxHighlighting = true,
|
|
2035
2328
|
mermaid = true
|
|
2036
2329
|
}) {
|
|
2037
|
-
const renderers = (0,
|
|
2330
|
+
const renderers = (0, import_react19.useMemo)(
|
|
2038
2331
|
() => buildIslandRenderers({ syntaxHighlighting, mermaid }),
|
|
2039
2332
|
[syntaxHighlighting, mermaid]
|
|
2040
2333
|
);
|
|
2041
|
-
return /* @__PURE__ */ (0,
|
|
2334
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
2042
2335
|
ReportInteractive,
|
|
2043
2336
|
{
|
|
2044
2337
|
report,
|
|
@@ -2052,6 +2345,7 @@ function ReportInteractiveIsland({
|
|
|
2052
2345
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2053
2346
|
0 && (module.exports = {
|
|
2054
2347
|
ReportFailureBanner,
|
|
2348
|
+
ReportFreshness,
|
|
2055
2349
|
ReportInteractive,
|
|
2056
2350
|
ReportInteractiveIsland,
|
|
2057
2351
|
ReportSearch,
|