executable-stories-react 0.4.0 → 0.5.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/LICENSE +202 -21
- 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 +843 -471
- 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 +806 -443
- package/dist/interactive.js.map +1 -1
- package/dist/report-island.global.js +103 -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 +2 -2
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: {
|
|
@@ -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) => {
|
|
@@ -926,7 +942,7 @@ function Card({ className, ...props }) {
|
|
|
926
942
|
{
|
|
927
943
|
"data-slot": "card",
|
|
928
944
|
className: cn(
|
|
929
|
-
"flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-
|
|
945
|
+
"flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-xs",
|
|
930
946
|
className
|
|
931
947
|
),
|
|
932
948
|
...props
|
|
@@ -957,52 +973,89 @@ function CardContent({ className, ...props }) {
|
|
|
957
973
|
);
|
|
958
974
|
}
|
|
959
975
|
|
|
960
|
-
// src/components/
|
|
976
|
+
// src/components/ui/dropdown-menu.tsx
|
|
977
|
+
var React3 = require("react");
|
|
978
|
+
var import_menu = require("@base-ui/react/menu");
|
|
979
|
+
var import_lucide_react = require("lucide-react");
|
|
961
980
|
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
|
-
|
|
981
|
+
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";
|
|
982
|
+
function DropdownMenu(props) {
|
|
983
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_menu.Menu.Root, { "data-slot": "dropdown-menu", ...props });
|
|
984
|
+
}
|
|
985
|
+
function DropdownMenuTrigger(props) {
|
|
986
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_menu.Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
|
|
987
|
+
}
|
|
988
|
+
function DropdownMenuContent({
|
|
989
|
+
className,
|
|
990
|
+
align = "end",
|
|
991
|
+
sideOffset = 4,
|
|
992
|
+
...props
|
|
993
|
+
}) {
|
|
994
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_menu.Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
995
|
+
import_menu.Menu.Positioner,
|
|
996
|
+
{
|
|
997
|
+
"data-slot": "dropdown-menu-positioner",
|
|
998
|
+
className: "z-50",
|
|
999
|
+
align,
|
|
1000
|
+
sideOffset,
|
|
1001
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1002
|
+
import_menu.Menu.Popup,
|
|
1003
|
+
{
|
|
1004
|
+
"data-slot": "dropdown-menu-content",
|
|
1005
|
+
className: cn(
|
|
1006
|
+
"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",
|
|
1007
|
+
className
|
|
1008
|
+
),
|
|
1009
|
+
...props
|
|
1010
|
+
}
|
|
1011
|
+
)
|
|
1012
|
+
}
|
|
1013
|
+
) });
|
|
1014
|
+
}
|
|
1015
|
+
function DropdownMenuItem({
|
|
1016
|
+
className,
|
|
1017
|
+
...props
|
|
1018
|
+
}) {
|
|
1019
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1020
|
+
import_menu.Menu.Item,
|
|
1021
|
+
{
|
|
1022
|
+
"data-slot": "dropdown-menu-item",
|
|
1023
|
+
className: cn(itemClasses, className),
|
|
1024
|
+
...props
|
|
1025
|
+
}
|
|
1026
|
+
);
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
// src/components/ReportScenario.tsx
|
|
1030
|
+
var import_lucide_react2 = require("lucide-react");
|
|
1031
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
1032
|
+
var STATUS_META = {
|
|
1033
|
+
passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
|
|
1034
|
+
failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
|
|
1035
|
+
skipped: { label: "Skipped", glyph: "\u25CB", glyphColor: "text-skip", badgeVariant: "skipped", showPill: true },
|
|
1036
|
+
pending: { label: "Pending", glyph: "\u25CB", glyphColor: "text-pend", badgeVariant: "pending", showPill: true }
|
|
985
1037
|
};
|
|
986
1038
|
function ReportScenario({ scenario, hideTitle = false }) {
|
|
987
1039
|
const titleId = `${scenario.id}-title`;
|
|
988
1040
|
const bodyId = `${scenario.id}-body`;
|
|
989
|
-
const
|
|
1041
|
+
const meta = STATUS_META[scenario.status];
|
|
1042
|
+
const label = scenario.planned ? "Planned" : meta.label;
|
|
990
1043
|
const collapse = useCollapse();
|
|
991
1044
|
const collapsible = collapse !== null && !hideTitle;
|
|
992
1045
|
const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
|
|
993
1046
|
const actions = useScenarioActions();
|
|
994
|
-
return /* @__PURE__ */ (0,
|
|
1047
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
995
1048
|
Card,
|
|
996
1049
|
{
|
|
997
1050
|
id: scenario.id,
|
|
998
1051
|
"data-status": scenario.status,
|
|
999
|
-
...hideTitle ? { "aria-label": `${scenario.title}
|
|
1052
|
+
...hideTitle ? { "aria-label": `${scenario.title}, ${label}` } : { "aria-labelledby": titleId },
|
|
1000
1053
|
className: "gap-0 py-0",
|
|
1001
1054
|
children: [
|
|
1002
|
-
/* @__PURE__ */ (0,
|
|
1003
|
-
/* @__PURE__ */ (0,
|
|
1004
|
-
hideTitle ? null : /* @__PURE__ */ (0,
|
|
1005
|
-
collapsible ? /* @__PURE__ */ (0,
|
|
1055
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(CardHeader, { className: "px-4 py-3", children: [
|
|
1056
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
|
|
1057
|
+
hideTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
|
|
1058
|
+
collapsible ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
1006
1059
|
"button",
|
|
1007
1060
|
{
|
|
1008
1061
|
type: "button",
|
|
@@ -1011,60 +1064,49 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1011
1064
|
"aria-controls": bodyId,
|
|
1012
1065
|
"aria-label": `Toggle ${scenario.title}`,
|
|
1013
1066
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
1014
|
-
children: /* @__PURE__ */ (0,
|
|
1067
|
+
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
1068
|
}
|
|
1016
1069
|
) : null,
|
|
1017
|
-
/* @__PURE__ */ (0,
|
|
1018
|
-
/* @__PURE__ */ (0,
|
|
1070
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
|
|
1071
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: scenario.title })
|
|
1019
1072
|
] }),
|
|
1020
|
-
/* @__PURE__ */ (0,
|
|
1021
|
-
/* @__PURE__ */ (0,
|
|
1022
|
-
scenario.durationMs > 0 ? /* @__PURE__ */ (0,
|
|
1023
|
-
/* @__PURE__ */ (0,
|
|
1024
|
-
actions ? /* @__PURE__ */ (0,
|
|
1025
|
-
/* @__PURE__ */ (0,
|
|
1026
|
-
|
|
1027
|
-
{
|
|
1028
|
-
type: "button",
|
|
1029
|
-
onClick: () => actions.copyLink(scenario),
|
|
1030
|
-
"aria-label": `Copy link to ${scenario.title}`,
|
|
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"
|
|
1034
|
-
}
|
|
1035
|
-
),
|
|
1036
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1037
|
-
"button",
|
|
1073
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
1074
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ScenarioRunHistory, { scenarioId: scenario.id }),
|
|
1075
|
+
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,
|
|
1076
|
+
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}` }),
|
|
1077
|
+
actions ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenu, { children: [
|
|
1078
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
1079
|
+
DropdownMenuTrigger,
|
|
1038
1080
|
{
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
"aria-
|
|
1042
|
-
title: "Copy as Markdown",
|
|
1043
|
-
className: "cursor-pointer rounded px-1 py-0.5 font-mono text-[0.625rem] text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
1044
|
-
children: "md"
|
|
1081
|
+
"aria-label": `Actions for ${scenario.title}`,
|
|
1082
|
+
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
1083
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react2.MoreHorizontalIcon, { "aria-hidden": true })
|
|
1045
1084
|
}
|
|
1046
1085
|
),
|
|
1047
|
-
/* @__PURE__ */ (0,
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1086
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenuContent, { align: "end", children: [
|
|
1087
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
|
|
1088
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react2.LinkIcon, {}),
|
|
1089
|
+
" Copy link"
|
|
1090
|
+
] }),
|
|
1091
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
|
|
1092
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react2.FileTextIcon, {}),
|
|
1093
|
+
" Copy as Markdown"
|
|
1094
|
+
] }),
|
|
1095
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
|
|
1096
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react2.SparklesIcon, {}),
|
|
1097
|
+
" Explain with AI"
|
|
1098
|
+
] })
|
|
1099
|
+
] })
|
|
1058
1100
|
] }) : null
|
|
1059
1101
|
] })
|
|
1060
1102
|
] }),
|
|
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,
|
|
1103
|
+
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: [
|
|
1104
|
+
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}`)),
|
|
1105
|
+
(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
1106
|
] }) : null
|
|
1065
1107
|
] }),
|
|
1066
|
-
/* @__PURE__ */ (0,
|
|
1067
|
-
scenario.errorMessage ? /* @__PURE__ */ (0,
|
|
1108
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
|
|
1109
|
+
scenario.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
1068
1110
|
"pre",
|
|
1069
1111
|
{
|
|
1070
1112
|
role: "alert",
|
|
@@ -1072,10 +1114,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1072
1114
|
children: scenario.errorMessage
|
|
1073
1115
|
}
|
|
1074
1116
|
) : null,
|
|
1075
|
-
/* @__PURE__ */ (0,
|
|
1076
|
-
scenario.docEntries.length > 0 ? /* @__PURE__ */ (0,
|
|
1077
|
-
/* @__PURE__ */ (0,
|
|
1078
|
-
/* @__PURE__ */ (0,
|
|
1117
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportSteps, { scenario }),
|
|
1118
|
+
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,
|
|
1119
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportAttachments, { attachments: scenario.attachments }),
|
|
1120
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReportTrace, { spans: scenario.otelSpans })
|
|
1079
1121
|
] })
|
|
1080
1122
|
]
|
|
1081
1123
|
}
|
|
@@ -1083,13 +1125,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1083
1125
|
}
|
|
1084
1126
|
|
|
1085
1127
|
// src/components/ReportScenarioList.tsx
|
|
1086
|
-
var
|
|
1128
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
1087
1129
|
function ReportScenarioList({ feature }) {
|
|
1088
|
-
return /* @__PURE__ */ (0,
|
|
1130
|
+
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
1131
|
}
|
|
1090
1132
|
|
|
1091
1133
|
// src/components/ReportFeature.tsx
|
|
1092
|
-
var
|
|
1134
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1093
1135
|
function ReportFeature({ feature }) {
|
|
1094
1136
|
const titleId = `${feature.id}-title`;
|
|
1095
1137
|
const bodyId = `${feature.id}-body`;
|
|
@@ -1097,74 +1139,80 @@ function ReportFeature({ feature }) {
|
|
|
1097
1139
|
const skipped = s.skipped + s.pending;
|
|
1098
1140
|
const collapse = useCollapse();
|
|
1099
1141
|
const collapsed = collapse?.isCollapsed(feature.id) ?? false;
|
|
1100
|
-
return
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
"
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1142
|
+
return (
|
|
1143
|
+
// Suite = a section heading + a divider, NOT another bordered card. Drops a
|
|
1144
|
+
// layer of nesting so the scenario cards below read as the primary unit.
|
|
1145
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
1146
|
+
"section",
|
|
1147
|
+
{
|
|
1148
|
+
id: feature.id,
|
|
1149
|
+
"data-slot": "feature",
|
|
1150
|
+
"aria-labelledby": titleId,
|
|
1151
|
+
className: "flex flex-col gap-3",
|
|
1152
|
+
children: [
|
|
1153
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
|
|
1154
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "min-w-0", children: [
|
|
1155
|
+
/* @__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)(
|
|
1156
|
+
"button",
|
|
1157
|
+
{
|
|
1158
|
+
type: "button",
|
|
1159
|
+
onClick: () => collapse.toggle(feature.id),
|
|
1160
|
+
"aria-expanded": !collapsed,
|
|
1161
|
+
"aria-controls": bodyId,
|
|
1162
|
+
className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
|
|
1163
|
+
children: [
|
|
1164
|
+
/* @__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" }),
|
|
1165
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "truncate", children: feature.title })
|
|
1166
|
+
]
|
|
1167
|
+
}
|
|
1168
|
+
) : feature.title }),
|
|
1169
|
+
/* @__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 })
|
|
1170
|
+
] }),
|
|
1171
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
1172
|
+
"p",
|
|
1112
1173
|
{
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1174
|
+
className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
|
|
1175
|
+
"aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
|
|
1176
|
+
children: [
|
|
1177
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { children: [
|
|
1178
|
+
s.passed,
|
|
1179
|
+
" passed"
|
|
1180
|
+
] }),
|
|
1181
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1182
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
|
|
1183
|
+
s.failed,
|
|
1184
|
+
" failed"
|
|
1185
|
+
] }),
|
|
1186
|
+
skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
|
|
1187
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1188
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { children: [
|
|
1189
|
+
skipped,
|
|
1190
|
+
" skipped"
|
|
1191
|
+
] })
|
|
1192
|
+
] }) : null
|
|
1193
|
+
]
|
|
1120
1194
|
}
|
|
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
|
-
] })
|
|
1195
|
+
)
|
|
1126
1196
|
] }),
|
|
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
|
-
}
|
|
1197
|
+
/* @__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 }) })
|
|
1198
|
+
]
|
|
1199
|
+
}
|
|
1200
|
+
)
|
|
1153
1201
|
);
|
|
1154
1202
|
}
|
|
1155
1203
|
|
|
1156
1204
|
// src/components/ReportFeatureList.tsx
|
|
1157
|
-
var
|
|
1205
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1158
1206
|
function ReportFeatureList() {
|
|
1159
1207
|
const report = useReport();
|
|
1160
|
-
return /* @__PURE__ */ (0,
|
|
1208
|
+
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
1209
|
}
|
|
1162
1210
|
|
|
1163
1211
|
// src/components/ui/empty.tsx
|
|
1164
1212
|
var import_class_variance_authority2 = require("class-variance-authority");
|
|
1165
|
-
var
|
|
1213
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1166
1214
|
function Empty({ className, ...props }) {
|
|
1167
|
-
return /* @__PURE__ */ (0,
|
|
1215
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1168
1216
|
"div",
|
|
1169
1217
|
{
|
|
1170
1218
|
"data-slot": "empty",
|
|
@@ -1177,7 +1225,7 @@ function Empty({ className, ...props }) {
|
|
|
1177
1225
|
);
|
|
1178
1226
|
}
|
|
1179
1227
|
function EmptyHeader({ className, ...props }) {
|
|
1180
|
-
return /* @__PURE__ */ (0,
|
|
1228
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1181
1229
|
"div",
|
|
1182
1230
|
{
|
|
1183
1231
|
"data-slot": "empty-header",
|
|
@@ -1204,7 +1252,7 @@ var emptyMediaVariants = (0, import_class_variance_authority2.cva)(
|
|
|
1204
1252
|
}
|
|
1205
1253
|
);
|
|
1206
1254
|
function EmptyTitle({ className, ...props }) {
|
|
1207
|
-
return /* @__PURE__ */ (0,
|
|
1255
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1208
1256
|
"div",
|
|
1209
1257
|
{
|
|
1210
1258
|
"data-slot": "empty-title",
|
|
@@ -1215,16 +1263,16 @@ function EmptyTitle({ className, ...props }) {
|
|
|
1215
1263
|
}
|
|
1216
1264
|
|
|
1217
1265
|
// src/components/ReportEmpty.tsx
|
|
1218
|
-
var
|
|
1266
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1219
1267
|
function ReportEmpty({ message }) {
|
|
1220
|
-
return /* @__PURE__ */ (0,
|
|
1268
|
+
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
1269
|
}
|
|
1222
1270
|
|
|
1223
1271
|
// src/components/ReportSummary.tsx
|
|
1224
|
-
var
|
|
1272
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
1225
1273
|
function ReportSummary({ className }) {
|
|
1226
1274
|
const report = useReport();
|
|
1227
|
-
return /* @__PURE__ */ (0,
|
|
1275
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
1228
1276
|
ReportSummaryView,
|
|
1229
1277
|
{
|
|
1230
1278
|
summary: report.summary,
|
|
@@ -1233,38 +1281,54 @@ function ReportSummary({ className }) {
|
|
|
1233
1281
|
}
|
|
1234
1282
|
);
|
|
1235
1283
|
}
|
|
1284
|
+
var TONE = {
|
|
1285
|
+
total: { num: "text-foreground", dot: "bg-muted-foreground/50" },
|
|
1286
|
+
passed: { num: "text-pass", dot: "bg-pass" },
|
|
1287
|
+
failed: { num: "text-fail", dot: "bg-fail" },
|
|
1288
|
+
skipped: { num: "text-skip", dot: "bg-skip" },
|
|
1289
|
+
pending: { num: "text-pend", dot: "bg-pend" }
|
|
1290
|
+
};
|
|
1236
1291
|
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
|
-
|
|
1292
|
+
const cards = [
|
|
1293
|
+
{ status: "total", label: "Total", value: summary.total },
|
|
1294
|
+
{ status: "passed", label: "Passed", value: summary.passed },
|
|
1295
|
+
{ status: "failed", label: "Failed", value: summary.failed },
|
|
1296
|
+
{ status: "skipped", label: "Skipped", value: summary.skipped }
|
|
1297
|
+
];
|
|
1298
|
+
if (summary.pending > 0) {
|
|
1299
|
+
cards.push({ status: "pending", label: "Pending", value: summary.pending });
|
|
1300
|
+
}
|
|
1301
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
1302
|
+
"dl",
|
|
1303
|
+
{
|
|
1304
|
+
className: cn(
|
|
1305
|
+
"grid grid-cols-2 gap-3",
|
|
1306
|
+
// Columns follow the card count so the row is always full — 5 statuses
|
|
1307
|
+
// (pending present) never leave a lone orphan card below a row of four.
|
|
1308
|
+
cards.length === 5 ? "sm:grid-cols-5" : "sm:grid-cols-4",
|
|
1309
|
+
className
|
|
1310
|
+
),
|
|
1311
|
+
"aria-label": ariaLabel,
|
|
1312
|
+
children: cards.map((c) => {
|
|
1313
|
+
const tone = TONE[c.status];
|
|
1314
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
1315
|
+
"div",
|
|
1316
|
+
{
|
|
1317
|
+
"data-status": c.status,
|
|
1318
|
+
className: "rounded-lg border bg-card px-4 py-3",
|
|
1319
|
+
children: [
|
|
1320
|
+
/* @__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: [
|
|
1321
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
|
|
1322
|
+
c.label
|
|
1323
|
+
] }),
|
|
1324
|
+
/* @__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 })
|
|
1325
|
+
]
|
|
1326
|
+
},
|
|
1327
|
+
c.status
|
|
1328
|
+
);
|
|
1329
|
+
})
|
|
1330
|
+
}
|
|
1331
|
+
);
|
|
1268
1332
|
}
|
|
1269
1333
|
|
|
1270
1334
|
// src/lib/provenance.ts
|
|
@@ -1317,7 +1381,7 @@ function prUrl(ci) {
|
|
|
1317
1381
|
}
|
|
1318
1382
|
|
|
1319
1383
|
// src/components/ReportMeta.tsx
|
|
1320
|
-
var
|
|
1384
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
1321
1385
|
function ReportMeta() {
|
|
1322
1386
|
const report = useReport();
|
|
1323
1387
|
const items = [];
|
|
@@ -1340,13 +1404,13 @@ function ReportMeta() {
|
|
|
1340
1404
|
const short = sha.slice(0, 8);
|
|
1341
1405
|
items.push({
|
|
1342
1406
|
label: "Commit",
|
|
1343
|
-
value: url ? /* @__PURE__ */ (0,
|
|
1407
|
+
value: url ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
|
|
1344
1408
|
});
|
|
1345
1409
|
}
|
|
1346
1410
|
if (report.ci) {
|
|
1347
1411
|
items.push({
|
|
1348
1412
|
label: "CI",
|
|
1349
|
-
value: report.ci.url ? /* @__PURE__ */ (0,
|
|
1413
|
+
value: report.ci.url ? /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
|
|
1350
1414
|
ciDisplayName(report.ci.name),
|
|
1351
1415
|
report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
|
|
1352
1416
|
] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
|
|
@@ -1357,59 +1421,172 @@ function ReportMeta() {
|
|
|
1357
1421
|
const label = `#${report.ci.prNumber}`;
|
|
1358
1422
|
items.push({
|
|
1359
1423
|
label: "PR",
|
|
1360
|
-
value: url ? /* @__PURE__ */ (0,
|
|
1424
|
+
value: url ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
|
|
1361
1425
|
});
|
|
1362
1426
|
}
|
|
1363
1427
|
if (items.length === 0) return null;
|
|
1364
|
-
return
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1428
|
+
return (
|
|
1429
|
+
// Run metadata is useful but secondary to "what failed" — tuck it into a
|
|
1430
|
+
// collapsed disclosure so it doesn't push the result down. Native <details>
|
|
1431
|
+
// so it works with no JS (the SSR/no-hydration report still toggles).
|
|
1432
|
+
/* @__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: [
|
|
1433
|
+
/* @__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: [
|
|
1434
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
|
|
1435
|
+
"Run details"
|
|
1436
|
+
] }),
|
|
1437
|
+
/* @__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: [
|
|
1438
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("dt", { className: "font-medium", children: item.label }),
|
|
1439
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("dd", { className: "font-mono text-foreground", children: item.value })
|
|
1440
|
+
] }, item.label)) })
|
|
1441
|
+
] })
|
|
1442
|
+
);
|
|
1368
1443
|
}
|
|
1369
1444
|
|
|
1370
1445
|
// src/components/ReportSchemaError.tsx
|
|
1371
|
-
var
|
|
1446
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
1372
1447
|
function ReportSchemaError({ error }) {
|
|
1373
|
-
return /* @__PURE__ */ (0,
|
|
1374
|
-
/* @__PURE__ */ (0,
|
|
1375
|
-
/* @__PURE__ */ (0,
|
|
1376
|
-
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0,
|
|
1448
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
|
|
1449
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("strong", { children: "Report could not be displayed." }) }),
|
|
1450
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("p", { children: error.message }),
|
|
1451
|
+
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("p", { children: [
|
|
1377
1452
|
"The report bundle is newer than this version of ",
|
|
1378
|
-
/* @__PURE__ */ (0,
|
|
1453
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("code", { children: "executable-stories-react" }),
|
|
1379
1454
|
". Upgrade the package, or regenerate the report with an older formatters CLI."
|
|
1380
1455
|
] }) : null,
|
|
1381
|
-
error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0,
|
|
1382
|
-
/* @__PURE__ */ (0,
|
|
1456
|
+
error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("details", { children: [
|
|
1457
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("summary", { children: [
|
|
1383
1458
|
error.issues.length,
|
|
1384
1459
|
" validation issue",
|
|
1385
1460
|
error.issues.length === 1 ? "" : "s"
|
|
1386
1461
|
] }),
|
|
1387
|
-
/* @__PURE__ */ (0,
|
|
1462
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
|
|
1388
1463
|
] }) : null
|
|
1389
1464
|
] });
|
|
1390
1465
|
}
|
|
1391
1466
|
|
|
1392
1467
|
// 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
|
-
}
|
|
1468
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
1401
1469
|
function ReportErrorShell({
|
|
1402
1470
|
error,
|
|
1403
1471
|
className,
|
|
1404
1472
|
title,
|
|
1405
1473
|
dataTheme
|
|
1406
1474
|
}) {
|
|
1407
|
-
return /* @__PURE__ */ (0,
|
|
1475
|
+
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 }) });
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
// src/interactive/ReportInteractive.tsx
|
|
1479
|
+
var import_lucide_react5 = require("lucide-react");
|
|
1480
|
+
|
|
1481
|
+
// src/components/ui/switch.tsx
|
|
1482
|
+
var React4 = require("react");
|
|
1483
|
+
var import_switch = require("@base-ui/react/switch");
|
|
1484
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
1485
|
+
function Switch({
|
|
1486
|
+
className,
|
|
1487
|
+
...props
|
|
1488
|
+
}) {
|
|
1489
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
1490
|
+
import_switch.Switch.Root,
|
|
1491
|
+
{
|
|
1492
|
+
"data-slot": "switch",
|
|
1493
|
+
className: cn(
|
|
1494
|
+
"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",
|
|
1495
|
+
className
|
|
1496
|
+
),
|
|
1497
|
+
...props,
|
|
1498
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
1499
|
+
import_switch.Switch.Thumb,
|
|
1500
|
+
{
|
|
1501
|
+
"data-slot": "switch-thumb",
|
|
1502
|
+
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"
|
|
1503
|
+
}
|
|
1504
|
+
)
|
|
1505
|
+
}
|
|
1506
|
+
);
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
// src/components/ui/toggle-group.tsx
|
|
1510
|
+
var React5 = __toESM(require("react"), 1);
|
|
1511
|
+
var import_toggle_group = require("@base-ui/react/toggle-group");
|
|
1512
|
+
var import_toggle = require("@base-ui/react/toggle");
|
|
1513
|
+
var import_class_variance_authority3 = require("class-variance-authority");
|
|
1514
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
1515
|
+
var toggleItemVariants = (0, import_class_variance_authority3.cva)(
|
|
1516
|
+
"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",
|
|
1517
|
+
{
|
|
1518
|
+
variants: {
|
|
1519
|
+
size: {
|
|
1520
|
+
default: "h-9 px-3 text-sm",
|
|
1521
|
+
sm: "h-8 px-2.5 text-[0.82rem]"
|
|
1522
|
+
}
|
|
1523
|
+
},
|
|
1524
|
+
defaultVariants: { size: "default" }
|
|
1525
|
+
}
|
|
1526
|
+
);
|
|
1527
|
+
var ToggleGroupContext = React5.createContext({
|
|
1528
|
+
size: "default"
|
|
1529
|
+
});
|
|
1530
|
+
function ToggleGroup({
|
|
1531
|
+
className,
|
|
1532
|
+
size,
|
|
1533
|
+
children,
|
|
1534
|
+
...props
|
|
1535
|
+
}) {
|
|
1536
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
1537
|
+
import_toggle_group.ToggleGroup,
|
|
1538
|
+
{
|
|
1539
|
+
"data-slot": "toggle-group",
|
|
1540
|
+
className: cn("flex w-fit items-center gap-0.5 rounded-lg bg-muted p-0.5", className),
|
|
1541
|
+
...props,
|
|
1542
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ToggleGroupContext.Provider, { value: { size }, children })
|
|
1543
|
+
}
|
|
1544
|
+
);
|
|
1545
|
+
}
|
|
1546
|
+
function ToggleGroupItem({
|
|
1547
|
+
className,
|
|
1548
|
+
children,
|
|
1549
|
+
size,
|
|
1550
|
+
...props
|
|
1551
|
+
}) {
|
|
1552
|
+
const context = React5.useContext(ToggleGroupContext);
|
|
1553
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
1554
|
+
import_toggle.Toggle,
|
|
1555
|
+
{
|
|
1556
|
+
"data-slot": "toggle-group-item",
|
|
1557
|
+
className: cn(toggleItemVariants({ size: context.size ?? size }), "flex-1 shrink-0", className),
|
|
1558
|
+
...props,
|
|
1559
|
+
children
|
|
1560
|
+
}
|
|
1561
|
+
);
|
|
1408
1562
|
}
|
|
1409
1563
|
|
|
1410
1564
|
// src/interactive/ReportSearch.tsx
|
|
1411
1565
|
var import_react8 = require("react");
|
|
1412
|
-
var
|
|
1566
|
+
var import_lucide_react3 = require("lucide-react");
|
|
1567
|
+
|
|
1568
|
+
// src/components/ui/input.tsx
|
|
1569
|
+
var React6 = require("react");
|
|
1570
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
1571
|
+
function Input({ className, type, ...props }) {
|
|
1572
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
1573
|
+
"input",
|
|
1574
|
+
{
|
|
1575
|
+
type,
|
|
1576
|
+
"data-slot": "input",
|
|
1577
|
+
className: cn(
|
|
1578
|
+
"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",
|
|
1579
|
+
"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
|
|
1580
|
+
"aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
|
|
1581
|
+
className
|
|
1582
|
+
),
|
|
1583
|
+
...props
|
|
1584
|
+
}
|
|
1585
|
+
);
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
// src/interactive/ReportSearch.tsx
|
|
1589
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
1413
1590
|
var ReportSearch = (0, import_react8.forwardRef)(
|
|
1414
1591
|
function ReportSearch2(props, ref) {
|
|
1415
1592
|
const {
|
|
@@ -1417,11 +1594,11 @@ var ReportSearch = (0, import_react8.forwardRef)(
|
|
|
1417
1594
|
onChange,
|
|
1418
1595
|
matchedCount,
|
|
1419
1596
|
totalCount,
|
|
1420
|
-
placeholder = "Search scenarios
|
|
1597
|
+
placeholder = "Search scenarios or tags\u2026",
|
|
1421
1598
|
className
|
|
1422
1599
|
} = props;
|
|
1423
1600
|
const inputId = (0, import_react8.useId)();
|
|
1424
|
-
const showCounts = typeof matchedCount === "number" && typeof totalCount === "number";
|
|
1601
|
+
const showCounts = value.trim().length > 0 && typeof matchedCount === "number" && typeof totalCount === "number";
|
|
1425
1602
|
function handleChange(e) {
|
|
1426
1603
|
onChange(e.target.value);
|
|
1427
1604
|
}
|
|
@@ -1431,24 +1608,46 @@ var ReportSearch = (0, import_react8.forwardRef)(
|
|
|
1431
1608
|
e.preventDefault();
|
|
1432
1609
|
}
|
|
1433
1610
|
}
|
|
1434
|
-
return /* @__PURE__ */ (0,
|
|
1435
|
-
/* @__PURE__ */ (0,
|
|
1436
|
-
/* @__PURE__ */ (0,
|
|
1437
|
-
|
|
1611
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: cn("es-search flex flex-col gap-1", className), children: [
|
|
1612
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("label", { htmlFor: inputId, className: "sr-only", children: "Search" }),
|
|
1613
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "relative w-full sm:w-72", children: [
|
|
1614
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
1615
|
+
import_lucide_react3.Search,
|
|
1616
|
+
{
|
|
1617
|
+
"aria-hidden": true,
|
|
1618
|
+
className: "pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground"
|
|
1619
|
+
}
|
|
1620
|
+
),
|
|
1621
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
1622
|
+
Input,
|
|
1623
|
+
{
|
|
1624
|
+
ref,
|
|
1625
|
+
id: inputId,
|
|
1626
|
+
type: "search",
|
|
1627
|
+
value,
|
|
1628
|
+
onChange: handleChange,
|
|
1629
|
+
onKeyDown: handleKeyDown,
|
|
1630
|
+
placeholder,
|
|
1631
|
+
autoComplete: "off",
|
|
1632
|
+
spellCheck: false,
|
|
1633
|
+
"aria-keyshortcuts": "/",
|
|
1634
|
+
className: "pl-8"
|
|
1635
|
+
}
|
|
1636
|
+
)
|
|
1637
|
+
] }),
|
|
1638
|
+
showCounts ? /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
1639
|
+
"span",
|
|
1438
1640
|
{
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
spellCheck: false,
|
|
1448
|
-
"aria-keyshortcuts": "/"
|
|
1641
|
+
className: "text-xs tabular-nums text-muted-foreground",
|
|
1642
|
+
"aria-live": "polite",
|
|
1643
|
+
children: [
|
|
1644
|
+
matchedCount,
|
|
1645
|
+
" of ",
|
|
1646
|
+
totalCount,
|
|
1647
|
+
" scenarios"
|
|
1648
|
+
]
|
|
1449
1649
|
}
|
|
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
|
|
1650
|
+
) : null
|
|
1452
1651
|
] });
|
|
1453
1652
|
}
|
|
1454
1653
|
);
|
|
@@ -1477,7 +1676,7 @@ function scrollToScenarioId(scenarioId, options = {}) {
|
|
|
1477
1676
|
}
|
|
1478
1677
|
|
|
1479
1678
|
// src/interactive/ReportFailureBanner.tsx
|
|
1480
|
-
var
|
|
1679
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
1481
1680
|
function ReportFailureBanner({ failures }) {
|
|
1482
1681
|
const first = failures[0];
|
|
1483
1682
|
const jumpToFirst = (0, import_react9.useCallback)(() => {
|
|
@@ -1485,7 +1684,7 @@ function ReportFailureBanner({ failures }) {
|
|
|
1485
1684
|
scrollToScenarioId(first.scenarioId);
|
|
1486
1685
|
}, [first]);
|
|
1487
1686
|
if (failures.length === 0) return null;
|
|
1488
|
-
return /* @__PURE__ */ (0,
|
|
1687
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
|
|
1489
1688
|
"div",
|
|
1490
1689
|
{
|
|
1491
1690
|
className: "es-failure-banner",
|
|
@@ -1493,20 +1692,20 @@ function ReportFailureBanner({ failures }) {
|
|
|
1493
1692
|
"aria-live": "polite",
|
|
1494
1693
|
"aria-label": "Failure summary",
|
|
1495
1694
|
children: [
|
|
1496
|
-
/* @__PURE__ */ (0,
|
|
1497
|
-
/* @__PURE__ */ (0,
|
|
1695
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { className: "es-failure-banner-text", children: [
|
|
1696
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("strong", { children: failures.length }),
|
|
1498
1697
|
" ",
|
|
1499
1698
|
"failure",
|
|
1500
1699
|
failures.length === 1 ? "" : "s"
|
|
1501
1700
|
] }),
|
|
1502
|
-
/* @__PURE__ */ (0,
|
|
1701
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
1503
1702
|
"button",
|
|
1504
1703
|
{
|
|
1505
1704
|
type: "button",
|
|
1506
1705
|
className: "es-failure-banner-jump",
|
|
1507
1706
|
onClick: jumpToFirst,
|
|
1508
|
-
"aria-label": "
|
|
1509
|
-
children: "
|
|
1707
|
+
"aria-label": "View first failure",
|
|
1708
|
+
children: "View first failure \u2193"
|
|
1510
1709
|
}
|
|
1511
1710
|
)
|
|
1512
1711
|
]
|
|
@@ -1516,7 +1715,7 @@ function ReportFailureBanner({ failures }) {
|
|
|
1516
1715
|
|
|
1517
1716
|
// src/interactive/ReportFreshness.tsx
|
|
1518
1717
|
var import_react10 = require("react");
|
|
1519
|
-
var
|
|
1718
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
1520
1719
|
function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
1521
1720
|
const [now, setNow] = (0, import_react10.useState)(nowMs);
|
|
1522
1721
|
(0, import_react10.useEffect)(() => {
|
|
@@ -1524,7 +1723,7 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
1524
1723
|
}, [nowMs]);
|
|
1525
1724
|
if (lastRunMs === void 0 || now === void 0) return null;
|
|
1526
1725
|
const age = formatRelativeAge(lastRunMs, now);
|
|
1527
|
-
const runLink = ciUrl ? /* @__PURE__ */ (0,
|
|
1726
|
+
const runLink = ciUrl ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
1528
1727
|
"a",
|
|
1529
1728
|
{
|
|
1530
1729
|
href: ciUrl,
|
|
@@ -1535,22 +1734,22 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
1535
1734
|
}
|
|
1536
1735
|
) : null;
|
|
1537
1736
|
if (isReportStale(lastRunMs, staleAfterDays, now)) {
|
|
1538
|
-
return /* @__PURE__ */ (0,
|
|
1539
|
-
/* @__PURE__ */ (0,
|
|
1540
|
-
/* @__PURE__ */ (0,
|
|
1737
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "es-stale-banner", role: "status", "aria-label": "Report freshness", children: [
|
|
1738
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { children: [
|
|
1739
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("strong", { children: [
|
|
1541
1740
|
"Last verified ",
|
|
1542
1741
|
age,
|
|
1543
1742
|
"."
|
|
1544
1743
|
] }),
|
|
1545
|
-
" This report may no longer match the current behavior
|
|
1744
|
+
" This report may no longer match the current behavior. Look for a newer run."
|
|
1546
1745
|
] }),
|
|
1547
1746
|
runLink
|
|
1548
1747
|
] });
|
|
1549
1748
|
}
|
|
1550
|
-
return /* @__PURE__ */ (0,
|
|
1749
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("p", { className: "es-freshness", "aria-label": "Report freshness", children: [
|
|
1551
1750
|
"Verified ",
|
|
1552
1751
|
age,
|
|
1553
|
-
runLink ? /* @__PURE__ */ (0,
|
|
1752
|
+
runLink ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_jsx_runtime38.Fragment, { children: [
|
|
1554
1753
|
" \xB7 ",
|
|
1555
1754
|
runLink
|
|
1556
1755
|
] }) : null
|
|
@@ -1558,15 +1757,15 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
1558
1757
|
}
|
|
1559
1758
|
|
|
1560
1759
|
// src/interactive/ReportLastRunDelta.tsx
|
|
1561
|
-
var
|
|
1760
|
+
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
1562
1761
|
var MAX_LINKS = 5;
|
|
1563
1762
|
function ScenarioLinks({ scenarios, tone }) {
|
|
1564
|
-
return /* @__PURE__ */ (0,
|
|
1565
|
-
scenarios.slice(0, MAX_LINKS).map((s, i) => /* @__PURE__ */ (0,
|
|
1763
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_jsx_runtime39.Fragment, { children: [
|
|
1764
|
+
scenarios.slice(0, MAX_LINKS).map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { children: [
|
|
1566
1765
|
i > 0 ? ", " : "",
|
|
1567
|
-
/* @__PURE__ */ (0,
|
|
1766
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
|
|
1568
1767
|
] }, s.id)),
|
|
1569
|
-
scenarios.length > MAX_LINKS ? /* @__PURE__ */ (0,
|
|
1768
|
+
scenarios.length > MAX_LINKS ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { children: [
|
|
1570
1769
|
" and ",
|
|
1571
1770
|
scenarios.length - MAX_LINKS,
|
|
1572
1771
|
" more"
|
|
@@ -1583,23 +1782,23 @@ function ReportLastRunDelta({
|
|
|
1583
1782
|
if (!delta) return null;
|
|
1584
1783
|
const { newlyFailing, newlyPassing, added } = delta;
|
|
1585
1784
|
if (newlyFailing.length === 0 && newlyPassing.length === 0 && added.length === 0) {
|
|
1586
|
-
return /* @__PURE__ */ (0,
|
|
1785
|
+
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
1786
|
}
|
|
1588
|
-
return /* @__PURE__ */ (0,
|
|
1589
|
-
/* @__PURE__ */ (0,
|
|
1590
|
-
newlyFailing.length > 0 ? /* @__PURE__ */ (0,
|
|
1787
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: [
|
|
1788
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "font-medium text-foreground", children: "Since last run:" }),
|
|
1789
|
+
newlyFailing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "ml-2 text-fail", children: [
|
|
1591
1790
|
newlyFailing.length,
|
|
1592
1791
|
" newly failing (",
|
|
1593
|
-
/* @__PURE__ */ (0,
|
|
1792
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ScenarioLinks, { scenarios: newlyFailing, tone: "text-fail" }),
|
|
1594
1793
|
")"
|
|
1595
1794
|
] }) : null,
|
|
1596
|
-
newlyPassing.length > 0 ? /* @__PURE__ */ (0,
|
|
1795
|
+
newlyPassing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "ml-2 text-pass", children: [
|
|
1597
1796
|
newlyPassing.length,
|
|
1598
1797
|
" fixed (",
|
|
1599
|
-
/* @__PURE__ */ (0,
|
|
1798
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ScenarioLinks, { scenarios: newlyPassing, tone: "text-pass" }),
|
|
1600
1799
|
")"
|
|
1601
1800
|
] }) : null,
|
|
1602
|
-
added.length > 0 ? /* @__PURE__ */ (0,
|
|
1801
|
+
added.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "ml-2", children: [
|
|
1603
1802
|
added.length,
|
|
1604
1803
|
" new"
|
|
1605
1804
|
] }) : null
|
|
@@ -1608,14 +1807,78 @@ function ReportLastRunDelta({
|
|
|
1608
1807
|
|
|
1609
1808
|
// src/interactive/ReportShortcutsHelp.tsx
|
|
1610
1809
|
var import_react11 = require("react");
|
|
1611
|
-
|
|
1810
|
+
|
|
1811
|
+
// src/components/ui/button.tsx
|
|
1812
|
+
var React7 = require("react");
|
|
1813
|
+
var import_class_variance_authority4 = require("class-variance-authority");
|
|
1814
|
+
var import_use_render2 = require("@base-ui/react/use-render");
|
|
1815
|
+
var buttonVariants = (0, import_class_variance_authority4.cva)(
|
|
1816
|
+
"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",
|
|
1817
|
+
{
|
|
1818
|
+
variants: {
|
|
1819
|
+
variant: {
|
|
1820
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
1821
|
+
destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
|
|
1822
|
+
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",
|
|
1823
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
1824
|
+
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
|
1825
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
1826
|
+
},
|
|
1827
|
+
size: {
|
|
1828
|
+
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
1829
|
+
xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
|
|
1830
|
+
sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
|
|
1831
|
+
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
1832
|
+
icon: "size-9",
|
|
1833
|
+
"icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
|
|
1834
|
+
"icon-sm": "size-8",
|
|
1835
|
+
"icon-lg": "size-10"
|
|
1836
|
+
}
|
|
1837
|
+
},
|
|
1838
|
+
defaultVariants: {
|
|
1839
|
+
variant: "default",
|
|
1840
|
+
size: "default"
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
);
|
|
1844
|
+
function Button({
|
|
1845
|
+
className,
|
|
1846
|
+
variant = "default",
|
|
1847
|
+
size = "default",
|
|
1848
|
+
render,
|
|
1849
|
+
...props
|
|
1850
|
+
}) {
|
|
1851
|
+
return (0, import_use_render2.useRender)({
|
|
1852
|
+
defaultTagName: "button",
|
|
1853
|
+
render,
|
|
1854
|
+
props: {
|
|
1855
|
+
"data-slot": "button",
|
|
1856
|
+
"data-variant": variant,
|
|
1857
|
+
"data-size": size,
|
|
1858
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
1859
|
+
...props
|
|
1860
|
+
}
|
|
1861
|
+
});
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1864
|
+
// src/interactive/ReportShortcutsHelp.tsx
|
|
1865
|
+
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
1612
1866
|
var SHORTCUTS = [
|
|
1613
1867
|
{ keys: "/", description: "Focus search" },
|
|
1614
1868
|
{ keys: "f", description: "Jump to next failure" },
|
|
1615
|
-
{ keys: "Shift
|
|
1616
|
-
{ keys: "
|
|
1617
|
-
{ keys: "
|
|
1869
|
+
{ keys: "Shift F", description: "Jump to previous failure" },
|
|
1870
|
+
{ keys: "e", description: "Expand all" },
|
|
1871
|
+
{ keys: "c", description: "Collapse all" },
|
|
1872
|
+
{ keys: "?", description: "Toggle this help" },
|
|
1873
|
+
{ keys: "Esc", description: "Clear search / close" }
|
|
1618
1874
|
];
|
|
1875
|
+
function Keys({ keys }) {
|
|
1876
|
+
const parts = keys.split(" ");
|
|
1877
|
+
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: [
|
|
1878
|
+
i > 0 ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "text-xs text-muted-foreground", children: "+" }) : null,
|
|
1879
|
+
/* @__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 })
|
|
1880
|
+
] }, k)) });
|
|
1881
|
+
}
|
|
1619
1882
|
function ReportShortcutsHelp({ open, onClose }) {
|
|
1620
1883
|
const dialogRef = (0, import_react11.useRef)(null);
|
|
1621
1884
|
(0, import_react11.useEffect)(() => {
|
|
@@ -1624,20 +1887,20 @@ function ReportShortcutsHelp({ open, onClose }) {
|
|
|
1624
1887
|
if (open && !dialog.open) dialog.showModal();
|
|
1625
1888
|
else if (!open && dialog.open) dialog.close();
|
|
1626
1889
|
}, [open]);
|
|
1627
|
-
return /* @__PURE__ */ (0,
|
|
1890
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
|
|
1628
1891
|
"dialog",
|
|
1629
1892
|
{
|
|
1630
1893
|
ref: dialogRef,
|
|
1631
|
-
className: "es-shortcuts-help",
|
|
1894
|
+
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
1895
|
"aria-label": "Keyboard shortcuts",
|
|
1633
1896
|
onClose,
|
|
1634
1897
|
children: [
|
|
1635
|
-
/* @__PURE__ */ (0,
|
|
1636
|
-
/* @__PURE__ */ (0,
|
|
1637
|
-
/* @__PURE__ */ (0,
|
|
1638
|
-
/* @__PURE__ */ (0,
|
|
1898
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("h2", { className: "text-base font-semibold", children: "Keyboard shortcuts" }),
|
|
1899
|
+
/* @__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: [
|
|
1900
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("dt", { className: "justify-self-start", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Keys, { keys: s.keys }) }),
|
|
1901
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("dd", { className: "text-sm text-muted-foreground", children: s.description })
|
|
1639
1902
|
] }, s.keys)) }),
|
|
1640
|
-
/* @__PURE__ */ (0,
|
|
1903
|
+
/* @__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
1904
|
]
|
|
1642
1905
|
}
|
|
1643
1906
|
);
|
|
@@ -1810,7 +2073,9 @@ function listFailures(report) {
|
|
|
1810
2073
|
}
|
|
1811
2074
|
|
|
1812
2075
|
// src/interactive/ReportFilters.tsx
|
|
1813
|
-
var
|
|
2076
|
+
var import_react14 = require("react");
|
|
2077
|
+
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
2078
|
+
var TAG_LIMIT = 12;
|
|
1814
2079
|
function ReportFilters({
|
|
1815
2080
|
statuses,
|
|
1816
2081
|
status,
|
|
@@ -1819,11 +2084,14 @@ function ReportFilters({
|
|
|
1819
2084
|
activeTags,
|
|
1820
2085
|
onToggleTag
|
|
1821
2086
|
}) {
|
|
2087
|
+
const [showAllTags, setShowAllTags] = (0, import_react14.useState)(false);
|
|
1822
2088
|
if (statuses.length === 0 && tags.length === 0) return null;
|
|
1823
|
-
|
|
1824
|
-
|
|
2089
|
+
const tagsCollapsed = tags.length > TAG_LIMIT && !showAllTags;
|
|
2090
|
+
const visibleTags = tagsCollapsed ? tags.slice(0, TAG_LIMIT) : tags;
|
|
2091
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
2092
|
+
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
2093
|
const active = status === opt.key;
|
|
1826
|
-
return /* @__PURE__ */ (0,
|
|
2094
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
|
|
1827
2095
|
"button",
|
|
1828
2096
|
{
|
|
1829
2097
|
type: "button",
|
|
@@ -1835,45 +2103,66 @@ function ReportFilters({
|
|
|
1835
2103
|
),
|
|
1836
2104
|
children: [
|
|
1837
2105
|
opt.label,
|
|
1838
|
-
/* @__PURE__ */ (0,
|
|
2106
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "ml-1 font-mono opacity-70", children: opt.count })
|
|
1839
2107
|
]
|
|
1840
2108
|
},
|
|
1841
2109
|
opt.key
|
|
1842
2110
|
);
|
|
1843
2111
|
}) }) : null,
|
|
1844
|
-
tags.length > 0 ? /* @__PURE__ */ (0,
|
|
1845
|
-
|
|
1846
|
-
|
|
2112
|
+
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: [
|
|
2113
|
+
visibleTags.map((tag) => {
|
|
2114
|
+
const active = activeTags.includes(tag);
|
|
2115
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
2116
|
+
"button",
|
|
2117
|
+
{
|
|
2118
|
+
type: "button",
|
|
2119
|
+
"aria-pressed": active,
|
|
2120
|
+
onClick: () => onToggleTag(tag),
|
|
2121
|
+
className: "cursor-pointer",
|
|
2122
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
2123
|
+
Badge,
|
|
2124
|
+
{
|
|
2125
|
+
variant: "tag",
|
|
2126
|
+
className: cn(
|
|
2127
|
+
active && "border-primary bg-primary text-primary-foreground"
|
|
2128
|
+
),
|
|
2129
|
+
children: tag
|
|
2130
|
+
}
|
|
2131
|
+
)
|
|
2132
|
+
}
|
|
2133
|
+
) }, tag);
|
|
2134
|
+
}),
|
|
2135
|
+
tags.length > TAG_LIMIT ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
1847
2136
|
"button",
|
|
1848
2137
|
{
|
|
1849
2138
|
type: "button",
|
|
1850
|
-
"aria-
|
|
1851
|
-
onClick: () =>
|
|
1852
|
-
className: "cursor-pointer",
|
|
1853
|
-
children:
|
|
2139
|
+
"aria-expanded": showAllTags,
|
|
2140
|
+
onClick: () => setShowAllTags((v) => !v),
|
|
2141
|
+
className: "cursor-pointer rounded-full px-2 py-0.5 text-xs font-medium text-muted-foreground hover:text-foreground",
|
|
2142
|
+
children: tagsCollapsed ? `+${tags.length - TAG_LIMIT} more` : "Show fewer"
|
|
1854
2143
|
}
|
|
1855
|
-
) }
|
|
1856
|
-
|
|
2144
|
+
) }) : null
|
|
2145
|
+
] }) : null
|
|
1857
2146
|
] });
|
|
1858
2147
|
}
|
|
1859
2148
|
|
|
1860
2149
|
// src/interactive/ReportToc.tsx
|
|
1861
|
-
var
|
|
1862
|
-
var
|
|
2150
|
+
var import_react15 = require("react");
|
|
2151
|
+
var import_jsx_runtime42 = require("react/jsx-runtime");
|
|
1863
2152
|
var DOT = {
|
|
1864
|
-
passed: "
|
|
1865
|
-
failed: "
|
|
1866
|
-
skipped: "
|
|
1867
|
-
pending: "
|
|
2153
|
+
passed: "bg-pass",
|
|
2154
|
+
failed: "bg-fail",
|
|
2155
|
+
skipped: "bg-skip",
|
|
2156
|
+
pending: "bg-pend"
|
|
1868
2157
|
};
|
|
1869
|
-
function
|
|
2158
|
+
function TocContent({ onNavigate }) {
|
|
1870
2159
|
const report = useReport();
|
|
1871
|
-
const [activeId, setActiveId] = (0,
|
|
1872
|
-
const scenarioIds = (0,
|
|
2160
|
+
const [activeId, setActiveId] = (0, import_react15.useState)(null);
|
|
2161
|
+
const scenarioIds = (0, import_react15.useMemo)(
|
|
1873
2162
|
() => report.features.flatMap((f) => f.scenarios.map((s) => s.id)),
|
|
1874
2163
|
[report]
|
|
1875
2164
|
);
|
|
1876
|
-
(0,
|
|
2165
|
+
(0, import_react15.useEffect)(() => {
|
|
1877
2166
|
if (typeof IntersectionObserver === "undefined") return;
|
|
1878
2167
|
const els = scenarioIds.map((id) => document.getElementById(id)).filter((el) => el !== null);
|
|
1879
2168
|
if (els.length === 0) return;
|
|
@@ -1888,91 +2177,166 @@ function ReportToc() {
|
|
|
1888
2177
|
return () => observer.disconnect();
|
|
1889
2178
|
}, [scenarioIds]);
|
|
1890
2179
|
if (report.features.length === 0) return null;
|
|
1891
|
-
return /* @__PURE__ */ (0,
|
|
2180
|
+
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: [
|
|
2181
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { className: "mb-1.5 font-semibold leading-snug text-foreground", children: feature.title }),
|
|
2182
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("ul", { className: "flex list-none flex-col gap-0.5 pl-0", children: feature.scenarios.map((scenario) => {
|
|
2183
|
+
const active = activeId === scenario.id;
|
|
2184
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
|
|
2185
|
+
"a",
|
|
2186
|
+
{
|
|
2187
|
+
href: `#${scenario.id}`,
|
|
2188
|
+
onClick: (e) => {
|
|
2189
|
+
e.preventDefault();
|
|
2190
|
+
scrollToScenarioId(scenario.id, { updateHash: true });
|
|
2191
|
+
onNavigate?.();
|
|
2192
|
+
},
|
|
2193
|
+
"aria-current": active ? "true" : void 0,
|
|
2194
|
+
className: cn(
|
|
2195
|
+
"flex items-start gap-2 border-l-2 py-1 pl-2.5 leading-snug hover:text-foreground",
|
|
2196
|
+
active ? "border-primary font-medium text-foreground" : "border-border text-muted-foreground"
|
|
2197
|
+
),
|
|
2198
|
+
children: [
|
|
2199
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
2200
|
+
"span",
|
|
2201
|
+
{
|
|
2202
|
+
"aria-hidden": true,
|
|
2203
|
+
className: cn("mt-1 size-1.5 shrink-0 rounded-full", DOT[scenario.status])
|
|
2204
|
+
}
|
|
2205
|
+
),
|
|
2206
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "break-words", children: scenario.title })
|
|
2207
|
+
]
|
|
2208
|
+
}
|
|
2209
|
+
) }, scenario.id);
|
|
2210
|
+
}) })
|
|
2211
|
+
] }, feature.id)) });
|
|
2212
|
+
}
|
|
2213
|
+
function ReportToc() {
|
|
2214
|
+
const report = useReport();
|
|
2215
|
+
if (report.features.length === 0) return null;
|
|
2216
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
|
|
1892
2217
|
"nav",
|
|
1893
2218
|
{
|
|
1894
2219
|
"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)) })
|
|
2220
|
+
className: "sticky top-4 hidden h-fit w-64 shrink-0 self-start text-xs lg:block",
|
|
2221
|
+
children: [
|
|
2222
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { className: "mb-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Contents" }),
|
|
2223
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(TocContent, {})
|
|
2224
|
+
]
|
|
1921
2225
|
}
|
|
1922
2226
|
);
|
|
1923
2227
|
}
|
|
1924
2228
|
|
|
2229
|
+
// src/interactive/ReportTocDrawer.tsx
|
|
2230
|
+
var import_react16 = require("react");
|
|
2231
|
+
var import_dialog = require("@base-ui/react/dialog");
|
|
2232
|
+
var import_lucide_react4 = require("lucide-react");
|
|
2233
|
+
var import_jsx_runtime43 = require("react/jsx-runtime");
|
|
2234
|
+
function ReportTocDrawer() {
|
|
2235
|
+
const report = useReport();
|
|
2236
|
+
const [open, setOpen] = (0, import_react16.useState)(false);
|
|
2237
|
+
if (report.features.length === 0) return null;
|
|
2238
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_dialog.Dialog.Root, { open, onOpenChange: setOpen, children: [
|
|
2239
|
+
/* @__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: [
|
|
2240
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react4.ListIcon, { "aria-hidden": true }),
|
|
2241
|
+
" Contents"
|
|
2242
|
+
] }),
|
|
2243
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_dialog.Dialog.Portal, { children: [
|
|
2244
|
+
/* @__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" }),
|
|
2245
|
+
/* @__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: [
|
|
2246
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
2247
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_dialog.Dialog.Title, { className: "text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Contents" }),
|
|
2248
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
2249
|
+
import_dialog.Dialog.Close,
|
|
2250
|
+
{
|
|
2251
|
+
"aria-label": "Close contents",
|
|
2252
|
+
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
2253
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react4.XIcon, { "aria-hidden": true })
|
|
2254
|
+
}
|
|
2255
|
+
)
|
|
2256
|
+
] }),
|
|
2257
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(TocContent, { onNavigate: () => setOpen(false) })
|
|
2258
|
+
] })
|
|
2259
|
+
] })
|
|
2260
|
+
] });
|
|
2261
|
+
}
|
|
2262
|
+
|
|
1925
2263
|
// src/interactive/use-theme.ts
|
|
1926
|
-
var
|
|
2264
|
+
var import_react17 = require("react");
|
|
1927
2265
|
var KEY = "es-theme";
|
|
1928
|
-
function
|
|
2266
|
+
function systemDark() {
|
|
2267
|
+
return typeof matchMedia !== "undefined" && matchMedia("(prefers-color-scheme: dark)").matches;
|
|
2268
|
+
}
|
|
2269
|
+
function resolve(pref) {
|
|
2270
|
+
return pref === "system" ? systemDark() ? "dark" : "light" : pref;
|
|
2271
|
+
}
|
|
2272
|
+
function applyTheme(pref) {
|
|
1929
2273
|
if (typeof document !== "undefined") {
|
|
1930
|
-
document.documentElement.setAttribute("data-theme",
|
|
2274
|
+
document.documentElement.setAttribute("data-theme", resolve(pref));
|
|
1931
2275
|
}
|
|
1932
2276
|
}
|
|
1933
|
-
function
|
|
2277
|
+
function initialPref() {
|
|
1934
2278
|
if (typeof localStorage !== "undefined") {
|
|
1935
2279
|
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";
|
|
2280
|
+
if (stored === "light" || stored === "dark" || stored === "system") return stored;
|
|
1940
2281
|
}
|
|
1941
|
-
|
|
1942
|
-
return "dark";
|
|
1943
|
-
}
|
|
1944
|
-
return "light";
|
|
2282
|
+
return "system";
|
|
1945
2283
|
}
|
|
1946
2284
|
function useTheme() {
|
|
1947
|
-
const [
|
|
1948
|
-
(0,
|
|
1949
|
-
const
|
|
1950
|
-
|
|
1951
|
-
applyTheme(
|
|
2285
|
+
const [pref, setPrefState] = (0, import_react17.useState)("system");
|
|
2286
|
+
(0, import_react17.useEffect)(() => {
|
|
2287
|
+
const p = initialPref();
|
|
2288
|
+
setPrefState(p);
|
|
2289
|
+
applyTheme(p);
|
|
1952
2290
|
}, []);
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
2291
|
+
(0, import_react17.useEffect)(() => {
|
|
2292
|
+
if (typeof matchMedia === "undefined") return;
|
|
2293
|
+
const mq = matchMedia("(prefers-color-scheme: dark)");
|
|
2294
|
+
const onChange = () => {
|
|
2295
|
+
if (pref === "system") applyTheme("system");
|
|
2296
|
+
};
|
|
2297
|
+
mq.addEventListener("change", onChange);
|
|
2298
|
+
return () => mq.removeEventListener("change", onChange);
|
|
2299
|
+
}, [pref]);
|
|
2300
|
+
const setPref = (0, import_react17.useCallback)((p) => {
|
|
2301
|
+
setPrefState(p);
|
|
2302
|
+
applyTheme(p);
|
|
2303
|
+
try {
|
|
2304
|
+
localStorage.setItem(KEY, p);
|
|
2305
|
+
} catch {
|
|
2306
|
+
}
|
|
1963
2307
|
}, []);
|
|
1964
|
-
return {
|
|
2308
|
+
return { pref, setPref };
|
|
1965
2309
|
}
|
|
1966
2310
|
|
|
1967
2311
|
// src/interactive/ReportInteractive.tsx
|
|
1968
|
-
var
|
|
2312
|
+
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
1969
2313
|
function ReportInteractive(props) {
|
|
1970
2314
|
const { report, className, title, dataTheme } = props;
|
|
1971
2315
|
const result = unwrapReport(report);
|
|
1972
2316
|
if (!result.ok) {
|
|
1973
|
-
return /* @__PURE__ */ (0,
|
|
2317
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
|
|
1974
2318
|
}
|
|
1975
|
-
return /* @__PURE__ */ (0,
|
|
2319
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportInteractiveView, { ...props, report: result.data });
|
|
2320
|
+
}
|
|
2321
|
+
var THEME_OPTIONS = [
|
|
2322
|
+
{ value: "light", label: "Light", Icon: import_lucide_react5.Sun },
|
|
2323
|
+
{ value: "system", label: "System", Icon: import_lucide_react5.Monitor },
|
|
2324
|
+
{ value: "dark", label: "Dark", Icon: import_lucide_react5.Moon }
|
|
2325
|
+
];
|
|
2326
|
+
function ThemeSegment({ pref, onPref }) {
|
|
2327
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2328
|
+
ToggleGroup,
|
|
2329
|
+
{
|
|
2330
|
+
size: "sm",
|
|
2331
|
+
value: [pref],
|
|
2332
|
+
onValueChange: (v) => {
|
|
2333
|
+
const next = v[0];
|
|
2334
|
+
if (next) onPref(next);
|
|
2335
|
+
},
|
|
2336
|
+
"aria-label": "Color theme",
|
|
2337
|
+
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))
|
|
2338
|
+
}
|
|
2339
|
+
);
|
|
1976
2340
|
}
|
|
1977
2341
|
function ReportInteractiveView({
|
|
1978
2342
|
report,
|
|
@@ -1982,24 +2346,27 @@ function ReportInteractiveView({
|
|
|
1982
2346
|
title,
|
|
1983
2347
|
dataTheme,
|
|
1984
2348
|
hideHeader = false,
|
|
2349
|
+
hideToc = false,
|
|
1985
2350
|
staleAfterDays = 7,
|
|
1986
2351
|
scenarioHistory
|
|
1987
2352
|
}) {
|
|
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
|
|
2353
|
+
const [query, setQuery] = (0, import_react18.useState)("");
|
|
2354
|
+
const [statusFilter, setStatusFilter] = (0, import_react18.useState)("all");
|
|
2355
|
+
const [activeTags, setActiveTags] = (0, import_react18.useState)([]);
|
|
2356
|
+
const [detail, setDetail] = (0, import_react18.useState)("full");
|
|
2357
|
+
const [helpOpen, setHelpOpen] = (0, import_react18.useState)(false);
|
|
2358
|
+
const { pref: themePref, setPref: setThemePref } = useTheme();
|
|
2359
|
+
const searchRef = (0, import_react18.useRef)(null);
|
|
2360
|
+
const expandId = (0, import_react18.useId)();
|
|
2361
|
+
const docsId = (0, import_react18.useId)();
|
|
2362
|
+
const deferredQuery = (0, import_react18.useDeferredValue)(query);
|
|
2363
|
+
const failures = (0, import_react18.useMemo)(() => listFailures(report), [report]);
|
|
2364
|
+
const filtered = (0, import_react18.useMemo)(
|
|
1998
2365
|
() => filterReport(report, { query: deferredQuery, status: statusFilter, tags: activeTags }),
|
|
1999
2366
|
[report, deferredQuery, statusFilter, activeTags]
|
|
2000
2367
|
);
|
|
2001
2368
|
const isFiltering = query !== deferredQuery;
|
|
2002
|
-
const statusOptions = (0,
|
|
2369
|
+
const statusOptions = (0, import_react18.useMemo)(() => {
|
|
2003
2370
|
const s = report.summary;
|
|
2004
2371
|
const opts = [
|
|
2005
2372
|
{ key: "all", label: "All", count: s.total }
|
|
@@ -2010,19 +2377,19 @@ function ReportInteractiveView({
|
|
|
2010
2377
|
if (s.pending) opts.push({ key: "pending", label: "Pending", count: s.pending });
|
|
2011
2378
|
return opts;
|
|
2012
2379
|
}, [report]);
|
|
2013
|
-
const tagOptions = (0,
|
|
2014
|
-
const toggleTag = (0,
|
|
2380
|
+
const tagOptions = (0, import_react18.useMemo)(() => allTags(report), [report]);
|
|
2381
|
+
const toggleTag = (0, import_react18.useCallback)(
|
|
2015
2382
|
(tag) => setActiveTags((prev) => prev.includes(tag) ? prev.filter((t) => t !== tag) : [...prev, tag]),
|
|
2016
2383
|
[]
|
|
2017
2384
|
);
|
|
2018
|
-
const [toast, setToast] = (0,
|
|
2019
|
-
const toastTimer = (0,
|
|
2020
|
-
const showToast = (0,
|
|
2385
|
+
const [toast, setToast] = (0, import_react18.useState)(null);
|
|
2386
|
+
const toastTimer = (0, import_react18.useRef)(null);
|
|
2387
|
+
const showToast = (0, import_react18.useCallback)((msg) => {
|
|
2021
2388
|
setToast(msg);
|
|
2022
2389
|
if (toastTimer.current) clearTimeout(toastTimer.current);
|
|
2023
2390
|
toastTimer.current = setTimeout(() => setToast(null), 1800);
|
|
2024
2391
|
}, []);
|
|
2025
|
-
const copy = (0,
|
|
2392
|
+
const copy = (0, import_react18.useCallback)(
|
|
2026
2393
|
(text, msg) => {
|
|
2027
2394
|
if (typeof navigator !== "undefined" && navigator.clipboard) {
|
|
2028
2395
|
navigator.clipboard.writeText(text).then(() => showToast(msg), () => showToast("Copy failed"));
|
|
@@ -2030,7 +2397,7 @@ function ReportInteractiveView({
|
|
|
2030
2397
|
},
|
|
2031
2398
|
[showToast]
|
|
2032
2399
|
);
|
|
2033
|
-
const scenarioActions = (0,
|
|
2400
|
+
const scenarioActions = (0, import_react18.useMemo)(
|
|
2034
2401
|
() => ({
|
|
2035
2402
|
copyLink: (s) => copy(scenarioPermalink(s), "Link copied"),
|
|
2036
2403
|
copyMarkdown: (s) => copy(scenarioToMarkdown(s), "Markdown copied"),
|
|
@@ -2038,17 +2405,26 @@ function ReportInteractiveView({
|
|
|
2038
2405
|
}),
|
|
2039
2406
|
[copy]
|
|
2040
2407
|
);
|
|
2041
|
-
const failureIndexRef = (0,
|
|
2042
|
-
const
|
|
2043
|
-
const allCollapsibleIds = (0, import_react16.useMemo)(
|
|
2408
|
+
const failureIndexRef = (0, import_react18.useRef)(0);
|
|
2409
|
+
const allCollapsibleIds = (0, import_react18.useMemo)(
|
|
2044
2410
|
() => report.features.flatMap((f) => [f.id, ...f.scenarios.map((s) => s.id)]),
|
|
2045
2411
|
[report]
|
|
2046
2412
|
);
|
|
2047
|
-
const
|
|
2048
|
-
const
|
|
2413
|
+
const collapse = useCollapseState();
|
|
2414
|
+
const collapseAll = (0, import_react18.useCallback)(() => collapse.collapseAll(allCollapsibleIds), [collapse, allCollapsibleIds]);
|
|
2415
|
+
const [expandedAll, setExpandedAll] = (0, import_react18.useState)(true);
|
|
2416
|
+
const setExpanded = (0, import_react18.useCallback)(
|
|
2417
|
+
(expanded) => {
|
|
2418
|
+
if (expanded) collapse.expandAll();
|
|
2419
|
+
else collapseAll();
|
|
2420
|
+
setExpandedAll(expanded);
|
|
2421
|
+
},
|
|
2422
|
+
[collapse, collapseAll]
|
|
2423
|
+
);
|
|
2424
|
+
const focusSearch = (0, import_react18.useCallback)(() => {
|
|
2049
2425
|
searchRef.current?.focus();
|
|
2050
2426
|
}, []);
|
|
2051
|
-
const stepFailure = (0,
|
|
2427
|
+
const stepFailure = (0, import_react18.useCallback)(
|
|
2052
2428
|
(direction) => {
|
|
2053
2429
|
if (failures.length === 0) return;
|
|
2054
2430
|
failureIndexRef.current = (failureIndexRef.current + direction + failures.length) % failures.length;
|
|
@@ -2057,10 +2433,10 @@ function ReportInteractiveView({
|
|
|
2057
2433
|
},
|
|
2058
2434
|
[failures]
|
|
2059
2435
|
);
|
|
2060
|
-
const toggleHelp = (0,
|
|
2436
|
+
const toggleHelp = (0, import_react18.useCallback)(() => {
|
|
2061
2437
|
setHelpOpen((v) => !v);
|
|
2062
2438
|
}, []);
|
|
2063
|
-
const escape = (0,
|
|
2439
|
+
const escape = (0, import_react18.useCallback)(() => {
|
|
2064
2440
|
if (helpOpen) setHelpOpen(false);
|
|
2065
2441
|
else if (query !== "") setQuery("");
|
|
2066
2442
|
}, [helpOpen, query]);
|
|
@@ -2070,20 +2446,21 @@ function ReportInteractiveView({
|
|
|
2070
2446
|
onPrevFailure: () => stepFailure(-1),
|
|
2071
2447
|
onToggleHelp: toggleHelp,
|
|
2072
2448
|
onEscape: escape,
|
|
2073
|
-
onExpandAll:
|
|
2074
|
-
onCollapseAll:
|
|
2449
|
+
onExpandAll: () => setExpanded(true),
|
|
2450
|
+
onCollapseAll: () => setExpanded(false)
|
|
2075
2451
|
});
|
|
2076
2452
|
useDeepLinkScroll();
|
|
2077
2453
|
const hasContent = filtered.features.length > 0;
|
|
2078
2454
|
const totalScenarios = report.summary.total;
|
|
2079
2455
|
const matchedScenarios = filtered.summary.total;
|
|
2080
|
-
|
|
2456
|
+
const showToc = !hideToc && totalScenarios > 3;
|
|
2457
|
+
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
2458
|
ReportRoot,
|
|
2082
2459
|
{
|
|
2083
2460
|
report: filtered,
|
|
2084
2461
|
customRenderers,
|
|
2085
2462
|
renderers,
|
|
2086
|
-
children: /* @__PURE__ */ (0,
|
|
2463
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
|
|
2087
2464
|
"main",
|
|
2088
2465
|
{
|
|
2089
2466
|
className: cn("es-report", "es-report-interactive", className),
|
|
@@ -2092,9 +2469,38 @@ function ReportInteractiveView({
|
|
|
2092
2469
|
"data-theme": dataTheme,
|
|
2093
2470
|
"data-detail-level": detail,
|
|
2094
2471
|
children: [
|
|
2095
|
-
/* @__PURE__ */ (0,
|
|
2096
|
-
|
|
2097
|
-
|
|
2472
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("header", { className: "es-report-header", children: [
|
|
2473
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
|
|
2474
|
+
"div",
|
|
2475
|
+
{
|
|
2476
|
+
"data-es-navbar": true,
|
|
2477
|
+
className: cn(
|
|
2478
|
+
"flex flex-wrap items-center gap-4",
|
|
2479
|
+
hideHeader ? "justify-end" : "justify-between"
|
|
2480
|
+
),
|
|
2481
|
+
children: [
|
|
2482
|
+
hideHeader ? null : /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("h1", { className: "min-w-0", children: title ?? "Story Report" }),
|
|
2483
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
2484
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2485
|
+
ReportSearch,
|
|
2486
|
+
{
|
|
2487
|
+
ref: searchRef,
|
|
2488
|
+
value: query,
|
|
2489
|
+
onChange: setQuery,
|
|
2490
|
+
matchedCount: matchedScenarios,
|
|
2491
|
+
totalCount: totalScenarios
|
|
2492
|
+
}
|
|
2493
|
+
),
|
|
2494
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ThemeSegment, { pref: themePref, onPref: setThemePref })
|
|
2495
|
+
] })
|
|
2496
|
+
]
|
|
2497
|
+
}
|
|
2498
|
+
),
|
|
2499
|
+
hideHeader ? null : /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(import_jsx_runtime44.Fragment, { children: [
|
|
2500
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportSummary, {}),
|
|
2501
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportMeta, {})
|
|
2502
|
+
] }),
|
|
2503
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2098
2504
|
ReportFreshness,
|
|
2099
2505
|
{
|
|
2100
2506
|
lastRunMs: reportLastRunMs(report),
|
|
@@ -2102,62 +2508,8 @@ function ReportInteractiveView({
|
|
|
2102
2508
|
staleAfterDays
|
|
2103
2509
|
}
|
|
2104
2510
|
),
|
|
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)(
|
|
2511
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportLastRunDelta, { history: scenarioHistory, report }),
|
|
2512
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2161
2513
|
ReportFilters,
|
|
2162
2514
|
{
|
|
2163
2515
|
statuses: statusOptions,
|
|
@@ -2167,26 +2519,44 @@ function ReportInteractiveView({
|
|
|
2167
2519
|
activeTags,
|
|
2168
2520
|
onToggleTag: toggleTag
|
|
2169
2521
|
}
|
|
2170
|
-
)
|
|
2522
|
+
),
|
|
2523
|
+
/* @__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: [
|
|
2524
|
+
showToc ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportTocDrawer, {}) : null,
|
|
2525
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
2526
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Switch, { id: expandId, checked: expandedAll, onCheckedChange: setExpanded }),
|
|
2527
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("label", { htmlFor: expandId, className: "cursor-pointer text-sm text-muted-foreground select-none", children: "Expand all" })
|
|
2528
|
+
] }),
|
|
2529
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
2530
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2531
|
+
Switch,
|
|
2532
|
+
{
|
|
2533
|
+
id: docsId,
|
|
2534
|
+
checked: detail === "full",
|
|
2535
|
+
onCheckedChange: (checked) => setDetail(checked ? "full" : "minimal")
|
|
2536
|
+
}
|
|
2537
|
+
),
|
|
2538
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("label", { htmlFor: docsId, className: "cursor-pointer text-sm text-muted-foreground select-none", children: "Show documentation" })
|
|
2539
|
+
] })
|
|
2540
|
+
] })
|
|
2171
2541
|
] }),
|
|
2172
|
-
/* @__PURE__ */ (0,
|
|
2173
|
-
hasContent ? /* @__PURE__ */ (0,
|
|
2174
|
-
/* @__PURE__ */ (0,
|
|
2175
|
-
/* @__PURE__ */ (0,
|
|
2176
|
-
] }) : /* @__PURE__ */ (0,
|
|
2177
|
-
/* @__PURE__ */ (0,
|
|
2542
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportFailureBanner, { failures }),
|
|
2543
|
+
hasContent ? showToc ? /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex gap-6", children: [
|
|
2544
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportToc, {}),
|
|
2545
|
+
/* @__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, {}) })
|
|
2546
|
+
] }) : /* @__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 }),
|
|
2547
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2178
2548
|
"button",
|
|
2179
2549
|
{
|
|
2180
2550
|
type: "button",
|
|
2181
|
-
className: "es-shortcuts-trigger",
|
|
2551
|
+
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
2552
|
"aria-label": "Keyboard shortcuts",
|
|
2183
|
-
"aria-keyshortcuts": "
|
|
2553
|
+
"aria-keyshortcuts": "?",
|
|
2184
2554
|
onClick: toggleHelp,
|
|
2185
2555
|
children: "?"
|
|
2186
2556
|
}
|
|
2187
2557
|
),
|
|
2188
|
-
/* @__PURE__ */ (0,
|
|
2189
|
-
toast ? /* @__PURE__ */ (0,
|
|
2558
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ReportShortcutsHelp, { open: helpOpen, onClose: () => setHelpOpen(false) }),
|
|
2559
|
+
toast ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
2190
2560
|
"div",
|
|
2191
2561
|
{
|
|
2192
2562
|
role: "status",
|
|
@@ -2203,14 +2573,14 @@ function ReportInteractiveView({
|
|
|
2203
2573
|
}
|
|
2204
2574
|
|
|
2205
2575
|
// src/interactive/ReportInteractiveIsland.tsx
|
|
2206
|
-
var
|
|
2576
|
+
var import_react21 = require("react");
|
|
2207
2577
|
|
|
2208
2578
|
// src/interactive/island-renderers.tsx
|
|
2209
|
-
var
|
|
2579
|
+
var import_react20 = require("react");
|
|
2210
2580
|
|
|
2211
2581
|
// src/components/doc/MermaidView.tsx
|
|
2212
|
-
var
|
|
2213
|
-
var
|
|
2582
|
+
var import_react19 = require("react");
|
|
2583
|
+
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
2214
2584
|
function prefersDark(el) {
|
|
2215
2585
|
const themed = el?.closest("[data-theme]");
|
|
2216
2586
|
if (themed?.dataset.theme === "dark") return true;
|
|
@@ -2218,9 +2588,9 @@ function prefersDark(el) {
|
|
|
2218
2588
|
return typeof window !== "undefined" && !!window.matchMedia?.("(prefers-color-scheme: dark)").matches;
|
|
2219
2589
|
}
|
|
2220
2590
|
function MermaidView({ entry, load }) {
|
|
2221
|
-
const ref = (0,
|
|
2222
|
-
const [svg, setSvg] = (0,
|
|
2223
|
-
(0,
|
|
2591
|
+
const ref = (0, import_react19.useRef)(null);
|
|
2592
|
+
const [svg, setSvg] = (0, import_react19.useState)(null);
|
|
2593
|
+
(0, import_react19.useEffect)(() => {
|
|
2224
2594
|
let cancelled = false;
|
|
2225
2595
|
const draw = async () => {
|
|
2226
2596
|
try {
|
|
@@ -2247,9 +2617,9 @@ function MermaidView({ entry, load }) {
|
|
|
2247
2617
|
};
|
|
2248
2618
|
}, [entry.code, load]);
|
|
2249
2619
|
if (svg) {
|
|
2250
|
-
return /* @__PURE__ */ (0,
|
|
2251
|
-
entry.title ? /* @__PURE__ */ (0,
|
|
2252
|
-
/* @__PURE__ */ (0,
|
|
2620
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("figure", { ref, className: "my-3", children: [
|
|
2621
|
+
entry.title ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
|
|
2622
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
2253
2623
|
"div",
|
|
2254
2624
|
{
|
|
2255
2625
|
role: "img",
|
|
@@ -2260,11 +2630,11 @@ function MermaidView({ entry, load }) {
|
|
|
2260
2630
|
)
|
|
2261
2631
|
] });
|
|
2262
2632
|
}
|
|
2263
|
-
return /* @__PURE__ */ (0,
|
|
2633
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(MermaidSource, { entry, ref });
|
|
2264
2634
|
}
|
|
2265
2635
|
|
|
2266
2636
|
// src/interactive/island-renderers.tsx
|
|
2267
|
-
var
|
|
2637
|
+
var import_jsx_runtime46 = require("react/jsx-runtime");
|
|
2268
2638
|
var HLJS_ESM = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/highlight.min.js";
|
|
2269
2639
|
var MERMAID_ESM = "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
|
|
2270
2640
|
function cachedCdnModule(url) {
|
|
@@ -2281,8 +2651,8 @@ function cachedCdnModule(url) {
|
|
|
2281
2651
|
var loadMermaidFromCdn = cachedCdnModule(MERMAID_ESM);
|
|
2282
2652
|
var loadHljs = cachedCdnModule(HLJS_ESM);
|
|
2283
2653
|
function CdnHighlightedCode({ entry }) {
|
|
2284
|
-
const [html, setHtml] = (0,
|
|
2285
|
-
(0,
|
|
2654
|
+
const [html, setHtml] = (0, import_react20.useState)(null);
|
|
2655
|
+
(0, import_react20.useEffect)(() => {
|
|
2286
2656
|
let cancelled = false;
|
|
2287
2657
|
void (async () => {
|
|
2288
2658
|
try {
|
|
@@ -2298,46 +2668,48 @@ function CdnHighlightedCode({ entry }) {
|
|
|
2298
2668
|
cancelled = true;
|
|
2299
2669
|
};
|
|
2300
2670
|
}, [entry.content, entry.lang]);
|
|
2301
|
-
return /* @__PURE__ */ (0,
|
|
2671
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(CodeFigure, { label: entry.label, children: html !== null ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
2302
2672
|
"code",
|
|
2303
2673
|
{
|
|
2304
2674
|
className: cn("hljs font-mono text-xs", entry.lang && `language-${entry.lang}`),
|
|
2305
2675
|
dangerouslySetInnerHTML: { __html: html }
|
|
2306
2676
|
}
|
|
2307
|
-
) : /* @__PURE__ */ (0,
|
|
2677
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
|
|
2308
2678
|
}
|
|
2309
2679
|
function buildIslandRenderers(opts) {
|
|
2310
2680
|
const renderers = {};
|
|
2311
2681
|
if (opts.mermaid) {
|
|
2312
|
-
renderers.mermaid = (entry) => (0,
|
|
2682
|
+
renderers.mermaid = (entry) => (0, import_react20.createElement)(MermaidView, { entry, load: loadMermaidFromCdn });
|
|
2313
2683
|
}
|
|
2314
2684
|
if (opts.syntaxHighlighting) {
|
|
2315
|
-
renderers.code = (entry) => (0,
|
|
2685
|
+
renderers.code = (entry) => (0, import_react20.createElement)(CdnHighlightedCode, { entry });
|
|
2316
2686
|
}
|
|
2317
2687
|
return renderers;
|
|
2318
2688
|
}
|
|
2319
2689
|
|
|
2320
2690
|
// src/interactive/ReportInteractiveIsland.tsx
|
|
2321
|
-
var
|
|
2691
|
+
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
2322
2692
|
function ReportInteractiveIsland({
|
|
2323
2693
|
report,
|
|
2324
2694
|
title,
|
|
2325
2695
|
className,
|
|
2326
2696
|
hideHeader,
|
|
2697
|
+
hideToc,
|
|
2327
2698
|
syntaxHighlighting = true,
|
|
2328
2699
|
mermaid = true
|
|
2329
2700
|
}) {
|
|
2330
|
-
const renderers = (0,
|
|
2701
|
+
const renderers = (0, import_react21.useMemo)(
|
|
2331
2702
|
() => buildIslandRenderers({ syntaxHighlighting, mermaid }),
|
|
2332
2703
|
[syntaxHighlighting, mermaid]
|
|
2333
2704
|
);
|
|
2334
|
-
return /* @__PURE__ */ (0,
|
|
2705
|
+
return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
2335
2706
|
ReportInteractive,
|
|
2336
2707
|
{
|
|
2337
2708
|
report,
|
|
2338
2709
|
title,
|
|
2339
2710
|
className,
|
|
2340
2711
|
hideHeader,
|
|
2712
|
+
hideToc,
|
|
2341
2713
|
renderers
|
|
2342
2714
|
}
|
|
2343
2715
|
);
|