executable-stories-react 0.12.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +73 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +73 -52
- package/dist/index.js.map +1 -1
- package/dist/interactive.cjs +737 -260
- package/dist/interactive.cjs.map +1 -1
- package/dist/interactive.d.cts +3 -1
- package/dist/interactive.d.ts +3 -1
- package/dist/interactive.js +698 -215
- package/dist/interactive.js.map +1 -1
- package/dist/report-island.global.js +65 -54
- package/dist/ssr.cjs +74 -53
- package/dist/ssr.cjs.map +1 -1
- package/dist/ssr.js +74 -53
- package/dist/ssr.js.map +1 -1
- package/dist/styles.css +1 -3
- package/dist/tailwind.css +2 -2
- package/package.json +24 -23
package/dist/interactive.js
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
// src/interactive/ReportInteractive.tsx
|
|
4
4
|
import { Monitor, Moon, Sun } from "lucide-react";
|
|
5
|
+
import { useTools } from "webmcpable/react";
|
|
5
6
|
import {
|
|
6
7
|
useCallback as useCallback5,
|
|
7
8
|
useDeferredValue,
|
|
8
9
|
useId as useId2,
|
|
9
10
|
useMemo as useMemo3,
|
|
10
11
|
useRef as useRef5,
|
|
11
|
-
useState as
|
|
12
|
+
useState as useState10
|
|
12
13
|
} from "react";
|
|
13
14
|
|
|
14
15
|
// src/components/ui/empty.tsx
|
|
@@ -205,7 +206,7 @@ function formatValue(value) {
|
|
|
205
206
|
function DocKv({ entry }) {
|
|
206
207
|
return /* @__PURE__ */ jsxs("dl", { className: "my-2 flex flex-wrap items-baseline gap-x-2 text-sm", children: [
|
|
207
208
|
/* @__PURE__ */ jsx6("dt", { className: "font-semibold text-muted-foreground", children: entry.label }),
|
|
208
|
-
/* @__PURE__ */ jsx6("dd", { className: "font-mono text-foreground", children: formatValue(entry.value) })
|
|
209
|
+
/* @__PURE__ */ jsx6("dd", { className: "min-w-0 break-words font-mono text-foreground", children: formatValue(entry.value) })
|
|
209
210
|
] });
|
|
210
211
|
}
|
|
211
212
|
|
|
@@ -413,7 +414,7 @@ function DocHtml({ entry }) {
|
|
|
413
414
|
loading: "lazy",
|
|
414
415
|
title,
|
|
415
416
|
className: "block w-full border-0",
|
|
416
|
-
style: { height }
|
|
417
|
+
style: { height, colorScheme: "light", background: "#fff" }
|
|
417
418
|
}
|
|
418
419
|
)
|
|
419
420
|
] });
|
|
@@ -1137,6 +1138,24 @@ function scenarioToPrompt(scenario) {
|
|
|
1137
1138
|
}
|
|
1138
1139
|
return lines.join("\n");
|
|
1139
1140
|
}
|
|
1141
|
+
function failuresToPrompt(scenarios) {
|
|
1142
|
+
if (scenarios.length === 0) return "";
|
|
1143
|
+
const noun = scenarios.length === 1 ? "test scenario is" : "test scenarios are";
|
|
1144
|
+
const lines = [
|
|
1145
|
+
`${scenarios.length} ${noun} failing. Investigate the likely cause (they may share one) and propose a fix.`
|
|
1146
|
+
];
|
|
1147
|
+
scenarios.forEach((scenario, i) => {
|
|
1148
|
+
lines.push("", `${i + 1}. ${scenario.title}`, "Steps:");
|
|
1149
|
+
for (const step of scenario.steps) {
|
|
1150
|
+
const mark = step.status === "failed" ? " \u27F5 failed here" : "";
|
|
1151
|
+
lines.push(` ${step.keyword} ${step.text}${mark}`);
|
|
1152
|
+
}
|
|
1153
|
+
if (scenario.errorMessage) {
|
|
1154
|
+
lines.push("Error:", scenario.errorMessage.trim());
|
|
1155
|
+
}
|
|
1156
|
+
});
|
|
1157
|
+
return lines.join("\n");
|
|
1158
|
+
}
|
|
1140
1159
|
function scenarioPermalink(scenario) {
|
|
1141
1160
|
if (typeof location === "undefined") return `#${scenario.id}`;
|
|
1142
1161
|
return `${location.href.split("#")[0]}#${scenario.id}`;
|
|
@@ -1262,57 +1281,68 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1262
1281
|
className: "gap-0 py-0",
|
|
1263
1282
|
children: [
|
|
1264
1283
|
/* @__PURE__ */ jsxs17(CardHeader, { className: "px-4 py-3", children: [
|
|
1265
|
-
/* @__PURE__ */ jsxs17(
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
}
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1284
|
+
/* @__PURE__ */ jsxs17(
|
|
1285
|
+
"div",
|
|
1286
|
+
{
|
|
1287
|
+
className: cn(
|
|
1288
|
+
// Wraps rather than squeezing: on a phone the status/duration group
|
|
1289
|
+
// is ~160px, which leaves a title column a few characters wide.
|
|
1290
|
+
"flex flex-wrap items-start gap-x-4 gap-y-1",
|
|
1291
|
+
hideTitle ? "justify-end" : "justify-between"
|
|
1292
|
+
),
|
|
1293
|
+
children: [
|
|
1294
|
+
hideTitle ? null : /* @__PURE__ */ jsxs17("h3", { id: titleId, className: "flex min-w-0 flex-1 basis-48 items-center gap-2 text-sm font-medium text-foreground", children: [
|
|
1295
|
+
collapsible ? /* @__PURE__ */ jsx26(
|
|
1296
|
+
"button",
|
|
1297
|
+
{
|
|
1298
|
+
type: "button",
|
|
1299
|
+
onClick: () => collapse.toggle(scenario.id),
|
|
1300
|
+
"aria-expanded": !collapsed,
|
|
1301
|
+
"aria-controls": bodyId,
|
|
1302
|
+
"aria-label": `Toggle ${scenario.title}`,
|
|
1303
|
+
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
1304
|
+
children: /* @__PURE__ */ jsx26("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
1305
|
+
}
|
|
1306
|
+
) : null,
|
|
1307
|
+
/* @__PURE__ */ jsx26("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
|
|
1308
|
+
/* @__PURE__ */ jsx26("span", { children: scenario.title })
|
|
1309
|
+
] }),
|
|
1310
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
1311
|
+
/* @__PURE__ */ jsx26(ScenarioRunHistory, { scenarioId: scenario.id }),
|
|
1312
|
+
/* @__PURE__ */ jsx26(ScenarioStaleness, { scenario }),
|
|
1313
|
+
scenario.durationMs > 0 ? /* @__PURE__ */ jsx26("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration3(scenario.durationMs) }) : null,
|
|
1314
|
+
meta.showPill ? /* @__PURE__ */ jsx26(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ jsx26("span", { className: "sr-only", children: `Status: ${label}` }),
|
|
1315
|
+
actions ? /* @__PURE__ */ jsxs17(DropdownMenu, { children: [
|
|
1316
|
+
/* @__PURE__ */ jsx26(
|
|
1317
|
+
DropdownMenuTrigger,
|
|
1318
|
+
{
|
|
1319
|
+
"aria-label": `Actions for ${scenario.title}`,
|
|
1320
|
+
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
1321
|
+
children: /* @__PURE__ */ jsx26(MoreHorizontalIcon, { "aria-hidden": true })
|
|
1322
|
+
}
|
|
1323
|
+
),
|
|
1324
|
+
/* @__PURE__ */ jsxs17(DropdownMenuContent, { align: "end", children: [
|
|
1325
|
+
/* @__PURE__ */ jsxs17(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
|
|
1326
|
+
/* @__PURE__ */ jsx26(LinkIcon, {}),
|
|
1327
|
+
" Copy link"
|
|
1328
|
+
] }),
|
|
1329
|
+
/* @__PURE__ */ jsxs17(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
|
|
1330
|
+
/* @__PURE__ */ jsx26(FileTextIcon, {}),
|
|
1331
|
+
" Copy as Markdown"
|
|
1332
|
+
] }),
|
|
1333
|
+
/* @__PURE__ */ jsxs17(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
|
|
1334
|
+
/* @__PURE__ */ jsx26(SparklesIcon, {}),
|
|
1335
|
+
" Explain with AI"
|
|
1336
|
+
] })
|
|
1337
|
+
] })
|
|
1338
|
+
] }) : null
|
|
1309
1339
|
] })
|
|
1310
|
-
]
|
|
1311
|
-
|
|
1312
|
-
|
|
1340
|
+
]
|
|
1341
|
+
}
|
|
1342
|
+
),
|
|
1313
1343
|
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ jsxs17("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
|
|
1314
1344
|
scenario.tags.map((t) => /* @__PURE__ */ jsx26("li", { children: /* @__PURE__ */ jsx26(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
|
|
1315
|
-
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ jsx26("li", { children: ticket.url ? /* @__PURE__ */ jsx26("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ jsx26(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ jsx26(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
|
|
1345
|
+
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ jsx26("li", { children: ticket.url ? /* @__PURE__ */ jsx26("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", className: "inline-flex min-h-6 items-center", children: /* @__PURE__ */ jsx26(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ jsx26(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
|
|
1316
1346
|
] }) : null
|
|
1317
1347
|
] }),
|
|
1318
1348
|
/* @__PURE__ */ jsxs17(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
|
|
@@ -1455,6 +1485,7 @@ function ReportFeatureList() {
|
|
|
1455
1485
|
|
|
1456
1486
|
// src/components/ReportMeta.tsx
|
|
1457
1487
|
import { formatDuration as formatDuration4 } from "executable-stories-core/utils/duration";
|
|
1488
|
+
import { slowestScenarios } from "executable-stories-core/report-queries";
|
|
1458
1489
|
import { jsx as jsx31, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1459
1490
|
function ReportMeta() {
|
|
1460
1491
|
const report = useReport();
|
|
@@ -1498,7 +1529,9 @@ function ReportMeta() {
|
|
|
1498
1529
|
value: url ? /* @__PURE__ */ jsx31("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
|
|
1499
1530
|
});
|
|
1500
1531
|
}
|
|
1501
|
-
|
|
1532
|
+
const slowest = slowestScenarios(report, 5);
|
|
1533
|
+
const showSlowest = slowest.length >= 3;
|
|
1534
|
+
if (items.length === 0 && !showSlowest) return null;
|
|
1502
1535
|
return (
|
|
1503
1536
|
// Run metadata is useful but secondary to "what failed" — tuck it into a
|
|
1504
1537
|
// collapsed disclosure so it doesn't push the result down. Native <details>
|
|
@@ -1511,7 +1544,14 @@ function ReportMeta() {
|
|
|
1511
1544
|
/* @__PURE__ */ jsx31("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__ */ jsxs20("div", { className: "flex items-baseline gap-1.5", children: [
|
|
1512
1545
|
/* @__PURE__ */ jsx31("dt", { className: "font-medium", children: item.label }),
|
|
1513
1546
|
/* @__PURE__ */ jsx31("dd", { className: "font-mono text-foreground", children: item.value })
|
|
1514
|
-
] }, item.label)) })
|
|
1547
|
+
] }, item.label)) }),
|
|
1548
|
+
showSlowest ? /* @__PURE__ */ jsxs20("div", { className: "border-t border-border px-4 py-3", children: [
|
|
1549
|
+
/* @__PURE__ */ jsx31("div", { className: "mb-1.5 font-medium text-muted-foreground", children: "Slowest scenarios" }),
|
|
1550
|
+
/* @__PURE__ */ jsx31("ol", { className: "flex flex-col gap-1", "aria-label": "Slowest scenarios", children: slowest.map((s) => /* @__PURE__ */ jsxs20("li", { className: "flex items-baseline justify-between gap-4", children: [
|
|
1551
|
+
/* @__PURE__ */ jsx31("a", { href: `#${s.id}`, className: "min-w-0 text-primary underline underline-offset-2", children: s.title }),
|
|
1552
|
+
/* @__PURE__ */ jsx31("span", { className: "shrink-0 font-mono tabular-nums text-muted-foreground", children: formatDuration4(s.durationMs) })
|
|
1553
|
+
] }, s.id)) })
|
|
1554
|
+
] }) : null
|
|
1515
1555
|
] })
|
|
1516
1556
|
);
|
|
1517
1557
|
}
|
|
@@ -1987,21 +2027,26 @@ function allTags(report) {
|
|
|
1987
2027
|
}
|
|
1988
2028
|
return [...seen];
|
|
1989
2029
|
}
|
|
1990
|
-
function queryMatches(scenario, q) {
|
|
2030
|
+
function queryMatches(scenario, q, sourceFile) {
|
|
1991
2031
|
if (q === "") return true;
|
|
1992
2032
|
if (scenario.title.toLowerCase().includes(q)) return true;
|
|
2033
|
+
if (sourceFile?.toLowerCase().includes(q)) return true;
|
|
2034
|
+
if (scenario.errorMessage?.toLowerCase().includes(q)) return true;
|
|
1993
2035
|
for (const tag of scenario.tags) {
|
|
1994
2036
|
if (tag.toLowerCase().includes(q)) return true;
|
|
1995
2037
|
}
|
|
2038
|
+
for (const ticket of scenario.tickets ?? []) {
|
|
2039
|
+
if (ticket.id.toLowerCase().includes(q)) return true;
|
|
2040
|
+
}
|
|
1996
2041
|
for (const step of scenario.steps) {
|
|
1997
2042
|
if (step.text.toLowerCase().includes(q)) return true;
|
|
1998
2043
|
}
|
|
1999
2044
|
return false;
|
|
2000
2045
|
}
|
|
2001
|
-
function scenarioMatches(scenario, q, status, tags) {
|
|
2046
|
+
function scenarioMatches(scenario, q, status, tags, sourceFile) {
|
|
2002
2047
|
if (status !== "all" && scenario.status !== status) return false;
|
|
2003
2048
|
if (tags.length > 0 && !tags.some((t) => scenario.tags.includes(t))) return false;
|
|
2004
|
-
return queryMatches(scenario, q);
|
|
2049
|
+
return queryMatches(scenario, q, sourceFile);
|
|
2005
2050
|
}
|
|
2006
2051
|
function summarizeScenarios(scenarios) {
|
|
2007
2052
|
let total = 0, passed = 0, failed = 0, skipped = 0, pending = 0, durationMs = 0;
|
|
@@ -2024,7 +2069,9 @@ function filterReport(report, criteria) {
|
|
|
2024
2069
|
const features = [];
|
|
2025
2070
|
let topTotal = 0, topPassed = 0, topFailed = 0, topSkipped = 0, topPending = 0, topDuration = 0;
|
|
2026
2071
|
for (const feature of report.features) {
|
|
2027
|
-
const matched = feature.scenarios.filter(
|
|
2072
|
+
const matched = feature.scenarios.filter(
|
|
2073
|
+
(s) => scenarioMatches(s, q, status, tags, feature.sourceFile)
|
|
2074
|
+
);
|
|
2028
2075
|
if (matched.length === 0) continue;
|
|
2029
2076
|
const summary = summarizeScenarios(matched);
|
|
2030
2077
|
features.push({ ...feature, summary, scenarios: matched });
|
|
@@ -2048,6 +2095,9 @@ function filterReport(report, criteria) {
|
|
|
2048
2095
|
features
|
|
2049
2096
|
};
|
|
2050
2097
|
}
|
|
2098
|
+
function failedScenarios(report) {
|
|
2099
|
+
return report.features.flatMap((f) => f.scenarios.filter((s) => s.status === "failed"));
|
|
2100
|
+
}
|
|
2051
2101
|
function listFailures(report) {
|
|
2052
2102
|
const out = [];
|
|
2053
2103
|
for (const feature of report.features) {
|
|
@@ -2068,17 +2118,77 @@ function listFailures(report) {
|
|
|
2068
2118
|
return out;
|
|
2069
2119
|
}
|
|
2070
2120
|
|
|
2121
|
+
// src/interactive/ReportAgentFilterNotice.tsx
|
|
2122
|
+
import { Bot, X } from "lucide-react";
|
|
2123
|
+
import { Fragment as Fragment11, jsx as jsx39, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2124
|
+
function ReportAgentFilterNotice({
|
|
2125
|
+
applied,
|
|
2126
|
+
onReset,
|
|
2127
|
+
onDismiss
|
|
2128
|
+
}) {
|
|
2129
|
+
const terms = [];
|
|
2130
|
+
if (applied.search) terms.push(`matching \u201C${applied.search}\u201D`);
|
|
2131
|
+
if (applied.status !== "all") terms.push(applied.status);
|
|
2132
|
+
if (applied.tags.length > 0) terms.push(applied.tags.join(", "));
|
|
2133
|
+
return /* @__PURE__ */ jsxs25(
|
|
2134
|
+
"div",
|
|
2135
|
+
{
|
|
2136
|
+
role: "status",
|
|
2137
|
+
"aria-live": "polite",
|
|
2138
|
+
className: "flex flex-wrap items-center gap-x-3 gap-y-1 rounded-md border border-primary/40 bg-primary/5 px-3 py-2 text-sm",
|
|
2139
|
+
children: [
|
|
2140
|
+
/* @__PURE__ */ jsx39(Bot, { "aria-hidden": true, className: "size-4 shrink-0 text-primary" }),
|
|
2141
|
+
/* @__PURE__ */ jsxs25("span", { className: "min-w-0 flex-1", children: [
|
|
2142
|
+
"An agent filtered this report",
|
|
2143
|
+
terms.length > 0 ? /* @__PURE__ */ jsxs25(Fragment11, { children: [
|
|
2144
|
+
" to ",
|
|
2145
|
+
terms.join(" \xB7 ")
|
|
2146
|
+
] }) : null,
|
|
2147
|
+
" \u2014",
|
|
2148
|
+
" ",
|
|
2149
|
+
/* @__PURE__ */ jsxs25("span", { className: "tabular-nums", children: [
|
|
2150
|
+
applied.matched,
|
|
2151
|
+
" of ",
|
|
2152
|
+
applied.total,
|
|
2153
|
+
" scenarios"
|
|
2154
|
+
] }),
|
|
2155
|
+
"."
|
|
2156
|
+
] }),
|
|
2157
|
+
/* @__PURE__ */ jsx39(
|
|
2158
|
+
"button",
|
|
2159
|
+
{
|
|
2160
|
+
type: "button",
|
|
2161
|
+
onClick: onReset,
|
|
2162
|
+
className: "cursor-pointer rounded-md border border-border px-2 py-1 text-xs hover:bg-muted",
|
|
2163
|
+
children: "Show all"
|
|
2164
|
+
}
|
|
2165
|
+
),
|
|
2166
|
+
/* @__PURE__ */ jsx39(
|
|
2167
|
+
"button",
|
|
2168
|
+
{
|
|
2169
|
+
type: "button",
|
|
2170
|
+
onClick: onDismiss,
|
|
2171
|
+
"aria-label": "Dismiss",
|
|
2172
|
+
className: "cursor-pointer rounded-md p-1 text-muted-foreground hover:text-foreground",
|
|
2173
|
+
children: /* @__PURE__ */ jsx39(X, { "aria-hidden": true, className: "size-4" })
|
|
2174
|
+
}
|
|
2175
|
+
)
|
|
2176
|
+
]
|
|
2177
|
+
}
|
|
2178
|
+
);
|
|
2179
|
+
}
|
|
2180
|
+
|
|
2071
2181
|
// src/interactive/ReportFailureBanner.tsx
|
|
2072
2182
|
import { useCallback as useCallback2 } from "react";
|
|
2073
|
-
import { jsx as
|
|
2074
|
-
function ReportFailureBanner({ failures }) {
|
|
2183
|
+
import { jsx as jsx40, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2184
|
+
function ReportFailureBanner({ failures, onCopyAll }) {
|
|
2075
2185
|
const first = failures[0];
|
|
2076
2186
|
const jumpToFirst = useCallback2(() => {
|
|
2077
2187
|
if (!first) return;
|
|
2078
2188
|
scrollToScenarioId(first.scenarioId);
|
|
2079
2189
|
}, [first]);
|
|
2080
2190
|
if (failures.length === 0) return null;
|
|
2081
|
-
return /* @__PURE__ */
|
|
2191
|
+
return /* @__PURE__ */ jsxs26(
|
|
2082
2192
|
"div",
|
|
2083
2193
|
{
|
|
2084
2194
|
className: "es-failure-banner",
|
|
@@ -2086,13 +2196,13 @@ function ReportFailureBanner({ failures }) {
|
|
|
2086
2196
|
"aria-live": "polite",
|
|
2087
2197
|
"aria-label": "Failure summary",
|
|
2088
2198
|
children: [
|
|
2089
|
-
/* @__PURE__ */
|
|
2090
|
-
/* @__PURE__ */
|
|
2199
|
+
/* @__PURE__ */ jsxs26("span", { className: "es-failure-banner-text", children: [
|
|
2200
|
+
/* @__PURE__ */ jsx40("strong", { children: failures.length }),
|
|
2091
2201
|
" ",
|
|
2092
2202
|
"failure",
|
|
2093
2203
|
failures.length === 1 ? "" : "s"
|
|
2094
2204
|
] }),
|
|
2095
|
-
/* @__PURE__ */
|
|
2205
|
+
/* @__PURE__ */ jsx40(
|
|
2096
2206
|
"button",
|
|
2097
2207
|
{
|
|
2098
2208
|
type: "button",
|
|
@@ -2101,7 +2211,23 @@ function ReportFailureBanner({ failures }) {
|
|
|
2101
2211
|
"aria-label": "View first failure",
|
|
2102
2212
|
children: "View first failure \u2193"
|
|
2103
2213
|
}
|
|
2104
|
-
)
|
|
2214
|
+
),
|
|
2215
|
+
onCopyAll ? /* @__PURE__ */ jsxs26(
|
|
2216
|
+
"button",
|
|
2217
|
+
{
|
|
2218
|
+
type: "button",
|
|
2219
|
+
className: "es-failure-banner-jump",
|
|
2220
|
+
onClick: onCopyAll,
|
|
2221
|
+
"aria-label": "Copy failures for an agent",
|
|
2222
|
+
children: [
|
|
2223
|
+
"Copy ",
|
|
2224
|
+
failures.length,
|
|
2225
|
+
" failure",
|
|
2226
|
+
failures.length === 1 ? "" : "s",
|
|
2227
|
+
" for an agent"
|
|
2228
|
+
]
|
|
2229
|
+
}
|
|
2230
|
+
) : null
|
|
2105
2231
|
]
|
|
2106
2232
|
}
|
|
2107
2233
|
);
|
|
@@ -2109,7 +2235,7 @@ function ReportFailureBanner({ failures }) {
|
|
|
2109
2235
|
|
|
2110
2236
|
// src/interactive/ReportFilters.tsx
|
|
2111
2237
|
import { useState as useState3 } from "react";
|
|
2112
|
-
import { jsx as
|
|
2238
|
+
import { jsx as jsx41, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2113
2239
|
var TAG_LIMIT = 12;
|
|
2114
2240
|
function ReportFilters({
|
|
2115
2241
|
statuses,
|
|
@@ -2123,10 +2249,10 @@ function ReportFilters({
|
|
|
2123
2249
|
if (statuses.length === 0 && tags.length === 0) return null;
|
|
2124
2250
|
const tagsCollapsed = tags.length > TAG_LIMIT && !showAllTags;
|
|
2125
2251
|
const visibleTags = tagsCollapsed ? tags.slice(0, TAG_LIMIT) : tags;
|
|
2126
|
-
return /* @__PURE__ */
|
|
2127
|
-
statuses.length > 0 ? /* @__PURE__ */
|
|
2252
|
+
return /* @__PURE__ */ jsxs27("div", { className: "flex flex-col gap-2", children: [
|
|
2253
|
+
statuses.length > 0 ? /* @__PURE__ */ jsx41("div", { role: "group", "aria-label": "Filter by status", className: "flex flex-wrap gap-1", children: statuses.map((opt) => {
|
|
2128
2254
|
const active = status === opt.key;
|
|
2129
|
-
return /* @__PURE__ */
|
|
2255
|
+
return /* @__PURE__ */ jsxs27(
|
|
2130
2256
|
"button",
|
|
2131
2257
|
{
|
|
2132
2258
|
type: "button",
|
|
@@ -2138,23 +2264,23 @@ function ReportFilters({
|
|
|
2138
2264
|
),
|
|
2139
2265
|
children: [
|
|
2140
2266
|
opt.label,
|
|
2141
|
-
/* @__PURE__ */
|
|
2267
|
+
/* @__PURE__ */ jsx41("span", { className: "ml-1 font-mono opacity-70", children: opt.count })
|
|
2142
2268
|
]
|
|
2143
2269
|
},
|
|
2144
2270
|
opt.key
|
|
2145
2271
|
);
|
|
2146
2272
|
}) }) : null,
|
|
2147
|
-
tags.length > 0 ? /* @__PURE__ */
|
|
2273
|
+
tags.length > 0 ? /* @__PURE__ */ jsxs27("ul", { "aria-label": "Filter by tag", className: "flex flex-wrap items-center gap-1.5", children: [
|
|
2148
2274
|
visibleTags.map((tag) => {
|
|
2149
2275
|
const active = activeTags.includes(tag);
|
|
2150
|
-
return /* @__PURE__ */
|
|
2276
|
+
return /* @__PURE__ */ jsx41("li", { children: /* @__PURE__ */ jsx41(
|
|
2151
2277
|
"button",
|
|
2152
2278
|
{
|
|
2153
2279
|
type: "button",
|
|
2154
2280
|
"aria-pressed": active,
|
|
2155
2281
|
onClick: () => onToggleTag(tag),
|
|
2156
2282
|
className: "cursor-pointer",
|
|
2157
|
-
children: /* @__PURE__ */
|
|
2283
|
+
children: /* @__PURE__ */ jsx41(
|
|
2158
2284
|
Badge,
|
|
2159
2285
|
{
|
|
2160
2286
|
variant: "tag",
|
|
@@ -2167,7 +2293,7 @@ function ReportFilters({
|
|
|
2167
2293
|
}
|
|
2168
2294
|
) }, tag);
|
|
2169
2295
|
}),
|
|
2170
|
-
tags.length > TAG_LIMIT ? /* @__PURE__ */
|
|
2296
|
+
tags.length > TAG_LIMIT ? /* @__PURE__ */ jsx41("li", { children: /* @__PURE__ */ jsx41(
|
|
2171
2297
|
"button",
|
|
2172
2298
|
{
|
|
2173
2299
|
type: "button",
|
|
@@ -2183,7 +2309,7 @@ function ReportFilters({
|
|
|
2183
2309
|
|
|
2184
2310
|
// src/interactive/ReportFreshness.tsx
|
|
2185
2311
|
import { useEffect as useEffect2, useState as useState4 } from "react";
|
|
2186
|
-
import { Fragment as
|
|
2312
|
+
import { Fragment as Fragment12, jsx as jsx42, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
2187
2313
|
function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
2188
2314
|
const [now, setNow] = useState4(nowMs);
|
|
2189
2315
|
useEffect2(() => {
|
|
@@ -2191,7 +2317,7 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
2191
2317
|
}, [nowMs]);
|
|
2192
2318
|
if (lastRunMs === void 0 || now === void 0) return null;
|
|
2193
2319
|
const age = formatRelativeAge(lastRunMs, now);
|
|
2194
|
-
const runLink = ciUrl ? /* @__PURE__ */
|
|
2320
|
+
const runLink = ciUrl ? /* @__PURE__ */ jsx42(
|
|
2195
2321
|
"a",
|
|
2196
2322
|
{
|
|
2197
2323
|
href: ciUrl,
|
|
@@ -2202,9 +2328,9 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
2202
2328
|
}
|
|
2203
2329
|
) : null;
|
|
2204
2330
|
if (isReportStale(lastRunMs, staleAfterDays, now)) {
|
|
2205
|
-
return /* @__PURE__ */
|
|
2206
|
-
/* @__PURE__ */
|
|
2207
|
-
/* @__PURE__ */
|
|
2331
|
+
return /* @__PURE__ */ jsxs28("div", { className: "es-stale-banner", role: "status", "aria-label": "Report freshness", children: [
|
|
2332
|
+
/* @__PURE__ */ jsxs28("span", { children: [
|
|
2333
|
+
/* @__PURE__ */ jsxs28("strong", { children: [
|
|
2208
2334
|
"Last verified ",
|
|
2209
2335
|
age,
|
|
2210
2336
|
"."
|
|
@@ -2214,10 +2340,10 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
2214
2340
|
runLink
|
|
2215
2341
|
] });
|
|
2216
2342
|
}
|
|
2217
|
-
return /* @__PURE__ */
|
|
2343
|
+
return /* @__PURE__ */ jsxs28("p", { className: "es-freshness", "aria-label": "Report freshness", children: [
|
|
2218
2344
|
"Verified ",
|
|
2219
2345
|
age,
|
|
2220
|
-
runLink ? /* @__PURE__ */
|
|
2346
|
+
runLink ? /* @__PURE__ */ jsxs28(Fragment12, { children: [
|
|
2221
2347
|
" \xB7 ",
|
|
2222
2348
|
runLink
|
|
2223
2349
|
] }) : null
|
|
@@ -2225,15 +2351,15 @@ function ReportFreshness({ lastRunMs, ciUrl, staleAfterDays, nowMs }) {
|
|
|
2225
2351
|
}
|
|
2226
2352
|
|
|
2227
2353
|
// src/interactive/ReportLastRunDelta.tsx
|
|
2228
|
-
import { Fragment as
|
|
2354
|
+
import { Fragment as Fragment13, jsx as jsx43, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
2229
2355
|
var MAX_LINKS = 5;
|
|
2230
2356
|
function ScenarioLinks({ scenarios, tone }) {
|
|
2231
|
-
return /* @__PURE__ */
|
|
2232
|
-
scenarios.slice(0, MAX_LINKS).map((s, i) => /* @__PURE__ */
|
|
2357
|
+
return /* @__PURE__ */ jsxs29(Fragment13, { children: [
|
|
2358
|
+
scenarios.slice(0, MAX_LINKS).map((s, i) => /* @__PURE__ */ jsxs29("span", { children: [
|
|
2233
2359
|
i > 0 ? ", " : "",
|
|
2234
|
-
/* @__PURE__ */
|
|
2360
|
+
/* @__PURE__ */ jsx43("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
|
|
2235
2361
|
] }, s.id)),
|
|
2236
|
-
scenarios.length > MAX_LINKS ? /* @__PURE__ */
|
|
2362
|
+
scenarios.length > MAX_LINKS ? /* @__PURE__ */ jsxs29("span", { children: [
|
|
2237
2363
|
" and ",
|
|
2238
2364
|
scenarios.length - MAX_LINKS,
|
|
2239
2365
|
" more"
|
|
@@ -2250,23 +2376,23 @@ function ReportLastRunDelta({
|
|
|
2250
2376
|
if (!delta) return null;
|
|
2251
2377
|
const { newlyFailing, newlyPassing, added } = delta;
|
|
2252
2378
|
if (newlyFailing.length === 0 && newlyPassing.length === 0 && added.length === 0) {
|
|
2253
|
-
return /* @__PURE__ */
|
|
2379
|
+
return /* @__PURE__ */ jsx43("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: "Since last run: no behavior changes." });
|
|
2254
2380
|
}
|
|
2255
|
-
return /* @__PURE__ */
|
|
2256
|
-
/* @__PURE__ */
|
|
2257
|
-
newlyFailing.length > 0 ? /* @__PURE__ */
|
|
2381
|
+
return /* @__PURE__ */ jsxs29("p", { className: "text-xs text-muted-foreground", "data-testid": "es-last-run-delta", children: [
|
|
2382
|
+
/* @__PURE__ */ jsx43("span", { className: "font-medium text-foreground", children: "Since last run:" }),
|
|
2383
|
+
newlyFailing.length > 0 ? /* @__PURE__ */ jsxs29("span", { className: "ml-2 text-fail", children: [
|
|
2258
2384
|
newlyFailing.length,
|
|
2259
2385
|
" newly failing (",
|
|
2260
|
-
/* @__PURE__ */
|
|
2386
|
+
/* @__PURE__ */ jsx43(ScenarioLinks, { scenarios: newlyFailing, tone: "text-fail" }),
|
|
2261
2387
|
")"
|
|
2262
2388
|
] }) : null,
|
|
2263
|
-
newlyPassing.length > 0 ? /* @__PURE__ */
|
|
2389
|
+
newlyPassing.length > 0 ? /* @__PURE__ */ jsxs29("span", { className: "ml-2 text-pass", children: [
|
|
2264
2390
|
newlyPassing.length,
|
|
2265
2391
|
" fixed (",
|
|
2266
|
-
/* @__PURE__ */
|
|
2392
|
+
/* @__PURE__ */ jsx43(ScenarioLinks, { scenarios: newlyPassing, tone: "text-pass" }),
|
|
2267
2393
|
")"
|
|
2268
2394
|
] }) : null,
|
|
2269
|
-
added.length > 0 ? /* @__PURE__ */
|
|
2395
|
+
added.length > 0 ? /* @__PURE__ */ jsxs29("span", { className: "ml-2", children: [
|
|
2270
2396
|
added.length,
|
|
2271
2397
|
" new"
|
|
2272
2398
|
] }) : null
|
|
@@ -2282,9 +2408,9 @@ import { Search } from "lucide-react";
|
|
|
2282
2408
|
|
|
2283
2409
|
// src/components/ui/input.tsx
|
|
2284
2410
|
import "react";
|
|
2285
|
-
import { jsx as
|
|
2411
|
+
import { jsx as jsx44 } from "react/jsx-runtime";
|
|
2286
2412
|
function Input({ className, type, ...props }) {
|
|
2287
|
-
return /* @__PURE__ */
|
|
2413
|
+
return /* @__PURE__ */ jsx44(
|
|
2288
2414
|
"input",
|
|
2289
2415
|
{
|
|
2290
2416
|
type,
|
|
@@ -2301,7 +2427,7 @@ function Input({ className, type, ...props }) {
|
|
|
2301
2427
|
}
|
|
2302
2428
|
|
|
2303
2429
|
// src/interactive/ReportSearch.tsx
|
|
2304
|
-
import { jsx as
|
|
2430
|
+
import { jsx as jsx45, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
2305
2431
|
var ReportSearch = forwardRef(
|
|
2306
2432
|
function ReportSearch2(props, ref) {
|
|
2307
2433
|
const {
|
|
@@ -2309,7 +2435,7 @@ var ReportSearch = forwardRef(
|
|
|
2309
2435
|
onChange,
|
|
2310
2436
|
matchedCount,
|
|
2311
2437
|
totalCount,
|
|
2312
|
-
placeholder = "Search scenarios
|
|
2438
|
+
placeholder = "Search scenarios, tags, tickets, errors\u2026",
|
|
2313
2439
|
className
|
|
2314
2440
|
} = props;
|
|
2315
2441
|
const inputId = useId();
|
|
@@ -2323,17 +2449,17 @@ var ReportSearch = forwardRef(
|
|
|
2323
2449
|
e.preventDefault();
|
|
2324
2450
|
}
|
|
2325
2451
|
}
|
|
2326
|
-
return /* @__PURE__ */
|
|
2327
|
-
/* @__PURE__ */
|
|
2328
|
-
/* @__PURE__ */
|
|
2329
|
-
/* @__PURE__ */
|
|
2452
|
+
return /* @__PURE__ */ jsxs30("div", { className: cn("es-search flex flex-col gap-1", className), children: [
|
|
2453
|
+
/* @__PURE__ */ jsx45("label", { htmlFor: inputId, className: "sr-only", children: "Search" }),
|
|
2454
|
+
/* @__PURE__ */ jsxs30("div", { className: "relative w-full sm:w-72", children: [
|
|
2455
|
+
/* @__PURE__ */ jsx45(
|
|
2330
2456
|
Search,
|
|
2331
2457
|
{
|
|
2332
2458
|
"aria-hidden": true,
|
|
2333
2459
|
className: "pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground"
|
|
2334
2460
|
}
|
|
2335
2461
|
),
|
|
2336
|
-
/* @__PURE__ */
|
|
2462
|
+
/* @__PURE__ */ jsx45(
|
|
2337
2463
|
Input,
|
|
2338
2464
|
{
|
|
2339
2465
|
ref,
|
|
@@ -2350,7 +2476,7 @@ var ReportSearch = forwardRef(
|
|
|
2350
2476
|
}
|
|
2351
2477
|
)
|
|
2352
2478
|
] }),
|
|
2353
|
-
showCounts ? /* @__PURE__ */
|
|
2479
|
+
showCounts ? /* @__PURE__ */ jsxs30(
|
|
2354
2480
|
"span",
|
|
2355
2481
|
{
|
|
2356
2482
|
className: "text-xs tabular-nums text-muted-foreground",
|
|
@@ -2367,8 +2493,118 @@ var ReportSearch = forwardRef(
|
|
|
2367
2493
|
}
|
|
2368
2494
|
);
|
|
2369
2495
|
|
|
2496
|
+
// src/interactive/ReportSinceLastVisit.tsx
|
|
2497
|
+
import { useEffect as useEffect3, useState as useState5 } from "react";
|
|
2498
|
+
|
|
2499
|
+
// src/interactive/last-visit.ts
|
|
2500
|
+
function snapshotOf(report, atMs) {
|
|
2501
|
+
const statuses = {};
|
|
2502
|
+
for (const feature of report.features) {
|
|
2503
|
+
for (const scenario of feature.scenarios) {
|
|
2504
|
+
statuses[scenario.id] = scenario.status;
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
return { runId: report.runId, atMs, statuses };
|
|
2508
|
+
}
|
|
2509
|
+
function diffSinceVisit(previous, report) {
|
|
2510
|
+
if (!previous) return null;
|
|
2511
|
+
if (previous.runId === report.runId) return null;
|
|
2512
|
+
const newlyFailing = [];
|
|
2513
|
+
const newlyPassing = [];
|
|
2514
|
+
const added = [];
|
|
2515
|
+
for (const feature of report.features) {
|
|
2516
|
+
for (const scenario of feature.scenarios) {
|
|
2517
|
+
const ref = { id: scenario.id, title: scenario.title };
|
|
2518
|
+
const before = previous.statuses[scenario.id];
|
|
2519
|
+
if (before === void 0) {
|
|
2520
|
+
added.push(ref);
|
|
2521
|
+
} else if (before !== "failed" && scenario.status === "failed") {
|
|
2522
|
+
newlyFailing.push(ref);
|
|
2523
|
+
} else if (before === "failed" && scenario.status === "passed") {
|
|
2524
|
+
newlyPassing.push(ref);
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
}
|
|
2528
|
+
if (newlyFailing.length === 0 && newlyPassing.length === 0 && added.length === 0) return null;
|
|
2529
|
+
return { sinceMs: previous.atMs, newlyFailing, newlyPassing, added };
|
|
2530
|
+
}
|
|
2531
|
+
|
|
2532
|
+
// src/interactive/ReportSinceLastVisit.tsx
|
|
2533
|
+
import { Fragment as Fragment14, jsx as jsx46, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
2534
|
+
var KEY = "es-last-visit";
|
|
2535
|
+
var MAX_LINKS2 = 5;
|
|
2536
|
+
function readVisit() {
|
|
2537
|
+
try {
|
|
2538
|
+
const raw = localStorage.getItem(KEY);
|
|
2539
|
+
if (!raw) return null;
|
|
2540
|
+
const parsed = JSON.parse(raw);
|
|
2541
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
2542
|
+
const v = parsed;
|
|
2543
|
+
if (typeof v.runId !== "string" || typeof v.atMs !== "number" || typeof v.statuses !== "object") {
|
|
2544
|
+
return null;
|
|
2545
|
+
}
|
|
2546
|
+
return { runId: v.runId, atMs: v.atMs, statuses: v.statuses };
|
|
2547
|
+
} catch {
|
|
2548
|
+
return null;
|
|
2549
|
+
}
|
|
2550
|
+
}
|
|
2551
|
+
function writeVisit(snapshot) {
|
|
2552
|
+
try {
|
|
2553
|
+
localStorage.setItem(KEY, JSON.stringify(snapshot));
|
|
2554
|
+
} catch {
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
function ScenarioLinks2({ scenarios, tone }) {
|
|
2558
|
+
return /* @__PURE__ */ jsxs31(Fragment14, { children: [
|
|
2559
|
+
scenarios.slice(0, MAX_LINKS2).map((s, i) => /* @__PURE__ */ jsxs31("span", { children: [
|
|
2560
|
+
i > 0 ? ", " : "",
|
|
2561
|
+
/* @__PURE__ */ jsx46("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
|
|
2562
|
+
] }, s.id)),
|
|
2563
|
+
scenarios.length > MAX_LINKS2 ? /* @__PURE__ */ jsxs31("span", { children: [
|
|
2564
|
+
" and ",
|
|
2565
|
+
scenarios.length - MAX_LINKS2,
|
|
2566
|
+
" more"
|
|
2567
|
+
] }) : null
|
|
2568
|
+
] });
|
|
2569
|
+
}
|
|
2570
|
+
function ReportSinceLastVisit({ report }) {
|
|
2571
|
+
const [delta, setDelta] = useState5(null);
|
|
2572
|
+
const [nowMs, setNowMs] = useState5(0);
|
|
2573
|
+
useEffect3(() => {
|
|
2574
|
+
const now = Date.now();
|
|
2575
|
+
setDelta(diffSinceVisit(readVisit(), report));
|
|
2576
|
+
setNowMs(now);
|
|
2577
|
+
writeVisit(snapshotOf(report, now));
|
|
2578
|
+
}, [report]);
|
|
2579
|
+
if (!delta) return null;
|
|
2580
|
+
const { newlyFailing, newlyPassing, added } = delta;
|
|
2581
|
+
return /* @__PURE__ */ jsxs31("p", { className: "text-xs text-muted-foreground", "data-testid": "es-since-last-visit", children: [
|
|
2582
|
+
/* @__PURE__ */ jsxs31("span", { className: "font-medium text-foreground", children: [
|
|
2583
|
+
"Since your last visit (",
|
|
2584
|
+
formatRelativeAge(delta.sinceMs, nowMs),
|
|
2585
|
+
"):"
|
|
2586
|
+
] }),
|
|
2587
|
+
newlyFailing.length > 0 ? /* @__PURE__ */ jsxs31("span", { className: "ml-2 text-fail", children: [
|
|
2588
|
+
newlyFailing.length,
|
|
2589
|
+
" started failing (",
|
|
2590
|
+
/* @__PURE__ */ jsx46(ScenarioLinks2, { scenarios: newlyFailing, tone: "text-fail" }),
|
|
2591
|
+
")"
|
|
2592
|
+
] }) : null,
|
|
2593
|
+
newlyPassing.length > 0 ? /* @__PURE__ */ jsxs31("span", { className: "ml-2 text-pass", children: [
|
|
2594
|
+
newlyPassing.length,
|
|
2595
|
+
" fixed (",
|
|
2596
|
+
/* @__PURE__ */ jsx46(ScenarioLinks2, { scenarios: newlyPassing, tone: "text-pass" }),
|
|
2597
|
+
")"
|
|
2598
|
+
] }) : null,
|
|
2599
|
+
added.length > 0 ? /* @__PURE__ */ jsxs31("span", { className: "ml-2", children: [
|
|
2600
|
+
added.length,
|
|
2601
|
+
" new"
|
|
2602
|
+
] }) : null
|
|
2603
|
+
] });
|
|
2604
|
+
}
|
|
2605
|
+
|
|
2370
2606
|
// src/interactive/ReportShortcutsHelp.tsx
|
|
2371
|
-
import { useEffect as
|
|
2607
|
+
import { useEffect as useEffect4, useRef } from "react";
|
|
2372
2608
|
|
|
2373
2609
|
// src/components/ui/button.tsx
|
|
2374
2610
|
import "react";
|
|
@@ -2424,7 +2660,7 @@ function Button({
|
|
|
2424
2660
|
}
|
|
2425
2661
|
|
|
2426
2662
|
// src/interactive/ReportShortcutsHelp.tsx
|
|
2427
|
-
import { jsx as
|
|
2663
|
+
import { jsx as jsx47, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
2428
2664
|
var SHORTCUTS = [
|
|
2429
2665
|
{ keys: "/", description: "Focus search" },
|
|
2430
2666
|
{ keys: "f", description: "Jump to next failure" },
|
|
@@ -2436,20 +2672,20 @@ var SHORTCUTS = [
|
|
|
2436
2672
|
];
|
|
2437
2673
|
function Keys({ keys }) {
|
|
2438
2674
|
const parts = keys.split(" ");
|
|
2439
|
-
return /* @__PURE__ */
|
|
2440
|
-
i > 0 ? /* @__PURE__ */
|
|
2441
|
-
/* @__PURE__ */
|
|
2675
|
+
return /* @__PURE__ */ jsx47("span", { className: "inline-flex items-center gap-1", children: parts.map((k, i) => /* @__PURE__ */ jsxs32("span", { className: "inline-flex items-center gap-1", children: [
|
|
2676
|
+
i > 0 ? /* @__PURE__ */ jsx47("span", { className: "text-xs text-muted-foreground", children: "+" }) : null,
|
|
2677
|
+
/* @__PURE__ */ jsx47("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 })
|
|
2442
2678
|
] }, k)) });
|
|
2443
2679
|
}
|
|
2444
2680
|
function ReportShortcutsHelp({ open, onClose }) {
|
|
2445
2681
|
const dialogRef = useRef(null);
|
|
2446
|
-
|
|
2682
|
+
useEffect4(() => {
|
|
2447
2683
|
const dialog = dialogRef.current;
|
|
2448
2684
|
if (!dialog) return;
|
|
2449
2685
|
if (open && !dialog.open) dialog.showModal();
|
|
2450
2686
|
else if (!open && dialog.open) dialog.close();
|
|
2451
2687
|
}, [open]);
|
|
2452
|
-
return /* @__PURE__ */
|
|
2688
|
+
return /* @__PURE__ */ jsxs32(
|
|
2453
2689
|
"dialog",
|
|
2454
2690
|
{
|
|
2455
2691
|
ref: dialogRef,
|
|
@@ -2457,20 +2693,20 @@ function ReportShortcutsHelp({ open, onClose }) {
|
|
|
2457
2693
|
"aria-label": "Keyboard shortcuts",
|
|
2458
2694
|
onClose,
|
|
2459
2695
|
children: [
|
|
2460
|
-
/* @__PURE__ */
|
|
2461
|
-
/* @__PURE__ */
|
|
2462
|
-
/* @__PURE__ */
|
|
2463
|
-
/* @__PURE__ */
|
|
2696
|
+
/* @__PURE__ */ jsx47("h2", { className: "text-base font-semibold", children: "Keyboard shortcuts" }),
|
|
2697
|
+
/* @__PURE__ */ jsx47("dl", { className: "mt-4 grid grid-cols-[auto_1fr] items-center gap-x-4 gap-y-2.5", children: SHORTCUTS.map((s) => /* @__PURE__ */ jsxs32("div", { className: "col-span-2 grid grid-cols-subgrid items-center", children: [
|
|
2698
|
+
/* @__PURE__ */ jsx47("dt", { className: "justify-self-start", children: /* @__PURE__ */ jsx47(Keys, { keys: s.keys }) }),
|
|
2699
|
+
/* @__PURE__ */ jsx47("dd", { className: "text-sm text-muted-foreground", children: s.description })
|
|
2464
2700
|
] }, s.keys)) }),
|
|
2465
|
-
/* @__PURE__ */
|
|
2701
|
+
/* @__PURE__ */ jsx47("form", { method: "dialog", className: "mt-6", children: /* @__PURE__ */ jsx47(Button, { type: "submit", variant: "outline", size: "sm", children: "Close" }) })
|
|
2466
2702
|
]
|
|
2467
2703
|
}
|
|
2468
2704
|
);
|
|
2469
2705
|
}
|
|
2470
2706
|
|
|
2471
2707
|
// src/interactive/ReportToc.tsx
|
|
2472
|
-
import { useEffect as
|
|
2473
|
-
import { jsx as
|
|
2708
|
+
import { useEffect as useEffect5, useMemo as useMemo2, useState as useState6 } from "react";
|
|
2709
|
+
import { jsx as jsx48, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
2474
2710
|
var DOT = {
|
|
2475
2711
|
passed: "bg-pass",
|
|
2476
2712
|
failed: "bg-fail",
|
|
@@ -2479,12 +2715,12 @@ var DOT = {
|
|
|
2479
2715
|
};
|
|
2480
2716
|
function TocContent({ onNavigate }) {
|
|
2481
2717
|
const report = useReport();
|
|
2482
|
-
const [activeId, setActiveId] =
|
|
2718
|
+
const [activeId, setActiveId] = useState6(null);
|
|
2483
2719
|
const scenarioIds = useMemo2(
|
|
2484
2720
|
() => report.features.flatMap((f) => f.scenarios.map((s) => s.id)),
|
|
2485
2721
|
[report]
|
|
2486
2722
|
);
|
|
2487
|
-
|
|
2723
|
+
useEffect5(() => {
|
|
2488
2724
|
if (typeof IntersectionObserver === "undefined") return;
|
|
2489
2725
|
const els = scenarioIds.map((id) => document.getElementById(id)).filter((el) => el !== null);
|
|
2490
2726
|
if (els.length === 0) return;
|
|
@@ -2499,11 +2735,11 @@ function TocContent({ onNavigate }) {
|
|
|
2499
2735
|
return () => observer.disconnect();
|
|
2500
2736
|
}, [scenarioIds]);
|
|
2501
2737
|
if (report.features.length === 0) return null;
|
|
2502
|
-
return /* @__PURE__ */
|
|
2503
|
-
/* @__PURE__ */
|
|
2504
|
-
/* @__PURE__ */
|
|
2738
|
+
return /* @__PURE__ */ jsx48("ul", { className: "flex list-none flex-col gap-4 pl-0", children: report.features.map((feature) => /* @__PURE__ */ jsxs33("li", { children: [
|
|
2739
|
+
/* @__PURE__ */ jsx48("p", { className: "mb-1.5 font-semibold leading-snug text-foreground", children: feature.title }),
|
|
2740
|
+
/* @__PURE__ */ jsx48("ul", { className: "flex list-none flex-col gap-0.5 pl-0", children: feature.scenarios.map((scenario) => {
|
|
2505
2741
|
const active = activeId === scenario.id;
|
|
2506
|
-
return /* @__PURE__ */
|
|
2742
|
+
return /* @__PURE__ */ jsx48("li", { children: /* @__PURE__ */ jsxs33(
|
|
2507
2743
|
"a",
|
|
2508
2744
|
{
|
|
2509
2745
|
href: `#${scenario.id}`,
|
|
@@ -2518,14 +2754,14 @@ function TocContent({ onNavigate }) {
|
|
|
2518
2754
|
active ? "border-primary font-medium text-foreground" : "border-border text-muted-foreground"
|
|
2519
2755
|
),
|
|
2520
2756
|
children: [
|
|
2521
|
-
/* @__PURE__ */
|
|
2757
|
+
/* @__PURE__ */ jsx48(
|
|
2522
2758
|
"span",
|
|
2523
2759
|
{
|
|
2524
2760
|
"aria-hidden": true,
|
|
2525
2761
|
className: cn("mt-1 size-1.5 shrink-0 rounded-full", DOT[scenario.status])
|
|
2526
2762
|
}
|
|
2527
2763
|
),
|
|
2528
|
-
/* @__PURE__ */
|
|
2764
|
+
/* @__PURE__ */ jsx48("span", { className: "break-words", children: scenario.title })
|
|
2529
2765
|
]
|
|
2530
2766
|
}
|
|
2531
2767
|
) }, scenario.id);
|
|
@@ -2535,48 +2771,48 @@ function TocContent({ onNavigate }) {
|
|
|
2535
2771
|
function ReportToc() {
|
|
2536
2772
|
const report = useReport();
|
|
2537
2773
|
if (report.features.length === 0) return null;
|
|
2538
|
-
return /* @__PURE__ */
|
|
2774
|
+
return /* @__PURE__ */ jsxs33(
|
|
2539
2775
|
"nav",
|
|
2540
2776
|
{
|
|
2541
2777
|
"aria-label": "Table of contents",
|
|
2542
2778
|
className: "sticky top-4 hidden h-fit w-64 shrink-0 self-start text-xs lg:block",
|
|
2543
2779
|
children: [
|
|
2544
|
-
/* @__PURE__ */
|
|
2545
|
-
/* @__PURE__ */
|
|
2780
|
+
/* @__PURE__ */ jsx48("p", { className: "mb-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Contents" }),
|
|
2781
|
+
/* @__PURE__ */ jsx48(TocContent, {})
|
|
2546
2782
|
]
|
|
2547
2783
|
}
|
|
2548
2784
|
);
|
|
2549
2785
|
}
|
|
2550
2786
|
|
|
2551
2787
|
// src/interactive/ReportTocDrawer.tsx
|
|
2552
|
-
import { useState as
|
|
2788
|
+
import { useState as useState7 } from "react";
|
|
2553
2789
|
import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
|
|
2554
2790
|
import { ListIcon, XIcon } from "lucide-react";
|
|
2555
|
-
import { jsx as
|
|
2791
|
+
import { jsx as jsx49, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
2556
2792
|
function ReportTocDrawer() {
|
|
2557
2793
|
const report = useReport();
|
|
2558
|
-
const [open, setOpen] =
|
|
2794
|
+
const [open, setOpen] = useState7(false);
|
|
2559
2795
|
if (report.features.length === 0) return null;
|
|
2560
|
-
return /* @__PURE__ */
|
|
2561
|
-
/* @__PURE__ */
|
|
2562
|
-
/* @__PURE__ */
|
|
2796
|
+
return /* @__PURE__ */ jsxs34(DialogPrimitive.Root, { open, onOpenChange: setOpen, children: [
|
|
2797
|
+
/* @__PURE__ */ jsxs34(DialogPrimitive.Trigger, { className: "flex cursor-pointer items-center gap-1 rounded-md border border-border px-2 py-1 text-xs text-muted-foreground hover:bg-muted hover:text-foreground lg:hidden [&_svg]:size-3.5", children: [
|
|
2798
|
+
/* @__PURE__ */ jsx49(ListIcon, { "aria-hidden": true }),
|
|
2563
2799
|
" Contents"
|
|
2564
2800
|
] }),
|
|
2565
|
-
/* @__PURE__ */
|
|
2566
|
-
/* @__PURE__ */
|
|
2567
|
-
/* @__PURE__ */
|
|
2568
|
-
/* @__PURE__ */
|
|
2569
|
-
/* @__PURE__ */
|
|
2570
|
-
/* @__PURE__ */
|
|
2801
|
+
/* @__PURE__ */ jsxs34(DialogPrimitive.Portal, { children: [
|
|
2802
|
+
/* @__PURE__ */ jsx49(DialogPrimitive.Backdrop, { className: "fixed inset-0 z-50 bg-black/50 transition-opacity duration-200 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0" }),
|
|
2803
|
+
/* @__PURE__ */ jsxs34(DialogPrimitive.Popup, { className: "fixed inset-y-0 left-0 z-50 flex w-72 max-w-[80vw] flex-col gap-3 overflow-y-auto border-r border-border bg-background p-4 font-sans text-xs shadow-lg outline-none transition-transform duration-200 data-[ending-style]:-translate-x-full data-[starting-style]:-translate-x-full", children: [
|
|
2804
|
+
/* @__PURE__ */ jsxs34("div", { className: "flex items-center justify-between", children: [
|
|
2805
|
+
/* @__PURE__ */ jsx49(DialogPrimitive.Title, { className: "text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Contents" }),
|
|
2806
|
+
/* @__PURE__ */ jsx49(
|
|
2571
2807
|
DialogPrimitive.Close,
|
|
2572
2808
|
{
|
|
2573
2809
|
"aria-label": "Close contents",
|
|
2574
2810
|
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
2575
|
-
children: /* @__PURE__ */
|
|
2811
|
+
children: /* @__PURE__ */ jsx49(XIcon, { "aria-hidden": true })
|
|
2576
2812
|
}
|
|
2577
2813
|
)
|
|
2578
2814
|
] }),
|
|
2579
|
-
/* @__PURE__ */
|
|
2815
|
+
/* @__PURE__ */ jsx49(TocContent, { onNavigate: () => setOpen(false) })
|
|
2580
2816
|
] })
|
|
2581
2817
|
] })
|
|
2582
2818
|
] });
|
|
@@ -2610,10 +2846,10 @@ function failuresFirst(report) {
|
|
|
2610
2846
|
}
|
|
2611
2847
|
|
|
2612
2848
|
// src/interactive/use-deep-link-scroll.ts
|
|
2613
|
-
import { useEffect as
|
|
2849
|
+
import { useEffect as useEffect6, useRef as useRef2 } from "react";
|
|
2614
2850
|
function useDeepLinkScroll() {
|
|
2615
2851
|
const lastAnchor = useRef2(null);
|
|
2616
|
-
|
|
2852
|
+
useEffect6(() => {
|
|
2617
2853
|
function scrollToHash() {
|
|
2618
2854
|
const { anchor } = splitHash(window.location.hash);
|
|
2619
2855
|
if (!anchor || anchor === lastAnchor.current) return;
|
|
@@ -2629,7 +2865,7 @@ function useDeepLinkScroll() {
|
|
|
2629
2865
|
}
|
|
2630
2866
|
|
|
2631
2867
|
// src/interactive/use-keyboard-shortcuts.ts
|
|
2632
|
-
import { useEffect as
|
|
2868
|
+
import { useEffect as useEffect7, useRef as useRef3 } from "react";
|
|
2633
2869
|
function isEditableTarget(target) {
|
|
2634
2870
|
if (!(target instanceof HTMLElement)) return false;
|
|
2635
2871
|
const tag = target.tagName;
|
|
@@ -2640,7 +2876,7 @@ function isEditableTarget(target) {
|
|
|
2640
2876
|
function useKeyboardShortcuts(handlers) {
|
|
2641
2877
|
const ref = useRef3(handlers);
|
|
2642
2878
|
ref.current = handlers;
|
|
2643
|
-
|
|
2879
|
+
useEffect7(() => {
|
|
2644
2880
|
function onKeyDown(e) {
|
|
2645
2881
|
const h = ref.current;
|
|
2646
2882
|
if (e.key === "Escape") {
|
|
@@ -2684,8 +2920,8 @@ function useKeyboardShortcuts(handlers) {
|
|
|
2684
2920
|
}
|
|
2685
2921
|
|
|
2686
2922
|
// src/interactive/use-theme.ts
|
|
2687
|
-
import { useCallback as useCallback3, useEffect as
|
|
2688
|
-
var
|
|
2923
|
+
import { useCallback as useCallback3, useEffect as useEffect8, useState as useState8 } from "react";
|
|
2924
|
+
var KEY2 = "es-theme";
|
|
2689
2925
|
function systemDark() {
|
|
2690
2926
|
return typeof matchMedia !== "undefined" && matchMedia("(prefers-color-scheme: dark)").matches;
|
|
2691
2927
|
}
|
|
@@ -2699,19 +2935,19 @@ function applyTheme(pref) {
|
|
|
2699
2935
|
}
|
|
2700
2936
|
function initialPref() {
|
|
2701
2937
|
if (typeof localStorage !== "undefined") {
|
|
2702
|
-
const stored = localStorage.getItem(
|
|
2938
|
+
const stored = localStorage.getItem(KEY2);
|
|
2703
2939
|
if (stored === "light" || stored === "dark" || stored === "system") return stored;
|
|
2704
2940
|
}
|
|
2705
2941
|
return "system";
|
|
2706
2942
|
}
|
|
2707
2943
|
function useTheme() {
|
|
2708
|
-
const [pref, setPrefState] =
|
|
2709
|
-
|
|
2944
|
+
const [pref, setPrefState] = useState8("system");
|
|
2945
|
+
useEffect8(() => {
|
|
2710
2946
|
const p = initialPref();
|
|
2711
2947
|
setPrefState(p);
|
|
2712
2948
|
applyTheme(p);
|
|
2713
2949
|
}, []);
|
|
2714
|
-
|
|
2950
|
+
useEffect8(() => {
|
|
2715
2951
|
if (typeof matchMedia === "undefined") return;
|
|
2716
2952
|
const mq = matchMedia("(prefers-color-scheme: dark)");
|
|
2717
2953
|
const onChange = () => {
|
|
@@ -2724,7 +2960,7 @@ function useTheme() {
|
|
|
2724
2960
|
setPrefState(p);
|
|
2725
2961
|
applyTheme(p);
|
|
2726
2962
|
try {
|
|
2727
|
-
localStorage.setItem(
|
|
2963
|
+
localStorage.setItem(KEY2, p);
|
|
2728
2964
|
} catch {
|
|
2729
2965
|
}
|
|
2730
2966
|
}, []);
|
|
@@ -2732,19 +2968,19 @@ function useTheme() {
|
|
|
2732
2968
|
}
|
|
2733
2969
|
|
|
2734
2970
|
// src/interactive/use-url-state.ts
|
|
2735
|
-
import { useCallback as useCallback4, useEffect as
|
|
2971
|
+
import { useCallback as useCallback4, useEffect as useEffect9, useRef as useRef4, useState as useState9 } from "react";
|
|
2736
2972
|
var WRITE_DELAY_MS = 250;
|
|
2737
2973
|
function useUrlState() {
|
|
2738
|
-
const [state, setState] =
|
|
2974
|
+
const [state, setState] = useState9(DEFAULT_URL_STATE);
|
|
2739
2975
|
const ready = useRef4(false);
|
|
2740
|
-
|
|
2976
|
+
useEffect9(() => {
|
|
2741
2977
|
const read = () => setState(decodeUrlState(splitHash(window.location.hash).params));
|
|
2742
2978
|
read();
|
|
2743
2979
|
ready.current = true;
|
|
2744
2980
|
window.addEventListener("hashchange", read);
|
|
2745
2981
|
return () => window.removeEventListener("hashchange", read);
|
|
2746
2982
|
}, []);
|
|
2747
|
-
|
|
2983
|
+
useEffect9(() => {
|
|
2748
2984
|
if (!ready.current) return;
|
|
2749
2985
|
const timer = setTimeout(
|
|
2750
2986
|
() => writeHash(splitHash(window.location.hash).anchor, encodeUrlState(state)),
|
|
@@ -2759,13 +2995,233 @@ function useUrlState() {
|
|
|
2759
2995
|
return [state, update];
|
|
2760
2996
|
}
|
|
2761
2997
|
|
|
2998
|
+
// src/interactive/webmcp-tools.ts
|
|
2999
|
+
import {
|
|
3000
|
+
getFeatureSummary,
|
|
3001
|
+
getScenario,
|
|
3002
|
+
listScenarioSummaries,
|
|
3003
|
+
runProvenance,
|
|
3004
|
+
toScenarioSummary
|
|
3005
|
+
} from "executable-stories-core/report-queries";
|
|
3006
|
+
var STATUSES2 = [
|
|
3007
|
+
"passed",
|
|
3008
|
+
"failed",
|
|
3009
|
+
"skipped",
|
|
3010
|
+
"pending"
|
|
3011
|
+
];
|
|
3012
|
+
var VIEW_STATUSES = ["all", ...STATUSES2];
|
|
3013
|
+
var ToolArgumentError = class extends Error {
|
|
3014
|
+
};
|
|
3015
|
+
function asRecord(input) {
|
|
3016
|
+
return typeof input === "object" && input !== null ? input : {};
|
|
3017
|
+
}
|
|
3018
|
+
function readString(input, key) {
|
|
3019
|
+
const value = input[key];
|
|
3020
|
+
if (value === void 0 || value === null) return void 0;
|
|
3021
|
+
if (typeof value !== "string") {
|
|
3022
|
+
throw new ToolArgumentError(`"${key}" must be a string, received ${typeof value}.`);
|
|
3023
|
+
}
|
|
3024
|
+
return value;
|
|
3025
|
+
}
|
|
3026
|
+
function readStringArray(input, key) {
|
|
3027
|
+
const value = input[key];
|
|
3028
|
+
if (value === void 0 || value === null) return void 0;
|
|
3029
|
+
if (typeof value === "string") return [value];
|
|
3030
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
|
|
3031
|
+
throw new ToolArgumentError(`"${key}" must be an array of strings.`);
|
|
3032
|
+
}
|
|
3033
|
+
return value;
|
|
3034
|
+
}
|
|
3035
|
+
function readEnum(input, key, allowed) {
|
|
3036
|
+
const value = readString(input, key);
|
|
3037
|
+
if (value === void 0) return void 0;
|
|
3038
|
+
if (!allowed.includes(value)) {
|
|
3039
|
+
throw new ToolArgumentError(
|
|
3040
|
+
`"${key}" must be one of: ${allowed.join(", ")}. Received "${value}".`
|
|
3041
|
+
);
|
|
3042
|
+
}
|
|
3043
|
+
return value;
|
|
3044
|
+
}
|
|
3045
|
+
function readStatuses(input) {
|
|
3046
|
+
const values = readStringArray(input, "statuses");
|
|
3047
|
+
if (values === void 0) return void 0;
|
|
3048
|
+
const invalid = values.filter((v) => !STATUSES2.includes(v));
|
|
3049
|
+
if (invalid.length > 0) {
|
|
3050
|
+
throw new ToolArgumentError(
|
|
3051
|
+
`"statuses" must contain only: ${STATUSES2.join(", ")}. Received "${invalid.join('", "')}".`
|
|
3052
|
+
);
|
|
3053
|
+
}
|
|
3054
|
+
return values;
|
|
3055
|
+
}
|
|
3056
|
+
function guarded(run) {
|
|
3057
|
+
try {
|
|
3058
|
+
return run();
|
|
3059
|
+
} catch (error) {
|
|
3060
|
+
if (error instanceof ToolArgumentError) return `Invalid input \u2014 ${error.message}`;
|
|
3061
|
+
throw error;
|
|
3062
|
+
}
|
|
3063
|
+
}
|
|
3064
|
+
var scenarioListSchema = {
|
|
3065
|
+
type: "object",
|
|
3066
|
+
properties: {
|
|
3067
|
+
statuses: {
|
|
3068
|
+
type: "array",
|
|
3069
|
+
items: { type: "string", enum: [...STATUSES2] },
|
|
3070
|
+
description: "Keep only scenarios with any of these statuses."
|
|
3071
|
+
},
|
|
3072
|
+
tags: {
|
|
3073
|
+
type: "array",
|
|
3074
|
+
items: { type: "string" },
|
|
3075
|
+
description: "Keep only scenarios carrying any of these tags."
|
|
3076
|
+
},
|
|
3077
|
+
sourceFiles: {
|
|
3078
|
+
type: "array",
|
|
3079
|
+
items: { type: "string" },
|
|
3080
|
+
description: "Keep only scenarios whose source file path contains any of these."
|
|
3081
|
+
}
|
|
3082
|
+
}
|
|
3083
|
+
};
|
|
3084
|
+
var READ_ONLY = { readOnlyHint: true, untrustedContentHint: true };
|
|
3085
|
+
function reportTools(deps) {
|
|
3086
|
+
const { report, setView, onAgentFilter } = deps;
|
|
3087
|
+
const now = deps.now ?? Date.now;
|
|
3088
|
+
const provenance = () => ({ run: runProvenance(report, now()) });
|
|
3089
|
+
const list = (filters) => {
|
|
3090
|
+
const scenarios = listScenarioSummaries(report, filters);
|
|
3091
|
+
return { ...provenance(), total: scenarios.length, scenarios };
|
|
3092
|
+
};
|
|
3093
|
+
return {
|
|
3094
|
+
list_scenarios: {
|
|
3095
|
+
title: "List scenarios",
|
|
3096
|
+
description: "List the behaviour scenarios in this report, optionally filtered by status, tag, or source file. Returns each scenario with its steps, tags, timing and failure message.",
|
|
3097
|
+
annotations: READ_ONLY,
|
|
3098
|
+
input: scenarioListSchema,
|
|
3099
|
+
execute: (input) => guarded(() => {
|
|
3100
|
+
const args = asRecord(input);
|
|
3101
|
+
const filters = {};
|
|
3102
|
+
const statuses = readStatuses(args);
|
|
3103
|
+
const tags = readStringArray(args, "tags");
|
|
3104
|
+
const sourceFiles = readStringArray(args, "sourceFiles");
|
|
3105
|
+
if (statuses) filters.statuses = statuses;
|
|
3106
|
+
if (tags) filters.tags = tags;
|
|
3107
|
+
if (sourceFiles) filters.sourceFiles = sourceFiles;
|
|
3108
|
+
return list(filters);
|
|
3109
|
+
})
|
|
3110
|
+
},
|
|
3111
|
+
get_failing_scenarios: {
|
|
3112
|
+
title: "Get failing scenarios",
|
|
3113
|
+
description: "List only the scenarios that failed in this run, each with the step that failed and its error message. Use this first when asked what is broken.",
|
|
3114
|
+
annotations: READ_ONLY,
|
|
3115
|
+
execute: () => list({ statuses: ["failed"] })
|
|
3116
|
+
},
|
|
3117
|
+
get_feature_summary: {
|
|
3118
|
+
title: "Get feature summary",
|
|
3119
|
+
description: 'Summarise each feature in the report with its scenario counts by status. Use this for "how are we doing" questions rather than listing every scenario.',
|
|
3120
|
+
annotations: READ_ONLY,
|
|
3121
|
+
execute: () => ({
|
|
3122
|
+
...provenance(),
|
|
3123
|
+
summary: report.summary,
|
|
3124
|
+
features: getFeatureSummary(report)
|
|
3125
|
+
})
|
|
3126
|
+
},
|
|
3127
|
+
get_scenario: {
|
|
3128
|
+
title: "Get scenario",
|
|
3129
|
+
description: "Get one scenario by its id or its exact title, with every step and any failure detail. Attachment and document bodies are omitted \u2014 `docKinds` names what the page shows.",
|
|
3130
|
+
annotations: READ_ONLY,
|
|
3131
|
+
input: {
|
|
3132
|
+
type: "object",
|
|
3133
|
+
properties: {
|
|
3134
|
+
idOrTitle: {
|
|
3135
|
+
type: "string",
|
|
3136
|
+
description: "The scenario id, or its exact title as shown in the report."
|
|
3137
|
+
}
|
|
3138
|
+
},
|
|
3139
|
+
required: ["idOrTitle"]
|
|
3140
|
+
},
|
|
3141
|
+
execute: (input) => guarded(() => {
|
|
3142
|
+
const idOrTitle = readString(asRecord(input), "idOrTitle") ?? "";
|
|
3143
|
+
const found = getScenario(report, idOrTitle);
|
|
3144
|
+
if (!found) {
|
|
3145
|
+
return {
|
|
3146
|
+
...provenance(),
|
|
3147
|
+
error: `No scenario found with id or title "${idOrTitle}". Call list_scenarios to see what this report contains.`
|
|
3148
|
+
};
|
|
3149
|
+
}
|
|
3150
|
+
return {
|
|
3151
|
+
...provenance(),
|
|
3152
|
+
feature: {
|
|
3153
|
+
id: found.feature.id,
|
|
3154
|
+
title: found.feature.title,
|
|
3155
|
+
sourceFile: found.feature.sourceFile
|
|
3156
|
+
},
|
|
3157
|
+
// The summary projection, not the raw scenario: doc entry bodies and
|
|
3158
|
+
// base64 attachments are unbounded, and this payload goes straight
|
|
3159
|
+
// into a model's context window.
|
|
3160
|
+
scenario: toScenarioSummary(found.feature, found.scenario)
|
|
3161
|
+
};
|
|
3162
|
+
})
|
|
3163
|
+
},
|
|
3164
|
+
filter_scenarios: {
|
|
3165
|
+
title: "Filter the report",
|
|
3166
|
+
description: `Change what the reader is looking at: set the report's search text, status filter and tag filter. Omitted fields are left as they are; pass an empty string, "all", or an empty array to clear one.`,
|
|
3167
|
+
input: {
|
|
3168
|
+
type: "object",
|
|
3169
|
+
properties: {
|
|
3170
|
+
search: {
|
|
3171
|
+
type: "string",
|
|
3172
|
+
description: "Free text matched against scenario titles, tags and step text. Empty string clears it."
|
|
3173
|
+
},
|
|
3174
|
+
status: {
|
|
3175
|
+
type: "string",
|
|
3176
|
+
enum: [...VIEW_STATUSES],
|
|
3177
|
+
description: 'Show only scenarios with this status. "all" clears the filter.'
|
|
3178
|
+
},
|
|
3179
|
+
tags: {
|
|
3180
|
+
type: "array",
|
|
3181
|
+
items: { type: "string" },
|
|
3182
|
+
description: "Show only scenarios carrying any of these tags. Empty array clears the filter."
|
|
3183
|
+
}
|
|
3184
|
+
}
|
|
3185
|
+
},
|
|
3186
|
+
execute: (input) => guarded(() => {
|
|
3187
|
+
const args = asRecord(input);
|
|
3188
|
+
const search = readString(args, "search");
|
|
3189
|
+
const status = readEnum(args, "status", VIEW_STATUSES);
|
|
3190
|
+
const tags = readStringArray(args, "tags");
|
|
3191
|
+
const applied = {
|
|
3192
|
+
search: search ?? deps.view.query,
|
|
3193
|
+
status: status ?? deps.view.status,
|
|
3194
|
+
tags: tags ?? deps.view.tags
|
|
3195
|
+
};
|
|
3196
|
+
const patch = {};
|
|
3197
|
+
if (search !== void 0) patch.query = search;
|
|
3198
|
+
if (status !== void 0) patch.status = status;
|
|
3199
|
+
if (tags !== void 0) patch.tags = tags;
|
|
3200
|
+
setView(patch);
|
|
3201
|
+
const matched = filterReport(report, {
|
|
3202
|
+
query: applied.search,
|
|
3203
|
+
status: applied.status,
|
|
3204
|
+
tags: applied.tags
|
|
3205
|
+
}).summary.total;
|
|
3206
|
+
const result = {
|
|
3207
|
+
...applied,
|
|
3208
|
+
matched,
|
|
3209
|
+
total: report.summary.total
|
|
3210
|
+
};
|
|
3211
|
+
onAgentFilter?.(result);
|
|
3212
|
+
return { ...provenance(), applied: result };
|
|
3213
|
+
})
|
|
3214
|
+
}
|
|
3215
|
+
};
|
|
3216
|
+
}
|
|
3217
|
+
|
|
2762
3218
|
// src/interactive/ReportInteractive.tsx
|
|
2763
|
-
import { Fragment as
|
|
3219
|
+
import { Fragment as Fragment15, jsx as jsx50, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
2764
3220
|
function ReportInteractive(props) {
|
|
2765
3221
|
const { report, className, title, dataTheme } = props;
|
|
2766
3222
|
const result = unwrapReport(report);
|
|
2767
3223
|
if (!result.ok) {
|
|
2768
|
-
return /* @__PURE__ */
|
|
3224
|
+
return /* @__PURE__ */ jsx50(
|
|
2769
3225
|
ReportErrorShell,
|
|
2770
3226
|
{
|
|
2771
3227
|
error: result.error,
|
|
@@ -2775,7 +3231,7 @@ function ReportInteractive(props) {
|
|
|
2775
3231
|
}
|
|
2776
3232
|
);
|
|
2777
3233
|
}
|
|
2778
|
-
return /* @__PURE__ */
|
|
3234
|
+
return /* @__PURE__ */ jsx50(ReportInteractiveView, { ...props, report: result.data });
|
|
2779
3235
|
}
|
|
2780
3236
|
var THEME_OPTIONS = [
|
|
2781
3237
|
{ value: "light", label: "Light", Icon: Sun },
|
|
@@ -2786,7 +3242,7 @@ function ThemeSegment({
|
|
|
2786
3242
|
pref,
|
|
2787
3243
|
onPref
|
|
2788
3244
|
}) {
|
|
2789
|
-
return /* @__PURE__ */
|
|
3245
|
+
return /* @__PURE__ */ jsx50(
|
|
2790
3246
|
ToggleGroup,
|
|
2791
3247
|
{
|
|
2792
3248
|
size: "sm",
|
|
@@ -2796,14 +3252,14 @@ function ThemeSegment({
|
|
|
2796
3252
|
if (next) onPref(next);
|
|
2797
3253
|
},
|
|
2798
3254
|
"aria-label": "Color theme",
|
|
2799
|
-
children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */
|
|
3255
|
+
children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */ jsx50(
|
|
2800
3256
|
ToggleGroupItem,
|
|
2801
3257
|
{
|
|
2802
3258
|
value,
|
|
2803
3259
|
"aria-label": label,
|
|
2804
3260
|
title: label,
|
|
2805
3261
|
className: "px-2",
|
|
2806
|
-
children: /* @__PURE__ */
|
|
3262
|
+
children: /* @__PURE__ */ jsx50(Icon, {})
|
|
2807
3263
|
},
|
|
2808
3264
|
value
|
|
2809
3265
|
))
|
|
@@ -2836,7 +3292,7 @@ function ReportInteractiveView({
|
|
|
2836
3292
|
(next) => setUrlState({ detail: next }),
|
|
2837
3293
|
[setUrlState]
|
|
2838
3294
|
);
|
|
2839
|
-
const [helpOpen, setHelpOpen] =
|
|
3295
|
+
const [helpOpen, setHelpOpen] = useState10(false);
|
|
2840
3296
|
const { pref: themePref, setPref: setThemePref } = useTheme();
|
|
2841
3297
|
const searchRef = useRef5(null);
|
|
2842
3298
|
const expandId = useId2();
|
|
@@ -2878,7 +3334,7 @@ function ReportInteractiveView({
|
|
|
2878
3334
|
}),
|
|
2879
3335
|
[activeTags, setUrlState]
|
|
2880
3336
|
);
|
|
2881
|
-
const [toast, setToast] =
|
|
3337
|
+
const [toast, setToast] = useState10(null);
|
|
2882
3338
|
const toastTimer = useRef5(null);
|
|
2883
3339
|
const showToast = useCallback5((msg) => {
|
|
2884
3340
|
setToast(msg);
|
|
@@ -2904,6 +3360,10 @@ function ReportInteractiveView({
|
|
|
2904
3360
|
}),
|
|
2905
3361
|
[copy]
|
|
2906
3362
|
);
|
|
3363
|
+
const copyAllFailures = useCallback5(
|
|
3364
|
+
() => copy(failuresToPrompt(failedScenarios(filtered)), "Failures copied"),
|
|
3365
|
+
[copy, filtered]
|
|
3366
|
+
);
|
|
2907
3367
|
const failureIndexRef = useRef5(0);
|
|
2908
3368
|
const allCollapsibleIds = useMemo3(
|
|
2909
3369
|
() => report.features.flatMap((f) => [f.id, ...f.scenarios.map((s) => s.id)]),
|
|
@@ -2921,7 +3381,7 @@ function ReportInteractiveView({
|
|
|
2921
3381
|
() => collapse.collapseAll(allCollapsibleIds),
|
|
2922
3382
|
[collapse, allCollapsibleIds]
|
|
2923
3383
|
);
|
|
2924
|
-
const [expandedAll, setExpandedAll] =
|
|
3384
|
+
const [expandedAll, setExpandedAll] = useState10(
|
|
2925
3385
|
() => report.summary.failed === 0
|
|
2926
3386
|
);
|
|
2927
3387
|
const setExpanded = useCallback5(
|
|
@@ -2932,6 +3392,20 @@ function ReportInteractiveView({
|
|
|
2932
3392
|
},
|
|
2933
3393
|
[collapse, collapseAll]
|
|
2934
3394
|
);
|
|
3395
|
+
const [agentFilter, setAgentFilter] = useState10(null);
|
|
3396
|
+
useTools(
|
|
3397
|
+
reportTools({
|
|
3398
|
+
report,
|
|
3399
|
+
view: urlState,
|
|
3400
|
+
setView: setUrlState,
|
|
3401
|
+
onAgentFilter: setAgentFilter
|
|
3402
|
+
})
|
|
3403
|
+
);
|
|
3404
|
+
const showAgentFilter = agentFilter !== null && agentFilter.search === query && agentFilter.status === statusFilter && agentFilter.tags.length === activeTags.length && agentFilter.tags.every((tag) => activeTags.includes(tag));
|
|
3405
|
+
const clearFilters = useCallback5(
|
|
3406
|
+
() => setUrlState({ query: "", status: "all", tags: [] }),
|
|
3407
|
+
[setUrlState]
|
|
3408
|
+
);
|
|
2935
3409
|
const focusSearch = useCallback5(() => {
|
|
2936
3410
|
searchRef.current?.focus();
|
|
2937
3411
|
}, []);
|
|
@@ -2965,13 +3439,13 @@ function ReportInteractiveView({
|
|
|
2965
3439
|
const totalScenarios = report.summary.total;
|
|
2966
3440
|
const matchedScenarios = filtered.summary.total;
|
|
2967
3441
|
const showToc = !hideToc && totalScenarios > 3;
|
|
2968
|
-
return /* @__PURE__ */
|
|
3442
|
+
return /* @__PURE__ */ jsx50(CollapseProvider, { value: visibleCollapse, children: /* @__PURE__ */ jsx50(ScenarioActionsProvider, { value: scenarioActions, children: /* @__PURE__ */ jsx50(ScenarioHistoryProvider, { value: scenarioHistory ?? null, children: /* @__PURE__ */ jsx50(ScenarioFreshnessProvider, { value: { staleAfterDays, report }, children: /* @__PURE__ */ jsx50(
|
|
2969
3443
|
ReportRoot,
|
|
2970
3444
|
{
|
|
2971
3445
|
report: filtered,
|
|
2972
3446
|
customRenderers,
|
|
2973
3447
|
renderers,
|
|
2974
|
-
children: /* @__PURE__ */
|
|
3448
|
+
children: /* @__PURE__ */ jsxs35(
|
|
2975
3449
|
"main",
|
|
2976
3450
|
{
|
|
2977
3451
|
className: cn("es-report", "es-report-interactive", className),
|
|
@@ -2980,8 +3454,8 @@ function ReportInteractiveView({
|
|
|
2980
3454
|
"data-theme": dataTheme,
|
|
2981
3455
|
"data-detail-level": detail,
|
|
2982
3456
|
children: [
|
|
2983
|
-
/* @__PURE__ */
|
|
2984
|
-
/* @__PURE__ */
|
|
3457
|
+
/* @__PURE__ */ jsxs35("header", { className: "es-report-header", children: [
|
|
3458
|
+
/* @__PURE__ */ jsxs35(
|
|
2985
3459
|
"div",
|
|
2986
3460
|
{
|
|
2987
3461
|
"data-es-navbar": true,
|
|
@@ -2990,9 +3464,9 @@ function ReportInteractiveView({
|
|
|
2990
3464
|
hideHeader ? "justify-end" : "justify-between"
|
|
2991
3465
|
),
|
|
2992
3466
|
children: [
|
|
2993
|
-
hideHeader ? null : /* @__PURE__ */
|
|
2994
|
-
/* @__PURE__ */
|
|
2995
|
-
/* @__PURE__ */
|
|
3467
|
+
hideHeader ? null : /* @__PURE__ */ jsx50("h1", { className: "min-w-0", children: title ?? "Story Report" }),
|
|
3468
|
+
/* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-2", children: [
|
|
3469
|
+
/* @__PURE__ */ jsx50(
|
|
2996
3470
|
ReportSearch,
|
|
2997
3471
|
{
|
|
2998
3472
|
ref: searchRef,
|
|
@@ -3002,16 +3476,16 @@ function ReportInteractiveView({
|
|
|
3002
3476
|
totalCount: totalScenarios
|
|
3003
3477
|
}
|
|
3004
3478
|
),
|
|
3005
|
-
/* @__PURE__ */
|
|
3479
|
+
/* @__PURE__ */ jsx50(ThemeSegment, { pref: themePref, onPref: setThemePref })
|
|
3006
3480
|
] })
|
|
3007
3481
|
]
|
|
3008
3482
|
}
|
|
3009
3483
|
),
|
|
3010
|
-
hideHeader ? null : /* @__PURE__ */
|
|
3011
|
-
/* @__PURE__ */
|
|
3012
|
-
/* @__PURE__ */
|
|
3484
|
+
hideHeader ? null : /* @__PURE__ */ jsxs35(Fragment15, { children: [
|
|
3485
|
+
/* @__PURE__ */ jsx50(ReportSummary, {}),
|
|
3486
|
+
/* @__PURE__ */ jsx50(ReportMeta, {})
|
|
3013
3487
|
] }),
|
|
3014
|
-
/* @__PURE__ */
|
|
3488
|
+
/* @__PURE__ */ jsx50(
|
|
3015
3489
|
ReportFreshness,
|
|
3016
3490
|
{
|
|
3017
3491
|
lastRunMs: reportLastRunMs(report),
|
|
@@ -3019,14 +3493,15 @@ function ReportInteractiveView({
|
|
|
3019
3493
|
staleAfterDays
|
|
3020
3494
|
}
|
|
3021
3495
|
),
|
|
3022
|
-
/* @__PURE__ */
|
|
3496
|
+
/* @__PURE__ */ jsx50(
|
|
3023
3497
|
ReportLastRunDelta,
|
|
3024
3498
|
{
|
|
3025
3499
|
history: scenarioHistory,
|
|
3026
3500
|
report
|
|
3027
3501
|
}
|
|
3028
3502
|
),
|
|
3029
|
-
/* @__PURE__ */
|
|
3503
|
+
/* @__PURE__ */ jsx50(ReportSinceLastVisit, { report }),
|
|
3504
|
+
/* @__PURE__ */ jsx50(
|
|
3030
3505
|
ReportFilters,
|
|
3031
3506
|
{
|
|
3032
3507
|
statuses: statusOptions,
|
|
@@ -3037,10 +3512,10 @@ function ReportInteractiveView({
|
|
|
3037
3512
|
onToggleTag: toggleTag
|
|
3038
3513
|
}
|
|
3039
3514
|
),
|
|
3040
|
-
/* @__PURE__ */
|
|
3041
|
-
showToc ? /* @__PURE__ */
|
|
3042
|
-
/* @__PURE__ */
|
|
3043
|
-
/* @__PURE__ */
|
|
3515
|
+
/* @__PURE__ */ jsxs35("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-2 border-t border-border/60 pt-3", children: [
|
|
3516
|
+
showToc ? /* @__PURE__ */ jsx50(ReportTocDrawer, {}) : null,
|
|
3517
|
+
/* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-2", children: [
|
|
3518
|
+
/* @__PURE__ */ jsx50(
|
|
3044
3519
|
Switch,
|
|
3045
3520
|
{
|
|
3046
3521
|
id: expandId,
|
|
@@ -3048,7 +3523,7 @@ function ReportInteractiveView({
|
|
|
3048
3523
|
onCheckedChange: setExpanded
|
|
3049
3524
|
}
|
|
3050
3525
|
),
|
|
3051
|
-
/* @__PURE__ */
|
|
3526
|
+
/* @__PURE__ */ jsx50(
|
|
3052
3527
|
"label",
|
|
3053
3528
|
{
|
|
3054
3529
|
htmlFor: expandId,
|
|
@@ -3057,8 +3532,8 @@ function ReportInteractiveView({
|
|
|
3057
3532
|
}
|
|
3058
3533
|
)
|
|
3059
3534
|
] }),
|
|
3060
|
-
/* @__PURE__ */
|
|
3061
|
-
/* @__PURE__ */
|
|
3535
|
+
/* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-2", children: [
|
|
3536
|
+
/* @__PURE__ */ jsx50(
|
|
3062
3537
|
Switch,
|
|
3063
3538
|
{
|
|
3064
3539
|
id: docsId,
|
|
@@ -3066,7 +3541,7 @@ function ReportInteractiveView({
|
|
|
3066
3541
|
onCheckedChange: (checked) => setDetail(checked ? "full" : "minimal")
|
|
3067
3542
|
}
|
|
3068
3543
|
),
|
|
3069
|
-
/* @__PURE__ */
|
|
3544
|
+
/* @__PURE__ */ jsx50(
|
|
3070
3545
|
"label",
|
|
3071
3546
|
{
|
|
3072
3547
|
htmlFor: docsId,
|
|
@@ -3077,17 +3552,25 @@ function ReportInteractiveView({
|
|
|
3077
3552
|
] })
|
|
3078
3553
|
] })
|
|
3079
3554
|
] }),
|
|
3080
|
-
/* @__PURE__ */
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3555
|
+
showAgentFilter ? /* @__PURE__ */ jsx50(
|
|
3556
|
+
ReportAgentFilterNotice,
|
|
3557
|
+
{
|
|
3558
|
+
applied: agentFilter,
|
|
3559
|
+
onReset: clearFilters,
|
|
3560
|
+
onDismiss: () => setAgentFilter(null)
|
|
3561
|
+
}
|
|
3562
|
+
) : null,
|
|
3563
|
+
/* @__PURE__ */ jsx50(ReportFailureBanner, { failures, onCopyAll: copyAllFailures }),
|
|
3564
|
+
hasContent ? showToc ? /* @__PURE__ */ jsxs35("div", { className: "flex gap-6", children: [
|
|
3565
|
+
/* @__PURE__ */ jsx50(ReportToc, {}),
|
|
3566
|
+
/* @__PURE__ */ jsx50("div", { className: "flex min-w-0 flex-1 flex-col gap-4", children: /* @__PURE__ */ jsx50(ReportFeatureList, {}) })
|
|
3567
|
+
] }) : /* @__PURE__ */ jsx50("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ jsx50(ReportFeatureList, {}) }) : /* @__PURE__ */ jsx50(
|
|
3085
3568
|
ReportEmpty,
|
|
3086
3569
|
{
|
|
3087
3570
|
message: query ? "No scenarios match the search." : void 0
|
|
3088
3571
|
}
|
|
3089
3572
|
),
|
|
3090
|
-
/* @__PURE__ */
|
|
3573
|
+
/* @__PURE__ */ jsx50(
|
|
3091
3574
|
"button",
|
|
3092
3575
|
{
|
|
3093
3576
|
type: "button",
|
|
@@ -3098,14 +3581,14 @@ function ReportInteractiveView({
|
|
|
3098
3581
|
children: "?"
|
|
3099
3582
|
}
|
|
3100
3583
|
),
|
|
3101
|
-
/* @__PURE__ */
|
|
3584
|
+
/* @__PURE__ */ jsx50(
|
|
3102
3585
|
ReportShortcutsHelp,
|
|
3103
3586
|
{
|
|
3104
3587
|
open: helpOpen,
|
|
3105
3588
|
onClose: () => setHelpOpen(false)
|
|
3106
3589
|
}
|
|
3107
3590
|
),
|
|
3108
|
-
toast ? /* @__PURE__ */
|
|
3591
|
+
toast ? /* @__PURE__ */ jsx50(
|
|
3109
3592
|
"div",
|
|
3110
3593
|
{
|
|
3111
3594
|
role: "status",
|
|
@@ -3125,11 +3608,11 @@ function ReportInteractiveView({
|
|
|
3125
3608
|
import { useMemo as useMemo4 } from "react";
|
|
3126
3609
|
|
|
3127
3610
|
// src/interactive/island-renderers.tsx
|
|
3128
|
-
import { createElement, useEffect as
|
|
3611
|
+
import { createElement, useEffect as useEffect11, useState as useState12 } from "react";
|
|
3129
3612
|
|
|
3130
3613
|
// src/components/doc/MermaidView.tsx
|
|
3131
|
-
import { useEffect as
|
|
3132
|
-
import { Fragment as
|
|
3614
|
+
import { useEffect as useEffect10, useRef as useRef6, useState as useState11 } from "react";
|
|
3615
|
+
import { Fragment as Fragment16, jsx as jsx51, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
3133
3616
|
function prefersDark(el) {
|
|
3134
3617
|
const themed = el?.closest("[data-theme]");
|
|
3135
3618
|
if (themed?.dataset.theme === "dark") return true;
|
|
@@ -3138,9 +3621,9 @@ function prefersDark(el) {
|
|
|
3138
3621
|
}
|
|
3139
3622
|
function MermaidView({ entry, load }) {
|
|
3140
3623
|
const ref = useRef6(null);
|
|
3141
|
-
const [svg, setSvg] =
|
|
3142
|
-
const [error, setError] =
|
|
3143
|
-
|
|
3624
|
+
const [svg, setSvg] = useState11(null);
|
|
3625
|
+
const [error, setError] = useState11(null);
|
|
3626
|
+
useEffect10(() => {
|
|
3144
3627
|
let cancelled = false;
|
|
3145
3628
|
const draw = async () => {
|
|
3146
3629
|
let mermaid;
|
|
@@ -3183,9 +3666,9 @@ function MermaidView({ entry, load }) {
|
|
|
3183
3666
|
};
|
|
3184
3667
|
}, [entry.code, load]);
|
|
3185
3668
|
if (svg) {
|
|
3186
|
-
return /* @__PURE__ */
|
|
3187
|
-
entry.title ? /* @__PURE__ */
|
|
3188
|
-
/* @__PURE__ */
|
|
3669
|
+
return /* @__PURE__ */ jsxs36("figure", { ref, className: "my-3", children: [
|
|
3670
|
+
entry.title ? /* @__PURE__ */ jsx51("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
|
|
3671
|
+
/* @__PURE__ */ jsx51(
|
|
3189
3672
|
"div",
|
|
3190
3673
|
{
|
|
3191
3674
|
role: "img",
|
|
@@ -3196,8 +3679,8 @@ function MermaidView({ entry, load }) {
|
|
|
3196
3679
|
)
|
|
3197
3680
|
] });
|
|
3198
3681
|
}
|
|
3199
|
-
return /* @__PURE__ */
|
|
3200
|
-
error ? /* @__PURE__ */
|
|
3682
|
+
return /* @__PURE__ */ jsxs36(Fragment16, { children: [
|
|
3683
|
+
error ? /* @__PURE__ */ jsxs36(
|
|
3201
3684
|
"p",
|
|
3202
3685
|
{
|
|
3203
3686
|
role: "alert",
|
|
@@ -3209,12 +3692,12 @@ function MermaidView({ entry, load }) {
|
|
|
3209
3692
|
]
|
|
3210
3693
|
}
|
|
3211
3694
|
) : null,
|
|
3212
|
-
/* @__PURE__ */
|
|
3695
|
+
/* @__PURE__ */ jsx51(MermaidSource, { entry, ref })
|
|
3213
3696
|
] });
|
|
3214
3697
|
}
|
|
3215
3698
|
|
|
3216
3699
|
// src/interactive/island-renderers.tsx
|
|
3217
|
-
import { jsx as
|
|
3700
|
+
import { jsx as jsx52 } from "react/jsx-runtime";
|
|
3218
3701
|
var HLJS_ESM = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/highlight.min.js";
|
|
3219
3702
|
var MERMAID_ESM = "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
|
|
3220
3703
|
function cachedCdnModule(url) {
|
|
@@ -3231,8 +3714,8 @@ function cachedCdnModule(url) {
|
|
|
3231
3714
|
var loadMermaidFromCdn = cachedCdnModule(MERMAID_ESM);
|
|
3232
3715
|
var loadHljs = cachedCdnModule(HLJS_ESM);
|
|
3233
3716
|
function CdnHighlightedCode({ entry }) {
|
|
3234
|
-
const [html, setHtml] =
|
|
3235
|
-
|
|
3717
|
+
const [html, setHtml] = useState12(null);
|
|
3718
|
+
useEffect11(() => {
|
|
3236
3719
|
let cancelled = false;
|
|
3237
3720
|
void (async () => {
|
|
3238
3721
|
try {
|
|
@@ -3248,13 +3731,13 @@ function CdnHighlightedCode({ entry }) {
|
|
|
3248
3731
|
cancelled = true;
|
|
3249
3732
|
};
|
|
3250
3733
|
}, [entry.content, entry.lang]);
|
|
3251
|
-
return /* @__PURE__ */
|
|
3734
|
+
return /* @__PURE__ */ jsx52(CodeFigure, { label: entry.label, children: html !== null ? /* @__PURE__ */ jsx52(
|
|
3252
3735
|
"code",
|
|
3253
3736
|
{
|
|
3254
3737
|
className: cn("hljs font-mono text-xs", entry.lang && `language-${entry.lang}`),
|
|
3255
3738
|
dangerouslySetInnerHTML: { __html: html }
|
|
3256
3739
|
}
|
|
3257
|
-
) : /* @__PURE__ */
|
|
3740
|
+
) : /* @__PURE__ */ jsx52("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
|
|
3258
3741
|
}
|
|
3259
3742
|
function buildIslandRenderers(opts) {
|
|
3260
3743
|
const renderers = {};
|
|
@@ -3268,7 +3751,7 @@ function buildIslandRenderers(opts) {
|
|
|
3268
3751
|
}
|
|
3269
3752
|
|
|
3270
3753
|
// src/interactive/ReportInteractiveIsland.tsx
|
|
3271
|
-
import { jsx as
|
|
3754
|
+
import { jsx as jsx53 } from "react/jsx-runtime";
|
|
3272
3755
|
function ReportInteractiveIsland({
|
|
3273
3756
|
report,
|
|
3274
3757
|
title,
|
|
@@ -3282,7 +3765,7 @@ function ReportInteractiveIsland({
|
|
|
3282
3765
|
() => buildIslandRenderers({ syntaxHighlighting, mermaid }),
|
|
3283
3766
|
[syntaxHighlighting, mermaid]
|
|
3284
3767
|
);
|
|
3285
|
-
return /* @__PURE__ */
|
|
3768
|
+
return /* @__PURE__ */ jsx53(
|
|
3286
3769
|
ReportInteractive,
|
|
3287
3770
|
{
|
|
3288
3771
|
report,
|