executable-stories-react 0.7.0 → 0.8.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 +418 -226
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -6
- package/dist/index.d.ts +17 -6
- package/dist/index.js +369 -177
- package/dist/index.js.map +1 -1
- package/dist/interactive.cjs +492 -318
- package/dist/interactive.cjs.map +1 -1
- package/dist/interactive.d.cts +10 -1
- package/dist/interactive.d.ts +10 -1
- package/dist/interactive.js +416 -242
- package/dist/interactive.js.map +1 -1
- package/dist/parse.cjs +30 -0
- package/dist/parse.cjs.map +1 -1
- package/dist/parse.d.cts +10 -1
- package/dist/parse.d.ts +10 -1
- package/dist/parse.js +30 -0
- package/dist/parse.js.map +1 -1
- package/dist/report-island.global.js +23 -23
- package/dist/ssr.cjs +356 -194
- package/dist/ssr.cjs.map +1 -1
- package/dist/ssr.d.cts +10 -1
- package/dist/ssr.d.ts +10 -1
- package/dist/ssr.js +316 -154
- package/dist/ssr.js.map +1 -1
- package/dist/tailwind.css +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -458,17 +458,29 @@ function DocHtml({ entry }) {
|
|
|
458
458
|
] });
|
|
459
459
|
}
|
|
460
460
|
|
|
461
|
-
// src/components/doc/
|
|
461
|
+
// src/components/doc/DocState.tsx
|
|
462
462
|
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
463
|
+
function DocState({ entry }) {
|
|
464
|
+
let json;
|
|
465
|
+
try {
|
|
466
|
+
json = JSON.stringify(entry.value, null, 2) ?? String(entry.value);
|
|
467
|
+
} catch {
|
|
468
|
+
json = String(entry.value);
|
|
469
|
+
}
|
|
470
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CodeFigure, { label: entry.label ?? "State", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("code", { className: "font-mono text-xs language-json", children: json }) });
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// src/components/doc/DocCustom.tsx
|
|
474
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
463
475
|
function DocCustom({ entry }) {
|
|
464
476
|
const renderers = useCustomRenderers();
|
|
465
477
|
const renderer = renderers[entry.type];
|
|
466
478
|
if (renderer) {
|
|
467
|
-
return /* @__PURE__ */ (0,
|
|
479
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_jsx_runtime14.Fragment, { children: renderer(entry) });
|
|
468
480
|
}
|
|
469
|
-
return /* @__PURE__ */ (0,
|
|
470
|
-
/* @__PURE__ */ (0,
|
|
471
|
-
/* @__PURE__ */ (0,
|
|
481
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "my-2", "data-type": entry.type, children: [
|
|
482
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "mb-1 text-xs font-medium text-muted-foreground", children: entry.type }),
|
|
483
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("pre", { tabIndex: 0, className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs text-foreground", children: safeStringify(entry.data) })
|
|
472
484
|
] });
|
|
473
485
|
}
|
|
474
486
|
function safeStringify(value) {
|
|
@@ -480,45 +492,47 @@ function safeStringify(value) {
|
|
|
480
492
|
}
|
|
481
493
|
|
|
482
494
|
// src/components/doc/DocEntry.tsx
|
|
483
|
-
var
|
|
495
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
484
496
|
function DocEntry({ entry }) {
|
|
485
497
|
switch (entry.kind) {
|
|
486
498
|
case "note":
|
|
487
|
-
return /* @__PURE__ */ (0,
|
|
499
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocNote, { entry });
|
|
488
500
|
case "tag":
|
|
489
|
-
return /* @__PURE__ */ (0,
|
|
501
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocTag, { entry });
|
|
490
502
|
case "kv":
|
|
491
|
-
return /* @__PURE__ */ (0,
|
|
503
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocKv, { entry });
|
|
492
504
|
case "code":
|
|
493
|
-
return /* @__PURE__ */ (0,
|
|
505
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocCode, { entry });
|
|
494
506
|
case "table":
|
|
495
|
-
return /* @__PURE__ */ (0,
|
|
507
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocTable, { entry });
|
|
496
508
|
case "link":
|
|
497
|
-
return /* @__PURE__ */ (0,
|
|
509
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocLink, { entry });
|
|
498
510
|
case "section":
|
|
499
|
-
return /* @__PURE__ */ (0,
|
|
511
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocSection, { entry });
|
|
500
512
|
case "mermaid":
|
|
501
|
-
return /* @__PURE__ */ (0,
|
|
513
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocMermaid, { entry });
|
|
502
514
|
case "screenshot":
|
|
503
|
-
return /* @__PURE__ */ (0,
|
|
515
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocScreenshot, { entry });
|
|
504
516
|
case "video":
|
|
505
|
-
return /* @__PURE__ */ (0,
|
|
517
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocVideo, { entry });
|
|
506
518
|
case "html":
|
|
507
|
-
return /* @__PURE__ */ (0,
|
|
519
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocHtml, { entry });
|
|
520
|
+
case "state":
|
|
521
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocState, { entry });
|
|
508
522
|
case "custom":
|
|
509
|
-
return /* @__PURE__ */ (0,
|
|
523
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DocCustom, { entry });
|
|
510
524
|
}
|
|
511
525
|
}
|
|
512
526
|
|
|
513
527
|
// src/components/ReportDocEntries.tsx
|
|
514
|
-
var
|
|
528
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
515
529
|
function ReportDocEntries({ entries }) {
|
|
516
530
|
if (entries.length === 0) return null;
|
|
517
|
-
return /* @__PURE__ */ (0,
|
|
531
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children: entries.map((entry, i) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DocEntry, { entry }, i)) });
|
|
518
532
|
}
|
|
519
533
|
|
|
520
534
|
// src/lib/step-params.tsx
|
|
521
|
-
var
|
|
535
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
522
536
|
var STEP_PARAM_PATTERN = /"[^"]*"|(?<![\w.-])\d+(?:\.\d+)?(?![\w.-])/g;
|
|
523
537
|
function highlightStepParams(text) {
|
|
524
538
|
const matches = Array.from(text.matchAll(STEP_PARAM_PATTERN));
|
|
@@ -530,7 +544,7 @@ function highlightStepParams(text) {
|
|
|
530
544
|
const end = start + match[0].length;
|
|
531
545
|
if (start > lastIndex) nodes.push(text.slice(lastIndex, start));
|
|
532
546
|
nodes.push(
|
|
533
|
-
/* @__PURE__ */ (0,
|
|
547
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "font-medium text-step-param italic", children: match[0] }, i)
|
|
534
548
|
);
|
|
535
549
|
lastIndex = end;
|
|
536
550
|
});
|
|
@@ -539,7 +553,7 @@ function highlightStepParams(text) {
|
|
|
539
553
|
}
|
|
540
554
|
|
|
541
555
|
// src/components/ReportSteps.tsx
|
|
542
|
-
var
|
|
556
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
543
557
|
var STEP_GLYPH = {
|
|
544
558
|
passed: "\u2713",
|
|
545
559
|
failed: "\u2717",
|
|
@@ -554,21 +568,21 @@ var STEP_GLYPH_COLOR = {
|
|
|
554
568
|
};
|
|
555
569
|
function ReportSteps({ scenario }) {
|
|
556
570
|
if (scenario.steps.length === 0) return null;
|
|
557
|
-
return /* @__PURE__ */ (0,
|
|
571
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("ol", { "data-slot": "steps", className: "flex flex-col", children: scenario.steps.map((step) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ReportStepItem, { step }, step.id)) });
|
|
558
572
|
}
|
|
559
573
|
function ReportStepItem({ step }) {
|
|
560
574
|
const kw = step.keyword.toLowerCase();
|
|
561
575
|
const continuation = kw === "and" || kw === "but";
|
|
562
|
-
return /* @__PURE__ */ (0,
|
|
576
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
563
577
|
"li",
|
|
564
578
|
{
|
|
565
579
|
id: step.id,
|
|
566
580
|
"data-status": step.status,
|
|
567
581
|
className: cn("py-1.5 text-[0.8125rem] leading-normal", continuation && "pl-5"),
|
|
568
582
|
children: [
|
|
569
|
-
/* @__PURE__ */ (0,
|
|
570
|
-
/* @__PURE__ */ (0,
|
|
571
|
-
/* @__PURE__ */ (0,
|
|
583
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-baseline gap-2", children: [
|
|
584
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { "aria-hidden": true, className: cn("w-4 shrink-0 text-center text-xs", STEP_GLYPH_COLOR[step.status]), children: STEP_GLYPH[step.status] ?? "\u25CB" }),
|
|
585
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
572
586
|
"span",
|
|
573
587
|
{
|
|
574
588
|
className: cn(
|
|
@@ -578,10 +592,10 @@ function ReportStepItem({ step }) {
|
|
|
578
592
|
children: step.keyword
|
|
579
593
|
}
|
|
580
594
|
),
|
|
581
|
-
/* @__PURE__ */ (0,
|
|
582
|
-
step.durationMs > 0 ? /* @__PURE__ */ (0,
|
|
595
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "flex-1 text-foreground", children: highlightStepParams(step.text) }),
|
|
596
|
+
step.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "shrink-0 whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(step.durationMs) }) : null
|
|
583
597
|
] }),
|
|
584
|
-
step.errorMessage ? /* @__PURE__ */ (0,
|
|
598
|
+
step.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
585
599
|
"pre",
|
|
586
600
|
{
|
|
587
601
|
role: "alert",
|
|
@@ -589,12 +603,72 @@ function ReportStepItem({ step }) {
|
|
|
589
603
|
children: step.errorMessage
|
|
590
604
|
}
|
|
591
605
|
) : null,
|
|
592
|
-
step.docEntries.length > 0 ? /* @__PURE__ */ (0,
|
|
606
|
+
step.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { "data-es-docs": true, className: "mt-2 ml-6", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ReportDocEntries, { entries: step.docEntries }) }) : null
|
|
593
607
|
]
|
|
594
608
|
}
|
|
595
609
|
);
|
|
596
610
|
}
|
|
597
611
|
|
|
612
|
+
// ../executable-stories-core/dist/state-diff.js
|
|
613
|
+
var isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
614
|
+
function deepEqual(a, b) {
|
|
615
|
+
if (Object.is(a, b)) return true;
|
|
616
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
617
|
+
return a.length === b.length && a.every((v, i) => deepEqual(v, b[i]));
|
|
618
|
+
}
|
|
619
|
+
if (isPlainObject(a) && isPlainObject(b)) {
|
|
620
|
+
const ak = Object.keys(a);
|
|
621
|
+
const bk = Object.keys(b);
|
|
622
|
+
return ak.length === bk.length && ak.every((k) => k in b && deepEqual(a[k], b[k]));
|
|
623
|
+
}
|
|
624
|
+
return false;
|
|
625
|
+
}
|
|
626
|
+
var joinKey = (path, key) => path === "" ? key : `${path}.${key}`;
|
|
627
|
+
function walk(path, before, after, out) {
|
|
628
|
+
if (Object.is(before, after)) return;
|
|
629
|
+
if (Array.isArray(before) && Array.isArray(after)) {
|
|
630
|
+
const shared = Math.min(before.length, after.length);
|
|
631
|
+
for (let i = 0; i < shared; i++) walk(`${path}[${i}]`, before[i], after[i], out);
|
|
632
|
+
for (let i = shared; i < after.length; i++) out.push({ path: `${path}[${i}]`, kind: "added", after: after[i] });
|
|
633
|
+
for (let i = shared; i < before.length; i++) out.push({ path: `${path}[${i}]`, kind: "removed", before: before[i] });
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
if (isPlainObject(before) && isPlainObject(after)) {
|
|
637
|
+
for (const key of Object.keys(after)) {
|
|
638
|
+
const p = joinKey(path, key);
|
|
639
|
+
if (key in before) walk(p, before[key], after[key], out);
|
|
640
|
+
else out.push({ path: p, kind: "added", after: after[key] });
|
|
641
|
+
}
|
|
642
|
+
for (const key of Object.keys(before)) {
|
|
643
|
+
if (!(key in after)) out.push({ path: joinKey(path, key), kind: "removed", before: before[key] });
|
|
644
|
+
}
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
if (!deepEqual(before, after)) out.push({ path, kind: "changed", before, after });
|
|
648
|
+
}
|
|
649
|
+
function diffStateValues(before, after) {
|
|
650
|
+
const out = [];
|
|
651
|
+
walk("", before, after, out);
|
|
652
|
+
return out;
|
|
653
|
+
}
|
|
654
|
+
function formatStateValue(value, maxLen = 60) {
|
|
655
|
+
const s = value === void 0 ? "undefined" : JSON.stringify(value);
|
|
656
|
+
return s.length > maxLen ? `${s.slice(0, maxLen - 1)}\u2026` : s;
|
|
657
|
+
}
|
|
658
|
+
function summarizeStateChanges(changes) {
|
|
659
|
+
return changes.map((c) => {
|
|
660
|
+
const at = c.path === "" ? "(root)" : c.path;
|
|
661
|
+
switch (c.kind) {
|
|
662
|
+
case "added":
|
|
663
|
+
return `+ ${at}: ${formatStateValue(c.after)}`;
|
|
664
|
+
case "removed":
|
|
665
|
+
return `\u2212 ${at}`;
|
|
666
|
+
case "changed":
|
|
667
|
+
return `${at}: ${formatStateValue(c.before)} \u2192 ${formatStateValue(c.after)}`;
|
|
668
|
+
}
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
|
|
598
672
|
// ../executable-stories-core/dist/storyboard.js
|
|
599
673
|
function findScreenshot(entries) {
|
|
600
674
|
for (const entry of entries) {
|
|
@@ -606,26 +680,55 @@ function findScreenshot(entries) {
|
|
|
606
680
|
}
|
|
607
681
|
return void 0;
|
|
608
682
|
}
|
|
683
|
+
function findStates(entries, out = []) {
|
|
684
|
+
for (const entry of entries) {
|
|
685
|
+
if (entry.kind === "state") out.push(entry);
|
|
686
|
+
if (entry.children) findStates(entry.children, out);
|
|
687
|
+
}
|
|
688
|
+
return out;
|
|
689
|
+
}
|
|
690
|
+
var laneOf = (label) => label ?? "";
|
|
609
691
|
function extractStoryboardFrames(scenario) {
|
|
610
692
|
const frames = [];
|
|
693
|
+
const laneOrder = [];
|
|
694
|
+
const previous = /* @__PURE__ */ new Map();
|
|
611
695
|
for (const step of scenario.steps) {
|
|
612
696
|
const shot = findScreenshot(step.docEntries);
|
|
613
|
-
|
|
697
|
+
const stateDocs = findStates(step.docEntries);
|
|
698
|
+
if (!shot && stateDocs.length === 0) continue;
|
|
699
|
+
const byLane = /* @__PURE__ */ new Map();
|
|
700
|
+
for (const doc of stateDocs) {
|
|
701
|
+
const lane = laneOf(doc.label);
|
|
702
|
+
if (!byLane.has(lane) && !laneOrder.includes(lane)) laneOrder.push(lane);
|
|
703
|
+
byLane.set(lane, doc);
|
|
704
|
+
}
|
|
705
|
+
const states = [];
|
|
706
|
+
for (const lane of laneOrder) {
|
|
707
|
+
const doc = byLane.get(lane);
|
|
708
|
+
if (!doc) continue;
|
|
709
|
+
const card = {
|
|
710
|
+
...doc.label !== void 0 && { label: doc.label },
|
|
711
|
+
value: doc.value
|
|
712
|
+
};
|
|
713
|
+
if (previous.has(lane)) card.changes = diffStateValues(previous.get(lane), doc.value);
|
|
714
|
+
previous.set(lane, doc.value);
|
|
715
|
+
states.push(card);
|
|
716
|
+
}
|
|
614
717
|
frames.push({
|
|
615
718
|
stepId: step.id,
|
|
616
719
|
stepIndex: step.index,
|
|
617
720
|
keyword: step.keyword,
|
|
618
721
|
text: step.text,
|
|
619
722
|
status: step.status,
|
|
620
|
-
path: shot.path,
|
|
621
|
-
|
|
723
|
+
...shot && { screenshot: { path: shot.path, ...shot.alt !== void 0 && { alt: shot.alt } } },
|
|
724
|
+
states
|
|
622
725
|
});
|
|
623
726
|
}
|
|
624
727
|
return frames;
|
|
625
728
|
}
|
|
626
729
|
|
|
627
730
|
// src/components/ReportStoryboard.tsx
|
|
628
|
-
var
|
|
731
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
629
732
|
var FRAME_GLYPH = {
|
|
630
733
|
passed: "\u2713",
|
|
631
734
|
failed: "\u2717",
|
|
@@ -641,55 +744,114 @@ var FRAME_GLYPH_COLOR = {
|
|
|
641
744
|
function ReportStoryboard({ scenario }) {
|
|
642
745
|
const frames = extractStoryboardFrames(scenario);
|
|
643
746
|
if (frames.length < 2) return null;
|
|
644
|
-
return /* @__PURE__ */ (0,
|
|
645
|
-
/* @__PURE__ */ (0,
|
|
646
|
-
/* @__PURE__ */ (0,
|
|
747
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("section", { "data-slot": "storyboard", "aria-label": "Storyboard", className: "mb-3", children: [
|
|
748
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h4", { className: "mb-1.5 text-xs font-semibold tracking-wide text-muted-foreground uppercase", children: "Storyboard" }),
|
|
749
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("ol", { className: "flex items-start gap-3 overflow-x-auto pb-2", children: frames.map((frame) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(StoryboardFrameItem, { frame }, frame.stepId)) })
|
|
647
750
|
] });
|
|
648
751
|
}
|
|
649
752
|
function StoryboardFrameItem({ frame }) {
|
|
650
|
-
const src = isLocalFsPath(frame.path) ? void 0 : safeImageUrl(frame.path);
|
|
651
753
|
const label = `${frame.keyword} ${frame.text}`;
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
754
|
+
const hasStates = frame.states.length > 0;
|
|
755
|
+
const caption = /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("p", { className: "mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug", children: [
|
|
756
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { "aria-hidden": true, className: cn("shrink-0", FRAME_GLYPH_COLOR[frame.status]), children: FRAME_GLYPH[frame.status] ?? "\u25CB" }),
|
|
757
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { className: "min-w-0", children: [
|
|
758
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "font-mono font-semibold text-keyword", children: frame.keyword }),
|
|
759
|
+
" ",
|
|
760
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-muted-foreground", children: frame.screenshot?.alt ?? frame.text })
|
|
761
|
+
] })
|
|
762
|
+
] });
|
|
763
|
+
return (
|
|
764
|
+
// State cards need room for diff rows; screenshot-only frames keep the
|
|
765
|
+
// original narrow film-cell width (and DOM) unchanged.
|
|
766
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("li", { className: cn("shrink-0", hasStates ? "w-64" : "w-40"), children: [
|
|
767
|
+
frame.screenshot ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(FrameScreenshot, { frame, label }) : null,
|
|
768
|
+
hasStates ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: cn("flex flex-col gap-1.5", frame.screenshot && "mt-1.5"), children: frame.states.map((card, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(StateCardView, { card }, card.label ?? i)) }) : null,
|
|
769
|
+
frame.screenshot ? caption : (
|
|
770
|
+
// No screenshot means no image anchor, so the caption carries the
|
|
771
|
+
// jump-to-step link instead.
|
|
772
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("a", { href: `#${frame.stepId}`, "aria-label": `Jump to step: ${label}`, className: "block hover:underline", children: caption })
|
|
773
|
+
)
|
|
774
|
+
] })
|
|
775
|
+
);
|
|
776
|
+
}
|
|
777
|
+
function FrameScreenshot({ frame, label }) {
|
|
778
|
+
const path = frame.screenshot?.path ?? "";
|
|
779
|
+
const src = isLocalFsPath(path) ? void 0 : safeImageUrl(path);
|
|
780
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
781
|
+
"a",
|
|
782
|
+
{
|
|
783
|
+
href: `#${frame.stepId}`,
|
|
784
|
+
"aria-label": `Jump to step: ${label}`,
|
|
785
|
+
className: "block overflow-hidden rounded-md border border-border transition-colors hover:border-ring",
|
|
786
|
+
children: src ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
787
|
+
"img",
|
|
788
|
+
{
|
|
789
|
+
src,
|
|
790
|
+
alt: frame.screenshot?.alt ?? label,
|
|
791
|
+
loading: "lazy",
|
|
792
|
+
className: "h-24 w-full bg-muted object-cover object-top"
|
|
793
|
+
}
|
|
794
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "flex h-24 w-full items-center justify-center border-b border-dashed border-border bg-muted px-2 text-center text-[0.6875rem] text-muted-foreground", children: "Screenshot unavailable" })
|
|
795
|
+
}
|
|
796
|
+
);
|
|
797
|
+
}
|
|
798
|
+
var CHANGE_TONE = {
|
|
799
|
+
added: "bg-pass-bg text-pass",
|
|
800
|
+
removed: "bg-fail-bg text-fail",
|
|
801
|
+
changed: "bg-skip-bg text-skip"
|
|
802
|
+
};
|
|
803
|
+
function prettyJson(value) {
|
|
804
|
+
try {
|
|
805
|
+
return JSON.stringify(value, null, 2) ?? String(value);
|
|
806
|
+
} catch {
|
|
807
|
+
return String(value);
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
function StateCardView({ card }) {
|
|
811
|
+
const json = prettyJson(card.value);
|
|
812
|
+
const firstCapture = card.changes === void 0;
|
|
813
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { "data-slot": "state-card", className: "rounded-md border border-border bg-card p-2", children: [
|
|
814
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("p", { className: "flex flex-wrap items-baseline gap-1.5", children: [
|
|
815
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "inline-flex rounded-full border border-border px-1.5 font-mono text-[0.625rem] font-medium text-muted-foreground", children: card.label ?? "State" }),
|
|
816
|
+
firstCapture ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-[0.625rem] text-muted-foreground italic", children: "first capture" }) : null
|
|
817
|
+
] }),
|
|
818
|
+
!firstCapture && (card.changes && card.changes.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("ul", { className: "mt-1.5 flex flex-col gap-0.5", children: card.changes.map((change, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
819
|
+
"li",
|
|
655
820
|
{
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
821
|
+
className: cn(
|
|
822
|
+
"rounded-sm px-1.5 py-0.5 font-mono text-[0.625rem] leading-snug break-all",
|
|
823
|
+
CHANGE_TONE[change.kind]
|
|
824
|
+
),
|
|
825
|
+
children: summarizeStateChanges([change])[0]
|
|
826
|
+
},
|
|
827
|
+
i
|
|
828
|
+
)) }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "mt-1.5 text-[0.625rem] text-muted-foreground", children: "No changes" })),
|
|
829
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
830
|
+
"details",
|
|
831
|
+
{
|
|
832
|
+
open: firstCapture && json.length <= 240,
|
|
833
|
+
className: cn(firstCapture ? "mt-1.5" : "mt-1"),
|
|
834
|
+
children: [
|
|
835
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("summary", { className: "cursor-pointer text-[0.625rem] text-muted-foreground hover:text-foreground", children: "Snapshot" }),
|
|
836
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("pre", { tabIndex: 0, className: "mt-1 max-h-48 overflow-auto rounded-sm bg-muted p-1.5 font-mono text-[0.625rem] leading-snug", children: json })
|
|
837
|
+
]
|
|
668
838
|
}
|
|
669
|
-
)
|
|
670
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("p", { className: "mt-1 flex items-baseline gap-1.5 text-[0.6875rem] leading-snug", children: [
|
|
671
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { "aria-hidden": true, className: cn("shrink-0", FRAME_GLYPH_COLOR[frame.status]), children: FRAME_GLYPH[frame.status] ?? "\u25CB" }),
|
|
672
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "min-w-0", children: [
|
|
673
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "font-mono font-semibold text-keyword", children: frame.keyword }),
|
|
674
|
-
" ",
|
|
675
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-muted-foreground", children: frame.alt ?? frame.text })
|
|
676
|
-
] })
|
|
677
|
-
] })
|
|
839
|
+
)
|
|
678
840
|
] });
|
|
679
841
|
}
|
|
680
842
|
|
|
681
843
|
// src/components/ReportAttachments.tsx
|
|
682
|
-
var
|
|
844
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
683
845
|
function ReportAttachments({ attachments }) {
|
|
684
846
|
if (attachments.length === 0) return null;
|
|
685
847
|
return (
|
|
686
848
|
// role="group" (not a labelled <section>) so multiple scenarios' attachment
|
|
687
849
|
// blocks don't create duplicate "Attachments" region landmarks.
|
|
688
|
-
/* @__PURE__ */ (0,
|
|
850
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { role: "group", "aria-label": "Attachments", className: "mt-3 flex flex-col gap-2", children: attachments.map((att, i) => {
|
|
689
851
|
const dataUri = att.contentEncoding === "BASE64" ? `data:${att.mediaType};base64,${att.body}` : `data:${att.mediaType},${encodeURIComponent(att.body)}`;
|
|
690
852
|
const isImage = att.mediaType.startsWith("image/");
|
|
691
|
-
return /* @__PURE__ */ (0,
|
|
692
|
-
/* @__PURE__ */ (0,
|
|
853
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("figure", { className: "m-0", children: isImage ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
|
|
854
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
693
855
|
"img",
|
|
694
856
|
{
|
|
695
857
|
src: dataUri,
|
|
@@ -698,8 +860,8 @@ function ReportAttachments({ attachments }) {
|
|
|
698
860
|
className: "max-w-full rounded-md border border-border"
|
|
699
861
|
}
|
|
700
862
|
),
|
|
701
|
-
/* @__PURE__ */ (0,
|
|
702
|
-
] }) : /* @__PURE__ */ (0,
|
|
863
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("figcaption", { className: "mt-1 text-xs text-muted-foreground", children: att.name })
|
|
864
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
703
865
|
"a",
|
|
704
866
|
{
|
|
705
867
|
href: dataUri,
|
|
@@ -708,7 +870,7 @@ function ReportAttachments({ attachments }) {
|
|
|
708
870
|
children: [
|
|
709
871
|
att.name,
|
|
710
872
|
" ",
|
|
711
|
-
/* @__PURE__ */ (0,
|
|
873
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "text-muted-foreground", children: [
|
|
712
874
|
"(",
|
|
713
875
|
att.mediaType,
|
|
714
876
|
")"
|
|
@@ -772,15 +934,15 @@ function toTraceRows(spans) {
|
|
|
772
934
|
roots.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);
|
|
773
935
|
const rows = [];
|
|
774
936
|
const seen = /* @__PURE__ */ new Set();
|
|
775
|
-
const
|
|
937
|
+
const walk2 = (node, depth) => {
|
|
776
938
|
if (seen.has(node.span.spanId)) return;
|
|
777
939
|
seen.add(node.span.spanId);
|
|
778
940
|
rows.push({ ...node.span, depth });
|
|
779
|
-
for (const child of node.children)
|
|
941
|
+
for (const child of node.children) walk2(child, depth + 1);
|
|
780
942
|
};
|
|
781
|
-
for (const root of roots)
|
|
943
|
+
for (const root of roots) walk2(root, 0);
|
|
782
944
|
for (const node of byId.values()) {
|
|
783
|
-
if (!seen.has(node.span.spanId))
|
|
945
|
+
if (!seen.has(node.span.spanId)) walk2(node, 0);
|
|
784
946
|
}
|
|
785
947
|
return rows;
|
|
786
948
|
}
|
|
@@ -796,7 +958,7 @@ function traceWindow(rows) {
|
|
|
796
958
|
}
|
|
797
959
|
|
|
798
960
|
// src/components/ReportTrace.tsx
|
|
799
|
-
var
|
|
961
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
800
962
|
var BAR_COLOR = {
|
|
801
963
|
ok: "bg-pass",
|
|
802
964
|
error: "bg-fail",
|
|
@@ -807,8 +969,8 @@ function ReportTrace({ spans }) {
|
|
|
807
969
|
const rows = toTraceRows(spans);
|
|
808
970
|
if (rows.length === 0) return null;
|
|
809
971
|
const { minStartMs, totalMs } = traceWindow(rows);
|
|
810
|
-
return /* @__PURE__ */ (0,
|
|
811
|
-
/* @__PURE__ */ (0,
|
|
972
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("details", { className: "mt-3 rounded-md border border-border bg-muted/30", children: [
|
|
973
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("summary", { className: "cursor-pointer px-3 py-2 text-xs font-medium text-muted-foreground", children: [
|
|
812
974
|
"Trace (",
|
|
813
975
|
rows.length,
|
|
814
976
|
" span",
|
|
@@ -817,11 +979,11 @@ function ReportTrace({ spans }) {
|
|
|
817
979
|
formatDuration(totalMs),
|
|
818
980
|
")"
|
|
819
981
|
] }),
|
|
820
|
-
/* @__PURE__ */ (0,
|
|
982
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("ul", { className: "flex flex-col gap-0.5 px-3 pb-3 font-mono text-[0.6875rem]", children: rows.map((row, i) => {
|
|
821
983
|
const leftPct = (row.startTimeMs - minStartMs) / totalMs * 100;
|
|
822
984
|
const widthPct = Math.max(row.durationMs / totalMs * 100, 0.5);
|
|
823
|
-
return /* @__PURE__ */ (0,
|
|
824
|
-
/* @__PURE__ */ (0,
|
|
985
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("li", { className: "flex items-center gap-2", children: [
|
|
986
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
825
987
|
"span",
|
|
826
988
|
{
|
|
827
989
|
className: "min-w-0 flex-1 truncate text-foreground",
|
|
@@ -830,14 +992,14 @@ function ReportTrace({ spans }) {
|
|
|
830
992
|
children: row.name
|
|
831
993
|
}
|
|
832
994
|
),
|
|
833
|
-
/* @__PURE__ */ (0,
|
|
995
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "relative h-3 w-1/2 shrink-0 overflow-hidden rounded-sm bg-border/40", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
834
996
|
"span",
|
|
835
997
|
{
|
|
836
998
|
className: cn("absolute top-0 h-full rounded-sm", BAR_COLOR[row.status]),
|
|
837
999
|
style: { left: `${leftPct}%`, width: `${widthPct}%` }
|
|
838
1000
|
}
|
|
839
1001
|
) }),
|
|
840
|
-
/* @__PURE__ */ (0,
|
|
1002
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "w-16 shrink-0 text-right text-muted-foreground", children: formatDuration(row.durationMs) })
|
|
841
1003
|
] }, `${row.spanId}-${i}`);
|
|
842
1004
|
}) })
|
|
843
1005
|
] });
|
|
@@ -888,7 +1050,7 @@ function flakinessOf(entries) {
|
|
|
888
1050
|
}
|
|
889
1051
|
|
|
890
1052
|
// src/components/ScenarioRunHistory.tsx
|
|
891
|
-
var
|
|
1053
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
892
1054
|
var MAX_DOTS = 10;
|
|
893
1055
|
var DOT_COLOR = {
|
|
894
1056
|
passed: "bg-pass",
|
|
@@ -908,16 +1070,16 @@ function ScenarioRunHistory({ scenarioId }) {
|
|
|
908
1070
|
const recent = entries.slice(-MAX_DOTS);
|
|
909
1071
|
const flaky = flakinessOf(recent) === "flaky";
|
|
910
1072
|
const summary = flaky ? `${describeRunHistory(recent)} \xB7 Flaky` : describeRunHistory(recent);
|
|
911
|
-
return /* @__PURE__ */ (0,
|
|
912
|
-
flaky ? /* @__PURE__ */ (0,
|
|
913
|
-
/* @__PURE__ */ (0,
|
|
1073
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
|
|
1074
|
+
flaky ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Badge, { variant: "pending", "aria-label": "Flaky: status flips between recent runs", title: summary, children: "Flaky" }) : null,
|
|
1075
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
914
1076
|
"span",
|
|
915
1077
|
{
|
|
916
1078
|
role: "img",
|
|
917
1079
|
"aria-label": `Run history: ${summary}`,
|
|
918
1080
|
title: summary,
|
|
919
1081
|
className: "flex shrink-0 items-center gap-[3px]",
|
|
920
|
-
children: recent.map((e, i) => /* @__PURE__ */ (0,
|
|
1082
|
+
children: recent.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
921
1083
|
"span",
|
|
922
1084
|
{
|
|
923
1085
|
"aria-hidden": true,
|
|
@@ -956,9 +1118,9 @@ function useScenarioActions() {
|
|
|
956
1118
|
|
|
957
1119
|
// src/components/ui/card.tsx
|
|
958
1120
|
var React2 = require("react");
|
|
959
|
-
var
|
|
1121
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
960
1122
|
function Card({ className, ...props }) {
|
|
961
|
-
return /* @__PURE__ */ (0,
|
|
1123
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
962
1124
|
"div",
|
|
963
1125
|
{
|
|
964
1126
|
"data-slot": "card",
|
|
@@ -971,7 +1133,7 @@ function Card({ className, ...props }) {
|
|
|
971
1133
|
);
|
|
972
1134
|
}
|
|
973
1135
|
function CardHeader({ className, ...props }) {
|
|
974
|
-
return /* @__PURE__ */ (0,
|
|
1136
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
975
1137
|
"div",
|
|
976
1138
|
{
|
|
977
1139
|
"data-slot": "card-header",
|
|
@@ -984,7 +1146,7 @@ function CardHeader({ className, ...props }) {
|
|
|
984
1146
|
);
|
|
985
1147
|
}
|
|
986
1148
|
function CardContent({ className, ...props }) {
|
|
987
|
-
return /* @__PURE__ */ (0,
|
|
1149
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
988
1150
|
"div",
|
|
989
1151
|
{
|
|
990
1152
|
"data-slot": "card-content",
|
|
@@ -998,13 +1160,13 @@ function CardContent({ className, ...props }) {
|
|
|
998
1160
|
var React3 = require("react");
|
|
999
1161
|
var import_menu = require("@base-ui/react/menu");
|
|
1000
1162
|
var import_lucide_react = require("lucide-react");
|
|
1001
|
-
var
|
|
1163
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
1002
1164
|
var itemClasses = "relative flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 [&_svg:not([class*='text-'])]:text-muted-foreground";
|
|
1003
1165
|
function DropdownMenu(props) {
|
|
1004
|
-
return /* @__PURE__ */ (0,
|
|
1166
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_menu.Menu.Root, { "data-slot": "dropdown-menu", ...props });
|
|
1005
1167
|
}
|
|
1006
1168
|
function DropdownMenuTrigger(props) {
|
|
1007
|
-
return /* @__PURE__ */ (0,
|
|
1169
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_menu.Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
|
|
1008
1170
|
}
|
|
1009
1171
|
function DropdownMenuContent({
|
|
1010
1172
|
className,
|
|
@@ -1012,14 +1174,14 @@ function DropdownMenuContent({
|
|
|
1012
1174
|
sideOffset = 4,
|
|
1013
1175
|
...props
|
|
1014
1176
|
}) {
|
|
1015
|
-
return /* @__PURE__ */ (0,
|
|
1177
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_menu.Menu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1016
1178
|
import_menu.Menu.Positioner,
|
|
1017
1179
|
{
|
|
1018
1180
|
"data-slot": "dropdown-menu-positioner",
|
|
1019
1181
|
className: "z-50",
|
|
1020
1182
|
align,
|
|
1021
1183
|
sideOffset,
|
|
1022
|
-
children: /* @__PURE__ */ (0,
|
|
1184
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1023
1185
|
import_menu.Menu.Popup,
|
|
1024
1186
|
{
|
|
1025
1187
|
"data-slot": "dropdown-menu-content",
|
|
@@ -1037,7 +1199,7 @@ function DropdownMenuItem({
|
|
|
1037
1199
|
className,
|
|
1038
1200
|
...props
|
|
1039
1201
|
}) {
|
|
1040
|
-
return /* @__PURE__ */ (0,
|
|
1202
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1041
1203
|
import_menu.Menu.Item,
|
|
1042
1204
|
{
|
|
1043
1205
|
"data-slot": "dropdown-menu-item",
|
|
@@ -1049,7 +1211,7 @@ function DropdownMenuItem({
|
|
|
1049
1211
|
|
|
1050
1212
|
// src/components/ReportScenario.tsx
|
|
1051
1213
|
var import_lucide_react2 = require("lucide-react");
|
|
1052
|
-
var
|
|
1214
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1053
1215
|
var STATUS_META = {
|
|
1054
1216
|
passed: { label: "Passed", glyph: "\u2713", glyphColor: "text-pass", badgeVariant: "passed", showPill: false },
|
|
1055
1217
|
failed: { label: "Failed", glyph: "\u2717", glyphColor: "text-fail", badgeVariant: "failed", showPill: true },
|
|
@@ -1065,7 +1227,7 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1065
1227
|
const collapsible = collapse !== null && !hideTitle;
|
|
1066
1228
|
const collapsed = collapsible ? collapse.isCollapsed(scenario.id) : false;
|
|
1067
1229
|
const actions = useScenarioActions();
|
|
1068
|
-
return /* @__PURE__ */ (0,
|
|
1230
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
1069
1231
|
Card,
|
|
1070
1232
|
{
|
|
1071
1233
|
id: scenario.id,
|
|
@@ -1073,10 +1235,10 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1073
1235
|
...hideTitle ? { "aria-label": `${scenario.title}, ${label}` } : { "aria-labelledby": titleId },
|
|
1074
1236
|
className: "gap-0 py-0",
|
|
1075
1237
|
children: [
|
|
1076
|
-
/* @__PURE__ */ (0,
|
|
1077
|
-
/* @__PURE__ */ (0,
|
|
1078
|
-
hideTitle ? null : /* @__PURE__ */ (0,
|
|
1079
|
-
collapsible ? /* @__PURE__ */ (0,
|
|
1238
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(CardHeader, { className: "px-4 py-3", children: [
|
|
1239
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: cn("flex items-start gap-4", hideTitle ? "justify-end" : "justify-between"), children: [
|
|
1240
|
+
hideTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("h3", { id: titleId, className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
|
|
1241
|
+
collapsible ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1080
1242
|
"button",
|
|
1081
1243
|
{
|
|
1082
1244
|
type: "button",
|
|
@@ -1085,49 +1247,49 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1085
1247
|
"aria-controls": bodyId,
|
|
1086
1248
|
"aria-label": `Toggle ${scenario.title}`,
|
|
1087
1249
|
className: "shrink-0 cursor-pointer text-muted-foreground hover:text-foreground",
|
|
1088
|
-
children: /* @__PURE__ */ (0,
|
|
1250
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, className: cn("inline-block text-xs transition-transform", !collapsed && "rotate-90"), children: "\u25B8" })
|
|
1089
1251
|
}
|
|
1090
1252
|
) : null,
|
|
1091
|
-
/* @__PURE__ */ (0,
|
|
1092
|
-
/* @__PURE__ */ (0,
|
|
1253
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { "aria-hidden": true, className: cn("text-sm leading-none", meta.glyphColor), children: meta.glyph }),
|
|
1254
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: scenario.title })
|
|
1093
1255
|
] }),
|
|
1094
|
-
/* @__PURE__ */ (0,
|
|
1095
|
-
/* @__PURE__ */ (0,
|
|
1096
|
-
scenario.durationMs > 0 ? /* @__PURE__ */ (0,
|
|
1097
|
-
meta.showPill ? /* @__PURE__ */ (0,
|
|
1098
|
-
actions ? /* @__PURE__ */ (0,
|
|
1099
|
-
/* @__PURE__ */ (0,
|
|
1256
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
1257
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ScenarioRunHistory, { scenarioId: scenario.id }),
|
|
1258
|
+
scenario.durationMs > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "whitespace-nowrap font-mono text-[0.6875rem] text-muted-foreground", children: formatDuration(scenario.durationMs) }) : null,
|
|
1259
|
+
meta.showPill ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Badge, { variant: meta.badgeVariant, "aria-label": `Status: ${label}`, children: label }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "sr-only", children: `Status: ${label}` }),
|
|
1260
|
+
actions ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenu, { children: [
|
|
1261
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1100
1262
|
DropdownMenuTrigger,
|
|
1101
1263
|
{
|
|
1102
1264
|
"aria-label": `Actions for ${scenario.title}`,
|
|
1103
1265
|
className: "cursor-pointer rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground [&_svg]:size-4",
|
|
1104
|
-
children: /* @__PURE__ */ (0,
|
|
1266
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react2.MoreHorizontalIcon, { "aria-hidden": true })
|
|
1105
1267
|
}
|
|
1106
1268
|
),
|
|
1107
|
-
/* @__PURE__ */ (0,
|
|
1108
|
-
/* @__PURE__ */ (0,
|
|
1109
|
-
/* @__PURE__ */ (0,
|
|
1269
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenuContent, { align: "end", children: [
|
|
1270
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenuItem, { onClick: () => actions.copyLink(scenario), children: [
|
|
1271
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react2.LinkIcon, {}),
|
|
1110
1272
|
" Copy link"
|
|
1111
1273
|
] }),
|
|
1112
|
-
/* @__PURE__ */ (0,
|
|
1113
|
-
/* @__PURE__ */ (0,
|
|
1274
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenuItem, { onClick: () => actions.copyMarkdown(scenario), children: [
|
|
1275
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react2.FileTextIcon, {}),
|
|
1114
1276
|
" Copy as Markdown"
|
|
1115
1277
|
] }),
|
|
1116
|
-
/* @__PURE__ */ (0,
|
|
1117
|
-
/* @__PURE__ */ (0,
|
|
1278
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(DropdownMenuItem, { onClick: () => actions.copyPrompt(scenario), children: [
|
|
1279
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react2.SparklesIcon, {}),
|
|
1118
1280
|
" Explain with AI"
|
|
1119
1281
|
] })
|
|
1120
1282
|
] })
|
|
1121
1283
|
] }) : null
|
|
1122
1284
|
] })
|
|
1123
1285
|
] }),
|
|
1124
|
-
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0,
|
|
1125
|
-
scenario.tags.map((t) => /* @__PURE__ */ (0,
|
|
1126
|
-
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0,
|
|
1286
|
+
scenario.tags.length > 0 || (scenario.tickets?.length ?? 0) > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("ul", { "aria-label": "Tags and tickets", className: "flex flex-wrap gap-1.5", children: [
|
|
1287
|
+
scenario.tags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Badge, { variant: "tag", children: t }) }, `tag-${t}`)),
|
|
1288
|
+
(scenario.tickets ?? []).map((ticket) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("li", { children: ticket.url ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("a", { href: ticket.url, target: "_blank", rel: "noreferrer noopener", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Badge, { variant: "outline", children: ticket.id }) }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Badge, { variant: "outline", children: ticket.id }) }, `ticket-${ticket.id}`))
|
|
1127
1289
|
] }) : null
|
|
1128
1290
|
] }),
|
|
1129
|
-
/* @__PURE__ */ (0,
|
|
1130
|
-
scenario.errorMessage ? /* @__PURE__ */ (0,
|
|
1291
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(CardContent, { id: bodyId, hidden: collapsed, className: "px-4 pt-0 pb-4", children: [
|
|
1292
|
+
scenario.errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1131
1293
|
"pre",
|
|
1132
1294
|
{
|
|
1133
1295
|
role: "alert",
|
|
@@ -1135,11 +1297,11 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1135
1297
|
children: scenario.errorMessage
|
|
1136
1298
|
}
|
|
1137
1299
|
) : null,
|
|
1138
|
-
/* @__PURE__ */ (0,
|
|
1139
|
-
/* @__PURE__ */ (0,
|
|
1140
|
-
scenario.docEntries.length > 0 ? /* @__PURE__ */ (0,
|
|
1141
|
-
/* @__PURE__ */ (0,
|
|
1142
|
-
/* @__PURE__ */ (0,
|
|
1300
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportStoryboard, { scenario }),
|
|
1301
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportSteps, { scenario }),
|
|
1302
|
+
scenario.docEntries.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { "data-es-docs": true, className: "mt-3", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportDocEntries, { entries: scenario.docEntries }) }) : null,
|
|
1303
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportAttachments, { attachments: scenario.attachments }),
|
|
1304
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ReportTrace, { spans: scenario.otelSpans })
|
|
1143
1305
|
] })
|
|
1144
1306
|
]
|
|
1145
1307
|
}
|
|
@@ -1147,13 +1309,13 @@ function ReportScenario({ scenario, hideTitle = false }) {
|
|
|
1147
1309
|
}
|
|
1148
1310
|
|
|
1149
1311
|
// src/components/ReportScenarioList.tsx
|
|
1150
|
-
var
|
|
1312
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1151
1313
|
function ReportScenarioList({ feature }) {
|
|
1152
|
-
return /* @__PURE__ */ (0,
|
|
1314
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_jsx_runtime26.Fragment, { children: feature.scenarios.map((scenario) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ReportScenario, { scenario }, scenario.id)) });
|
|
1153
1315
|
}
|
|
1154
1316
|
|
|
1155
1317
|
// src/components/ReportFeature.tsx
|
|
1156
|
-
var
|
|
1318
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1157
1319
|
function ReportFeature({ feature }) {
|
|
1158
1320
|
const titleId = `${feature.id}-title`;
|
|
1159
1321
|
const bodyId = `${feature.id}-body`;
|
|
@@ -1164,7 +1326,7 @@ function ReportFeature({ feature }) {
|
|
|
1164
1326
|
return (
|
|
1165
1327
|
// Suite = a section heading + a divider, NOT another bordered card. Drops a
|
|
1166
1328
|
// layer of nesting so the scenario cards below read as the primary unit.
|
|
1167
|
-
/* @__PURE__ */ (0,
|
|
1329
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
1168
1330
|
"section",
|
|
1169
1331
|
{
|
|
1170
1332
|
id: feature.id,
|
|
@@ -1172,9 +1334,9 @@ function ReportFeature({ feature }) {
|
|
|
1172
1334
|
"aria-labelledby": titleId,
|
|
1173
1335
|
className: "flex flex-col gap-3",
|
|
1174
1336
|
children: [
|
|
1175
|
-
/* @__PURE__ */ (0,
|
|
1176
|
-
/* @__PURE__ */ (0,
|
|
1177
|
-
/* @__PURE__ */ (0,
|
|
1337
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-end justify-between gap-4 border-b border-border pb-2", children: [
|
|
1338
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "min-w-0", children: [
|
|
1339
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("h2", { id: titleId, className: "text-base font-semibold tracking-tight text-foreground", children: collapse ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
1178
1340
|
"button",
|
|
1179
1341
|
{
|
|
1180
1342
|
type: "button",
|
|
@@ -1183,31 +1345,31 @@ function ReportFeature({ feature }) {
|
|
|
1183
1345
|
"aria-controls": bodyId,
|
|
1184
1346
|
className: "flex w-full cursor-pointer items-center gap-2 text-left hover:text-foreground/80",
|
|
1185
1347
|
children: [
|
|
1186
|
-
/* @__PURE__ */ (0,
|
|
1187
|
-
/* @__PURE__ */ (0,
|
|
1348
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { "aria-hidden": true, className: cn("shrink-0 text-xs text-muted-foreground transition-transform", !collapsed && "rotate-90"), children: "\u25B8" }),
|
|
1349
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "truncate", children: feature.title })
|
|
1188
1350
|
]
|
|
1189
1351
|
}
|
|
1190
1352
|
) : feature.title }),
|
|
1191
|
-
/* @__PURE__ */ (0,
|
|
1353
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: cn("mt-0.5 truncate font-mono text-xs text-muted-foreground", collapse && "pl-5"), children: feature.sourceFile })
|
|
1192
1354
|
] }),
|
|
1193
|
-
/* @__PURE__ */ (0,
|
|
1355
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
1194
1356
|
"p",
|
|
1195
1357
|
{
|
|
1196
1358
|
className: "flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground",
|
|
1197
1359
|
"aria-label": `${s.passed} passed, ${s.failed} failed, ${skipped} skipped`,
|
|
1198
1360
|
children: [
|
|
1199
|
-
/* @__PURE__ */ (0,
|
|
1361
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { children: [
|
|
1200
1362
|
s.passed,
|
|
1201
1363
|
" passed"
|
|
1202
1364
|
] }),
|
|
1203
|
-
/* @__PURE__ */ (0,
|
|
1204
|
-
/* @__PURE__ */ (0,
|
|
1365
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1366
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: cn(s.failed > 0 && "font-medium text-fail"), children: [
|
|
1205
1367
|
s.failed,
|
|
1206
1368
|
" failed"
|
|
1207
1369
|
] }),
|
|
1208
|
-
skipped > 0 ? /* @__PURE__ */ (0,
|
|
1209
|
-
/* @__PURE__ */ (0,
|
|
1210
|
-
/* @__PURE__ */ (0,
|
|
1370
|
+
skipped > 0 ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
|
|
1371
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1372
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { children: [
|
|
1211
1373
|
skipped,
|
|
1212
1374
|
" skipped"
|
|
1213
1375
|
] })
|
|
@@ -1216,7 +1378,7 @@ function ReportFeature({ feature }) {
|
|
|
1216
1378
|
}
|
|
1217
1379
|
)
|
|
1218
1380
|
] }),
|
|
1219
|
-
/* @__PURE__ */ (0,
|
|
1381
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { id: bodyId, hidden: collapsed, className: "flex flex-col gap-3", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ReportScenarioList, { feature }) })
|
|
1220
1382
|
]
|
|
1221
1383
|
}
|
|
1222
1384
|
)
|
|
@@ -1224,17 +1386,17 @@ function ReportFeature({ feature }) {
|
|
|
1224
1386
|
}
|
|
1225
1387
|
|
|
1226
1388
|
// src/components/ReportFeatureList.tsx
|
|
1227
|
-
var
|
|
1389
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1228
1390
|
function ReportFeatureList() {
|
|
1229
1391
|
const report = useReport();
|
|
1230
|
-
return /* @__PURE__ */ (0,
|
|
1392
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "flex flex-col gap-8", children: report.features.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ReportFeature, { feature }, feature.id)) });
|
|
1231
1393
|
}
|
|
1232
1394
|
|
|
1233
1395
|
// src/components/ui/empty.tsx
|
|
1234
1396
|
var import_class_variance_authority2 = require("class-variance-authority");
|
|
1235
|
-
var
|
|
1397
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
1236
1398
|
function Empty({ className, ...props }) {
|
|
1237
|
-
return /* @__PURE__ */ (0,
|
|
1399
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
1238
1400
|
"div",
|
|
1239
1401
|
{
|
|
1240
1402
|
"data-slot": "empty",
|
|
@@ -1247,7 +1409,7 @@ function Empty({ className, ...props }) {
|
|
|
1247
1409
|
);
|
|
1248
1410
|
}
|
|
1249
1411
|
function EmptyHeader({ className, ...props }) {
|
|
1250
|
-
return /* @__PURE__ */ (0,
|
|
1412
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
1251
1413
|
"div",
|
|
1252
1414
|
{
|
|
1253
1415
|
"data-slot": "empty-header",
|
|
@@ -1274,7 +1436,7 @@ var emptyMediaVariants = (0, import_class_variance_authority2.cva)(
|
|
|
1274
1436
|
}
|
|
1275
1437
|
);
|
|
1276
1438
|
function EmptyTitle({ className, ...props }) {
|
|
1277
|
-
return /* @__PURE__ */ (0,
|
|
1439
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
1278
1440
|
"div",
|
|
1279
1441
|
{
|
|
1280
1442
|
"data-slot": "empty-title",
|
|
@@ -1285,16 +1447,16 @@ function EmptyTitle({ className, ...props }) {
|
|
|
1285
1447
|
}
|
|
1286
1448
|
|
|
1287
1449
|
// src/components/ReportEmpty.tsx
|
|
1288
|
-
var
|
|
1450
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
1289
1451
|
function ReportEmpty({ message }) {
|
|
1290
|
-
return /* @__PURE__ */ (0,
|
|
1452
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Empty, { "aria-live": "polite", className: "border", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(EmptyHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(EmptyTitle, { children: message ?? "No scenarios in this report." }) }) });
|
|
1291
1453
|
}
|
|
1292
1454
|
|
|
1293
1455
|
// src/components/ReportSummary.tsx
|
|
1294
|
-
var
|
|
1456
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
1295
1457
|
function ReportSummary({ className }) {
|
|
1296
1458
|
const report = useReport();
|
|
1297
|
-
return /* @__PURE__ */ (0,
|
|
1459
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
1298
1460
|
ReportSummaryView,
|
|
1299
1461
|
{
|
|
1300
1462
|
summary: report.summary,
|
|
@@ -1320,7 +1482,7 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1320
1482
|
if (summary.pending > 0) {
|
|
1321
1483
|
cards.push({ status: "pending", label: "Pending", value: summary.pending });
|
|
1322
1484
|
}
|
|
1323
|
-
return /* @__PURE__ */ (0,
|
|
1485
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
1324
1486
|
"dl",
|
|
1325
1487
|
{
|
|
1326
1488
|
className: cn(
|
|
@@ -1333,17 +1495,17 @@ function ReportSummaryView({ summary, className, ariaLabel }) {
|
|
|
1333
1495
|
"aria-label": ariaLabel,
|
|
1334
1496
|
children: cards.map((c) => {
|
|
1335
1497
|
const tone = TONE[c.status];
|
|
1336
|
-
return /* @__PURE__ */ (0,
|
|
1498
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
|
|
1337
1499
|
"div",
|
|
1338
1500
|
{
|
|
1339
1501
|
"data-status": c.status,
|
|
1340
1502
|
className: "rounded-lg border bg-card px-4 py-3",
|
|
1341
1503
|
children: [
|
|
1342
|
-
/* @__PURE__ */ (0,
|
|
1343
|
-
/* @__PURE__ */ (0,
|
|
1504
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("dt", { className: "flex items-center gap-1.5 font-mono text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: [
|
|
1505
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: cn("size-1.5 shrink-0 rounded-full", tone.dot), "aria-hidden": "true" }),
|
|
1344
1506
|
c.label
|
|
1345
1507
|
] }),
|
|
1346
|
-
/* @__PURE__ */ (0,
|
|
1508
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("dd", { className: cn("mt-2 text-3xl font-semibold leading-none tracking-tight tabular-nums", tone.num), children: c.value })
|
|
1347
1509
|
]
|
|
1348
1510
|
},
|
|
1349
1511
|
c.status
|
|
@@ -1403,7 +1565,7 @@ function prUrl(ci) {
|
|
|
1403
1565
|
}
|
|
1404
1566
|
|
|
1405
1567
|
// src/components/ReportMeta.tsx
|
|
1406
|
-
var
|
|
1568
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
1407
1569
|
function ReportMeta() {
|
|
1408
1570
|
const report = useReport();
|
|
1409
1571
|
const items = [];
|
|
@@ -1426,13 +1588,13 @@ function ReportMeta() {
|
|
|
1426
1588
|
const short = sha.slice(0, 8);
|
|
1427
1589
|
items.push({
|
|
1428
1590
|
label: "Commit",
|
|
1429
|
-
value: url ? /* @__PURE__ */ (0,
|
|
1591
|
+
value: url ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: short }) : short
|
|
1430
1592
|
});
|
|
1431
1593
|
}
|
|
1432
1594
|
if (report.ci) {
|
|
1433
1595
|
items.push({
|
|
1434
1596
|
label: "CI",
|
|
1435
|
-
value: report.ci.url ? /* @__PURE__ */ (0,
|
|
1597
|
+
value: report.ci.url ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("a", { href: report.ci.url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: [
|
|
1436
1598
|
ciDisplayName(report.ci.name),
|
|
1437
1599
|
report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""
|
|
1438
1600
|
] }) : `${ciDisplayName(report.ci.name)}${report.ci.buildNumber ? ` #${report.ci.buildNumber}` : ""}`
|
|
@@ -1443,7 +1605,7 @@ function ReportMeta() {
|
|
|
1443
1605
|
const label = `#${report.ci.prNumber}`;
|
|
1444
1606
|
items.push({
|
|
1445
1607
|
label: "PR",
|
|
1446
|
-
value: url ? /* @__PURE__ */ (0,
|
|
1608
|
+
value: url ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("a", { href: url, target: "_blank", rel: "noreferrer noopener", className: linkClass, children: label }) : label
|
|
1447
1609
|
});
|
|
1448
1610
|
}
|
|
1449
1611
|
if (items.length === 0) return null;
|
|
@@ -1451,48 +1613,48 @@ function ReportMeta() {
|
|
|
1451
1613
|
// Run metadata is useful but secondary to "what failed" — tuck it into a
|
|
1452
1614
|
// collapsed disclosure so it doesn't push the result down. Native <details>
|
|
1453
1615
|
// so it works with no JS (the SSR/no-hydration report still toggles).
|
|
1454
|
-
/* @__PURE__ */ (0,
|
|
1455
|
-
/* @__PURE__ */ (0,
|
|
1456
|
-
/* @__PURE__ */ (0,
|
|
1616
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("details", { "data-es-meta-card": true, className: "es-run-details group rounded-lg border border-border bg-card text-xs", children: [
|
|
1617
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("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: [
|
|
1618
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { "aria-hidden": true, className: "text-xs transition-transform group-open:rotate-90", children: "\u25B8" }),
|
|
1457
1619
|
"Run details"
|
|
1458
1620
|
] }),
|
|
1459
|
-
/* @__PURE__ */ (0,
|
|
1460
|
-
/* @__PURE__ */ (0,
|
|
1461
|
-
/* @__PURE__ */ (0,
|
|
1621
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("dl", { className: "flex flex-wrap gap-x-5 gap-y-2 border-t border-border px-4 py-3 text-muted-foreground", "aria-label": "Run metadata", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex items-baseline gap-1.5", children: [
|
|
1622
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("dt", { className: "font-medium", children: item.label }),
|
|
1623
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("dd", { className: "font-mono text-foreground", children: item.value })
|
|
1462
1624
|
] }, item.label)) })
|
|
1463
1625
|
] })
|
|
1464
1626
|
);
|
|
1465
1627
|
}
|
|
1466
1628
|
|
|
1467
1629
|
// src/components/ReportSchemaError.tsx
|
|
1468
|
-
var
|
|
1630
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
1469
1631
|
function ReportSchemaError({ error }) {
|
|
1470
|
-
return /* @__PURE__ */ (0,
|
|
1471
|
-
/* @__PURE__ */ (0,
|
|
1472
|
-
/* @__PURE__ */ (0,
|
|
1473
|
-
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0,
|
|
1632
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("section", { className: "es-schema-error", role: "alert", "aria-live": "assertive", children: [
|
|
1633
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("strong", { children: "Report could not be displayed." }) }),
|
|
1634
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { children: error.message }),
|
|
1635
|
+
error.code === "SCHEMA_VERSION_MISMATCH" ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("p", { children: [
|
|
1474
1636
|
"The report bundle is newer than this version of ",
|
|
1475
|
-
/* @__PURE__ */ (0,
|
|
1637
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("code", { children: "executable-stories-react" }),
|
|
1476
1638
|
". Upgrade the package, or regenerate the report with an older formatters CLI."
|
|
1477
1639
|
] }) : null,
|
|
1478
|
-
error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0,
|
|
1479
|
-
/* @__PURE__ */ (0,
|
|
1640
|
+
error.issues && error.issues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("details", { children: [
|
|
1641
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("summary", { children: [
|
|
1480
1642
|
error.issues.length,
|
|
1481
1643
|
" validation issue",
|
|
1482
1644
|
error.issues.length === 1 ? "" : "s"
|
|
1483
1645
|
] }),
|
|
1484
|
-
/* @__PURE__ */ (0,
|
|
1646
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("pre", { children: error.issues.slice(0, 20).map((i) => `${i.path}: ${i.message}`).join("\n") })
|
|
1485
1647
|
] }) : null
|
|
1486
1648
|
] });
|
|
1487
1649
|
}
|
|
1488
1650
|
|
|
1489
1651
|
// src/components/ReportShell.tsx
|
|
1490
|
-
var
|
|
1652
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
1491
1653
|
function ReportTitleBlock({ title }) {
|
|
1492
|
-
return /* @__PURE__ */ (0,
|
|
1493
|
-
/* @__PURE__ */ (0,
|
|
1494
|
-
/* @__PURE__ */ (0,
|
|
1495
|
-
/* @__PURE__ */ (0,
|
|
1654
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
|
|
1655
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("h1", { children: title ?? "Story Report" }),
|
|
1656
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportSummary, {}),
|
|
1657
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportMeta, {})
|
|
1496
1658
|
] });
|
|
1497
1659
|
}
|
|
1498
1660
|
function ReportErrorShell({
|
|
@@ -1501,28 +1663,28 @@ function ReportErrorShell({
|
|
|
1501
1663
|
title,
|
|
1502
1664
|
dataTheme
|
|
1503
1665
|
}) {
|
|
1504
|
-
return /* @__PURE__ */ (0,
|
|
1666
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ReportSchemaError, { error }) });
|
|
1505
1667
|
}
|
|
1506
1668
|
|
|
1507
1669
|
// src/components/Report.tsx
|
|
1508
|
-
var
|
|
1670
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
1509
1671
|
function Report(props) {
|
|
1510
1672
|
const { report, customRenderers, renderers, className, title, dataTheme } = props;
|
|
1511
1673
|
const result = unwrapReport(report);
|
|
1512
1674
|
if (!result.ok) {
|
|
1513
|
-
return /* @__PURE__ */ (0,
|
|
1675
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportErrorShell, { error: result.error, className, title, dataTheme });
|
|
1514
1676
|
}
|
|
1515
1677
|
const data = result.data;
|
|
1516
1678
|
const hasContent = data.features.length > 0;
|
|
1517
|
-
return /* @__PURE__ */ (0,
|
|
1518
|
-
/* @__PURE__ */ (0,
|
|
1519
|
-
hasContent ? /* @__PURE__ */ (0,
|
|
1679
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
|
|
1680
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("header", { className: "es-report-header", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportTitleBlock, { title }) }),
|
|
1681
|
+
hasContent ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportFeatureList, {}) : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ReportEmpty, {})
|
|
1520
1682
|
] }) });
|
|
1521
1683
|
}
|
|
1522
1684
|
|
|
1523
1685
|
// src/components/doc/MermaidView.tsx
|
|
1524
1686
|
var import_react8 = require("react");
|
|
1525
|
-
var
|
|
1687
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
1526
1688
|
function prefersDark(el) {
|
|
1527
1689
|
const themed = el?.closest("[data-theme]");
|
|
1528
1690
|
if (themed?.dataset.theme === "dark") return true;
|
|
@@ -1559,9 +1721,9 @@ function MermaidView({ entry, load }) {
|
|
|
1559
1721
|
};
|
|
1560
1722
|
}, [entry.code, load]);
|
|
1561
1723
|
if (svg) {
|
|
1562
|
-
return /* @__PURE__ */ (0,
|
|
1563
|
-
entry.title ? /* @__PURE__ */ (0,
|
|
1564
|
-
/* @__PURE__ */ (0,
|
|
1724
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("figure", { ref, className: "my-3", children: [
|
|
1725
|
+
entry.title ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("figcaption", { className: "mb-1.5 text-xs font-medium text-muted-foreground", children: entry.title }) : null,
|
|
1726
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
1565
1727
|
"div",
|
|
1566
1728
|
{
|
|
1567
1729
|
role: "img",
|
|
@@ -1572,18 +1734,18 @@ function MermaidView({ entry, load }) {
|
|
|
1572
1734
|
)
|
|
1573
1735
|
] });
|
|
1574
1736
|
}
|
|
1575
|
-
return /* @__PURE__ */ (0,
|
|
1737
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(MermaidSource, { entry, ref });
|
|
1576
1738
|
}
|
|
1577
1739
|
|
|
1578
1740
|
// src/components/doc/MermaidDiagram.tsx
|
|
1579
|
-
var
|
|
1741
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
1580
1742
|
var mermaidLoader;
|
|
1581
1743
|
function loadMermaid() {
|
|
1582
1744
|
mermaidLoader ??= import("mermaid").then((m) => m.default);
|
|
1583
1745
|
return mermaidLoader;
|
|
1584
1746
|
}
|
|
1585
1747
|
function MermaidDiagram({ entry, load = loadMermaid }) {
|
|
1586
|
-
return /* @__PURE__ */ (0,
|
|
1748
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(MermaidView, { entry, load });
|
|
1587
1749
|
}
|
|
1588
1750
|
|
|
1589
1751
|
// src/components/ScenarioExplorer.tsx
|
|
@@ -1593,12 +1755,12 @@ var import_react9 = require("react");
|
|
|
1593
1755
|
var React4 = require("react");
|
|
1594
1756
|
var import_cmdk = require("cmdk");
|
|
1595
1757
|
var import_lucide_react3 = require("lucide-react");
|
|
1596
|
-
var
|
|
1758
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
1597
1759
|
function Command({
|
|
1598
1760
|
className,
|
|
1599
1761
|
...props
|
|
1600
1762
|
}) {
|
|
1601
|
-
return /* @__PURE__ */ (0,
|
|
1763
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
1602
1764
|
import_cmdk.Command,
|
|
1603
1765
|
{
|
|
1604
1766
|
"data-slot": "command",
|
|
@@ -1614,14 +1776,14 @@ function CommandInput({
|
|
|
1614
1776
|
className,
|
|
1615
1777
|
...props
|
|
1616
1778
|
}) {
|
|
1617
|
-
return /* @__PURE__ */ (0,
|
|
1779
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
|
|
1618
1780
|
"div",
|
|
1619
1781
|
{
|
|
1620
1782
|
"data-slot": "command-input-wrapper",
|
|
1621
1783
|
className: "flex h-9 items-center gap-2 border-b px-3",
|
|
1622
1784
|
children: [
|
|
1623
|
-
/* @__PURE__ */ (0,
|
|
1624
|
-
/* @__PURE__ */ (0,
|
|
1785
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_lucide_react3.SearchIcon, { className: "size-4 shrink-0 opacity-50" }),
|
|
1786
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
1625
1787
|
import_cmdk.Command.Input,
|
|
1626
1788
|
{
|
|
1627
1789
|
"data-slot": "command-input",
|
|
@@ -1640,7 +1802,7 @@ function CommandList({
|
|
|
1640
1802
|
className,
|
|
1641
1803
|
...props
|
|
1642
1804
|
}) {
|
|
1643
|
-
return /* @__PURE__ */ (0,
|
|
1805
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
1644
1806
|
import_cmdk.Command.List,
|
|
1645
1807
|
{
|
|
1646
1808
|
"data-slot": "command-list",
|
|
@@ -1655,7 +1817,7 @@ function CommandList({
|
|
|
1655
1817
|
function CommandEmpty({
|
|
1656
1818
|
...props
|
|
1657
1819
|
}) {
|
|
1658
|
-
return /* @__PURE__ */ (0,
|
|
1820
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
1659
1821
|
import_cmdk.Command.Empty,
|
|
1660
1822
|
{
|
|
1661
1823
|
"data-slot": "command-empty",
|
|
@@ -1668,7 +1830,7 @@ function CommandGroup({
|
|
|
1668
1830
|
className,
|
|
1669
1831
|
...props
|
|
1670
1832
|
}) {
|
|
1671
|
-
return /* @__PURE__ */ (0,
|
|
1833
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
1672
1834
|
import_cmdk.Command.Group,
|
|
1673
1835
|
{
|
|
1674
1836
|
"data-slot": "command-group",
|
|
@@ -1684,7 +1846,7 @@ function CommandItem({
|
|
|
1684
1846
|
className,
|
|
1685
1847
|
...props
|
|
1686
1848
|
}) {
|
|
1687
|
-
return /* @__PURE__ */ (0,
|
|
1849
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
1688
1850
|
import_cmdk.Command.Item,
|
|
1689
1851
|
{
|
|
1690
1852
|
"data-slot": "command-item",
|
|
@@ -1698,7 +1860,7 @@ function CommandItem({
|
|
|
1698
1860
|
}
|
|
1699
1861
|
|
|
1700
1862
|
// src/components/ScenarioExplorer.tsx
|
|
1701
|
-
var
|
|
1863
|
+
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
1702
1864
|
var STATUS_FILTERS = [
|
|
1703
1865
|
{ value: "all", label: "All" },
|
|
1704
1866
|
{ value: "passed", label: "Passed" },
|
|
@@ -1709,22 +1871,22 @@ var STATUS_FILTERS = [
|
|
|
1709
1871
|
function ScenarioExplorer({ scenarios, summary }) {
|
|
1710
1872
|
const [status, setStatus] = (0, import_react9.useState)("all");
|
|
1711
1873
|
const visible = status === "all" ? scenarios : scenarios.filter((s) => s.status === status);
|
|
1712
|
-
return /* @__PURE__ */ (0,
|
|
1713
|
-
summary ? /* @__PURE__ */ (0,
|
|
1874
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "font-sans text-foreground", children: [
|
|
1875
|
+
summary ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("p", { className: "mb-3 text-sm text-muted-foreground", children: [
|
|
1714
1876
|
summary.total,
|
|
1715
1877
|
" scenarios \xB7 ",
|
|
1716
|
-
/* @__PURE__ */ (0,
|
|
1878
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "text-pass", children: [
|
|
1717
1879
|
summary.passed,
|
|
1718
1880
|
" passed"
|
|
1719
1881
|
] }),
|
|
1720
1882
|
" \xB7",
|
|
1721
1883
|
" ",
|
|
1722
|
-
/* @__PURE__ */ (0,
|
|
1884
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "text-fail", children: [
|
|
1723
1885
|
summary.failed,
|
|
1724
1886
|
" failed"
|
|
1725
1887
|
] })
|
|
1726
1888
|
] }) : null,
|
|
1727
|
-
/* @__PURE__ */ (0,
|
|
1889
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "mb-2 flex flex-wrap gap-1.5", role: "group", "aria-label": "Filter by status", children: STATUS_FILTERS.map((f) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
1728
1890
|
"button",
|
|
1729
1891
|
{
|
|
1730
1892
|
type: "button",
|
|
@@ -1739,26 +1901,26 @@ function ScenarioExplorer({ scenarios, summary }) {
|
|
|
1739
1901
|
},
|
|
1740
1902
|
f.value
|
|
1741
1903
|
)) }),
|
|
1742
|
-
/* @__PURE__ */ (0,
|
|
1904
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
|
|
1743
1905
|
Command,
|
|
1744
1906
|
{
|
|
1745
1907
|
className: "rounded-lg border border-border bg-card",
|
|
1746
1908
|
filter: (value, search) => value.toLowerCase().includes(search.toLowerCase()) ? 1 : 0,
|
|
1747
1909
|
children: [
|
|
1748
|
-
/* @__PURE__ */ (0,
|
|
1749
|
-
/* @__PURE__ */ (0,
|
|
1750
|
-
/* @__PURE__ */ (0,
|
|
1751
|
-
/* @__PURE__ */ (0,
|
|
1910
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(CommandInput, { placeholder: "Search scenarios\u2026" }),
|
|
1911
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(CommandList, { className: "max-h-none", children: [
|
|
1912
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(CommandEmpty, { children: "No scenarios match your filters." }),
|
|
1913
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(CommandGroup, { children: visible.map((s) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
1752
1914
|
CommandItem,
|
|
1753
1915
|
{
|
|
1754
1916
|
value: `${s.title} ${s.feature} ${s.tags.join(" ")}`,
|
|
1755
1917
|
asChild: true,
|
|
1756
1918
|
className: "cursor-pointer",
|
|
1757
|
-
children: /* @__PURE__ */ (0,
|
|
1758
|
-
/* @__PURE__ */ (0,
|
|
1759
|
-
/* @__PURE__ */ (0,
|
|
1760
|
-
s.tags.slice(0, 3).map((t) => /* @__PURE__ */ (0,
|
|
1761
|
-
/* @__PURE__ */ (0,
|
|
1919
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("a", { href: s.href, className: "flex items-center gap-3", children: [
|
|
1920
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Badge, { variant: s.status, children: s.status }),
|
|
1921
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "min-w-0 flex-1 truncate font-medium", children: s.title }),
|
|
1922
|
+
s.tags.slice(0, 3).map((t) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Badge, { variant: "tag", className: "hidden sm:inline-flex", children: t }, t)),
|
|
1923
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("code", { className: "hidden font-mono text-xs text-muted-foreground md:inline", children: s.feature })
|
|
1762
1924
|
] })
|
|
1763
1925
|
},
|
|
1764
1926
|
s.id
|
|
@@ -2254,6 +2416,9 @@ var story_report_v1_default = {
|
|
|
2254
2416
|
{
|
|
2255
2417
|
$ref: "#/$defs/DocHtml"
|
|
2256
2418
|
},
|
|
2419
|
+
{
|
|
2420
|
+
$ref: "#/$defs/DocState"
|
|
2421
|
+
},
|
|
2257
2422
|
{
|
|
2258
2423
|
$ref: "#/$defs/DocCustom"
|
|
2259
2424
|
}
|
|
@@ -2629,6 +2794,33 @@ var story_report_v1_default = {
|
|
|
2629
2794
|
}
|
|
2630
2795
|
]
|
|
2631
2796
|
},
|
|
2797
|
+
DocState: {
|
|
2798
|
+
type: "object",
|
|
2799
|
+
properties: {
|
|
2800
|
+
kind: {
|
|
2801
|
+
const: "state"
|
|
2802
|
+
},
|
|
2803
|
+
label: {
|
|
2804
|
+
type: "string"
|
|
2805
|
+
},
|
|
2806
|
+
value: {},
|
|
2807
|
+
phase: {
|
|
2808
|
+
$ref: "#/$defs/DocPhase"
|
|
2809
|
+
},
|
|
2810
|
+
children: {
|
|
2811
|
+
type: "array",
|
|
2812
|
+
items: {
|
|
2813
|
+
$ref: "#/$defs/DocEntry"
|
|
2814
|
+
}
|
|
2815
|
+
}
|
|
2816
|
+
},
|
|
2817
|
+
required: [
|
|
2818
|
+
"kind",
|
|
2819
|
+
"value",
|
|
2820
|
+
"phase"
|
|
2821
|
+
],
|
|
2822
|
+
additionalProperties: false
|
|
2823
|
+
},
|
|
2632
2824
|
DocCustom: {
|
|
2633
2825
|
type: "object",
|
|
2634
2826
|
properties: {
|