executable-stories-react 0.13.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 +401 -221
- 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 +354 -174
- package/dist/interactive.js.map +1 -1
- package/dist/report-island.global.js +31 -30
- package/dist/ssr.cjs +73 -52
- package/dist/ssr.cjs.map +1 -1
- package/dist/ssr.js +73 -52
- package/dist/ssr.js.map +1 -1
- package/dist/styles.css +1 -3
- package/dist/tailwind.css +1 -1
- package/package.json +2 -2
package/dist/interactive.cjs
CHANGED
|
@@ -48,8 +48,8 @@ module.exports = __toCommonJS(interactive_exports);
|
|
|
48
48
|
|
|
49
49
|
// src/interactive/ReportInteractive.tsx
|
|
50
50
|
var import_lucide_react6 = require("lucide-react");
|
|
51
|
-
var
|
|
52
|
-
var
|
|
51
|
+
var import_react22 = require("webmcpable/react");
|
|
52
|
+
var import_react23 = require("react");
|
|
53
53
|
|
|
54
54
|
// src/components/ui/empty.tsx
|
|
55
55
|
var import_class_variance_authority = require("class-variance-authority");
|
|
@@ -242,7 +242,7 @@ function formatValue(value) {
|
|
|
242
242
|
function DocKv({ entry }) {
|
|
243
243
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("dl", { className: "my-2 flex flex-wrap items-baseline gap-x-2 text-sm", children: [
|
|
244
244
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("dt", { className: "font-semibold text-muted-foreground", children: entry.label }),
|
|
245
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("dd", { className: "font-mono text-foreground", children: formatValue(entry.value) })
|
|
245
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("dd", { className: "min-w-0 break-words font-mono text-foreground", children: formatValue(entry.value) })
|
|
246
246
|
] });
|
|
247
247
|
}
|
|
248
248
|
|
|
@@ -450,7 +450,7 @@ function DocHtml({ entry }) {
|
|
|
450
450
|
loading: "lazy",
|
|
451
451
|
title,
|
|
452
452
|
className: "block w-full border-0",
|
|
453
|
-
style: { height }
|
|
453
|
+
style: { height, colorScheme: "light", background: "#fff" }
|
|
454
454
|
}
|
|
455
455
|
)
|
|
456
456
|
] });
|
|
@@ -1174,6 +1174,24 @@ function scenarioToPrompt(scenario) {
|
|
|
1174
1174
|
}
|
|
1175
1175
|
return lines.join("\n");
|
|
1176
1176
|
}
|
|
1177
|
+
function failuresToPrompt(scenarios) {
|
|
1178
|
+
if (scenarios.length === 0) return "";
|
|
1179
|
+
const noun = scenarios.length === 1 ? "test scenario is" : "test scenarios are";
|
|
1180
|
+
const lines = [
|
|
1181
|
+
`${scenarios.length} ${noun} failing. Investigate the likely cause (they may share one) and propose a fix.`
|
|
1182
|
+
];
|
|
1183
|
+
scenarios.forEach((scenario, i) => {
|
|
1184
|
+
lines.push("", `${i + 1}. ${scenario.title}`, "Steps:");
|
|
1185
|
+
for (const step of scenario.steps) {
|
|
1186
|
+
const mark = step.status === "failed" ? " \u27F5 failed here" : "";
|
|
1187
|
+
lines.push(` ${step.keyword} ${step.text}${mark}`);
|
|
1188
|
+
}
|
|
1189
|
+
if (scenario.errorMessage) {
|
|
1190
|
+
lines.push("Error:", scenario.errorMessage.trim());
|
|
1191
|
+
}
|
|
1192
|
+
});
|
|
1193
|
+
return lines.join("\n");
|
|
1194
|
+
}
|
|
1177
1195
|
function scenarioPermalink(scenario) {
|
|
1178
1196
|
if (typeof location === "undefined") return `#${scenario.id}`;
|
|
1179
1197
|
return `${location.href.split("#")[0]}#${scenario.id}`;
|
|
@@ -1299,57 +1317,68 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1299
1317
|
className: "gap-0 py-0",
|
|
1300
1318
|
children: [
|
|
1301
1319
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(CardHeader, { className: "px-4 py-3", children: [
|
|
1302
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
}
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1320
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
1321
|
+
"div",
|
|
1322
|
+
{
|
|
1323
|
+
className: cn(
|
|
1324
|
+
// Wraps rather than squeezing: on a phone the status/duration group
|
|
1325
|
+
// is ~160px, which leaves a title column a few characters wide.
|
|
1326
|
+
"flex flex-wrap items-start gap-x-4 gap-y-1",
|
|
1327
|
+
hideTitle ? "justify-end" : "justify-between"
|
|
1328
|
+
),
|
|
1329
|
+
children: [
|
|
1330
|
+
hideTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("h3", { id: titleId, className: "flex min-w-0 flex-1 basis-48 items-center gap-2 text-sm font-medium text-foreground", children: [
|
|
1331
|
+
collapsible ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1332
|
+
"button",
|
|
1333
|
+
{
|
|
1334
|
+
type: "button",
|
|
1335
|
+
onClick: () => collapse.toggle(scenario.id),
|
|
1336
|
+
"aria-expanded": !collapsed,
|
|
1337
|
+
"aria-controls": bodyId,
|
|
1338
|
+
"aria-label": `Toggle ${scenario.title}`,
|
|
1339
|
+
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
1340
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
1341
|
+
}
|
|
1342
|
+
) : null,
|
|
1343
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
|
|
1344
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { children: scenario.title })
|
|
1345
|
+
] }),
|
|
1346
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
1347
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ScenarioRunHistory, { scenarioId: scenario.id }),
|
|
1348
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ScenarioStaleness, { scenario }),
|
|
1349
|
+
scenario.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: (0, import_duration3.formatDuration)(scenario.durationMs) }) : null,
|
|
1350
|
+
meta.showPill ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "sr-only", children: `Status: ${label}` }),
|
|
1351
|
+
actions ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(DropdownMenu, { children: [
|
|
1352
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1353
|
+
DropdownMenuTrigger,
|
|
1354
|
+
{
|
|
1355
|
+
"aria-label": `Actions for ${scenario.title}`,
|
|
1356
|
+
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
1357
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react2.MoreHorizontalIcon, { "aria-hidden": true })
|
|
1358
|
+
}
|
|
1359
|
+
),
|
|
1360
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(DropdownMenuContent, { align: "end", children: [
|
|
1361
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
|
|
1362
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react2.LinkIcon, {}),
|
|
1363
|
+
" Copy link"
|
|
1364
|
+
] }),
|
|
1365
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
|
|
1366
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react2.FileTextIcon, {}),
|
|
1367
|
+
" Copy as Markdown"
|
|
1368
|
+
] }),
|
|
1369
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
|
|
1370
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react2.SparklesIcon, {}),
|
|
1371
|
+
" Explain with AI"
|
|
1372
|
+
] })
|
|
1373
|
+
] })
|
|
1374
|
+
] }) : null
|
|
1346
1375
|
] })
|
|
1347
|
-
]
|
|
1348
|
-
|
|
1349
|
-
|
|
1376
|
+
]
|
|
1377
|
+
}
|
|
1378
|
+
),
|
|
1350
1379
|
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
|
|
1351
1380
|
scenario.tags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
|
|
1352
|
-
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("li", { children: ticket.url ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
|
|
1381
|
+
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("li", { children: ticket.url ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", className: "inline-flex min-h-6 items-center", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
|
|
1353
1382
|
] }) : null
|
|
1354
1383
|
] }),
|
|
1355
1384
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
|
|
@@ -1492,6 +1521,7 @@ function ReportFeatureList() {
|
|
|
1492
1521
|
|
|
1493
1522
|
// src/components/ReportMeta.tsx
|
|
1494
1523
|
var import_duration4 = require("executable-stories-core/utils/duration");
|
|
1524
|
+
var import_report_queries = require("executable-stories-core/report-queries");
|
|
1495
1525
|
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
1496
1526
|
function ReportMeta() {
|
|
1497
1527
|
const report = useReport();
|
|
@@ -1535,7 +1565,9 @@ function ReportMeta() {
|
|
|
1535
1565
|
value: url ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
|
|
1536
1566
|
});
|
|
1537
1567
|
}
|
|
1538
|
-
|
|
1568
|
+
const slowest = (0, import_report_queries.slowestScenarios)(report, 5);
|
|
1569
|
+
const showSlowest = slowest.length >= 3;
|
|
1570
|
+
if (items.length === 0 && !showSlowest) return null;
|
|
1539
1571
|
return (
|
|
1540
1572
|
// Run metadata is useful but secondary to "what failed" — tuck it into a
|
|
1541
1573
|
// collapsed disclosure so it doesn't push the result down. Native <details>
|
|
@@ -1548,7 +1580,14 @@ function ReportMeta() {
|
|
|
1548
1580
|
/* @__PURE__ */ (0, import_jsx_runtime32.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_runtime32.jsxs)("div", { className: "flex items-baseline gap-1.5", children: [
|
|
1549
1581
|
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("dt", { className: "font-medium", children: item.label }),
|
|
1550
1582
|
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("dd", { className: "font-mono text-foreground", children: item.value })
|
|
1551
|
-
] }, item.label)) })
|
|
1583
|
+
] }, item.label)) }),
|
|
1584
|
+
showSlowest ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "border-t border-border px-4 py-3", children: [
|
|
1585
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "mb-1.5 font-medium text-muted-foreground", children: "Slowest scenarios" }),
|
|
1586
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("ol", { className: "flex flex-col gap-1", "aria-label": "Slowest scenarios", children: slowest.map((s) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("li", { className: "flex items-baseline justify-between gap-4", children: [
|
|
1587
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("a", { href: `#${s.id}`, className: "min-w-0 text-primary underline underline-offset-2", children: s.title }),
|
|
1588
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "shrink-0 font-mono tabular-nums text-muted-foreground", children: (0, import_duration4.formatDuration)(s.durationMs) })
|
|
1589
|
+
] }, s.id)) })
|
|
1590
|
+
] }) : null
|
|
1552
1591
|
] })
|
|
1553
1592
|
);
|
|
1554
1593
|
}
|
|
@@ -2024,21 +2063,26 @@ function allTags(report) {
|
|
|
2024
2063
|
}
|
|
2025
2064
|
return [...seen];
|
|
2026
2065
|
}
|
|
2027
|
-
function queryMatches(scenario, q) {
|
|
2066
|
+
function queryMatches(scenario, q, sourceFile) {
|
|
2028
2067
|
if (q === "") return true;
|
|
2029
2068
|
if (scenario.title.toLowerCase().includes(q)) return true;
|
|
2069
|
+
if (sourceFile?.toLowerCase().includes(q)) return true;
|
|
2070
|
+
if (scenario.errorMessage?.toLowerCase().includes(q)) return true;
|
|
2030
2071
|
for (const tag of scenario.tags) {
|
|
2031
2072
|
if (tag.toLowerCase().includes(q)) return true;
|
|
2032
2073
|
}
|
|
2074
|
+
for (const ticket of scenario.tickets ?? []) {
|
|
2075
|
+
if (ticket.id.toLowerCase().includes(q)) return true;
|
|
2076
|
+
}
|
|
2033
2077
|
for (const step of scenario.steps) {
|
|
2034
2078
|
if (step.text.toLowerCase().includes(q)) return true;
|
|
2035
2079
|
}
|
|
2036
2080
|
return false;
|
|
2037
2081
|
}
|
|
2038
|
-
function scenarioMatches(scenario, q, status, tags) {
|
|
2082
|
+
function scenarioMatches(scenario, q, status, tags, sourceFile) {
|
|
2039
2083
|
if (status !== "all" && scenario.status !== status) return false;
|
|
2040
2084
|
if (tags.length > 0 && !tags.some((t) => scenario.tags.includes(t))) return false;
|
|
2041
|
-
return queryMatches(scenario, q);
|
|
2085
|
+
return queryMatches(scenario, q, sourceFile);
|
|
2042
2086
|
}
|
|
2043
2087
|
function summarizeScenarios(scenarios) {
|
|
2044
2088
|
let total = 0, passed = 0, failed = 0, skipped = 0, pending = 0, durationMs = 0;
|
|
@@ -2061,7 +2105,9 @@ function filterReport(report, criteria) {
|
|
|
2061
2105
|
const features = [];
|
|
2062
2106
|
let topTotal = 0, topPassed = 0, topFailed = 0, topSkipped = 0, topPending = 0, topDuration = 0;
|
|
2063
2107
|
for (const feature of report.features) {
|
|
2064
|
-
const matched = feature.scenarios.filter(
|
|
2108
|
+
const matched = feature.scenarios.filter(
|
|
2109
|
+
(s) => scenarioMatches(s, q, status, tags, feature.sourceFile)
|
|
2110
|
+
);
|
|
2065
2111
|
if (matched.length === 0) continue;
|
|
2066
2112
|
const summary = summarizeScenarios(matched);
|
|
2067
2113
|
features.push({ ...feature, summary, scenarios: matched });
|
|
@@ -2085,6 +2131,9 @@ function filterReport(report, criteria) {
|
|
|
2085
2131
|
features
|
|
2086
2132
|
};
|
|
2087
2133
|
}
|
|
2134
|
+
function failedScenarios(report) {
|
|
2135
|
+
return report.features.flatMap((f) => f.scenarios.filter((s) => s.status === "failed"));
|
|
2136
|
+
}
|
|
2088
2137
|
function listFailures(report) {
|
|
2089
2138
|
const out = [];
|
|
2090
2139
|
for (const feature of report.features) {
|
|
@@ -2168,7 +2217,7 @@ function ReportAgentFilterNotice({
|
|
|
2168
2217
|
// src/interactive/ReportFailureBanner.tsx
|
|
2169
2218
|
var import_react10 = require("react");
|
|
2170
2219
|
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
2171
|
-
function ReportFailureBanner({ failures }) {
|
|
2220
|
+
function ReportFailureBanner({ failures, onCopyAll }) {
|
|
2172
2221
|
const first = failures[0];
|
|
2173
2222
|
const jumpToFirst = (0, import_react10.useCallback)(() => {
|
|
2174
2223
|
if (!first) return;
|
|
@@ -2198,7 +2247,23 @@ function ReportFailureBanner({ failures }) {
|
|
|
2198
2247
|
"aria-label": "View first failure",
|
|
2199
2248
|
children: "View first failure \u2193"
|
|
2200
2249
|
}
|
|
2201
|
-
)
|
|
2250
|
+
),
|
|
2251
|
+
onCopyAll ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
|
|
2252
|
+
"button",
|
|
2253
|
+
{
|
|
2254
|
+
type: "button",
|
|
2255
|
+
className: "es-failure-banner-jump",
|
|
2256
|
+
onClick: onCopyAll,
|
|
2257
|
+
"aria-label": "Copy failures for an agent",
|
|
2258
|
+
children: [
|
|
2259
|
+
"Copy ",
|
|
2260
|
+
failures.length,
|
|
2261
|
+
" failure",
|
|
2262
|
+
failures.length === 1 ? "" : "s",
|
|
2263
|
+
" for an agent"
|
|
2264
|
+
]
|
|
2265
|
+
}
|
|
2266
|
+
) : null
|
|
2202
2267
|
]
|
|
2203
2268
|
}
|
|
2204
2269
|
);
|
|
@@ -2403,7 +2468,7 @@ var ReportSearch = (0, import_react13.forwardRef)(
|
|
|
2403
2468
|
onChange,
|
|
2404
2469
|
matchedCount,
|
|
2405
2470
|
totalCount,
|
|
2406
|
-
placeholder = "Search scenarios
|
|
2471
|
+
placeholder = "Search scenarios, tags, tickets, errors\u2026",
|
|
2407
2472
|
className
|
|
2408
2473
|
} = props;
|
|
2409
2474
|
const inputId = (0, import_react13.useId)();
|
|
@@ -2461,9 +2526,119 @@ var ReportSearch = (0, import_react13.forwardRef)(
|
|
|
2461
2526
|
}
|
|
2462
2527
|
);
|
|
2463
2528
|
|
|
2464
|
-
// src/interactive/
|
|
2529
|
+
// src/interactive/ReportSinceLastVisit.tsx
|
|
2465
2530
|
var import_react14 = require("react");
|
|
2466
2531
|
|
|
2532
|
+
// src/interactive/last-visit.ts
|
|
2533
|
+
function snapshotOf(report, atMs) {
|
|
2534
|
+
const statuses = {};
|
|
2535
|
+
for (const feature of report.features) {
|
|
2536
|
+
for (const scenario of feature.scenarios) {
|
|
2537
|
+
statuses[scenario.id] = scenario.status;
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
return { runId: report.runId, atMs, statuses };
|
|
2541
|
+
}
|
|
2542
|
+
function diffSinceVisit(previous, report) {
|
|
2543
|
+
if (!previous) return null;
|
|
2544
|
+
if (previous.runId === report.runId) return null;
|
|
2545
|
+
const newlyFailing = [];
|
|
2546
|
+
const newlyPassing = [];
|
|
2547
|
+
const added = [];
|
|
2548
|
+
for (const feature of report.features) {
|
|
2549
|
+
for (const scenario of feature.scenarios) {
|
|
2550
|
+
const ref = { id: scenario.id, title: scenario.title };
|
|
2551
|
+
const before = previous.statuses[scenario.id];
|
|
2552
|
+
if (before === void 0) {
|
|
2553
|
+
added.push(ref);
|
|
2554
|
+
} else if (before !== "failed" && scenario.status === "failed") {
|
|
2555
|
+
newlyFailing.push(ref);
|
|
2556
|
+
} else if (before === "failed" && scenario.status === "passed") {
|
|
2557
|
+
newlyPassing.push(ref);
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
}
|
|
2561
|
+
if (newlyFailing.length === 0 && newlyPassing.length === 0 && added.length === 0) return null;
|
|
2562
|
+
return { sinceMs: previous.atMs, newlyFailing, newlyPassing, added };
|
|
2563
|
+
}
|
|
2564
|
+
|
|
2565
|
+
// src/interactive/ReportSinceLastVisit.tsx
|
|
2566
|
+
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
2567
|
+
var KEY = "es-last-visit";
|
|
2568
|
+
var MAX_LINKS2 = 5;
|
|
2569
|
+
function readVisit() {
|
|
2570
|
+
try {
|
|
2571
|
+
const raw = localStorage.getItem(KEY);
|
|
2572
|
+
if (!raw) return null;
|
|
2573
|
+
const parsed = JSON.parse(raw);
|
|
2574
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
2575
|
+
const v = parsed;
|
|
2576
|
+
if (typeof v.runId !== "string" || typeof v.atMs !== "number" || typeof v.statuses !== "object") {
|
|
2577
|
+
return null;
|
|
2578
|
+
}
|
|
2579
|
+
return { runId: v.runId, atMs: v.atMs, statuses: v.statuses };
|
|
2580
|
+
} catch {
|
|
2581
|
+
return null;
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2584
|
+
function writeVisit(snapshot) {
|
|
2585
|
+
try {
|
|
2586
|
+
localStorage.setItem(KEY, JSON.stringify(snapshot));
|
|
2587
|
+
} catch {
|
|
2588
|
+
}
|
|
2589
|
+
}
|
|
2590
|
+
function ScenarioLinks2({ scenarios, tone }) {
|
|
2591
|
+
return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_jsx_runtime47.Fragment, { children: [
|
|
2592
|
+
scenarios.slice(0, MAX_LINKS2).map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { children: [
|
|
2593
|
+
i > 0 ? ", " : "",
|
|
2594
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("a", { href: `#${s.id}`, className: cn("underline underline-offset-2 hover:no-underline", tone), children: s.title })
|
|
2595
|
+
] }, s.id)),
|
|
2596
|
+
scenarios.length > MAX_LINKS2 ? /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { children: [
|
|
2597
|
+
" and ",
|
|
2598
|
+
scenarios.length - MAX_LINKS2,
|
|
2599
|
+
" more"
|
|
2600
|
+
] }) : null
|
|
2601
|
+
] });
|
|
2602
|
+
}
|
|
2603
|
+
function ReportSinceLastVisit({ report }) {
|
|
2604
|
+
const [delta, setDelta] = (0, import_react14.useState)(null);
|
|
2605
|
+
const [nowMs, setNowMs] = (0, import_react14.useState)(0);
|
|
2606
|
+
(0, import_react14.useEffect)(() => {
|
|
2607
|
+
const now = Date.now();
|
|
2608
|
+
setDelta(diffSinceVisit(readVisit(), report));
|
|
2609
|
+
setNowMs(now);
|
|
2610
|
+
writeVisit(snapshotOf(report, now));
|
|
2611
|
+
}, [report]);
|
|
2612
|
+
if (!delta) return null;
|
|
2613
|
+
const { newlyFailing, newlyPassing, added } = delta;
|
|
2614
|
+
return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("p", { className: "text-xs text-muted-foreground", "data-testid": "es-since-last-visit", children: [
|
|
2615
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "font-medium text-foreground", children: [
|
|
2616
|
+
"Since your last visit (",
|
|
2617
|
+
formatRelativeAge(delta.sinceMs, nowMs),
|
|
2618
|
+
"):"
|
|
2619
|
+
] }),
|
|
2620
|
+
newlyFailing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "ml-2 text-fail", children: [
|
|
2621
|
+
newlyFailing.length,
|
|
2622
|
+
" started failing (",
|
|
2623
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ScenarioLinks2, { scenarios: newlyFailing, tone: "text-fail" }),
|
|
2624
|
+
")"
|
|
2625
|
+
] }) : null,
|
|
2626
|
+
newlyPassing.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "ml-2 text-pass", children: [
|
|
2627
|
+
newlyPassing.length,
|
|
2628
|
+
" fixed (",
|
|
2629
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(ScenarioLinks2, { scenarios: newlyPassing, tone: "text-pass" }),
|
|
2630
|
+
")"
|
|
2631
|
+
] }) : null,
|
|
2632
|
+
added.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "ml-2", children: [
|
|
2633
|
+
added.length,
|
|
2634
|
+
" new"
|
|
2635
|
+
] }) : null
|
|
2636
|
+
] });
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2639
|
+
// src/interactive/ReportShortcutsHelp.tsx
|
|
2640
|
+
var import_react15 = require("react");
|
|
2641
|
+
|
|
2467
2642
|
// src/components/ui/button.tsx
|
|
2468
2643
|
var React7 = require("react");
|
|
2469
2644
|
var import_class_variance_authority4 = require("class-variance-authority");
|
|
@@ -2518,7 +2693,7 @@ function Button({
|
|
|
2518
2693
|
}
|
|
2519
2694
|
|
|
2520
2695
|
// src/interactive/ReportShortcutsHelp.tsx
|
|
2521
|
-
var
|
|
2696
|
+
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
2522
2697
|
var SHORTCUTS = [
|
|
2523
2698
|
{ keys: "/", description: "Focus search" },
|
|
2524
2699
|
{ keys: "f", description: "Jump to next failure" },
|
|
@@ -2530,20 +2705,20 @@ var SHORTCUTS = [
|
|
|
2530
2705
|
];
|
|
2531
2706
|
function Keys({ keys }) {
|
|
2532
2707
|
const parts = keys.split(" ");
|
|
2533
|
-
return /* @__PURE__ */ (0,
|
|
2534
|
-
i > 0 ? /* @__PURE__ */ (0,
|
|
2535
|
-
/* @__PURE__ */ (0,
|
|
2708
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "inline-flex items-center gap-1", children: parts.map((k, i) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
|
|
2709
|
+
i > 0 ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "text-xs text-muted-foreground", children: "+" }) : null,
|
|
2710
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.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 })
|
|
2536
2711
|
] }, k)) });
|
|
2537
2712
|
}
|
|
2538
2713
|
function ReportShortcutsHelp({ open, onClose }) {
|
|
2539
|
-
const dialogRef = (0,
|
|
2540
|
-
(0,
|
|
2714
|
+
const dialogRef = (0, import_react15.useRef)(null);
|
|
2715
|
+
(0, import_react15.useEffect)(() => {
|
|
2541
2716
|
const dialog = dialogRef.current;
|
|
2542
2717
|
if (!dialog) return;
|
|
2543
2718
|
if (open && !dialog.open) dialog.showModal();
|
|
2544
2719
|
else if (!open && dialog.open) dialog.close();
|
|
2545
2720
|
}, [open]);
|
|
2546
|
-
return /* @__PURE__ */ (0,
|
|
2721
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
|
|
2547
2722
|
"dialog",
|
|
2548
2723
|
{
|
|
2549
2724
|
ref: dialogRef,
|
|
@@ -2551,20 +2726,20 @@ function ReportShortcutsHelp({ open, onClose }) {
|
|
|
2551
2726
|
"aria-label": "Keyboard shortcuts",
|
|
2552
2727
|
onClose,
|
|
2553
2728
|
children: [
|
|
2554
|
-
/* @__PURE__ */ (0,
|
|
2555
|
-
/* @__PURE__ */ (0,
|
|
2556
|
-
/* @__PURE__ */ (0,
|
|
2557
|
-
/* @__PURE__ */ (0,
|
|
2729
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("h2", { className: "text-base font-semibold", children: "Keyboard shortcuts" }),
|
|
2730
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.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_runtime48.jsxs)("div", { className: "col-span-2 grid grid-cols-subgrid items-center", children: [
|
|
2731
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("dt", { className: "justify-self-start", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(Keys, { keys: s.keys }) }),
|
|
2732
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("dd", { className: "text-sm text-muted-foreground", children: s.description })
|
|
2558
2733
|
] }, s.keys)) }),
|
|
2559
|
-
/* @__PURE__ */ (0,
|
|
2734
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("form", { method: "dialog", className: "mt-6", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(Button, { type: "submit", variant: "outline", size: "sm", children: "Close" }) })
|
|
2560
2735
|
]
|
|
2561
2736
|
}
|
|
2562
2737
|
);
|
|
2563
2738
|
}
|
|
2564
2739
|
|
|
2565
2740
|
// src/interactive/ReportToc.tsx
|
|
2566
|
-
var
|
|
2567
|
-
var
|
|
2741
|
+
var import_react16 = require("react");
|
|
2742
|
+
var import_jsx_runtime49 = require("react/jsx-runtime");
|
|
2568
2743
|
var DOT = {
|
|
2569
2744
|
passed: "bg-pass",
|
|
2570
2745
|
failed: "bg-fail",
|
|
@@ -2573,12 +2748,12 @@ var DOT = {
|
|
|
2573
2748
|
};
|
|
2574
2749
|
function TocContent({ onNavigate }) {
|
|
2575
2750
|
const report = useReport();
|
|
2576
|
-
const [activeId, setActiveId] = (0,
|
|
2577
|
-
const scenarioIds = (0,
|
|
2751
|
+
const [activeId, setActiveId] = (0, import_react16.useState)(null);
|
|
2752
|
+
const scenarioIds = (0, import_react16.useMemo)(
|
|
2578
2753
|
() => report.features.flatMap((f) => f.scenarios.map((s) => s.id)),
|
|
2579
2754
|
[report]
|
|
2580
2755
|
);
|
|
2581
|
-
(0,
|
|
2756
|
+
(0, import_react16.useEffect)(() => {
|
|
2582
2757
|
if (typeof IntersectionObserver === "undefined") return;
|
|
2583
2758
|
const els = scenarioIds.map((id) => document.getElementById(id)).filter((el) => el !== null);
|
|
2584
2759
|
if (els.length === 0) return;
|
|
@@ -2593,11 +2768,11 @@ function TocContent({ onNavigate }) {
|
|
|
2593
2768
|
return () => observer.disconnect();
|
|
2594
2769
|
}, [scenarioIds]);
|
|
2595
2770
|
if (report.features.length === 0) return null;
|
|
2596
|
-
return /* @__PURE__ */ (0,
|
|
2597
|
-
/* @__PURE__ */ (0,
|
|
2598
|
-
/* @__PURE__ */ (0,
|
|
2771
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("ul", { className: "flex list-none flex-col gap-4 pl-0", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("li", { children: [
|
|
2772
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: "mb-1.5 font-semibold leading-snug text-foreground", children: feature.title }),
|
|
2773
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("ul", { className: "flex list-none flex-col gap-0.5 pl-0", children: feature.scenarios.map((scenario) => {
|
|
2599
2774
|
const active = activeId === scenario.id;
|
|
2600
|
-
return /* @__PURE__ */ (0,
|
|
2775
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
|
|
2601
2776
|
"a",
|
|
2602
2777
|
{
|
|
2603
2778
|
href: `#${scenario.id}`,
|
|
@@ -2612,14 +2787,14 @@ function TocContent({ onNavigate }) {
|
|
|
2612
2787
|
active ? "border-primary font-medium text-foreground" : "border-border text-muted-foreground"
|
|
2613
2788
|
),
|
|
2614
2789
|
children: [
|
|
2615
|
-
/* @__PURE__ */ (0,
|
|
2790
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
2616
2791
|
"span",
|
|
2617
2792
|
{
|
|
2618
2793
|
"aria-hidden": true,
|
|
2619
2794
|
className: cn("mt-1 size-1.5 shrink-0 rounded-full", DOT[scenario.status])
|
|
2620
2795
|
}
|
|
2621
2796
|
),
|
|
2622
|
-
/* @__PURE__ */ (0,
|
|
2797
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "break-words", children: scenario.title })
|
|
2623
2798
|
]
|
|
2624
2799
|
}
|
|
2625
2800
|
) }, scenario.id);
|
|
@@ -2629,48 +2804,48 @@ function TocContent({ onNavigate }) {
|
|
|
2629
2804
|
function ReportToc() {
|
|
2630
2805
|
const report = useReport();
|
|
2631
2806
|
if (report.features.length === 0) return null;
|
|
2632
|
-
return /* @__PURE__ */ (0,
|
|
2807
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
|
|
2633
2808
|
"nav",
|
|
2634
2809
|
{
|
|
2635
2810
|
"aria-label": "Table of contents",
|
|
2636
2811
|
className: "sticky top-4 hidden h-fit w-64 shrink-0 self-start text-xs lg:block",
|
|
2637
2812
|
children: [
|
|
2638
|
-
/* @__PURE__ */ (0,
|
|
2639
|
-
/* @__PURE__ */ (0,
|
|
2813
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: "mb-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Contents" }),
|
|
2814
|
+
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)(TocContent, {})
|
|
2640
2815
|
]
|
|
2641
2816
|
}
|
|
2642
2817
|
);
|
|
2643
2818
|
}
|
|
2644
2819
|
|
|
2645
2820
|
// src/interactive/ReportTocDrawer.tsx
|
|
2646
|
-
var
|
|
2821
|
+
var import_react17 = require("react");
|
|
2647
2822
|
var import_dialog = require("@base-ui/react/dialog");
|
|
2648
2823
|
var import_lucide_react5 = require("lucide-react");
|
|
2649
|
-
var
|
|
2824
|
+
var import_jsx_runtime50 = require("react/jsx-runtime");
|
|
2650
2825
|
function ReportTocDrawer() {
|
|
2651
2826
|
const report = useReport();
|
|
2652
|
-
const [open, setOpen] = (0,
|
|
2827
|
+
const [open, setOpen] = (0, import_react17.useState)(false);
|
|
2653
2828
|
if (report.features.length === 0) return null;
|
|
2654
|
-
return /* @__PURE__ */ (0,
|
|
2655
|
-
/* @__PURE__ */ (0,
|
|
2656
|
-
/* @__PURE__ */ (0,
|
|
2829
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_dialog.Dialog.Root, { open, onOpenChange: setOpen, children: [
|
|
2830
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.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: [
|
|
2831
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_lucide_react5.ListIcon, { "aria-hidden": true }),
|
|
2657
2832
|
" Contents"
|
|
2658
2833
|
] }),
|
|
2659
|
-
/* @__PURE__ */ (0,
|
|
2660
|
-
/* @__PURE__ */ (0,
|
|
2661
|
-
/* @__PURE__ */ (0,
|
|
2662
|
-
/* @__PURE__ */ (0,
|
|
2663
|
-
/* @__PURE__ */ (0,
|
|
2664
|
-
/* @__PURE__ */ (0,
|
|
2834
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_dialog.Dialog.Portal, { children: [
|
|
2835
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.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" }),
|
|
2836
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.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: [
|
|
2837
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
2838
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_dialog.Dialog.Title, { className: "text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Contents" }),
|
|
2839
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
2665
2840
|
import_dialog.Dialog.Close,
|
|
2666
2841
|
{
|
|
2667
2842
|
"aria-label": "Close contents",
|
|
2668
2843
|
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
2669
|
-
children: /* @__PURE__ */ (0,
|
|
2844
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_lucide_react5.XIcon, { "aria-hidden": true })
|
|
2670
2845
|
}
|
|
2671
2846
|
)
|
|
2672
2847
|
] }),
|
|
2673
|
-
/* @__PURE__ */ (0,
|
|
2848
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(TocContent, { onNavigate: () => setOpen(false) })
|
|
2674
2849
|
] })
|
|
2675
2850
|
] })
|
|
2676
2851
|
] });
|
|
@@ -2704,10 +2879,10 @@ function failuresFirst(report) {
|
|
|
2704
2879
|
}
|
|
2705
2880
|
|
|
2706
2881
|
// src/interactive/use-deep-link-scroll.ts
|
|
2707
|
-
var
|
|
2882
|
+
var import_react18 = require("react");
|
|
2708
2883
|
function useDeepLinkScroll() {
|
|
2709
|
-
const lastAnchor = (0,
|
|
2710
|
-
(0,
|
|
2884
|
+
const lastAnchor = (0, import_react18.useRef)(null);
|
|
2885
|
+
(0, import_react18.useEffect)(() => {
|
|
2711
2886
|
function scrollToHash() {
|
|
2712
2887
|
const { anchor } = splitHash(window.location.hash);
|
|
2713
2888
|
if (!anchor || anchor === lastAnchor.current) return;
|
|
@@ -2723,7 +2898,7 @@ function useDeepLinkScroll() {
|
|
|
2723
2898
|
}
|
|
2724
2899
|
|
|
2725
2900
|
// src/interactive/use-keyboard-shortcuts.ts
|
|
2726
|
-
var
|
|
2901
|
+
var import_react19 = require("react");
|
|
2727
2902
|
function isEditableTarget(target) {
|
|
2728
2903
|
if (!(target instanceof HTMLElement)) return false;
|
|
2729
2904
|
const tag = target.tagName;
|
|
@@ -2732,9 +2907,9 @@ function isEditableTarget(target) {
|
|
|
2732
2907
|
return false;
|
|
2733
2908
|
}
|
|
2734
2909
|
function useKeyboardShortcuts(handlers) {
|
|
2735
|
-
const ref = (0,
|
|
2910
|
+
const ref = (0, import_react19.useRef)(handlers);
|
|
2736
2911
|
ref.current = handlers;
|
|
2737
|
-
(0,
|
|
2912
|
+
(0, import_react19.useEffect)(() => {
|
|
2738
2913
|
function onKeyDown(e) {
|
|
2739
2914
|
const h = ref.current;
|
|
2740
2915
|
if (e.key === "Escape") {
|
|
@@ -2778,8 +2953,8 @@ function useKeyboardShortcuts(handlers) {
|
|
|
2778
2953
|
}
|
|
2779
2954
|
|
|
2780
2955
|
// src/interactive/use-theme.ts
|
|
2781
|
-
var
|
|
2782
|
-
var
|
|
2956
|
+
var import_react20 = require("react");
|
|
2957
|
+
var KEY2 = "es-theme";
|
|
2783
2958
|
function systemDark() {
|
|
2784
2959
|
return typeof matchMedia !== "undefined" && matchMedia("(prefers-color-scheme: dark)").matches;
|
|
2785
2960
|
}
|
|
@@ -2793,19 +2968,19 @@ function applyTheme(pref) {
|
|
|
2793
2968
|
}
|
|
2794
2969
|
function initialPref() {
|
|
2795
2970
|
if (typeof localStorage !== "undefined") {
|
|
2796
|
-
const stored = localStorage.getItem(
|
|
2971
|
+
const stored = localStorage.getItem(KEY2);
|
|
2797
2972
|
if (stored === "light" || stored === "dark" || stored === "system") return stored;
|
|
2798
2973
|
}
|
|
2799
2974
|
return "system";
|
|
2800
2975
|
}
|
|
2801
2976
|
function useTheme() {
|
|
2802
|
-
const [pref, setPrefState] = (0,
|
|
2803
|
-
(0,
|
|
2977
|
+
const [pref, setPrefState] = (0, import_react20.useState)("system");
|
|
2978
|
+
(0, import_react20.useEffect)(() => {
|
|
2804
2979
|
const p = initialPref();
|
|
2805
2980
|
setPrefState(p);
|
|
2806
2981
|
applyTheme(p);
|
|
2807
2982
|
}, []);
|
|
2808
|
-
(0,
|
|
2983
|
+
(0, import_react20.useEffect)(() => {
|
|
2809
2984
|
if (typeof matchMedia === "undefined") return;
|
|
2810
2985
|
const mq = matchMedia("(prefers-color-scheme: dark)");
|
|
2811
2986
|
const onChange = () => {
|
|
@@ -2814,11 +2989,11 @@ function useTheme() {
|
|
|
2814
2989
|
mq.addEventListener("change", onChange);
|
|
2815
2990
|
return () => mq.removeEventListener("change", onChange);
|
|
2816
2991
|
}, [pref]);
|
|
2817
|
-
const setPref = (0,
|
|
2992
|
+
const setPref = (0, import_react20.useCallback)((p) => {
|
|
2818
2993
|
setPrefState(p);
|
|
2819
2994
|
applyTheme(p);
|
|
2820
2995
|
try {
|
|
2821
|
-
localStorage.setItem(
|
|
2996
|
+
localStorage.setItem(KEY2, p);
|
|
2822
2997
|
} catch {
|
|
2823
2998
|
}
|
|
2824
2999
|
}, []);
|
|
@@ -2826,19 +3001,19 @@ function useTheme() {
|
|
|
2826
3001
|
}
|
|
2827
3002
|
|
|
2828
3003
|
// src/interactive/use-url-state.ts
|
|
2829
|
-
var
|
|
3004
|
+
var import_react21 = require("react");
|
|
2830
3005
|
var WRITE_DELAY_MS = 250;
|
|
2831
3006
|
function useUrlState() {
|
|
2832
|
-
const [state, setState] = (0,
|
|
2833
|
-
const ready = (0,
|
|
2834
|
-
(0,
|
|
3007
|
+
const [state, setState] = (0, import_react21.useState)(DEFAULT_URL_STATE);
|
|
3008
|
+
const ready = (0, import_react21.useRef)(false);
|
|
3009
|
+
(0, import_react21.useEffect)(() => {
|
|
2835
3010
|
const read = () => setState(decodeUrlState(splitHash(window.location.hash).params));
|
|
2836
3011
|
read();
|
|
2837
3012
|
ready.current = true;
|
|
2838
3013
|
window.addEventListener("hashchange", read);
|
|
2839
3014
|
return () => window.removeEventListener("hashchange", read);
|
|
2840
3015
|
}, []);
|
|
2841
|
-
(0,
|
|
3016
|
+
(0, import_react21.useEffect)(() => {
|
|
2842
3017
|
if (!ready.current) return;
|
|
2843
3018
|
const timer = setTimeout(
|
|
2844
3019
|
() => writeHash(splitHash(window.location.hash).anchor, encodeUrlState(state)),
|
|
@@ -2846,7 +3021,7 @@ function useUrlState() {
|
|
|
2846
3021
|
);
|
|
2847
3022
|
return () => clearTimeout(timer);
|
|
2848
3023
|
}, [state]);
|
|
2849
|
-
const update = (0,
|
|
3024
|
+
const update = (0, import_react21.useCallback)(
|
|
2850
3025
|
(patch) => setState((prev) => ({ ...prev, ...patch })),
|
|
2851
3026
|
[]
|
|
2852
3027
|
);
|
|
@@ -2854,7 +3029,7 @@ function useUrlState() {
|
|
|
2854
3029
|
}
|
|
2855
3030
|
|
|
2856
3031
|
// src/interactive/webmcp-tools.ts
|
|
2857
|
-
var
|
|
3032
|
+
var import_report_queries2 = require("executable-stories-core/report-queries");
|
|
2858
3033
|
var STATUSES2 = [
|
|
2859
3034
|
"passed",
|
|
2860
3035
|
"failed",
|
|
@@ -2937,9 +3112,9 @@ var READ_ONLY = { readOnlyHint: true, untrustedContentHint: true };
|
|
|
2937
3112
|
function reportTools(deps) {
|
|
2938
3113
|
const { report, setView, onAgentFilter } = deps;
|
|
2939
3114
|
const now = deps.now ?? Date.now;
|
|
2940
|
-
const provenance = () => ({ run: (0,
|
|
3115
|
+
const provenance = () => ({ run: (0, import_report_queries2.runProvenance)(report, now()) });
|
|
2941
3116
|
const list = (filters) => {
|
|
2942
|
-
const scenarios = (0,
|
|
3117
|
+
const scenarios = (0, import_report_queries2.listScenarioSummaries)(report, filters);
|
|
2943
3118
|
return { ...provenance(), total: scenarios.length, scenarios };
|
|
2944
3119
|
};
|
|
2945
3120
|
return {
|
|
@@ -2973,7 +3148,7 @@ function reportTools(deps) {
|
|
|
2973
3148
|
execute: () => ({
|
|
2974
3149
|
...provenance(),
|
|
2975
3150
|
summary: report.summary,
|
|
2976
|
-
features: (0,
|
|
3151
|
+
features: (0, import_report_queries2.getFeatureSummary)(report)
|
|
2977
3152
|
})
|
|
2978
3153
|
},
|
|
2979
3154
|
get_scenario: {
|
|
@@ -2992,7 +3167,7 @@ function reportTools(deps) {
|
|
|
2992
3167
|
},
|
|
2993
3168
|
execute: (input) => guarded(() => {
|
|
2994
3169
|
const idOrTitle = readString(asRecord(input), "idOrTitle") ?? "";
|
|
2995
|
-
const found = (0,
|
|
3170
|
+
const found = (0, import_report_queries2.getScenario)(report, idOrTitle);
|
|
2996
3171
|
if (!found) {
|
|
2997
3172
|
return {
|
|
2998
3173
|
...provenance(),
|
|
@@ -3009,7 +3184,7 @@ function reportTools(deps) {
|
|
|
3009
3184
|
// The summary projection, not the raw scenario: doc entry bodies and
|
|
3010
3185
|
// base64 attachments are unbounded, and this payload goes straight
|
|
3011
3186
|
// into a model's context window.
|
|
3012
|
-
scenario: (0,
|
|
3187
|
+
scenario: (0, import_report_queries2.toScenarioSummary)(found.feature, found.scenario)
|
|
3013
3188
|
};
|
|
3014
3189
|
})
|
|
3015
3190
|
},
|
|
@@ -3068,12 +3243,12 @@ function reportTools(deps) {
|
|
|
3068
3243
|
}
|
|
3069
3244
|
|
|
3070
3245
|
// src/interactive/ReportInteractive.tsx
|
|
3071
|
-
var
|
|
3246
|
+
var import_jsx_runtime51 = require("react/jsx-runtime");
|
|
3072
3247
|
function ReportInteractive(props) {
|
|
3073
3248
|
const { report, className, title, dataTheme } = props;
|
|
3074
3249
|
const result = unwrapReport(report);
|
|
3075
3250
|
if (!result.ok) {
|
|
3076
|
-
return /* @__PURE__ */ (0,
|
|
3251
|
+
return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3077
3252
|
ReportErrorShell,
|
|
3078
3253
|
{
|
|
3079
3254
|
error: result.error,
|
|
@@ -3083,7 +3258,7 @@ function ReportInteractive(props) {
|
|
|
3083
3258
|
}
|
|
3084
3259
|
);
|
|
3085
3260
|
}
|
|
3086
|
-
return /* @__PURE__ */ (0,
|
|
3261
|
+
return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ReportInteractiveView, { ...props, report: result.data });
|
|
3087
3262
|
}
|
|
3088
3263
|
var THEME_OPTIONS = [
|
|
3089
3264
|
{ value: "light", label: "Light", Icon: import_lucide_react6.Sun },
|
|
@@ -3094,7 +3269,7 @@ function ThemeSegment({
|
|
|
3094
3269
|
pref,
|
|
3095
3270
|
onPref
|
|
3096
3271
|
}) {
|
|
3097
|
-
return /* @__PURE__ */ (0,
|
|
3272
|
+
return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3098
3273
|
ToggleGroup,
|
|
3099
3274
|
{
|
|
3100
3275
|
size: "sm",
|
|
@@ -3104,14 +3279,14 @@ function ThemeSegment({
|
|
|
3104
3279
|
if (next) onPref(next);
|
|
3105
3280
|
},
|
|
3106
3281
|
"aria-label": "Color theme",
|
|
3107
|
-
children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */ (0,
|
|
3282
|
+
children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3108
3283
|
ToggleGroupItem,
|
|
3109
3284
|
{
|
|
3110
3285
|
value,
|
|
3111
3286
|
"aria-label": label,
|
|
3112
3287
|
title: label,
|
|
3113
3288
|
className: "px-2",
|
|
3114
|
-
children: /* @__PURE__ */ (0,
|
|
3289
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(Icon, {})
|
|
3115
3290
|
},
|
|
3116
3291
|
value
|
|
3117
3292
|
))
|
|
@@ -3132,26 +3307,26 @@ function ReportInteractiveView({
|
|
|
3132
3307
|
}) {
|
|
3133
3308
|
const [urlState, setUrlState] = useUrlState();
|
|
3134
3309
|
const { query, status: statusFilter, tags: activeTags, detail } = urlState;
|
|
3135
|
-
const setQuery = (0,
|
|
3310
|
+
const setQuery = (0, import_react23.useCallback)(
|
|
3136
3311
|
(next) => setUrlState({ query: next }),
|
|
3137
3312
|
[setUrlState]
|
|
3138
3313
|
);
|
|
3139
|
-
const setStatusFilter = (0,
|
|
3314
|
+
const setStatusFilter = (0, import_react23.useCallback)(
|
|
3140
3315
|
(next) => setUrlState({ status: next }),
|
|
3141
3316
|
[setUrlState]
|
|
3142
3317
|
);
|
|
3143
|
-
const setDetail = (0,
|
|
3318
|
+
const setDetail = (0, import_react23.useCallback)(
|
|
3144
3319
|
(next) => setUrlState({ detail: next }),
|
|
3145
3320
|
[setUrlState]
|
|
3146
3321
|
);
|
|
3147
|
-
const [helpOpen, setHelpOpen] = (0,
|
|
3322
|
+
const [helpOpen, setHelpOpen] = (0, import_react23.useState)(false);
|
|
3148
3323
|
const { pref: themePref, setPref: setThemePref } = useTheme();
|
|
3149
|
-
const searchRef = (0,
|
|
3150
|
-
const expandId = (0,
|
|
3151
|
-
const docsId = (0,
|
|
3152
|
-
const deferredQuery = (0,
|
|
3153
|
-
const failures = (0,
|
|
3154
|
-
const filtered = (0,
|
|
3324
|
+
const searchRef = (0, import_react23.useRef)(null);
|
|
3325
|
+
const expandId = (0, import_react23.useId)();
|
|
3326
|
+
const docsId = (0, import_react23.useId)();
|
|
3327
|
+
const deferredQuery = (0, import_react23.useDeferredValue)(query);
|
|
3328
|
+
const failures = (0, import_react23.useMemo)(() => listFailures(report), [report]);
|
|
3329
|
+
const filtered = (0, import_react23.useMemo)(
|
|
3155
3330
|
// Features carrying failures float to the top so the first thing on screen
|
|
3156
3331
|
// is the thing that needs attention; an all-green run keeps source order.
|
|
3157
3332
|
() => failuresFirst(
|
|
@@ -3164,7 +3339,7 @@ function ReportInteractiveView({
|
|
|
3164
3339
|
[report, deferredQuery, statusFilter, activeTags]
|
|
3165
3340
|
);
|
|
3166
3341
|
const isFiltering = query !== deferredQuery;
|
|
3167
|
-
const statusOptions = (0,
|
|
3342
|
+
const statusOptions = (0, import_react23.useMemo)(() => {
|
|
3168
3343
|
const s = report.summary;
|
|
3169
3344
|
const opts = [
|
|
3170
3345
|
{ key: "all", label: "All", count: s.total }
|
|
@@ -3179,21 +3354,21 @@ function ReportInteractiveView({
|
|
|
3179
3354
|
opts.push({ key: "pending", label: "Pending", count: s.pending });
|
|
3180
3355
|
return opts;
|
|
3181
3356
|
}, [report]);
|
|
3182
|
-
const tagOptions = (0,
|
|
3183
|
-
const toggleTag = (0,
|
|
3357
|
+
const tagOptions = (0, import_react23.useMemo)(() => allTags(report), [report]);
|
|
3358
|
+
const toggleTag = (0, import_react23.useCallback)(
|
|
3184
3359
|
(tag) => setUrlState({
|
|
3185
3360
|
tags: activeTags.includes(tag) ? activeTags.filter((t) => t !== tag) : [...activeTags, tag]
|
|
3186
3361
|
}),
|
|
3187
3362
|
[activeTags, setUrlState]
|
|
3188
3363
|
);
|
|
3189
|
-
const [toast, setToast] = (0,
|
|
3190
|
-
const toastTimer = (0,
|
|
3191
|
-
const showToast = (0,
|
|
3364
|
+
const [toast, setToast] = (0, import_react23.useState)(null);
|
|
3365
|
+
const toastTimer = (0, import_react23.useRef)(null);
|
|
3366
|
+
const showToast = (0, import_react23.useCallback)((msg) => {
|
|
3192
3367
|
setToast(msg);
|
|
3193
3368
|
if (toastTimer.current) clearTimeout(toastTimer.current);
|
|
3194
3369
|
toastTimer.current = setTimeout(() => setToast(null), 1800);
|
|
3195
3370
|
}, []);
|
|
3196
|
-
const copy = (0,
|
|
3371
|
+
const copy = (0, import_react23.useCallback)(
|
|
3197
3372
|
(text, msg) => {
|
|
3198
3373
|
if (typeof navigator !== "undefined" && navigator.clipboard) {
|
|
3199
3374
|
navigator.clipboard.writeText(text).then(
|
|
@@ -3204,7 +3379,7 @@ function ReportInteractiveView({
|
|
|
3204
3379
|
},
|
|
3205
3380
|
[showToast]
|
|
3206
3381
|
);
|
|
3207
|
-
const scenarioActions = (0,
|
|
3382
|
+
const scenarioActions = (0, import_react23.useMemo)(
|
|
3208
3383
|
() => ({
|
|
3209
3384
|
copyLink: (s) => copy(scenarioPermalink(s), "Link copied"),
|
|
3210
3385
|
copyMarkdown: (s) => copy(scenarioToMarkdown(s), "Markdown copied"),
|
|
@@ -3212,27 +3387,31 @@ function ReportInteractiveView({
|
|
|
3212
3387
|
}),
|
|
3213
3388
|
[copy]
|
|
3214
3389
|
);
|
|
3215
|
-
const
|
|
3216
|
-
|
|
3390
|
+
const copyAllFailures = (0, import_react23.useCallback)(
|
|
3391
|
+
() => copy(failuresToPrompt(failedScenarios(filtered)), "Failures copied"),
|
|
3392
|
+
[copy, filtered]
|
|
3393
|
+
);
|
|
3394
|
+
const failureIndexRef = (0, import_react23.useRef)(0);
|
|
3395
|
+
const allCollapsibleIds = (0, import_react23.useMemo)(
|
|
3217
3396
|
() => report.features.flatMap((f) => [f.id, ...f.scenarios.map((s) => s.id)]),
|
|
3218
3397
|
[report]
|
|
3219
3398
|
);
|
|
3220
3399
|
const collapse = useCollapseState(
|
|
3221
|
-
(0,
|
|
3400
|
+
(0, import_react23.useCallback)(() => defaultCollapsedIds(report), [report])
|
|
3222
3401
|
);
|
|
3223
3402
|
const revealFilteredResults = deferredQuery.trim() !== "" || statusFilter !== "all" || activeTags.length > 0;
|
|
3224
|
-
const visibleCollapse = (0,
|
|
3403
|
+
const visibleCollapse = (0, import_react23.useMemo)(
|
|
3225
3404
|
() => revealFilteredResults ? { ...collapse.api, isCollapsed: () => false } : collapse.api,
|
|
3226
3405
|
[collapse.api, revealFilteredResults]
|
|
3227
3406
|
);
|
|
3228
|
-
const collapseAll = (0,
|
|
3407
|
+
const collapseAll = (0, import_react23.useCallback)(
|
|
3229
3408
|
() => collapse.collapseAll(allCollapsibleIds),
|
|
3230
3409
|
[collapse, allCollapsibleIds]
|
|
3231
3410
|
);
|
|
3232
|
-
const [expandedAll, setExpandedAll] = (0,
|
|
3411
|
+
const [expandedAll, setExpandedAll] = (0, import_react23.useState)(
|
|
3233
3412
|
() => report.summary.failed === 0
|
|
3234
3413
|
);
|
|
3235
|
-
const setExpanded = (0,
|
|
3414
|
+
const setExpanded = (0, import_react23.useCallback)(
|
|
3236
3415
|
(expanded) => {
|
|
3237
3416
|
if (expanded) collapse.expandAll();
|
|
3238
3417
|
else collapseAll();
|
|
@@ -3240,8 +3419,8 @@ function ReportInteractiveView({
|
|
|
3240
3419
|
},
|
|
3241
3420
|
[collapse, collapseAll]
|
|
3242
3421
|
);
|
|
3243
|
-
const [agentFilter, setAgentFilter] = (0,
|
|
3244
|
-
(0,
|
|
3422
|
+
const [agentFilter, setAgentFilter] = (0, import_react23.useState)(null);
|
|
3423
|
+
(0, import_react22.useTools)(
|
|
3245
3424
|
reportTools({
|
|
3246
3425
|
report,
|
|
3247
3426
|
view: urlState,
|
|
@@ -3250,14 +3429,14 @@ function ReportInteractiveView({
|
|
|
3250
3429
|
})
|
|
3251
3430
|
);
|
|
3252
3431
|
const showAgentFilter = agentFilter !== null && agentFilter.search === query && agentFilter.status === statusFilter && agentFilter.tags.length === activeTags.length && agentFilter.tags.every((tag) => activeTags.includes(tag));
|
|
3253
|
-
const clearFilters = (0,
|
|
3432
|
+
const clearFilters = (0, import_react23.useCallback)(
|
|
3254
3433
|
() => setUrlState({ query: "", status: "all", tags: [] }),
|
|
3255
3434
|
[setUrlState]
|
|
3256
3435
|
);
|
|
3257
|
-
const focusSearch = (0,
|
|
3436
|
+
const focusSearch = (0, import_react23.useCallback)(() => {
|
|
3258
3437
|
searchRef.current?.focus();
|
|
3259
3438
|
}, []);
|
|
3260
|
-
const stepFailure = (0,
|
|
3439
|
+
const stepFailure = (0, import_react23.useCallback)(
|
|
3261
3440
|
(direction) => {
|
|
3262
3441
|
if (failures.length === 0) return;
|
|
3263
3442
|
failureIndexRef.current = (failureIndexRef.current + direction + failures.length) % failures.length;
|
|
@@ -3266,10 +3445,10 @@ function ReportInteractiveView({
|
|
|
3266
3445
|
},
|
|
3267
3446
|
[failures]
|
|
3268
3447
|
);
|
|
3269
|
-
const toggleHelp = (0,
|
|
3448
|
+
const toggleHelp = (0, import_react23.useCallback)(() => {
|
|
3270
3449
|
setHelpOpen((v) => !v);
|
|
3271
3450
|
}, []);
|
|
3272
|
-
const escape = (0,
|
|
3451
|
+
const escape = (0, import_react23.useCallback)(() => {
|
|
3273
3452
|
if (helpOpen) setHelpOpen(false);
|
|
3274
3453
|
else if (query !== "") setQuery("");
|
|
3275
3454
|
}, [helpOpen, query, setQuery]);
|
|
@@ -3287,13 +3466,13 @@ function ReportInteractiveView({
|
|
|
3287
3466
|
const totalScenarios = report.summary.total;
|
|
3288
3467
|
const matchedScenarios = filtered.summary.total;
|
|
3289
3468
|
const showToc = !hideToc && totalScenarios > 3;
|
|
3290
|
-
return /* @__PURE__ */ (0,
|
|
3469
|
+
return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(CollapseProvider, { value: visibleCollapse, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ScenarioActionsProvider, { value: scenarioActions, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ScenarioHistoryProvider, { value: scenarioHistory ?? null, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ScenarioFreshnessProvider, { value: { staleAfterDays, report }, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3291
3470
|
ReportRoot,
|
|
3292
3471
|
{
|
|
3293
3472
|
report: filtered,
|
|
3294
3473
|
customRenderers,
|
|
3295
3474
|
renderers,
|
|
3296
|
-
children: /* @__PURE__ */ (0,
|
|
3475
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
|
|
3297
3476
|
"main",
|
|
3298
3477
|
{
|
|
3299
3478
|
className: cn("es-report", "es-report-interactive", className),
|
|
@@ -3302,8 +3481,8 @@ function ReportInteractiveView({
|
|
|
3302
3481
|
"data-theme": dataTheme,
|
|
3303
3482
|
"data-detail-level": detail,
|
|
3304
3483
|
children: [
|
|
3305
|
-
/* @__PURE__ */ (0,
|
|
3306
|
-
/* @__PURE__ */ (0,
|
|
3484
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("header", { className: "es-report-header", children: [
|
|
3485
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
|
|
3307
3486
|
"div",
|
|
3308
3487
|
{
|
|
3309
3488
|
"data-es-navbar": true,
|
|
@@ -3312,9 +3491,9 @@ function ReportInteractiveView({
|
|
|
3312
3491
|
hideHeader ? "justify-end" : "justify-between"
|
|
3313
3492
|
),
|
|
3314
3493
|
children: [
|
|
3315
|
-
hideHeader ? null : /* @__PURE__ */ (0,
|
|
3316
|
-
/* @__PURE__ */ (0,
|
|
3317
|
-
/* @__PURE__ */ (0,
|
|
3494
|
+
hideHeader ? null : /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("h1", { className: "min-w-0", children: title ?? "Story Report" }),
|
|
3495
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3496
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3318
3497
|
ReportSearch,
|
|
3319
3498
|
{
|
|
3320
3499
|
ref: searchRef,
|
|
@@ -3324,16 +3503,16 @@ function ReportInteractiveView({
|
|
|
3324
3503
|
totalCount: totalScenarios
|
|
3325
3504
|
}
|
|
3326
3505
|
),
|
|
3327
|
-
/* @__PURE__ */ (0,
|
|
3506
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ThemeSegment, { pref: themePref, onPref: setThemePref })
|
|
3328
3507
|
] })
|
|
3329
3508
|
]
|
|
3330
3509
|
}
|
|
3331
3510
|
),
|
|
3332
|
-
hideHeader ? null : /* @__PURE__ */ (0,
|
|
3333
|
-
/* @__PURE__ */ (0,
|
|
3334
|
-
/* @__PURE__ */ (0,
|
|
3511
|
+
hideHeader ? null : /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_jsx_runtime51.Fragment, { children: [
|
|
3512
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ReportSummary, {}),
|
|
3513
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ReportMeta, {})
|
|
3335
3514
|
] }),
|
|
3336
|
-
/* @__PURE__ */ (0,
|
|
3515
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3337
3516
|
ReportFreshness,
|
|
3338
3517
|
{
|
|
3339
3518
|
lastRunMs: reportLastRunMs(report),
|
|
@@ -3341,14 +3520,15 @@ function ReportInteractiveView({
|
|
|
3341
3520
|
staleAfterDays
|
|
3342
3521
|
}
|
|
3343
3522
|
),
|
|
3344
|
-
/* @__PURE__ */ (0,
|
|
3523
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3345
3524
|
ReportLastRunDelta,
|
|
3346
3525
|
{
|
|
3347
3526
|
history: scenarioHistory,
|
|
3348
3527
|
report
|
|
3349
3528
|
}
|
|
3350
3529
|
),
|
|
3351
|
-
/* @__PURE__ */ (0,
|
|
3530
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ReportSinceLastVisit, { report }),
|
|
3531
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3352
3532
|
ReportFilters,
|
|
3353
3533
|
{
|
|
3354
3534
|
statuses: statusOptions,
|
|
@@ -3359,10 +3539,10 @@ function ReportInteractiveView({
|
|
|
3359
3539
|
onToggleTag: toggleTag
|
|
3360
3540
|
}
|
|
3361
3541
|
),
|
|
3362
|
-
/* @__PURE__ */ (0,
|
|
3363
|
-
showToc ? /* @__PURE__ */ (0,
|
|
3364
|
-
/* @__PURE__ */ (0,
|
|
3365
|
-
/* @__PURE__ */ (0,
|
|
3542
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-2 border-t border-border/60 pt-3", children: [
|
|
3543
|
+
showToc ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ReportTocDrawer, {}) : null,
|
|
3544
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3545
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3366
3546
|
Switch,
|
|
3367
3547
|
{
|
|
3368
3548
|
id: expandId,
|
|
@@ -3370,7 +3550,7 @@ function ReportInteractiveView({
|
|
|
3370
3550
|
onCheckedChange: setExpanded
|
|
3371
3551
|
}
|
|
3372
3552
|
),
|
|
3373
|
-
/* @__PURE__ */ (0,
|
|
3553
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3374
3554
|
"label",
|
|
3375
3555
|
{
|
|
3376
3556
|
htmlFor: expandId,
|
|
@@ -3379,8 +3559,8 @@ function ReportInteractiveView({
|
|
|
3379
3559
|
}
|
|
3380
3560
|
)
|
|
3381
3561
|
] }),
|
|
3382
|
-
/* @__PURE__ */ (0,
|
|
3383
|
-
/* @__PURE__ */ (0,
|
|
3562
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
3563
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3384
3564
|
Switch,
|
|
3385
3565
|
{
|
|
3386
3566
|
id: docsId,
|
|
@@ -3388,7 +3568,7 @@ function ReportInteractiveView({
|
|
|
3388
3568
|
onCheckedChange: (checked) => setDetail(checked ? "full" : "minimal")
|
|
3389
3569
|
}
|
|
3390
3570
|
),
|
|
3391
|
-
/* @__PURE__ */ (0,
|
|
3571
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3392
3572
|
"label",
|
|
3393
3573
|
{
|
|
3394
3574
|
htmlFor: docsId,
|
|
@@ -3399,7 +3579,7 @@ function ReportInteractiveView({
|
|
|
3399
3579
|
] })
|
|
3400
3580
|
] })
|
|
3401
3581
|
] }),
|
|
3402
|
-
showAgentFilter ? /* @__PURE__ */ (0,
|
|
3582
|
+
showAgentFilter ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3403
3583
|
ReportAgentFilterNotice,
|
|
3404
3584
|
{
|
|
3405
3585
|
applied: agentFilter,
|
|
@@ -3407,17 +3587,17 @@ function ReportInteractiveView({
|
|
|
3407
3587
|
onDismiss: () => setAgentFilter(null)
|
|
3408
3588
|
}
|
|
3409
3589
|
) : null,
|
|
3410
|
-
/* @__PURE__ */ (0,
|
|
3411
|
-
hasContent ? showToc ? /* @__PURE__ */ (0,
|
|
3412
|
-
/* @__PURE__ */ (0,
|
|
3413
|
-
/* @__PURE__ */ (0,
|
|
3414
|
-
] }) : /* @__PURE__ */ (0,
|
|
3590
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ReportFailureBanner, { failures, onCopyAll: copyAllFailures }),
|
|
3591
|
+
hasContent ? showToc ? /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "flex gap-6", children: [
|
|
3592
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ReportToc, {}),
|
|
3593
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "flex min-w-0 flex-1 flex-col gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ReportFeatureList, {}) })
|
|
3594
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ReportFeatureList, {}) }) : /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3415
3595
|
ReportEmpty,
|
|
3416
3596
|
{
|
|
3417
3597
|
message: query ? "No scenarios match the search." : void 0
|
|
3418
3598
|
}
|
|
3419
3599
|
),
|
|
3420
|
-
/* @__PURE__ */ (0,
|
|
3600
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3421
3601
|
"button",
|
|
3422
3602
|
{
|
|
3423
3603
|
type: "button",
|
|
@@ -3428,14 +3608,14 @@ function ReportInteractiveView({
|
|
|
3428
3608
|
children: "?"
|
|
3429
3609
|
}
|
|
3430
3610
|
),
|
|
3431
|
-
/* @__PURE__ */ (0,
|
|
3611
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3432
3612
|
ReportShortcutsHelp,
|
|
3433
3613
|
{
|
|
3434
3614
|
open: helpOpen,
|
|
3435
3615
|
onClose: () => setHelpOpen(false)
|
|
3436
3616
|
}
|
|
3437
3617
|
),
|
|
3438
|
-
toast ? /* @__PURE__ */ (0,
|
|
3618
|
+
toast ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
3439
3619
|
"div",
|
|
3440
3620
|
{
|
|
3441
3621
|
role: "status",
|
|
@@ -3452,14 +3632,14 @@ function ReportInteractiveView({
|
|
|
3452
3632
|
}
|
|
3453
3633
|
|
|
3454
3634
|
// src/interactive/ReportInteractiveIsland.tsx
|
|
3455
|
-
var
|
|
3635
|
+
var import_react26 = require("react");
|
|
3456
3636
|
|
|
3457
3637
|
// src/interactive/island-renderers.tsx
|
|
3458
|
-
var
|
|
3638
|
+
var import_react25 = require("react");
|
|
3459
3639
|
|
|
3460
3640
|
// src/components/doc/MermaidView.tsx
|
|
3461
|
-
var
|
|
3462
|
-
var
|
|
3641
|
+
var import_react24 = require("react");
|
|
3642
|
+
var import_jsx_runtime52 = require("react/jsx-runtime");
|
|
3463
3643
|
function prefersDark(el) {
|
|
3464
3644
|
const themed = el?.closest("[data-theme]");
|
|
3465
3645
|
if (themed?.dataset.theme === "dark") return true;
|
|
@@ -3467,10 +3647,10 @@ function prefersDark(el) {
|
|
|
3467
3647
|
return typeof window !== "undefined" && !!window.matchMedia?.("(prefers-color-scheme: dark)").matches;
|
|
3468
3648
|
}
|
|
3469
3649
|
function MermaidView({ entry, load }) {
|
|
3470
|
-
const ref = (0,
|
|
3471
|
-
const [svg, setSvg] = (0,
|
|
3472
|
-
const [error, setError] = (0,
|
|
3473
|
-
(0,
|
|
3650
|
+
const ref = (0, import_react24.useRef)(null);
|
|
3651
|
+
const [svg, setSvg] = (0, import_react24.useState)(null);
|
|
3652
|
+
const [error, setError] = (0, import_react24.useState)(null);
|
|
3653
|
+
(0, import_react24.useEffect)(() => {
|
|
3474
3654
|
let cancelled = false;
|
|
3475
3655
|
const draw = async () => {
|
|
3476
3656
|
let mermaid;
|
|
@@ -3513,9 +3693,9 @@ function MermaidView({ entry, load }) {
|
|
|
3513
3693
|
};
|
|
3514
3694
|
}, [entry.code, load]);
|
|
3515
3695
|
if (svg) {
|
|
3516
|
-
return /* @__PURE__ */ (0,
|
|
3517
|
-
entry.title ? /* @__PURE__ */ (0,
|
|
3518
|
-
/* @__PURE__ */ (0,
|
|
3696
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("figure", { ref, className: "my-3", children: [
|
|
3697
|
+
entry.title ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
|
|
3698
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
3519
3699
|
"div",
|
|
3520
3700
|
{
|
|
3521
3701
|
role: "img",
|
|
@@ -3526,8 +3706,8 @@ function MermaidView({ entry, load }) {
|
|
|
3526
3706
|
)
|
|
3527
3707
|
] });
|
|
3528
3708
|
}
|
|
3529
|
-
return /* @__PURE__ */ (0,
|
|
3530
|
-
error ? /* @__PURE__ */ (0,
|
|
3709
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_jsx_runtime52.Fragment, { children: [
|
|
3710
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
|
|
3531
3711
|
"p",
|
|
3532
3712
|
{
|
|
3533
3713
|
role: "alert",
|
|
@@ -3539,12 +3719,12 @@ function MermaidView({ entry, load }) {
|
|
|
3539
3719
|
]
|
|
3540
3720
|
}
|
|
3541
3721
|
) : null,
|
|
3542
|
-
/* @__PURE__ */ (0,
|
|
3722
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(MermaidSource, { entry, ref })
|
|
3543
3723
|
] });
|
|
3544
3724
|
}
|
|
3545
3725
|
|
|
3546
3726
|
// src/interactive/island-renderers.tsx
|
|
3547
|
-
var
|
|
3727
|
+
var import_jsx_runtime53 = require("react/jsx-runtime");
|
|
3548
3728
|
var HLJS_ESM = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/highlight.min.js";
|
|
3549
3729
|
var MERMAID_ESM = "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
|
|
3550
3730
|
function cachedCdnModule(url) {
|
|
@@ -3561,8 +3741,8 @@ function cachedCdnModule(url) {
|
|
|
3561
3741
|
var loadMermaidFromCdn = cachedCdnModule(MERMAID_ESM);
|
|
3562
3742
|
var loadHljs = cachedCdnModule(HLJS_ESM);
|
|
3563
3743
|
function CdnHighlightedCode({ entry }) {
|
|
3564
|
-
const [html, setHtml] = (0,
|
|
3565
|
-
(0,
|
|
3744
|
+
const [html, setHtml] = (0, import_react25.useState)(null);
|
|
3745
|
+
(0, import_react25.useEffect)(() => {
|
|
3566
3746
|
let cancelled = false;
|
|
3567
3747
|
void (async () => {
|
|
3568
3748
|
try {
|
|
@@ -3578,27 +3758,27 @@ function CdnHighlightedCode({ entry }) {
|
|
|
3578
3758
|
cancelled = true;
|
|
3579
3759
|
};
|
|
3580
3760
|
}, [entry.content, entry.lang]);
|
|
3581
|
-
return /* @__PURE__ */ (0,
|
|
3761
|
+
return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(CodeFigure, { label: entry.label, children: html !== null ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
3582
3762
|
"code",
|
|
3583
3763
|
{
|
|
3584
3764
|
className: cn("hljs font-mono text-xs", entry.lang && `language-${entry.lang}`),
|
|
3585
3765
|
dangerouslySetInnerHTML: { __html: html }
|
|
3586
3766
|
}
|
|
3587
|
-
) : /* @__PURE__ */ (0,
|
|
3767
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
|
|
3588
3768
|
}
|
|
3589
3769
|
function buildIslandRenderers(opts) {
|
|
3590
3770
|
const renderers = {};
|
|
3591
3771
|
if (opts.mermaid) {
|
|
3592
|
-
renderers.mermaid = (entry) => (0,
|
|
3772
|
+
renderers.mermaid = (entry) => (0, import_react25.createElement)(MermaidView, { entry, load: loadMermaidFromCdn });
|
|
3593
3773
|
}
|
|
3594
3774
|
if (opts.syntaxHighlighting) {
|
|
3595
|
-
renderers.code = (entry) => (0,
|
|
3775
|
+
renderers.code = (entry) => (0, import_react25.createElement)(CdnHighlightedCode, { entry });
|
|
3596
3776
|
}
|
|
3597
3777
|
return renderers;
|
|
3598
3778
|
}
|
|
3599
3779
|
|
|
3600
3780
|
// src/interactive/ReportInteractiveIsland.tsx
|
|
3601
|
-
var
|
|
3781
|
+
var import_jsx_runtime54 = require("react/jsx-runtime");
|
|
3602
3782
|
function ReportInteractiveIsland({
|
|
3603
3783
|
report,
|
|
3604
3784
|
title,
|
|
@@ -3608,11 +3788,11 @@ function ReportInteractiveIsland({
|
|
|
3608
3788
|
syntaxHighlighting = true,
|
|
3609
3789
|
mermaid = true
|
|
3610
3790
|
}) {
|
|
3611
|
-
const renderers = (0,
|
|
3791
|
+
const renderers = (0, import_react26.useMemo)(
|
|
3612
3792
|
() => buildIslandRenderers({ syntaxHighlighting, mermaid }),
|
|
3613
3793
|
[syntaxHighlighting, mermaid]
|
|
3614
3794
|
);
|
|
3615
|
-
return /* @__PURE__ */ (0,
|
|
3795
|
+
return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
3616
3796
|
ReportInteractive,
|
|
3617
3797
|
{
|
|
3618
3798
|
report,
|