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.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
useId as useId2,
|
|
10
10
|
useMemo as useMemo3,
|
|
11
11
|
useRef as useRef5,
|
|
12
|
-
useState as
|
|
12
|
+
useState as useState10
|
|
13
13
|
} from "react";
|
|
14
14
|
|
|
15
15
|
// src/components/ui/empty.tsx
|
|
@@ -206,7 +206,7 @@ function formatValue(value) {
|
|
|
206
206
|
function DocKv({ entry }) {
|
|
207
207
|
return /* @__PURE__ */ jsxs("dl", { className: "my-2 flex flex-wrap items-baseline gap-x-2 text-sm", children: [
|
|
208
208
|
/* @__PURE__ */ jsx6("dt", { className: "font-semibold text-muted-foreground", children: entry.label }),
|
|
209
|
-
/* @__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) })
|
|
210
210
|
] });
|
|
211
211
|
}
|
|
212
212
|
|
|
@@ -414,7 +414,7 @@ function DocHtml({ entry }) {
|
|
|
414
414
|
loading: "lazy",
|
|
415
415
|
title,
|
|
416
416
|
className: "block w-full border-0",
|
|
417
|
-
style: { height }
|
|
417
|
+
style: { height, colorScheme: "light", background: "#fff" }
|
|
418
418
|
}
|
|
419
419
|
)
|
|
420
420
|
] });
|
|
@@ -1138,6 +1138,24 @@ function scenarioToPrompt(scenario) {
|
|
|
1138
1138
|
}
|
|
1139
1139
|
return lines.join("\n");
|
|
1140
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
|
+
}
|
|
1141
1159
|
function scenarioPermalink(scenario) {
|
|
1142
1160
|
if (typeof location === "undefined") return `#${scenario.id}`;
|
|
1143
1161
|
return `${location.href.split("#")[0]}#${scenario.id}`;
|
|
@@ -1263,57 +1281,68 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1263
1281
|
className: "gap-0 py-0",
|
|
1264
1282
|
children: [
|
|
1265
1283
|
/* @__PURE__ */ jsxs17(CardHeader, { className: "px-4 py-3", children: [
|
|
1266
|
-
/* @__PURE__ */ jsxs17(
|
|
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
|
-
|
|
1309
|
-
|
|
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
|
|
1310
1339
|
] })
|
|
1311
|
-
]
|
|
1312
|
-
|
|
1313
|
-
|
|
1340
|
+
]
|
|
1341
|
+
}
|
|
1342
|
+
),
|
|
1314
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: [
|
|
1315
1344
|
scenario.tags.map((t) => /* @__PURE__ */ jsx26("li", { children: /* @__PURE__ */ jsx26(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
|
|
1316
|
-
(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}`))
|
|
1317
1346
|
] }) : null
|
|
1318
1347
|
] }),
|
|
1319
1348
|
/* @__PURE__ */ jsxs17(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
|
|
@@ -1456,6 +1485,7 @@ function ReportFeatureList() {
|
|
|
1456
1485
|
|
|
1457
1486
|
// src/components/ReportMeta.tsx
|
|
1458
1487
|
import { formatDuration as formatDuration4 } from "executable-stories-core/utils/duration";
|
|
1488
|
+
import { slowestScenarios } from "executable-stories-core/report-queries";
|
|
1459
1489
|
import { jsx as jsx31, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1460
1490
|
function ReportMeta() {
|
|
1461
1491
|
const report = useReport();
|
|
@@ -1499,7 +1529,9 @@ function ReportMeta() {
|
|
|
1499
1529
|
value: url ? /* @__PURE__ */ jsx31("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
|
|
1500
1530
|
});
|
|
1501
1531
|
}
|
|
1502
|
-
|
|
1532
|
+
const slowest = slowestScenarios(report, 5);
|
|
1533
|
+
const showSlowest = slowest.length >= 3;
|
|
1534
|
+
if (items.length === 0 && !showSlowest) return null;
|
|
1503
1535
|
return (
|
|
1504
1536
|
// Run metadata is useful but secondary to "what failed" — tuck it into a
|
|
1505
1537
|
// collapsed disclosure so it doesn't push the result down. Native <details>
|
|
@@ -1512,7 +1544,14 @@ function ReportMeta() {
|
|
|
1512
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: [
|
|
1513
1545
|
/* @__PURE__ */ jsx31("dt", { className: "font-medium", children: item.label }),
|
|
1514
1546
|
/* @__PURE__ */ jsx31("dd", { className: "font-mono text-foreground", children: item.value })
|
|
1515
|
-
] }, 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
|
|
1516
1555
|
] })
|
|
1517
1556
|
);
|
|
1518
1557
|
}
|
|
@@ -1988,21 +2027,26 @@ function allTags(report) {
|
|
|
1988
2027
|
}
|
|
1989
2028
|
return [...seen];
|
|
1990
2029
|
}
|
|
1991
|
-
function queryMatches(scenario, q) {
|
|
2030
|
+
function queryMatches(scenario, q, sourceFile) {
|
|
1992
2031
|
if (q === "") return true;
|
|
1993
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;
|
|
1994
2035
|
for (const tag of scenario.tags) {
|
|
1995
2036
|
if (tag.toLowerCase().includes(q)) return true;
|
|
1996
2037
|
}
|
|
2038
|
+
for (const ticket of scenario.tickets ?? []) {
|
|
2039
|
+
if (ticket.id.toLowerCase().includes(q)) return true;
|
|
2040
|
+
}
|
|
1997
2041
|
for (const step of scenario.steps) {
|
|
1998
2042
|
if (step.text.toLowerCase().includes(q)) return true;
|
|
1999
2043
|
}
|
|
2000
2044
|
return false;
|
|
2001
2045
|
}
|
|
2002
|
-
function scenarioMatches(scenario, q, status, tags) {
|
|
2046
|
+
function scenarioMatches(scenario, q, status, tags, sourceFile) {
|
|
2003
2047
|
if (status !== "all" && scenario.status !== status) return false;
|
|
2004
2048
|
if (tags.length > 0 && !tags.some((t) => scenario.tags.includes(t))) return false;
|
|
2005
|
-
return queryMatches(scenario, q);
|
|
2049
|
+
return queryMatches(scenario, q, sourceFile);
|
|
2006
2050
|
}
|
|
2007
2051
|
function summarizeScenarios(scenarios) {
|
|
2008
2052
|
let total = 0, passed = 0, failed = 0, skipped = 0, pending = 0, durationMs = 0;
|
|
@@ -2025,7 +2069,9 @@ function filterReport(report, criteria) {
|
|
|
2025
2069
|
const features = [];
|
|
2026
2070
|
let topTotal = 0, topPassed = 0, topFailed = 0, topSkipped = 0, topPending = 0, topDuration = 0;
|
|
2027
2071
|
for (const feature of report.features) {
|
|
2028
|
-
const matched = feature.scenarios.filter(
|
|
2072
|
+
const matched = feature.scenarios.filter(
|
|
2073
|
+
(s) => scenarioMatches(s, q, status, tags, feature.sourceFile)
|
|
2074
|
+
);
|
|
2029
2075
|
if (matched.length === 0) continue;
|
|
2030
2076
|
const summary = summarizeScenarios(matched);
|
|
2031
2077
|
features.push({ ...feature, summary, scenarios: matched });
|
|
@@ -2049,6 +2095,9 @@ function filterReport(report, criteria) {
|
|
|
2049
2095
|
features
|
|
2050
2096
|
};
|
|
2051
2097
|
}
|
|
2098
|
+
function failedScenarios(report) {
|
|
2099
|
+
return report.features.flatMap((f) => f.scenarios.filter((s) => s.status === "failed"));
|
|
2100
|
+
}
|
|
2052
2101
|
function listFailures(report) {
|
|
2053
2102
|
const out = [];
|
|
2054
2103
|
for (const feature of report.features) {
|
|
@@ -2132,7 +2181,7 @@ function ReportAgentFilterNotice({
|
|
|
2132
2181
|
// src/interactive/ReportFailureBanner.tsx
|
|
2133
2182
|
import { useCallback as useCallback2 } from "react";
|
|
2134
2183
|
import { jsx as jsx40, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2135
|
-
function ReportFailureBanner({ failures }) {
|
|
2184
|
+
function ReportFailureBanner({ failures, onCopyAll }) {
|
|
2136
2185
|
const first = failures[0];
|
|
2137
2186
|
const jumpToFirst = useCallback2(() => {
|
|
2138
2187
|
if (!first) return;
|
|
@@ -2162,7 +2211,23 @@ function ReportFailureBanner({ failures }) {
|
|
|
2162
2211
|
"aria-label": "View first failure",
|
|
2163
2212
|
children: "View first failure \u2193"
|
|
2164
2213
|
}
|
|
2165
|
-
)
|
|
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
|
|
2166
2231
|
]
|
|
2167
2232
|
}
|
|
2168
2233
|
);
|
|
@@ -2370,7 +2435,7 @@ var ReportSearch = forwardRef(
|
|
|
2370
2435
|
onChange,
|
|
2371
2436
|
matchedCount,
|
|
2372
2437
|
totalCount,
|
|
2373
|
-
placeholder = "Search scenarios
|
|
2438
|
+
placeholder = "Search scenarios, tags, tickets, errors\u2026",
|
|
2374
2439
|
className
|
|
2375
2440
|
} = props;
|
|
2376
2441
|
const inputId = useId();
|
|
@@ -2428,8 +2493,118 @@ var ReportSearch = forwardRef(
|
|
|
2428
2493
|
}
|
|
2429
2494
|
);
|
|
2430
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
|
+
|
|
2431
2606
|
// src/interactive/ReportShortcutsHelp.tsx
|
|
2432
|
-
import { useEffect as
|
|
2607
|
+
import { useEffect as useEffect4, useRef } from "react";
|
|
2433
2608
|
|
|
2434
2609
|
// src/components/ui/button.tsx
|
|
2435
2610
|
import "react";
|
|
@@ -2485,7 +2660,7 @@ function Button({
|
|
|
2485
2660
|
}
|
|
2486
2661
|
|
|
2487
2662
|
// src/interactive/ReportShortcutsHelp.tsx
|
|
2488
|
-
import { jsx as
|
|
2663
|
+
import { jsx as jsx47, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
2489
2664
|
var SHORTCUTS = [
|
|
2490
2665
|
{ keys: "/", description: "Focus search" },
|
|
2491
2666
|
{ keys: "f", description: "Jump to next failure" },
|
|
@@ -2497,20 +2672,20 @@ var SHORTCUTS = [
|
|
|
2497
2672
|
];
|
|
2498
2673
|
function Keys({ keys }) {
|
|
2499
2674
|
const parts = keys.split(" ");
|
|
2500
|
-
return /* @__PURE__ */
|
|
2501
|
-
i > 0 ? /* @__PURE__ */
|
|
2502
|
-
/* @__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 })
|
|
2503
2678
|
] }, k)) });
|
|
2504
2679
|
}
|
|
2505
2680
|
function ReportShortcutsHelp({ open, onClose }) {
|
|
2506
2681
|
const dialogRef = useRef(null);
|
|
2507
|
-
|
|
2682
|
+
useEffect4(() => {
|
|
2508
2683
|
const dialog = dialogRef.current;
|
|
2509
2684
|
if (!dialog) return;
|
|
2510
2685
|
if (open && !dialog.open) dialog.showModal();
|
|
2511
2686
|
else if (!open && dialog.open) dialog.close();
|
|
2512
2687
|
}, [open]);
|
|
2513
|
-
return /* @__PURE__ */
|
|
2688
|
+
return /* @__PURE__ */ jsxs32(
|
|
2514
2689
|
"dialog",
|
|
2515
2690
|
{
|
|
2516
2691
|
ref: dialogRef,
|
|
@@ -2518,20 +2693,20 @@ function ReportShortcutsHelp({ open, onClose }) {
|
|
|
2518
2693
|
"aria-label": "Keyboard shortcuts",
|
|
2519
2694
|
onClose,
|
|
2520
2695
|
children: [
|
|
2521
|
-
/* @__PURE__ */
|
|
2522
|
-
/* @__PURE__ */
|
|
2523
|
-
/* @__PURE__ */
|
|
2524
|
-
/* @__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 })
|
|
2525
2700
|
] }, s.keys)) }),
|
|
2526
|
-
/* @__PURE__ */
|
|
2701
|
+
/* @__PURE__ */ jsx47("form", { method: "dialog", className: "mt-6", children: /* @__PURE__ */ jsx47(Button, { type: "submit", variant: "outline", size: "sm", children: "Close" }) })
|
|
2527
2702
|
]
|
|
2528
2703
|
}
|
|
2529
2704
|
);
|
|
2530
2705
|
}
|
|
2531
2706
|
|
|
2532
2707
|
// src/interactive/ReportToc.tsx
|
|
2533
|
-
import { useEffect as
|
|
2534
|
-
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";
|
|
2535
2710
|
var DOT = {
|
|
2536
2711
|
passed: "bg-pass",
|
|
2537
2712
|
failed: "bg-fail",
|
|
@@ -2540,12 +2715,12 @@ var DOT = {
|
|
|
2540
2715
|
};
|
|
2541
2716
|
function TocContent({ onNavigate }) {
|
|
2542
2717
|
const report = useReport();
|
|
2543
|
-
const [activeId, setActiveId] =
|
|
2718
|
+
const [activeId, setActiveId] = useState6(null);
|
|
2544
2719
|
const scenarioIds = useMemo2(
|
|
2545
2720
|
() => report.features.flatMap((f) => f.scenarios.map((s) => s.id)),
|
|
2546
2721
|
[report]
|
|
2547
2722
|
);
|
|
2548
|
-
|
|
2723
|
+
useEffect5(() => {
|
|
2549
2724
|
if (typeof IntersectionObserver === "undefined") return;
|
|
2550
2725
|
const els = scenarioIds.map((id) => document.getElementById(id)).filter((el) => el !== null);
|
|
2551
2726
|
if (els.length === 0) return;
|
|
@@ -2560,11 +2735,11 @@ function TocContent({ onNavigate }) {
|
|
|
2560
2735
|
return () => observer.disconnect();
|
|
2561
2736
|
}, [scenarioIds]);
|
|
2562
2737
|
if (report.features.length === 0) return null;
|
|
2563
|
-
return /* @__PURE__ */
|
|
2564
|
-
/* @__PURE__ */
|
|
2565
|
-
/* @__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) => {
|
|
2566
2741
|
const active = activeId === scenario.id;
|
|
2567
|
-
return /* @__PURE__ */
|
|
2742
|
+
return /* @__PURE__ */ jsx48("li", { children: /* @__PURE__ */ jsxs33(
|
|
2568
2743
|
"a",
|
|
2569
2744
|
{
|
|
2570
2745
|
href: `#${scenario.id}`,
|
|
@@ -2579,14 +2754,14 @@ function TocContent({ onNavigate }) {
|
|
|
2579
2754
|
active ? "border-primary font-medium text-foreground" : "border-border text-muted-foreground"
|
|
2580
2755
|
),
|
|
2581
2756
|
children: [
|
|
2582
|
-
/* @__PURE__ */
|
|
2757
|
+
/* @__PURE__ */ jsx48(
|
|
2583
2758
|
"span",
|
|
2584
2759
|
{
|
|
2585
2760
|
"aria-hidden": true,
|
|
2586
2761
|
className: cn("mt-1 size-1.5 shrink-0 rounded-full", DOT[scenario.status])
|
|
2587
2762
|
}
|
|
2588
2763
|
),
|
|
2589
|
-
/* @__PURE__ */
|
|
2764
|
+
/* @__PURE__ */ jsx48("span", { className: "break-words", children: scenario.title })
|
|
2590
2765
|
]
|
|
2591
2766
|
}
|
|
2592
2767
|
) }, scenario.id);
|
|
@@ -2596,48 +2771,48 @@ function TocContent({ onNavigate }) {
|
|
|
2596
2771
|
function ReportToc() {
|
|
2597
2772
|
const report = useReport();
|
|
2598
2773
|
if (report.features.length === 0) return null;
|
|
2599
|
-
return /* @__PURE__ */
|
|
2774
|
+
return /* @__PURE__ */ jsxs33(
|
|
2600
2775
|
"nav",
|
|
2601
2776
|
{
|
|
2602
2777
|
"aria-label": "Table of contents",
|
|
2603
2778
|
className: "sticky top-4 hidden h-fit w-64 shrink-0 self-start text-xs lg:block",
|
|
2604
2779
|
children: [
|
|
2605
|
-
/* @__PURE__ */
|
|
2606
|
-
/* @__PURE__ */
|
|
2780
|
+
/* @__PURE__ */ jsx48("p", { className: "mb-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Contents" }),
|
|
2781
|
+
/* @__PURE__ */ jsx48(TocContent, {})
|
|
2607
2782
|
]
|
|
2608
2783
|
}
|
|
2609
2784
|
);
|
|
2610
2785
|
}
|
|
2611
2786
|
|
|
2612
2787
|
// src/interactive/ReportTocDrawer.tsx
|
|
2613
|
-
import { useState as
|
|
2788
|
+
import { useState as useState7 } from "react";
|
|
2614
2789
|
import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
|
|
2615
2790
|
import { ListIcon, XIcon } from "lucide-react";
|
|
2616
|
-
import { jsx as
|
|
2791
|
+
import { jsx as jsx49, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
2617
2792
|
function ReportTocDrawer() {
|
|
2618
2793
|
const report = useReport();
|
|
2619
|
-
const [open, setOpen] =
|
|
2794
|
+
const [open, setOpen] = useState7(false);
|
|
2620
2795
|
if (report.features.length === 0) return null;
|
|
2621
|
-
return /* @__PURE__ */
|
|
2622
|
-
/* @__PURE__ */
|
|
2623
|
-
/* @__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 }),
|
|
2624
2799
|
" Contents"
|
|
2625
2800
|
] }),
|
|
2626
|
-
/* @__PURE__ */
|
|
2627
|
-
/* @__PURE__ */
|
|
2628
|
-
/* @__PURE__ */
|
|
2629
|
-
/* @__PURE__ */
|
|
2630
|
-
/* @__PURE__ */
|
|
2631
|
-
/* @__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(
|
|
2632
2807
|
DialogPrimitive.Close,
|
|
2633
2808
|
{
|
|
2634
2809
|
"aria-label": "Close contents",
|
|
2635
2810
|
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
2636
|
-
children: /* @__PURE__ */
|
|
2811
|
+
children: /* @__PURE__ */ jsx49(XIcon, { "aria-hidden": true })
|
|
2637
2812
|
}
|
|
2638
2813
|
)
|
|
2639
2814
|
] }),
|
|
2640
|
-
/* @__PURE__ */
|
|
2815
|
+
/* @__PURE__ */ jsx49(TocContent, { onNavigate: () => setOpen(false) })
|
|
2641
2816
|
] })
|
|
2642
2817
|
] })
|
|
2643
2818
|
] });
|
|
@@ -2671,10 +2846,10 @@ function failuresFirst(report) {
|
|
|
2671
2846
|
}
|
|
2672
2847
|
|
|
2673
2848
|
// src/interactive/use-deep-link-scroll.ts
|
|
2674
|
-
import { useEffect as
|
|
2849
|
+
import { useEffect as useEffect6, useRef as useRef2 } from "react";
|
|
2675
2850
|
function useDeepLinkScroll() {
|
|
2676
2851
|
const lastAnchor = useRef2(null);
|
|
2677
|
-
|
|
2852
|
+
useEffect6(() => {
|
|
2678
2853
|
function scrollToHash() {
|
|
2679
2854
|
const { anchor } = splitHash(window.location.hash);
|
|
2680
2855
|
if (!anchor || anchor === lastAnchor.current) return;
|
|
@@ -2690,7 +2865,7 @@ function useDeepLinkScroll() {
|
|
|
2690
2865
|
}
|
|
2691
2866
|
|
|
2692
2867
|
// src/interactive/use-keyboard-shortcuts.ts
|
|
2693
|
-
import { useEffect as
|
|
2868
|
+
import { useEffect as useEffect7, useRef as useRef3 } from "react";
|
|
2694
2869
|
function isEditableTarget(target) {
|
|
2695
2870
|
if (!(target instanceof HTMLElement)) return false;
|
|
2696
2871
|
const tag = target.tagName;
|
|
@@ -2701,7 +2876,7 @@ function isEditableTarget(target) {
|
|
|
2701
2876
|
function useKeyboardShortcuts(handlers) {
|
|
2702
2877
|
const ref = useRef3(handlers);
|
|
2703
2878
|
ref.current = handlers;
|
|
2704
|
-
|
|
2879
|
+
useEffect7(() => {
|
|
2705
2880
|
function onKeyDown(e) {
|
|
2706
2881
|
const h = ref.current;
|
|
2707
2882
|
if (e.key === "Escape") {
|
|
@@ -2745,8 +2920,8 @@ function useKeyboardShortcuts(handlers) {
|
|
|
2745
2920
|
}
|
|
2746
2921
|
|
|
2747
2922
|
// src/interactive/use-theme.ts
|
|
2748
|
-
import { useCallback as useCallback3, useEffect as
|
|
2749
|
-
var
|
|
2923
|
+
import { useCallback as useCallback3, useEffect as useEffect8, useState as useState8 } from "react";
|
|
2924
|
+
var KEY2 = "es-theme";
|
|
2750
2925
|
function systemDark() {
|
|
2751
2926
|
return typeof matchMedia !== "undefined" && matchMedia("(prefers-color-scheme: dark)").matches;
|
|
2752
2927
|
}
|
|
@@ -2760,19 +2935,19 @@ function applyTheme(pref) {
|
|
|
2760
2935
|
}
|
|
2761
2936
|
function initialPref() {
|
|
2762
2937
|
if (typeof localStorage !== "undefined") {
|
|
2763
|
-
const stored = localStorage.getItem(
|
|
2938
|
+
const stored = localStorage.getItem(KEY2);
|
|
2764
2939
|
if (stored === "light" || stored === "dark" || stored === "system") return stored;
|
|
2765
2940
|
}
|
|
2766
2941
|
return "system";
|
|
2767
2942
|
}
|
|
2768
2943
|
function useTheme() {
|
|
2769
|
-
const [pref, setPrefState] =
|
|
2770
|
-
|
|
2944
|
+
const [pref, setPrefState] = useState8("system");
|
|
2945
|
+
useEffect8(() => {
|
|
2771
2946
|
const p = initialPref();
|
|
2772
2947
|
setPrefState(p);
|
|
2773
2948
|
applyTheme(p);
|
|
2774
2949
|
}, []);
|
|
2775
|
-
|
|
2950
|
+
useEffect8(() => {
|
|
2776
2951
|
if (typeof matchMedia === "undefined") return;
|
|
2777
2952
|
const mq = matchMedia("(prefers-color-scheme: dark)");
|
|
2778
2953
|
const onChange = () => {
|
|
@@ -2785,7 +2960,7 @@ function useTheme() {
|
|
|
2785
2960
|
setPrefState(p);
|
|
2786
2961
|
applyTheme(p);
|
|
2787
2962
|
try {
|
|
2788
|
-
localStorage.setItem(
|
|
2963
|
+
localStorage.setItem(KEY2, p);
|
|
2789
2964
|
} catch {
|
|
2790
2965
|
}
|
|
2791
2966
|
}, []);
|
|
@@ -2793,19 +2968,19 @@ function useTheme() {
|
|
|
2793
2968
|
}
|
|
2794
2969
|
|
|
2795
2970
|
// src/interactive/use-url-state.ts
|
|
2796
|
-
import { useCallback as useCallback4, useEffect as
|
|
2971
|
+
import { useCallback as useCallback4, useEffect as useEffect9, useRef as useRef4, useState as useState9 } from "react";
|
|
2797
2972
|
var WRITE_DELAY_MS = 250;
|
|
2798
2973
|
function useUrlState() {
|
|
2799
|
-
const [state, setState] =
|
|
2974
|
+
const [state, setState] = useState9(DEFAULT_URL_STATE);
|
|
2800
2975
|
const ready = useRef4(false);
|
|
2801
|
-
|
|
2976
|
+
useEffect9(() => {
|
|
2802
2977
|
const read = () => setState(decodeUrlState(splitHash(window.location.hash).params));
|
|
2803
2978
|
read();
|
|
2804
2979
|
ready.current = true;
|
|
2805
2980
|
window.addEventListener("hashchange", read);
|
|
2806
2981
|
return () => window.removeEventListener("hashchange", read);
|
|
2807
2982
|
}, []);
|
|
2808
|
-
|
|
2983
|
+
useEffect9(() => {
|
|
2809
2984
|
if (!ready.current) return;
|
|
2810
2985
|
const timer = setTimeout(
|
|
2811
2986
|
() => writeHash(splitHash(window.location.hash).anchor, encodeUrlState(state)),
|
|
@@ -3041,12 +3216,12 @@ function reportTools(deps) {
|
|
|
3041
3216
|
}
|
|
3042
3217
|
|
|
3043
3218
|
// src/interactive/ReportInteractive.tsx
|
|
3044
|
-
import { Fragment as
|
|
3219
|
+
import { Fragment as Fragment15, jsx as jsx50, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
3045
3220
|
function ReportInteractive(props) {
|
|
3046
3221
|
const { report, className, title, dataTheme } = props;
|
|
3047
3222
|
const result = unwrapReport(report);
|
|
3048
3223
|
if (!result.ok) {
|
|
3049
|
-
return /* @__PURE__ */
|
|
3224
|
+
return /* @__PURE__ */ jsx50(
|
|
3050
3225
|
ReportErrorShell,
|
|
3051
3226
|
{
|
|
3052
3227
|
error: result.error,
|
|
@@ -3056,7 +3231,7 @@ function ReportInteractive(props) {
|
|
|
3056
3231
|
}
|
|
3057
3232
|
);
|
|
3058
3233
|
}
|
|
3059
|
-
return /* @__PURE__ */
|
|
3234
|
+
return /* @__PURE__ */ jsx50(ReportInteractiveView, { ...props, report: result.data });
|
|
3060
3235
|
}
|
|
3061
3236
|
var THEME_OPTIONS = [
|
|
3062
3237
|
{ value: "light", label: "Light", Icon: Sun },
|
|
@@ -3067,7 +3242,7 @@ function ThemeSegment({
|
|
|
3067
3242
|
pref,
|
|
3068
3243
|
onPref
|
|
3069
3244
|
}) {
|
|
3070
|
-
return /* @__PURE__ */
|
|
3245
|
+
return /* @__PURE__ */ jsx50(
|
|
3071
3246
|
ToggleGroup,
|
|
3072
3247
|
{
|
|
3073
3248
|
size: "sm",
|
|
@@ -3077,14 +3252,14 @@ function ThemeSegment({
|
|
|
3077
3252
|
if (next) onPref(next);
|
|
3078
3253
|
},
|
|
3079
3254
|
"aria-label": "Color theme",
|
|
3080
|
-
children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */
|
|
3255
|
+
children: THEME_OPTIONS.map(({ value, label, Icon }) => /* @__PURE__ */ jsx50(
|
|
3081
3256
|
ToggleGroupItem,
|
|
3082
3257
|
{
|
|
3083
3258
|
value,
|
|
3084
3259
|
"aria-label": label,
|
|
3085
3260
|
title: label,
|
|
3086
3261
|
className: "px-2",
|
|
3087
|
-
children: /* @__PURE__ */
|
|
3262
|
+
children: /* @__PURE__ */ jsx50(Icon, {})
|
|
3088
3263
|
},
|
|
3089
3264
|
value
|
|
3090
3265
|
))
|
|
@@ -3117,7 +3292,7 @@ function ReportInteractiveView({
|
|
|
3117
3292
|
(next) => setUrlState({ detail: next }),
|
|
3118
3293
|
[setUrlState]
|
|
3119
3294
|
);
|
|
3120
|
-
const [helpOpen, setHelpOpen] =
|
|
3295
|
+
const [helpOpen, setHelpOpen] = useState10(false);
|
|
3121
3296
|
const { pref: themePref, setPref: setThemePref } = useTheme();
|
|
3122
3297
|
const searchRef = useRef5(null);
|
|
3123
3298
|
const expandId = useId2();
|
|
@@ -3159,7 +3334,7 @@ function ReportInteractiveView({
|
|
|
3159
3334
|
}),
|
|
3160
3335
|
[activeTags, setUrlState]
|
|
3161
3336
|
);
|
|
3162
|
-
const [toast, setToast] =
|
|
3337
|
+
const [toast, setToast] = useState10(null);
|
|
3163
3338
|
const toastTimer = useRef5(null);
|
|
3164
3339
|
const showToast = useCallback5((msg) => {
|
|
3165
3340
|
setToast(msg);
|
|
@@ -3185,6 +3360,10 @@ function ReportInteractiveView({
|
|
|
3185
3360
|
}),
|
|
3186
3361
|
[copy]
|
|
3187
3362
|
);
|
|
3363
|
+
const copyAllFailures = useCallback5(
|
|
3364
|
+
() => copy(failuresToPrompt(failedScenarios(filtered)), "Failures copied"),
|
|
3365
|
+
[copy, filtered]
|
|
3366
|
+
);
|
|
3188
3367
|
const failureIndexRef = useRef5(0);
|
|
3189
3368
|
const allCollapsibleIds = useMemo3(
|
|
3190
3369
|
() => report.features.flatMap((f) => [f.id, ...f.scenarios.map((s) => s.id)]),
|
|
@@ -3202,7 +3381,7 @@ function ReportInteractiveView({
|
|
|
3202
3381
|
() => collapse.collapseAll(allCollapsibleIds),
|
|
3203
3382
|
[collapse, allCollapsibleIds]
|
|
3204
3383
|
);
|
|
3205
|
-
const [expandedAll, setExpandedAll] =
|
|
3384
|
+
const [expandedAll, setExpandedAll] = useState10(
|
|
3206
3385
|
() => report.summary.failed === 0
|
|
3207
3386
|
);
|
|
3208
3387
|
const setExpanded = useCallback5(
|
|
@@ -3213,7 +3392,7 @@ function ReportInteractiveView({
|
|
|
3213
3392
|
},
|
|
3214
3393
|
[collapse, collapseAll]
|
|
3215
3394
|
);
|
|
3216
|
-
const [agentFilter, setAgentFilter] =
|
|
3395
|
+
const [agentFilter, setAgentFilter] = useState10(null);
|
|
3217
3396
|
useTools(
|
|
3218
3397
|
reportTools({
|
|
3219
3398
|
report,
|
|
@@ -3260,13 +3439,13 @@ function ReportInteractiveView({
|
|
|
3260
3439
|
const totalScenarios = report.summary.total;
|
|
3261
3440
|
const matchedScenarios = filtered.summary.total;
|
|
3262
3441
|
const showToc = !hideToc && totalScenarios > 3;
|
|
3263
|
-
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(
|
|
3264
3443
|
ReportRoot,
|
|
3265
3444
|
{
|
|
3266
3445
|
report: filtered,
|
|
3267
3446
|
customRenderers,
|
|
3268
3447
|
renderers,
|
|
3269
|
-
children: /* @__PURE__ */
|
|
3448
|
+
children: /* @__PURE__ */ jsxs35(
|
|
3270
3449
|
"main",
|
|
3271
3450
|
{
|
|
3272
3451
|
className: cn("es-report", "es-report-interactive", className),
|
|
@@ -3275,8 +3454,8 @@ function ReportInteractiveView({
|
|
|
3275
3454
|
"data-theme": dataTheme,
|
|
3276
3455
|
"data-detail-level": detail,
|
|
3277
3456
|
children: [
|
|
3278
|
-
/* @__PURE__ */
|
|
3279
|
-
/* @__PURE__ */
|
|
3457
|
+
/* @__PURE__ */ jsxs35("header", { className: "es-report-header", children: [
|
|
3458
|
+
/* @__PURE__ */ jsxs35(
|
|
3280
3459
|
"div",
|
|
3281
3460
|
{
|
|
3282
3461
|
"data-es-navbar": true,
|
|
@@ -3285,9 +3464,9 @@ function ReportInteractiveView({
|
|
|
3285
3464
|
hideHeader ? "justify-end" : "justify-between"
|
|
3286
3465
|
),
|
|
3287
3466
|
children: [
|
|
3288
|
-
hideHeader ? null : /* @__PURE__ */
|
|
3289
|
-
/* @__PURE__ */
|
|
3290
|
-
/* @__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(
|
|
3291
3470
|
ReportSearch,
|
|
3292
3471
|
{
|
|
3293
3472
|
ref: searchRef,
|
|
@@ -3297,16 +3476,16 @@ function ReportInteractiveView({
|
|
|
3297
3476
|
totalCount: totalScenarios
|
|
3298
3477
|
}
|
|
3299
3478
|
),
|
|
3300
|
-
/* @__PURE__ */
|
|
3479
|
+
/* @__PURE__ */ jsx50(ThemeSegment, { pref: themePref, onPref: setThemePref })
|
|
3301
3480
|
] })
|
|
3302
3481
|
]
|
|
3303
3482
|
}
|
|
3304
3483
|
),
|
|
3305
|
-
hideHeader ? null : /* @__PURE__ */
|
|
3306
|
-
/* @__PURE__ */
|
|
3307
|
-
/* @__PURE__ */
|
|
3484
|
+
hideHeader ? null : /* @__PURE__ */ jsxs35(Fragment15, { children: [
|
|
3485
|
+
/* @__PURE__ */ jsx50(ReportSummary, {}),
|
|
3486
|
+
/* @__PURE__ */ jsx50(ReportMeta, {})
|
|
3308
3487
|
] }),
|
|
3309
|
-
/* @__PURE__ */
|
|
3488
|
+
/* @__PURE__ */ jsx50(
|
|
3310
3489
|
ReportFreshness,
|
|
3311
3490
|
{
|
|
3312
3491
|
lastRunMs: reportLastRunMs(report),
|
|
@@ -3314,14 +3493,15 @@ function ReportInteractiveView({
|
|
|
3314
3493
|
staleAfterDays
|
|
3315
3494
|
}
|
|
3316
3495
|
),
|
|
3317
|
-
/* @__PURE__ */
|
|
3496
|
+
/* @__PURE__ */ jsx50(
|
|
3318
3497
|
ReportLastRunDelta,
|
|
3319
3498
|
{
|
|
3320
3499
|
history: scenarioHistory,
|
|
3321
3500
|
report
|
|
3322
3501
|
}
|
|
3323
3502
|
),
|
|
3324
|
-
/* @__PURE__ */
|
|
3503
|
+
/* @__PURE__ */ jsx50(ReportSinceLastVisit, { report }),
|
|
3504
|
+
/* @__PURE__ */ jsx50(
|
|
3325
3505
|
ReportFilters,
|
|
3326
3506
|
{
|
|
3327
3507
|
statuses: statusOptions,
|
|
@@ -3332,10 +3512,10 @@ function ReportInteractiveView({
|
|
|
3332
3512
|
onToggleTag: toggleTag
|
|
3333
3513
|
}
|
|
3334
3514
|
),
|
|
3335
|
-
/* @__PURE__ */
|
|
3336
|
-
showToc ? /* @__PURE__ */
|
|
3337
|
-
/* @__PURE__ */
|
|
3338
|
-
/* @__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(
|
|
3339
3519
|
Switch,
|
|
3340
3520
|
{
|
|
3341
3521
|
id: expandId,
|
|
@@ -3343,7 +3523,7 @@ function ReportInteractiveView({
|
|
|
3343
3523
|
onCheckedChange: setExpanded
|
|
3344
3524
|
}
|
|
3345
3525
|
),
|
|
3346
|
-
/* @__PURE__ */
|
|
3526
|
+
/* @__PURE__ */ jsx50(
|
|
3347
3527
|
"label",
|
|
3348
3528
|
{
|
|
3349
3529
|
htmlFor: expandId,
|
|
@@ -3352,8 +3532,8 @@ function ReportInteractiveView({
|
|
|
3352
3532
|
}
|
|
3353
3533
|
)
|
|
3354
3534
|
] }),
|
|
3355
|
-
/* @__PURE__ */
|
|
3356
|
-
/* @__PURE__ */
|
|
3535
|
+
/* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-2", children: [
|
|
3536
|
+
/* @__PURE__ */ jsx50(
|
|
3357
3537
|
Switch,
|
|
3358
3538
|
{
|
|
3359
3539
|
id: docsId,
|
|
@@ -3361,7 +3541,7 @@ function ReportInteractiveView({
|
|
|
3361
3541
|
onCheckedChange: (checked) => setDetail(checked ? "full" : "minimal")
|
|
3362
3542
|
}
|
|
3363
3543
|
),
|
|
3364
|
-
/* @__PURE__ */
|
|
3544
|
+
/* @__PURE__ */ jsx50(
|
|
3365
3545
|
"label",
|
|
3366
3546
|
{
|
|
3367
3547
|
htmlFor: docsId,
|
|
@@ -3372,7 +3552,7 @@ function ReportInteractiveView({
|
|
|
3372
3552
|
] })
|
|
3373
3553
|
] })
|
|
3374
3554
|
] }),
|
|
3375
|
-
showAgentFilter ? /* @__PURE__ */
|
|
3555
|
+
showAgentFilter ? /* @__PURE__ */ jsx50(
|
|
3376
3556
|
ReportAgentFilterNotice,
|
|
3377
3557
|
{
|
|
3378
3558
|
applied: agentFilter,
|
|
@@ -3380,17 +3560,17 @@ function ReportInteractiveView({
|
|
|
3380
3560
|
onDismiss: () => setAgentFilter(null)
|
|
3381
3561
|
}
|
|
3382
3562
|
) : null,
|
|
3383
|
-
/* @__PURE__ */
|
|
3384
|
-
hasContent ? showToc ? /* @__PURE__ */
|
|
3385
|
-
/* @__PURE__ */
|
|
3386
|
-
/* @__PURE__ */
|
|
3387
|
-
] }) : /* @__PURE__ */
|
|
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(
|
|
3388
3568
|
ReportEmpty,
|
|
3389
3569
|
{
|
|
3390
3570
|
message: query ? "No scenarios match the search." : void 0
|
|
3391
3571
|
}
|
|
3392
3572
|
),
|
|
3393
|
-
/* @__PURE__ */
|
|
3573
|
+
/* @__PURE__ */ jsx50(
|
|
3394
3574
|
"button",
|
|
3395
3575
|
{
|
|
3396
3576
|
type: "button",
|
|
@@ -3401,14 +3581,14 @@ function ReportInteractiveView({
|
|
|
3401
3581
|
children: "?"
|
|
3402
3582
|
}
|
|
3403
3583
|
),
|
|
3404
|
-
/* @__PURE__ */
|
|
3584
|
+
/* @__PURE__ */ jsx50(
|
|
3405
3585
|
ReportShortcutsHelp,
|
|
3406
3586
|
{
|
|
3407
3587
|
open: helpOpen,
|
|
3408
3588
|
onClose: () => setHelpOpen(false)
|
|
3409
3589
|
}
|
|
3410
3590
|
),
|
|
3411
|
-
toast ? /* @__PURE__ */
|
|
3591
|
+
toast ? /* @__PURE__ */ jsx50(
|
|
3412
3592
|
"div",
|
|
3413
3593
|
{
|
|
3414
3594
|
role: "status",
|
|
@@ -3428,11 +3608,11 @@ function ReportInteractiveView({
|
|
|
3428
3608
|
import { useMemo as useMemo4 } from "react";
|
|
3429
3609
|
|
|
3430
3610
|
// src/interactive/island-renderers.tsx
|
|
3431
|
-
import { createElement, useEffect as
|
|
3611
|
+
import { createElement, useEffect as useEffect11, useState as useState12 } from "react";
|
|
3432
3612
|
|
|
3433
3613
|
// src/components/doc/MermaidView.tsx
|
|
3434
|
-
import { useEffect as
|
|
3435
|
-
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";
|
|
3436
3616
|
function prefersDark(el) {
|
|
3437
3617
|
const themed = el?.closest("[data-theme]");
|
|
3438
3618
|
if (themed?.dataset.theme === "dark") return true;
|
|
@@ -3441,9 +3621,9 @@ function prefersDark(el) {
|
|
|
3441
3621
|
}
|
|
3442
3622
|
function MermaidView({ entry, load }) {
|
|
3443
3623
|
const ref = useRef6(null);
|
|
3444
|
-
const [svg, setSvg] =
|
|
3445
|
-
const [error, setError] =
|
|
3446
|
-
|
|
3624
|
+
const [svg, setSvg] = useState11(null);
|
|
3625
|
+
const [error, setError] = useState11(null);
|
|
3626
|
+
useEffect10(() => {
|
|
3447
3627
|
let cancelled = false;
|
|
3448
3628
|
const draw = async () => {
|
|
3449
3629
|
let mermaid;
|
|
@@ -3486,9 +3666,9 @@ function MermaidView({ entry, load }) {
|
|
|
3486
3666
|
};
|
|
3487
3667
|
}, [entry.code, load]);
|
|
3488
3668
|
if (svg) {
|
|
3489
|
-
return /* @__PURE__ */
|
|
3490
|
-
entry.title ? /* @__PURE__ */
|
|
3491
|
-
/* @__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(
|
|
3492
3672
|
"div",
|
|
3493
3673
|
{
|
|
3494
3674
|
role: "img",
|
|
@@ -3499,8 +3679,8 @@ function MermaidView({ entry, load }) {
|
|
|
3499
3679
|
)
|
|
3500
3680
|
] });
|
|
3501
3681
|
}
|
|
3502
|
-
return /* @__PURE__ */
|
|
3503
|
-
error ? /* @__PURE__ */
|
|
3682
|
+
return /* @__PURE__ */ jsxs36(Fragment16, { children: [
|
|
3683
|
+
error ? /* @__PURE__ */ jsxs36(
|
|
3504
3684
|
"p",
|
|
3505
3685
|
{
|
|
3506
3686
|
role: "alert",
|
|
@@ -3512,12 +3692,12 @@ function MermaidView({ entry, load }) {
|
|
|
3512
3692
|
]
|
|
3513
3693
|
}
|
|
3514
3694
|
) : null,
|
|
3515
|
-
/* @__PURE__ */
|
|
3695
|
+
/* @__PURE__ */ jsx51(MermaidSource, { entry, ref })
|
|
3516
3696
|
] });
|
|
3517
3697
|
}
|
|
3518
3698
|
|
|
3519
3699
|
// src/interactive/island-renderers.tsx
|
|
3520
|
-
import { jsx as
|
|
3700
|
+
import { jsx as jsx52 } from "react/jsx-runtime";
|
|
3521
3701
|
var HLJS_ESM = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/highlight.min.js";
|
|
3522
3702
|
var MERMAID_ESM = "https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs";
|
|
3523
3703
|
function cachedCdnModule(url) {
|
|
@@ -3534,8 +3714,8 @@ function cachedCdnModule(url) {
|
|
|
3534
3714
|
var loadMermaidFromCdn = cachedCdnModule(MERMAID_ESM);
|
|
3535
3715
|
var loadHljs = cachedCdnModule(HLJS_ESM);
|
|
3536
3716
|
function CdnHighlightedCode({ entry }) {
|
|
3537
|
-
const [html, setHtml] =
|
|
3538
|
-
|
|
3717
|
+
const [html, setHtml] = useState12(null);
|
|
3718
|
+
useEffect11(() => {
|
|
3539
3719
|
let cancelled = false;
|
|
3540
3720
|
void (async () => {
|
|
3541
3721
|
try {
|
|
@@ -3551,13 +3731,13 @@ function CdnHighlightedCode({ entry }) {
|
|
|
3551
3731
|
cancelled = true;
|
|
3552
3732
|
};
|
|
3553
3733
|
}, [entry.content, entry.lang]);
|
|
3554
|
-
return /* @__PURE__ */
|
|
3734
|
+
return /* @__PURE__ */ jsx52(CodeFigure, { label: entry.label, children: html !== null ? /* @__PURE__ */ jsx52(
|
|
3555
3735
|
"code",
|
|
3556
3736
|
{
|
|
3557
3737
|
className: cn("hljs font-mono text-xs", entry.lang && `language-${entry.lang}`),
|
|
3558
3738
|
dangerouslySetInnerHTML: { __html: html }
|
|
3559
3739
|
}
|
|
3560
|
-
) : /* @__PURE__ */
|
|
3740
|
+
) : /* @__PURE__ */ jsx52("code", { className: cn("font-mono text-xs", entry.lang && `language-${entry.lang}`), children: entry.content }) });
|
|
3561
3741
|
}
|
|
3562
3742
|
function buildIslandRenderers(opts) {
|
|
3563
3743
|
const renderers = {};
|
|
@@ -3571,7 +3751,7 @@ function buildIslandRenderers(opts) {
|
|
|
3571
3751
|
}
|
|
3572
3752
|
|
|
3573
3753
|
// src/interactive/ReportInteractiveIsland.tsx
|
|
3574
|
-
import { jsx as
|
|
3754
|
+
import { jsx as jsx53 } from "react/jsx-runtime";
|
|
3575
3755
|
function ReportInteractiveIsland({
|
|
3576
3756
|
report,
|
|
3577
3757
|
title,
|
|
@@ -3585,7 +3765,7 @@ function ReportInteractiveIsland({
|
|
|
3585
3765
|
() => buildIslandRenderers({ syntaxHighlighting, mermaid }),
|
|
3586
3766
|
[syntaxHighlighting, mermaid]
|
|
3587
3767
|
);
|
|
3588
|
-
return /* @__PURE__ */
|
|
3768
|
+
return /* @__PURE__ */ jsx53(
|
|
3589
3769
|
ReportInteractive,
|
|
3590
3770
|
{
|
|
3591
3771
|
report,
|