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.cjs
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
3
4
|
var __defProp = Object.defineProperty;
|
|
4
5
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
9
|
var __export = (target, all) => {
|
|
8
10
|
for (var name in all)
|
|
@@ -16,6 +18,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
18
|
}
|
|
17
19
|
return to;
|
|
18
20
|
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
19
29
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
30
|
|
|
21
31
|
// src/interactive/index.ts
|
|
@@ -37,7 +47,7 @@ __export(interactive_exports, {
|
|
|
37
47
|
module.exports = __toCommonJS(interactive_exports);
|
|
38
48
|
|
|
39
49
|
// src/interactive/ReportInteractive.tsx
|
|
40
|
-
var
|
|
50
|
+
var import_react18 = require("react");
|
|
41
51
|
|
|
42
52
|
// src/result.ts
|
|
43
53
|
var ok = (data) => ({ ok: true, data });
|
|
@@ -136,11 +146,15 @@ var badgeVariants = (0, import_class_variance_authority.cva)(
|
|
|
136
146
|
outline: "border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
|
|
137
147
|
ghost: "[a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
|
|
138
148
|
link: "text-primary underline-offset-4 [a&]:hover:underline",
|
|
139
|
-
|
|
149
|
+
// Pass/skip/pending are the quiet states: outline + coloured text, no
|
|
150
|
+
// fill, so a green report reads calm. Only `failed` keeps a tinted
|
|
151
|
+
// fill, making it the single loud badge on the page, so red pops the
|
|
152
|
+
// instant something breaks. Colour-as-accent, matching the KPI cards.
|
|
153
|
+
passed: "border-pass-border text-pass font-mono uppercase",
|
|
140
154
|
failed: "border-fail-border bg-fail-bg text-fail font-mono uppercase",
|
|
141
|
-
skipped: "border-skip-border
|
|
142
|
-
pending: "border-pend-border
|
|
143
|
-
tag: "border-
|
|
155
|
+
skipped: "border-skip-border text-skip font-mono uppercase",
|
|
156
|
+
pending: "border-pend-border text-pend font-mono uppercase",
|
|
157
|
+
tag: "border-border text-muted-foreground font-mono font-medium [a&]:hover:bg-muted"
|
|
144
158
|
}
|
|
145
159
|
},
|
|
146
160
|
defaultVariants: {
|
|
@@ -227,7 +241,7 @@ function DocTable({ entry }) {
|
|
|
227
241
|
entry.label ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.label }) : null,
|
|
228
242
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("table", { className: "w-full border-collapse text-sm", children: [
|
|
229
243
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("tr", { className: "bg-muted/50", children: entry.columns.map((c) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: c }, c)) }) }),
|
|
230
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("tbody", { children: entry.rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("tr", { children: row.map((
|
|
244
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("tbody", { children: entry.rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("tr", { children: row.map((cell2, j) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("td", { className: "border-b border-border px-3 py-2 text-foreground", children: cell2 }, j)) }, i)) })
|
|
231
245
|
] }) })
|
|
232
246
|
] });
|
|
233
247
|
}
|
|
@@ -693,7 +707,7 @@ function ReportTrace({ spans }) {
|
|
|
693
707
|
{
|
|
694
708
|
className: "min-w-0 flex-1 truncate text-foreground",
|
|
695
709
|
style: { paddingLeft: `${row.depth * 12}px` },
|
|
696
|
-
title: row.statusMessage ? `${row.name}
|
|
710
|
+
title: row.statusMessage ? `${row.name}: ${row.statusMessage}` : row.name,
|
|
697
711
|
children: row.name
|
|
698
712
|
}
|
|
699
713
|
),
|
|
@@ -832,12 +846,12 @@ function useCollapse() {
|
|
|
832
846
|
}
|
|
833
847
|
var STORAGE_KEY = "es-collapsed-ids";
|
|
834
848
|
function readPersisted() {
|
|
835
|
-
if (typeof localStorage === "undefined") return
|
|
849
|
+
if (typeof localStorage === "undefined") return null;
|
|
836
850
|
try {
|
|
837
851
|
const raw = localStorage.getItem(STORAGE_KEY);
|
|
838
|
-
return raw ? new Set(JSON.parse(raw)) :
|
|
852
|
+
return raw ? new Set(JSON.parse(raw)) : null;
|
|
839
853
|
} catch {
|
|
840
|
-
return
|
|
854
|
+
return null;
|
|
841
855
|
}
|
|
842
856
|
}
|
|
843
857
|
function persist(ids) {
|
|
@@ -847,8 +861,10 @@ function persist(ids) {
|
|
|
847
861
|
} catch {
|
|
848
862
|
}
|
|
849
863
|
}
|
|
850
|
-
function useCollapseState() {
|
|
851
|
-
const [collapsed, setCollapsed] = (0, import_react6.useState)(
|
|
864
|
+
function useCollapseState(computeDefault) {
|
|
865
|
+
const [collapsed, setCollapsed] = (0, import_react6.useState)(
|
|
866
|
+
() => readPersisted() ?? computeDefault?.() ?? /* @__PURE__ */ new Set()
|
|
867
|
+
);
|
|
852
868
|
const isCollapsed = (0, import_react6.useCallback)((id) => collapsed.has(id), [collapsed]);
|
|
853
869
|
const toggle = (0, import_react6.useCallback)((id) => {
|
|
854
870
|
setCollapsed((prev) => {
|
|
@@ -878,20 +894,118 @@ function useCollapseState() {
|
|
|
878
894
|
|
|
879
895
|
// src/interactive/scenario-actions.tsx
|
|
880
896
|
var import_react7 = require("react");
|
|
897
|
+
|
|
898
|
+
// ../executable-stories-core/dist/utils/scenario-markdown.js
|
|
899
|
+
function cell(value) {
|
|
900
|
+
return value.replaceAll("|", "\\|").replaceAll("\n", " ");
|
|
901
|
+
}
|
|
902
|
+
function stringify(value) {
|
|
903
|
+
if (typeof value === "string") return value;
|
|
904
|
+
try {
|
|
905
|
+
return JSON.stringify(value, null, 2) ?? String(value);
|
|
906
|
+
} catch {
|
|
907
|
+
return String(value);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
function docEntryToMarkdown(entry) {
|
|
911
|
+
const lines = [];
|
|
912
|
+
switch (entry.kind) {
|
|
913
|
+
case "note":
|
|
914
|
+
lines.push(entry.text);
|
|
915
|
+
break;
|
|
916
|
+
case "tag":
|
|
917
|
+
lines.push(entry.names.map((n) => `\`@${n}\``).join(" "));
|
|
918
|
+
break;
|
|
919
|
+
case "kv":
|
|
920
|
+
lines.push(`**${entry.label}:** ${stringify(entry.value)}`);
|
|
921
|
+
break;
|
|
922
|
+
case "code":
|
|
923
|
+
lines.push(`**${entry.label}**`, "", "```" + (entry.lang ?? ""), entry.content, "```");
|
|
924
|
+
break;
|
|
925
|
+
case "table": {
|
|
926
|
+
lines.push(`**${entry.label}**`, "");
|
|
927
|
+
lines.push(`| ${entry.columns.map(cell).join(" | ")} |`);
|
|
928
|
+
lines.push(`| ${entry.columns.map(() => "---").join(" | ")} |`);
|
|
929
|
+
for (const row of entry.rows) lines.push(`| ${row.map(cell).join(" | ")} |`);
|
|
930
|
+
break;
|
|
931
|
+
}
|
|
932
|
+
case "link":
|
|
933
|
+
lines.push(`[${entry.label}](${entry.url})`);
|
|
934
|
+
break;
|
|
935
|
+
case "section":
|
|
936
|
+
lines.push(`### ${entry.title}`, "", entry.markdown);
|
|
937
|
+
break;
|
|
938
|
+
case "mermaid":
|
|
939
|
+
if (entry.title) lines.push(`**${entry.title}**`, "");
|
|
940
|
+
lines.push("```mermaid", entry.code, "```");
|
|
941
|
+
break;
|
|
942
|
+
case "screenshot":
|
|
943
|
+
lines.push(``);
|
|
944
|
+
break;
|
|
945
|
+
case "video":
|
|
946
|
+
lines.push(`Video: ${entry.path}${entry.caption ? ` \u2014 ${entry.caption}` : ""}`);
|
|
947
|
+
break;
|
|
948
|
+
case "html": {
|
|
949
|
+
const htmlTitle = entry.title ?? "Embedded HTML";
|
|
950
|
+
if (entry.content) {
|
|
951
|
+
lines.push(`**${htmlTitle}**`, "", "```html", entry.content, "```");
|
|
952
|
+
} else if (entry.url) {
|
|
953
|
+
lines.push(`[${htmlTitle}](${entry.url})`);
|
|
954
|
+
} else {
|
|
955
|
+
lines.push(`Embedded HTML: ${entry.path ?? "(inline)"}`);
|
|
956
|
+
}
|
|
957
|
+
break;
|
|
958
|
+
}
|
|
959
|
+
case "custom":
|
|
960
|
+
lines.push(`**${entry.type}**`, "", "```json", stringify(entry.data), "```");
|
|
961
|
+
break;
|
|
962
|
+
}
|
|
963
|
+
for (const child of entry.children ?? []) {
|
|
964
|
+
lines.push("", ...docEntryToMarkdown(child));
|
|
965
|
+
}
|
|
966
|
+
return lines;
|
|
967
|
+
}
|
|
968
|
+
function stepLines(step, ordinal, full) {
|
|
969
|
+
const status = step.status === "passed" ? "" : ` \u2014 **${step.status}**`;
|
|
970
|
+
const lines = [`${ordinal}. **${step.keyword}** ${step.text}${status}`];
|
|
971
|
+
if (!full) return lines;
|
|
972
|
+
if (step.errorMessage) {
|
|
973
|
+
lines.push(...step.errorMessage.split("\n").map((l) => ` > ${l}`));
|
|
974
|
+
}
|
|
975
|
+
for (const entry of step.docEntries) {
|
|
976
|
+
lines.push("", ...docEntryToMarkdown(entry).map((l) => l === "" ? l : ` ${l}`));
|
|
977
|
+
}
|
|
978
|
+
return lines;
|
|
979
|
+
}
|
|
980
|
+
function scenarioToMarkdown(scenario, options = {}) {
|
|
981
|
+
const { variant = "full", meta = [] } = options;
|
|
982
|
+
const full = variant === "full";
|
|
983
|
+
const lines = full ? [`# ${scenario.title}`, ""] : [`## ${scenario.title} _(${scenario.status})_`, ""];
|
|
984
|
+
if (full && meta.length > 0) lines.push(...meta);
|
|
985
|
+
if (scenario.steps.length > 0) {
|
|
986
|
+
if (full) lines.push("", "## Steps", "");
|
|
987
|
+
scenario.steps.forEach((step, i) => lines.push(...stepLines(step, i + 1, full)));
|
|
988
|
+
}
|
|
989
|
+
if (scenario.errorMessage) {
|
|
990
|
+
if (full) lines.push("", "## Failure", "");
|
|
991
|
+
else lines.push("");
|
|
992
|
+
lines.push("```", scenario.errorMessage.trim(), "```");
|
|
993
|
+
}
|
|
994
|
+
if (full && scenario.docEntries.length > 0) {
|
|
995
|
+
lines.push("", "## Docs", "");
|
|
996
|
+
for (const entry of scenario.docEntries) lines.push(...docEntryToMarkdown(entry), "");
|
|
997
|
+
}
|
|
998
|
+
return lines.join("\n").replaceAll(/\n{3,}/g, "\n\n").trimEnd() + (full ? "\n" : "");
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
// src/interactive/scenario-actions.tsx
|
|
881
1002
|
var ScenarioActionsContext = (0, import_react7.createContext)(null);
|
|
882
1003
|
var ScenarioActionsProvider = ScenarioActionsContext.Provider;
|
|
883
1004
|
function useScenarioActions() {
|
|
884
1005
|
return (0, import_react7.useContext)(ScenarioActionsContext);
|
|
885
1006
|
}
|
|
886
|
-
function
|
|
887
|
-
|
|
888
|
-
for (const step of scenario.steps) {
|
|
889
|
-
lines.push(`- **${step.keyword}** ${step.text}`);
|
|
890
|
-
}
|
|
891
|
-
if (scenario.errorMessage) {
|
|
892
|
-
lines.push("", "```", scenario.errorMessage.trim(), "```");
|
|
893
|
-
}
|
|
894
|
-
return lines.join("\n");
|
|
1007
|
+
function scenarioToMarkdown2(scenario) {
|
|
1008
|
+
return scenarioToMarkdown(scenario, { variant: "compact" });
|
|
895
1009
|
}
|
|
896
1010
|
function scenarioToPrompt(scenario) {
|
|
897
1011
|
const lines = [
|
|
@@ -926,7 +1040,7 @@ function Card({ className, ...props }) {
|
|
|
926
1040
|
{
|
|
927
1041
|
"data-slot": "card",
|
|
928
1042
|
className: cn(
|
|
929
|
-
"flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-
|
|
1043
|
+
"flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-xs",
|
|
930
1044
|
className
|
|
931
1045
|
),
|
|
932
1046
|
...props
|
|
@@ -957,52 +1071,89 @@ function CardContent({ className, ...props }) {
|
|
|
957
1071
|
);
|
|
958
1072
|
}
|
|
959
1073
|
|
|
960
|
-
// src/components/
|
|
1074
|
+
// src/components/ui/dropdown-menu.tsx
|
|
1075
|
+
var React3 = require("react");
|
|
1076
|
+
var import_menu = require("@base-ui/react/menu");
|
|
1077
|
+
var import_lucide_react = require("lucide-react");
|
|
961
1078
|
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
962
|
-
var
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
};
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
1079
|
+
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";
|
|
1080
|
+
function DropdownMenu(props) {
|
|
1081
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_menu.Menu.Root, { "data-slot": "dropdown-menu", ...props });
|
|
1082
|
+
}
|
|
1083
|
+
function DropdownMenuTrigger(props) {
|
|
1084
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_menu.Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
|
|
1085
|
+
}
|
|
1086
|
+
function DropdownMenuContent({
|
|
1087
|
+
className,
|
|
1088
|
+
align = "end",
|
|
1089
|
+
sideOffset = 4,
|
|
1090
|
+
...props
|
|
1091
|
+
}) {
|
|
1092
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_menu.Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1093
|
+
import_menu.Menu.Positioner,
|
|
1094
|
+
{
|
|
1095
|
+
"data-slot": "dropdown-menu-positioner",
|
|
1096
|
+
className: "z-50",
|
|
1097
|
+
align,
|
|
1098
|
+
sideOffset,
|
|
1099
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1100
|
+
import_menu.Menu.Popup,
|
|
1101
|
+
{
|
|
1102
|
+
"data-slot": "dropdown-menu-content",
|
|
1103
|
+
className: cn(
|
|
1104
|
+
"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",
|
|
1105
|
+
className
|
|
1106
|
+
),
|
|
1107
|
+
...props
|
|
1108
|
+
}
|
|
1109
|
+
)
|
|
1110
|
+
}
|
|
1111
|
+
) });
|
|
1112
|
+
}
|
|
1113
|
+
function DropdownMenuItem({
|
|
1114
|
+
className,
|
|
1115
|
+
...props
|
|
1116
|
+
}) {
|
|
1117
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1118
|
+
import_menu.Menu.Item,
|
|
1119
|
+
{
|
|
1120
|
+
"data-slot": "dropdown-menu-item",
|
|
1121
|
+
className: cn(itemClasses, className),
|
|
1122
|
+
...props
|
|
1123
|
+
}
|
|
1124
|
+
);
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
// src/components/ReportScenario.tsx
|
|
1128
|
+
var import_lucide_react2 = require("lucide-react");
|
|
1129
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
1130
|
+
var STATUS_META = {
|
|
1131
|
+
passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
|
|
1132
|
+
failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
|
|
1133
|
+
skipped: { label: "Skipped", glyph: "\u25CB", glyphColor: "text-skip", badgeVariant: "skipped", showPill: true },
|
|
1134
|
+
pending: { label: "Pending", glyph: "\u25CB", glyphColor: "text-pend", badgeVariant: "pending", showPill: true }
|
|
985
1135
|
};
|
|
986
1136
|
function ReportScenario({ scenario, hideTitle = false }) {
|
|
987
1137
|
const titleId = `${scenario.id}-title`;
|
|
988
1138
|
const bodyId = `${scenario.id}-body`;
|
|
989
|
-
const
|
|
1139
|
+
const meta = STATUS_META[scenario.status];
|
|
1140
|
+
const label = scenario.planned ? "Planned" : meta.label;
|
|
990
1141
|
const collapse = useCollapse();
|
|
991
1142
|
const collapsible = collapse !== null && !hideTitle;
|
|
992
1143
|
const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
|
|
993
1144
|
const actions = useScenarioActions();
|
|
994
|
-
return /* @__PURE__ */ (0,
|
|
1145
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
995
1146
|
Card,
|
|
996
1147
|
{
|
|
997
1148
|
id: scenario.id,
|
|
998
1149
|
"data-status": scenario.status,
|
|
999
|
-
...hideTitle ? { "aria-label": `${scenario.title}
|
|
1150
|
+
...hideTitle ? { "aria-label": `${scenario.title}, ${label}` } : { "aria-labelledby": titleId },
|
|
1000
1151
|
className: "gap-0 py-0",
|
|
1001
1152
|
children: [
|
|
1002
|
-
/* @__PURE__ */ (0,
|
|
1003
|
-
/* @__PURE__ */ (0,
|
|
1004
|
-
hideTitle ? null : /* @__PURE__ */ (0,
|
|
1005
|
-
collapsible ? /* @__PURE__ */ (0,
|
|
1153
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(CardHeader, { className: "px-4 py-3", children: [
|
|
1154
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
|
|
1155
|
+
hideTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
|
|
1156
|
+
collapsible ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
1006
1157
|
"button",
|
|
1007
1158
|
{
|
|
1008
1159
|
type: "button",
|
|
@@ -1011,60 +1162,49 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1011
1162
|
"aria-controls": bodyId,
|
|
1012
1163
|
"aria-label": `Toggle ${scenario.title}`,
|
|
1013
1164
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
1014
|
-
children: /* @__PURE__ */ (0,
|
|
1165
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
1015
1166
|
}
|
|
1016
1167
|
) : null,
|
|
1017
|
-
/* @__PURE__ */ (0,
|
|
1018
|
-
/* @__PURE__ */ (0,
|
|
1168
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
|
|
1169
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: scenario.title })
|
|
1019
1170
|
] }),
|
|
1020
|
-
/* @__PURE__ */ (0,
|
|
1021
|
-
/* @__PURE__ */ (0,
|
|
1022
|
-
scenario.durationMs > 0 ? /* @__PURE__ */ (0,
|
|
1023
|
-
/* @__PURE__ */ (0,
|
|
1024
|
-
actions ? /* @__PURE__ */ (0,
|
|
1025
|
-
/* @__PURE__ */ (0,
|
|
1026
|
-
|
|
1171
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
1172
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ScenarioRunHistory, { scenarioId: scenario.id }),
|
|
1173
|
+
scenario.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
|
|
1174
|
+
meta.showPill ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "sr-only", children: `Status: ${label}` }),
|
|
1175
|
+
actions ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenu, { children: [
|
|
1176
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
1177
|
+
DropdownMenuTrigger,
|
|
1027
1178
|
{
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
"aria-
|
|
1031
|
-
title: "Copy permalink",
|
|
1032
|
-
className: "cursor-pointer rounded px-1 py-0.5 font-mono text-[0.625rem] text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
1033
|
-
children: "link"
|
|
1179
|
+
"aria-label": `Actions for ${scenario.title}`,
|
|
1180
|
+
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
1181
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react2.MoreHorizontalIcon, { "aria-hidden": true })
|
|
1034
1182
|
}
|
|
1035
1183
|
),
|
|
1036
|
-
/* @__PURE__ */ (0,
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
type: "button",
|
|
1051
|
-
onClick: () => actions.copyPrompt(scenario),
|
|
1052
|
-
"aria-label": `Copy ${scenario.title} as an AI investigation prompt`,
|
|
1053
|
-
title: "Copy as AI prompt",
|
|
1054
|
-
className: "cursor-pointer rounded px-1 py-0.5 font-mono text-[0.625rem] text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
1055
|
-
children: "ai"
|
|
1056
|
-
}
|
|
1057
|
-
)
|
|
1184
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenuContent, { align: "end", children: [
|
|
1185
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
|
|
1186
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react2.LinkIcon, {}),
|
|
1187
|
+
" Copy link"
|
|
1188
|
+
] }),
|
|
1189
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
|
|
1190
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react2.FileTextIcon, {}),
|
|
1191
|
+
" Copy as Markdown"
|
|
1192
|
+
] }),
|
|
1193
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
|
|
1194
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react2.SparklesIcon, {}),
|
|
1195
|
+
" Explain with AI"
|
|
1196
|
+
] })
|
|
1197
|
+
] })
|
|
1058
1198
|
] }) : null
|
|
1059
1199
|
] })
|
|
1060
1200
|
] }),
|
|
1061
|
-
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0,
|
|
1062
|
-
scenario.tags.map((t) => /* @__PURE__ */ (0,
|
|
1063
|
-
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0,
|
|
1201
|
+
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
|
|
1202
|
+
scenario.tags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
|
|
1203
|
+
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("li", { children: ticket.url ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
|
|
1064
1204
|
] }) : null
|
|
1065
1205
|
] }),
|
|
1066
|
-
/* @__PURE__ */ (0,
|
|
1067
|
-
scenario.errorMessage ? /* @__PURE__ */ (0,
|
|
1206
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
|
|
1207
|
+
scenario.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
1068
1208
|
"pre",
|
|
1069
1209
|
{
|
|
1070
1210
|
role: "alert",
|
|
@@ -1072,10 +1212,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1072
1212
|
children: scenario.errorMessage
|
|
1073
1213
|
}
|
|
1074
1214
|
) : null,
|
|
1075
|
-
/* @__PURE__ */ (0,
|
|
1076
|
-
scenario.docEntries.length > 0 ? /* @__PURE__ */ (0,
|
|
1077
|
-
/* @__PURE__ */ (0,
|
|
1078
|
-
/* @__PURE__ */ (0,
|
|
1215
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportSteps, { scenario }),
|
|
1216
|
+
scenario.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
|
|
1217
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportAttachments, { attachments: scenario.attachments }),
|
|
1218
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportTrace, { spans: scenario.otelSpans })
|
|
1079
1219
|
] })
|
|
1080
1220
|
]
|
|
1081
1221
|
}
|
|
@@ -1083,13 +1223,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1083
1223
|
}
|
|
1084
1224
|
|
|
1085
1225
|
// src/components/ReportScenarioList.tsx
|
|
1086
|
-
var
|
|
1226
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
1087
1227
|
function ReportScenarioList({ feature }) {
|
|
1088
|
-
return /* @__PURE__ */ (0,
|
|
1228
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_jsx_runtime24.Fragment, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ReportScenario, { scenario }, scenario.id)) });
|
|
1089
1229
|
}
|
|
1090
1230
|
|
|
1091
1231
|
// src/components/ReportFeature.tsx
|
|
1092
|
-
var
|
|
1232
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1093
1233
|
function ReportFeature({ feature }) {
|
|
1094
1234
|
const titleId = `${feature.id}-title`;
|
|
1095
1235
|
const bodyId = `${feature.id}-body`;
|
|
@@ -1097,74 +1237,80 @@ function ReportFeature({ feature }) {
|
|
|
1097
1237
|
const skipped = s.skipped + s.pending;
|
|
1098
1238
|
const collapse = useCollapse();
|
|
1099
1239
|
const collapsed = collapse?.isCollapsed(feature.id) ?? false;
|
|
1100
|
-
return
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
"
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1240
|
+
return (
|
|
1241
|
+
// Suite = a section heading + a divider, NOT another bordered card. Drops a
|
|
1242
|
+
// layer of nesting so the scenario cards below read as the primary unit.
|
|
1243
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
1244
|
+
"section",
|
|
1245
|
+
{
|
|
1246
|
+
id: feature.id,
|
|
1247
|
+
"data-slot": "feature",
|
|
1248
|
+
"aria-labelledby": titleId,
|
|
1249
|
+
className: "flex flex-col gap-3",
|
|
1250
|
+
children: [
|
|
1251
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
|
|
1252
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "min-w-0", children: [
|
|
1253
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
1254
|
+
"button",
|
|
1255
|
+
{
|
|
1256
|
+
type: "button",
|
|
1257
|
+
onClick: () => collapse.toggle(feature.id),
|
|
1258
|
+
"aria-expanded": !collapsed,
|
|
1259
|
+
"aria-controls": bodyId,
|
|
1260
|
+
className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
|
|
1261
|
+
children: [
|
|
1262
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
|
|
1263
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "truncate", children: feature.title })
|
|
1264
|
+
]
|
|
1265
|
+
}
|
|
1266
|
+
) : feature.title }),
|
|
1267
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
|
|
1268
|
+
] }),
|
|
1269
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
1270
|
+
"p",
|
|
1112
1271
|
{
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1272
|
+
className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
|
|
1273
|
+
"aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
|
|
1274
|
+
children: [
|
|
1275
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { children: [
|
|
1276
|
+
s.passed,
|
|
1277
|
+
" passed"
|
|
1278
|
+
] }),
|
|
1279
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1280
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
|
|
1281
|
+
s.failed,
|
|
1282
|
+
" failed"
|
|
1283
|
+
] }),
|
|
1284
|
+
skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
|
|
1285
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1286
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { children: [
|
|
1287
|
+
skipped,
|
|
1288
|
+
" skipped"
|
|
1289
|
+
] })
|
|
1290
|
+
] }) : null
|
|
1291
|
+
]
|
|
1120
1292
|
}
|
|
1121
|
-
)
|
|
1122
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "min-w-0", children: [
|
|
1123
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h2", { id: titleId, className: "text-sm font-semibold tracking-tight text-foreground", children: feature.title }),
|
|
1124
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "mt-0.5 truncate font-mono text-xs text-muted-foreground", children: feature.sourceFile })
|
|
1125
|
-
] })
|
|
1293
|
+
)
|
|
1126
1294
|
] }),
|
|
1127
|
-
/* @__PURE__ */ (0,
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
className: "flex shrink-0 items-center gap-2.5 font-mono text-xs font-medium",
|
|
1132
|
-
"aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
|
|
1133
|
-
children: [
|
|
1134
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { "aria-hidden": true, className: "text-pass", children: [
|
|
1135
|
-
"\u2713",
|
|
1136
|
-
s.passed
|
|
1137
|
-
] }),
|
|
1138
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { "aria-hidden": true, className: "text-fail", children: [
|
|
1139
|
-
"\u2717",
|
|
1140
|
-
s.failed
|
|
1141
|
-
] }),
|
|
1142
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("span", { "aria-hidden": true, className: "text-skip", children: [
|
|
1143
|
-
"\u25CB",
|
|
1144
|
-
skipped
|
|
1145
|
-
] })
|
|
1146
|
-
]
|
|
1147
|
-
}
|
|
1148
|
-
)
|
|
1149
|
-
] }),
|
|
1150
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-2 p-3", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ReportScenarioList, { feature }) })
|
|
1151
|
-
]
|
|
1152
|
-
}
|
|
1295
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportScenarioList, { feature }) })
|
|
1296
|
+
]
|
|
1297
|
+
}
|
|
1298
|
+
)
|
|
1153
1299
|
);
|
|
1154
1300
|
}
|
|
1155
1301
|
|
|
1156
1302
|
// src/components/ReportFeatureList.tsx
|
|
1157
|
-
var
|
|
1303
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1158
1304
|
function ReportFeatureList() {
|
|
1159
1305
|
const report = useReport();
|
|
1160
|
-
return /* @__PURE__ */ (0,
|
|
1306
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportFeature, { feature }, feature.id)) });
|
|
1161
1307
|
}
|
|
1162
1308
|
|
|
1163
1309
|
// src/components/ui/empty.tsx
|
|
1164
1310
|
var import_class_variance_authority2 = require("class-variance-authority");
|
|
1165
|
-
var
|
|
1311
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1166
1312
|
function Empty({ className, ...props }) {
|
|
1167
|
-
return /* @__PURE__ */ (0,
|
|
1313
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1168
1314
|
"div",
|
|
1169
1315
|
{
|
|
1170
1316
|
"data-slot": "empty",
|
|
@@ -1177,7 +1323,7 @@ function Empty({ className, ...props }) {
|
|
|
1177
1323
|
);
|
|
1178
1324
|
}
|
|
1179
1325
|
function EmptyHeader({ className, ...props }) {
|
|
1180
|
-
return /* @__PURE__ */ (0,
|
|
1326
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1181
1327
|
"div",
|
|
1182
1328
|
{
|
|
1183
1329
|
"data-slot": "empty-header",
|
|
@@ -1204,7 +1350,7 @@ var emptyMediaVariants = (0, import_class_variance_authority2.cva)(
|
|
|
1204
1350
|
}
|
|
1205
1351
|
);
|
|
1206
1352
|
function EmptyTitle({ className, ...props }) {
|
|
1207
|
-
return /* @__PURE__ */ (0,
|
|
1353
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1208
1354
|
"div",
|
|
1209
1355
|
{
|
|
1210
1356
|
"data-slot": "empty-title",
|
|
@@ -1215,16 +1361,16 @@ function EmptyTitle({ className, ...props }) {
|
|
|
1215
1361
|
}
|
|
1216
1362
|
|
|
1217
1363
|
// src/components/ReportEmpty.tsx
|
|
1218
|
-
var
|
|
1364
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1219
1365
|
function ReportEmpty({ message }) {
|
|
1220
|
-
return /* @__PURE__ */ (0,
|
|
1366
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(EmptyHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
|
|
1221
1367
|
}
|
|
1222
1368
|
|
|
1223
1369
|
// src/components/ReportSummary.tsx
|
|
1224
|
-
var
|
|
1370
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
1225
1371
|
function ReportSummary({ className }) {
|
|
1226
1372
|
const report = useReport();
|
|
1227
|
-
return /* @__PURE__ */ (0,
|
|
1373
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
1228
1374
|
ReportSummaryView,
|
|
1229
1375
|
{
|
|
1230
1376
|
summary: report.summary,
|
|
@@ -1233,38 +1379,54 @@ function ReportSummary({ className }) {
|
|
|
1233
1379
|
}
|
|
1234
1380
|
);
|
|
1235
1381
|
}
|
|
1382
|
+
var TONE = {
|
|
1383
|
+
total: { num: "text-foreground", dot: "bg-muted-foreground/50" },
|
|
1384
|
+
passed: { num: "text-pass", dot: "bg-pass" },
|
|
1385
|
+
failed: { num: "text-fail", dot: "bg-fail" },
|
|
1386
|
+
skipped: { num: "text-skip", dot: "bg-skip" },
|
|
1387
|
+
pending: { num: "text-pend", dot: "bg-pend" }
|
|
1388
|
+
};
|
|
1236
1389
|
function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1390
|
+
const cards = [
|
|
1391
|
+
{ status: "total", label: "Total", value: summary.total },
|
|
1392
|
+
{ status: "passed", label: "Passed", value: summary.passed },
|
|
1393
|
+
{ status: "failed", label: "Failed", value: summary.failed },
|
|
1394
|
+
{ status: "skipped", label: "Skipped", value: summary.skipped }
|
|
1395
|
+
];
|
|
1396
|
+
if (summary.pending > 0) {
|
|
1397
|
+
cards.push({ status: "pending", label: "Pending", value: summary.pending });
|
|
1398
|
+
}
|
|
1399
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
1400
|
+
"dl",
|
|
1401
|
+
{
|
|
1402
|
+
className: cn(
|
|
1403
|
+
"grid grid-cols-2 gap-3",
|
|
1404
|
+
// Columns follow the card count so the row is always full — 5 statuses
|
|
1405
|
+
// (pending present) never leave a lone orphan card below a row of four.
|
|
1406
|
+
cards.length === 5 ? "sm:grid-cols-5" : "sm:grid-cols-4",
|
|
1407
|
+
className
|
|
1408
|
+
),
|
|
1409
|
+
"aria-label": ariaLabel,
|
|
1410
|
+
children: cards.map((c) => {
|
|
1411
|
+
const tone = TONE[c.status];
|
|
1412
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
1413
|
+
"div",
|
|
1414
|
+
{
|
|
1415
|
+
"data-status": c.status,
|
|
1416
|
+
className: "rounded-lg border bg-card px-4 py-3",
|
|
1417
|
+
children: [
|
|
1418
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
|
|
1419
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
|
|
1420
|
+
c.label
|
|
1421
|
+
] }),
|
|
1422
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
|
|
1423
|
+
]
|
|
1424
|
+
},
|
|
1425
|
+
c.status
|
|
1426
|
+
);
|
|
1427
|
+
})
|
|
1428
|
+
}
|
|
1429
|
+
);
|
|
1268
1430
|
}
|
|
1269
1431
|
|
|
1270
1432
|
// src/lib/provenance.ts
|
|
@@ -1317,7 +1479,7 @@ function prUrl(ci) {
|
|
|
1317
1479
|
}
|
|
1318
1480
|
|
|
1319
1481
|
// src/components/ReportMeta.tsx
|
|
1320
|
-
var
|
|
1482
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
1321
1483
|
function ReportMeta() {
|
|
1322
1484
|
const report = useReport();
|
|
1323
1485
|
const items = [];
|
|
@@ -1340,13 +1502,13 @@ function ReportMeta() {
|
|
|
1340
1502
|
const short = sha.slice(0, 8);
|
|
1341
1503
|
items.push({
|
|
1342
1504
|
label: "Commit",
|
|
1343
|
-
value: url ? /* @__PURE__ */ (0,
|
|
1505
|
+
value: url ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
|
|
1344
1506
|
});
|
|
1345
1507
|
}
|
|
1346
1508
|
if (report.ci) {
|
|
1347
1509
|
items.push({
|
|
1348
1510
|
label: "CI",
|
|
1349
|
-
value: report.ci.url ? /* @__PURE__ */ (0,
|
|
1511
|
+
value: report.ci.url ? /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
|
|
1350
1512
|
ciDisplayName(report.ci.name),
|
|
1351
1513
|
report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
|
|
1352
1514
|
] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
|
|
@@ -1357,59 +1519,172 @@ function ReportMeta() {
|
|
|
1357
1519
|
const label = `#${report.ci.prNumber}`;
|
|
1358
1520
|
items.push({
|
|
1359
1521
|
label: "PR",
|
|
1360
|
-
value: url ? /* @__PURE__ */ (0,
|
|
1522
|
+
value: url ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
|
|
1361
1523
|
});
|
|
1362
1524
|
}
|
|
1363
1525
|
if (items.length === 0) return null;
|
|
1364
|
-
return
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1526
|
+
return (
|
|
1527
|
+
// Run metadata is useful but secondary to "what failed" — tuck it into a
|
|
1528
|
+
// collapsed disclosure so it doesn't push the result down. Native <details>
|
|
1529
|
+
// so it works with no JS (the SSR/no-hydration report still toggles).
|
|
1530
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
|
|
1531
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("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: [
|
|
1532
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
|
|
1533
|
+
"Run details"
|
|
1534
|
+
] }),
|
|
1535
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("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__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex items-baseline gap-1.5", children: [
|
|
1536
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("dt", { className: "font-medium", children: item.label }),
|
|
1537
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("dd", { className: "font-mono text-foreground", children: item.value })
|
|
1538
|
+
] }, item.label)) })
|
|
1539
|
+
] })
|
|
1540
|
+
);
|
|
1368
1541
|
}
|
|
1369
1542
|
|
|
1370
1543
|
// src/components/ReportSchemaError.tsx
|
|
1371
|
-
var
|
|
1544
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
1372
1545
|
function ReportSchemaError({ error }) {
|
|
1373
|
-
return /* @__PURE__ */ (0,
|
|
1374
|
-
/* @__PURE__ */ (0,
|
|
1375
|
-
/* @__PURE__ */ (0,
|
|
1376
|
-
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0,
|
|
1546
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
|
|
1547
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("strong", { children: "Report could not be displayed." }) }),
|
|
1548
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { children: error.message }),
|
|
1549
|
+
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("p", { children: [
|
|
1377
1550
|
"The report bundle is newer than this version of ",
|
|
1378
|
-
/* @__PURE__ */ (0,
|
|
1551
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("code", { children: "executable-stories-react" }),
|
|
1379
1552
|
". Upgrade the package, or regenerate the report with an older formatters CLI."
|
|
1380
1553
|
] }) : null,
|
|
1381
|
-
error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0,
|
|
1382
|
-
/* @__PURE__ */ (0,
|
|
1554
|
+
error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("details", { children: [
|
|
1555
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("summary", { children: [
|
|
1383
1556
|
error.issues.length,
|
|
1384
1557
|
" validation issue",
|
|
1385
1558
|
error.issues.length === 1 ? "" : "s"
|
|
1386
1559
|
] }),
|
|
1387
|
-
/* @__PURE__ */ (0,
|
|
1560
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
|
|
1388
1561
|
] }) : null
|
|
1389
1562
|
] });
|
|
1390
1563
|
}
|
|
1391
1564
|
|
|
1392
1565
|
// src/components/ReportShell.tsx
|
|
1393
|
-
var
|
|
1394
|
-
function ReportTitleBlock({ title }) {
|
|
1395
|
-
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_jsx_runtime31.Fragment, { children: [
|
|
1396
|
-
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("h1", { children: title ?? "Story Report" }),
|
|
1397
|
-
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ReportSummary, {}),
|
|
1398
|
-
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ReportMeta, {})
|
|
1399
|
-
] });
|
|
1400
|
-
}
|
|
1566
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
1401
1567
|
function ReportErrorShell({
|
|
1402
1568
|
error,
|
|
1403
1569
|
className,
|
|
1404
1570
|
title,
|
|
1405
1571
|
dataTheme
|
|
1406
1572
|
}) {
|
|
1407
|
-
return /* @__PURE__ */ (0,
|
|
1573
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ReportSchemaError, { error }) });
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
// src/interactive/ReportInteractive.tsx
|
|
1577
|
+
var import_lucide_react5 = require("lucide-react");
|
|
1578
|
+
|
|
1579
|
+
// src/components/ui/switch.tsx
|
|
1580
|
+
var React4 = require("react");
|
|
1581
|
+
var import_switch = require("@base-ui/react/switch");
|
|
1582
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
1583
|
+
function Switch({
|
|
1584
|
+
className,
|
|
1585
|
+
...props
|
|
1586
|
+
}) {
|
|
1587
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
1588
|
+
import_switch.Switch.Root,
|
|
1589
|
+
{
|
|
1590
|
+
"data-slot": "switch",
|
|
1591
|
+
className: cn(
|
|
1592
|
+
"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",
|
|
1593
|
+
className
|
|
1594
|
+
),
|
|
1595
|
+
...props,
|
|
1596
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
1597
|
+
import_switch.Switch.Thumb,
|
|
1598
|
+
{
|
|
1599
|
+
"data-slot": "switch-thumb",
|
|
1600
|
+
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"
|
|
1601
|
+
}
|
|
1602
|
+
)
|
|
1603
|
+
}
|
|
1604
|
+
);
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
// src/components/ui/toggle-group.tsx
|
|
1608
|
+
var React5 = __toESM(require("react"), 1);
|
|
1609
|
+
var import_toggle_group = require("@base-ui/react/toggle-group");
|
|
1610
|
+
var import_toggle = require("@base-ui/react/toggle");
|
|
1611
|
+
var import_class_variance_authority3 = require("class-variance-authority");
|
|
1612
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
1613
|
+
var toggleItemVariants = (0, import_class_variance_authority3.cva)(
|
|
1614
|
+
"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",
|
|
1615
|
+
{
|
|
1616
|
+
variants: {
|
|
1617
|
+
size: {
|
|
1618
|
+
default: "h-9 px-3 text-sm",
|
|
1619
|
+
sm: "h-8 px-2.5 text-[0.82rem]"
|
|
1620
|
+
}
|
|
1621
|
+
},
|
|
1622
|
+
defaultVariants: { size: "default" }
|
|
1623
|
+
}
|
|
1624
|
+
);
|
|
1625
|
+
var ToggleGroupContext = React5.createContext({
|
|
1626
|
+
size: "default"
|
|
1627
|
+
});
|
|
1628
|
+
function ToggleGroup({
|
|
1629
|
+
className,
|
|
1630
|
+
size,
|
|
1631
|
+
children,
|
|
1632
|
+
...props
|
|
1633
|
+
}) {
|
|
1634
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
1635
|
+
import_toggle_group.ToggleGroup,
|
|
1636
|
+
{
|
|
1637
|
+
"data-slot": "toggle-group",
|
|
1638
|
+
className: cn("flex w-fit items-center gap-0.5 rounded-lg bg-muted p-0.5", className),
|
|
1639
|
+
...props,
|
|
1640
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ToggleGroupContext.Provider, { value: { size }, children })
|
|
1641
|
+
}
|
|
1642
|
+
);
|
|
1643
|
+
}
|
|
1644
|
+
function ToggleGroupItem({
|
|
1645
|
+
className,
|
|
1646
|
+
children,
|
|
1647
|
+
size,
|
|
1648
|
+
...props
|
|
1649
|
+
}) {
|
|
1650
|
+
const context = React5.useContext(ToggleGroupContext);
|
|
1651
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
1652
|
+
import_toggle.Toggle,
|
|
1653
|
+
{
|
|
1654
|
+
"data-slot": "toggle-group-item",
|
|
1655
|
+
className: cn(toggleItemVariants({ size: context.size ?? size }), "flex-1 shrink-0", className),
|
|
1656
|
+
...props,
|
|
1657
|
+
children
|
|
1658
|
+
}
|
|
1659
|
+
);
|
|
1408
1660
|
}
|
|
1409
1661
|
|
|
1410
1662
|
// src/interactive/ReportSearch.tsx
|
|
1411
1663
|
var import_react8 = require("react");
|
|
1412
|
-
var
|
|
1664
|
+
var import_lucide_react3 = require("lucide-react");
|
|
1665
|
+
|
|
1666
|
+
// src/components/ui/input.tsx
|
|
1667
|
+
var React6 = require("react");
|
|
1668
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
1669
|
+
function Input({ className, type, ...props }) {
|
|
1670
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
1671
|
+
"input",
|
|
1672
|
+
{
|
|
1673
|
+
type,
|
|
1674
|
+
"data-slot": "input",
|
|
1675
|
+
className: cn(
|
|
1676
|
+
"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",
|
|
1677
|
+
"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
|
|
1678
|
+
"aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
|
|
1679
|
+
className
|
|
1680
|
+
),
|
|
1681
|
+
...props
|
|
1682
|
+
}
|
|
1683
|
+
);
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
// src/interactive/ReportSearch.tsx
|
|
1687
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
1413
1688
|
var ReportSearch = (0, import_react8.forwardRef)(
|
|
1414
1689
|
function ReportSearch2(props, ref) {
|
|
1415
1690
|
const {
|
|
@@ -1417,11 +1692,11 @@ var ReportSearch = (0, import_react8.forwardRef)(
|
|
|
1417
1692
|
onChange,
|
|
1418
1693
|
matchedCount,
|
|
1419
1694
|
totalCount,
|
|
1420
|
-
placeholder = "Search scenarios
|
|
1695
|
+
placeholder = "Search scenarios or tags\u2026",
|
|
1421
1696
|
className
|
|
1422
1697
|
} = props;
|
|
1423
1698
|
const inputId = (0, import_react8.useId)();
|
|
1424
|
-
const showCounts = typeof matchedCount === "number" && typeof totalCount === "number";
|
|
1699
|
+
const showCounts = value.trim().length > 0 && typeof matchedCount === "number" && typeof totalCount === "number";
|
|
1425
1700
|
function handleChange(e) {
|
|
1426
1701
|
onChange(e.target.value);
|
|
1427
1702
|
}
|
|
@@ -1431,24 +1706,46 @@ var ReportSearch = (0, import_react8.forwardRef)(
|
|
|
1431
1706
|
e.preventDefault();
|
|
1432
1707
|
}
|
|
1433
1708
|
}
|
|
1434
|
-
return /* @__PURE__ */ (0,
|
|
1435
|
-
/* @__PURE__ */ (0,
|
|
1436
|
-
/* @__PURE__ */ (0,
|
|
1437
|
-
|
|
1709
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: cn("es-search flex flex-col gap-1", className), children: [
|
|
1710
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("label", { htmlFor: inputId, className: "sr-only", children: "Search" }),
|
|
1711
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "relative w-full sm:w-72", children: [
|
|
1712
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
1713
|
+
import_lucide_react3.Search,
|
|
1714
|
+
{
|
|
1715
|
+
"aria-hidden": true,
|
|
1716
|
+
className: "pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground"
|
|
1717
|
+
}
|
|
1718
|
+
),
|
|
1719
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
1720
|
+
Input,
|
|
1721
|
+
{
|
|
1722
|
+
ref,
|
|
1723
|
+
id: inputId,
|
|
1724
|
+
type: "search",
|
|
1725
|
+
value,
|
|
1726
|
+
onChange: handleChange,
|
|
1727
|
+
onKeyDown: handleKeyDown,
|
|
1728
|
+
placeholder,
|
|
1729
|
+
autoComplete: "off",
|
|
1730
|
+
spellCheck: false,
|
|
1731
|
+
"aria-keyshortcuts": "/",
|
|
1732
|
+
className: "pl-8"
|
|
1733
|
+
}
|
|
1734
|
+
)
|
|
1735
|
+
] }),
|
|
1736
|
+
showCounts ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
1737
|
+
"span",
|
|
1438
1738
|
{
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
spellCheck: false,
|
|
1448
|
-
"aria-keyshortcuts": "/"
|
|
1739
|
+
className: "text-xs tabular-nums text-muted-foreground",
|
|
1740
|
+
"aria-live": "polite",
|
|
1741
|
+
children: [
|
|
1742
|
+
matchedCount,
|
|
1743
|
+
" of ",
|
|
1744
|
+
totalCount,
|
|
1745
|
+
" scenarios"
|
|
1746
|
+
]
|
|
1449
1747
|
}
|
|
1450
|
-
)
|
|
1451
|
-
showCounts ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "es-search-counts", "aria-live": "polite", children: value ? `${matchedCount} of ${totalCount}` : `${totalCount} total` }) : null
|
|
1748
|
+
) : null
|
|
1452
1749
|
] });
|
|
1453
1750
|
}
|
|
1454
1751
|
);
|
|
@@ -1477,7 +1774,7 @@ function scrollToScenarioId(scenarioId, options = {}) {
|
|
|
1477
1774
|
}
|
|
1478
1775
|
|
|
1479
1776
|
// src/interactive/ReportFailureBanner.tsx
|
|
1480
|
-
var
|
|
1777
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
1481
1778
|
function ReportFailureBanner({ failures }) {
|
|
1482
1779
|
const first = failures[0];
|
|
1483
1780
|
const jumpToFirst = (0, import_react9.useCallback)(() => {
|
|
@@ -1485,7 +1782,7 @@ function ReportFailureBanner({ failures }) {
|
|
|
1485
1782
|
scrollToScenarioId(first.scenarioId);
|
|
1486
1783
|
}, [first]);
|
|
1487
1784
|
if (failures.length === 0) return null;
|
|
1488
|
-
return /* @__PURE__ */ (0,
|
|
1785
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
|
|
1489
1786
|
"div",
|
|
1490
1787
|
{
|
|
1491
1788
|
className: "es-failure-banner",
|
|
@@ -1493,20 +1790,20 @@ function ReportFailureBanner({ failures }) {
|
|
|
1493
1790
|
"aria-live": "polite",
|
|
1494
1791
|
"aria-label": "Failure summary",
|
|
1495
1792
|
children: [
|
|
1496
|
-
/* @__PURE__ */ (0,
|
|
1497
|
-
/* @__PURE__ */ (0,
|
|
1793
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { className: "es-failure-banner-text", children: [
|
|
1794
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("strong", { children: failures.length }),
|
|
1498
1795
|
" ",
|
|
1499
1796
|
"failure",
|
|
1500
1797
|
failures.length === 1 ? "" : "s"
|
|
1501
1798
|
] }),
|
|
1502
|
-
/* @__PURE__ */ (0,
|
|
1799
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
1503
1800
|
"button",
|
|
1504
1801
|
{
|
|
1505
1802
|
type: "button",
|
|
1506
1803
|
className: "es-failure-banner-jump",
|
|
1507
1804
|
onClick: jumpToFirst,
|
|
1508
|
-
"aria-label": "
|
|
1509
|
-
children: "
|
|
1805
|
+
"aria-label": "View first failure",
|
|
1806
|
+
children: "View first failure \u2193"
|
|
1510
1807
|
}
|
|
1511
1808
|
)
|
|
1512
1809
|
]
|
|
@@ -1516,7 +1813,7 @@ function ReportFailureBanner({ failures }) {
|
|
|
1516
1813
|
|
|
1517
1814
|
// src/interactive/ReportFreshness.tsx
|
|
1518
1815
|
var import_react10 = require("react");
|
|
1519
|
-
var
|
|
1816
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
1520
1817
|
function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
1521
1818
|
const [now, setNow] = (0, import_react10.useState)(nowMs);
|
|
1522
1819
|
(0, import_react10.useEffect)(() => {
|
|
@@ -1524,7 +1821,7 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
1524
1821
|
}, [nowMs]);
|
|
1525
1822
|
if (lastRunMs === void 0 || now === void 0) return null;
|
|
1526
1823
|
const age = formatRelativeAge(lastRunMs, now);
|
|
1527
|
-
const runLink = ciUrl ? /* @__PURE__ */ (0,
|
|
1824
|
+
const runLink = ciUrl ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
1528
1825
|
"a",
|
|
1529
1826
|
{
|
|
1530
1827
|
href: ciUrl,
|
|
@@ -1535,22 +1832,22 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
1535
1832
|
}
|
|
1536
1833
|
) : null;
|
|
1537
1834
|
if (isReportStale(lastRunMs, staleAfterDays, now)) {
|
|
1538
|
-
return /* @__PURE__ */ (0,
|
|
1539
|
-
/* @__PURE__ */ (0,
|
|
1540
|
-
/* @__PURE__ */ (0,
|
|
1835
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "es-stale-banner", role: "status", "aria-label": "Report freshness", children: [
|
|
1836
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { children: [
|
|
1837
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("strong", { children: [
|
|
1541
1838
|
"Last verified ",
|
|
1542
1839
|
age,
|
|
1543
1840
|
"."
|
|
1544
1841
|
] }),
|
|
1545
|
-
" This report may no longer match the current behavior
|
|
1842
|
+
" This report may no longer match the current behavior. Look for a newer run."
|
|
1546
1843
|
] }),
|
|
1547
1844
|
runLink
|
|
1548
1845
|
] });
|
|
1549
1846
|
}
|
|
1550
|
-
return /* @__PURE__ */ (0,
|
|
1847
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("p", { className: "es-freshness", "aria-label": "Report freshness", children: [
|
|
1551
1848
|
"Verified ",
|
|
1552
1849
|
age,
|
|
1553
|
-
runLink ? /* @__PURE__ */ (0,
|
|
1850
|
+
runLink ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_jsx_runtime38.Fragment, { children: [
|
|
1554
1851
|
" \xB7 ",
|
|
1555
1852
|
runLink
|
|
1556
1853
|
] }) : null
|
|
@@ -1558,15 +1855,15 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
1558
1855
|
}
|
|
1559
1856
|
|
|
1560
1857
|
// src/interactive/ReportLastRunDelta.tsx
|
|
1561
|
-
var
|
|
1858
|
+
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
1562
1859
|
var MAX_LINKS = 5;
|
|
1563
1860
|
function ScenarioLinks({ scenarios, tone }) {
|
|
1564
|
-
return /* @__PURE__ */ (0,
|
|
1565
|
-
scenarios.slice(0, MAX_LINKS).map((s, i) => /* @__PURE__ */ (0,
|
|
1861
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_jsx_runtime39.Fragment, { children: [
|
|
1862
|
+
scenarios.slice(0, MAX_LINKS).map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { children: [
|
|
1566
1863
|
i > 0 ? ", " : "",
|
|
1567
|
-
/* @__PURE__ */ (0,
|
|
1864
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
|
|
1568
1865
|
] }, s.id)),
|
|
1569
|
-
scenarios.length > MAX_LINKS ? /* @__PURE__ */ (0,
|
|
1866
|
+
scenarios.length > MAX_LINKS ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { children: [
|
|
1570
1867
|
" and ",
|
|
1571
1868
|
scenarios.length - MAX_LINKS,
|
|
1572
1869
|
" more"
|
|
@@ -1583,23 +1880,23 @@ function ReportLastRunDelta({
|
|
|
1583
1880
|
if (!delta) return null;
|
|
1584
1881
|
const { newlyFailing, newlyPassing, added } = delta;
|
|
1585
1882
|
if (newlyFailing.length === 0 && newlyPassing.length === 0 && added.length === 0) {
|
|
1586
|
-
return /* @__PURE__ */ (0,
|
|
1883
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: "Since last run: no behavior changes." });
|
|
1587
1884
|
}
|
|
1588
|
-
return /* @__PURE__ */ (0,
|
|
1589
|
-
/* @__PURE__ */ (0,
|
|
1590
|
-
newlyFailing.length > 0 ? /* @__PURE__ */ (0,
|
|
1885
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: [
|
|
1886
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "font-medium text-foreground", children: "Since last run:" }),
|
|
1887
|
+
newlyFailing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "ml-2 text-fail", children: [
|
|
1591
1888
|
newlyFailing.length,
|
|
1592
1889
|
" newly failing (",
|
|
1593
|
-
/* @__PURE__ */ (0,
|
|
1890
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ScenarioLinks, { scenarios: newlyFailing, tone: "text-fail" }),
|
|
1594
1891
|
")"
|
|
1595
1892
|
] }) : null,
|
|
1596
|
-
newlyPassing.length > 0 ? /* @__PURE__ */ (0,
|
|
1893
|
+
newlyPassing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "ml-2 text-pass", children: [
|
|
1597
1894
|
newlyPassing.length,
|
|
1598
1895
|
" fixed (",
|
|
1599
|
-
/* @__PURE__ */ (0,
|
|
1896
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ScenarioLinks, { scenarios: newlyPassing, tone: "text-pass" }),
|
|
1600
1897
|
")"
|
|
1601
1898
|
] }) : null,
|
|
1602
|
-
added.length > 0 ? /* @__PURE__ */ (0,
|
|
1899
|
+
added.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "ml-2", children: [
|
|
1603
1900
|
added.length,
|
|
1604
1901
|
" new"
|
|
1605
1902
|
] }) : null
|
|
@@ -1608,14 +1905,78 @@ function ReportLastRunDelta({
|
|
|
1608
1905
|
|
|
1609
1906
|
// src/interactive/ReportShortcutsHelp.tsx
|
|
1610
1907
|
var import_react11 = require("react");
|
|
1611
|
-
|
|
1908
|
+
|
|
1909
|
+
// src/components/ui/button.tsx
|
|
1910
|
+
var React7 = require("react");
|
|
1911
|
+
var import_class_variance_authority4 = require("class-variance-authority");
|
|
1912
|
+
var import_use_render2 = require("@base-ui/react/use-render");
|
|
1913
|
+
var buttonVariants = (0, import_class_variance_authority4.cva)(
|
|
1914
|
+
"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",
|
|
1915
|
+
{
|
|
1916
|
+
variants: {
|
|
1917
|
+
variant: {
|
|
1918
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
1919
|
+
destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
|
|
1920
|
+
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",
|
|
1921
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
1922
|
+
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
|
1923
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
1924
|
+
},
|
|
1925
|
+
size: {
|
|
1926
|
+
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
1927
|
+
xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
|
|
1928
|
+
sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
|
|
1929
|
+
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
1930
|
+
icon: "size-9",
|
|
1931
|
+
"icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
|
|
1932
|
+
"icon-sm": "size-8",
|
|
1933
|
+
"icon-lg": "size-10"
|
|
1934
|
+
}
|
|
1935
|
+
},
|
|
1936
|
+
defaultVariants: {
|
|
1937
|
+
variant: "default",
|
|
1938
|
+
size: "default"
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
);
|
|
1942
|
+
function Button({
|
|
1943
|
+
className,
|
|
1944
|
+
variant = "default",
|
|
1945
|
+
size = "default",
|
|
1946
|
+
render,
|
|
1947
|
+
...props
|
|
1948
|
+
}) {
|
|
1949
|
+
return (0, import_use_render2.useRender)({
|
|
1950
|
+
defaultTagName: "button",
|
|
1951
|
+
render,
|
|
1952
|
+
props: {
|
|
1953
|
+
"data-slot": "button",
|
|
1954
|
+
"data-variant": variant,
|
|
1955
|
+
"data-size": size,
|
|
1956
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
1957
|
+
...props
|
|
1958
|
+
}
|
|
1959
|
+
});
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
// src/interactive/ReportShortcutsHelp.tsx
|
|
1963
|
+
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
1612
1964
|
var SHORTCUTS = [
|
|
1613
1965
|
{ keys: "/", description: "Focus search" },
|
|
1614
1966
|
{ keys: "f", description: "Jump to next failure" },
|
|
1615
|
-
{ keys: "Shift
|
|
1616
|
-
{ keys: "
|
|
1617
|
-
{ keys: "
|
|
1967
|
+
{ keys: "Shift F", description: "Jump to previous failure" },
|
|
1968
|
+
{ keys: "e", description: "Expand all" },
|
|
1969
|
+
{ keys: "c", description: "Collapse all" },
|
|
1970
|
+
{ keys: "?", description: "Toggle this help" },
|
|
1971
|
+
{ keys: "Esc", description: "Clear search / close" }
|
|
1618
1972
|
];
|
|
1973
|
+
function Keys({ keys }) {
|
|
1974
|
+
const parts = keys.split(" ");
|
|
1975
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "inline-flex items-center gap-1", children: parts.map((k, i) => /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
|
|
1976
|
+
i > 0 ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "text-xs text-muted-foreground", children: "+" }) : null,
|
|
1977
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("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 })
|
|
1978
|
+
] }, k)) });
|
|
1979
|
+
}
|
|
1619
1980
|
function ReportShortcutsHelp({ open, onClose }) {
|
|
1620
1981
|
const dialogRef = (0, import_react11.useRef)(null);
|
|
1621
1982
|
(0, import_react11.useEffect)(() => {
|
|
@@ -1624,20 +1985,20 @@ function ReportShortcutsHelp({ open, onClose }) {
|
|
|
1624
1985
|
if (open && !dialog.open) dialog.showModal();
|
|
1625
1986
|
else if (!open && dialog.open) dialog.close();
|
|
1626
1987
|
}, [open]);
|
|
1627
|
-
return /* @__PURE__ */ (0,
|
|
1988
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
|
|
1628
1989
|
"dialog",
|
|
1629
1990
|
{
|
|
1630
1991
|
ref: dialogRef,
|
|
1631
|
-
className: "es-shortcuts-help",
|
|
1992
|
+
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",
|
|
1632
1993
|
"aria-label": "Keyboard shortcuts",
|
|
1633
1994
|
onClose,
|
|
1634
1995
|
children: [
|
|
1635
|
-
/* @__PURE__ */ (0,
|
|
1636
|
-
/* @__PURE__ */ (0,
|
|
1637
|
-
/* @__PURE__ */ (0,
|
|
1638
|
-
/* @__PURE__ */ (0,
|
|
1996
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("h2", { className: "text-base font-semibold", children: "Keyboard shortcuts" }),
|
|
1997
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("dl", { className: "mt-4 grid grid-cols-[auto_1fr] items-center gap-x-4 gap-y-2.5", children: SHORTCUTS.map((s) => /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "col-span-2 grid grid-cols-subgrid items-center", children: [
|
|
1998
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("dt", { className: "justify-self-start", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Keys, { keys: s.keys }) }),
|
|
1999
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("dd", { className: "text-sm text-muted-foreground", children: s.description })
|
|
1639
2000
|
] }, s.keys)) }),
|
|
1640
|
-
/* @__PURE__ */ (0,
|
|
2001
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("form", { method: "dialog", className: "mt-6", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Button, { type: "submit", variant: "outline", size: "sm", children: "Close" }) })
|
|
1641
2002
|
]
|
|
1642
2003
|
}
|
|
1643
2004
|
);
|
|
@@ -1809,8 +2170,37 @@ function listFailures(report) {
|
|
|
1809
2170
|
return out;
|
|
1810
2171
|
}
|
|
1811
2172
|
|
|
2173
|
+
// src/interactive/triage-default.ts
|
|
2174
|
+
function needsAttention(status) {
|
|
2175
|
+
return status === "failed";
|
|
2176
|
+
}
|
|
2177
|
+
function defaultCollapsedIds(report) {
|
|
2178
|
+
const collapsed = /* @__PURE__ */ new Set();
|
|
2179
|
+
if (report.summary.failed === 0) return collapsed;
|
|
2180
|
+
for (const feature of report.features) {
|
|
2181
|
+
const featureHasFailure = feature.scenarios.some((s) => needsAttention(s.status));
|
|
2182
|
+
if (!featureHasFailure) collapsed.add(feature.id);
|
|
2183
|
+
for (const scenario of feature.scenarios) {
|
|
2184
|
+
if (!needsAttention(scenario.status)) collapsed.add(scenario.id);
|
|
2185
|
+
}
|
|
2186
|
+
}
|
|
2187
|
+
return collapsed;
|
|
2188
|
+
}
|
|
2189
|
+
function failuresFirst(report) {
|
|
2190
|
+
if (report.summary.failed === 0) return report;
|
|
2191
|
+
const withFailures = [];
|
|
2192
|
+
const rest = [];
|
|
2193
|
+
for (const feature of report.features) {
|
|
2194
|
+
(feature.scenarios.some((s) => needsAttention(s.status)) ? withFailures : rest).push(feature);
|
|
2195
|
+
}
|
|
2196
|
+
if (withFailures.length === 0) return report;
|
|
2197
|
+
return { ...report, features: [...withFailures, ...rest] };
|
|
2198
|
+
}
|
|
2199
|
+
|
|
1812
2200
|
// src/interactive/ReportFilters.tsx
|
|
1813
|
-
var
|
|
2201
|
+
var import_react14 = require("react");
|
|
2202
|
+
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
2203
|
+
var TAG_LIMIT = 12;
|
|
1814
2204
|
function ReportFilters({
|
|
1815
2205
|
statuses,
|
|
1816
2206
|
status,
|
|
@@ -1819,11 +2209,14 @@ function ReportFilters({
|
|
|
1819
2209
|
activeTags,
|
|
1820
2210
|
onToggleTag
|
|
1821
2211
|
}) {
|
|
2212
|
+
const [showAllTags, setShowAllTags] = (0, import_react14.useState)(false);
|
|
1822
2213
|
if (statuses.length === 0 && tags.length === 0) return null;
|
|
1823
|
-
|
|
1824
|
-
|
|
2214
|
+
const tagsCollapsed = tags.length > TAG_LIMIT && !showAllTags;
|
|
2215
|
+
const visibleTags = tagsCollapsed ? tags.slice(0, TAG_LIMIT) : tags;
|
|
2216
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
2217
|
+
statuses.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { role: "group", "aria-label": "Filter by status", className: "flex flex-wrap gap-1", children: statuses.map((opt) => {
|
|
1825
2218
|
const active = status === opt.key;
|
|
1826
|
-
return /* @__PURE__ */ (0,
|
|
2219
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
|
|
1827
2220
|
"button",
|
|
1828
2221
|
{
|
|
1829
2222
|
type: "button",
|
|
@@ -1835,45 +2228,66 @@ function ReportFilters({
|
|
|
1835
2228
|
),
|
|
1836
2229
|
children: [
|
|
1837
2230
|
opt.label,
|
|
1838
|
-
/* @__PURE__ */ (0,
|
|
2231
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "ml-1 font-mono opacity-70", children: opt.count })
|
|
1839
2232
|
]
|
|
1840
2233
|
},
|
|
1841
2234
|
opt.key
|
|
1842
2235
|
);
|
|
1843
2236
|
}) }) : null,
|
|
1844
|
-
tags.length > 0 ? /* @__PURE__ */ (0,
|
|
1845
|
-
|
|
1846
|
-
|
|
2237
|
+
tags.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("ul", { "aria-label": "Filter by tag", className: "flex flex-wrap items-center gap-1.5", children: [
|
|
2238
|
+
visibleTags.map((tag) => {
|
|
2239
|
+
const active = activeTags.includes(tag);
|
|
2240
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
2241
|
+
"button",
|
|
2242
|
+
{
|
|
2243
|
+
type: "button",
|
|
2244
|
+
"aria-pressed": active,
|
|
2245
|
+
onClick: () => onToggleTag(tag),
|
|
2246
|
+
className: "cursor-pointer",
|
|
2247
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
2248
|
+
Badge,
|
|
2249
|
+
{
|
|
2250
|
+
variant: "tag",
|
|
2251
|
+
className: cn(
|
|
2252
|
+
active && "border-primary bg-primary text-primary-foreground"
|
|
2253
|
+
),
|
|
2254
|
+
children: tag
|
|
2255
|
+
}
|
|
2256
|
+
)
|
|
2257
|
+
}
|
|
2258
|
+
) }, tag);
|
|
2259
|
+
}),
|
|
2260
|
+
tags.length > TAG_LIMIT ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
1847
2261
|
"button",
|
|
1848
2262
|
{
|
|
1849
2263
|
type: "button",
|
|
1850
|
-
"aria-
|
|
1851
|
-
onClick: () =>
|
|
1852
|
-
className: "cursor-pointer",
|
|
1853
|
-
children:
|
|
2264
|
+
"aria-expanded": showAllTags,
|
|
2265
|
+
onClick: () => setShowAllTags((v) => !v),
|
|
2266
|
+
className: "cursor-pointer rounded-full px-2 py-0.5 text-xs font-medium text-muted-foreground hover:text-foreground",
|
|
2267
|
+
children: tagsCollapsed ? `+${tags.length - TAG_LIMIT} more` : "Show fewer"
|
|
1854
2268
|
}
|
|
1855
|
-
) }
|
|
1856
|
-
|
|
2269
|
+
) }) : null
|
|
2270
|
+
] }) : null
|
|
1857
2271
|
] });
|
|
1858
2272
|
}
|
|
1859
2273
|
|
|
1860
2274
|
// src/interactive/ReportToc.tsx
|
|
1861
|
-
var
|
|
1862
|
-
var
|
|
2275
|
+
var import_react15 = require("react");
|
|
2276
|
+
var import_jsx_runtime42 = require("react/jsx-runtime");
|
|
1863
2277
|
var DOT = {
|
|
1864
|
-
passed: "
|
|
1865
|
-
failed: "
|
|
1866
|
-
skipped: "
|
|
1867
|
-
pending: "
|
|
2278
|
+
passed: "bg-pass",
|
|
2279
|
+
failed: "bg-fail",
|
|
2280
|
+
skipped: "bg-skip",
|
|
2281
|
+
pending: "bg-pend"
|
|
1868
2282
|
};
|
|
1869
|
-
function
|
|
2283
|
+
function TocContent({ onNavigate }) {
|
|
1870
2284
|
const report = useReport();
|
|
1871
|
-
const [activeId, setActiveId] = (0,
|
|
1872
|
-
const scenarioIds = (0,
|
|
2285
|
+
const [activeId, setActiveId] = (0, import_react15.useState)(null);
|
|
2286
|
+
const scenarioIds = (0, import_react15.useMemo)(
|
|
1873
2287
|
() => report.features.flatMap((f) => f.scenarios.map((s) => s.id)),
|
|
1874
2288
|
[report]
|
|
1875
2289
|
);
|
|
1876
|
-
(0,
|
|
2290
|
+
(0, import_react15.useEffect)(() => {
|
|
1877
2291
|
if (typeof IntersectionObserver === "undefined") return;
|
|
1878
2292
|
const els = scenarioIds.map((id) => document.getElementById(id)).filter((el) => el !== null);
|
|
1879
2293
|
if (els.length === 0) return;
|
|
@@ -1888,91 +2302,166 @@ function ReportToc() {
|
|
|
1888
2302
|
return () => observer.disconnect();
|
|
1889
2303
|
}, [scenarioIds]);
|
|
1890
2304
|
if (report.features.length === 0) return null;
|
|
1891
|
-
return /* @__PURE__ */ (0,
|
|
2305
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("ul", { className: "flex list-none flex-col gap-4 pl-0", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("li", { children: [
|
|
2306
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { className: "mb-1.5 font-semibold leading-snug text-foreground", children: feature.title }),
|
|
2307
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("ul", { className: "flex list-none flex-col gap-0.5 pl-0", children: feature.scenarios.map((scenario) => {
|
|
2308
|
+
const active = activeId === scenario.id;
|
|
2309
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
|
|
2310
|
+
"a",
|
|
2311
|
+
{
|
|
2312
|
+
href: `#${scenario.id}`,
|
|
2313
|
+
onClick: (e) => {
|
|
2314
|
+
e.preventDefault();
|
|
2315
|
+
scrollToScenarioId(scenario.id, { updateHash: true });
|
|
2316
|
+
onNavigate?.();
|
|
2317
|
+
},
|
|
2318
|
+
"aria-current": active ? "true" : void 0,
|
|
2319
|
+
className: cn(
|
|
2320
|
+
"flex items-start gap-2 border-l-2 py-1 pl-2.5 leading-snug hover:text-foreground",
|
|
2321
|
+
active ? "border-primary font-medium text-foreground" : "border-border text-muted-foreground"
|
|
2322
|
+
),
|
|
2323
|
+
children: [
|
|
2324
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
2325
|
+
"span",
|
|
2326
|
+
{
|
|
2327
|
+
"aria-hidden": true,
|
|
2328
|
+
className: cn("mt-1 size-1.5 shrink-0 rounded-full", DOT[scenario.status])
|
|
2329
|
+
}
|
|
2330
|
+
),
|
|
2331
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "break-words", children: scenario.title })
|
|
2332
|
+
]
|
|
2333
|
+
}
|
|
2334
|
+
) }, scenario.id);
|
|
2335
|
+
}) })
|
|
2336
|
+
] }, feature.id)) });
|
|
2337
|
+
}
|
|
2338
|
+
function ReportToc() {
|
|
2339
|
+
const report = useReport();
|
|
2340
|
+
if (report.features.length === 0) return null;
|
|
2341
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
|
|
1892
2342
|
"nav",
|
|
1893
2343
|
{
|
|
1894
2344
|
"aria-label": "Table of contents",
|
|
1895
|
-
className: "sticky top-4 hidden h-fit w-
|
|
1896
|
-
children:
|
|
1897
|
-
/* @__PURE__ */ (0,
|
|
1898
|
-
/* @__PURE__ */ (0,
|
|
1899
|
-
|
|
1900
|
-
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
|
|
1901
|
-
"a",
|
|
1902
|
-
{
|
|
1903
|
-
href: `#${scenario.id}`,
|
|
1904
|
-
onClick: (e) => {
|
|
1905
|
-
e.preventDefault();
|
|
1906
|
-
scrollToScenarioId(scenario.id, { updateHash: true });
|
|
1907
|
-
},
|
|
1908
|
-
"aria-current": active ? "true" : void 0,
|
|
1909
|
-
className: cn(
|
|
1910
|
-
"flex items-center gap-1.5 truncate border-l-2 py-0.5 pl-2 hover:text-foreground",
|
|
1911
|
-
active ? "border-primary font-medium text-foreground" : "border-border text-muted-foreground"
|
|
1912
|
-
),
|
|
1913
|
-
children: [
|
|
1914
|
-
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { "aria-hidden": true, className: cn("shrink-0", DOT[scenario.status]), children: "\u2022" }),
|
|
1915
|
-
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "truncate", children: scenario.title })
|
|
1916
|
-
]
|
|
1917
|
-
}
|
|
1918
|
-
) }, scenario.id);
|
|
1919
|
-
}) })
|
|
1920
|
-
] }, feature.id)) })
|
|
2345
|
+
className: "sticky top-4 hidden h-fit w-64 shrink-0 self-start text-xs lg:block",
|
|
2346
|
+
children: [
|
|
2347
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { className: "mb-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Contents" }),
|
|
2348
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(TocContent, {})
|
|
2349
|
+
]
|
|
1921
2350
|
}
|
|
1922
2351
|
);
|
|
1923
2352
|
}
|
|
1924
2353
|
|
|
2354
|
+
// src/interactive/ReportTocDrawer.tsx
|
|
2355
|
+
var import_react16 = require("react");
|
|
2356
|
+
var import_dialog = require("@base-ui/react/dialog");
|
|
2357
|
+
var import_lucide_react4 = require("lucide-react");
|
|
2358
|
+
var import_jsx_runtime43 = require("react/jsx-runtime");
|
|
2359
|
+
function ReportTocDrawer() {
|
|
2360
|
+
const report = useReport();
|
|
2361
|
+
const [open, setOpen] = (0, import_react16.useState)(false);
|
|
2362
|
+
if (report.features.length === 0) return null;
|
|
2363
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_dialog.Dialog.Root, { open, onOpenChange: setOpen, children: [
|
|
2364
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_dialog.Dialog.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: [
|
|
2365
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react4.ListIcon, { "aria-hidden": true }),
|
|
2366
|
+
" Contents"
|
|
2367
|
+
] }),
|
|
2368
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_dialog.Dialog.Portal, { children: [
|
|
2369
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_dialog.Dialog.Backdrop, { className: "fixed inset-0 z-50 bg-black/50 transition-opacity duration-200 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0" }),
|
|
2370
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_dialog.Dialog.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: [
|
|
2371
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
2372
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_dialog.Dialog.Title, { className: "text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Contents" }),
|
|
2373
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
2374
|
+
import_dialog.Dialog.Close,
|
|
2375
|
+
{
|
|
2376
|
+
"aria-label": "Close contents",
|
|
2377
|
+
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
2378
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react4.XIcon, { "aria-hidden": true })
|
|
2379
|
+
}
|
|
2380
|
+
)
|
|
2381
|
+
] }),
|
|
2382
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(TocContent, { onNavigate: () => setOpen(false) })
|
|
2383
|
+
] })
|
|
2384
|
+
] })
|
|
2385
|
+
] });
|
|
2386
|
+
}
|
|
2387
|
+
|
|
1925
2388
|
// src/interactive/use-theme.ts
|
|
1926
|
-
var
|
|
2389
|
+
var import_react17 = require("react");
|
|
1927
2390
|
var KEY = "es-theme";
|
|
1928
|
-
function
|
|
2391
|
+
function systemDark() {
|
|
2392
|
+
return typeof matchMedia !== "undefined" && matchMedia("(prefers-color-scheme: dark)").matches;
|
|
2393
|
+
}
|
|
2394
|
+
function resolve(pref) {
|
|
2395
|
+
return pref === "system" ? systemDark() ? "dark" : "light" : pref;
|
|
2396
|
+
}
|
|
2397
|
+
function applyTheme(pref) {
|
|
1929
2398
|
if (typeof document !== "undefined") {
|
|
1930
|
-
document.documentElement.setAttribute("data-theme",
|
|
2399
|
+
document.documentElement.setAttribute("data-theme", resolve(pref));
|
|
1931
2400
|
}
|
|
1932
2401
|
}
|
|
1933
|
-
function
|
|
2402
|
+
function initialPref() {
|
|
1934
2403
|
if (typeof localStorage !== "undefined") {
|
|
1935
2404
|
const stored = localStorage.getItem(KEY);
|
|
1936
|
-
if (stored === "light" || stored === "dark") return stored;
|
|
1937
|
-
}
|
|
1938
|
-
if (typeof document !== "undefined" && document.documentElement.getAttribute("data-theme") === "dark") {
|
|
1939
|
-
return "dark";
|
|
1940
|
-
}
|
|
1941
|
-
if (typeof matchMedia !== "undefined" && matchMedia("(prefers-color-scheme: dark)").matches) {
|
|
1942
|
-
return "dark";
|
|
2405
|
+
if (stored === "light" || stored === "dark" || stored === "system") return stored;
|
|
1943
2406
|
}
|
|
1944
|
-
return "
|
|
2407
|
+
return "system";
|
|
1945
2408
|
}
|
|
1946
2409
|
function useTheme() {
|
|
1947
|
-
const [
|
|
1948
|
-
(0,
|
|
1949
|
-
const
|
|
1950
|
-
|
|
1951
|
-
applyTheme(
|
|
2410
|
+
const [pref, setPrefState] = (0, import_react17.useState)("system");
|
|
2411
|
+
(0, import_react17.useEffect)(() => {
|
|
2412
|
+
const p = initialPref();
|
|
2413
|
+
setPrefState(p);
|
|
2414
|
+
applyTheme(p);
|
|
1952
2415
|
}, []);
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
2416
|
+
(0, import_react17.useEffect)(() => {
|
|
2417
|
+
if (typeof matchMedia === "undefined") return;
|
|
2418
|
+
const mq = matchMedia("(prefers-color-scheme: dark)");
|
|
2419
|
+
const onChange = () => {
|
|
2420
|
+
if (pref === "system") applyTheme("system");
|
|
2421
|
+
};
|
|
2422
|
+
mq.addEventListener("change", onChange);
|
|
2423
|
+
return () => mq.removeEventListener("change", onChange);
|
|
2424
|
+
}, [pref]);
|
|
2425
|
+
const setPref = (0, import_react17.useCallback)((p) => {
|
|
2426
|
+
setPrefState(p);
|
|
2427
|
+
applyTheme(p);
|
|
2428
|
+
try {
|
|
2429
|
+
localStorage.setItem(KEY, p);
|
|
2430
|
+
} catch {
|
|
2431
|
+
}
|
|
1963
2432
|
}, []);
|
|
1964
|
-
return {
|
|
2433
|
+
return { pref, setPref };
|
|
1965
2434
|
}
|
|
1966
2435
|
|
|
1967
2436
|
// src/interactive/ReportInteractive.tsx
|
|
1968
|
-
var
|
|
2437
|
+
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
1969
2438
|
function ReportInteractive(props) {
|
|
1970
2439
|
const { report, className, title, dataTheme } = props;
|
|
1971
2440
|
const result = unwrapReport(report);
|
|
1972
2441
|
if (!result.ok) {
|
|
1973
|
-
return /* @__PURE__ */ (0,
|
|
2442
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
|
|
1974
2443
|
}
|
|
1975
|
-
return /* @__PURE__ */ (0,
|
|
2444
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportInteractiveView, { ...props, report: result.data });
|
|
2445
|
+
}
|
|
2446
|
+
var THEME_OPTIONS = [
|
|
2447
|
+
{ value: "light", label: "Light", Icon: import_lucide_react5.Sun },
|
|
2448
|
+
{ value: "system", label: "System", Icon: import_lucide_react5.Monitor },
|
|
2449
|
+
{ value: "dark", label: "Dark", Icon: import_lucide_react5.Moon }
|
|
2450
|
+
];
|
|
2451
|
+
function ThemeSegment({ pref, onPref }) {
|
|
2452
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2453
|
+
ToggleGroup,
|
|
2454
|
+
{
|
|
2455
|
+
size: "sm",
|
|
2456
|
+
value: [pref],
|
|
2457
|
+
onValueChange: (v) => {
|
|
2458
|
+
const next = v[0];
|
|
2459
|
+
if (next) onPref(next);
|
|
2460
|
+
},
|
|
2461
|
+
"aria-label": "Color theme",
|
|
2462
|
+
children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ToggleGroupItem, { value, "aria-label": label, title: label, className: "px-2", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Icon, {}) }, value))
|
|
2463
|
+
}
|
|
2464
|
+
);
|
|
1976
2465
|
}
|
|
1977
2466
|
function ReportInteractiveView({
|
|
1978
2467
|
report,
|
|
@@ -1982,24 +2471,29 @@ function ReportInteractiveView({
|
|
|
1982
2471
|
title,
|
|
1983
2472
|
dataTheme,
|
|
1984
2473
|
hideHeader = false,
|
|
2474
|
+
hideToc = false,
|
|
1985
2475
|
staleAfterDays = 7,
|
|
1986
2476
|
scenarioHistory
|
|
1987
2477
|
}) {
|
|
1988
|
-
const [query, setQuery] = (0,
|
|
1989
|
-
const [statusFilter, setStatusFilter] = (0,
|
|
1990
|
-
const [activeTags, setActiveTags] = (0,
|
|
1991
|
-
const [detail, setDetail] = (0,
|
|
1992
|
-
const [helpOpen, setHelpOpen] = (0,
|
|
1993
|
-
const {
|
|
1994
|
-
const searchRef = (0,
|
|
1995
|
-
const
|
|
1996
|
-
const
|
|
1997
|
-
const
|
|
1998
|
-
|
|
2478
|
+
const [query, setQuery] = (0, import_react18.useState)("");
|
|
2479
|
+
const [statusFilter, setStatusFilter] = (0, import_react18.useState)("all");
|
|
2480
|
+
const [activeTags, setActiveTags] = (0, import_react18.useState)([]);
|
|
2481
|
+
const [detail, setDetail] = (0, import_react18.useState)("full");
|
|
2482
|
+
const [helpOpen, setHelpOpen] = (0, import_react18.useState)(false);
|
|
2483
|
+
const { pref: themePref, setPref: setThemePref } = useTheme();
|
|
2484
|
+
const searchRef = (0, import_react18.useRef)(null);
|
|
2485
|
+
const expandId = (0, import_react18.useId)();
|
|
2486
|
+
const docsId = (0, import_react18.useId)();
|
|
2487
|
+
const deferredQuery = (0, import_react18.useDeferredValue)(query);
|
|
2488
|
+
const failures = (0, import_react18.useMemo)(() => listFailures(report), [report]);
|
|
2489
|
+
const filtered = (0, import_react18.useMemo)(
|
|
2490
|
+
// Features carrying failures float to the top so the first thing on screen
|
|
2491
|
+
// is the thing that needs attention; an all-green run keeps source order.
|
|
2492
|
+
() => failuresFirst(filterReport(report, { query: deferredQuery, status: statusFilter, tags: activeTags })),
|
|
1999
2493
|
[report, deferredQuery, statusFilter, activeTags]
|
|
2000
2494
|
);
|
|
2001
2495
|
const isFiltering = query !== deferredQuery;
|
|
2002
|
-
const statusOptions = (0,
|
|
2496
|
+
const statusOptions = (0, import_react18.useMemo)(() => {
|
|
2003
2497
|
const s = report.summary;
|
|
2004
2498
|
const opts = [
|
|
2005
2499
|
{ key: "all", label: "All", count: s.total }
|
|
@@ -2010,19 +2504,19 @@ function ReportInteractiveView({
|
|
|
2010
2504
|
if (s.pending) opts.push({ key: "pending", label: "Pending", count: s.pending });
|
|
2011
2505
|
return opts;
|
|
2012
2506
|
}, [report]);
|
|
2013
|
-
const tagOptions = (0,
|
|
2014
|
-
const toggleTag = (0,
|
|
2507
|
+
const tagOptions = (0, import_react18.useMemo)(() => allTags(report), [report]);
|
|
2508
|
+
const toggleTag = (0, import_react18.useCallback)(
|
|
2015
2509
|
(tag) => setActiveTags((prev) => prev.includes(tag) ? prev.filter((t) => t !== tag) : [...prev, tag]),
|
|
2016
2510
|
[]
|
|
2017
2511
|
);
|
|
2018
|
-
const [toast, setToast] = (0,
|
|
2019
|
-
const toastTimer = (0,
|
|
2020
|
-
const showToast = (0,
|
|
2512
|
+
const [toast, setToast] = (0, import_react18.useState)(null);
|
|
2513
|
+
const toastTimer = (0, import_react18.useRef)(null);
|
|
2514
|
+
const showToast = (0, import_react18.useCallback)((msg) => {
|
|
2021
2515
|
setToast(msg);
|
|
2022
2516
|
if (toastTimer.current) clearTimeout(toastTimer.current);
|
|
2023
2517
|
toastTimer.current = setTimeout(() => setToast(null), 1800);
|
|
2024
2518
|
}, []);
|
|
2025
|
-
const copy = (0,
|
|
2519
|
+
const copy = (0, import_react18.useCallback)(
|
|
2026
2520
|
(text, msg) => {
|
|
2027
2521
|
if (typeof navigator !== "undefined" && navigator.clipboard) {
|
|
2028
2522
|
navigator.clipboard.writeText(text).then(() => showToast(msg), () => showToast("Copy failed"));
|
|
@@ -2030,25 +2524,34 @@ function ReportInteractiveView({
|
|
|
2030
2524
|
},
|
|
2031
2525
|
[showToast]
|
|
2032
2526
|
);
|
|
2033
|
-
const scenarioActions = (0,
|
|
2527
|
+
const scenarioActions = (0, import_react18.useMemo)(
|
|
2034
2528
|
() => ({
|
|
2035
2529
|
copyLink: (s) => copy(scenarioPermalink(s), "Link copied"),
|
|
2036
|
-
copyMarkdown: (s) => copy(
|
|
2530
|
+
copyMarkdown: (s) => copy(scenarioToMarkdown2(s), "Markdown copied"),
|
|
2037
2531
|
copyPrompt: (s) => copy(scenarioToPrompt(s), "Prompt copied")
|
|
2038
2532
|
}),
|
|
2039
2533
|
[copy]
|
|
2040
2534
|
);
|
|
2041
|
-
const failureIndexRef = (0,
|
|
2042
|
-
const
|
|
2043
|
-
const allCollapsibleIds = (0, import_react16.useMemo)(
|
|
2535
|
+
const failureIndexRef = (0, import_react18.useRef)(0);
|
|
2536
|
+
const allCollapsibleIds = (0, import_react18.useMemo)(
|
|
2044
2537
|
() => report.features.flatMap((f) => [f.id, ...f.scenarios.map((s) => s.id)]),
|
|
2045
2538
|
[report]
|
|
2046
2539
|
);
|
|
2047
|
-
const
|
|
2048
|
-
const
|
|
2540
|
+
const collapse = useCollapseState((0, import_react18.useCallback)(() => defaultCollapsedIds(report), [report]));
|
|
2541
|
+
const collapseAll = (0, import_react18.useCallback)(() => collapse.collapseAll(allCollapsibleIds), [collapse, allCollapsibleIds]);
|
|
2542
|
+
const [expandedAll, setExpandedAll] = (0, import_react18.useState)(() => report.summary.failed === 0);
|
|
2543
|
+
const setExpanded = (0, import_react18.useCallback)(
|
|
2544
|
+
(expanded) => {
|
|
2545
|
+
if (expanded) collapse.expandAll();
|
|
2546
|
+
else collapseAll();
|
|
2547
|
+
setExpandedAll(expanded);
|
|
2548
|
+
},
|
|
2549
|
+
[collapse, collapseAll]
|
|
2550
|
+
);
|
|
2551
|
+
const focusSearch = (0, import_react18.useCallback)(() => {
|
|
2049
2552
|
searchRef.current?.focus();
|
|
2050
2553
|
}, []);
|
|
2051
|
-
const stepFailure = (0,
|
|
2554
|
+
const stepFailure = (0, import_react18.useCallback)(
|
|
2052
2555
|
(direction) => {
|
|
2053
2556
|
if (failures.length === 0) return;
|
|
2054
2557
|
failureIndexRef.current = (failureIndexRef.current + direction + failures.length) % failures.length;
|
|
@@ -2057,10 +2560,10 @@ function ReportInteractiveView({
|
|
|
2057
2560
|
},
|
|
2058
2561
|
[failures]
|
|
2059
2562
|
);
|
|
2060
|
-
const toggleHelp = (0,
|
|
2563
|
+
const toggleHelp = (0, import_react18.useCallback)(() => {
|
|
2061
2564
|
setHelpOpen((v) => !v);
|
|
2062
2565
|
}, []);
|
|
2063
|
-
const escape = (0,
|
|
2566
|
+
const escape = (0, import_react18.useCallback)(() => {
|
|
2064
2567
|
if (helpOpen) setHelpOpen(false);
|
|
2065
2568
|
else if (query !== "") setQuery("");
|
|
2066
2569
|
}, [helpOpen, query]);
|
|
@@ -2070,20 +2573,21 @@ function ReportInteractiveView({
|
|
|
2070
2573
|
onPrevFailure: () => stepFailure(-1),
|
|
2071
2574
|
onToggleHelp: toggleHelp,
|
|
2072
2575
|
onEscape: escape,
|
|
2073
|
-
onExpandAll:
|
|
2074
|
-
onCollapseAll:
|
|
2576
|
+
onExpandAll: () => setExpanded(true),
|
|
2577
|
+
onCollapseAll: () => setExpanded(false)
|
|
2075
2578
|
});
|
|
2076
2579
|
useDeepLinkScroll();
|
|
2077
2580
|
const hasContent = filtered.features.length > 0;
|
|
2078
2581
|
const totalScenarios = report.summary.total;
|
|
2079
2582
|
const matchedScenarios = filtered.summary.total;
|
|
2080
|
-
|
|
2583
|
+
const showToc = !hideToc && totalScenarios > 3;
|
|
2584
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(CollapseProvider, { value: collapse.api, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ScenarioActionsProvider, { value: scenarioActions, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ScenarioHistoryProvider, { value: scenarioHistory ?? null, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2081
2585
|
ReportRoot,
|
|
2082
2586
|
{
|
|
2083
2587
|
report: filtered,
|
|
2084
2588
|
customRenderers,
|
|
2085
2589
|
renderers,
|
|
2086
|
-
children: /* @__PURE__ */ (0,
|
|
2590
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
|
|
2087
2591
|
"main",
|
|
2088
2592
|
{
|
|
2089
2593
|
className: cn("es-report", "es-report-interactive", className),
|
|
@@ -2092,9 +2596,38 @@ function ReportInteractiveView({
|
|
|
2092
2596
|
"data-theme": dataTheme,
|
|
2093
2597
|
"data-detail-level": detail,
|
|
2094
2598
|
children: [
|
|
2095
|
-
/* @__PURE__ */ (0,
|
|
2096
|
-
|
|
2097
|
-
|
|
2599
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("header", { className: "es-report-header", children: [
|
|
2600
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
|
|
2601
|
+
"div",
|
|
2602
|
+
{
|
|
2603
|
+
"data-es-navbar": true,
|
|
2604
|
+
className: cn(
|
|
2605
|
+
"flex flex-wrap items-center gap-4",
|
|
2606
|
+
hideHeader ? "justify-end" : "justify-between"
|
|
2607
|
+
),
|
|
2608
|
+
children: [
|
|
2609
|
+
hideHeader ? null : /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("h1", { className: "min-w-0", children: title ?? "Story Report" }),
|
|
2610
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
2611
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2612
|
+
ReportSearch,
|
|
2613
|
+
{
|
|
2614
|
+
ref: searchRef,
|
|
2615
|
+
value: query,
|
|
2616
|
+
onChange: setQuery,
|
|
2617
|
+
matchedCount: matchedScenarios,
|
|
2618
|
+
totalCount: totalScenarios
|
|
2619
|
+
}
|
|
2620
|
+
),
|
|
2621
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ThemeSegment, { pref: themePref, onPref: setThemePref })
|
|
2622
|
+
] })
|
|
2623
|
+
]
|
|
2624
|
+
}
|
|
2625
|
+
),
|
|
2626
|
+
hideHeader ? null : /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(import_jsx_runtime44.Fragment, { children: [
|
|
2627
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportSummary, {}),
|
|
2628
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportMeta, {})
|
|
2629
|
+
] }),
|
|
2630
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2098
2631
|
ReportFreshness,
|
|
2099
2632
|
{
|
|
2100
2633
|
lastRunMs: reportLastRunMs(report),
|
|
@@ -2102,62 +2635,8 @@ function ReportInteractiveView({
|
|
|
2102
2635
|
staleAfterDays
|
|
2103
2636
|
}
|
|
2104
2637
|
),
|
|
2105
|
-
/* @__PURE__ */ (0,
|
|
2106
|
-
/* @__PURE__ */ (0,
|
|
2107
|
-
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
2108
|
-
ReportSearch,
|
|
2109
|
-
{
|
|
2110
|
-
ref: searchRef,
|
|
2111
|
-
value: query,
|
|
2112
|
-
onChange: setQuery,
|
|
2113
|
-
matchedCount: matchedScenarios,
|
|
2114
|
-
totalCount: totalScenarios
|
|
2115
|
-
}
|
|
2116
|
-
),
|
|
2117
|
-
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex shrink-0 gap-1", children: [
|
|
2118
|
-
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
2119
|
-
"button",
|
|
2120
|
-
{
|
|
2121
|
-
type: "button",
|
|
2122
|
-
onClick: collapse.expandAll,
|
|
2123
|
-
"aria-keyshortcuts": "e",
|
|
2124
|
-
className: "cursor-pointer rounded-md border border-border px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
2125
|
-
children: "Expand all"
|
|
2126
|
-
}
|
|
2127
|
-
),
|
|
2128
|
-
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
2129
|
-
"button",
|
|
2130
|
-
{
|
|
2131
|
-
type: "button",
|
|
2132
|
-
onClick: collapseAll,
|
|
2133
|
-
"aria-keyshortcuts": "c",
|
|
2134
|
-
className: "cursor-pointer rounded-md border border-border px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
2135
|
-
children: "Collapse all"
|
|
2136
|
-
}
|
|
2137
|
-
),
|
|
2138
|
-
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
2139
|
-
"button",
|
|
2140
|
-
{
|
|
2141
|
-
type: "button",
|
|
2142
|
-
onClick: () => setDetail((d) => d === "full" ? "minimal" : "full"),
|
|
2143
|
-
"aria-pressed": detail === "minimal",
|
|
2144
|
-
className: "cursor-pointer rounded-md border border-border px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
2145
|
-
children: detail === "full" ? "Hide docs" : "Show docs"
|
|
2146
|
-
}
|
|
2147
|
-
),
|
|
2148
|
-
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
2149
|
-
"button",
|
|
2150
|
-
{
|
|
2151
|
-
type: "button",
|
|
2152
|
-
onClick: toggleTheme,
|
|
2153
|
-
"aria-label": `Switch to ${theme === "dark" ? "light" : "dark"} theme`,
|
|
2154
|
-
className: "cursor-pointer rounded-md border border-border px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
2155
|
-
children: theme === "dark" ? "\u2600 Light" : "\u263E Dark"
|
|
2156
|
-
}
|
|
2157
|
-
)
|
|
2158
|
-
] })
|
|
2159
|
-
] }),
|
|
2160
|
-
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
2638
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportLastRunDelta, { history: scenarioHistory, report }),
|
|
2639
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2161
2640
|
ReportFilters,
|
|
2162
2641
|
{
|
|
2163
2642
|
statuses: statusOptions,
|
|
@@ -2167,26 +2646,44 @@ function ReportInteractiveView({
|
|
|
2167
2646
|
activeTags,
|
|
2168
2647
|
onToggleTag: toggleTag
|
|
2169
2648
|
}
|
|
2170
|
-
)
|
|
2649
|
+
),
|
|
2650
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-2 border-t border-border/60 pt-3", children: [
|
|
2651
|
+
showToc ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportTocDrawer, {}) : null,
|
|
2652
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
2653
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Switch, { id: expandId, checked: expandedAll, onCheckedChange: setExpanded }),
|
|
2654
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("label", { htmlFor: expandId, className: "cursor-pointer text-sm text-muted-foreground select-none", children: "Expand all" })
|
|
2655
|
+
] }),
|
|
2656
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
2657
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2658
|
+
Switch,
|
|
2659
|
+
{
|
|
2660
|
+
id: docsId,
|
|
2661
|
+
checked: detail === "full",
|
|
2662
|
+
onCheckedChange: (checked) => setDetail(checked ? "full" : "minimal")
|
|
2663
|
+
}
|
|
2664
|
+
),
|
|
2665
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("label", { htmlFor: docsId, className: "cursor-pointer text-sm text-muted-foreground select-none", children: "Show documentation" })
|
|
2666
|
+
] })
|
|
2667
|
+
] })
|
|
2171
2668
|
] }),
|
|
2172
|
-
/* @__PURE__ */ (0,
|
|
2173
|
-
hasContent ? /* @__PURE__ */ (0,
|
|
2174
|
-
/* @__PURE__ */ (0,
|
|
2175
|
-
/* @__PURE__ */ (0,
|
|
2176
|
-
] }) : /* @__PURE__ */ (0,
|
|
2177
|
-
/* @__PURE__ */ (0,
|
|
2669
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportFailureBanner, { failures }),
|
|
2670
|
+
hasContent ? showToc ? /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex gap-6", children: [
|
|
2671
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportToc, {}),
|
|
2672
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "flex min-w-0 flex-1 flex-col gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportFeatureList, {}) })
|
|
2673
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportFeatureList, {}) }) : /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportEmpty, { message: query ? "No scenarios match the search." : void 0 }),
|
|
2674
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2178
2675
|
"button",
|
|
2179
2676
|
{
|
|
2180
2677
|
type: "button",
|
|
2181
|
-
className: "es-shortcuts-trigger",
|
|
2678
|
+
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",
|
|
2182
2679
|
"aria-label": "Keyboard shortcuts",
|
|
2183
|
-
"aria-keyshortcuts": "
|
|
2680
|
+
"aria-keyshortcuts": "?",
|
|
2184
2681
|
onClick: toggleHelp,
|
|
2185
2682
|
children: "?"
|
|
2186
2683
|
}
|
|
2187
2684
|
),
|
|
2188
|
-
/* @__PURE__ */ (0,
|
|
2189
|
-
toast ? /* @__PURE__ */ (0,
|
|
2685
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportShortcutsHelp, { open: helpOpen, onClose: () => setHelpOpen(false) }),
|
|
2686
|
+
toast ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2190
2687
|
"div",
|
|
2191
2688
|
{
|
|
2192
2689
|
role: "status",
|
|
@@ -2203,14 +2700,14 @@ function ReportInteractiveView({
|
|
|
2203
2700
|
}
|
|
2204
2701
|
|
|
2205
2702
|
// src/interactive/ReportInteractiveIsland.tsx
|
|
2206
|
-
var
|
|
2703
|
+
var import_react21 = require("react");
|
|
2207
2704
|
|
|
2208
2705
|
// src/interactive/island-renderers.tsx
|
|
2209
|
-
var
|
|
2706
|
+
var import_react20 = require("react");
|
|
2210
2707
|
|
|
2211
2708
|
// src/components/doc/MermaidView.tsx
|
|
2212
|
-
var
|
|
2213
|
-
var
|
|
2709
|
+
var import_react19 = require("react");
|
|
2710
|
+
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
2214
2711
|
function prefersDark(el) {
|
|
2215
2712
|
const themed = el?.closest("[data-theme]");
|
|
2216
2713
|
if (themed?.dataset.theme === "dark") return true;
|
|
@@ -2218,9 +2715,9 @@ function prefersDark(el) {
|
|
|
2218
2715
|
return typeof window !== "undefined" && !!window.matchMedia?.("(prefers-color-scheme: dark)").matches;
|
|
2219
2716
|
}
|
|
2220
2717
|
function MermaidView({ entry, load }) {
|
|
2221
|
-
const ref = (0,
|
|
2222
|
-
const [svg, setSvg] = (0,
|
|
2223
|
-
(0,
|
|
2718
|
+
const ref = (0, import_react19.useRef)(null);
|
|
2719
|
+
const [svg, setSvg] = (0, import_react19.useState)(null);
|
|
2720
|
+
(0, import_react19.useEffect)(() => {
|
|
2224
2721
|
let cancelled = false;
|
|
2225
2722
|
const draw = async () => {
|
|
2226
2723
|
try {
|
|
@@ -2247,9 +2744,9 @@ function MermaidView({ entry, load }) {
|
|
|
2247
2744
|
};
|
|
2248
2745
|
}, [entry.code, load]);
|
|
2249
2746
|
if (svg) {
|
|
2250
|
-
return /* @__PURE__ */ (0,
|
|
2251
|
-
entry.title ? /* @__PURE__ */ (0,
|
|
2252
|
-
/* @__PURE__ */ (0,
|
|
2747
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("figure", { ref, className: "my-3", children: [
|
|
2748
|
+
entry.title ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
|
|
2749
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
2253
2750
|
"div",
|
|
2254
2751
|
{
|
|
2255
2752
|
role: "img",
|
|
@@ -2260,11 +2757,11 @@ function MermaidView({ entry, load }) {
|
|
|
2260
2757
|
)
|
|
2261
2758
|
] });
|
|
2262
2759
|
}
|
|
2263
|
-
return /* @__PURE__ */ (0,
|
|
2760
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(MermaidSource, { entry, ref });
|
|
2264
2761
|
}
|
|
2265
2762
|
|
|
2266
2763
|
// src/interactive/island-renderers.tsx
|
|
2267
|
-
var
|
|
2764
|
+
var import_jsx_runtime46 = require("react/jsx-runtime");
|
|
2268
2765
|
var HLJS_ESM = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/highlight.min.js";
|
|
2269
2766
|
var MERMAID_ESM = "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
|
|
2270
2767
|
function cachedCdnModule(url) {
|
|
@@ -2281,8 +2778,8 @@ function cachedCdnModule(url) {
|
|
|
2281
2778
|
var loadMermaidFromCdn = cachedCdnModule(MERMAID_ESM);
|
|
2282
2779
|
var loadHljs = cachedCdnModule(HLJS_ESM);
|
|
2283
2780
|
function CdnHighlightedCode({ entry }) {
|
|
2284
|
-
const [html, setHtml] = (0,
|
|
2285
|
-
(0,
|
|
2781
|
+
const [html, setHtml] = (0, import_react20.useState)(null);
|
|
2782
|
+
(0, import_react20.useEffect)(() => {
|
|
2286
2783
|
let cancelled = false;
|
|
2287
2784
|
void (async () => {
|
|
2288
2785
|
try {
|
|
@@ -2298,46 +2795,48 @@ function CdnHighlightedCode({ entry }) {
|
|
|
2298
2795
|
cancelled = true;
|
|
2299
2796
|
};
|
|
2300
2797
|
}, [entry.content, entry.lang]);
|
|
2301
|
-
return /* @__PURE__ */ (0,
|
|
2798
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(CodeFigure, { label: entry.label, children: html !== null ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
2302
2799
|
"code",
|
|
2303
2800
|
{
|
|
2304
2801
|
className: cn("hljs font-mono text-xs", entry.lang && `language-${entry.lang}`),
|
|
2305
2802
|
dangerouslySetInnerHTML: { __html: html }
|
|
2306
2803
|
}
|
|
2307
|
-
) : /* @__PURE__ */ (0,
|
|
2804
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
|
|
2308
2805
|
}
|
|
2309
2806
|
function buildIslandRenderers(opts) {
|
|
2310
2807
|
const renderers = {};
|
|
2311
2808
|
if (opts.mermaid) {
|
|
2312
|
-
renderers.mermaid = (entry) => (0,
|
|
2809
|
+
renderers.mermaid = (entry) => (0, import_react20.createElement)(MermaidView, { entry, load: loadMermaidFromCdn });
|
|
2313
2810
|
}
|
|
2314
2811
|
if (opts.syntaxHighlighting) {
|
|
2315
|
-
renderers.code = (entry) => (0,
|
|
2812
|
+
renderers.code = (entry) => (0, import_react20.createElement)(CdnHighlightedCode, { entry });
|
|
2316
2813
|
}
|
|
2317
2814
|
return renderers;
|
|
2318
2815
|
}
|
|
2319
2816
|
|
|
2320
2817
|
// src/interactive/ReportInteractiveIsland.tsx
|
|
2321
|
-
var
|
|
2818
|
+
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
2322
2819
|
function ReportInteractiveIsland({
|
|
2323
2820
|
report,
|
|
2324
2821
|
title,
|
|
2325
2822
|
className,
|
|
2326
2823
|
hideHeader,
|
|
2824
|
+
hideToc,
|
|
2327
2825
|
syntaxHighlighting = true,
|
|
2328
2826
|
mermaid = true
|
|
2329
2827
|
}) {
|
|
2330
|
-
const renderers = (0,
|
|
2828
|
+
const renderers = (0, import_react21.useMemo)(
|
|
2331
2829
|
() => buildIslandRenderers({ syntaxHighlighting, mermaid }),
|
|
2332
2830
|
[syntaxHighlighting, mermaid]
|
|
2333
2831
|
);
|
|
2334
|
-
return /* @__PURE__ */ (0,
|
|
2832
|
+
return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
2335
2833
|
ReportInteractive,
|
|
2336
2834
|
{
|
|
2337
2835
|
report,
|
|
2338
2836
|
title,
|
|
2339
2837
|
className,
|
|
2340
2838
|
hideHeader,
|
|
2839
|
+
hideToc,
|
|
2341
2840
|
renderers
|
|
2342
2841
|
}
|
|
2343
2842
|
);
|