executable-stories-react 0.4.1 → 0.6.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 +303 -240
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +301 -238
- package/dist/index.js.map +1 -1
- package/dist/interactive.cjs +982 -483
- package/dist/interactive.cjs.map +1 -1
- package/dist/interactive.d.cts +10 -1
- package/dist/interactive.d.ts +10 -1
- package/dist/interactive.js +945 -455
- package/dist/interactive.js.map +1 -1
- package/dist/report-island.global.js +108 -59
- package/dist/ssr.cjs +269 -206
- package/dist/ssr.cjs.map +1 -1
- package/dist/ssr.js +269 -206
- package/dist/ssr.js.map +1 -1
- package/dist/styles.css +18 -42
- package/dist/tailwind.css +1 -1
- package/package.json +1 -1
package/dist/interactive.js
CHANGED
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
import {
|
|
5
5
|
useCallback as useCallback4,
|
|
6
6
|
useDeferredValue,
|
|
7
|
+
useId as useId2,
|
|
7
8
|
useMemo as useMemo3,
|
|
8
9
|
useRef as useRef3,
|
|
9
|
-
useState as
|
|
10
|
+
useState as useState7
|
|
10
11
|
} from "react";
|
|
11
12
|
|
|
12
13
|
// src/result.ts
|
|
@@ -106,11 +107,15 @@ var badgeVariants = cva(
|
|
|
106
107
|
outline: "border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
|
|
107
108
|
ghost: "[a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
|
|
108
109
|
link: "text-primary underline-offset-4 [a&]:hover:underline",
|
|
109
|
-
|
|
110
|
+
// Pass/skip/pending are the quiet states: outline + coloured text, no
|
|
111
|
+
// fill, so a green report reads calm. Only `failed` keeps a tinted
|
|
112
|
+
// fill, making it the single loud badge on the page, so red pops the
|
|
113
|
+
// instant something breaks. Colour-as-accent, matching the KPI cards.
|
|
114
|
+
passed: "border-pass-border text-pass font-mono uppercase",
|
|
110
115
|
failed: "border-fail-border bg-fail-bg text-fail font-mono uppercase",
|
|
111
|
-
skipped: "border-skip-border
|
|
112
|
-
pending: "border-pend-border
|
|
113
|
-
tag: "border-
|
|
116
|
+
skipped: "border-skip-border text-skip font-mono uppercase",
|
|
117
|
+
pending: "border-pend-border text-pend font-mono uppercase",
|
|
118
|
+
tag: "border-border text-muted-foreground font-mono font-medium [a&]:hover:bg-muted"
|
|
114
119
|
}
|
|
115
120
|
},
|
|
116
121
|
defaultVariants: {
|
|
@@ -197,7 +202,7 @@ function DocTable({ entry }) {
|
|
|
197
202
|
entry.label ? /* @__PURE__ */ jsx6("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.label }) : null,
|
|
198
203
|
/* @__PURE__ */ jsx6("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border", children: /* @__PURE__ */ jsxs3("table", { className: "w-full border-collapse text-sm", children: [
|
|
199
204
|
/* @__PURE__ */ jsx6("thead", { children: /* @__PURE__ */ jsx6("tr", { className: "bg-muted/50", children: entry.columns.map((c) => /* @__PURE__ */ jsx6("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: c }, c)) }) }),
|
|
200
|
-
/* @__PURE__ */ jsx6("tbody", { children: entry.rows.map((row, i) => /* @__PURE__ */ jsx6("tr", { children: row.map((
|
|
205
|
+
/* @__PURE__ */ jsx6("tbody", { children: entry.rows.map((row, i) => /* @__PURE__ */ jsx6("tr", { children: row.map((cell2, j) => /* @__PURE__ */ jsx6("td", { className: "border-b border-border px-3 py-2 text-foreground", children: cell2 }, j)) }, i)) })
|
|
201
206
|
] }) })
|
|
202
207
|
] });
|
|
203
208
|
}
|
|
@@ -663,7 +668,7 @@ function ReportTrace({ spans }) {
|
|
|
663
668
|
{
|
|
664
669
|
className: "min-w-0 flex-1 truncate text-foreground",
|
|
665
670
|
style: { paddingLeft: `${row.depth * 12}px` },
|
|
666
|
-
title: row.statusMessage ? `${row.name}
|
|
671
|
+
title: row.statusMessage ? `${row.name}: ${row.statusMessage}` : row.name,
|
|
667
672
|
children: row.name
|
|
668
673
|
}
|
|
669
674
|
),
|
|
@@ -802,12 +807,12 @@ function useCollapse() {
|
|
|
802
807
|
}
|
|
803
808
|
var STORAGE_KEY = "es-collapsed-ids";
|
|
804
809
|
function readPersisted() {
|
|
805
|
-
if (typeof localStorage === "undefined") return
|
|
810
|
+
if (typeof localStorage === "undefined") return null;
|
|
806
811
|
try {
|
|
807
812
|
const raw = localStorage.getItem(STORAGE_KEY);
|
|
808
|
-
return raw ? new Set(JSON.parse(raw)) :
|
|
813
|
+
return raw ? new Set(JSON.parse(raw)) : null;
|
|
809
814
|
} catch {
|
|
810
|
-
return
|
|
815
|
+
return null;
|
|
811
816
|
}
|
|
812
817
|
}
|
|
813
818
|
function persist(ids) {
|
|
@@ -817,8 +822,10 @@ function persist(ids) {
|
|
|
817
822
|
} catch {
|
|
818
823
|
}
|
|
819
824
|
}
|
|
820
|
-
function useCollapseState() {
|
|
821
|
-
const [collapsed, setCollapsed] = useState(
|
|
825
|
+
function useCollapseState(computeDefault) {
|
|
826
|
+
const [collapsed, setCollapsed] = useState(
|
|
827
|
+
() => readPersisted() ?? computeDefault?.() ?? /* @__PURE__ */ new Set()
|
|
828
|
+
);
|
|
822
829
|
const isCollapsed = useCallback((id) => collapsed.has(id), [collapsed]);
|
|
823
830
|
const toggle = useCallback((id) => {
|
|
824
831
|
setCollapsed((prev) => {
|
|
@@ -848,20 +855,118 @@ function useCollapseState() {
|
|
|
848
855
|
|
|
849
856
|
// src/interactive/scenario-actions.tsx
|
|
850
857
|
import { createContext as createContext4, useContext as useContext5 } from "react";
|
|
858
|
+
|
|
859
|
+
// ../executable-stories-core/dist/utils/scenario-markdown.js
|
|
860
|
+
function cell(value) {
|
|
861
|
+
return value.replaceAll("|", "\\|").replaceAll("\n", " ");
|
|
862
|
+
}
|
|
863
|
+
function stringify(value) {
|
|
864
|
+
if (typeof value === "string") return value;
|
|
865
|
+
try {
|
|
866
|
+
return JSON.stringify(value, null, 2) ?? String(value);
|
|
867
|
+
} catch {
|
|
868
|
+
return String(value);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
function docEntryToMarkdown(entry) {
|
|
872
|
+
const lines = [];
|
|
873
|
+
switch (entry.kind) {
|
|
874
|
+
case "note":
|
|
875
|
+
lines.push(entry.text);
|
|
876
|
+
break;
|
|
877
|
+
case "tag":
|
|
878
|
+
lines.push(entry.names.map((n) => `\`@${n}\``).join(" "));
|
|
879
|
+
break;
|
|
880
|
+
case "kv":
|
|
881
|
+
lines.push(`**${entry.label}:** ${stringify(entry.value)}`);
|
|
882
|
+
break;
|
|
883
|
+
case "code":
|
|
884
|
+
lines.push(`**${entry.label}**`, "", "```" + (entry.lang ?? ""), entry.content, "```");
|
|
885
|
+
break;
|
|
886
|
+
case "table": {
|
|
887
|
+
lines.push(`**${entry.label}**`, "");
|
|
888
|
+
lines.push(`| ${entry.columns.map(cell).join(" | ")} |`);
|
|
889
|
+
lines.push(`| ${entry.columns.map(() => "---").join(" | ")} |`);
|
|
890
|
+
for (const row of entry.rows) lines.push(`| ${row.map(cell).join(" | ")} |`);
|
|
891
|
+
break;
|
|
892
|
+
}
|
|
893
|
+
case "link":
|
|
894
|
+
lines.push(`[${entry.label}](${entry.url})`);
|
|
895
|
+
break;
|
|
896
|
+
case "section":
|
|
897
|
+
lines.push(`### ${entry.title}`, "", entry.markdown);
|
|
898
|
+
break;
|
|
899
|
+
case "mermaid":
|
|
900
|
+
if (entry.title) lines.push(`**${entry.title}**`, "");
|
|
901
|
+
lines.push("```mermaid", entry.code, "```");
|
|
902
|
+
break;
|
|
903
|
+
case "screenshot":
|
|
904
|
+
lines.push(``);
|
|
905
|
+
break;
|
|
906
|
+
case "video":
|
|
907
|
+
lines.push(`Video: ${entry.path}${entry.caption ? ` \u2014 ${entry.caption}` : ""}`);
|
|
908
|
+
break;
|
|
909
|
+
case "html": {
|
|
910
|
+
const htmlTitle = entry.title ?? "Embedded HTML";
|
|
911
|
+
if (entry.content) {
|
|
912
|
+
lines.push(`**${htmlTitle}**`, "", "```html", entry.content, "```");
|
|
913
|
+
} else if (entry.url) {
|
|
914
|
+
lines.push(`[${htmlTitle}](${entry.url})`);
|
|
915
|
+
} else {
|
|
916
|
+
lines.push(`Embedded HTML: ${entry.path ?? "(inline)"}`);
|
|
917
|
+
}
|
|
918
|
+
break;
|
|
919
|
+
}
|
|
920
|
+
case "custom":
|
|
921
|
+
lines.push(`**${entry.type}**`, "", "```json", stringify(entry.data), "```");
|
|
922
|
+
break;
|
|
923
|
+
}
|
|
924
|
+
for (const child of entry.children ?? []) {
|
|
925
|
+
lines.push("", ...docEntryToMarkdown(child));
|
|
926
|
+
}
|
|
927
|
+
return lines;
|
|
928
|
+
}
|
|
929
|
+
function stepLines(step, ordinal, full) {
|
|
930
|
+
const status = step.status === "passed" ? "" : ` \u2014 **${step.status}**`;
|
|
931
|
+
const lines = [`${ordinal}. **${step.keyword}** ${step.text}${status}`];
|
|
932
|
+
if (!full) return lines;
|
|
933
|
+
if (step.errorMessage) {
|
|
934
|
+
lines.push(...step.errorMessage.split("\n").map((l) => ` > ${l}`));
|
|
935
|
+
}
|
|
936
|
+
for (const entry of step.docEntries) {
|
|
937
|
+
lines.push("", ...docEntryToMarkdown(entry).map((l) => l === "" ? l : ` ${l}`));
|
|
938
|
+
}
|
|
939
|
+
return lines;
|
|
940
|
+
}
|
|
941
|
+
function scenarioToMarkdown(scenario, options = {}) {
|
|
942
|
+
const { variant = "full", meta = [] } = options;
|
|
943
|
+
const full = variant === "full";
|
|
944
|
+
const lines = full ? [`# ${scenario.title}`, ""] : [`## ${scenario.title} _(${scenario.status})_`, ""];
|
|
945
|
+
if (full && meta.length > 0) lines.push(...meta);
|
|
946
|
+
if (scenario.steps.length > 0) {
|
|
947
|
+
if (full) lines.push("", "## Steps", "");
|
|
948
|
+
scenario.steps.forEach((step, i) => lines.push(...stepLines(step, i + 1, full)));
|
|
949
|
+
}
|
|
950
|
+
if (scenario.errorMessage) {
|
|
951
|
+
if (full) lines.push("", "## Failure", "");
|
|
952
|
+
else lines.push("");
|
|
953
|
+
lines.push("```", scenario.errorMessage.trim(), "```");
|
|
954
|
+
}
|
|
955
|
+
if (full && scenario.docEntries.length > 0) {
|
|
956
|
+
lines.push("", "## Docs", "");
|
|
957
|
+
for (const entry of scenario.docEntries) lines.push(...docEntryToMarkdown(entry), "");
|
|
958
|
+
}
|
|
959
|
+
return lines.join("\n").replaceAll(/\n{3,}/g, "\n\n").trimEnd() + (full ? "\n" : "");
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
// src/interactive/scenario-actions.tsx
|
|
851
963
|
var ScenarioActionsContext = createContext4(null);
|
|
852
964
|
var ScenarioActionsProvider = ScenarioActionsContext.Provider;
|
|
853
965
|
function useScenarioActions() {
|
|
854
966
|
return useContext5(ScenarioActionsContext);
|
|
855
967
|
}
|
|
856
|
-
function
|
|
857
|
-
|
|
858
|
-
for (const step of scenario.steps) {
|
|
859
|
-
lines.push(`- **${step.keyword}** ${step.text}`);
|
|
860
|
-
}
|
|
861
|
-
if (scenario.errorMessage) {
|
|
862
|
-
lines.push("", "```", scenario.errorMessage.trim(), "```");
|
|
863
|
-
}
|
|
864
|
-
return lines.join("\n");
|
|
968
|
+
function scenarioToMarkdown2(scenario) {
|
|
969
|
+
return scenarioToMarkdown(scenario, { variant: "compact" });
|
|
865
970
|
}
|
|
866
971
|
function scenarioToPrompt(scenario) {
|
|
867
972
|
const lines = [
|
|
@@ -896,7 +1001,7 @@ function Card({ className, ...props }) {
|
|
|
896
1001
|
{
|
|
897
1002
|
"data-slot": "card",
|
|
898
1003
|
className: cn(
|
|
899
|
-
"flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-
|
|
1004
|
+
"flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-xs",
|
|
900
1005
|
className
|
|
901
1006
|
),
|
|
902
1007
|
...props
|
|
@@ -927,52 +1032,89 @@ function CardContent({ className, ...props }) {
|
|
|
927
1032
|
);
|
|
928
1033
|
}
|
|
929
1034
|
|
|
930
|
-
// src/components/
|
|
1035
|
+
// src/components/ui/dropdown-menu.tsx
|
|
1036
|
+
import "react";
|
|
1037
|
+
import { Menu as MenuPrimitive } from "@base-ui/react/menu";
|
|
1038
|
+
import { CheckIcon } from "lucide-react";
|
|
931
1039
|
import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
932
|
-
var
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
};
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
1040
|
+
var itemClasses = "relative flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 [&_svg:not([class*='text-'])]:text-muted-foreground";
|
|
1041
|
+
function DropdownMenu(props) {
|
|
1042
|
+
return /* @__PURE__ */ jsx22(MenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
|
|
1043
|
+
}
|
|
1044
|
+
function DropdownMenuTrigger(props) {
|
|
1045
|
+
return /* @__PURE__ */ jsx22(MenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
|
|
1046
|
+
}
|
|
1047
|
+
function DropdownMenuContent({
|
|
1048
|
+
className,
|
|
1049
|
+
align = "end",
|
|
1050
|
+
sideOffset = 4,
|
|
1051
|
+
...props
|
|
1052
|
+
}) {
|
|
1053
|
+
return /* @__PURE__ */ jsx22(MenuPrimitive.Portal, { children: /* @__PURE__ */ jsx22(
|
|
1054
|
+
MenuPrimitive.Positioner,
|
|
1055
|
+
{
|
|
1056
|
+
"data-slot": "dropdown-menu-positioner",
|
|
1057
|
+
className: "z-50",
|
|
1058
|
+
align,
|
|
1059
|
+
sideOffset,
|
|
1060
|
+
children: /* @__PURE__ */ jsx22(
|
|
1061
|
+
MenuPrimitive.Popup,
|
|
1062
|
+
{
|
|
1063
|
+
"data-slot": "dropdown-menu-content",
|
|
1064
|
+
className: cn(
|
|
1065
|
+
"z-50 min-w-[11rem] origin-[var(--transform-origin)] overflow-hidden rounded-md border border-border bg-popover p-1 font-sans text-sm text-popover-foreground shadow-md transition-[opacity,transform] data-[ending-style]:scale-95 data-[ending-style]:opacity-0 data-[starting-style]:scale-95 data-[starting-style]:opacity-0",
|
|
1066
|
+
className
|
|
1067
|
+
),
|
|
1068
|
+
...props
|
|
1069
|
+
}
|
|
1070
|
+
)
|
|
1071
|
+
}
|
|
1072
|
+
) });
|
|
1073
|
+
}
|
|
1074
|
+
function DropdownMenuItem({
|
|
1075
|
+
className,
|
|
1076
|
+
...props
|
|
1077
|
+
}) {
|
|
1078
|
+
return /* @__PURE__ */ jsx22(
|
|
1079
|
+
MenuPrimitive.Item,
|
|
1080
|
+
{
|
|
1081
|
+
"data-slot": "dropdown-menu-item",
|
|
1082
|
+
className: cn(itemClasses, className),
|
|
1083
|
+
...props
|
|
1084
|
+
}
|
|
1085
|
+
);
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
// src/components/ReportScenario.tsx
|
|
1089
|
+
import { LinkIcon, FileTextIcon, SparklesIcon, MoreHorizontalIcon } from "lucide-react";
|
|
1090
|
+
import { jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1091
|
+
var STATUS_META = {
|
|
1092
|
+
passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
|
|
1093
|
+
failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
|
|
1094
|
+
skipped: { label: "Skipped", glyph: "\u25CB", glyphColor: "text-skip", badgeVariant: "skipped", showPill: true },
|
|
1095
|
+
pending: { label: "Pending", glyph: "\u25CB", glyphColor: "text-pend", badgeVariant: "pending", showPill: true }
|
|
955
1096
|
};
|
|
956
1097
|
function ReportScenario({ scenario, hideTitle = false }) {
|
|
957
1098
|
const titleId = `${scenario.id}-title`;
|
|
958
1099
|
const bodyId = `${scenario.id}-body`;
|
|
959
|
-
const
|
|
1100
|
+
const meta = STATUS_META[scenario.status];
|
|
1101
|
+
const label = scenario.planned ? "Planned" : meta.label;
|
|
960
1102
|
const collapse = useCollapse();
|
|
961
1103
|
const collapsible = collapse !== null && !hideTitle;
|
|
962
1104
|
const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
|
|
963
1105
|
const actions = useScenarioActions();
|
|
964
|
-
return /* @__PURE__ */
|
|
1106
|
+
return /* @__PURE__ */ jsxs15(
|
|
965
1107
|
Card,
|
|
966
1108
|
{
|
|
967
1109
|
id: scenario.id,
|
|
968
1110
|
"data-status": scenario.status,
|
|
969
|
-
...hideTitle ? { "aria-label": `${scenario.title}
|
|
1111
|
+
...hideTitle ? { "aria-label": `${scenario.title}, ${label}` } : { "aria-labelledby": titleId },
|
|
970
1112
|
className: "gap-0 py-0",
|
|
971
1113
|
children: [
|
|
972
|
-
/* @__PURE__ */
|
|
973
|
-
/* @__PURE__ */
|
|
974
|
-
hideTitle ? null : /* @__PURE__ */
|
|
975
|
-
collapsible ? /* @__PURE__ */
|
|
1114
|
+
/* @__PURE__ */ jsxs15(CardHeader, { className: "px-4 py-3", children: [
|
|
1115
|
+
/* @__PURE__ */ jsxs15("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
|
|
1116
|
+
hideTitle ? null : /* @__PURE__ */ jsxs15("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
|
|
1117
|
+
collapsible ? /* @__PURE__ */ jsx23(
|
|
976
1118
|
"button",
|
|
977
1119
|
{
|
|
978
1120
|
type: "button",
|
|
@@ -981,60 +1123,49 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
981
1123
|
"aria-controls": bodyId,
|
|
982
1124
|
"aria-label": `Toggle ${scenario.title}`,
|
|
983
1125
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
984
|
-
children: /* @__PURE__ */
|
|
1126
|
+
children: /* @__PURE__ */ jsx23("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
985
1127
|
}
|
|
986
1128
|
) : null,
|
|
987
|
-
/* @__PURE__ */
|
|
988
|
-
/* @__PURE__ */
|
|
1129
|
+
/* @__PURE__ */ jsx23("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
|
|
1130
|
+
/* @__PURE__ */ jsx23("span", { children: scenario.title })
|
|
989
1131
|
] }),
|
|
990
|
-
/* @__PURE__ */
|
|
991
|
-
/* @__PURE__ */
|
|
992
|
-
scenario.durationMs > 0 ? /* @__PURE__ */
|
|
993
|
-
/* @__PURE__ */
|
|
994
|
-
actions ? /* @__PURE__ */
|
|
995
|
-
/* @__PURE__ */
|
|
996
|
-
|
|
997
|
-
{
|
|
998
|
-
type: "button",
|
|
999
|
-
onClick: () => actions.copyLink(scenario),
|
|
1000
|
-
"aria-label": `Copy link to ${scenario.title}`,
|
|
1001
|
-
title: "Copy permalink",
|
|
1002
|
-
className: "cursor-pointer rounded px-1 py-0.5 font-mono text-[0.625rem] text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
1003
|
-
children: "link"
|
|
1004
|
-
}
|
|
1005
|
-
),
|
|
1006
|
-
/* @__PURE__ */ jsx22(
|
|
1007
|
-
"button",
|
|
1132
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
1133
|
+
/* @__PURE__ */ jsx23(ScenarioRunHistory, { scenarioId: scenario.id }),
|
|
1134
|
+
scenario.durationMs > 0 ? /* @__PURE__ */ jsx23("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
|
|
1135
|
+
meta.showPill ? /* @__PURE__ */ jsx23(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ jsx23("span", { className: "sr-only", children: `Status: ${label}` }),
|
|
1136
|
+
actions ? /* @__PURE__ */ jsxs15(DropdownMenu, { children: [
|
|
1137
|
+
/* @__PURE__ */ jsx23(
|
|
1138
|
+
DropdownMenuTrigger,
|
|
1008
1139
|
{
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
"aria-
|
|
1012
|
-
title: "Copy as Markdown",
|
|
1013
|
-
className: "cursor-pointer rounded px-1 py-0.5 font-mono text-[0.625rem] text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
1014
|
-
children: "md"
|
|
1140
|
+
"aria-label": `Actions for ${scenario.title}`,
|
|
1141
|
+
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
1142
|
+
children: /* @__PURE__ */ jsx23(MoreHorizontalIcon, { "aria-hidden": true })
|
|
1015
1143
|
}
|
|
1016
1144
|
),
|
|
1017
|
-
/* @__PURE__ */
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1145
|
+
/* @__PURE__ */ jsxs15(DropdownMenuContent, { align: "end", children: [
|
|
1146
|
+
/* @__PURE__ */ jsxs15(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
|
|
1147
|
+
/* @__PURE__ */ jsx23(LinkIcon, {}),
|
|
1148
|
+
" Copy link"
|
|
1149
|
+
] }),
|
|
1150
|
+
/* @__PURE__ */ jsxs15(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
|
|
1151
|
+
/* @__PURE__ */ jsx23(FileTextIcon, {}),
|
|
1152
|
+
" Copy as Markdown"
|
|
1153
|
+
] }),
|
|
1154
|
+
/* @__PURE__ */ jsxs15(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
|
|
1155
|
+
/* @__PURE__ */ jsx23(SparklesIcon, {}),
|
|
1156
|
+
" Explain with AI"
|
|
1157
|
+
] })
|
|
1158
|
+
] })
|
|
1028
1159
|
] }) : null
|
|
1029
1160
|
] })
|
|
1030
1161
|
] }),
|
|
1031
|
-
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */
|
|
1032
|
-
scenario.tags.map((t) => /* @__PURE__ */
|
|
1033
|
-
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */
|
|
1162
|
+
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs15("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
|
|
1163
|
+
scenario.tags.map((t) => /* @__PURE__ */ jsx23("li", { children: /* @__PURE__ */ jsx23(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
|
|
1164
|
+
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ jsx23("li", { children: ticket.url ? /* @__PURE__ */ jsx23("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ jsx23(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ jsx23(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
|
|
1034
1165
|
] }) : null
|
|
1035
1166
|
] }),
|
|
1036
|
-
/* @__PURE__ */
|
|
1037
|
-
scenario.errorMessage ? /* @__PURE__ */
|
|
1167
|
+
/* @__PURE__ */ jsxs15(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
|
|
1168
|
+
scenario.errorMessage ? /* @__PURE__ */ jsx23(
|
|
1038
1169
|
"pre",
|
|
1039
1170
|
{
|
|
1040
1171
|
role: "alert",
|
|
@@ -1042,10 +1173,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1042
1173
|
children: scenario.errorMessage
|
|
1043
1174
|
}
|
|
1044
1175
|
) : null,
|
|
1045
|
-
/* @__PURE__ */
|
|
1046
|
-
scenario.docEntries.length > 0 ? /* @__PURE__ */
|
|
1047
|
-
/* @__PURE__ */
|
|
1048
|
-
/* @__PURE__ */
|
|
1176
|
+
/* @__PURE__ */ jsx23(ReportSteps, { scenario }),
|
|
1177
|
+
scenario.docEntries.length > 0 ? /* @__PURE__ */ jsx23("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ jsx23(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
|
|
1178
|
+
/* @__PURE__ */ jsx23(ReportAttachments, { attachments: scenario.attachments }),
|
|
1179
|
+
/* @__PURE__ */ jsx23(ReportTrace, { spans: scenario.otelSpans })
|
|
1049
1180
|
] })
|
|
1050
1181
|
]
|
|
1051
1182
|
}
|
|
@@ -1053,13 +1184,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1053
1184
|
}
|
|
1054
1185
|
|
|
1055
1186
|
// src/components/ReportScenarioList.tsx
|
|
1056
|
-
import { Fragment as Fragment8, jsx as
|
|
1187
|
+
import { Fragment as Fragment8, jsx as jsx24 } from "react/jsx-runtime";
|
|
1057
1188
|
function ReportScenarioList({ feature }) {
|
|
1058
|
-
return /* @__PURE__ */
|
|
1189
|
+
return /* @__PURE__ */ jsx24(Fragment8, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ jsx24(ReportScenario, { scenario }, scenario.id)) });
|
|
1059
1190
|
}
|
|
1060
1191
|
|
|
1061
1192
|
// src/components/ReportFeature.tsx
|
|
1062
|
-
import { jsx as
|
|
1193
|
+
import { Fragment as Fragment9, jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1063
1194
|
function ReportFeature({ feature }) {
|
|
1064
1195
|
const titleId = `${feature.id}-title`;
|
|
1065
1196
|
const bodyId = `${feature.id}-body`;
|
|
@@ -1067,74 +1198,80 @@ function ReportFeature({ feature }) {
|
|
|
1067
1198
|
const skipped = s.skipped + s.pending;
|
|
1068
1199
|
const collapse = useCollapse();
|
|
1069
1200
|
const collapsed = collapse?.isCollapsed(feature.id) ?? false;
|
|
1070
|
-
return
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
"
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1201
|
+
return (
|
|
1202
|
+
// Suite = a section heading + a divider, NOT another bordered card. Drops a
|
|
1203
|
+
// layer of nesting so the scenario cards below read as the primary unit.
|
|
1204
|
+
/* @__PURE__ */ jsxs16(
|
|
1205
|
+
"section",
|
|
1206
|
+
{
|
|
1207
|
+
id: feature.id,
|
|
1208
|
+
"data-slot": "feature",
|
|
1209
|
+
"aria-labelledby": titleId,
|
|
1210
|
+
className: "flex flex-col gap-3",
|
|
1211
|
+
children: [
|
|
1212
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
|
|
1213
|
+
/* @__PURE__ */ jsxs16("div", { className: "min-w-0", children: [
|
|
1214
|
+
/* @__PURE__ */ jsx25("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ jsxs16(
|
|
1215
|
+
"button",
|
|
1216
|
+
{
|
|
1217
|
+
type: "button",
|
|
1218
|
+
onClick: () => collapse.toggle(feature.id),
|
|
1219
|
+
"aria-expanded": !collapsed,
|
|
1220
|
+
"aria-controls": bodyId,
|
|
1221
|
+
className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
|
|
1222
|
+
children: [
|
|
1223
|
+
/* @__PURE__ */ jsx25("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
|
|
1224
|
+
/* @__PURE__ */ jsx25("span", { className: "truncate", children: feature.title })
|
|
1225
|
+
]
|
|
1226
|
+
}
|
|
1227
|
+
) : feature.title }),
|
|
1228
|
+
/* @__PURE__ */ jsx25("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
|
|
1229
|
+
] }),
|
|
1230
|
+
/* @__PURE__ */ jsxs16(
|
|
1231
|
+
"p",
|
|
1082
1232
|
{
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1233
|
+
className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
|
|
1234
|
+
"aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
|
|
1235
|
+
children: [
|
|
1236
|
+
/* @__PURE__ */ jsxs16("span", { children: [
|
|
1237
|
+
s.passed,
|
|
1238
|
+
" passed"
|
|
1239
|
+
] }),
|
|
1240
|
+
/* @__PURE__ */ jsx25("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1241
|
+
/* @__PURE__ */ jsxs16("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
|
|
1242
|
+
s.failed,
|
|
1243
|
+
" failed"
|
|
1244
|
+
] }),
|
|
1245
|
+
skipped > 0 ? /* @__PURE__ */ jsxs16(Fragment9, { children: [
|
|
1246
|
+
/* @__PURE__ */ jsx25("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1247
|
+
/* @__PURE__ */ jsxs16("span", { children: [
|
|
1248
|
+
skipped,
|
|
1249
|
+
" skipped"
|
|
1250
|
+
] })
|
|
1251
|
+
] }) : null
|
|
1252
|
+
]
|
|
1090
1253
|
}
|
|
1091
|
-
)
|
|
1092
|
-
/* @__PURE__ */ jsxs15("div", { className: "min-w-0", children: [
|
|
1093
|
-
/* @__PURE__ */ jsx24("h2", { id: titleId, className: "text-sm font-semibold tracking-tight text-foreground", children: feature.title }),
|
|
1094
|
-
/* @__PURE__ */ jsx24("p", { className: "mt-0.5 truncate font-mono text-xs text-muted-foreground", children: feature.sourceFile })
|
|
1095
|
-
] })
|
|
1254
|
+
)
|
|
1096
1255
|
] }),
|
|
1097
|
-
/* @__PURE__ */
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
className: "flex shrink-0 items-center gap-2.5 font-mono text-xs font-medium",
|
|
1102
|
-
"aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
|
|
1103
|
-
children: [
|
|
1104
|
-
/* @__PURE__ */ jsxs15("span", { "aria-hidden": true, className: "text-pass", children: [
|
|
1105
|
-
"\u2713",
|
|
1106
|
-
s.passed
|
|
1107
|
-
] }),
|
|
1108
|
-
/* @__PURE__ */ jsxs15("span", { "aria-hidden": true, className: "text-fail", children: [
|
|
1109
|
-
"\u2717",
|
|
1110
|
-
s.failed
|
|
1111
|
-
] }),
|
|
1112
|
-
/* @__PURE__ */ jsxs15("span", { "aria-hidden": true, className: "text-skip", children: [
|
|
1113
|
-
"\u25CB",
|
|
1114
|
-
skipped
|
|
1115
|
-
] })
|
|
1116
|
-
]
|
|
1117
|
-
}
|
|
1118
|
-
)
|
|
1119
|
-
] }),
|
|
1120
|
-
/* @__PURE__ */ jsx24("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-2 p-3", children: /* @__PURE__ */ jsx24(ReportScenarioList, { feature }) })
|
|
1121
|
-
]
|
|
1122
|
-
}
|
|
1256
|
+
/* @__PURE__ */ jsx25("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ jsx25(ReportScenarioList, { feature }) })
|
|
1257
|
+
]
|
|
1258
|
+
}
|
|
1259
|
+
)
|
|
1123
1260
|
);
|
|
1124
1261
|
}
|
|
1125
1262
|
|
|
1126
1263
|
// src/components/ReportFeatureList.tsx
|
|
1127
|
-
import {
|
|
1264
|
+
import { jsx as jsx26 } from "react/jsx-runtime";
|
|
1128
1265
|
function ReportFeatureList() {
|
|
1129
1266
|
const report = useReport();
|
|
1130
|
-
return /* @__PURE__ */
|
|
1267
|
+
return /* @__PURE__ */ jsx26("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ jsx26(ReportFeature, { feature }, feature.id)) });
|
|
1131
1268
|
}
|
|
1132
1269
|
|
|
1133
1270
|
// src/components/ui/empty.tsx
|
|
1134
1271
|
import { cva as cva2 } from "class-variance-authority";
|
|
1135
|
-
import { jsx as
|
|
1272
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
1136
1273
|
function Empty({ className, ...props }) {
|
|
1137
|
-
return /* @__PURE__ */
|
|
1274
|
+
return /* @__PURE__ */ jsx27(
|
|
1138
1275
|
"div",
|
|
1139
1276
|
{
|
|
1140
1277
|
"data-slot": "empty",
|
|
@@ -1147,7 +1284,7 @@ function Empty({ className, ...props }) {
|
|
|
1147
1284
|
);
|
|
1148
1285
|
}
|
|
1149
1286
|
function EmptyHeader({ className, ...props }) {
|
|
1150
|
-
return /* @__PURE__ */
|
|
1287
|
+
return /* @__PURE__ */ jsx27(
|
|
1151
1288
|
"div",
|
|
1152
1289
|
{
|
|
1153
1290
|
"data-slot": "empty-header",
|
|
@@ -1174,7 +1311,7 @@ var emptyMediaVariants = cva2(
|
|
|
1174
1311
|
}
|
|
1175
1312
|
);
|
|
1176
1313
|
function EmptyTitle({ className, ...props }) {
|
|
1177
|
-
return /* @__PURE__ */
|
|
1314
|
+
return /* @__PURE__ */ jsx27(
|
|
1178
1315
|
"div",
|
|
1179
1316
|
{
|
|
1180
1317
|
"data-slot": "empty-title",
|
|
@@ -1185,16 +1322,16 @@ function EmptyTitle({ className, ...props }) {
|
|
|
1185
1322
|
}
|
|
1186
1323
|
|
|
1187
1324
|
// src/components/ReportEmpty.tsx
|
|
1188
|
-
import { jsx as
|
|
1325
|
+
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
1189
1326
|
function ReportEmpty({ message }) {
|
|
1190
|
-
return /* @__PURE__ */
|
|
1327
|
+
return /* @__PURE__ */ jsx28(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ jsx28(EmptyHeader, { children: /* @__PURE__ */ jsx28(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
|
|
1191
1328
|
}
|
|
1192
1329
|
|
|
1193
1330
|
// src/components/ReportSummary.tsx
|
|
1194
|
-
import {
|
|
1331
|
+
import { jsx as jsx29, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1195
1332
|
function ReportSummary({ className }) {
|
|
1196
1333
|
const report = useReport();
|
|
1197
|
-
return /* @__PURE__ */
|
|
1334
|
+
return /* @__PURE__ */ jsx29(
|
|
1198
1335
|
ReportSummaryView,
|
|
1199
1336
|
{
|
|
1200
1337
|
summary: report.summary,
|
|
@@ -1203,38 +1340,54 @@ function ReportSummary({ className }) {
|
|
|
1203
1340
|
}
|
|
1204
1341
|
);
|
|
1205
1342
|
}
|
|
1343
|
+
var TONE = {
|
|
1344
|
+
total: { num: "text-foreground", dot: "bg-muted-foreground/50" },
|
|
1345
|
+
passed: { num: "text-pass", dot: "bg-pass" },
|
|
1346
|
+
failed: { num: "text-fail", dot: "bg-fail" },
|
|
1347
|
+
skipped: { num: "text-skip", dot: "bg-skip" },
|
|
1348
|
+
pending: { num: "text-pend", dot: "bg-pend" }
|
|
1349
|
+
};
|
|
1206
1350
|
function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1351
|
+
const cards = [
|
|
1352
|
+
{ status: "total", label: "Total", value: summary.total },
|
|
1353
|
+
{ status: "passed", label: "Passed", value: summary.passed },
|
|
1354
|
+
{ status: "failed", label: "Failed", value: summary.failed },
|
|
1355
|
+
{ status: "skipped", label: "Skipped", value: summary.skipped }
|
|
1356
|
+
];
|
|
1357
|
+
if (summary.pending > 0) {
|
|
1358
|
+
cards.push({ status: "pending", label: "Pending", value: summary.pending });
|
|
1359
|
+
}
|
|
1360
|
+
return /* @__PURE__ */ jsx29(
|
|
1361
|
+
"dl",
|
|
1362
|
+
{
|
|
1363
|
+
className: cn(
|
|
1364
|
+
"grid grid-cols-2 gap-3",
|
|
1365
|
+
// Columns follow the card count so the row is always full — 5 statuses
|
|
1366
|
+
// (pending present) never leave a lone orphan card below a row of four.
|
|
1367
|
+
cards.length === 5 ? "sm:grid-cols-5" : "sm:grid-cols-4",
|
|
1368
|
+
className
|
|
1369
|
+
),
|
|
1370
|
+
"aria-label": ariaLabel,
|
|
1371
|
+
children: cards.map((c) => {
|
|
1372
|
+
const tone = TONE[c.status];
|
|
1373
|
+
return /* @__PURE__ */ jsxs17(
|
|
1374
|
+
"div",
|
|
1375
|
+
{
|
|
1376
|
+
"data-status": c.status,
|
|
1377
|
+
className: "rounded-lg border bg-card px-4 py-3",
|
|
1378
|
+
children: [
|
|
1379
|
+
/* @__PURE__ */ jsxs17("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
|
|
1380
|
+
/* @__PURE__ */ jsx29("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
|
|
1381
|
+
c.label
|
|
1382
|
+
] }),
|
|
1383
|
+
/* @__PURE__ */ jsx29("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
|
|
1384
|
+
]
|
|
1385
|
+
},
|
|
1386
|
+
c.status
|
|
1387
|
+
);
|
|
1388
|
+
})
|
|
1389
|
+
}
|
|
1390
|
+
);
|
|
1238
1391
|
}
|
|
1239
1392
|
|
|
1240
1393
|
// src/lib/provenance.ts
|
|
@@ -1287,7 +1440,7 @@ function prUrl(ci) {
|
|
|
1287
1440
|
}
|
|
1288
1441
|
|
|
1289
1442
|
// src/components/ReportMeta.tsx
|
|
1290
|
-
import { jsx as
|
|
1443
|
+
import { jsx as jsx30, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1291
1444
|
function ReportMeta() {
|
|
1292
1445
|
const report = useReport();
|
|
1293
1446
|
const items = [];
|
|
@@ -1310,13 +1463,13 @@ function ReportMeta() {
|
|
|
1310
1463
|
const short = sha.slice(0, 8);
|
|
1311
1464
|
items.push({
|
|
1312
1465
|
label: "Commit",
|
|
1313
|
-
value: url ? /* @__PURE__ */
|
|
1466
|
+
value: url ? /* @__PURE__ */ jsx30("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
|
|
1314
1467
|
});
|
|
1315
1468
|
}
|
|
1316
1469
|
if (report.ci) {
|
|
1317
1470
|
items.push({
|
|
1318
1471
|
label: "CI",
|
|
1319
|
-
value: report.ci.url ? /* @__PURE__ */
|
|
1472
|
+
value: report.ci.url ? /* @__PURE__ */ jsxs18("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
|
|
1320
1473
|
ciDisplayName(report.ci.name),
|
|
1321
1474
|
report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
|
|
1322
1475
|
] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
|
|
@@ -1327,54 +1480,144 @@ function ReportMeta() {
|
|
|
1327
1480
|
const label = `#${report.ci.prNumber}`;
|
|
1328
1481
|
items.push({
|
|
1329
1482
|
label: "PR",
|
|
1330
|
-
value: url ? /* @__PURE__ */
|
|
1483
|
+
value: url ? /* @__PURE__ */ jsx30("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
|
|
1331
1484
|
});
|
|
1332
1485
|
}
|
|
1333
1486
|
if (items.length === 0) return null;
|
|
1334
|
-
return
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1487
|
+
return (
|
|
1488
|
+
// Run metadata is useful but secondary to "what failed" — tuck it into a
|
|
1489
|
+
// collapsed disclosure so it doesn't push the result down. Native <details>
|
|
1490
|
+
// so it works with no JS (the SSR/no-hydration report still toggles).
|
|
1491
|
+
/* @__PURE__ */ jsxs18("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
|
|
1492
|
+
/* @__PURE__ */ jsxs18("summary", { className: "flex cursor-pointer list-none select-none items-center gap-1.5 px-4 py-2 font-medium text-muted-foreground [&::-webkit-details-marker]:hidden", children: [
|
|
1493
|
+
/* @__PURE__ */ jsx30("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
|
|
1494
|
+
"Run details"
|
|
1495
|
+
] }),
|
|
1496
|
+
/* @__PURE__ */ jsx30("dl", { className: "flex flex-wrap gap-x-5 gap-y-2 border-t border-border px-4 py-3 text-muted-foreground", "aria-label": "Run metadata", children: items.map((item) => /* @__PURE__ */ jsxs18("div", { className: "flex items-baseline gap-1.5", children: [
|
|
1497
|
+
/* @__PURE__ */ jsx30("dt", { className: "font-medium", children: item.label }),
|
|
1498
|
+
/* @__PURE__ */ jsx30("dd", { className: "font-mono text-foreground", children: item.value })
|
|
1499
|
+
] }, item.label)) })
|
|
1500
|
+
] })
|
|
1501
|
+
);
|
|
1338
1502
|
}
|
|
1339
1503
|
|
|
1340
1504
|
// src/components/ReportSchemaError.tsx
|
|
1341
|
-
import { jsx as
|
|
1505
|
+
import { jsx as jsx31, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1342
1506
|
function ReportSchemaError({ error }) {
|
|
1343
|
-
return /* @__PURE__ */
|
|
1344
|
-
/* @__PURE__ */
|
|
1345
|
-
/* @__PURE__ */
|
|
1346
|
-
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */
|
|
1507
|
+
return /* @__PURE__ */ jsxs19("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
|
|
1508
|
+
/* @__PURE__ */ jsx31("p", { children: /* @__PURE__ */ jsx31("strong", { children: "Report could not be displayed." }) }),
|
|
1509
|
+
/* @__PURE__ */ jsx31("p", { children: error.message }),
|
|
1510
|
+
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ jsxs19("p", { children: [
|
|
1347
1511
|
"The report bundle is newer than this version of ",
|
|
1348
|
-
/* @__PURE__ */
|
|
1512
|
+
/* @__PURE__ */ jsx31("code", { children: "executable-stories-react" }),
|
|
1349
1513
|
". Upgrade the package, or regenerate the report with an older formatters CLI."
|
|
1350
1514
|
] }) : null,
|
|
1351
|
-
error.issues && error.issues.length > 0 ? /* @__PURE__ */
|
|
1352
|
-
/* @__PURE__ */
|
|
1515
|
+
error.issues && error.issues.length > 0 ? /* @__PURE__ */ jsxs19("details", { children: [
|
|
1516
|
+
/* @__PURE__ */ jsxs19("summary", { children: [
|
|
1353
1517
|
error.issues.length,
|
|
1354
1518
|
" validation issue",
|
|
1355
1519
|
error.issues.length === 1 ? "" : "s"
|
|
1356
1520
|
] }),
|
|
1357
|
-
/* @__PURE__ */
|
|
1521
|
+
/* @__PURE__ */ jsx31("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
|
|
1358
1522
|
] }) : null
|
|
1359
1523
|
] });
|
|
1360
1524
|
}
|
|
1361
1525
|
|
|
1362
1526
|
// src/components/ReportShell.tsx
|
|
1363
|
-
import { Fragment as
|
|
1364
|
-
function ReportTitleBlock({ title }) {
|
|
1365
|
-
return /* @__PURE__ */ jsxs19(Fragment11, { children: [
|
|
1366
|
-
/* @__PURE__ */ jsx31("h1", { children: title ?? "Story Report" }),
|
|
1367
|
-
/* @__PURE__ */ jsx31(ReportSummary, {}),
|
|
1368
|
-
/* @__PURE__ */ jsx31(ReportMeta, {})
|
|
1369
|
-
] });
|
|
1370
|
-
}
|
|
1527
|
+
import { Fragment as Fragment10, jsx as jsx32, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1371
1528
|
function ReportErrorShell({
|
|
1372
1529
|
error,
|
|
1373
1530
|
className,
|
|
1374
1531
|
title,
|
|
1375
1532
|
dataTheme
|
|
1376
1533
|
}) {
|
|
1377
|
-
return /* @__PURE__ */
|
|
1534
|
+
return /* @__PURE__ */ jsx32("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ jsx32(ReportSchemaError, { error }) });
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
// src/interactive/ReportInteractive.tsx
|
|
1538
|
+
import { Monitor, Moon, Sun } from "lucide-react";
|
|
1539
|
+
|
|
1540
|
+
// src/components/ui/switch.tsx
|
|
1541
|
+
import "react";
|
|
1542
|
+
import { Switch as SwitchPrimitive } from "@base-ui/react/switch";
|
|
1543
|
+
import { jsx as jsx33 } from "react/jsx-runtime";
|
|
1544
|
+
function Switch({
|
|
1545
|
+
className,
|
|
1546
|
+
...props
|
|
1547
|
+
}) {
|
|
1548
|
+
return /* @__PURE__ */ jsx33(
|
|
1549
|
+
SwitchPrimitive.Root,
|
|
1550
|
+
{
|
|
1551
|
+
"data-slot": "switch",
|
|
1552
|
+
className: cn(
|
|
1553
|
+
"peer inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent shadow-xs outline-none transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-[checked]:bg-primary data-[unchecked]:bg-input",
|
|
1554
|
+
className
|
|
1555
|
+
),
|
|
1556
|
+
...props,
|
|
1557
|
+
children: /* @__PURE__ */ jsx33(
|
|
1558
|
+
SwitchPrimitive.Thumb,
|
|
1559
|
+
{
|
|
1560
|
+
"data-slot": "switch-thumb",
|
|
1561
|
+
className: "pointer-events-none block size-4 rounded-full bg-background ring-0 transition-transform data-[checked]:translate-x-[calc(100%-2px)] data-[unchecked]:translate-x-0"
|
|
1562
|
+
}
|
|
1563
|
+
)
|
|
1564
|
+
}
|
|
1565
|
+
);
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
// src/components/ui/toggle-group.tsx
|
|
1569
|
+
import * as React5 from "react";
|
|
1570
|
+
import { ToggleGroup as ToggleGroupPrimitive } from "@base-ui/react/toggle-group";
|
|
1571
|
+
import { Toggle as TogglePrimitive } from "@base-ui/react/toggle";
|
|
1572
|
+
import { cva as cva3 } from "class-variance-authority";
|
|
1573
|
+
import { jsx as jsx34 } from "react/jsx-runtime";
|
|
1574
|
+
var toggleItemVariants = cva3(
|
|
1575
|
+
"inline-flex items-center justify-center gap-1.5 rounded-md font-medium whitespace-nowrap text-muted-foreground transition-[color,background-color,box-shadow] outline-none hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 data-[pressed]:bg-background data-[pressed]:text-foreground data-[pressed]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
1576
|
+
{
|
|
1577
|
+
variants: {
|
|
1578
|
+
size: {
|
|
1579
|
+
default: "h-9 px-3 text-sm",
|
|
1580
|
+
sm: "h-8 px-2.5 text-[0.82rem]"
|
|
1581
|
+
}
|
|
1582
|
+
},
|
|
1583
|
+
defaultVariants: { size: "default" }
|
|
1584
|
+
}
|
|
1585
|
+
);
|
|
1586
|
+
var ToggleGroupContext = React5.createContext({
|
|
1587
|
+
size: "default"
|
|
1588
|
+
});
|
|
1589
|
+
function ToggleGroup({
|
|
1590
|
+
className,
|
|
1591
|
+
size,
|
|
1592
|
+
children,
|
|
1593
|
+
...props
|
|
1594
|
+
}) {
|
|
1595
|
+
return /* @__PURE__ */ jsx34(
|
|
1596
|
+
ToggleGroupPrimitive,
|
|
1597
|
+
{
|
|
1598
|
+
"data-slot": "toggle-group",
|
|
1599
|
+
className: cn("flex w-fit items-center gap-0.5 rounded-lg bg-muted p-0.5", className),
|
|
1600
|
+
...props,
|
|
1601
|
+
children: /* @__PURE__ */ jsx34(ToggleGroupContext.Provider, { value: { size }, children })
|
|
1602
|
+
}
|
|
1603
|
+
);
|
|
1604
|
+
}
|
|
1605
|
+
function ToggleGroupItem({
|
|
1606
|
+
className,
|
|
1607
|
+
children,
|
|
1608
|
+
size,
|
|
1609
|
+
...props
|
|
1610
|
+
}) {
|
|
1611
|
+
const context = React5.useContext(ToggleGroupContext);
|
|
1612
|
+
return /* @__PURE__ */ jsx34(
|
|
1613
|
+
TogglePrimitive,
|
|
1614
|
+
{
|
|
1615
|
+
"data-slot": "toggle-group-item",
|
|
1616
|
+
className: cn(toggleItemVariants({ size: context.size ?? size }), "flex-1 shrink-0", className),
|
|
1617
|
+
...props,
|
|
1618
|
+
children
|
|
1619
|
+
}
|
|
1620
|
+
);
|
|
1378
1621
|
}
|
|
1379
1622
|
|
|
1380
1623
|
// src/interactive/ReportSearch.tsx
|
|
@@ -1382,7 +1625,30 @@ import {
|
|
|
1382
1625
|
forwardRef,
|
|
1383
1626
|
useId
|
|
1384
1627
|
} from "react";
|
|
1385
|
-
import {
|
|
1628
|
+
import { Search } from "lucide-react";
|
|
1629
|
+
|
|
1630
|
+
// src/components/ui/input.tsx
|
|
1631
|
+
import "react";
|
|
1632
|
+
import { jsx as jsx35 } from "react/jsx-runtime";
|
|
1633
|
+
function Input({ className, type, ...props }) {
|
|
1634
|
+
return /* @__PURE__ */ jsx35(
|
|
1635
|
+
"input",
|
|
1636
|
+
{
|
|
1637
|
+
type,
|
|
1638
|
+
"data-slot": "input",
|
|
1639
|
+
className: cn(
|
|
1640
|
+
"h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:bg-input/30",
|
|
1641
|
+
"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
|
|
1642
|
+
"aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
|
|
1643
|
+
className
|
|
1644
|
+
),
|
|
1645
|
+
...props
|
|
1646
|
+
}
|
|
1647
|
+
);
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
// src/interactive/ReportSearch.tsx
|
|
1651
|
+
import { jsx as jsx36, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1386
1652
|
var ReportSearch = forwardRef(
|
|
1387
1653
|
function ReportSearch2(props, ref) {
|
|
1388
1654
|
const {
|
|
@@ -1390,11 +1656,11 @@ var ReportSearch = forwardRef(
|
|
|
1390
1656
|
onChange,
|
|
1391
1657
|
matchedCount,
|
|
1392
1658
|
totalCount,
|
|
1393
|
-
placeholder = "Search scenarios
|
|
1659
|
+
placeholder = "Search scenarios or tags\u2026",
|
|
1394
1660
|
className
|
|
1395
1661
|
} = props;
|
|
1396
1662
|
const inputId = useId();
|
|
1397
|
-
const showCounts = typeof matchedCount === "number" && typeof totalCount === "number";
|
|
1663
|
+
const showCounts = value.trim().length > 0 && typeof matchedCount === "number" && typeof totalCount === "number";
|
|
1398
1664
|
function handleChange(e) {
|
|
1399
1665
|
onChange(e.target.value);
|
|
1400
1666
|
}
|
|
@@ -1404,24 +1670,46 @@ var ReportSearch = forwardRef(
|
|
|
1404
1670
|
e.preventDefault();
|
|
1405
1671
|
}
|
|
1406
1672
|
}
|
|
1407
|
-
return /* @__PURE__ */
|
|
1408
|
-
/* @__PURE__ */
|
|
1409
|
-
/* @__PURE__ */
|
|
1410
|
-
|
|
1673
|
+
return /* @__PURE__ */ jsxs21("div", { className: cn("es-search flex flex-col gap-1", className), children: [
|
|
1674
|
+
/* @__PURE__ */ jsx36("label", { htmlFor: inputId, className: "sr-only", children: "Search" }),
|
|
1675
|
+
/* @__PURE__ */ jsxs21("div", { className: "relative w-full sm:w-72", children: [
|
|
1676
|
+
/* @__PURE__ */ jsx36(
|
|
1677
|
+
Search,
|
|
1678
|
+
{
|
|
1679
|
+
"aria-hidden": true,
|
|
1680
|
+
className: "pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground"
|
|
1681
|
+
}
|
|
1682
|
+
),
|
|
1683
|
+
/* @__PURE__ */ jsx36(
|
|
1684
|
+
Input,
|
|
1685
|
+
{
|
|
1686
|
+
ref,
|
|
1687
|
+
id: inputId,
|
|
1688
|
+
type: "search",
|
|
1689
|
+
value,
|
|
1690
|
+
onChange: handleChange,
|
|
1691
|
+
onKeyDown: handleKeyDown,
|
|
1692
|
+
placeholder,
|
|
1693
|
+
autoComplete: "off",
|
|
1694
|
+
spellCheck: false,
|
|
1695
|
+
"aria-keyshortcuts": "/",
|
|
1696
|
+
className: "pl-8"
|
|
1697
|
+
}
|
|
1698
|
+
)
|
|
1699
|
+
] }),
|
|
1700
|
+
showCounts ? /* @__PURE__ */ jsxs21(
|
|
1701
|
+
"span",
|
|
1411
1702
|
{
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
spellCheck: false,
|
|
1421
|
-
"aria-keyshortcuts": "/"
|
|
1703
|
+
className: "text-xs tabular-nums text-muted-foreground",
|
|
1704
|
+
"aria-live": "polite",
|
|
1705
|
+
children: [
|
|
1706
|
+
matchedCount,
|
|
1707
|
+
" of ",
|
|
1708
|
+
totalCount,
|
|
1709
|
+
" scenarios"
|
|
1710
|
+
]
|
|
1422
1711
|
}
|
|
1423
|
-
)
|
|
1424
|
-
showCounts ? /* @__PURE__ */ jsx32("span", { className: "es-search-counts", "aria-live": "polite", children: value ? `${matchedCount} of ${totalCount}` : `${totalCount} total` }) : null
|
|
1712
|
+
) : null
|
|
1425
1713
|
] });
|
|
1426
1714
|
}
|
|
1427
1715
|
);
|
|
@@ -1450,7 +1738,7 @@ function scrollToScenarioId(scenarioId, options = {}) {
|
|
|
1450
1738
|
}
|
|
1451
1739
|
|
|
1452
1740
|
// src/interactive/ReportFailureBanner.tsx
|
|
1453
|
-
import { jsx as
|
|
1741
|
+
import { jsx as jsx37, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1454
1742
|
function ReportFailureBanner({ failures }) {
|
|
1455
1743
|
const first = failures[0];
|
|
1456
1744
|
const jumpToFirst = useCallback2(() => {
|
|
@@ -1458,7 +1746,7 @@ function ReportFailureBanner({ failures }) {
|
|
|
1458
1746
|
scrollToScenarioId(first.scenarioId);
|
|
1459
1747
|
}, [first]);
|
|
1460
1748
|
if (failures.length === 0) return null;
|
|
1461
|
-
return /* @__PURE__ */
|
|
1749
|
+
return /* @__PURE__ */ jsxs22(
|
|
1462
1750
|
"div",
|
|
1463
1751
|
{
|
|
1464
1752
|
className: "es-failure-banner",
|
|
@@ -1466,20 +1754,20 @@ function ReportFailureBanner({ failures }) {
|
|
|
1466
1754
|
"aria-live": "polite",
|
|
1467
1755
|
"aria-label": "Failure summary",
|
|
1468
1756
|
children: [
|
|
1469
|
-
/* @__PURE__ */
|
|
1470
|
-
/* @__PURE__ */
|
|
1757
|
+
/* @__PURE__ */ jsxs22("span", { className: "es-failure-banner-text", children: [
|
|
1758
|
+
/* @__PURE__ */ jsx37("strong", { children: failures.length }),
|
|
1471
1759
|
" ",
|
|
1472
1760
|
"failure",
|
|
1473
1761
|
failures.length === 1 ? "" : "s"
|
|
1474
1762
|
] }),
|
|
1475
|
-
/* @__PURE__ */
|
|
1763
|
+
/* @__PURE__ */ jsx37(
|
|
1476
1764
|
"button",
|
|
1477
1765
|
{
|
|
1478
1766
|
type: "button",
|
|
1479
1767
|
className: "es-failure-banner-jump",
|
|
1480
1768
|
onClick: jumpToFirst,
|
|
1481
|
-
"aria-label": "
|
|
1482
|
-
children: "
|
|
1769
|
+
"aria-label": "View first failure",
|
|
1770
|
+
children: "View first failure \u2193"
|
|
1483
1771
|
}
|
|
1484
1772
|
)
|
|
1485
1773
|
]
|
|
@@ -1489,7 +1777,7 @@ function ReportFailureBanner({ failures }) {
|
|
|
1489
1777
|
|
|
1490
1778
|
// src/interactive/ReportFreshness.tsx
|
|
1491
1779
|
import { useEffect, useState as useState2 } from "react";
|
|
1492
|
-
import { Fragment as
|
|
1780
|
+
import { Fragment as Fragment11, jsx as jsx38, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1493
1781
|
function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
1494
1782
|
const [now, setNow] = useState2(nowMs);
|
|
1495
1783
|
useEffect(() => {
|
|
@@ -1497,7 +1785,7 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
1497
1785
|
}, [nowMs]);
|
|
1498
1786
|
if (lastRunMs === void 0 || now === void 0) return null;
|
|
1499
1787
|
const age = formatRelativeAge(lastRunMs, now);
|
|
1500
|
-
const runLink = ciUrl ? /* @__PURE__ */
|
|
1788
|
+
const runLink = ciUrl ? /* @__PURE__ */ jsx38(
|
|
1501
1789
|
"a",
|
|
1502
1790
|
{
|
|
1503
1791
|
href: ciUrl,
|
|
@@ -1508,22 +1796,22 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
1508
1796
|
}
|
|
1509
1797
|
) : null;
|
|
1510
1798
|
if (isReportStale(lastRunMs, staleAfterDays, now)) {
|
|
1511
|
-
return /* @__PURE__ */
|
|
1512
|
-
/* @__PURE__ */
|
|
1513
|
-
/* @__PURE__ */
|
|
1799
|
+
return /* @__PURE__ */ jsxs23("div", { className: "es-stale-banner", role: "status", "aria-label": "Report freshness", children: [
|
|
1800
|
+
/* @__PURE__ */ jsxs23("span", { children: [
|
|
1801
|
+
/* @__PURE__ */ jsxs23("strong", { children: [
|
|
1514
1802
|
"Last verified ",
|
|
1515
1803
|
age,
|
|
1516
1804
|
"."
|
|
1517
1805
|
] }),
|
|
1518
|
-
" This report may no longer match the current behavior
|
|
1806
|
+
" This report may no longer match the current behavior. Look for a newer run."
|
|
1519
1807
|
] }),
|
|
1520
1808
|
runLink
|
|
1521
1809
|
] });
|
|
1522
1810
|
}
|
|
1523
|
-
return /* @__PURE__ */
|
|
1811
|
+
return /* @__PURE__ */ jsxs23("p", { className: "es-freshness", "aria-label": "Report freshness", children: [
|
|
1524
1812
|
"Verified ",
|
|
1525
1813
|
age,
|
|
1526
|
-
runLink ? /* @__PURE__ */
|
|
1814
|
+
runLink ? /* @__PURE__ */ jsxs23(Fragment11, { children: [
|
|
1527
1815
|
" \xB7 ",
|
|
1528
1816
|
runLink
|
|
1529
1817
|
] }) : null
|
|
@@ -1531,15 +1819,15 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
1531
1819
|
}
|
|
1532
1820
|
|
|
1533
1821
|
// src/interactive/ReportLastRunDelta.tsx
|
|
1534
|
-
import { Fragment as
|
|
1822
|
+
import { Fragment as Fragment12, jsx as jsx39, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
1535
1823
|
var MAX_LINKS = 5;
|
|
1536
1824
|
function ScenarioLinks({ scenarios, tone }) {
|
|
1537
|
-
return /* @__PURE__ */
|
|
1538
|
-
scenarios.slice(0, MAX_LINKS).map((s, i) => /* @__PURE__ */
|
|
1825
|
+
return /* @__PURE__ */ jsxs24(Fragment12, { children: [
|
|
1826
|
+
scenarios.slice(0, MAX_LINKS).map((s, i) => /* @__PURE__ */ jsxs24("span", { children: [
|
|
1539
1827
|
i > 0 ? ", " : "",
|
|
1540
|
-
/* @__PURE__ */
|
|
1828
|
+
/* @__PURE__ */ jsx39("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
|
|
1541
1829
|
] }, s.id)),
|
|
1542
|
-
scenarios.length > MAX_LINKS ? /* @__PURE__ */
|
|
1830
|
+
scenarios.length > MAX_LINKS ? /* @__PURE__ */ jsxs24("span", { children: [
|
|
1543
1831
|
" and ",
|
|
1544
1832
|
scenarios.length - MAX_LINKS,
|
|
1545
1833
|
" more"
|
|
@@ -1556,23 +1844,23 @@ function ReportLastRunDelta({
|
|
|
1556
1844
|
if (!delta) return null;
|
|
1557
1845
|
const { newlyFailing, newlyPassing, added } = delta;
|
|
1558
1846
|
if (newlyFailing.length === 0 && newlyPassing.length === 0 && added.length === 0) {
|
|
1559
|
-
return /* @__PURE__ */
|
|
1847
|
+
return /* @__PURE__ */ jsx39("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: "Since last run: no behavior changes." });
|
|
1560
1848
|
}
|
|
1561
|
-
return /* @__PURE__ */
|
|
1562
|
-
/* @__PURE__ */
|
|
1563
|
-
newlyFailing.length > 0 ? /* @__PURE__ */
|
|
1849
|
+
return /* @__PURE__ */ jsxs24("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: [
|
|
1850
|
+
/* @__PURE__ */ jsx39("span", { className: "font-medium text-foreground", children: "Since last run:" }),
|
|
1851
|
+
newlyFailing.length > 0 ? /* @__PURE__ */ jsxs24("span", { className: "ml-2 text-fail", children: [
|
|
1564
1852
|
newlyFailing.length,
|
|
1565
1853
|
" newly failing (",
|
|
1566
|
-
/* @__PURE__ */
|
|
1854
|
+
/* @__PURE__ */ jsx39(ScenarioLinks, { scenarios: newlyFailing, tone: "text-fail" }),
|
|
1567
1855
|
")"
|
|
1568
1856
|
] }) : null,
|
|
1569
|
-
newlyPassing.length > 0 ? /* @__PURE__ */
|
|
1857
|
+
newlyPassing.length > 0 ? /* @__PURE__ */ jsxs24("span", { className: "ml-2 text-pass", children: [
|
|
1570
1858
|
newlyPassing.length,
|
|
1571
1859
|
" fixed (",
|
|
1572
|
-
/* @__PURE__ */
|
|
1860
|
+
/* @__PURE__ */ jsx39(ScenarioLinks, { scenarios: newlyPassing, tone: "text-pass" }),
|
|
1573
1861
|
")"
|
|
1574
1862
|
] }) : null,
|
|
1575
|
-
added.length > 0 ? /* @__PURE__ */
|
|
1863
|
+
added.length > 0 ? /* @__PURE__ */ jsxs24("span", { className: "ml-2", children: [
|
|
1576
1864
|
added.length,
|
|
1577
1865
|
" new"
|
|
1578
1866
|
] }) : null
|
|
@@ -1581,14 +1869,78 @@ function ReportLastRunDelta({
|
|
|
1581
1869
|
|
|
1582
1870
|
// src/interactive/ReportShortcutsHelp.tsx
|
|
1583
1871
|
import { useEffect as useEffect2, useRef } from "react";
|
|
1584
|
-
|
|
1872
|
+
|
|
1873
|
+
// src/components/ui/button.tsx
|
|
1874
|
+
import "react";
|
|
1875
|
+
import { cva as cva4 } from "class-variance-authority";
|
|
1876
|
+
import { useRender as useRender2 } from "@base-ui/react/use-render";
|
|
1877
|
+
var buttonVariants = cva4(
|
|
1878
|
+
"inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,background-color,border-color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
1879
|
+
{
|
|
1880
|
+
variants: {
|
|
1881
|
+
variant: {
|
|
1882
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
1883
|
+
destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
|
|
1884
|
+
outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
|
|
1885
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
1886
|
+
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
|
1887
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
1888
|
+
},
|
|
1889
|
+
size: {
|
|
1890
|
+
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
1891
|
+
xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
|
|
1892
|
+
sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
|
|
1893
|
+
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
1894
|
+
icon: "size-9",
|
|
1895
|
+
"icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
|
|
1896
|
+
"icon-sm": "size-8",
|
|
1897
|
+
"icon-lg": "size-10"
|
|
1898
|
+
}
|
|
1899
|
+
},
|
|
1900
|
+
defaultVariants: {
|
|
1901
|
+
variant: "default",
|
|
1902
|
+
size: "default"
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
);
|
|
1906
|
+
function Button({
|
|
1907
|
+
className,
|
|
1908
|
+
variant = "default",
|
|
1909
|
+
size = "default",
|
|
1910
|
+
render,
|
|
1911
|
+
...props
|
|
1912
|
+
}) {
|
|
1913
|
+
return useRender2({
|
|
1914
|
+
defaultTagName: "button",
|
|
1915
|
+
render,
|
|
1916
|
+
props: {
|
|
1917
|
+
"data-slot": "button",
|
|
1918
|
+
"data-variant": variant,
|
|
1919
|
+
"data-size": size,
|
|
1920
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
1921
|
+
...props
|
|
1922
|
+
}
|
|
1923
|
+
});
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
// src/interactive/ReportShortcutsHelp.tsx
|
|
1927
|
+
import { jsx as jsx40, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
1585
1928
|
var SHORTCUTS = [
|
|
1586
1929
|
{ keys: "/", description: "Focus search" },
|
|
1587
1930
|
{ keys: "f", description: "Jump to next failure" },
|
|
1588
|
-
{ keys: "Shift
|
|
1589
|
-
{ keys: "
|
|
1590
|
-
{ keys: "
|
|
1931
|
+
{ keys: "Shift F", description: "Jump to previous failure" },
|
|
1932
|
+
{ keys: "e", description: "Expand all" },
|
|
1933
|
+
{ keys: "c", description: "Collapse all" },
|
|
1934
|
+
{ keys: "?", description: "Toggle this help" },
|
|
1935
|
+
{ keys: "Esc", description: "Clear search / close" }
|
|
1591
1936
|
];
|
|
1937
|
+
function Keys({ keys }) {
|
|
1938
|
+
const parts = keys.split(" ");
|
|
1939
|
+
return /* @__PURE__ */ jsx40("span", { className: "inline-flex items-center gap-1", children: parts.map((k, i) => /* @__PURE__ */ jsxs25("span", { className: "inline-flex items-center gap-1", children: [
|
|
1940
|
+
i > 0 ? /* @__PURE__ */ jsx40("span", { className: "text-xs text-muted-foreground", children: "+" }) : null,
|
|
1941
|
+
/* @__PURE__ */ jsx40("kbd", { className: "inline-flex h-6 min-w-6 items-center justify-center rounded border border-border bg-muted px-1.5 font-mono text-xs font-medium text-muted-foreground", children: k })
|
|
1942
|
+
] }, k)) });
|
|
1943
|
+
}
|
|
1592
1944
|
function ReportShortcutsHelp({ open, onClose }) {
|
|
1593
1945
|
const dialogRef = useRef(null);
|
|
1594
1946
|
useEffect2(() => {
|
|
@@ -1597,20 +1949,20 @@ function ReportShortcutsHelp({ open, onClose }) {
|
|
|
1597
1949
|
if (open && !dialog.open) dialog.showModal();
|
|
1598
1950
|
else if (!open && dialog.open) dialog.close();
|
|
1599
1951
|
}, [open]);
|
|
1600
|
-
return /* @__PURE__ */
|
|
1952
|
+
return /* @__PURE__ */ jsxs25(
|
|
1601
1953
|
"dialog",
|
|
1602
1954
|
{
|
|
1603
1955
|
ref: dialogRef,
|
|
1604
|
-
className: "es-shortcuts-help",
|
|
1956
|
+
className: "es-shortcuts-help m-auto w-[min(90vw,28rem)] rounded-lg border border-border bg-card p-6 text-card-foreground shadow-lg [overscroll-behavior:contain] backdrop:bg-black/40",
|
|
1605
1957
|
"aria-label": "Keyboard shortcuts",
|
|
1606
1958
|
onClose,
|
|
1607
1959
|
children: [
|
|
1608
|
-
/* @__PURE__ */
|
|
1609
|
-
/* @__PURE__ */
|
|
1610
|
-
/* @__PURE__ */
|
|
1611
|
-
/* @__PURE__ */
|
|
1960
|
+
/* @__PURE__ */ jsx40("h2", { className: "text-base font-semibold", children: "Keyboard shortcuts" }),
|
|
1961
|
+
/* @__PURE__ */ jsx40("dl", { className: "mt-4 grid grid-cols-[auto_1fr] items-center gap-x-4 gap-y-2.5", children: SHORTCUTS.map((s) => /* @__PURE__ */ jsxs25("div", { className: "col-span-2 grid grid-cols-subgrid items-center", children: [
|
|
1962
|
+
/* @__PURE__ */ jsx40("dt", { className: "justify-self-start", children: /* @__PURE__ */ jsx40(Keys, { keys: s.keys }) }),
|
|
1963
|
+
/* @__PURE__ */ jsx40("dd", { className: "text-sm text-muted-foreground", children: s.description })
|
|
1612
1964
|
] }, s.keys)) }),
|
|
1613
|
-
/* @__PURE__ */
|
|
1965
|
+
/* @__PURE__ */ jsx40("form", { method: "dialog", className: "mt-6", children: /* @__PURE__ */ jsx40(Button, { type: "submit", variant: "outline", size: "sm", children: "Close" }) })
|
|
1614
1966
|
]
|
|
1615
1967
|
}
|
|
1616
1968
|
);
|
|
@@ -1782,8 +2134,37 @@ function listFailures(report) {
|
|
|
1782
2134
|
return out;
|
|
1783
2135
|
}
|
|
1784
2136
|
|
|
2137
|
+
// src/interactive/triage-default.ts
|
|
2138
|
+
function needsAttention(status) {
|
|
2139
|
+
return status === "failed";
|
|
2140
|
+
}
|
|
2141
|
+
function defaultCollapsedIds(report) {
|
|
2142
|
+
const collapsed = /* @__PURE__ */ new Set();
|
|
2143
|
+
if (report.summary.failed === 0) return collapsed;
|
|
2144
|
+
for (const feature of report.features) {
|
|
2145
|
+
const featureHasFailure = feature.scenarios.some((s) => needsAttention(s.status));
|
|
2146
|
+
if (!featureHasFailure) collapsed.add(feature.id);
|
|
2147
|
+
for (const scenario of feature.scenarios) {
|
|
2148
|
+
if (!needsAttention(scenario.status)) collapsed.add(scenario.id);
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
return collapsed;
|
|
2152
|
+
}
|
|
2153
|
+
function failuresFirst(report) {
|
|
2154
|
+
if (report.summary.failed === 0) return report;
|
|
2155
|
+
const withFailures = [];
|
|
2156
|
+
const rest = [];
|
|
2157
|
+
for (const feature of report.features) {
|
|
2158
|
+
(feature.scenarios.some((s) => needsAttention(s.status)) ? withFailures : rest).push(feature);
|
|
2159
|
+
}
|
|
2160
|
+
if (withFailures.length === 0) return report;
|
|
2161
|
+
return { ...report, features: [...withFailures, ...rest] };
|
|
2162
|
+
}
|
|
2163
|
+
|
|
1785
2164
|
// src/interactive/ReportFilters.tsx
|
|
1786
|
-
import {
|
|
2165
|
+
import { useState as useState3 } from "react";
|
|
2166
|
+
import { jsx as jsx41, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2167
|
+
var TAG_LIMIT = 12;
|
|
1787
2168
|
function ReportFilters({
|
|
1788
2169
|
statuses,
|
|
1789
2170
|
status,
|
|
@@ -1792,11 +2173,14 @@ function ReportFilters({
|
|
|
1792
2173
|
activeTags,
|
|
1793
2174
|
onToggleTag
|
|
1794
2175
|
}) {
|
|
2176
|
+
const [showAllTags, setShowAllTags] = useState3(false);
|
|
1795
2177
|
if (statuses.length === 0 && tags.length === 0) return null;
|
|
1796
|
-
|
|
1797
|
-
|
|
2178
|
+
const tagsCollapsed = tags.length > TAG_LIMIT && !showAllTags;
|
|
2179
|
+
const visibleTags = tagsCollapsed ? tags.slice(0, TAG_LIMIT) : tags;
|
|
2180
|
+
return /* @__PURE__ */ jsxs26("div", { className: "flex flex-col gap-2", children: [
|
|
2181
|
+
statuses.length > 0 ? /* @__PURE__ */ jsx41("div", { role: "group", "aria-label": "Filter by status", className: "flex flex-wrap gap-1", children: statuses.map((opt) => {
|
|
1798
2182
|
const active = status === opt.key;
|
|
1799
|
-
return /* @__PURE__ */
|
|
2183
|
+
return /* @__PURE__ */ jsxs26(
|
|
1800
2184
|
"button",
|
|
1801
2185
|
{
|
|
1802
2186
|
type: "button",
|
|
@@ -1808,40 +2192,61 @@ function ReportFilters({
|
|
|
1808
2192
|
),
|
|
1809
2193
|
children: [
|
|
1810
2194
|
opt.label,
|
|
1811
|
-
/* @__PURE__ */
|
|
2195
|
+
/* @__PURE__ */ jsx41("span", { className: "ml-1 font-mono opacity-70", children: opt.count })
|
|
1812
2196
|
]
|
|
1813
2197
|
},
|
|
1814
2198
|
opt.key
|
|
1815
2199
|
);
|
|
1816
2200
|
}) }) : null,
|
|
1817
|
-
tags.length > 0 ? /* @__PURE__ */
|
|
1818
|
-
|
|
1819
|
-
|
|
2201
|
+
tags.length > 0 ? /* @__PURE__ */ jsxs26("ul", { "aria-label": "Filter by tag", className: "flex flex-wrap items-center gap-1.5", children: [
|
|
2202
|
+
visibleTags.map((tag) => {
|
|
2203
|
+
const active = activeTags.includes(tag);
|
|
2204
|
+
return /* @__PURE__ */ jsx41("li", { children: /* @__PURE__ */ jsx41(
|
|
2205
|
+
"button",
|
|
2206
|
+
{
|
|
2207
|
+
type: "button",
|
|
2208
|
+
"aria-pressed": active,
|
|
2209
|
+
onClick: () => onToggleTag(tag),
|
|
2210
|
+
className: "cursor-pointer",
|
|
2211
|
+
children: /* @__PURE__ */ jsx41(
|
|
2212
|
+
Badge,
|
|
2213
|
+
{
|
|
2214
|
+
variant: "tag",
|
|
2215
|
+
className: cn(
|
|
2216
|
+
active && "border-primary bg-primary text-primary-foreground"
|
|
2217
|
+
),
|
|
2218
|
+
children: tag
|
|
2219
|
+
}
|
|
2220
|
+
)
|
|
2221
|
+
}
|
|
2222
|
+
) }, tag);
|
|
2223
|
+
}),
|
|
2224
|
+
tags.length > TAG_LIMIT ? /* @__PURE__ */ jsx41("li", { children: /* @__PURE__ */ jsx41(
|
|
1820
2225
|
"button",
|
|
1821
2226
|
{
|
|
1822
2227
|
type: "button",
|
|
1823
|
-
"aria-
|
|
1824
|
-
onClick: () =>
|
|
1825
|
-
className: "cursor-pointer",
|
|
1826
|
-
children:
|
|
2228
|
+
"aria-expanded": showAllTags,
|
|
2229
|
+
onClick: () => setShowAllTags((v) => !v),
|
|
2230
|
+
className: "cursor-pointer rounded-full px-2 py-0.5 text-xs font-medium text-muted-foreground hover:text-foreground",
|
|
2231
|
+
children: tagsCollapsed ? `+${tags.length - TAG_LIMIT} more` : "Show fewer"
|
|
1827
2232
|
}
|
|
1828
|
-
) }
|
|
1829
|
-
|
|
2233
|
+
) }) : null
|
|
2234
|
+
] }) : null
|
|
1830
2235
|
] });
|
|
1831
2236
|
}
|
|
1832
2237
|
|
|
1833
2238
|
// src/interactive/ReportToc.tsx
|
|
1834
|
-
import { useEffect as useEffect5, useMemo as useMemo2, useState as
|
|
1835
|
-
import { jsx as
|
|
2239
|
+
import { useEffect as useEffect5, useMemo as useMemo2, useState as useState4 } from "react";
|
|
2240
|
+
import { jsx as jsx42, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
1836
2241
|
var DOT = {
|
|
1837
|
-
passed: "
|
|
1838
|
-
failed: "
|
|
1839
|
-
skipped: "
|
|
1840
|
-
pending: "
|
|
2242
|
+
passed: "bg-pass",
|
|
2243
|
+
failed: "bg-fail",
|
|
2244
|
+
skipped: "bg-skip",
|
|
2245
|
+
pending: "bg-pend"
|
|
1841
2246
|
};
|
|
1842
|
-
function
|
|
2247
|
+
function TocContent({ onNavigate }) {
|
|
1843
2248
|
const report = useReport();
|
|
1844
|
-
const [activeId, setActiveId] =
|
|
2249
|
+
const [activeId, setActiveId] = useState4(null);
|
|
1845
2250
|
const scenarioIds = useMemo2(
|
|
1846
2251
|
() => report.features.flatMap((f) => f.scenarios.map((s) => s.id)),
|
|
1847
2252
|
[report]
|
|
@@ -1861,91 +2266,166 @@ function ReportToc() {
|
|
|
1861
2266
|
return () => observer.disconnect();
|
|
1862
2267
|
}, [scenarioIds]);
|
|
1863
2268
|
if (report.features.length === 0) return null;
|
|
1864
|
-
return /* @__PURE__ */
|
|
2269
|
+
return /* @__PURE__ */ jsx42("ul", { className: "flex list-none flex-col gap-4 pl-0", children: report.features.map((feature) => /* @__PURE__ */ jsxs27("li", { children: [
|
|
2270
|
+
/* @__PURE__ */ jsx42("p", { className: "mb-1.5 font-semibold leading-snug text-foreground", children: feature.title }),
|
|
2271
|
+
/* @__PURE__ */ jsx42("ul", { className: "flex list-none flex-col gap-0.5 pl-0", children: feature.scenarios.map((scenario) => {
|
|
2272
|
+
const active = activeId === scenario.id;
|
|
2273
|
+
return /* @__PURE__ */ jsx42("li", { children: /* @__PURE__ */ jsxs27(
|
|
2274
|
+
"a",
|
|
2275
|
+
{
|
|
2276
|
+
href: `#${scenario.id}`,
|
|
2277
|
+
onClick: (e) => {
|
|
2278
|
+
e.preventDefault();
|
|
2279
|
+
scrollToScenarioId(scenario.id, { updateHash: true });
|
|
2280
|
+
onNavigate?.();
|
|
2281
|
+
},
|
|
2282
|
+
"aria-current": active ? "true" : void 0,
|
|
2283
|
+
className: cn(
|
|
2284
|
+
"flex items-start gap-2 border-l-2 py-1 pl-2.5 leading-snug hover:text-foreground",
|
|
2285
|
+
active ? "border-primary font-medium text-foreground" : "border-border text-muted-foreground"
|
|
2286
|
+
),
|
|
2287
|
+
children: [
|
|
2288
|
+
/* @__PURE__ */ jsx42(
|
|
2289
|
+
"span",
|
|
2290
|
+
{
|
|
2291
|
+
"aria-hidden": true,
|
|
2292
|
+
className: cn("mt-1 size-1.5 shrink-0 rounded-full", DOT[scenario.status])
|
|
2293
|
+
}
|
|
2294
|
+
),
|
|
2295
|
+
/* @__PURE__ */ jsx42("span", { className: "break-words", children: scenario.title })
|
|
2296
|
+
]
|
|
2297
|
+
}
|
|
2298
|
+
) }, scenario.id);
|
|
2299
|
+
}) })
|
|
2300
|
+
] }, feature.id)) });
|
|
2301
|
+
}
|
|
2302
|
+
function ReportToc() {
|
|
2303
|
+
const report = useReport();
|
|
2304
|
+
if (report.features.length === 0) return null;
|
|
2305
|
+
return /* @__PURE__ */ jsxs27(
|
|
1865
2306
|
"nav",
|
|
1866
2307
|
{
|
|
1867
2308
|
"aria-label": "Table of contents",
|
|
1868
|
-
className: "sticky top-4 hidden h-fit w-
|
|
1869
|
-
children:
|
|
1870
|
-
/* @__PURE__ */
|
|
1871
|
-
/* @__PURE__ */
|
|
1872
|
-
|
|
1873
|
-
return /* @__PURE__ */ jsx38("li", { children: /* @__PURE__ */ jsxs26(
|
|
1874
|
-
"a",
|
|
1875
|
-
{
|
|
1876
|
-
href: `#${scenario.id}`,
|
|
1877
|
-
onClick: (e) => {
|
|
1878
|
-
e.preventDefault();
|
|
1879
|
-
scrollToScenarioId(scenario.id, { updateHash: true });
|
|
1880
|
-
},
|
|
1881
|
-
"aria-current": active ? "true" : void 0,
|
|
1882
|
-
className: cn(
|
|
1883
|
-
"flex items-center gap-1.5 truncate border-l-2 py-0.5 pl-2 hover:text-foreground",
|
|
1884
|
-
active ? "border-primary font-medium text-foreground" : "border-border text-muted-foreground"
|
|
1885
|
-
),
|
|
1886
|
-
children: [
|
|
1887
|
-
/* @__PURE__ */ jsx38("span", { "aria-hidden": true, className: cn("shrink-0", DOT[scenario.status]), children: "\u2022" }),
|
|
1888
|
-
/* @__PURE__ */ jsx38("span", { className: "truncate", children: scenario.title })
|
|
1889
|
-
]
|
|
1890
|
-
}
|
|
1891
|
-
) }, scenario.id);
|
|
1892
|
-
}) })
|
|
1893
|
-
] }, feature.id)) })
|
|
2309
|
+
className: "sticky top-4 hidden h-fit w-64 shrink-0 self-start text-xs lg:block",
|
|
2310
|
+
children: [
|
|
2311
|
+
/* @__PURE__ */ jsx42("p", { className: "mb-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Contents" }),
|
|
2312
|
+
/* @__PURE__ */ jsx42(TocContent, {})
|
|
2313
|
+
]
|
|
1894
2314
|
}
|
|
1895
2315
|
);
|
|
1896
2316
|
}
|
|
1897
2317
|
|
|
2318
|
+
// src/interactive/ReportTocDrawer.tsx
|
|
2319
|
+
import { useState as useState5 } from "react";
|
|
2320
|
+
import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
|
|
2321
|
+
import { ListIcon, XIcon } from "lucide-react";
|
|
2322
|
+
import { jsx as jsx43, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
2323
|
+
function ReportTocDrawer() {
|
|
2324
|
+
const report = useReport();
|
|
2325
|
+
const [open, setOpen] = useState5(false);
|
|
2326
|
+
if (report.features.length === 0) return null;
|
|
2327
|
+
return /* @__PURE__ */ jsxs28(DialogPrimitive.Root, { open, onOpenChange: setOpen, children: [
|
|
2328
|
+
/* @__PURE__ */ jsxs28(DialogPrimitive.Trigger, { className: "flex cursor-pointer items-center gap-1 rounded-md border border-border px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground lg:hidden [&_svg]:size-3.5", children: [
|
|
2329
|
+
/* @__PURE__ */ jsx43(ListIcon, { "aria-hidden": true }),
|
|
2330
|
+
" Contents"
|
|
2331
|
+
] }),
|
|
2332
|
+
/* @__PURE__ */ jsxs28(DialogPrimitive.Portal, { children: [
|
|
2333
|
+
/* @__PURE__ */ jsx43(DialogPrimitive.Backdrop, { className: "fixed inset-0 z-50 bg-black/50 transition-opacity duration-200 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0" }),
|
|
2334
|
+
/* @__PURE__ */ jsxs28(DialogPrimitive.Popup, { className: "fixed inset-y-0 left-0 z-50 flex w-72 max-w-[80vw] flex-col gap-3 overflow-y-auto border-r border-border bg-background p-4 font-sans text-xs shadow-lg outline-none transition-transform duration-200 data-[ending-style]:-translate-x-full data-[starting-style]:-translate-x-full", children: [
|
|
2335
|
+
/* @__PURE__ */ jsxs28("div", { className: "flex items-center justify-between", children: [
|
|
2336
|
+
/* @__PURE__ */ jsx43(DialogPrimitive.Title, { className: "text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Contents" }),
|
|
2337
|
+
/* @__PURE__ */ jsx43(
|
|
2338
|
+
DialogPrimitive.Close,
|
|
2339
|
+
{
|
|
2340
|
+
"aria-label": "Close contents",
|
|
2341
|
+
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
2342
|
+
children: /* @__PURE__ */ jsx43(XIcon, { "aria-hidden": true })
|
|
2343
|
+
}
|
|
2344
|
+
)
|
|
2345
|
+
] }),
|
|
2346
|
+
/* @__PURE__ */ jsx43(TocContent, { onNavigate: () => setOpen(false) })
|
|
2347
|
+
] })
|
|
2348
|
+
] })
|
|
2349
|
+
] });
|
|
2350
|
+
}
|
|
2351
|
+
|
|
1898
2352
|
// src/interactive/use-theme.ts
|
|
1899
|
-
import { useCallback as useCallback3, useEffect as useEffect6, useState as
|
|
2353
|
+
import { useCallback as useCallback3, useEffect as useEffect6, useState as useState6 } from "react";
|
|
1900
2354
|
var KEY = "es-theme";
|
|
1901
|
-
function
|
|
2355
|
+
function systemDark() {
|
|
2356
|
+
return typeof matchMedia !== "undefined" && matchMedia("(prefers-color-scheme: dark)").matches;
|
|
2357
|
+
}
|
|
2358
|
+
function resolve(pref) {
|
|
2359
|
+
return pref === "system" ? systemDark() ? "dark" : "light" : pref;
|
|
2360
|
+
}
|
|
2361
|
+
function applyTheme(pref) {
|
|
1902
2362
|
if (typeof document !== "undefined") {
|
|
1903
|
-
document.documentElement.setAttribute("data-theme",
|
|
2363
|
+
document.documentElement.setAttribute("data-theme", resolve(pref));
|
|
1904
2364
|
}
|
|
1905
2365
|
}
|
|
1906
|
-
function
|
|
2366
|
+
function initialPref() {
|
|
1907
2367
|
if (typeof localStorage !== "undefined") {
|
|
1908
2368
|
const stored = localStorage.getItem(KEY);
|
|
1909
|
-
if (stored === "light" || stored === "dark") return stored;
|
|
1910
|
-
}
|
|
1911
|
-
if (typeof document !== "undefined" && document.documentElement.getAttribute("data-theme") === "dark") {
|
|
1912
|
-
return "dark";
|
|
1913
|
-
}
|
|
1914
|
-
if (typeof matchMedia !== "undefined" && matchMedia("(prefers-color-scheme: dark)").matches) {
|
|
1915
|
-
return "dark";
|
|
2369
|
+
if (stored === "light" || stored === "dark" || stored === "system") return stored;
|
|
1916
2370
|
}
|
|
1917
|
-
return "
|
|
2371
|
+
return "system";
|
|
1918
2372
|
}
|
|
1919
2373
|
function useTheme() {
|
|
1920
|
-
const [
|
|
2374
|
+
const [pref, setPrefState] = useState6("system");
|
|
1921
2375
|
useEffect6(() => {
|
|
1922
|
-
const
|
|
1923
|
-
|
|
1924
|
-
applyTheme(
|
|
2376
|
+
const p = initialPref();
|
|
2377
|
+
setPrefState(p);
|
|
2378
|
+
applyTheme(p);
|
|
1925
2379
|
}, []);
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
2380
|
+
useEffect6(() => {
|
|
2381
|
+
if (typeof matchMedia === "undefined") return;
|
|
2382
|
+
const mq = matchMedia("(prefers-color-scheme: dark)");
|
|
2383
|
+
const onChange = () => {
|
|
2384
|
+
if (pref === "system") applyTheme("system");
|
|
2385
|
+
};
|
|
2386
|
+
mq.addEventListener("change", onChange);
|
|
2387
|
+
return () => mq.removeEventListener("change", onChange);
|
|
2388
|
+
}, [pref]);
|
|
2389
|
+
const setPref = useCallback3((p) => {
|
|
2390
|
+
setPrefState(p);
|
|
2391
|
+
applyTheme(p);
|
|
2392
|
+
try {
|
|
2393
|
+
localStorage.setItem(KEY, p);
|
|
2394
|
+
} catch {
|
|
2395
|
+
}
|
|
1936
2396
|
}, []);
|
|
1937
|
-
return {
|
|
2397
|
+
return { pref, setPref };
|
|
1938
2398
|
}
|
|
1939
2399
|
|
|
1940
2400
|
// src/interactive/ReportInteractive.tsx
|
|
1941
|
-
import { jsx as
|
|
2401
|
+
import { Fragment as Fragment13, jsx as jsx44, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
1942
2402
|
function ReportInteractive(props) {
|
|
1943
2403
|
const { report, className, title, dataTheme } = props;
|
|
1944
2404
|
const result = unwrapReport(report);
|
|
1945
2405
|
if (!result.ok) {
|
|
1946
|
-
return /* @__PURE__ */
|
|
2406
|
+
return /* @__PURE__ */ jsx44(ReportErrorShell, { error: result.error, className, title, dataTheme });
|
|
1947
2407
|
}
|
|
1948
|
-
return /* @__PURE__ */
|
|
2408
|
+
return /* @__PURE__ */ jsx44(ReportInteractiveView, { ...props, report: result.data });
|
|
2409
|
+
}
|
|
2410
|
+
var THEME_OPTIONS = [
|
|
2411
|
+
{ value: "light", label: "Light", Icon: Sun },
|
|
2412
|
+
{ value: "system", label: "System", Icon: Monitor },
|
|
2413
|
+
{ value: "dark", label: "Dark", Icon: Moon }
|
|
2414
|
+
];
|
|
2415
|
+
function ThemeSegment({ pref, onPref }) {
|
|
2416
|
+
return /* @__PURE__ */ jsx44(
|
|
2417
|
+
ToggleGroup,
|
|
2418
|
+
{
|
|
2419
|
+
size: "sm",
|
|
2420
|
+
value: [pref],
|
|
2421
|
+
onValueChange: (v) => {
|
|
2422
|
+
const next = v[0];
|
|
2423
|
+
if (next) onPref(next);
|
|
2424
|
+
},
|
|
2425
|
+
"aria-label": "Color theme",
|
|
2426
|
+
children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */ jsx44(ToggleGroupItem, { value, "aria-label": label, title: label, className: "px-2", children: /* @__PURE__ */ jsx44(Icon, {}) }, value))
|
|
2427
|
+
}
|
|
2428
|
+
);
|
|
1949
2429
|
}
|
|
1950
2430
|
function ReportInteractiveView({
|
|
1951
2431
|
report,
|
|
@@ -1955,20 +2435,25 @@ function ReportInteractiveView({
|
|
|
1955
2435
|
title,
|
|
1956
2436
|
dataTheme,
|
|
1957
2437
|
hideHeader = false,
|
|
2438
|
+
hideToc = false,
|
|
1958
2439
|
staleAfterDays = 7,
|
|
1959
2440
|
scenarioHistory
|
|
1960
2441
|
}) {
|
|
1961
|
-
const [query, setQuery] =
|
|
1962
|
-
const [statusFilter, setStatusFilter] =
|
|
1963
|
-
const [activeTags, setActiveTags] =
|
|
1964
|
-
const [detail, setDetail] =
|
|
1965
|
-
const [helpOpen, setHelpOpen] =
|
|
1966
|
-
const {
|
|
2442
|
+
const [query, setQuery] = useState7("");
|
|
2443
|
+
const [statusFilter, setStatusFilter] = useState7("all");
|
|
2444
|
+
const [activeTags, setActiveTags] = useState7([]);
|
|
2445
|
+
const [detail, setDetail] = useState7("full");
|
|
2446
|
+
const [helpOpen, setHelpOpen] = useState7(false);
|
|
2447
|
+
const { pref: themePref, setPref: setThemePref } = useTheme();
|
|
1967
2448
|
const searchRef = useRef3(null);
|
|
2449
|
+
const expandId = useId2();
|
|
2450
|
+
const docsId = useId2();
|
|
1968
2451
|
const deferredQuery = useDeferredValue(query);
|
|
1969
2452
|
const failures = useMemo3(() => listFailures(report), [report]);
|
|
1970
2453
|
const filtered = useMemo3(
|
|
1971
|
-
|
|
2454
|
+
// Features carrying failures float to the top so the first thing on screen
|
|
2455
|
+
// is the thing that needs attention; an all-green run keeps source order.
|
|
2456
|
+
() => failuresFirst(filterReport(report, { query: deferredQuery, status: statusFilter, tags: activeTags })),
|
|
1972
2457
|
[report, deferredQuery, statusFilter, activeTags]
|
|
1973
2458
|
);
|
|
1974
2459
|
const isFiltering = query !== deferredQuery;
|
|
@@ -1988,7 +2473,7 @@ function ReportInteractiveView({
|
|
|
1988
2473
|
(tag) => setActiveTags((prev) => prev.includes(tag) ? prev.filter((t) => t !== tag) : [...prev, tag]),
|
|
1989
2474
|
[]
|
|
1990
2475
|
);
|
|
1991
|
-
const [toast, setToast] =
|
|
2476
|
+
const [toast, setToast] = useState7(null);
|
|
1992
2477
|
const toastTimer = useRef3(null);
|
|
1993
2478
|
const showToast = useCallback4((msg) => {
|
|
1994
2479
|
setToast(msg);
|
|
@@ -2006,18 +2491,27 @@ function ReportInteractiveView({
|
|
|
2006
2491
|
const scenarioActions = useMemo3(
|
|
2007
2492
|
() => ({
|
|
2008
2493
|
copyLink: (s) => copy(scenarioPermalink(s), "Link copied"),
|
|
2009
|
-
copyMarkdown: (s) => copy(
|
|
2494
|
+
copyMarkdown: (s) => copy(scenarioToMarkdown2(s), "Markdown copied"),
|
|
2010
2495
|
copyPrompt: (s) => copy(scenarioToPrompt(s), "Prompt copied")
|
|
2011
2496
|
}),
|
|
2012
2497
|
[copy]
|
|
2013
2498
|
);
|
|
2014
2499
|
const failureIndexRef = useRef3(0);
|
|
2015
|
-
const collapse = useCollapseState();
|
|
2016
2500
|
const allCollapsibleIds = useMemo3(
|
|
2017
2501
|
() => report.features.flatMap((f) => [f.id, ...f.scenarios.map((s) => s.id)]),
|
|
2018
2502
|
[report]
|
|
2019
2503
|
);
|
|
2504
|
+
const collapse = useCollapseState(useCallback4(() => defaultCollapsedIds(report), [report]));
|
|
2020
2505
|
const collapseAll = useCallback4(() => collapse.collapseAll(allCollapsibleIds), [collapse, allCollapsibleIds]);
|
|
2506
|
+
const [expandedAll, setExpandedAll] = useState7(() => report.summary.failed === 0);
|
|
2507
|
+
const setExpanded = useCallback4(
|
|
2508
|
+
(expanded) => {
|
|
2509
|
+
if (expanded) collapse.expandAll();
|
|
2510
|
+
else collapseAll();
|
|
2511
|
+
setExpandedAll(expanded);
|
|
2512
|
+
},
|
|
2513
|
+
[collapse, collapseAll]
|
|
2514
|
+
);
|
|
2021
2515
|
const focusSearch = useCallback4(() => {
|
|
2022
2516
|
searchRef.current?.focus();
|
|
2023
2517
|
}, []);
|
|
@@ -2043,20 +2537,21 @@ function ReportInteractiveView({
|
|
|
2043
2537
|
onPrevFailure: () => stepFailure(-1),
|
|
2044
2538
|
onToggleHelp: toggleHelp,
|
|
2045
2539
|
onEscape: escape,
|
|
2046
|
-
onExpandAll:
|
|
2047
|
-
onCollapseAll:
|
|
2540
|
+
onExpandAll: () => setExpanded(true),
|
|
2541
|
+
onCollapseAll: () => setExpanded(false)
|
|
2048
2542
|
});
|
|
2049
2543
|
useDeepLinkScroll();
|
|
2050
2544
|
const hasContent = filtered.features.length > 0;
|
|
2051
2545
|
const totalScenarios = report.summary.total;
|
|
2052
2546
|
const matchedScenarios = filtered.summary.total;
|
|
2053
|
-
|
|
2547
|
+
const showToc = !hideToc && totalScenarios > 3;
|
|
2548
|
+
return /* @__PURE__ */ jsx44(CollapseProvider, { value: collapse.api, children: /* @__PURE__ */ jsx44(ScenarioActionsProvider, { value: scenarioActions, children: /* @__PURE__ */ jsx44(ScenarioHistoryProvider, { value: scenarioHistory ?? null, children: /* @__PURE__ */ jsx44(
|
|
2054
2549
|
ReportRoot,
|
|
2055
2550
|
{
|
|
2056
2551
|
report: filtered,
|
|
2057
2552
|
customRenderers,
|
|
2058
2553
|
renderers,
|
|
2059
|
-
children: /* @__PURE__ */
|
|
2554
|
+
children: /* @__PURE__ */ jsxs29(
|
|
2060
2555
|
"main",
|
|
2061
2556
|
{
|
|
2062
2557
|
className: cn("es-report", "es-report-interactive", className),
|
|
@@ -2065,9 +2560,38 @@ function ReportInteractiveView({
|
|
|
2065
2560
|
"data-theme": dataTheme,
|
|
2066
2561
|
"data-detail-level": detail,
|
|
2067
2562
|
children: [
|
|
2068
|
-
/* @__PURE__ */
|
|
2069
|
-
|
|
2070
|
-
|
|
2563
|
+
/* @__PURE__ */ jsxs29("header", { className: "es-report-header", children: [
|
|
2564
|
+
/* @__PURE__ */ jsxs29(
|
|
2565
|
+
"div",
|
|
2566
|
+
{
|
|
2567
|
+
"data-es-navbar": true,
|
|
2568
|
+
className: cn(
|
|
2569
|
+
"flex flex-wrap items-center gap-4",
|
|
2570
|
+
hideHeader ? "justify-end" : "justify-between"
|
|
2571
|
+
),
|
|
2572
|
+
children: [
|
|
2573
|
+
hideHeader ? null : /* @__PURE__ */ jsx44("h1", { className: "min-w-0", children: title ?? "Story Report" }),
|
|
2574
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex items-center gap-2", children: [
|
|
2575
|
+
/* @__PURE__ */ jsx44(
|
|
2576
|
+
ReportSearch,
|
|
2577
|
+
{
|
|
2578
|
+
ref: searchRef,
|
|
2579
|
+
value: query,
|
|
2580
|
+
onChange: setQuery,
|
|
2581
|
+
matchedCount: matchedScenarios,
|
|
2582
|
+
totalCount: totalScenarios
|
|
2583
|
+
}
|
|
2584
|
+
),
|
|
2585
|
+
/* @__PURE__ */ jsx44(ThemeSegment, { pref: themePref, onPref: setThemePref })
|
|
2586
|
+
] })
|
|
2587
|
+
]
|
|
2588
|
+
}
|
|
2589
|
+
),
|
|
2590
|
+
hideHeader ? null : /* @__PURE__ */ jsxs29(Fragment13, { children: [
|
|
2591
|
+
/* @__PURE__ */ jsx44(ReportSummary, {}),
|
|
2592
|
+
/* @__PURE__ */ jsx44(ReportMeta, {})
|
|
2593
|
+
] }),
|
|
2594
|
+
/* @__PURE__ */ jsx44(
|
|
2071
2595
|
ReportFreshness,
|
|
2072
2596
|
{
|
|
2073
2597
|
lastRunMs: reportLastRunMs(report),
|
|
@@ -2075,62 +2599,8 @@ function ReportInteractiveView({
|
|
|
2075
2599
|
staleAfterDays
|
|
2076
2600
|
}
|
|
2077
2601
|
),
|
|
2078
|
-
/* @__PURE__ */
|
|
2079
|
-
/* @__PURE__ */
|
|
2080
|
-
/* @__PURE__ */ jsx39(
|
|
2081
|
-
ReportSearch,
|
|
2082
|
-
{
|
|
2083
|
-
ref: searchRef,
|
|
2084
|
-
value: query,
|
|
2085
|
-
onChange: setQuery,
|
|
2086
|
-
matchedCount: matchedScenarios,
|
|
2087
|
-
totalCount: totalScenarios
|
|
2088
|
-
}
|
|
2089
|
-
),
|
|
2090
|
-
/* @__PURE__ */ jsxs27("div", { className: "flex shrink-0 gap-1", children: [
|
|
2091
|
-
/* @__PURE__ */ jsx39(
|
|
2092
|
-
"button",
|
|
2093
|
-
{
|
|
2094
|
-
type: "button",
|
|
2095
|
-
onClick: collapse.expandAll,
|
|
2096
|
-
"aria-keyshortcuts": "e",
|
|
2097
|
-
className: "cursor-pointer rounded-md border border-border px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
2098
|
-
children: "Expand all"
|
|
2099
|
-
}
|
|
2100
|
-
),
|
|
2101
|
-
/* @__PURE__ */ jsx39(
|
|
2102
|
-
"button",
|
|
2103
|
-
{
|
|
2104
|
-
type: "button",
|
|
2105
|
-
onClick: collapseAll,
|
|
2106
|
-
"aria-keyshortcuts": "c",
|
|
2107
|
-
className: "cursor-pointer rounded-md border border-border px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
2108
|
-
children: "Collapse all"
|
|
2109
|
-
}
|
|
2110
|
-
),
|
|
2111
|
-
/* @__PURE__ */ jsx39(
|
|
2112
|
-
"button",
|
|
2113
|
-
{
|
|
2114
|
-
type: "button",
|
|
2115
|
-
onClick: () => setDetail((d) => d === "full" ? "minimal" : "full"),
|
|
2116
|
-
"aria-pressed": detail === "minimal",
|
|
2117
|
-
className: "cursor-pointer rounded-md border border-border px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
2118
|
-
children: detail === "full" ? "Hide docs" : "Show docs"
|
|
2119
|
-
}
|
|
2120
|
-
),
|
|
2121
|
-
/* @__PURE__ */ jsx39(
|
|
2122
|
-
"button",
|
|
2123
|
-
{
|
|
2124
|
-
type: "button",
|
|
2125
|
-
onClick: toggleTheme,
|
|
2126
|
-
"aria-label": `Switch to ${theme === "dark" ? "light" : "dark"} theme`,
|
|
2127
|
-
className: "cursor-pointer rounded-md border border-border px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
2128
|
-
children: theme === "dark" ? "\u2600 Light" : "\u263E Dark"
|
|
2129
|
-
}
|
|
2130
|
-
)
|
|
2131
|
-
] })
|
|
2132
|
-
] }),
|
|
2133
|
-
/* @__PURE__ */ jsx39(
|
|
2602
|
+
/* @__PURE__ */ jsx44(ReportLastRunDelta, { history: scenarioHistory, report }),
|
|
2603
|
+
/* @__PURE__ */ jsx44(
|
|
2134
2604
|
ReportFilters,
|
|
2135
2605
|
{
|
|
2136
2606
|
statuses: statusOptions,
|
|
@@ -2140,26 +2610,44 @@ function ReportInteractiveView({
|
|
|
2140
2610
|
activeTags,
|
|
2141
2611
|
onToggleTag: toggleTag
|
|
2142
2612
|
}
|
|
2143
|
-
)
|
|
2613
|
+
),
|
|
2614
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-2 border-t border-border/60 pt-3", children: [
|
|
2615
|
+
showToc ? /* @__PURE__ */ jsx44(ReportTocDrawer, {}) : null,
|
|
2616
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex items-center gap-2", children: [
|
|
2617
|
+
/* @__PURE__ */ jsx44(Switch, { id: expandId, checked: expandedAll, onCheckedChange: setExpanded }),
|
|
2618
|
+
/* @__PURE__ */ jsx44("label", { htmlFor: expandId, className: "cursor-pointer text-sm text-muted-foreground select-none", children: "Expand all" })
|
|
2619
|
+
] }),
|
|
2620
|
+
/* @__PURE__ */ jsxs29("div", { className: "flex items-center gap-2", children: [
|
|
2621
|
+
/* @__PURE__ */ jsx44(
|
|
2622
|
+
Switch,
|
|
2623
|
+
{
|
|
2624
|
+
id: docsId,
|
|
2625
|
+
checked: detail === "full",
|
|
2626
|
+
onCheckedChange: (checked) => setDetail(checked ? "full" : "minimal")
|
|
2627
|
+
}
|
|
2628
|
+
),
|
|
2629
|
+
/* @__PURE__ */ jsx44("label", { htmlFor: docsId, className: "cursor-pointer text-sm text-muted-foreground select-none", children: "Show documentation" })
|
|
2630
|
+
] })
|
|
2631
|
+
] })
|
|
2144
2632
|
] }),
|
|
2145
|
-
/* @__PURE__ */
|
|
2146
|
-
hasContent ? /* @__PURE__ */
|
|
2147
|
-
/* @__PURE__ */
|
|
2148
|
-
/* @__PURE__ */
|
|
2149
|
-
] }) : /* @__PURE__ */
|
|
2150
|
-
/* @__PURE__ */
|
|
2633
|
+
/* @__PURE__ */ jsx44(ReportFailureBanner, { failures }),
|
|
2634
|
+
hasContent ? showToc ? /* @__PURE__ */ jsxs29("div", { className: "flex gap-6", children: [
|
|
2635
|
+
/* @__PURE__ */ jsx44(ReportToc, {}),
|
|
2636
|
+
/* @__PURE__ */ jsx44("div", { className: "flex min-w-0 flex-1 flex-col gap-4", children: /* @__PURE__ */ jsx44(ReportFeatureList, {}) })
|
|
2637
|
+
] }) : /* @__PURE__ */ jsx44("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ jsx44(ReportFeatureList, {}) }) : /* @__PURE__ */ jsx44(ReportEmpty, { message: query ? "No scenarios match the search." : void 0 }),
|
|
2638
|
+
/* @__PURE__ */ jsx44(
|
|
2151
2639
|
"button",
|
|
2152
2640
|
{
|
|
2153
2641
|
type: "button",
|
|
2154
|
-
className: "es-shortcuts-trigger",
|
|
2642
|
+
className: "es-shortcuts-trigger fixed right-4 bottom-4 z-40 flex size-9 items-center justify-center rounded-full border border-border bg-card text-muted-foreground shadow-sm transition-colors hover:bg-muted hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/50",
|
|
2155
2643
|
"aria-label": "Keyboard shortcuts",
|
|
2156
|
-
"aria-keyshortcuts": "
|
|
2644
|
+
"aria-keyshortcuts": "?",
|
|
2157
2645
|
onClick: toggleHelp,
|
|
2158
2646
|
children: "?"
|
|
2159
2647
|
}
|
|
2160
2648
|
),
|
|
2161
|
-
/* @__PURE__ */
|
|
2162
|
-
toast ? /* @__PURE__ */
|
|
2649
|
+
/* @__PURE__ */ jsx44(ReportShortcutsHelp, { open: helpOpen, onClose: () => setHelpOpen(false) }),
|
|
2650
|
+
toast ? /* @__PURE__ */ jsx44(
|
|
2163
2651
|
"div",
|
|
2164
2652
|
{
|
|
2165
2653
|
role: "status",
|
|
@@ -2179,11 +2667,11 @@ function ReportInteractiveView({
|
|
|
2179
2667
|
import { useMemo as useMemo4 } from "react";
|
|
2180
2668
|
|
|
2181
2669
|
// src/interactive/island-renderers.tsx
|
|
2182
|
-
import { createElement, useEffect as useEffect8, useState as
|
|
2670
|
+
import { createElement, useEffect as useEffect8, useState as useState9 } from "react";
|
|
2183
2671
|
|
|
2184
2672
|
// src/components/doc/MermaidView.tsx
|
|
2185
|
-
import { useEffect as useEffect7, useRef as useRef4, useState as
|
|
2186
|
-
import { jsx as
|
|
2673
|
+
import { useEffect as useEffect7, useRef as useRef4, useState as useState8 } from "react";
|
|
2674
|
+
import { jsx as jsx45, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
2187
2675
|
function prefersDark(el) {
|
|
2188
2676
|
const themed = el?.closest("[data-theme]");
|
|
2189
2677
|
if (themed?.dataset.theme === "dark") return true;
|
|
@@ -2192,7 +2680,7 @@ function prefersDark(el) {
|
|
|
2192
2680
|
}
|
|
2193
2681
|
function MermaidView({ entry, load }) {
|
|
2194
2682
|
const ref = useRef4(null);
|
|
2195
|
-
const [svg, setSvg] =
|
|
2683
|
+
const [svg, setSvg] = useState8(null);
|
|
2196
2684
|
useEffect7(() => {
|
|
2197
2685
|
let cancelled = false;
|
|
2198
2686
|
const draw = async () => {
|
|
@@ -2220,9 +2708,9 @@ function MermaidView({ entry, load }) {
|
|
|
2220
2708
|
};
|
|
2221
2709
|
}, [entry.code, load]);
|
|
2222
2710
|
if (svg) {
|
|
2223
|
-
return /* @__PURE__ */
|
|
2224
|
-
entry.title ? /* @__PURE__ */
|
|
2225
|
-
/* @__PURE__ */
|
|
2711
|
+
return /* @__PURE__ */ jsxs30("figure", { ref, className: "my-3", children: [
|
|
2712
|
+
entry.title ? /* @__PURE__ */ jsx45("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
|
|
2713
|
+
/* @__PURE__ */ jsx45(
|
|
2226
2714
|
"div",
|
|
2227
2715
|
{
|
|
2228
2716
|
role: "img",
|
|
@@ -2233,11 +2721,11 @@ function MermaidView({ entry, load }) {
|
|
|
2233
2721
|
)
|
|
2234
2722
|
] });
|
|
2235
2723
|
}
|
|
2236
|
-
return /* @__PURE__ */
|
|
2724
|
+
return /* @__PURE__ */ jsx45(MermaidSource, { entry, ref });
|
|
2237
2725
|
}
|
|
2238
2726
|
|
|
2239
2727
|
// src/interactive/island-renderers.tsx
|
|
2240
|
-
import { jsx as
|
|
2728
|
+
import { jsx as jsx46 } from "react/jsx-runtime";
|
|
2241
2729
|
var HLJS_ESM = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/highlight.min.js";
|
|
2242
2730
|
var MERMAID_ESM = "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
|
|
2243
2731
|
function cachedCdnModule(url) {
|
|
@@ -2254,7 +2742,7 @@ function cachedCdnModule(url) {
|
|
|
2254
2742
|
var loadMermaidFromCdn = cachedCdnModule(MERMAID_ESM);
|
|
2255
2743
|
var loadHljs = cachedCdnModule(HLJS_ESM);
|
|
2256
2744
|
function CdnHighlightedCode({ entry }) {
|
|
2257
|
-
const [html, setHtml] =
|
|
2745
|
+
const [html, setHtml] = useState9(null);
|
|
2258
2746
|
useEffect8(() => {
|
|
2259
2747
|
let cancelled = false;
|
|
2260
2748
|
void (async () => {
|
|
@@ -2271,13 +2759,13 @@ function CdnHighlightedCode({ entry }) {
|
|
|
2271
2759
|
cancelled = true;
|
|
2272
2760
|
};
|
|
2273
2761
|
}, [entry.content, entry.lang]);
|
|
2274
|
-
return /* @__PURE__ */
|
|
2762
|
+
return /* @__PURE__ */ jsx46(CodeFigure, { label: entry.label, children: html !== null ? /* @__PURE__ */ jsx46(
|
|
2275
2763
|
"code",
|
|
2276
2764
|
{
|
|
2277
2765
|
className: cn("hljs font-mono text-xs", entry.lang && `language-${entry.lang}`),
|
|
2278
2766
|
dangerouslySetInnerHTML: { __html: html }
|
|
2279
2767
|
}
|
|
2280
|
-
) : /* @__PURE__ */
|
|
2768
|
+
) : /* @__PURE__ */ jsx46("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
|
|
2281
2769
|
}
|
|
2282
2770
|
function buildIslandRenderers(opts) {
|
|
2283
2771
|
const renderers = {};
|
|
@@ -2291,12 +2779,13 @@ function buildIslandRenderers(opts) {
|
|
|
2291
2779
|
}
|
|
2292
2780
|
|
|
2293
2781
|
// src/interactive/ReportInteractiveIsland.tsx
|
|
2294
|
-
import { jsx as
|
|
2782
|
+
import { jsx as jsx47 } from "react/jsx-runtime";
|
|
2295
2783
|
function ReportInteractiveIsland({
|
|
2296
2784
|
report,
|
|
2297
2785
|
title,
|
|
2298
2786
|
className,
|
|
2299
2787
|
hideHeader,
|
|
2788
|
+
hideToc,
|
|
2300
2789
|
syntaxHighlighting = true,
|
|
2301
2790
|
mermaid = true
|
|
2302
2791
|
}) {
|
|
@@ -2304,13 +2793,14 @@ function ReportInteractiveIsland({
|
|
|
2304
2793
|
() => buildIslandRenderers({ syntaxHighlighting, mermaid }),
|
|
2305
2794
|
[syntaxHighlighting, mermaid]
|
|
2306
2795
|
);
|
|
2307
|
-
return /* @__PURE__ */
|
|
2796
|
+
return /* @__PURE__ */ jsx47(
|
|
2308
2797
|
ReportInteractive,
|
|
2309
2798
|
{
|
|
2310
2799
|
report,
|
|
2311
2800
|
title,
|
|
2312
2801
|
className,
|
|
2313
2802
|
hideHeader,
|
|
2803
|
+
hideToc,
|
|
2314
2804
|
renderers
|
|
2315
2805
|
}
|
|
2316
2806
|
);
|