executable-stories-react 0.10.0 → 0.10.1
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 +35 -170
- 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 +26 -161
- package/dist/index.js.map +1 -1
- package/dist/interactive.cjs +39 -291
- 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 +30 -282
- package/dist/interactive.js.map +1 -1
- package/dist/parse.d.cts +3 -234
- package/dist/parse.d.ts +3 -234
- package/dist/ssr.cjs +35 -170
- 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 +26 -161
- package/dist/ssr.js.map +1 -1
- package/package.json +4 -4
package/dist/interactive.cjs
CHANGED
|
@@ -334,23 +334,11 @@ function useReport() {
|
|
|
334
334
|
return ctx.report;
|
|
335
335
|
}
|
|
336
336
|
|
|
337
|
-
//
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
if (ms < 6e4) {
|
|
343
|
-
return `${(ms / 1e3).toFixed(2)} s`;
|
|
344
|
-
}
|
|
345
|
-
const minutes = Math.floor(ms / 6e4);
|
|
346
|
-
const seconds = Math.floor(ms % 6e4 / 1e3);
|
|
347
|
-
if (minutes < 60) {
|
|
348
|
-
return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
|
|
349
|
-
}
|
|
350
|
-
const hours = Math.floor(minutes / 60);
|
|
351
|
-
const remainingMinutes = minutes % 60;
|
|
352
|
-
return `${hours}h ${remainingMinutes}m`;
|
|
353
|
-
}
|
|
337
|
+
// src/components/ReportScenario.tsx
|
|
338
|
+
var import_duration3 = require("executable-stories-core/utils/duration");
|
|
339
|
+
|
|
340
|
+
// src/components/ReportSteps.tsx
|
|
341
|
+
var import_duration = require("executable-stories-core/utils/duration");
|
|
354
342
|
|
|
355
343
|
// src/components/doc/DocNote.tsx
|
|
356
344
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
@@ -419,7 +407,7 @@ function DocTable({ entry }) {
|
|
|
419
407
|
entry.label ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.label }) : null,
|
|
420
408
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { tabIndex: 0, className: "overflow-x-auto rounded-md border border-border", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("table", { className: "w-full border-collapse text-sm", children: [
|
|
421
409
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tr", { className: "bg-muted/50", children: entry.columns.map((c) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("th", { scope: "col", className: "border-b border-border px-3 py-2 text-left font-semibold", children: c }, c)) }) }),
|
|
422
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tbody", { children: entry.rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tr", { children: row.map((
|
|
410
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tbody", { children: entry.rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tr", { children: row.map((cell, j) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("td", { className: "border-b border-border px-3 py-2 text-foreground", children: cell }, j)) }, i)) })
|
|
423
411
|
] }) })
|
|
424
412
|
] });
|
|
425
413
|
}
|
|
@@ -442,28 +430,13 @@ function DocLink({ entry }) {
|
|
|
442
430
|
// src/components/doc/DocSection.tsx
|
|
443
431
|
var import_marked = require("marked");
|
|
444
432
|
|
|
445
|
-
//
|
|
446
|
-
|
|
447
|
-
if (!value) return void 0;
|
|
448
|
-
const trimmed = value.trim();
|
|
449
|
-
const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(trimmed);
|
|
450
|
-
if (scheme && !/^https?$/i.test(scheme[1] ?? "")) return void 0;
|
|
451
|
-
return trimmed;
|
|
452
|
-
}
|
|
453
|
-
function safeImageUrl(value) {
|
|
454
|
-
if (!value) return void 0;
|
|
455
|
-
const trimmed = value.trim();
|
|
456
|
-
if (/^data:image\//i.test(trimmed)) return trimmed;
|
|
457
|
-
return safeUrl(trimmed);
|
|
458
|
-
}
|
|
459
|
-
function isLocalFsPath(value) {
|
|
460
|
-
return /^(?:[/\\]|[A-Za-z]:[/\\])/.test(value);
|
|
461
|
-
}
|
|
433
|
+
// src/lib/url.ts
|
|
434
|
+
var import_url = require("executable-stories-core/utils/url");
|
|
462
435
|
|
|
463
436
|
// src/components/doc/DocSection.tsx
|
|
464
437
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
465
438
|
function neutralizeUrl(value) {
|
|
466
|
-
return safeUrl(value) ?? "#";
|
|
439
|
+
return (0, import_url.safeUrl)(value) ?? "#";
|
|
467
440
|
}
|
|
468
441
|
function safeMarkdownHtml(markdown) {
|
|
469
442
|
const raw = import_marked.marked.parse(markdown, { async: false });
|
|
@@ -514,7 +487,7 @@ function DocMermaid({ entry }) {
|
|
|
514
487
|
// src/components/doc/DocScreenshot.tsx
|
|
515
488
|
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
516
489
|
function DocScreenshot({ entry }) {
|
|
517
|
-
const src = isLocalFsPath(entry.path) ? void 0 : safeImageUrl(entry.path);
|
|
490
|
+
const src = (0, import_url.isLocalFsPath)(entry.path) ? void 0 : (0, import_url.safeImageUrl)(entry.path);
|
|
518
491
|
if (!src) {
|
|
519
492
|
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
|
|
520
493
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "font-medium", children: "Screenshot unavailable" }),
|
|
@@ -539,15 +512,15 @@ function DocScreenshot({ entry }) {
|
|
|
539
512
|
// src/components/doc/DocVideo.tsx
|
|
540
513
|
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
541
514
|
function DocVideo({ entry }) {
|
|
542
|
-
if (isLocalFsPath(entry.path)) {
|
|
515
|
+
if ((0, import_url.isLocalFsPath)(entry.path)) {
|
|
543
516
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figure", { className: "my-3 rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground", children: [
|
|
544
517
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "font-medium", children: "Video unavailable" }),
|
|
545
518
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "mt-1 break-all font-mono text-xs", children: entry.path }),
|
|
546
519
|
entry.caption ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("figcaption", { className: "mt-1.5 text-xs", children: entry.caption }) : null
|
|
547
520
|
] });
|
|
548
521
|
}
|
|
549
|
-
const src = safeUrl(entry.path);
|
|
550
|
-
const poster = safeUrl(entry.poster);
|
|
522
|
+
const src = (0, import_url.safeUrl)(entry.path);
|
|
523
|
+
const poster = (0, import_url.safeUrl)(entry.poster);
|
|
551
524
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("figure", { className: "my-3", children: [
|
|
552
525
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
553
526
|
"video",
|
|
@@ -568,7 +541,7 @@ var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
|
568
541
|
function DocHtml({ entry }) {
|
|
569
542
|
const height = typeof entry.height === "number" ? `${entry.height}px` : entry.height ?? "400px";
|
|
570
543
|
const title = entry.title ?? "Embedded HTML";
|
|
571
|
-
const safeHref = safeUrl(entry.url ?? entry.path);
|
|
544
|
+
const safeHref = (0, import_url.safeUrl)(entry.url ?? entry.path);
|
|
572
545
|
const frameProps = entry.content !== void 0 ? { srcDoc: entry.content } : { src: safeHref ?? "" };
|
|
573
546
|
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("figure", { className: "my-3 overflow-hidden rounded-md border border-border", children: [
|
|
574
547
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("figcaption", { className: "flex items-center justify-between border-b border-border bg-muted/40 px-3 py-1.5 text-xs font-medium text-muted-foreground", children: [
|
|
@@ -735,7 +708,7 @@ function ReportStepItem({ step }) {
|
|
|
735
708
|
}
|
|
736
709
|
),
|
|
737
710
|
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
|
|
738
|
-
step.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(step.durationMs) }) : null
|
|
711
|
+
step.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: (0, import_duration.formatDuration)(step.durationMs) }) : null
|
|
739
712
|
] }),
|
|
740
713
|
step.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
741
714
|
"pre",
|
|
@@ -751,125 +724,10 @@ function ReportStepItem({ step }) {
|
|
|
751
724
|
);
|
|
752
725
|
}
|
|
753
726
|
|
|
754
|
-
// ../executable-stories-core/dist/state-diff.js
|
|
755
|
-
var isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
756
|
-
function deepEqual(a, b) {
|
|
757
|
-
if (Object.is(a, b)) return true;
|
|
758
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
759
|
-
return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
|
|
760
|
-
}
|
|
761
|
-
if (isPlainObject(a) && isPlainObject(b)) {
|
|
762
|
-
const ak = Object.keys(a);
|
|
763
|
-
const bk = Object.keys(b);
|
|
764
|
-
return ak.length === bk.length && ak.every((k) => k in b && deepEqual(a[k], b[k]));
|
|
765
|
-
}
|
|
766
|
-
return false;
|
|
767
|
-
}
|
|
768
|
-
var joinKey = (path, key) => path === "" ? key : `${path}.${key}`;
|
|
769
|
-
function walk(path, before, after, out) {
|
|
770
|
-
if (Object.is(before, after)) return;
|
|
771
|
-
if (Array.isArray(before) && Array.isArray(after)) {
|
|
772
|
-
const shared = Math.min(before.length, after.length);
|
|
773
|
-
for (let i = 0; i < shared; i++) walk(`${path}[${i}]`, before[i], after[i], out);
|
|
774
|
-
for (let i = shared; i < after.length; i++) out.push({ path: `${path}[${i}]`, kind: "added", after: after[i] });
|
|
775
|
-
for (let i = shared; i < before.length; i++) out.push({ path: `${path}[${i}]`, kind: "removed", before: before[i] });
|
|
776
|
-
return;
|
|
777
|
-
}
|
|
778
|
-
if (isPlainObject(before) && isPlainObject(after)) {
|
|
779
|
-
for (const key of Object.keys(after)) {
|
|
780
|
-
const p = joinKey(path, key);
|
|
781
|
-
if (key in before) walk(p, before[key], after[key], out);
|
|
782
|
-
else out.push({ path: p, kind: "added", after: after[key] });
|
|
783
|
-
}
|
|
784
|
-
for (const key of Object.keys(before)) {
|
|
785
|
-
if (!(key in after)) out.push({ path: joinKey(path, key), kind: "removed", before: before[key] });
|
|
786
|
-
}
|
|
787
|
-
return;
|
|
788
|
-
}
|
|
789
|
-
if (!deepEqual(before, after)) out.push({ path, kind: "changed", before, after });
|
|
790
|
-
}
|
|
791
|
-
function diffStateValues(before, after) {
|
|
792
|
-
const out = [];
|
|
793
|
-
walk("", before, after, out);
|
|
794
|
-
return out;
|
|
795
|
-
}
|
|
796
|
-
function formatStateValue(value, maxLen = 60) {
|
|
797
|
-
const s = value === void 0 ? "undefined" : JSON.stringify(value);
|
|
798
|
-
return s.length > maxLen ? `${s.slice(0, maxLen - 1)}\u2026` : s;
|
|
799
|
-
}
|
|
800
|
-
function summarizeStateChanges(changes) {
|
|
801
|
-
return changes.map((c) => {
|
|
802
|
-
const at = c.path === "" ? "(root)" : c.path;
|
|
803
|
-
switch (c.kind) {
|
|
804
|
-
case "added":
|
|
805
|
-
return `+ ${at}: ${formatStateValue(c.after)}`;
|
|
806
|
-
case "removed":
|
|
807
|
-
return `\u2212 ${at}`;
|
|
808
|
-
case "changed":
|
|
809
|
-
return `${at}: ${formatStateValue(c.before)} \u2192 ${formatStateValue(c.after)}`;
|
|
810
|
-
}
|
|
811
|
-
});
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
// ../executable-stories-core/dist/storyboard.js
|
|
815
|
-
function findScreenshot(entries) {
|
|
816
|
-
for (const entry of entries) {
|
|
817
|
-
if (entry.kind === "screenshot") return entry;
|
|
818
|
-
if (entry.children) {
|
|
819
|
-
const nested = findScreenshot(entry.children);
|
|
820
|
-
if (nested) return nested;
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
return void 0;
|
|
824
|
-
}
|
|
825
|
-
function findStates(entries, out = []) {
|
|
826
|
-
for (const entry of entries) {
|
|
827
|
-
if (entry.kind === "state") out.push(entry);
|
|
828
|
-
if (entry.children) findStates(entry.children, out);
|
|
829
|
-
}
|
|
830
|
-
return out;
|
|
831
|
-
}
|
|
832
|
-
var laneOf = (label) => label ?? "";
|
|
833
|
-
function extractStoryboardFrames(scenario) {
|
|
834
|
-
const frames = [];
|
|
835
|
-
const laneOrder = [];
|
|
836
|
-
const previous = /* @__PURE__ */ new Map();
|
|
837
|
-
for (const step of scenario.steps) {
|
|
838
|
-
const shot = findScreenshot(step.docEntries);
|
|
839
|
-
const stateDocs = findStates(step.docEntries);
|
|
840
|
-
if (!shot && stateDocs.length === 0) continue;
|
|
841
|
-
const byLane = /* @__PURE__ */ new Map();
|
|
842
|
-
for (const doc of stateDocs) {
|
|
843
|
-
const lane = laneOf(doc.label);
|
|
844
|
-
if (!byLane.has(lane) && !laneOrder.includes(lane)) laneOrder.push(lane);
|
|
845
|
-
byLane.set(lane, doc);
|
|
846
|
-
}
|
|
847
|
-
const states = [];
|
|
848
|
-
for (const lane of laneOrder) {
|
|
849
|
-
const doc = byLane.get(lane);
|
|
850
|
-
if (!doc) continue;
|
|
851
|
-
const card = {
|
|
852
|
-
...doc.label !== void 0 && { label: doc.label },
|
|
853
|
-
value: doc.value
|
|
854
|
-
};
|
|
855
|
-
if (previous.has(lane)) card.changes = diffStateValues(previous.get(lane), doc.value);
|
|
856
|
-
previous.set(lane, doc.value);
|
|
857
|
-
states.push(card);
|
|
858
|
-
}
|
|
859
|
-
frames.push({
|
|
860
|
-
stepId: step.id,
|
|
861
|
-
stepIndex: step.index,
|
|
862
|
-
keyword: step.keyword,
|
|
863
|
-
text: step.text,
|
|
864
|
-
status: step.status,
|
|
865
|
-
...shot && { screenshot: { path: shot.path, ...shot.alt !== void 0 && { alt: shot.alt } } },
|
|
866
|
-
states
|
|
867
|
-
});
|
|
868
|
-
}
|
|
869
|
-
return frames;
|
|
870
|
-
}
|
|
871
|
-
|
|
872
727
|
// src/components/ReportStoryboard.tsx
|
|
728
|
+
var import_storyboard = require("executable-stories-core/storyboard");
|
|
729
|
+
var import_state_diff = require("executable-stories-core/state-diff");
|
|
730
|
+
var import_url6 = require("executable-stories-core/utils/url");
|
|
873
731
|
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
874
732
|
var FRAME_GLYPH = {
|
|
875
733
|
passed: "\u2713",
|
|
@@ -884,7 +742,7 @@ var FRAME_GLYPH_COLOR = {
|
|
|
884
742
|
pending: "text-pend"
|
|
885
743
|
};
|
|
886
744
|
function ReportStoryboard({ scenario }) {
|
|
887
|
-
const frames = extractStoryboardFrames(scenario);
|
|
745
|
+
const frames = (0, import_storyboard.extractStoryboardFrames)(scenario);
|
|
888
746
|
if (frames.length < 2) return null;
|
|
889
747
|
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("section", { "data-slot": "storyboard", "aria-label": "Storyboard", className: "mb-3", children: [
|
|
890
748
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h4", { className: "mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Storyboard" }),
|
|
@@ -918,7 +776,7 @@ function StoryboardFrameItem({ frame }) {
|
|
|
918
776
|
}
|
|
919
777
|
function FrameScreenshot({ frame, label }) {
|
|
920
778
|
const path = frame.screenshot?.path ?? "";
|
|
921
|
-
const src = isLocalFsPath(path) ? void 0 : safeImageUrl(path);
|
|
779
|
+
const src = (0, import_url6.isLocalFsPath)(path) ? void 0 : (0, import_url6.safeImageUrl)(path);
|
|
922
780
|
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
923
781
|
"a",
|
|
924
782
|
{
|
|
@@ -964,7 +822,7 @@ function StateCardView({ card }) {
|
|
|
964
822
|
"rounded-sm px-1.5 py-0.5 font-mono text-[0.625rem] leading-snug break-all",
|
|
965
823
|
CHANGE_TONE[change.kind]
|
|
966
824
|
),
|
|
967
|
-
children: summarizeStateChanges([change])[0]
|
|
825
|
+
children: (0, import_state_diff.summarizeStateChanges)([change])[0]
|
|
968
826
|
},
|
|
969
827
|
i
|
|
970
828
|
)) }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "mt-1.5 text-[0.625rem] text-muted-foreground", children: "No changes" })),
|
|
@@ -1024,6 +882,9 @@ function ReportAttachments({ attachments }) {
|
|
|
1024
882
|
);
|
|
1025
883
|
}
|
|
1026
884
|
|
|
885
|
+
// src/components/ReportTrace.tsx
|
|
886
|
+
var import_duration2 = require("executable-stories-core/utils/duration");
|
|
887
|
+
|
|
1027
888
|
// src/lib/trace.ts
|
|
1028
889
|
var VALID = /* @__PURE__ */ new Set(["ok", "error", "unset"]);
|
|
1029
890
|
var safeStatus = (s) => VALID.has(s) ? s : "unset";
|
|
@@ -1076,15 +937,15 @@ function toTraceRows(spans) {
|
|
|
1076
937
|
roots.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);
|
|
1077
938
|
const rows = [];
|
|
1078
939
|
const seen = /* @__PURE__ */ new Set();
|
|
1079
|
-
const
|
|
940
|
+
const walk = (node, depth) => {
|
|
1080
941
|
if (seen.has(node.span.spanId)) return;
|
|
1081
942
|
seen.add(node.span.spanId);
|
|
1082
943
|
rows.push({ ...node.span, depth });
|
|
1083
|
-
for (const child of node.children)
|
|
944
|
+
for (const child of node.children) walk(child, depth + 1);
|
|
1084
945
|
};
|
|
1085
|
-
for (const root of roots)
|
|
946
|
+
for (const root of roots) walk(root, 0);
|
|
1086
947
|
for (const node of byId.values()) {
|
|
1087
|
-
if (!seen.has(node.span.spanId))
|
|
948
|
+
if (!seen.has(node.span.spanId)) walk(node, 0);
|
|
1088
949
|
}
|
|
1089
950
|
return rows;
|
|
1090
951
|
}
|
|
@@ -1118,7 +979,7 @@ function ReportTrace({ spans }) {
|
|
|
1118
979
|
" span",
|
|
1119
980
|
rows.length === 1 ? "" : "s",
|
|
1120
981
|
", ",
|
|
1121
|
-
formatDuration(totalMs),
|
|
982
|
+
(0, import_duration2.formatDuration)(totalMs),
|
|
1122
983
|
")"
|
|
1123
984
|
] }),
|
|
1124
985
|
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
|
|
@@ -1141,7 +1002,7 @@ function ReportTrace({ spans }) {
|
|
|
1141
1002
|
style: { left: `${leftPct}%`, width: `${widthPct}%` }
|
|
1142
1003
|
}
|
|
1143
1004
|
) }),
|
|
1144
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
|
|
1005
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: (0, import_duration2.formatDuration)(row.durationMs) })
|
|
1145
1006
|
] }, `${row.spanId}-${i}`);
|
|
1146
1007
|
}) })
|
|
1147
1008
|
] });
|
|
@@ -1317,130 +1178,14 @@ function useCollapseState(computeDefault) {
|
|
|
1317
1178
|
|
|
1318
1179
|
// src/interactive/scenario-actions.tsx
|
|
1319
1180
|
var import_react7 = require("react");
|
|
1320
|
-
|
|
1321
|
-
// ../executable-stories-core/dist/utils/scenario-markdown.js
|
|
1322
|
-
function cell(value) {
|
|
1323
|
-
return value.replaceAll("|", "\\|").replaceAll("\n", " ");
|
|
1324
|
-
}
|
|
1325
|
-
function stringify(value) {
|
|
1326
|
-
if (typeof value === "string") return value;
|
|
1327
|
-
try {
|
|
1328
|
-
return JSON.stringify(value, null, 2) ?? String(value);
|
|
1329
|
-
} catch {
|
|
1330
|
-
return String(value);
|
|
1331
|
-
}
|
|
1332
|
-
}
|
|
1333
|
-
function docEntryToMarkdown(entry, stateLanes) {
|
|
1334
|
-
const lines = [];
|
|
1335
|
-
switch (entry.kind) {
|
|
1336
|
-
case "note":
|
|
1337
|
-
lines.push(entry.text);
|
|
1338
|
-
break;
|
|
1339
|
-
case "tag":
|
|
1340
|
-
lines.push(entry.names.map((n) => `\`@${n}\``).join(" "));
|
|
1341
|
-
break;
|
|
1342
|
-
case "kv":
|
|
1343
|
-
lines.push(`**${entry.label}:** ${stringify(entry.value)}`);
|
|
1344
|
-
break;
|
|
1345
|
-
case "code":
|
|
1346
|
-
lines.push(`**${entry.label}**`, "", "```" + (entry.lang ?? ""), entry.content, "```");
|
|
1347
|
-
break;
|
|
1348
|
-
case "table": {
|
|
1349
|
-
lines.push(`**${entry.label}**`, "");
|
|
1350
|
-
lines.push(`| ${entry.columns.map(cell).join(" | ")} |`);
|
|
1351
|
-
lines.push(`| ${entry.columns.map(() => "---").join(" | ")} |`);
|
|
1352
|
-
for (const row of entry.rows) lines.push(`| ${row.map(cell).join(" | ")} |`);
|
|
1353
|
-
break;
|
|
1354
|
-
}
|
|
1355
|
-
case "link":
|
|
1356
|
-
lines.push(`[${entry.label}](${entry.url})`);
|
|
1357
|
-
break;
|
|
1358
|
-
case "section":
|
|
1359
|
-
lines.push(`### ${entry.title}`, "", entry.markdown);
|
|
1360
|
-
break;
|
|
1361
|
-
case "mermaid":
|
|
1362
|
-
if (entry.title) lines.push(`**${entry.title}**`, "");
|
|
1363
|
-
lines.push("```mermaid", entry.code, "```");
|
|
1364
|
-
break;
|
|
1365
|
-
case "screenshot":
|
|
1366
|
-
lines.push(``);
|
|
1367
|
-
break;
|
|
1368
|
-
case "video":
|
|
1369
|
-
lines.push(`Video: ${entry.path}${entry.caption ? ` \u2014 ${entry.caption}` : ""}`);
|
|
1370
|
-
break;
|
|
1371
|
-
case "html": {
|
|
1372
|
-
const htmlTitle = entry.title ?? "Embedded HTML";
|
|
1373
|
-
if (entry.content) {
|
|
1374
|
-
lines.push(`**${htmlTitle}**`, "", "```html", entry.content, "```");
|
|
1375
|
-
} else if (entry.url) {
|
|
1376
|
-
lines.push(`[${htmlTitle}](${entry.url})`);
|
|
1377
|
-
} else {
|
|
1378
|
-
lines.push(`Embedded HTML: ${entry.path ?? "(inline)"}`);
|
|
1379
|
-
}
|
|
1380
|
-
break;
|
|
1381
|
-
}
|
|
1382
|
-
case "custom":
|
|
1383
|
-
lines.push(`**${entry.type}**`, "", "```json", stringify(entry.data), "```");
|
|
1384
|
-
break;
|
|
1385
|
-
case "state": {
|
|
1386
|
-
const lane = entry.label ?? "";
|
|
1387
|
-
lines.push(`**${entry.label ?? "State"}**`);
|
|
1388
|
-
if (stateLanes?.has(lane)) {
|
|
1389
|
-
const summary = summarizeStateChanges(diffStateValues(stateLanes.get(lane), entry.value));
|
|
1390
|
-
if (summary.length > 0) lines.push("", ...summary.map((l) => `- ${l}`));
|
|
1391
|
-
}
|
|
1392
|
-
stateLanes?.set(lane, entry.value);
|
|
1393
|
-
lines.push("", "<details>", "<summary>snapshot</summary>", "", "```json", stringify(entry.value ?? null), "```", "", "</details>");
|
|
1394
|
-
break;
|
|
1395
|
-
}
|
|
1396
|
-
}
|
|
1397
|
-
for (const child of entry.children ?? []) {
|
|
1398
|
-
lines.push("", ...docEntryToMarkdown(child, stateLanes));
|
|
1399
|
-
}
|
|
1400
|
-
return lines;
|
|
1401
|
-
}
|
|
1402
|
-
function stepLines(step, ordinal, full, stateLanes) {
|
|
1403
|
-
const status = step.status === "passed" ? "" : ` \u2014 **${step.status}**`;
|
|
1404
|
-
const lines = [`${ordinal}. **${step.keyword}** ${step.text}${status}`];
|
|
1405
|
-
if (!full) return lines;
|
|
1406
|
-
if (step.errorMessage) {
|
|
1407
|
-
lines.push(...step.errorMessage.split("\n").map((l) => ` > ${l}`));
|
|
1408
|
-
}
|
|
1409
|
-
for (const entry of step.docEntries) {
|
|
1410
|
-
lines.push("", ...docEntryToMarkdown(entry, stateLanes).map((l) => l === "" ? l : ` ${l}`));
|
|
1411
|
-
}
|
|
1412
|
-
return lines;
|
|
1413
|
-
}
|
|
1414
|
-
function scenarioToMarkdown(scenario, options = {}) {
|
|
1415
|
-
const { variant = "full", meta = [] } = options;
|
|
1416
|
-
const full = variant === "full";
|
|
1417
|
-
const lines = full ? [`# ${scenario.title}`, ""] : [`## ${scenario.title} _(${scenario.status})_`, ""];
|
|
1418
|
-
if (full && meta.length > 0) lines.push(...meta);
|
|
1419
|
-
const stateLanes = /* @__PURE__ */ new Map();
|
|
1420
|
-
if (scenario.steps.length > 0) {
|
|
1421
|
-
if (full) lines.push("", "## Steps", "");
|
|
1422
|
-
scenario.steps.forEach((step, i) => lines.push(...stepLines(step, i + 1, full, stateLanes)));
|
|
1423
|
-
}
|
|
1424
|
-
if (scenario.errorMessage) {
|
|
1425
|
-
if (full) lines.push("", "## Failure", "");
|
|
1426
|
-
else lines.push("");
|
|
1427
|
-
lines.push("```", scenario.errorMessage.trim(), "```");
|
|
1428
|
-
}
|
|
1429
|
-
if (full && scenario.docEntries.length > 0) {
|
|
1430
|
-
lines.push("", "## Docs", "");
|
|
1431
|
-
for (const entry of scenario.docEntries) lines.push(...docEntryToMarkdown(entry, stateLanes), "");
|
|
1432
|
-
}
|
|
1433
|
-
return lines.join("\n").replaceAll(/\n{3,}/g, "\n\n").trimEnd() + (full ? "\n" : "");
|
|
1434
|
-
}
|
|
1435
|
-
|
|
1436
|
-
// src/interactive/scenario-actions.tsx
|
|
1181
|
+
var import_scenario_markdown = require("executable-stories-core/utils/scenario-markdown");
|
|
1437
1182
|
var ScenarioActionsContext = (0, import_react7.createContext)(null);
|
|
1438
1183
|
var ScenarioActionsProvider = ScenarioActionsContext.Provider;
|
|
1439
1184
|
function useScenarioActions() {
|
|
1440
1185
|
return (0, import_react7.useContext)(ScenarioActionsContext);
|
|
1441
1186
|
}
|
|
1442
|
-
function
|
|
1443
|
-
return scenarioToMarkdown(scenario, { variant: "compact" });
|
|
1187
|
+
function scenarioToMarkdown(scenario) {
|
|
1188
|
+
return (0, import_scenario_markdown.scenarioToMarkdown)(scenario, { variant: "compact" });
|
|
1444
1189
|
}
|
|
1445
1190
|
function scenarioToPrompt(scenario) {
|
|
1446
1191
|
const lines = [
|
|
@@ -1605,7 +1350,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1605
1350
|
] }),
|
|
1606
1351
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
1607
1352
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ScenarioRunHistory, { scenarioId: scenario.id }),
|
|
1608
|
-
scenario.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
|
|
1353
|
+
scenario.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: (0, import_duration3.formatDuration)(scenario.durationMs) }) : null,
|
|
1609
1354
|
meta.showPill ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "sr-only", children: `Status: ${label}` }),
|
|
1610
1355
|
actions ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DropdownMenu, { children: [
|
|
1611
1356
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
@@ -1865,6 +1610,9 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1865
1610
|
);
|
|
1866
1611
|
}
|
|
1867
1612
|
|
|
1613
|
+
// src/components/ReportMeta.tsx
|
|
1614
|
+
var import_duration4 = require("executable-stories-core/utils/duration");
|
|
1615
|
+
|
|
1868
1616
|
// src/lib/provenance.ts
|
|
1869
1617
|
function reportLastRunMs(report) {
|
|
1870
1618
|
if (report.finishedAtMs && report.finishedAtMs > 0) return report.finishedAtMs;
|
|
@@ -1924,7 +1672,7 @@ function ReportMeta() {
|
|
|
1924
1672
|
items.push({ label: "Started", value: new Date(report.startedAtMs).toLocaleString() });
|
|
1925
1673
|
}
|
|
1926
1674
|
if (report.durationMs) {
|
|
1927
|
-
items.push({ label: "Duration", value: formatDuration(report.durationMs) });
|
|
1675
|
+
items.push({ label: "Duration", value: (0, import_duration4.formatDuration)(report.durationMs) });
|
|
1928
1676
|
}
|
|
1929
1677
|
if (report.packageVersion) {
|
|
1930
1678
|
items.push({ label: "Version", value: report.packageVersion });
|
|
@@ -3050,7 +2798,7 @@ function ReportInteractiveView({
|
|
|
3050
2798
|
const scenarioActions = (0, import_react19.useMemo)(
|
|
3051
2799
|
() => ({
|
|
3052
2800
|
copyLink: (s) => copy(scenarioPermalink(s), "Link copied"),
|
|
3053
|
-
copyMarkdown: (s) => copy(
|
|
2801
|
+
copyMarkdown: (s) => copy(scenarioToMarkdown(s), "Markdown copied"),
|
|
3054
2802
|
copyPrompt: (s) => copy(scenarioToPrompt(s), "Prompt copied")
|
|
3055
2803
|
}),
|
|
3056
2804
|
[copy]
|