executable-stories-react 0.10.0 → 0.11.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 +216 -270
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -235
- package/dist/index.d.ts +6 -235
- package/dist/index.js +208 -262
- package/dist/index.js.map +1 -1
- package/dist/interactive.cjs +266 -476
- package/dist/interactive.cjs.map +1 -1
- package/dist/interactive.d.cts +1 -233
- package/dist/interactive.d.ts +1 -233
- package/dist/interactive.js +258 -468
- package/dist/interactive.js.map +1 -1
- package/dist/parse.cjs +40 -1
- package/dist/parse.cjs.map +1 -1
- package/dist/parse.d.cts +3 -234
- package/dist/parse.d.ts +3 -234
- package/dist/parse.js +40 -1
- package/dist/parse.js.map +1 -1
- package/dist/report-island.global.js +23 -21
- package/dist/ssr.cjs +143 -236
- package/dist/ssr.cjs.map +1 -1
- package/dist/ssr.d.cts +1 -232
- package/dist/ssr.d.ts +1 -232
- package/dist/ssr.js +135 -228
- package/dist/ssr.js.map +1 -1
- package/dist/tailwind.css +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -286,23 +286,11 @@ function useReport() {
|
|
|
286
286
|
return ctx.report;
|
|
287
287
|
}
|
|
288
288
|
|
|
289
|
-
//
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
if (ms < 6e4) {
|
|
295
|
-
return `${(ms / 1e3).toFixed(2)} s`;
|
|
296
|
-
}
|
|
297
|
-
const minutes = Math.floor(ms / 6e4);
|
|
298
|
-
const seconds = Math.floor(ms % 6e4 / 1e3);
|
|
299
|
-
if (minutes < 60) {
|
|
300
|
-
return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
|
|
301
|
-
}
|
|
302
|
-
const hours = Math.floor(minutes / 60);
|
|
303
|
-
const remainingMinutes = minutes % 60;
|
|
304
|
-
return `${hours}h ${remainingMinutes}m`;
|
|
305
|
-
}
|
|
289
|
+
// src/components/ReportScenario.tsx
|
|
290
|
+
import { formatDuration as formatDuration3 } from "executable-stories-core/utils/duration";
|
|
291
|
+
|
|
292
|
+
// src/components/ReportSteps.tsx
|
|
293
|
+
import { formatDuration } from "executable-stories-core/utils/duration";
|
|
306
294
|
|
|
307
295
|
// src/components/doc/DocNote.tsx
|
|
308
296
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
@@ -391,36 +379,29 @@ function DocLink({ entry }) {
|
|
|
391
379
|
);
|
|
392
380
|
}
|
|
393
381
|
|
|
394
|
-
// src/
|
|
382
|
+
// src/lib/markdown.ts
|
|
395
383
|
import { marked } from "marked";
|
|
396
384
|
|
|
397
|
-
//
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
return
|
|
385
|
+
// src/lib/url.ts
|
|
386
|
+
import { safeUrl, safeImageUrl, isLocalFsPath } from "executable-stories-core/utils/url";
|
|
387
|
+
|
|
388
|
+
// src/lib/markdown.ts
|
|
389
|
+
function safeMarkdownHtml(markdown) {
|
|
390
|
+
const raw = marked.parse(markdown, { async: false });
|
|
391
|
+
return raw.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, "").replace(/<\/?(?:iframe|object|embed|form|base)\b[^>]*>/gi, "").replace(/\son[a-z]+\s*=\s*"[^"]*"/gi, "").replace(/\son[a-z]+\s*=\s*'[^']*'/gi, "").replace(/\son[a-z]+\s*=\s*[^\s>]+/gi, "").replace(/(href|src)\s*=\s*"([^"]*)"/gi, (_m, attr, val) => `${attr}="${neutralizeUrl(val)}"`).replace(/(href|src)\s*=\s*'([^']*)'/gi, (_m, attr, val) => `${attr}='${neutralizeUrl(val)}'`);
|
|
404
392
|
}
|
|
405
|
-
function
|
|
406
|
-
|
|
407
|
-
const
|
|
408
|
-
|
|
409
|
-
return
|
|
393
|
+
function dedent(text) {
|
|
394
|
+
const lines = text.replace(/\t/g, " ").split("\n");
|
|
395
|
+
const indents = lines.filter((line) => line.trim().length > 0).map((line) => line.length - line.trimStart().length);
|
|
396
|
+
const shortest = indents.length > 0 ? Math.min(...indents) : 0;
|
|
397
|
+
return lines.map((line) => line.slice(shortest)).join("\n").trim();
|
|
410
398
|
}
|
|
411
|
-
function
|
|
412
|
-
return
|
|
399
|
+
function neutralizeUrl(value) {
|
|
400
|
+
return safeUrl(value) ?? "#";
|
|
413
401
|
}
|
|
414
402
|
|
|
415
403
|
// src/components/doc/DocSection.tsx
|
|
416
404
|
import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
417
|
-
function neutralizeUrl(value) {
|
|
418
|
-
return safeUrl(value) ?? "#";
|
|
419
|
-
}
|
|
420
|
-
function safeMarkdownHtml(markdown) {
|
|
421
|
-
const raw = marked.parse(markdown, { async: false });
|
|
422
|
-
return raw.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, "").replace(/<\/?(?:iframe|object|embed|form|base)\b[^>]*>/gi, "").replace(/\son[a-z]+\s*=\s*"[^"]*"/gi, "").replace(/\son[a-z]+\s*=\s*'[^']*'/gi, "").replace(/\son[a-z]+\s*=\s*[^\s>]+/gi, "").replace(/(href|src)\s*=\s*"([^"]*)"/gi, (_m, attr, val) => `${attr}="${neutralizeUrl(val)}"`).replace(/(href|src)\s*=\s*'([^']*)'/gi, (_m, attr, val) => `${attr}='${neutralizeUrl(val)}'`);
|
|
423
|
-
}
|
|
424
405
|
function DocSection({ entry }) {
|
|
425
406
|
const renderers = useBuiltinRenderers();
|
|
426
407
|
if (renderers.section) {
|
|
@@ -703,125 +684,10 @@ function ReportStepItem({ step }) {
|
|
|
703
684
|
);
|
|
704
685
|
}
|
|
705
686
|
|
|
706
|
-
// ../executable-stories-core/dist/state-diff.js
|
|
707
|
-
var isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
708
|
-
function deepEqual(a, b) {
|
|
709
|
-
if (Object.is(a, b)) return true;
|
|
710
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
711
|
-
return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
|
|
712
|
-
}
|
|
713
|
-
if (isPlainObject(a) && isPlainObject(b)) {
|
|
714
|
-
const ak = Object.keys(a);
|
|
715
|
-
const bk = Object.keys(b);
|
|
716
|
-
return ak.length === bk.length && ak.every((k) => k in b && deepEqual(a[k], b[k]));
|
|
717
|
-
}
|
|
718
|
-
return false;
|
|
719
|
-
}
|
|
720
|
-
var joinKey = (path, key) => path === "" ? key : `${path}.${key}`;
|
|
721
|
-
function walk(path, before, after, out) {
|
|
722
|
-
if (Object.is(before, after)) return;
|
|
723
|
-
if (Array.isArray(before) && Array.isArray(after)) {
|
|
724
|
-
const shared = Math.min(before.length, after.length);
|
|
725
|
-
for (let i = 0; i < shared; i++) walk(`${path}[${i}]`, before[i], after[i], out);
|
|
726
|
-
for (let i = shared; i < after.length; i++) out.push({ path: `${path}[${i}]`, kind: "added", after: after[i] });
|
|
727
|
-
for (let i = shared; i < before.length; i++) out.push({ path: `${path}[${i}]`, kind: "removed", before: before[i] });
|
|
728
|
-
return;
|
|
729
|
-
}
|
|
730
|
-
if (isPlainObject(before) && isPlainObject(after)) {
|
|
731
|
-
for (const key of Object.keys(after)) {
|
|
732
|
-
const p = joinKey(path, key);
|
|
733
|
-
if (key in before) walk(p, before[key], after[key], out);
|
|
734
|
-
else out.push({ path: p, kind: "added", after: after[key] });
|
|
735
|
-
}
|
|
736
|
-
for (const key of Object.keys(before)) {
|
|
737
|
-
if (!(key in after)) out.push({ path: joinKey(path, key), kind: "removed", before: before[key] });
|
|
738
|
-
}
|
|
739
|
-
return;
|
|
740
|
-
}
|
|
741
|
-
if (!deepEqual(before, after)) out.push({ path, kind: "changed", before, after });
|
|
742
|
-
}
|
|
743
|
-
function diffStateValues(before, after) {
|
|
744
|
-
const out = [];
|
|
745
|
-
walk("", before, after, out);
|
|
746
|
-
return out;
|
|
747
|
-
}
|
|
748
|
-
function formatStateValue(value, maxLen = 60) {
|
|
749
|
-
const s = value === void 0 ? "undefined" : JSON.stringify(value);
|
|
750
|
-
return s.length > maxLen ? `${s.slice(0, maxLen - 1)}\u2026` : s;
|
|
751
|
-
}
|
|
752
|
-
function summarizeStateChanges(changes) {
|
|
753
|
-
return changes.map((c) => {
|
|
754
|
-
const at = c.path === "" ? "(root)" : c.path;
|
|
755
|
-
switch (c.kind) {
|
|
756
|
-
case "added":
|
|
757
|
-
return `+ ${at}: ${formatStateValue(c.after)}`;
|
|
758
|
-
case "removed":
|
|
759
|
-
return `\u2212 ${at}`;
|
|
760
|
-
case "changed":
|
|
761
|
-
return `${at}: ${formatStateValue(c.before)} \u2192 ${formatStateValue(c.after)}`;
|
|
762
|
-
}
|
|
763
|
-
});
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
// ../executable-stories-core/dist/storyboard.js
|
|
767
|
-
function findScreenshot(entries) {
|
|
768
|
-
for (const entry of entries) {
|
|
769
|
-
if (entry.kind === "screenshot") return entry;
|
|
770
|
-
if (entry.children) {
|
|
771
|
-
const nested = findScreenshot(entry.children);
|
|
772
|
-
if (nested) return nested;
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
return void 0;
|
|
776
|
-
}
|
|
777
|
-
function findStates(entries, out = []) {
|
|
778
|
-
for (const entry of entries) {
|
|
779
|
-
if (entry.kind === "state") out.push(entry);
|
|
780
|
-
if (entry.children) findStates(entry.children, out);
|
|
781
|
-
}
|
|
782
|
-
return out;
|
|
783
|
-
}
|
|
784
|
-
var laneOf = (label) => label ?? "";
|
|
785
|
-
function extractStoryboardFrames(scenario) {
|
|
786
|
-
const frames = [];
|
|
787
|
-
const laneOrder = [];
|
|
788
|
-
const previous = /* @__PURE__ */ new Map();
|
|
789
|
-
for (const step of scenario.steps) {
|
|
790
|
-
const shot = findScreenshot(step.docEntries);
|
|
791
|
-
const stateDocs = findStates(step.docEntries);
|
|
792
|
-
if (!shot && stateDocs.length === 0) continue;
|
|
793
|
-
const byLane = /* @__PURE__ */ new Map();
|
|
794
|
-
for (const doc of stateDocs) {
|
|
795
|
-
const lane = laneOf(doc.label);
|
|
796
|
-
if (!byLane.has(lane) && !laneOrder.includes(lane)) laneOrder.push(lane);
|
|
797
|
-
byLane.set(lane, doc);
|
|
798
|
-
}
|
|
799
|
-
const states = [];
|
|
800
|
-
for (const lane of laneOrder) {
|
|
801
|
-
const doc = byLane.get(lane);
|
|
802
|
-
if (!doc) continue;
|
|
803
|
-
const card = {
|
|
804
|
-
...doc.label !== void 0 && { label: doc.label },
|
|
805
|
-
value: doc.value
|
|
806
|
-
};
|
|
807
|
-
if (previous.has(lane)) card.changes = diffStateValues(previous.get(lane), doc.value);
|
|
808
|
-
previous.set(lane, doc.value);
|
|
809
|
-
states.push(card);
|
|
810
|
-
}
|
|
811
|
-
frames.push({
|
|
812
|
-
stepId: step.id,
|
|
813
|
-
stepIndex: step.index,
|
|
814
|
-
keyword: step.keyword,
|
|
815
|
-
text: step.text,
|
|
816
|
-
status: step.status,
|
|
817
|
-
...shot && { screenshot: { path: shot.path, ...shot.alt !== void 0 && { alt: shot.alt } } },
|
|
818
|
-
states
|
|
819
|
-
});
|
|
820
|
-
}
|
|
821
|
-
return frames;
|
|
822
|
-
}
|
|
823
|
-
|
|
824
687
|
// src/components/ReportStoryboard.tsx
|
|
688
|
+
import { extractStoryboardFrames } from "executable-stories-core/storyboard";
|
|
689
|
+
import { summarizeStateChanges } from "executable-stories-core/state-diff";
|
|
690
|
+
import { isLocalFsPath as isLocalFsPath2, safeImageUrl as safeImageUrl2 } from "executable-stories-core/utils/url";
|
|
825
691
|
import { jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
826
692
|
var FRAME_GLYPH = {
|
|
827
693
|
passed: "\u2713",
|
|
@@ -870,7 +736,7 @@ function StoryboardFrameItem({ frame }) {
|
|
|
870
736
|
}
|
|
871
737
|
function FrameScreenshot({ frame, label }) {
|
|
872
738
|
const path = frame.screenshot?.path ?? "";
|
|
873
|
-
const src =
|
|
739
|
+
const src = isLocalFsPath2(path) ? void 0 : safeImageUrl2(path);
|
|
874
740
|
return /* @__PURE__ */ jsx20(
|
|
875
741
|
"a",
|
|
876
742
|
{
|
|
@@ -976,6 +842,9 @@ function ReportAttachments({ attachments }) {
|
|
|
976
842
|
);
|
|
977
843
|
}
|
|
978
844
|
|
|
845
|
+
// src/components/ReportTrace.tsx
|
|
846
|
+
import { formatDuration as formatDuration2 } from "executable-stories-core/utils/duration";
|
|
847
|
+
|
|
979
848
|
// src/lib/trace.ts
|
|
980
849
|
var VALID = /* @__PURE__ */ new Set(["ok", "error", "unset"]);
|
|
981
850
|
var safeStatus = (s) => VALID.has(s) ? s : "unset";
|
|
@@ -1028,15 +897,15 @@ function toTraceRows(spans) {
|
|
|
1028
897
|
roots.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);
|
|
1029
898
|
const rows = [];
|
|
1030
899
|
const seen = /* @__PURE__ */ new Set();
|
|
1031
|
-
const
|
|
900
|
+
const walk = (node, depth) => {
|
|
1032
901
|
if (seen.has(node.span.spanId)) return;
|
|
1033
902
|
seen.add(node.span.spanId);
|
|
1034
903
|
rows.push({ ...node.span, depth });
|
|
1035
|
-
for (const child of node.children)
|
|
904
|
+
for (const child of node.children) walk(child, depth + 1);
|
|
1036
905
|
};
|
|
1037
|
-
for (const root of roots)
|
|
906
|
+
for (const root of roots) walk(root, 0);
|
|
1038
907
|
for (const node of byId.values()) {
|
|
1039
|
-
if (!seen.has(node.span.spanId))
|
|
908
|
+
if (!seen.has(node.span.spanId)) walk(node, 0);
|
|
1040
909
|
}
|
|
1041
910
|
return rows;
|
|
1042
911
|
}
|
|
@@ -1070,7 +939,7 @@ function ReportTrace({ spans }) {
|
|
|
1070
939
|
" span",
|
|
1071
940
|
rows.length === 1 ? "" : "s",
|
|
1072
941
|
", ",
|
|
1073
|
-
|
|
942
|
+
formatDuration2(totalMs),
|
|
1074
943
|
")"
|
|
1075
944
|
] }),
|
|
1076
945
|
/* @__PURE__ */ jsx22("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
|
|
@@ -1093,7 +962,7 @@ function ReportTrace({ spans }) {
|
|
|
1093
962
|
style: { left: `${leftPct}%`, width: `${widthPct}%` }
|
|
1094
963
|
}
|
|
1095
964
|
) }),
|
|
1096
|
-
/* @__PURE__ */ jsx22("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children:
|
|
965
|
+
/* @__PURE__ */ jsx22("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration2(row.durationMs) })
|
|
1097
966
|
] }, `${row.spanId}-${i}`);
|
|
1098
967
|
}) })
|
|
1099
968
|
] });
|
|
@@ -1204,6 +1073,7 @@ function useCollapse() {
|
|
|
1204
1073
|
|
|
1205
1074
|
// src/interactive/scenario-actions.tsx
|
|
1206
1075
|
import { createContext as createContext4, useContext as useContext5 } from "react";
|
|
1076
|
+
import { scenarioToMarkdown as coreScenarioToMarkdown } from "executable-stories-core/utils/scenario-markdown";
|
|
1207
1077
|
var ScenarioActionsContext = createContext4(null);
|
|
1208
1078
|
var ScenarioActionsProvider = ScenarioActionsContext.Provider;
|
|
1209
1079
|
function useScenarioActions() {
|
|
@@ -1349,7 +1219,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1349
1219
|
] }),
|
|
1350
1220
|
/* @__PURE__ */ jsxs17("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
1351
1221
|
/* @__PURE__ */ jsx26(ScenarioRunHistory, { scenarioId: scenario.id }),
|
|
1352
|
-
scenario.durationMs > 0 ? /* @__PURE__ */ jsx26("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children:
|
|
1222
|
+
scenario.durationMs > 0 ? /* @__PURE__ */ jsx26("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration3(scenario.durationMs) }) : null,
|
|
1353
1223
|
meta.showPill ? /* @__PURE__ */ jsx26(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ jsx26("span", { className: "sr-only", children: `Status: ${label}` }),
|
|
1354
1224
|
actions ? /* @__PURE__ */ jsxs17(DropdownMenu, { children: [
|
|
1355
1225
|
/* @__PURE__ */ jsx26(
|
|
@@ -1408,8 +1278,35 @@ function ReportScenarioList({ feature }) {
|
|
|
1408
1278
|
return /* @__PURE__ */ jsx27(Fragment8, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ jsx27(ReportScenario, { scenario }, scenario.id)) });
|
|
1409
1279
|
}
|
|
1410
1280
|
|
|
1281
|
+
// src/components/ReportFeatureIntro.tsx
|
|
1282
|
+
import { jsx as jsx28, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1283
|
+
function ReportFeatureIntro({ feature }) {
|
|
1284
|
+
const hasNarrative = Boolean(feature.narrative?.trim());
|
|
1285
|
+
const hasGlossary = Boolean(feature.glossary?.length);
|
|
1286
|
+
if (!hasNarrative && !hasGlossary) return null;
|
|
1287
|
+
return /* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-3 border-l-2 border-border pl-4 text-sm", children: [
|
|
1288
|
+
hasNarrative ? /* @__PURE__ */ jsx28(
|
|
1289
|
+
"div",
|
|
1290
|
+
{
|
|
1291
|
+
className: "es-doc-prose prose prose-sm max-w-none text-muted-foreground",
|
|
1292
|
+
dangerouslySetInnerHTML: { __html: safeMarkdownHtml(dedent(feature.narrative)) }
|
|
1293
|
+
}
|
|
1294
|
+
) : null,
|
|
1295
|
+
hasGlossary ? /* @__PURE__ */ jsx28("dl", { className: "grid gap-1.5", "aria-label": "Glossary", children: feature.glossary.map((entry) => /* @__PURE__ */ jsxs18("div", { className: "flex flex-wrap gap-x-2 text-xs", children: [
|
|
1296
|
+
/* @__PURE__ */ jsx28("dt", { className: "font-medium text-foreground", children: entry.term }),
|
|
1297
|
+
/* @__PURE__ */ jsx28("dd", { className: "flex-1 text-muted-foreground", children: entry.definition })
|
|
1298
|
+
] }, entry.term)) }) : null
|
|
1299
|
+
] });
|
|
1300
|
+
}
|
|
1301
|
+
function featureKindLabel(kind) {
|
|
1302
|
+
if (kind === "ability") return "Ability";
|
|
1303
|
+
if (kind === "business-need") return "Business need";
|
|
1304
|
+
if (kind === "feature") return "Feature";
|
|
1305
|
+
return null;
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1411
1308
|
// src/components/ReportFeature.tsx
|
|
1412
|
-
import { Fragment as Fragment9, jsx as
|
|
1309
|
+
import { Fragment as Fragment9, jsx as jsx29, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1413
1310
|
function ReportFeature({ feature }) {
|
|
1414
1311
|
const titleId = `${feature.id}-title`;
|
|
1415
1312
|
const bodyId = `${feature.id}-body`;
|
|
@@ -1417,10 +1314,11 @@ function ReportFeature({ feature }) {
|
|
|
1417
1314
|
const skipped = s.skipped + s.pending;
|
|
1418
1315
|
const collapse = useCollapse();
|
|
1419
1316
|
const collapsed = collapse?.isCollapsed(feature.id) ?? false;
|
|
1317
|
+
const kindLabel = featureKindLabel(feature.kind);
|
|
1420
1318
|
return (
|
|
1421
1319
|
// Suite = a section heading + a divider, NOT another bordered card. Drops a
|
|
1422
1320
|
// layer of nesting so the scenario cards below read as the primary unit.
|
|
1423
|
-
/* @__PURE__ */
|
|
1321
|
+
/* @__PURE__ */ jsxs19(
|
|
1424
1322
|
"section",
|
|
1425
1323
|
{
|
|
1426
1324
|
id: feature.id,
|
|
@@ -1428,9 +1326,9 @@ function ReportFeature({ feature }) {
|
|
|
1428
1326
|
"aria-labelledby": titleId,
|
|
1429
1327
|
className: "flex flex-col gap-3",
|
|
1430
1328
|
children: [
|
|
1431
|
-
/* @__PURE__ */
|
|
1432
|
-
/* @__PURE__ */
|
|
1433
|
-
/* @__PURE__ */
|
|
1329
|
+
/* @__PURE__ */ jsxs19("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
|
|
1330
|
+
/* @__PURE__ */ jsxs19("div", { className: "min-w-0", children: [
|
|
1331
|
+
/* @__PURE__ */ jsx29("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ jsxs19(
|
|
1434
1332
|
"button",
|
|
1435
1333
|
{
|
|
1436
1334
|
type: "button",
|
|
@@ -1439,31 +1337,34 @@ function ReportFeature({ feature }) {
|
|
|
1439
1337
|
"aria-controls": bodyId,
|
|
1440
1338
|
className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
|
|
1441
1339
|
children: [
|
|
1442
|
-
/* @__PURE__ */
|
|
1443
|
-
/* @__PURE__ */
|
|
1340
|
+
/* @__PURE__ */ jsx29("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
|
|
1341
|
+
/* @__PURE__ */ jsx29("span", { className: "truncate", children: feature.title })
|
|
1444
1342
|
]
|
|
1445
1343
|
}
|
|
1446
1344
|
) : feature.title }),
|
|
1447
|
-
/* @__PURE__ */
|
|
1345
|
+
/* @__PURE__ */ jsxs19("p", { className: cn("mt-0.5 flex items-center gap-2 text-xs text-muted-foreground", collapse && "pl-5"), children: [
|
|
1346
|
+
kindLabel ? /* @__PURE__ */ jsx29("span", { className: "shrink-0 rounded-sm bg-muted px-1.5 py-0.5 font-medium text-foreground", children: kindLabel }) : null,
|
|
1347
|
+
/* @__PURE__ */ jsx29("span", { className: "truncate font-mono", children: feature.sourceFile })
|
|
1348
|
+
] })
|
|
1448
1349
|
] }),
|
|
1449
|
-
/* @__PURE__ */
|
|
1350
|
+
/* @__PURE__ */ jsxs19(
|
|
1450
1351
|
"p",
|
|
1451
1352
|
{
|
|
1452
1353
|
className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
|
|
1453
1354
|
"aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
|
|
1454
1355
|
children: [
|
|
1455
|
-
/* @__PURE__ */
|
|
1356
|
+
/* @__PURE__ */ jsxs19("span", { children: [
|
|
1456
1357
|
s.passed,
|
|
1457
1358
|
" passed"
|
|
1458
1359
|
] }),
|
|
1459
|
-
/* @__PURE__ */
|
|
1460
|
-
/* @__PURE__ */
|
|
1360
|
+
/* @__PURE__ */ jsx29("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1361
|
+
/* @__PURE__ */ jsxs19("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
|
|
1461
1362
|
s.failed,
|
|
1462
1363
|
" failed"
|
|
1463
1364
|
] }),
|
|
1464
|
-
skipped > 0 ? /* @__PURE__ */
|
|
1465
|
-
/* @__PURE__ */
|
|
1466
|
-
/* @__PURE__ */
|
|
1365
|
+
skipped > 0 ? /* @__PURE__ */ jsxs19(Fragment9, { children: [
|
|
1366
|
+
/* @__PURE__ */ jsx29("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1367
|
+
/* @__PURE__ */ jsxs19("span", { children: [
|
|
1467
1368
|
skipped,
|
|
1468
1369
|
" skipped"
|
|
1469
1370
|
] })
|
|
@@ -1472,7 +1373,10 @@ function ReportFeature({ feature }) {
|
|
|
1472
1373
|
}
|
|
1473
1374
|
)
|
|
1474
1375
|
] }),
|
|
1475
|
-
/* @__PURE__ */
|
|
1376
|
+
/* @__PURE__ */ jsxs19("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: [
|
|
1377
|
+
/* @__PURE__ */ jsx29(ReportFeatureIntro, { feature }),
|
|
1378
|
+
/* @__PURE__ */ jsx29(ReportScenarioList, { feature })
|
|
1379
|
+
] })
|
|
1476
1380
|
]
|
|
1477
1381
|
}
|
|
1478
1382
|
)
|
|
@@ -1480,17 +1384,17 @@ function ReportFeature({ feature }) {
|
|
|
1480
1384
|
}
|
|
1481
1385
|
|
|
1482
1386
|
// src/components/ReportFeatureList.tsx
|
|
1483
|
-
import { jsx as
|
|
1387
|
+
import { jsx as jsx30 } from "react/jsx-runtime";
|
|
1484
1388
|
function ReportFeatureList() {
|
|
1485
1389
|
const report = useReport();
|
|
1486
|
-
return /* @__PURE__ */
|
|
1390
|
+
return /* @__PURE__ */ jsx30("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ jsx30(ReportFeature, { feature }, feature.id)) });
|
|
1487
1391
|
}
|
|
1488
1392
|
|
|
1489
1393
|
// src/components/ui/empty.tsx
|
|
1490
1394
|
import { cva as cva2 } from "class-variance-authority";
|
|
1491
|
-
import { jsx as
|
|
1395
|
+
import { jsx as jsx31 } from "react/jsx-runtime";
|
|
1492
1396
|
function Empty({ className, ...props }) {
|
|
1493
|
-
return /* @__PURE__ */
|
|
1397
|
+
return /* @__PURE__ */ jsx31(
|
|
1494
1398
|
"div",
|
|
1495
1399
|
{
|
|
1496
1400
|
"data-slot": "empty",
|
|
@@ -1503,7 +1407,7 @@ function Empty({ className, ...props }) {
|
|
|
1503
1407
|
);
|
|
1504
1408
|
}
|
|
1505
1409
|
function EmptyHeader({ className, ...props }) {
|
|
1506
|
-
return /* @__PURE__ */
|
|
1410
|
+
return /* @__PURE__ */ jsx31(
|
|
1507
1411
|
"div",
|
|
1508
1412
|
{
|
|
1509
1413
|
"data-slot": "empty-header",
|
|
@@ -1530,7 +1434,7 @@ var emptyMediaVariants = cva2(
|
|
|
1530
1434
|
}
|
|
1531
1435
|
);
|
|
1532
1436
|
function EmptyTitle({ className, ...props }) {
|
|
1533
|
-
return /* @__PURE__ */
|
|
1437
|
+
return /* @__PURE__ */ jsx31(
|
|
1534
1438
|
"div",
|
|
1535
1439
|
{
|
|
1536
1440
|
"data-slot": "empty-title",
|
|
@@ -1541,16 +1445,16 @@ function EmptyTitle({ className, ...props }) {
|
|
|
1541
1445
|
}
|
|
1542
1446
|
|
|
1543
1447
|
// src/components/ReportEmpty.tsx
|
|
1544
|
-
import { jsx as
|
|
1448
|
+
import { jsx as jsx32 } from "react/jsx-runtime";
|
|
1545
1449
|
function ReportEmpty({ message }) {
|
|
1546
|
-
return /* @__PURE__ */
|
|
1450
|
+
return /* @__PURE__ */ jsx32(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ jsx32(EmptyHeader, { children: /* @__PURE__ */ jsx32(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
|
|
1547
1451
|
}
|
|
1548
1452
|
|
|
1549
1453
|
// src/components/ReportSummary.tsx
|
|
1550
|
-
import { jsx as
|
|
1454
|
+
import { jsx as jsx33, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1551
1455
|
function ReportSummary({ className }) {
|
|
1552
1456
|
const report = useReport();
|
|
1553
|
-
return /* @__PURE__ */
|
|
1457
|
+
return /* @__PURE__ */ jsx33(
|
|
1554
1458
|
ReportSummaryView,
|
|
1555
1459
|
{
|
|
1556
1460
|
summary: report.summary,
|
|
@@ -1576,7 +1480,7 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1576
1480
|
if (summary.pending > 0) {
|
|
1577
1481
|
cards.push({ status: "pending", label: "Pending", value: summary.pending });
|
|
1578
1482
|
}
|
|
1579
|
-
return /* @__PURE__ */
|
|
1483
|
+
return /* @__PURE__ */ jsx33(
|
|
1580
1484
|
"dl",
|
|
1581
1485
|
{
|
|
1582
1486
|
className: cn(
|
|
@@ -1589,17 +1493,17 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1589
1493
|
"aria-label": ariaLabel,
|
|
1590
1494
|
children: cards.map((c) => {
|
|
1591
1495
|
const tone = TONE[c.status];
|
|
1592
|
-
return /* @__PURE__ */
|
|
1496
|
+
return /* @__PURE__ */ jsxs20(
|
|
1593
1497
|
"div",
|
|
1594
1498
|
{
|
|
1595
1499
|
"data-status": c.status,
|
|
1596
1500
|
className: "rounded-lg border bg-card px-4 py-3",
|
|
1597
1501
|
children: [
|
|
1598
|
-
/* @__PURE__ */
|
|
1599
|
-
/* @__PURE__ */
|
|
1502
|
+
/* @__PURE__ */ jsxs20("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
|
|
1503
|
+
/* @__PURE__ */ jsx33("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
|
|
1600
1504
|
c.label
|
|
1601
1505
|
] }),
|
|
1602
|
-
/* @__PURE__ */
|
|
1506
|
+
/* @__PURE__ */ jsx33("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
|
|
1603
1507
|
]
|
|
1604
1508
|
},
|
|
1605
1509
|
c.status
|
|
@@ -1609,6 +1513,9 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1609
1513
|
);
|
|
1610
1514
|
}
|
|
1611
1515
|
|
|
1516
|
+
// src/components/ReportMeta.tsx
|
|
1517
|
+
import { formatDuration as formatDuration4 } from "executable-stories-core/utils/duration";
|
|
1518
|
+
|
|
1612
1519
|
// src/lib/provenance.ts
|
|
1613
1520
|
function reportLastRunMs(report) {
|
|
1614
1521
|
if (report.finishedAtMs && report.finishedAtMs > 0) return report.finishedAtMs;
|
|
@@ -1659,7 +1566,7 @@ function prUrl(ci) {
|
|
|
1659
1566
|
}
|
|
1660
1567
|
|
|
1661
1568
|
// src/components/ReportMeta.tsx
|
|
1662
|
-
import { jsx as
|
|
1569
|
+
import { jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1663
1570
|
function ReportMeta() {
|
|
1664
1571
|
const report = useReport();
|
|
1665
1572
|
const items = [];
|
|
@@ -1668,7 +1575,7 @@ function ReportMeta() {
|
|
|
1668
1575
|
items.push({ label: "Started", value: new Date(report.startedAtMs).toLocaleString() });
|
|
1669
1576
|
}
|
|
1670
1577
|
if (report.durationMs) {
|
|
1671
|
-
items.push({ label: "Duration", value:
|
|
1578
|
+
items.push({ label: "Duration", value: formatDuration4(report.durationMs) });
|
|
1672
1579
|
}
|
|
1673
1580
|
if (report.packageVersion) {
|
|
1674
1581
|
items.push({ label: "Version", value: report.packageVersion });
|
|
@@ -1682,13 +1589,13 @@ function ReportMeta() {
|
|
|
1682
1589
|
const short = sha.slice(0, 8);
|
|
1683
1590
|
items.push({
|
|
1684
1591
|
label: "Commit",
|
|
1685
|
-
value: url ? /* @__PURE__ */
|
|
1592
|
+
value: url ? /* @__PURE__ */ jsx34("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
|
|
1686
1593
|
});
|
|
1687
1594
|
}
|
|
1688
1595
|
if (report.ci) {
|
|
1689
1596
|
items.push({
|
|
1690
1597
|
label: "CI",
|
|
1691
|
-
value: report.ci.url ? /* @__PURE__ */
|
|
1598
|
+
value: report.ci.url ? /* @__PURE__ */ jsxs21("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
|
|
1692
1599
|
ciDisplayName(report.ci.name),
|
|
1693
1600
|
report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
|
|
1694
1601
|
] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
|
|
@@ -1699,7 +1606,7 @@ function ReportMeta() {
|
|
|
1699
1606
|
const label = `#${report.ci.prNumber}`;
|
|
1700
1607
|
items.push({
|
|
1701
1608
|
label: "PR",
|
|
1702
|
-
value: url ? /* @__PURE__ */
|
|
1609
|
+
value: url ? /* @__PURE__ */ jsx34("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
|
|
1703
1610
|
});
|
|
1704
1611
|
}
|
|
1705
1612
|
if (items.length === 0) return null;
|
|
@@ -1707,48 +1614,48 @@ function ReportMeta() {
|
|
|
1707
1614
|
// Run metadata is useful but secondary to "what failed" — tuck it into a
|
|
1708
1615
|
// collapsed disclosure so it doesn't push the result down. Native <details>
|
|
1709
1616
|
// so it works with no JS (the SSR/no-hydration report still toggles).
|
|
1710
|
-
/* @__PURE__ */
|
|
1711
|
-
/* @__PURE__ */
|
|
1712
|
-
/* @__PURE__ */
|
|
1617
|
+
/* @__PURE__ */ jsxs21("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
|
|
1618
|
+
/* @__PURE__ */ jsxs21("summary", { className: "flex cursor-pointer list-none select-none items-center gap-1.5 px-4 py-2 font-medium text-muted-foreground [&::-webkit-details-marker]:hidden", children: [
|
|
1619
|
+
/* @__PURE__ */ jsx34("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
|
|
1713
1620
|
"Run details"
|
|
1714
1621
|
] }),
|
|
1715
|
-
/* @__PURE__ */
|
|
1716
|
-
/* @__PURE__ */
|
|
1717
|
-
/* @__PURE__ */
|
|
1622
|
+
/* @__PURE__ */ jsx34("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__ */ jsxs21("div", { className: "flex items-baseline gap-1.5", children: [
|
|
1623
|
+
/* @__PURE__ */ jsx34("dt", { className: "font-medium", children: item.label }),
|
|
1624
|
+
/* @__PURE__ */ jsx34("dd", { className: "font-mono text-foreground", children: item.value })
|
|
1718
1625
|
] }, item.label)) })
|
|
1719
1626
|
] })
|
|
1720
1627
|
);
|
|
1721
1628
|
}
|
|
1722
1629
|
|
|
1723
1630
|
// src/components/ReportSchemaError.tsx
|
|
1724
|
-
import { jsx as
|
|
1631
|
+
import { jsx as jsx35, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1725
1632
|
function ReportSchemaError({ error }) {
|
|
1726
|
-
return /* @__PURE__ */
|
|
1727
|
-
/* @__PURE__ */
|
|
1728
|
-
/* @__PURE__ */
|
|
1729
|
-
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */
|
|
1633
|
+
return /* @__PURE__ */ jsxs22("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
|
|
1634
|
+
/* @__PURE__ */ jsx35("p", { children: /* @__PURE__ */ jsx35("strong", { children: "Report could not be displayed." }) }),
|
|
1635
|
+
/* @__PURE__ */ jsx35("p", { children: error.message }),
|
|
1636
|
+
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ jsxs22("p", { children: [
|
|
1730
1637
|
"The report bundle is newer than this version of ",
|
|
1731
|
-
/* @__PURE__ */
|
|
1638
|
+
/* @__PURE__ */ jsx35("code", { children: "executable-stories-react" }),
|
|
1732
1639
|
". Upgrade the package, or regenerate the report with an older formatters CLI."
|
|
1733
1640
|
] }) : null,
|
|
1734
|
-
error.issues && error.issues.length > 0 ? /* @__PURE__ */
|
|
1735
|
-
/* @__PURE__ */
|
|
1641
|
+
error.issues && error.issues.length > 0 ? /* @__PURE__ */ jsxs22("details", { children: [
|
|
1642
|
+
/* @__PURE__ */ jsxs22("summary", { children: [
|
|
1736
1643
|
error.issues.length,
|
|
1737
1644
|
" validation issue",
|
|
1738
1645
|
error.issues.length === 1 ? "" : "s"
|
|
1739
1646
|
] }),
|
|
1740
|
-
/* @__PURE__ */
|
|
1647
|
+
/* @__PURE__ */ jsx35("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
|
|
1741
1648
|
] }) : null
|
|
1742
1649
|
] });
|
|
1743
1650
|
}
|
|
1744
1651
|
|
|
1745
1652
|
// src/components/ReportShell.tsx
|
|
1746
|
-
import { Fragment as Fragment10, jsx as
|
|
1653
|
+
import { Fragment as Fragment10, jsx as jsx36, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1747
1654
|
function ReportTitleBlock({ title }) {
|
|
1748
|
-
return /* @__PURE__ */
|
|
1749
|
-
/* @__PURE__ */
|
|
1750
|
-
/* @__PURE__ */
|
|
1751
|
-
/* @__PURE__ */
|
|
1655
|
+
return /* @__PURE__ */ jsxs23(Fragment10, { children: [
|
|
1656
|
+
/* @__PURE__ */ jsx36("h1", { children: title ?? "Story Report" }),
|
|
1657
|
+
/* @__PURE__ */ jsx36(ReportSummary, {}),
|
|
1658
|
+
/* @__PURE__ */ jsx36(ReportMeta, {})
|
|
1752
1659
|
] });
|
|
1753
1660
|
}
|
|
1754
1661
|
function ReportErrorShell({
|
|
@@ -1757,28 +1664,28 @@ function ReportErrorShell({
|
|
|
1757
1664
|
title,
|
|
1758
1665
|
dataTheme
|
|
1759
1666
|
}) {
|
|
1760
|
-
return /* @__PURE__ */
|
|
1667
|
+
return /* @__PURE__ */ jsx36("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ jsx36(ReportSchemaError, { error }) });
|
|
1761
1668
|
}
|
|
1762
1669
|
|
|
1763
1670
|
// src/components/Report.tsx
|
|
1764
|
-
import { jsx as
|
|
1671
|
+
import { jsx as jsx37, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
1765
1672
|
function Report(props) {
|
|
1766
1673
|
const { report, customRenderers, renderers, className, title, dataTheme } = props;
|
|
1767
1674
|
const result = unwrapReport(report);
|
|
1768
1675
|
if (!result.ok) {
|
|
1769
|
-
return /* @__PURE__ */
|
|
1676
|
+
return /* @__PURE__ */ jsx37(ReportErrorShell, { error: result.error, className, title, dataTheme });
|
|
1770
1677
|
}
|
|
1771
1678
|
const data = result.data;
|
|
1772
1679
|
const hasContent = data.features.length > 0;
|
|
1773
|
-
return /* @__PURE__ */
|
|
1774
|
-
/* @__PURE__ */
|
|
1775
|
-
hasContent ? /* @__PURE__ */
|
|
1680
|
+
return /* @__PURE__ */ jsx37(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ jsxs24("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
|
|
1681
|
+
/* @__PURE__ */ jsx37("header", { className: "es-report-header", children: /* @__PURE__ */ jsx37(ReportTitleBlock, { title }) }),
|
|
1682
|
+
hasContent ? /* @__PURE__ */ jsx37(ReportFeatureList, {}) : /* @__PURE__ */ jsx37(ReportEmpty, {})
|
|
1776
1683
|
] }) });
|
|
1777
1684
|
}
|
|
1778
1685
|
|
|
1779
1686
|
// src/components/doc/MermaidView.tsx
|
|
1780
1687
|
import { useEffect, useRef, useState as useState2 } from "react";
|
|
1781
|
-
import { Fragment as Fragment11, jsx as
|
|
1688
|
+
import { Fragment as Fragment11, jsx as jsx38, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
1782
1689
|
function prefersDark(el) {
|
|
1783
1690
|
const themed = el?.closest("[data-theme]");
|
|
1784
1691
|
if (themed?.dataset.theme === "dark") return true;
|
|
@@ -1832,9 +1739,9 @@ function MermaidView({ entry, load }) {
|
|
|
1832
1739
|
};
|
|
1833
1740
|
}, [entry.code, load]);
|
|
1834
1741
|
if (svg) {
|
|
1835
|
-
return /* @__PURE__ */
|
|
1836
|
-
entry.title ? /* @__PURE__ */
|
|
1837
|
-
/* @__PURE__ */
|
|
1742
|
+
return /* @__PURE__ */ jsxs25("figure", { ref, className: "my-3", children: [
|
|
1743
|
+
entry.title ? /* @__PURE__ */ jsx38("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
|
|
1744
|
+
/* @__PURE__ */ jsx38(
|
|
1838
1745
|
"div",
|
|
1839
1746
|
{
|
|
1840
1747
|
role: "img",
|
|
@@ -1845,8 +1752,8 @@ function MermaidView({ entry, load }) {
|
|
|
1845
1752
|
)
|
|
1846
1753
|
] });
|
|
1847
1754
|
}
|
|
1848
|
-
return /* @__PURE__ */
|
|
1849
|
-
error ? /* @__PURE__ */
|
|
1755
|
+
return /* @__PURE__ */ jsxs25(Fragment11, { children: [
|
|
1756
|
+
error ? /* @__PURE__ */ jsxs25(
|
|
1850
1757
|
"p",
|
|
1851
1758
|
{
|
|
1852
1759
|
role: "alert",
|
|
@@ -1858,19 +1765,19 @@ function MermaidView({ entry, load }) {
|
|
|
1858
1765
|
]
|
|
1859
1766
|
}
|
|
1860
1767
|
) : null,
|
|
1861
|
-
/* @__PURE__ */
|
|
1768
|
+
/* @__PURE__ */ jsx38(MermaidSource, { entry, ref })
|
|
1862
1769
|
] });
|
|
1863
1770
|
}
|
|
1864
1771
|
|
|
1865
1772
|
// src/components/doc/MermaidDiagram.tsx
|
|
1866
|
-
import { jsx as
|
|
1773
|
+
import { jsx as jsx39 } from "react/jsx-runtime";
|
|
1867
1774
|
var mermaidLoader;
|
|
1868
1775
|
function loadMermaid() {
|
|
1869
1776
|
mermaidLoader ??= import("mermaid").then((m) => m.default);
|
|
1870
1777
|
return mermaidLoader;
|
|
1871
1778
|
}
|
|
1872
1779
|
function MermaidDiagram({ entry, load = loadMermaid }) {
|
|
1873
|
-
return /* @__PURE__ */
|
|
1780
|
+
return /* @__PURE__ */ jsx39(MermaidView, { entry, load });
|
|
1874
1781
|
}
|
|
1875
1782
|
|
|
1876
1783
|
// src/components/ScenarioExplorer.tsx
|
|
@@ -1880,12 +1787,12 @@ import { useState as useState3 } from "react";
|
|
|
1880
1787
|
import "react";
|
|
1881
1788
|
import { Command as CommandPrimitive } from "cmdk";
|
|
1882
1789
|
import { SearchIcon } from "lucide-react";
|
|
1883
|
-
import { jsx as
|
|
1790
|
+
import { jsx as jsx40, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
1884
1791
|
function Command({
|
|
1885
1792
|
className,
|
|
1886
1793
|
...props
|
|
1887
1794
|
}) {
|
|
1888
|
-
return /* @__PURE__ */
|
|
1795
|
+
return /* @__PURE__ */ jsx40(
|
|
1889
1796
|
CommandPrimitive,
|
|
1890
1797
|
{
|
|
1891
1798
|
"data-slot": "command",
|
|
@@ -1901,14 +1808,14 @@ function CommandInput({
|
|
|
1901
1808
|
className,
|
|
1902
1809
|
...props
|
|
1903
1810
|
}) {
|
|
1904
|
-
return /* @__PURE__ */
|
|
1811
|
+
return /* @__PURE__ */ jsxs26(
|
|
1905
1812
|
"div",
|
|
1906
1813
|
{
|
|
1907
1814
|
"data-slot": "command-input-wrapper",
|
|
1908
1815
|
className: "flex h-9 items-center gap-2 border-b px-3",
|
|
1909
1816
|
children: [
|
|
1910
|
-
/* @__PURE__ */
|
|
1911
|
-
/* @__PURE__ */
|
|
1817
|
+
/* @__PURE__ */ jsx40(SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
|
|
1818
|
+
/* @__PURE__ */ jsx40(
|
|
1912
1819
|
CommandPrimitive.Input,
|
|
1913
1820
|
{
|
|
1914
1821
|
"data-slot": "command-input",
|
|
@@ -1927,7 +1834,7 @@ function CommandList({
|
|
|
1927
1834
|
className,
|
|
1928
1835
|
...props
|
|
1929
1836
|
}) {
|
|
1930
|
-
return /* @__PURE__ */
|
|
1837
|
+
return /* @__PURE__ */ jsx40(
|
|
1931
1838
|
CommandPrimitive.List,
|
|
1932
1839
|
{
|
|
1933
1840
|
"data-slot": "command-list",
|
|
@@ -1942,7 +1849,7 @@ function CommandList({
|
|
|
1942
1849
|
function CommandEmpty({
|
|
1943
1850
|
...props
|
|
1944
1851
|
}) {
|
|
1945
|
-
return /* @__PURE__ */
|
|
1852
|
+
return /* @__PURE__ */ jsx40(
|
|
1946
1853
|
CommandPrimitive.Empty,
|
|
1947
1854
|
{
|
|
1948
1855
|
"data-slot": "command-empty",
|
|
@@ -1955,7 +1862,7 @@ function CommandGroup({
|
|
|
1955
1862
|
className,
|
|
1956
1863
|
...props
|
|
1957
1864
|
}) {
|
|
1958
|
-
return /* @__PURE__ */
|
|
1865
|
+
return /* @__PURE__ */ jsx40(
|
|
1959
1866
|
CommandPrimitive.Group,
|
|
1960
1867
|
{
|
|
1961
1868
|
"data-slot": "command-group",
|
|
@@ -1971,7 +1878,7 @@ function CommandItem({
|
|
|
1971
1878
|
className,
|
|
1972
1879
|
...props
|
|
1973
1880
|
}) {
|
|
1974
|
-
return /* @__PURE__ */
|
|
1881
|
+
return /* @__PURE__ */ jsx40(
|
|
1975
1882
|
CommandPrimitive.Item,
|
|
1976
1883
|
{
|
|
1977
1884
|
"data-slot": "command-item",
|
|
@@ -1985,7 +1892,7 @@ function CommandItem({
|
|
|
1985
1892
|
}
|
|
1986
1893
|
|
|
1987
1894
|
// src/components/ScenarioExplorer.tsx
|
|
1988
|
-
import { jsx as
|
|
1895
|
+
import { jsx as jsx41, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
1989
1896
|
var STATUS_FILTERS = [
|
|
1990
1897
|
{ value: "all", label: "All" },
|
|
1991
1898
|
{ value: "passed", label: "Passed" },
|
|
@@ -1996,22 +1903,22 @@ var STATUS_FILTERS = [
|
|
|
1996
1903
|
function ScenarioExplorer({ scenarios, summary }) {
|
|
1997
1904
|
const [status, setStatus] = useState3("all");
|
|
1998
1905
|
const visible = status === "all" ? scenarios : scenarios.filter((s) => s.status === status);
|
|
1999
|
-
return /* @__PURE__ */
|
|
2000
|
-
summary ? /* @__PURE__ */
|
|
1906
|
+
return /* @__PURE__ */ jsxs27("div", { className: "font-sans text-foreground", children: [
|
|
1907
|
+
summary ? /* @__PURE__ */ jsxs27("p", { className: "mb-3 text-sm text-muted-foreground", children: [
|
|
2001
1908
|
summary.total,
|
|
2002
1909
|
" scenarios \xB7 ",
|
|
2003
|
-
/* @__PURE__ */
|
|
1910
|
+
/* @__PURE__ */ jsxs27("span", { className: "text-pass", children: [
|
|
2004
1911
|
summary.passed,
|
|
2005
1912
|
" passed"
|
|
2006
1913
|
] }),
|
|
2007
1914
|
" \xB7",
|
|
2008
1915
|
" ",
|
|
2009
|
-
/* @__PURE__ */
|
|
1916
|
+
/* @__PURE__ */ jsxs27("span", { className: "text-fail", children: [
|
|
2010
1917
|
summary.failed,
|
|
2011
1918
|
" failed"
|
|
2012
1919
|
] })
|
|
2013
1920
|
] }) : null,
|
|
2014
|
-
/* @__PURE__ */
|
|
1921
|
+
/* @__PURE__ */ jsx41("div", { className: "mb-2 flex flex-wrap gap-1.5", role: "group", "aria-label": "Filter by status", children: STATUS_FILTERS.map((f) => /* @__PURE__ */ jsx41(
|
|
2015
1922
|
"button",
|
|
2016
1923
|
{
|
|
2017
1924
|
type: "button",
|
|
@@ -2026,26 +1933,26 @@ function ScenarioExplorer({ scenarios, summary }) {
|
|
|
2026
1933
|
},
|
|
2027
1934
|
f.value
|
|
2028
1935
|
)) }),
|
|
2029
|
-
/* @__PURE__ */
|
|
1936
|
+
/* @__PURE__ */ jsxs27(
|
|
2030
1937
|
Command,
|
|
2031
1938
|
{
|
|
2032
1939
|
className: "rounded-lg border border-border bg-card",
|
|
2033
1940
|
filter: (value, search) => value.toLowerCase().includes(search.toLowerCase()) ? 1 : 0,
|
|
2034
1941
|
children: [
|
|
2035
|
-
/* @__PURE__ */
|
|
2036
|
-
/* @__PURE__ */
|
|
2037
|
-
/* @__PURE__ */
|
|
2038
|
-
/* @__PURE__ */
|
|
1942
|
+
/* @__PURE__ */ jsx41(CommandInput, { placeholder: "Search scenarios\u2026" }),
|
|
1943
|
+
/* @__PURE__ */ jsxs27(CommandList, { className: "max-h-none", children: [
|
|
1944
|
+
/* @__PURE__ */ jsx41(CommandEmpty, { children: "No scenarios match your filters." }),
|
|
1945
|
+
/* @__PURE__ */ jsx41(CommandGroup, { children: visible.map((s) => /* @__PURE__ */ jsx41(
|
|
2039
1946
|
CommandItem,
|
|
2040
1947
|
{
|
|
2041
1948
|
value: `${s.title} ${s.feature} ${s.tags.join(" ")}`,
|
|
2042
1949
|
asChild: true,
|
|
2043
1950
|
className: "cursor-pointer",
|
|
2044
|
-
children: /* @__PURE__ */
|
|
2045
|
-
/* @__PURE__ */
|
|
2046
|
-
/* @__PURE__ */
|
|
2047
|
-
s.tags.slice(0, 3).map((t) => /* @__PURE__ */
|
|
2048
|
-
/* @__PURE__ */
|
|
1951
|
+
children: /* @__PURE__ */ jsxs27("a", { href: s.href, className: "flex items-center gap-3", children: [
|
|
1952
|
+
/* @__PURE__ */ jsx41(Badge, { variant: s.status, children: s.status }),
|
|
1953
|
+
/* @__PURE__ */ jsx41("span", { className: "min-w-0 flex-1 truncate font-medium", children: s.title }),
|
|
1954
|
+
s.tags.slice(0, 3).map((t) => /* @__PURE__ */ jsx41(Badge, { variant: "tag", className: "hidden sm:inline-flex", children: t }, t)),
|
|
1955
|
+
/* @__PURE__ */ jsx41("code", { className: "hidden font-mono text-xs text-muted-foreground md:inline", children: s.feature })
|
|
2049
1956
|
] })
|
|
2050
1957
|
},
|
|
2051
1958
|
s.id
|
|
@@ -2192,7 +2099,7 @@ var story_report_v1_default = {
|
|
|
2192
2099
|
title: {
|
|
2193
2100
|
type: "string",
|
|
2194
2101
|
minLength: 1,
|
|
2195
|
-
description: "Display title.
|
|
2102
|
+
description: "Display title. Comes from story.feature(...) when declared, otherwise the describe block or file basename."
|
|
2196
2103
|
},
|
|
2197
2104
|
sourceFile: {
|
|
2198
2105
|
type: "string",
|
|
@@ -2208,6 +2115,26 @@ var story_report_v1_default = {
|
|
|
2208
2115
|
$ref: "#/$defs/Scenario"
|
|
2209
2116
|
},
|
|
2210
2117
|
description: "Scenarios in this feature, in declaration order."
|
|
2118
|
+
},
|
|
2119
|
+
kind: {
|
|
2120
|
+
type: "string",
|
|
2121
|
+
enum: [
|
|
2122
|
+
"feature",
|
|
2123
|
+
"ability",
|
|
2124
|
+
"business-need"
|
|
2125
|
+
],
|
|
2126
|
+
description: "How the feature was declared. Absent when the title was derived rather than declared."
|
|
2127
|
+
},
|
|
2128
|
+
narrative: {
|
|
2129
|
+
type: "string",
|
|
2130
|
+
description: "Markdown explaining why the feature exists and who it serves."
|
|
2131
|
+
},
|
|
2132
|
+
glossary: {
|
|
2133
|
+
type: "array",
|
|
2134
|
+
items: {
|
|
2135
|
+
$ref: "#/$defs/GlossaryTerm"
|
|
2136
|
+
},
|
|
2137
|
+
description: "Terms this feature defines, linked wherever they appear in scenario text."
|
|
2211
2138
|
}
|
|
2212
2139
|
},
|
|
2213
2140
|
required: [
|
|
@@ -3019,6 +2946,25 @@ var story_report_v1_default = {
|
|
|
3019
2946
|
}
|
|
3020
2947
|
},
|
|
3021
2948
|
additionalProperties: false
|
|
2949
|
+
},
|
|
2950
|
+
GlossaryTerm: {
|
|
2951
|
+
type: "object",
|
|
2952
|
+
description: "One glossary entry: a term the scenarios use and what it means.",
|
|
2953
|
+
properties: {
|
|
2954
|
+
term: {
|
|
2955
|
+
type: "string",
|
|
2956
|
+
minLength: 1
|
|
2957
|
+
},
|
|
2958
|
+
definition: {
|
|
2959
|
+
type: "string",
|
|
2960
|
+
minLength: 1
|
|
2961
|
+
}
|
|
2962
|
+
},
|
|
2963
|
+
required: [
|
|
2964
|
+
"term",
|
|
2965
|
+
"definition"
|
|
2966
|
+
],
|
|
2967
|
+
additionalProperties: false
|
|
3022
2968
|
}
|
|
3023
2969
|
}
|
|
3024
2970
|
};
|