@flanksource/clicky-ui 0.3.54 → 0.3.55

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.
@@ -1,7 +1,6 @@
1
1
  const require_utils = require("../../lib/utils.cjs");
2
2
  const require_UiServer = require("../../icons/components/UiServer.cjs");
3
3
  const require_UiClock = require("../../icons/components/UiClock.cjs");
4
- const require_ProgressBar = require("../ProgressBar.cjs");
5
4
  const require_matrix_marks = require("./matrix-marks.cjs");
6
5
  let react_jsx_runtime = require("react/jsx-runtime");
7
6
  // src/data/test-runner/MatrixMarks.tsx
@@ -49,6 +48,23 @@ function MatrixElapsed({ ms, running, clock = false }) {
49
48
  }), require_matrix_marks.formatMatrixDuration(ms)]
50
49
  });
51
50
  }
51
+ /** One tick per item, filled with its outcome's bar colour. */
52
+ function MatrixHeatmap({ ticks, unit, static: isStatic = false }) {
53
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
54
+ role: "list",
55
+ ...ticks.length > 0 ? { tabIndex: 0 } : {},
56
+ className: "flex h-3 min-w-10 flex-1 items-stretch gap-px overflow-x-auto [scrollbar-width:none] print:[print-color-adjust:exact] print:[-webkit-print-color-adjust:exact]",
57
+ "aria-label": `${ticks.length} ${unit}`,
58
+ "data-heatmap": unit,
59
+ children: ticks.map((tick, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
60
+ role: "listitem",
61
+ "aria-label": `${i + 1}. ${tick.label} · ${require_matrix_marks.MATRIX_MARKS[tick.mark].label}`,
62
+ title: `${i + 1}. ${tick.label} · ${require_matrix_marks.MATRIX_MARKS[tick.mark].label}`,
63
+ className: require_utils.cn("min-w-[3px] max-w-4 flex-1 rounded-[1px]", require_matrix_marks.matrixBarClass(tick.mark, isStatic)),
64
+ "data-tick-outcome": tick.mark
65
+ }, i))
66
+ });
67
+ }
52
68
  /**
53
69
  * A plan with no run in an environment: pending while queued, error when it
54
70
  * never started, hollow when not part of that run.
@@ -110,9 +126,11 @@ var HEADER_GRID = "grid min-w-48 grid-rows-[auto_auto_auto] gap-1.5";
110
126
  var HEADER_ROW = "flex h-5 min-w-0 items-center gap-2";
111
127
  /**
112
128
  * One environment's column head in three fixed rows: its chip, the plans'
113
- * progress with the elapsed time, and the plan verdict naming its units.
129
+ * progress as a heatmap with the elapsed time, and the plan verdict naming
130
+ * its units.
114
131
  */
115
- function MatrixEnvHeader({ context, counts, durationMs, running, renderChip, aside, static: isStatic = false }) {
132
+ function MatrixEnvHeader({ context, counts, plans, durationMs, running, renderChip, aside, static: isStatic = false }) {
133
+ if (plans.length !== counts.total) throw new Error(`${context} header has ${plans.length} plan ticks but counts ${counts.total} plans`);
116
134
  const done = counts.passed + counts.warned + counts.failed + counts.error;
117
135
  const chip = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EnvChip, { context });
118
136
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -128,17 +146,10 @@ function MatrixEnvHeader({ context, counts, durationMs, running, renderChip, asi
128
146
  title: `${done} of ${counts.total} plans finished`,
129
147
  "data-env-progress": "",
130
148
  children: [
131
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
132
- className: "min-w-0 flex-1",
133
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_ProgressBar.ProgressBar, {
134
- total: counts.total,
135
- height: "h-1.5",
136
- segments: require_matrix_marks.MATRIX_PLAN_BAR.map((key) => ({
137
- count: counts[key],
138
- color: require_matrix_marks.matrixBarClass(key, isStatic),
139
- label: `${require_matrix_marks.MATRIX_MARKS[key].label} plans`
140
- }))
141
- })
149
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MatrixHeatmap, {
150
+ ticks: plans,
151
+ unit: "plans",
152
+ static: isStatic
142
153
  }),
143
154
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
144
155
  className: "shrink-0 whitespace-nowrap text-[11px] tabular-nums text-foreground",
@@ -204,6 +215,7 @@ exports.EmptyMatrixCell = EmptyMatrixCell;
204
215
  exports.EnvChip = EnvChip;
205
216
  exports.MatrixElapsed = MatrixElapsed;
206
217
  exports.MatrixEnvHeader = MatrixEnvHeader;
218
+ exports.MatrixHeatmap = MatrixHeatmap;
207
219
  exports.MatrixLegend = MatrixLegend;
208
220
  exports.MatrixMark = MatrixMark;
209
221
  exports.MatrixMix = MatrixMix;
@@ -1 +1 @@
1
- {"version":3,"file":"MatrixMarks.cjs","names":["MATRIX_MARKS","cn","MATRIX_ORDER","UiClock","formatMatrixDuration","UiServer","ProgressBar","MATRIX_PLAN_BAR","matrixBarClass"],"sources":["../../../src/data/test-runner/MatrixMarks.tsx"],"sourcesContent":["// Renders the matrix-marks.ts vocabulary: one outcome's glyph, outcome mixes,\n// durations, empty cells, the legend, environment chips and the environment\n// column header. Props-only, so a live web matrix and a static print template\n// draw the same marks; `static` drops animation and links for print.\n\nimport type { ReactNode } from \"react\";\nimport { UiClock, UiServer } from \"../../icons\";\nimport { cn } from \"../../lib/utils\";\nimport { ProgressBar } from \"../ProgressBar\";\nimport {\n MATRIX_MARKS,\n MATRIX_ORDER,\n MATRIX_PLAN_BAR,\n formatMatrixDuration,\n matrixBarClass,\n type MatrixCounts,\n type MatrixEnvCounts,\n type MatrixMarkKey,\n type MatrixMarkToken,\n} from \"./matrix-marks\";\n\nexport type MatrixMarkProps = {\n mark: MatrixMarkKey;\n /** Hover title; \"\" leaves the glyph untitled where the surrounding element already names it. */\n label?: string;\n className?: string;\n /** Print: never spins. */\n static?: boolean;\n};\n\nexport function MatrixMark({ mark, label, className, static: isStatic = false }: MatrixMarkProps) {\n const token: MatrixMarkToken = MATRIX_MARKS[mark];\n const Glyph = token.icon;\n return (\n <Glyph\n {...(label === \"\" ? {} : { title: label ?? token.label })}\n className={cn(\"size-3.5 shrink-0\", token.tone, token.spin && !isStatic && \"animate-spin\", className)}\n data-mark={mark}\n />\n );\n}\n\nexport type MatrixMixProps = {\n counts: MatrixCounts;\n unit: \"steps\" | \"plans\";\n /** Outcomes drawn even at zero; every other zero count is dropped. */\n always?: readonly MatrixMarkKey[];\n static?: boolean;\n};\n\n/** Outcome counts as glyph + number, in matrix order. */\nexport function MatrixMix({ counts, unit, always = [], static: isStatic = false }: MatrixMixProps) {\n return (\n <span role=\"group\" aria-label={`${unit} by outcome`} className=\"flex shrink-0 items-center gap-2 text-xs tabular-nums\" data-mix={unit}>\n {MATRIX_ORDER.filter((key) => (counts[key] ?? 0) > 0 || always.includes(key)).map((key) => {\n const text = `${counts[key] ?? 0} ${MATRIX_MARKS[key].label} ${unit}`;\n return (\n <span key={key} role=\"img\" aria-label={text} title={text} className={cn(\"inline-flex items-center gap-0.5\", MATRIX_MARKS[key].tone)} data-mix-outcome={key}>\n <MatrixMark mark={key} label=\"\" static={isStatic} />\n {counts[key] ?? 0}\n </span>\n );\n })}\n </span>\n );\n}\n\nexport type MatrixElapsedProps = {\n ms: number;\n /** Still counting: drawn blue and titled \"elapsed so far\". */\n running: boolean;\n /** Prefix a clock glyph. */\n clock?: boolean;\n};\n\nexport function MatrixElapsed({ ms, running, clock = false }: MatrixElapsedProps) {\n return (\n <span\n className={cn(\"inline-flex shrink-0 items-center gap-1 whitespace-nowrap text-[11px] tabular-nums\", running ? \"text-blue-700 dark:text-blue-300\" : \"text-muted-foreground\")}\n title={running ? \"elapsed so far\" : \"total duration\"}\n data-duration=\"\"\n >\n {clock && <UiClock className=\"size-3\" aria-hidden=\"true\" />}\n {formatMatrixDuration(ms)}\n </span>\n );\n}\n\nexport type EmptyMatrixCellProps = {\n /** The cell outcome: \"queued\", \"absent\", or \"error\" with detail \"never started\". Anything else throws. */\n outcome: string;\n /** Why a cell has no run: \"never started\". */\n detail?: string;\n /** Hover title of the cell. */\n title: string;\n /** The glyph alone (sub-step rows), its meaning on hover. */\n bare?: boolean;\n};\n\n/**\n * A plan with no run in an environment: pending while queued, error when it\n * never started, hollow when not part of that run.\n */\nexport function EmptyMatrixCell({ outcome, detail, title, bare = false }: EmptyMatrixCellProps) {\n const neverStarted = detail === \"never started\";\n if (!neverStarted && outcome !== \"queued\" && outcome !== \"absent\") throw new Error(`unexpected empty matrix cell ${outcome}: ${title}`);\n const mark: MatrixMarkKey = neverStarted ? \"error\" : outcome === \"queued\" ? \"pending\" : \"absent\";\n const label = neverStarted ? \"never started\" : MATRIX_MARKS[mark].label;\n return (\n <span title={title} className=\"flex h-5 min-w-0 items-center gap-1.5 text-xs\" data-empty-cell={mark}>\n <MatrixMark mark={mark} label={label} />\n {!bare && <span className={MATRIX_MARKS[mark].tone}>{label}</span>}\n </span>\n );\n}\n\nexport type MatrixLegendProps = { static?: boolean };\n\nexport function MatrixLegend({ static: isStatic = false }: MatrixLegendProps) {\n return (\n <div className=\"flex flex-wrap items-center gap-x-4 gap-y-1 text-xs text-muted-foreground\" data-batch-legend=\"\">\n {MATRIX_ORDER.map((key) => {\n const token: MatrixMarkToken = MATRIX_MARKS[key];\n return (\n <span key={key} className=\"inline-flex items-center gap-1\" data-legend-mark={key}>\n <MatrixMark mark={key} label=\"\" static={isStatic} />\n {token.legend ?? token.label}\n </span>\n );\n })}\n <span className=\"inline-flex items-center gap-1\">\n <UiClock className=\"size-3\" aria-hidden=\"true\" />\n elapsed · total duration\n </span>\n </div>\n );\n}\n\nexport type EnvChipProps = { context: string; className?: string };\n\n/** A context name, always in the same chip, so an environment never reads as a plan or a status. */\nexport function EnvChip({ context, className }: EnvChipProps) {\n return (\n <span\n className={cn(\"inline-flex items-center gap-1 rounded border border-border bg-muted/50 px-1.5 py-0.5 font-mono text-[11px] text-foreground\", className)}\n data-env-chip={context}\n >\n <UiServer className=\"size-3 text-muted-foreground\" aria-hidden=\"true\" />\n {context}\n </span>\n );\n}\n\nconst HEADER_GRID = \"grid min-w-48 grid-rows-[auto_auto_auto] gap-1.5\";\nconst HEADER_ROW = \"flex h-5 min-w-0 items-center gap-2\";\n\nexport type MatrixEnvHeaderProps = {\n context: string;\n counts: MatrixEnvCounts;\n durationMs: number;\n /** The environment's run is still running: its elapsed time is still counting. */\n running: boolean;\n /** Wraps the chip, e.g. in the host router's link to the member run. Never called when static. */\n renderChip?: (chip: ReactNode) => ReactNode;\n /** Drawn beside the chip, e.g. how often the member was retried. */\n aside?: ReactNode;\n static?: boolean;\n};\n\n/**\n * One environment's column head in three fixed rows: its chip, the plans'\n * progress with the elapsed time, and the plan verdict naming its units.\n */\nexport function MatrixEnvHeader({ context, counts, durationMs, running, renderChip, aside, static: isStatic = false }: MatrixEnvHeaderProps) {\n const done = counts.passed + counts.warned + counts.failed + counts.error;\n const chip = <EnvChip context={context} />;\n return (\n <div className={HEADER_GRID} data-env-header={context}>\n <div className={HEADER_ROW}>\n {renderChip && !isStatic ? renderChip(chip) : chip}\n {aside}\n </div>\n <div className={HEADER_ROW} title={`${done} of ${counts.total} plans finished`} data-env-progress=\"\">\n <span className=\"min-w-0 flex-1\">\n <ProgressBar\n total={counts.total}\n height=\"h-1.5\"\n segments={MATRIX_PLAN_BAR.map((key) => ({ count: counts[key], color: matrixBarClass(key, isStatic), label: `${MATRIX_MARKS[key].label} plans` }))}\n />\n </span>\n <span className=\"shrink-0 whitespace-nowrap text-[11px] tabular-nums text-foreground\">\n {done}/{counts.total} plans\n </span>\n <MatrixElapsed ms={durationMs} running={running} clock />\n </div>\n <div className={HEADER_ROW} data-env-verdict=\"\">\n <MatrixMix\n counts={{ passed: counts.passed, warned: counts.warned, running: counts.running, pending: counts.queued, failed: counts.failed, error: counts.error }}\n unit=\"plans\"\n always={[\"failed\"]}\n static={isStatic}\n />\n </div>\n </div>\n );\n}\n\nexport type MatrixUnavailableEnvHeaderProps = { context: string };\n\n/** An environment whose member run did not load, in the same three rows as MatrixEnvHeader. */\nexport function MatrixUnavailableEnvHeader({ context }: MatrixUnavailableEnvHeaderProps) {\n return (\n <div className={HEADER_GRID} data-env-header={context}>\n <div className={HEADER_ROW}>\n <EnvChip context={context} />\n </div>\n <div className={`${HEADER_ROW} text-[11px] font-medium ${MATRIX_MARKS.error.tone}`}>\n <MatrixMark mark=\"error\" label=\"\" />\n did not load\n </div>\n <div className={HEADER_ROW} aria-hidden=\"true\" />\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"MatrixMarks.cjs","names":["MATRIX_MARKS","cn","MATRIX_ORDER","UiClock","formatMatrixDuration","matrixBarClass","UiServer"],"sources":["../../../src/data/test-runner/MatrixMarks.tsx"],"sourcesContent":["// Renders the matrix-marks.ts vocabulary: one outcome's glyph, outcome mixes,\n// durations, empty cells, the legend, environment chips and the environment\n// column header. Props-only, so a live web matrix and a static print template\n// draw the same marks; `static` drops animation and links for print.\n\nimport type { ReactNode } from \"react\";\nimport { UiClock, UiServer } from \"../../icons\";\nimport { cn } from \"../../lib/utils\";\nimport {\n MATRIX_MARKS,\n MATRIX_ORDER,\n formatMatrixDuration,\n matrixBarClass,\n type MatrixCounts,\n type MatrixEnvCounts,\n type MatrixMarkKey,\n type MatrixMarkToken,\n} from \"./matrix-marks\";\n\nexport type MatrixMarkProps = {\n mark: MatrixMarkKey;\n /** Hover title; \"\" leaves the glyph untitled where the surrounding element already names it. */\n label?: string;\n className?: string;\n /** Print: never spins. */\n static?: boolean;\n};\n\nexport function MatrixMark({ mark, label, className, static: isStatic = false }: MatrixMarkProps) {\n const token: MatrixMarkToken = MATRIX_MARKS[mark];\n const Glyph = token.icon;\n return (\n <Glyph\n {...(label === \"\" ? {} : { title: label ?? token.label })}\n className={cn(\"size-3.5 shrink-0\", token.tone, token.spin && !isStatic && \"animate-spin\", className)}\n data-mark={mark}\n />\n );\n}\n\nexport type MatrixMixProps = {\n counts: MatrixCounts;\n unit: \"steps\" | \"plans\";\n /** Outcomes drawn even at zero; every other zero count is dropped. */\n always?: readonly MatrixMarkKey[];\n static?: boolean;\n};\n\n/** Outcome counts as glyph + number, in matrix order. */\nexport function MatrixMix({ counts, unit, always = [], static: isStatic = false }: MatrixMixProps) {\n return (\n <span role=\"group\" aria-label={`${unit} by outcome`} className=\"flex shrink-0 items-center gap-2 text-xs tabular-nums\" data-mix={unit}>\n {MATRIX_ORDER.filter((key) => (counts[key] ?? 0) > 0 || always.includes(key)).map((key) => {\n const text = `${counts[key] ?? 0} ${MATRIX_MARKS[key].label} ${unit}`;\n return (\n <span key={key} role=\"img\" aria-label={text} title={text} className={cn(\"inline-flex items-center gap-0.5\", MATRIX_MARKS[key].tone)} data-mix-outcome={key}>\n <MatrixMark mark={key} label=\"\" static={isStatic} />\n {counts[key] ?? 0}\n </span>\n );\n })}\n </span>\n );\n}\n\nexport type MatrixElapsedProps = {\n ms: number;\n /** Still counting: drawn blue and titled \"elapsed so far\". */\n running: boolean;\n /** Prefix a clock glyph. */\n clock?: boolean;\n};\n\nexport function MatrixElapsed({ ms, running, clock = false }: MatrixElapsedProps) {\n return (\n <span\n className={cn(\"inline-flex shrink-0 items-center gap-1 whitespace-nowrap text-[11px] tabular-nums\", running ? \"text-blue-700 dark:text-blue-300\" : \"text-muted-foreground\")}\n title={running ? \"elapsed so far\" : \"total duration\"}\n data-duration=\"\"\n >\n {clock && <UiClock className=\"size-3\" aria-hidden=\"true\" />}\n {formatMatrixDuration(ms)}\n </span>\n );\n}\n\n/** One heatmap tick: an item (a plan, a step) and its outcome. */\nexport type MatrixTick = { label: string; mark: MatrixMarkKey };\n\nexport type MatrixHeatmapProps = {\n /** In run order: where a run is and where it broke read left to right. */\n ticks: readonly MatrixTick[];\n unit: \"steps\" | \"plans\";\n static?: boolean;\n};\n\n/** One tick per item, filled with its outcome's bar colour. */\nexport function MatrixHeatmap({ ticks, unit, static: isStatic = false }: MatrixHeatmapProps) {\n return (\n <span role=\"list\" {...(ticks.length > 0 ? { tabIndex: 0 } : {})} className=\"flex h-3 min-w-10 flex-1 items-stretch gap-px overflow-x-auto [scrollbar-width:none] print:[print-color-adjust:exact] print:[-webkit-print-color-adjust:exact]\" aria-label={`${ticks.length} ${unit}`} data-heatmap={unit}>\n {ticks.map((tick, i) => (\n <span\n key={i}\n role=\"listitem\"\n aria-label={`${i + 1}. ${tick.label} · ${MATRIX_MARKS[tick.mark].label}`}\n title={`${i + 1}. ${tick.label} · ${MATRIX_MARKS[tick.mark].label}`}\n className={cn(\"min-w-[3px] max-w-4 flex-1 rounded-[1px]\", matrixBarClass(tick.mark, isStatic))}\n data-tick-outcome={tick.mark}\n />\n ))}\n </span>\n );\n}\n\nexport type EmptyMatrixCellProps = {\n /** The cell outcome: \"queued\", \"absent\", or \"error\" with detail \"never started\". Anything else throws. */\n outcome: string;\n /** Why a cell has no run: \"never started\". */\n detail?: string;\n /** Hover title of the cell. */\n title: string;\n /** The glyph alone (sub-step rows), its meaning on hover. */\n bare?: boolean;\n};\n\n/**\n * A plan with no run in an environment: pending while queued, error when it\n * never started, hollow when not part of that run.\n */\nexport function EmptyMatrixCell({ outcome, detail, title, bare = false }: EmptyMatrixCellProps) {\n const neverStarted = detail === \"never started\";\n if (!neverStarted && outcome !== \"queued\" && outcome !== \"absent\") throw new Error(`unexpected empty matrix cell ${outcome}: ${title}`);\n const mark: MatrixMarkKey = neverStarted ? \"error\" : outcome === \"queued\" ? \"pending\" : \"absent\";\n const label = neverStarted ? \"never started\" : MATRIX_MARKS[mark].label;\n return (\n <span title={title} className=\"flex h-5 min-w-0 items-center gap-1.5 text-xs\" data-empty-cell={mark}>\n <MatrixMark mark={mark} label={label} />\n {!bare && <span className={MATRIX_MARKS[mark].tone}>{label}</span>}\n </span>\n );\n}\n\nexport type MatrixLegendProps = { static?: boolean };\n\nexport function MatrixLegend({ static: isStatic = false }: MatrixLegendProps) {\n return (\n <div className=\"flex flex-wrap items-center gap-x-4 gap-y-1 text-xs text-muted-foreground\" data-batch-legend=\"\">\n {MATRIX_ORDER.map((key) => {\n const token: MatrixMarkToken = MATRIX_MARKS[key];\n return (\n <span key={key} className=\"inline-flex items-center gap-1\" data-legend-mark={key}>\n <MatrixMark mark={key} label=\"\" static={isStatic} />\n {token.legend ?? token.label}\n </span>\n );\n })}\n <span className=\"inline-flex items-center gap-1\">\n <UiClock className=\"size-3\" aria-hidden=\"true\" />\n elapsed · total duration\n </span>\n </div>\n );\n}\n\nexport type EnvChipProps = { context: string; className?: string };\n\n/** A context name, always in the same chip, so an environment never reads as a plan or a status. */\nexport function EnvChip({ context, className }: EnvChipProps) {\n return (\n <span\n className={cn(\"inline-flex items-center gap-1 rounded border border-border bg-muted/50 px-1.5 py-0.5 font-mono text-[11px] text-foreground\", className)}\n data-env-chip={context}\n >\n <UiServer className=\"size-3 text-muted-foreground\" aria-hidden=\"true\" />\n {context}\n </span>\n );\n}\n\nconst HEADER_GRID = \"grid min-w-48 grid-rows-[auto_auto_auto] gap-1.5\";\nconst HEADER_ROW = \"flex h-5 min-w-0 items-center gap-2\";\n\nexport type MatrixEnvHeaderProps = {\n context: string;\n counts: MatrixEnvCounts;\n /** Every plan the counts total, in row order, drawn as the progress heatmap. */\n plans: readonly MatrixTick[];\n durationMs: number;\n /** The environment's run is still running: its elapsed time is still counting. */\n running: boolean;\n /** Wraps the chip, e.g. in the host router's link to the member run. Never called when static. */\n renderChip?: (chip: ReactNode) => ReactNode;\n /** Drawn beside the chip, e.g. how often the member was retried. */\n aside?: ReactNode;\n static?: boolean;\n};\n\n/**\n * One environment's column head in three fixed rows: its chip, the plans'\n * progress as a heatmap with the elapsed time, and the plan verdict naming\n * its units.\n */\nexport function MatrixEnvHeader({ context, counts, plans, durationMs, running, renderChip, aside, static: isStatic = false }: MatrixEnvHeaderProps) {\n if (plans.length !== counts.total) throw new Error(`${context} header has ${plans.length} plan ticks but counts ${counts.total} plans`);\n const done = counts.passed + counts.warned + counts.failed + counts.error;\n const chip = <EnvChip context={context} />;\n return (\n <div className={HEADER_GRID} data-env-header={context}>\n <div className={HEADER_ROW}>\n {renderChip && !isStatic ? renderChip(chip) : chip}\n {aside}\n </div>\n <div className={HEADER_ROW} title={`${done} of ${counts.total} plans finished`} data-env-progress=\"\">\n <MatrixHeatmap ticks={plans} unit=\"plans\" static={isStatic} />\n <span className=\"shrink-0 whitespace-nowrap text-[11px] tabular-nums text-foreground\">\n {done}/{counts.total} plans\n </span>\n <MatrixElapsed ms={durationMs} running={running} clock />\n </div>\n <div className={HEADER_ROW} data-env-verdict=\"\">\n <MatrixMix\n counts={{ passed: counts.passed, warned: counts.warned, running: counts.running, pending: counts.queued, failed: counts.failed, error: counts.error }}\n unit=\"plans\"\n always={[\"failed\"]}\n static={isStatic}\n />\n </div>\n </div>\n );\n}\n\nexport type MatrixUnavailableEnvHeaderProps = { context: string };\n\n/** An environment whose member run did not load, in the same three rows as MatrixEnvHeader. */\nexport function MatrixUnavailableEnvHeader({ context }: MatrixUnavailableEnvHeaderProps) {\n return (\n <div className={HEADER_GRID} data-env-header={context}>\n <div className={HEADER_ROW}>\n <EnvChip context={context} />\n </div>\n <div className={`${HEADER_ROW} text-[11px] font-medium ${MATRIX_MARKS.error.tone}`}>\n <MatrixMark mark=\"error\" label=\"\" />\n did not load\n </div>\n <div className={HEADER_ROW} aria-hidden=\"true\" />\n </div>\n );\n}\n"],"mappings":"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"}
@@ -26,6 +26,19 @@ export type MatrixElapsedProps = {
26
26
  clock?: boolean;
27
27
  };
28
28
  export declare function MatrixElapsed({ ms, running, clock }: MatrixElapsedProps): import("react").JSX.Element;
29
+ /** One heatmap tick: an item (a plan, a step) and its outcome. */
30
+ export type MatrixTick = {
31
+ label: string;
32
+ mark: MatrixMarkKey;
33
+ };
34
+ export type MatrixHeatmapProps = {
35
+ /** In run order: where a run is and where it broke read left to right. */
36
+ ticks: readonly MatrixTick[];
37
+ unit: "steps" | "plans";
38
+ static?: boolean;
39
+ };
40
+ /** One tick per item, filled with its outcome's bar colour. */
41
+ export declare function MatrixHeatmap({ ticks, unit, static: isStatic }: MatrixHeatmapProps): import("react").JSX.Element;
29
42
  export type EmptyMatrixCellProps = {
30
43
  /** The cell outcome: "queued", "absent", or "error" with detail "never started". Anything else throws. */
31
44
  outcome: string;
@@ -54,6 +67,8 @@ export declare function EnvChip({ context, className }: EnvChipProps): import("r
54
67
  export type MatrixEnvHeaderProps = {
55
68
  context: string;
56
69
  counts: MatrixEnvCounts;
70
+ /** Every plan the counts total, in row order, drawn as the progress heatmap. */
71
+ plans: readonly MatrixTick[];
57
72
  durationMs: number;
58
73
  /** The environment's run is still running: its elapsed time is still counting. */
59
74
  running: boolean;
@@ -65,9 +80,10 @@ export type MatrixEnvHeaderProps = {
65
80
  };
66
81
  /**
67
82
  * One environment's column head in three fixed rows: its chip, the plans'
68
- * progress with the elapsed time, and the plan verdict naming its units.
83
+ * progress as a heatmap with the elapsed time, and the plan verdict naming
84
+ * its units.
69
85
  */
70
- export declare function MatrixEnvHeader({ context, counts, durationMs, running, renderChip, aside, static: isStatic }: MatrixEnvHeaderProps): import("react").JSX.Element;
86
+ export declare function MatrixEnvHeader({ context, counts, plans, durationMs, running, renderChip, aside, static: isStatic }: MatrixEnvHeaderProps): import("react").JSX.Element;
71
87
  export type MatrixUnavailableEnvHeaderProps = {
72
88
  context: string;
73
89
  };
@@ -1 +1 @@
1
- {"version":3,"file":"MatrixMarks.d.ts","sourceRoot":"","sources":["../../../src/data/test-runner/MatrixMarks.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MatrixMarks.d.ts","sourceRoot":"","sources":["../../../src/data/test-runner/MatrixMarks.tsx"],"names":[],"mappings":"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"}
@@ -1,8 +1,7 @@
1
1
  import { cn } from "../../lib/utils.js";
2
2
  import { UiServer } from "../../icons/components/UiServer.js";
3
3
  import { UiClock } from "../../icons/components/UiClock.js";
4
- import { ProgressBar } from "../ProgressBar.js";
5
- import { MATRIX_MARKS, MATRIX_ORDER, MATRIX_PLAN_BAR, formatMatrixDuration, matrixBarClass } from "./matrix-marks.js";
4
+ import { MATRIX_MARKS, MATRIX_ORDER, formatMatrixDuration, matrixBarClass } from "./matrix-marks.js";
6
5
  import { jsx, jsxs } from "react/jsx-runtime";
7
6
  // src/data/test-runner/MatrixMarks.tsx
8
7
  function MatrixMark({ mark, label, className, static: isStatic = false }) {
@@ -49,6 +48,23 @@ function MatrixElapsed({ ms, running, clock = false }) {
49
48
  }), formatMatrixDuration(ms)]
50
49
  });
51
50
  }
51
+ /** One tick per item, filled with its outcome's bar colour. */
52
+ function MatrixHeatmap({ ticks, unit, static: isStatic = false }) {
53
+ return /* @__PURE__ */ jsx("span", {
54
+ role: "list",
55
+ ...ticks.length > 0 ? { tabIndex: 0 } : {},
56
+ className: "flex h-3 min-w-10 flex-1 items-stretch gap-px overflow-x-auto [scrollbar-width:none] print:[print-color-adjust:exact] print:[-webkit-print-color-adjust:exact]",
57
+ "aria-label": `${ticks.length} ${unit}`,
58
+ "data-heatmap": unit,
59
+ children: ticks.map((tick, i) => /* @__PURE__ */ jsx("span", {
60
+ role: "listitem",
61
+ "aria-label": `${i + 1}. ${tick.label} · ${MATRIX_MARKS[tick.mark].label}`,
62
+ title: `${i + 1}. ${tick.label} · ${MATRIX_MARKS[tick.mark].label}`,
63
+ className: cn("min-w-[3px] max-w-4 flex-1 rounded-[1px]", matrixBarClass(tick.mark, isStatic)),
64
+ "data-tick-outcome": tick.mark
65
+ }, i))
66
+ });
67
+ }
52
68
  /**
53
69
  * A plan with no run in an environment: pending while queued, error when it
54
70
  * never started, hollow when not part of that run.
@@ -110,9 +126,11 @@ var HEADER_GRID = "grid min-w-48 grid-rows-[auto_auto_auto] gap-1.5";
110
126
  var HEADER_ROW = "flex h-5 min-w-0 items-center gap-2";
111
127
  /**
112
128
  * One environment's column head in three fixed rows: its chip, the plans'
113
- * progress with the elapsed time, and the plan verdict naming its units.
129
+ * progress as a heatmap with the elapsed time, and the plan verdict naming
130
+ * its units.
114
131
  */
115
- function MatrixEnvHeader({ context, counts, durationMs, running, renderChip, aside, static: isStatic = false }) {
132
+ function MatrixEnvHeader({ context, counts, plans, durationMs, running, renderChip, aside, static: isStatic = false }) {
133
+ if (plans.length !== counts.total) throw new Error(`${context} header has ${plans.length} plan ticks but counts ${counts.total} plans`);
116
134
  const done = counts.passed + counts.warned + counts.failed + counts.error;
117
135
  const chip = /* @__PURE__ */ jsx(EnvChip, { context });
118
136
  return /* @__PURE__ */ jsxs("div", {
@@ -128,17 +146,10 @@ function MatrixEnvHeader({ context, counts, durationMs, running, renderChip, asi
128
146
  title: `${done} of ${counts.total} plans finished`,
129
147
  "data-env-progress": "",
130
148
  children: [
131
- /* @__PURE__ */ jsx("span", {
132
- className: "min-w-0 flex-1",
133
- children: /* @__PURE__ */ jsx(ProgressBar, {
134
- total: counts.total,
135
- height: "h-1.5",
136
- segments: MATRIX_PLAN_BAR.map((key) => ({
137
- count: counts[key],
138
- color: matrixBarClass(key, isStatic),
139
- label: `${MATRIX_MARKS[key].label} plans`
140
- }))
141
- })
149
+ /* @__PURE__ */ jsx(MatrixHeatmap, {
150
+ ticks: plans,
151
+ unit: "plans",
152
+ static: isStatic
142
153
  }),
143
154
  /* @__PURE__ */ jsxs("span", {
144
155
  className: "shrink-0 whitespace-nowrap text-[11px] tabular-nums text-foreground",
@@ -200,6 +211,6 @@ function MatrixUnavailableEnvHeader({ context }) {
200
211
  ]
201
212
  });
202
213
  }
203
- export { EmptyMatrixCell, EnvChip, MatrixElapsed, MatrixEnvHeader, MatrixLegend, MatrixMark, MatrixMix, MatrixUnavailableEnvHeader };
214
+ export { EmptyMatrixCell, EnvChip, MatrixElapsed, MatrixEnvHeader, MatrixHeatmap, MatrixLegend, MatrixMark, MatrixMix, MatrixUnavailableEnvHeader };
204
215
 
205
216
  //# sourceMappingURL=MatrixMarks.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MatrixMarks.js","names":[],"sources":["../../../src/data/test-runner/MatrixMarks.tsx"],"sourcesContent":["// Renders the matrix-marks.ts vocabulary: one outcome's glyph, outcome mixes,\n// durations, empty cells, the legend, environment chips and the environment\n// column header. Props-only, so a live web matrix and a static print template\n// draw the same marks; `static` drops animation and links for print.\n\nimport type { ReactNode } from \"react\";\nimport { UiClock, UiServer } from \"../../icons\";\nimport { cn } from \"../../lib/utils\";\nimport { ProgressBar } from \"../ProgressBar\";\nimport {\n MATRIX_MARKS,\n MATRIX_ORDER,\n MATRIX_PLAN_BAR,\n formatMatrixDuration,\n matrixBarClass,\n type MatrixCounts,\n type MatrixEnvCounts,\n type MatrixMarkKey,\n type MatrixMarkToken,\n} from \"./matrix-marks\";\n\nexport type MatrixMarkProps = {\n mark: MatrixMarkKey;\n /** Hover title; \"\" leaves the glyph untitled where the surrounding element already names it. */\n label?: string;\n className?: string;\n /** Print: never spins. */\n static?: boolean;\n};\n\nexport function MatrixMark({ mark, label, className, static: isStatic = false }: MatrixMarkProps) {\n const token: MatrixMarkToken = MATRIX_MARKS[mark];\n const Glyph = token.icon;\n return (\n <Glyph\n {...(label === \"\" ? {} : { title: label ?? token.label })}\n className={cn(\"size-3.5 shrink-0\", token.tone, token.spin && !isStatic && \"animate-spin\", className)}\n data-mark={mark}\n />\n );\n}\n\nexport type MatrixMixProps = {\n counts: MatrixCounts;\n unit: \"steps\" | \"plans\";\n /** Outcomes drawn even at zero; every other zero count is dropped. */\n always?: readonly MatrixMarkKey[];\n static?: boolean;\n};\n\n/** Outcome counts as glyph + number, in matrix order. */\nexport function MatrixMix({ counts, unit, always = [], static: isStatic = false }: MatrixMixProps) {\n return (\n <span role=\"group\" aria-label={`${unit} by outcome`} className=\"flex shrink-0 items-center gap-2 text-xs tabular-nums\" data-mix={unit}>\n {MATRIX_ORDER.filter((key) => (counts[key] ?? 0) > 0 || always.includes(key)).map((key) => {\n const text = `${counts[key] ?? 0} ${MATRIX_MARKS[key].label} ${unit}`;\n return (\n <span key={key} role=\"img\" aria-label={text} title={text} className={cn(\"inline-flex items-center gap-0.5\", MATRIX_MARKS[key].tone)} data-mix-outcome={key}>\n <MatrixMark mark={key} label=\"\" static={isStatic} />\n {counts[key] ?? 0}\n </span>\n );\n })}\n </span>\n );\n}\n\nexport type MatrixElapsedProps = {\n ms: number;\n /** Still counting: drawn blue and titled \"elapsed so far\". */\n running: boolean;\n /** Prefix a clock glyph. */\n clock?: boolean;\n};\n\nexport function MatrixElapsed({ ms, running, clock = false }: MatrixElapsedProps) {\n return (\n <span\n className={cn(\"inline-flex shrink-0 items-center gap-1 whitespace-nowrap text-[11px] tabular-nums\", running ? \"text-blue-700 dark:text-blue-300\" : \"text-muted-foreground\")}\n title={running ? \"elapsed so far\" : \"total duration\"}\n data-duration=\"\"\n >\n {clock && <UiClock className=\"size-3\" aria-hidden=\"true\" />}\n {formatMatrixDuration(ms)}\n </span>\n );\n}\n\nexport type EmptyMatrixCellProps = {\n /** The cell outcome: \"queued\", \"absent\", or \"error\" with detail \"never started\". Anything else throws. */\n outcome: string;\n /** Why a cell has no run: \"never started\". */\n detail?: string;\n /** Hover title of the cell. */\n title: string;\n /** The glyph alone (sub-step rows), its meaning on hover. */\n bare?: boolean;\n};\n\n/**\n * A plan with no run in an environment: pending while queued, error when it\n * never started, hollow when not part of that run.\n */\nexport function EmptyMatrixCell({ outcome, detail, title, bare = false }: EmptyMatrixCellProps) {\n const neverStarted = detail === \"never started\";\n if (!neverStarted && outcome !== \"queued\" && outcome !== \"absent\") throw new Error(`unexpected empty matrix cell ${outcome}: ${title}`);\n const mark: MatrixMarkKey = neverStarted ? \"error\" : outcome === \"queued\" ? \"pending\" : \"absent\";\n const label = neverStarted ? \"never started\" : MATRIX_MARKS[mark].label;\n return (\n <span title={title} className=\"flex h-5 min-w-0 items-center gap-1.5 text-xs\" data-empty-cell={mark}>\n <MatrixMark mark={mark} label={label} />\n {!bare && <span className={MATRIX_MARKS[mark].tone}>{label}</span>}\n </span>\n );\n}\n\nexport type MatrixLegendProps = { static?: boolean };\n\nexport function MatrixLegend({ static: isStatic = false }: MatrixLegendProps) {\n return (\n <div className=\"flex flex-wrap items-center gap-x-4 gap-y-1 text-xs text-muted-foreground\" data-batch-legend=\"\">\n {MATRIX_ORDER.map((key) => {\n const token: MatrixMarkToken = MATRIX_MARKS[key];\n return (\n <span key={key} className=\"inline-flex items-center gap-1\" data-legend-mark={key}>\n <MatrixMark mark={key} label=\"\" static={isStatic} />\n {token.legend ?? token.label}\n </span>\n );\n })}\n <span className=\"inline-flex items-center gap-1\">\n <UiClock className=\"size-3\" aria-hidden=\"true\" />\n elapsed · total duration\n </span>\n </div>\n );\n}\n\nexport type EnvChipProps = { context: string; className?: string };\n\n/** A context name, always in the same chip, so an environment never reads as a plan or a status. */\nexport function EnvChip({ context, className }: EnvChipProps) {\n return (\n <span\n className={cn(\"inline-flex items-center gap-1 rounded border border-border bg-muted/50 px-1.5 py-0.5 font-mono text-[11px] text-foreground\", className)}\n data-env-chip={context}\n >\n <UiServer className=\"size-3 text-muted-foreground\" aria-hidden=\"true\" />\n {context}\n </span>\n );\n}\n\nconst HEADER_GRID = \"grid min-w-48 grid-rows-[auto_auto_auto] gap-1.5\";\nconst HEADER_ROW = \"flex h-5 min-w-0 items-center gap-2\";\n\nexport type MatrixEnvHeaderProps = {\n context: string;\n counts: MatrixEnvCounts;\n durationMs: number;\n /** The environment's run is still running: its elapsed time is still counting. */\n running: boolean;\n /** Wraps the chip, e.g. in the host router's link to the member run. Never called when static. */\n renderChip?: (chip: ReactNode) => ReactNode;\n /** Drawn beside the chip, e.g. how often the member was retried. */\n aside?: ReactNode;\n static?: boolean;\n};\n\n/**\n * One environment's column head in three fixed rows: its chip, the plans'\n * progress with the elapsed time, and the plan verdict naming its units.\n */\nexport function MatrixEnvHeader({ context, counts, durationMs, running, renderChip, aside, static: isStatic = false }: MatrixEnvHeaderProps) {\n const done = counts.passed + counts.warned + counts.failed + counts.error;\n const chip = <EnvChip context={context} />;\n return (\n <div className={HEADER_GRID} data-env-header={context}>\n <div className={HEADER_ROW}>\n {renderChip && !isStatic ? renderChip(chip) : chip}\n {aside}\n </div>\n <div className={HEADER_ROW} title={`${done} of ${counts.total} plans finished`} data-env-progress=\"\">\n <span className=\"min-w-0 flex-1\">\n <ProgressBar\n total={counts.total}\n height=\"h-1.5\"\n segments={MATRIX_PLAN_BAR.map((key) => ({ count: counts[key], color: matrixBarClass(key, isStatic), label: `${MATRIX_MARKS[key].label} plans` }))}\n />\n </span>\n <span className=\"shrink-0 whitespace-nowrap text-[11px] tabular-nums text-foreground\">\n {done}/{counts.total} plans\n </span>\n <MatrixElapsed ms={durationMs} running={running} clock />\n </div>\n <div className={HEADER_ROW} data-env-verdict=\"\">\n <MatrixMix\n counts={{ passed: counts.passed, warned: counts.warned, running: counts.running, pending: counts.queued, failed: counts.failed, error: counts.error }}\n unit=\"plans\"\n always={[\"failed\"]}\n static={isStatic}\n />\n </div>\n </div>\n );\n}\n\nexport type MatrixUnavailableEnvHeaderProps = { context: string };\n\n/** An environment whose member run did not load, in the same three rows as MatrixEnvHeader. */\nexport function MatrixUnavailableEnvHeader({ context }: MatrixUnavailableEnvHeaderProps) {\n return (\n <div className={HEADER_GRID} data-env-header={context}>\n <div className={HEADER_ROW}>\n <EnvChip context={context} />\n </div>\n <div className={`${HEADER_ROW} text-[11px] font-medium ${MATRIX_MARKS.error.tone}`}>\n <MatrixMark mark=\"error\" label=\"\" />\n did not load\n </div>\n <div className={HEADER_ROW} aria-hidden=\"true\" />\n </div>\n );\n}\n"],"mappings":";;;;;;;AA8BA,SAAgB,WAAW,EAAE,MAAM,OAAO,WAAW,QAAQ,WAAW,SAA0B;CAChG,MAAM,QAAyB,aAAa;CAC5C,MAAM,QAAQ,MAAM;CACpB,OACE,oBAAC,OAAD;EACE,GAAK,UAAU,KAAK,CAAC,IAAI,EAAE,OAAO,SAAS,MAAM,MAAM;EACvD,WAAW,GAAG,qBAAqB,MAAM,MAAM,MAAM,QAAQ,CAAC,YAAY,gBAAgB,SAAS;EACnG,aAAW;CACZ,CAAA;AAEL;;AAWA,SAAgB,UAAU,EAAE,QAAQ,MAAM,SAAS,CAAC,GAAG,QAAQ,WAAW,SAAyB;CACjG,OACE,oBAAC,QAAD;EAAM,MAAK;EAAQ,cAAY,GAAG,KAAK;EAAc,WAAU;EAAwD,YAAU;EAC9H,UAAA,aAAa,QAAQ,SAAS,OAAO,QAAQ,KAAK,KAAK,OAAO,SAAS,GAAG,CAAC,CAAC,CAAC,KAAK,QAAQ;GACzF,MAAM,OAAO,GAAG,OAAO,QAAQ,EAAE,GAAG,aAAa,IAAI,CAAC,MAAM,GAAG;GAC/D,OACE,qBAAC,QAAD;IAAgB,MAAK;IAAM,cAAY;IAAM,OAAO;IAAM,WAAW,GAAG,oCAAoC,aAAa,IAAI,CAAC,IAAI;IAAG,oBAAkB;IAAvJ,UAAA,CACE,oBAAC,YAAD;KAAY,MAAM;KAAK,OAAM;KAAG,QAAQ;IAAW,CAAA,GAClD,OAAO,QAAQ,CACZ;GAHK,GAAA,GAGL;EAEV,CAAC;CACG,CAAA;AAEV;AAUA,SAAgB,cAAc,EAAE,IAAI,SAAS,QAAQ,SAA6B;CAChF,OACE,qBAAC,QAAD;EACE,WAAW,GAAG,sFAAsF,UAAU,qCAAqC,uBAAuB;EAC1K,OAAO,UAAU,mBAAmB;EACpC,iBAAc;EAHhB,UAAA,CAKG,SAAS,oBAAC,SAAD;GAAS,WAAU;GAAS,eAAY;EAAQ,CAAA,GACzD,qBAAqB,EAAE,CACpB;;AAEV;;;;;AAiBA,SAAgB,gBAAgB,EAAE,SAAS,QAAQ,OAAO,OAAO,SAA+B;CAC9F,MAAM,eAAe,WAAW;CAChC,IAAI,CAAC,gBAAgB,YAAY,YAAY,YAAY,UAAU,MAAM,IAAI,MAAM,gCAAgC,QAAQ,IAAI,OAAO;CACtI,MAAM,OAAsB,eAAe,UAAU,YAAY,WAAW,YAAY;CACxF,MAAM,QAAQ,eAAe,kBAAkB,aAAa,KAAK,CAAC;CAClE,OACE,qBAAC,QAAD;EAAa;EAAO,WAAU;EAAgD,mBAAiB;EAA/F,UAAA,CACE,oBAAC,YAAD;GAAkB;GAAa;EAAQ,CAAA,GACtC,CAAC,QAAQ,oBAAC,QAAD;GAAM,WAAW,aAAa,KAAK,CAAC;GAAO,UAAA;EAAY,CAAA,CAC7D;;AAEV;AAIA,SAAgB,aAAa,EAAE,QAAQ,WAAW,SAA4B;CAC5E,OACE,qBAAC,OAAD;EAAK,WAAU;EAA4E,qBAAkB;EAA7G,UAAA,CACG,aAAa,KAAK,QAAQ;GACzB,MAAM,QAAyB,aAAa;GAC5C,OACE,qBAAC,QAAD;IAAgB,WAAU;IAAiC,oBAAkB;IAA7E,UAAA,CACE,oBAAC,YAAD;KAAY,MAAM;KAAK,OAAM;KAAG,QAAQ;IAAW,CAAA,GAClD,MAAM,UAAU,MAAM,KACnB;GAHK,GAAA,GAGL;EAEV,CAAC,GACD,qBAAC,QAAD;GAAM,WAAU;GAAhB,UAAA,CACE,oBAAC,SAAD;IAAS,WAAU;IAAS,eAAY;GAAQ,CAAA,GAAC,0BAE7C;EACH,CAAA,CAAA;;AAET;;AAKA,SAAgB,QAAQ,EAAE,SAAS,aAA2B;CAC5D,OACE,qBAAC,QAAD;EACE,WAAW,GAAG,+HAA+H,SAAS;EACtJ,iBAAe;EAFjB,UAAA,CAIE,oBAAC,UAAD;GAAU,WAAU;GAA+B,eAAY;EAAQ,CAAA,GACtE,OACG;;AAEV;AAEA,IAAM,cAAc;AACpB,IAAM,aAAa;;;;;AAmBnB,SAAgB,gBAAgB,EAAE,SAAS,QAAQ,YAAY,SAAS,YAAY,OAAO,QAAQ,WAAW,SAA+B;CAC3I,MAAM,OAAO,OAAO,SAAS,OAAO,SAAS,OAAO,SAAS,OAAO;CACpE,MAAM,OAAO,oBAAC,SAAD,EAAkB,QAAU,CAAA;CACzC,OACE,qBAAC,OAAD;EAAK,WAAW;EAAa,mBAAiB;EAA9C,UAAA;GACE,qBAAC,OAAD;IAAK,WAAW;IAAhB,UAAA,CACG,cAAc,CAAC,WAAW,WAAW,IAAI,IAAI,MAC7C,KACE;;GACL,qBAAC,OAAD;IAAK,WAAW;IAAY,OAAO,GAAG,KAAK,MAAM,OAAO,MAAM;IAAkB,qBAAkB;IAAlG,UAAA;KACE,oBAAC,QAAD;MAAM,WAAU;MACd,UAAA,oBAAC,aAAD;OACE,OAAO,OAAO;OACd,QAAO;OACP,UAAU,gBAAgB,KAAK,SAAS;QAAE,OAAO,OAAO;QAAM,OAAO,eAAe,KAAK,QAAQ;QAAG,OAAO,GAAG,aAAa,IAAI,CAAC,MAAM;OAAQ,EAAE;MACjJ,CAAA;KACG,CAAA;KACN,qBAAC,QAAD;MAAM,WAAU;MAAhB,UAAA;OACG;OAAK;OAAE,OAAO;OAAM;MACjB;;KACN,oBAAC,eAAD;MAAe,IAAI;MAAqB;MAAS,OAAA;KAAO,CAAA;IACrD;;GACL,oBAAC,OAAD;IAAK,WAAW;IAAY,oBAAiB;IAC3C,UAAA,oBAAC,WAAD;KACE,QAAQ;MAAE,QAAQ,OAAO;MAAQ,QAAQ,OAAO;MAAQ,SAAS,OAAO;MAAS,SAAS,OAAO;MAAQ,QAAQ,OAAO;MAAQ,OAAO,OAAO;KAAM;KACpJ,MAAK;KACL,QAAQ,CAAC,QAAQ;KACjB,QAAQ;IACT,CAAA;GACE,CAAA;EACF;;AAET;;AAKA,SAAgB,2BAA2B,EAAE,WAA4C;CACvF,OACE,qBAAC,OAAD;EAAK,WAAW;EAAa,mBAAiB;EAA9C,UAAA;GACE,oBAAC,OAAD;IAAK,WAAW;IACd,UAAA,oBAAC,SAAD,EAAkB,QAAU,CAAA;GACzB,CAAA;GACL,qBAAC,OAAD;IAAK,WAAW,GAAG,WAAW,2BAA2B,aAAa,MAAM;IAA5E,UAAA,CACE,oBAAC,YAAD;KAAY,MAAK;KAAQ,OAAM;IAAI,CAAA,GAAC,cAEjC;;GACL,oBAAC,OAAD;IAAK,WAAW;IAAY,eAAY;GAAQ,CAAA;EAC7C;;AAET"}
1
+ {"version":3,"file":"MatrixMarks.js","names":[],"sources":["../../../src/data/test-runner/MatrixMarks.tsx"],"sourcesContent":["// Renders the matrix-marks.ts vocabulary: one outcome's glyph, outcome mixes,\n// durations, empty cells, the legend, environment chips and the environment\n// column header. Props-only, so a live web matrix and a static print template\n// draw the same marks; `static` drops animation and links for print.\n\nimport type { ReactNode } from \"react\";\nimport { UiClock, UiServer } from \"../../icons\";\nimport { cn } from \"../../lib/utils\";\nimport {\n MATRIX_MARKS,\n MATRIX_ORDER,\n formatMatrixDuration,\n matrixBarClass,\n type MatrixCounts,\n type MatrixEnvCounts,\n type MatrixMarkKey,\n type MatrixMarkToken,\n} from \"./matrix-marks\";\n\nexport type MatrixMarkProps = {\n mark: MatrixMarkKey;\n /** Hover title; \"\" leaves the glyph untitled where the surrounding element already names it. */\n label?: string;\n className?: string;\n /** Print: never spins. */\n static?: boolean;\n};\n\nexport function MatrixMark({ mark, label, className, static: isStatic = false }: MatrixMarkProps) {\n const token: MatrixMarkToken = MATRIX_MARKS[mark];\n const Glyph = token.icon;\n return (\n <Glyph\n {...(label === \"\" ? {} : { title: label ?? token.label })}\n className={cn(\"size-3.5 shrink-0\", token.tone, token.spin && !isStatic && \"animate-spin\", className)}\n data-mark={mark}\n />\n );\n}\n\nexport type MatrixMixProps = {\n counts: MatrixCounts;\n unit: \"steps\" | \"plans\";\n /** Outcomes drawn even at zero; every other zero count is dropped. */\n always?: readonly MatrixMarkKey[];\n static?: boolean;\n};\n\n/** Outcome counts as glyph + number, in matrix order. */\nexport function MatrixMix({ counts, unit, always = [], static: isStatic = false }: MatrixMixProps) {\n return (\n <span role=\"group\" aria-label={`${unit} by outcome`} className=\"flex shrink-0 items-center gap-2 text-xs tabular-nums\" data-mix={unit}>\n {MATRIX_ORDER.filter((key) => (counts[key] ?? 0) > 0 || always.includes(key)).map((key) => {\n const text = `${counts[key] ?? 0} ${MATRIX_MARKS[key].label} ${unit}`;\n return (\n <span key={key} role=\"img\" aria-label={text} title={text} className={cn(\"inline-flex items-center gap-0.5\", MATRIX_MARKS[key].tone)} data-mix-outcome={key}>\n <MatrixMark mark={key} label=\"\" static={isStatic} />\n {counts[key] ?? 0}\n </span>\n );\n })}\n </span>\n );\n}\n\nexport type MatrixElapsedProps = {\n ms: number;\n /** Still counting: drawn blue and titled \"elapsed so far\". */\n running: boolean;\n /** Prefix a clock glyph. */\n clock?: boolean;\n};\n\nexport function MatrixElapsed({ ms, running, clock = false }: MatrixElapsedProps) {\n return (\n <span\n className={cn(\"inline-flex shrink-0 items-center gap-1 whitespace-nowrap text-[11px] tabular-nums\", running ? \"text-blue-700 dark:text-blue-300\" : \"text-muted-foreground\")}\n title={running ? \"elapsed so far\" : \"total duration\"}\n data-duration=\"\"\n >\n {clock && <UiClock className=\"size-3\" aria-hidden=\"true\" />}\n {formatMatrixDuration(ms)}\n </span>\n );\n}\n\n/** One heatmap tick: an item (a plan, a step) and its outcome. */\nexport type MatrixTick = { label: string; mark: MatrixMarkKey };\n\nexport type MatrixHeatmapProps = {\n /** In run order: where a run is and where it broke read left to right. */\n ticks: readonly MatrixTick[];\n unit: \"steps\" | \"plans\";\n static?: boolean;\n};\n\n/** One tick per item, filled with its outcome's bar colour. */\nexport function MatrixHeatmap({ ticks, unit, static: isStatic = false }: MatrixHeatmapProps) {\n return (\n <span role=\"list\" {...(ticks.length > 0 ? { tabIndex: 0 } : {})} className=\"flex h-3 min-w-10 flex-1 items-stretch gap-px overflow-x-auto [scrollbar-width:none] print:[print-color-adjust:exact] print:[-webkit-print-color-adjust:exact]\" aria-label={`${ticks.length} ${unit}`} data-heatmap={unit}>\n {ticks.map((tick, i) => (\n <span\n key={i}\n role=\"listitem\"\n aria-label={`${i + 1}. ${tick.label} · ${MATRIX_MARKS[tick.mark].label}`}\n title={`${i + 1}. ${tick.label} · ${MATRIX_MARKS[tick.mark].label}`}\n className={cn(\"min-w-[3px] max-w-4 flex-1 rounded-[1px]\", matrixBarClass(tick.mark, isStatic))}\n data-tick-outcome={tick.mark}\n />\n ))}\n </span>\n );\n}\n\nexport type EmptyMatrixCellProps = {\n /** The cell outcome: \"queued\", \"absent\", or \"error\" with detail \"never started\". Anything else throws. */\n outcome: string;\n /** Why a cell has no run: \"never started\". */\n detail?: string;\n /** Hover title of the cell. */\n title: string;\n /** The glyph alone (sub-step rows), its meaning on hover. */\n bare?: boolean;\n};\n\n/**\n * A plan with no run in an environment: pending while queued, error when it\n * never started, hollow when not part of that run.\n */\nexport function EmptyMatrixCell({ outcome, detail, title, bare = false }: EmptyMatrixCellProps) {\n const neverStarted = detail === \"never started\";\n if (!neverStarted && outcome !== \"queued\" && outcome !== \"absent\") throw new Error(`unexpected empty matrix cell ${outcome}: ${title}`);\n const mark: MatrixMarkKey = neverStarted ? \"error\" : outcome === \"queued\" ? \"pending\" : \"absent\";\n const label = neverStarted ? \"never started\" : MATRIX_MARKS[mark].label;\n return (\n <span title={title} className=\"flex h-5 min-w-0 items-center gap-1.5 text-xs\" data-empty-cell={mark}>\n <MatrixMark mark={mark} label={label} />\n {!bare && <span className={MATRIX_MARKS[mark].tone}>{label}</span>}\n </span>\n );\n}\n\nexport type MatrixLegendProps = { static?: boolean };\n\nexport function MatrixLegend({ static: isStatic = false }: MatrixLegendProps) {\n return (\n <div className=\"flex flex-wrap items-center gap-x-4 gap-y-1 text-xs text-muted-foreground\" data-batch-legend=\"\">\n {MATRIX_ORDER.map((key) => {\n const token: MatrixMarkToken = MATRIX_MARKS[key];\n return (\n <span key={key} className=\"inline-flex items-center gap-1\" data-legend-mark={key}>\n <MatrixMark mark={key} label=\"\" static={isStatic} />\n {token.legend ?? token.label}\n </span>\n );\n })}\n <span className=\"inline-flex items-center gap-1\">\n <UiClock className=\"size-3\" aria-hidden=\"true\" />\n elapsed · total duration\n </span>\n </div>\n );\n}\n\nexport type EnvChipProps = { context: string; className?: string };\n\n/** A context name, always in the same chip, so an environment never reads as a plan or a status. */\nexport function EnvChip({ context, className }: EnvChipProps) {\n return (\n <span\n className={cn(\"inline-flex items-center gap-1 rounded border border-border bg-muted/50 px-1.5 py-0.5 font-mono text-[11px] text-foreground\", className)}\n data-env-chip={context}\n >\n <UiServer className=\"size-3 text-muted-foreground\" aria-hidden=\"true\" />\n {context}\n </span>\n );\n}\n\nconst HEADER_GRID = \"grid min-w-48 grid-rows-[auto_auto_auto] gap-1.5\";\nconst HEADER_ROW = \"flex h-5 min-w-0 items-center gap-2\";\n\nexport type MatrixEnvHeaderProps = {\n context: string;\n counts: MatrixEnvCounts;\n /** Every plan the counts total, in row order, drawn as the progress heatmap. */\n plans: readonly MatrixTick[];\n durationMs: number;\n /** The environment's run is still running: its elapsed time is still counting. */\n running: boolean;\n /** Wraps the chip, e.g. in the host router's link to the member run. Never called when static. */\n renderChip?: (chip: ReactNode) => ReactNode;\n /** Drawn beside the chip, e.g. how often the member was retried. */\n aside?: ReactNode;\n static?: boolean;\n};\n\n/**\n * One environment's column head in three fixed rows: its chip, the plans'\n * progress as a heatmap with the elapsed time, and the plan verdict naming\n * its units.\n */\nexport function MatrixEnvHeader({ context, counts, plans, durationMs, running, renderChip, aside, static: isStatic = false }: MatrixEnvHeaderProps) {\n if (plans.length !== counts.total) throw new Error(`${context} header has ${plans.length} plan ticks but counts ${counts.total} plans`);\n const done = counts.passed + counts.warned + counts.failed + counts.error;\n const chip = <EnvChip context={context} />;\n return (\n <div className={HEADER_GRID} data-env-header={context}>\n <div className={HEADER_ROW}>\n {renderChip && !isStatic ? renderChip(chip) : chip}\n {aside}\n </div>\n <div className={HEADER_ROW} title={`${done} of ${counts.total} plans finished`} data-env-progress=\"\">\n <MatrixHeatmap ticks={plans} unit=\"plans\" static={isStatic} />\n <span className=\"shrink-0 whitespace-nowrap text-[11px] tabular-nums text-foreground\">\n {done}/{counts.total} plans\n </span>\n <MatrixElapsed ms={durationMs} running={running} clock />\n </div>\n <div className={HEADER_ROW} data-env-verdict=\"\">\n <MatrixMix\n counts={{ passed: counts.passed, warned: counts.warned, running: counts.running, pending: counts.queued, failed: counts.failed, error: counts.error }}\n unit=\"plans\"\n always={[\"failed\"]}\n static={isStatic}\n />\n </div>\n </div>\n );\n}\n\nexport type MatrixUnavailableEnvHeaderProps = { context: string };\n\n/** An environment whose member run did not load, in the same three rows as MatrixEnvHeader. */\nexport function MatrixUnavailableEnvHeader({ context }: MatrixUnavailableEnvHeaderProps) {\n return (\n <div className={HEADER_GRID} data-env-header={context}>\n <div className={HEADER_ROW}>\n <EnvChip context={context} />\n </div>\n <div className={`${HEADER_ROW} text-[11px] font-medium ${MATRIX_MARKS.error.tone}`}>\n <MatrixMark mark=\"error\" label=\"\" />\n did not load\n </div>\n <div className={HEADER_ROW} aria-hidden=\"true\" />\n </div>\n );\n}\n"],"mappings":"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"}
@@ -17,8 +17,8 @@ export { genericCopySections, mergeCopySections, buildBrief, buildNodeBrief, bui
17
17
  export { type StatusCounts, type TestStatus, sum, sumNonTaskTests, aggregateStatusCounts, STATUS_LABELS, hasFailed, hasPending, testStatus, totalDuration, outcomeFor, type TestOutcome, statusToneFor, formatTestDuration, formatCount, humanizeName, collectFrameworks, collapseSingleChildChains, filterTests, } from './status.js';
18
18
  export { TEST_OUTCOMES, LINT_SEVERITIES, TEST_TOOLS, toolMark, toolKeyFor, type ResultMark, type LintSeverity, type ToolKind, type ToolMark, } from './marks.js';
19
19
  export { OutcomeIcon, LintSeverityIcon, ToolIcon } from './MarkIcons.js';
20
- export { MATRIX_MARKS, MATRIX_ORDER, MATRIX_PLAN_BAR, matrixMarkKey, repeatsMark, matrixBarClass, formatMatrixDuration, type MatrixMarkToken, type MatrixMarkKey, type MatrixCounts, type MatrixEnvCounts, } from './matrix-marks.js';
21
- export { MatrixMark, MatrixMix, MatrixElapsed, EmptyMatrixCell, MatrixLegend, EnvChip, MatrixEnvHeader, MatrixUnavailableEnvHeader, type MatrixMarkProps, type MatrixMixProps, type MatrixElapsedProps, type EmptyMatrixCellProps, type MatrixLegendProps, type EnvChipProps, type MatrixEnvHeaderProps, type MatrixUnavailableEnvHeaderProps, } from './MatrixMarks.js';
20
+ export { MATRIX_MARKS, MATRIX_ORDER, matrixMarkKey, repeatsMark, matrixBarClass, formatMatrixDuration, type MatrixMarkToken, type MatrixMarkKey, type MatrixCounts, type MatrixEnvCounts, } from './matrix-marks.js';
21
+ export { MatrixMark, MatrixMix, MatrixElapsed, MatrixHeatmap, EmptyMatrixCell, MatrixLegend, EnvChip, MatrixEnvHeader, MatrixUnavailableEnvHeader, type MatrixMarkProps, type MatrixMixProps, type MatrixElapsedProps, type MatrixHeatmapProps, type MatrixTick, type EmptyMatrixCellProps, type MatrixLegendProps, type EnvChipProps, type MatrixEnvHeaderProps, type MatrixUnavailableEnvHeaderProps, } from './MatrixMarks.js';
22
22
  export { slugify, annotateRoutePaths, findNodeByRoutePath } from './routePath.js';
23
23
  export { type FilterMode, type FilterState, type TestFilters, emptyTestFilters, decodeFilterState, encodeFilterState, cycleFilterState, matchesFilterState, filterStateToRecord, recordToFilterState, } from './filterState.js';
24
24
  export type { Test, TestSummary, TestAttempt, FailureDetail, FailureKind, GoTestContext, GinkgoContext, FixtureContext, TaskContext, RunMeta, Snapshot, SnapshotGit, SnapshotStatus, } from './types.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/data/test-runner/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/data/test-runner/index.ts"],"names":[],"mappings":"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"}
@@ -75,14 +75,6 @@ var MATRIX_MARKS = {
75
75
  }
76
76
  };
77
77
  var MATRIX_ORDER = Object.keys(MATRIX_MARKS);
78
- /** The plan outcomes an environment header's progress bar fills, left to right. */
79
- var MATRIX_PLAN_BAR = [
80
- "passed",
81
- "warned",
82
- "failed",
83
- "error",
84
- "running"
85
- ];
86
78
  function matrixMarkKey(outcome) {
87
79
  if (!Object.hasOwn(MATRIX_MARKS, outcome)) throw new Error(`matrix has no mark for outcome "${outcome}"`);
88
80
  return outcome;
@@ -95,9 +87,9 @@ function repeatsMark(counts, mark) {
95
87
  const nonZero = MATRIX_ORDER.filter((key) => (counts[key] ?? 0) > 0);
96
88
  return nonZero.length === 1 && nonZero[0] === mark;
97
89
  }
98
- /** A mark's progress-bar fill; static (print) drops its animate-* classes. */
90
+ /** A mark's progress-bar fill, the muted track for one with none; static (print) drops its animate-* classes. */
99
91
  function matrixBarClass(mark, isStatic) {
100
- const bar = MATRIX_MARKS[mark].bar;
92
+ const bar = MATRIX_MARKS[mark].bar ?? "bg-muted";
101
93
  return isStatic ? bar.split(" ").filter((c) => !c.startsWith("animate-")).join(" ") : bar;
102
94
  }
103
95
  /** The matrix's one duration format: 42s, 4m 12s, 1h 03m. */
@@ -110,7 +102,6 @@ function formatMatrixDuration(ms) {
110
102
  }
111
103
  exports.MATRIX_MARKS = MATRIX_MARKS;
112
104
  exports.MATRIX_ORDER = MATRIX_ORDER;
113
- exports.MATRIX_PLAN_BAR = MATRIX_PLAN_BAR;
114
105
  exports.formatMatrixDuration = formatMatrixDuration;
115
106
  exports.matrixBarClass = matrixBarClass;
116
107
  exports.matrixMarkKey = matrixMarkKey;
@@ -1 +1 @@
1
- {"version":3,"file":"matrix-marks.cjs","names":["UiPass","UiWarningCircle","UiSkipForward","UiLoader","UiProhibit","UiCircleX","UiWarningTriangleFilled","UiHourglass","UiCircleOutline"],"sources":["../../../src/data/test-runner/matrix-marks.ts"],"sourcesContent":["// The glyph vocabulary of a bulk test matrix (plans × environments): plan\n// cells, sub-steps, the environment header's verdict row and the legend all\n// read MATRIX_MARKS, in this order. The live web matrix and its printed report\n// draw from this one table. MatrixMarks.tsx renders it; this file holds only\n// the tokens and pure helpers (react/only-export-components).\n\nimport {\n UiCircleOutline,\n UiCircleX,\n UiHourglass,\n UiLoader,\n UiPass,\n UiProhibit,\n UiSkipForward,\n UiWarningCircle,\n UiWarningTriangleFilled,\n type IconComponent,\n} from \"../../icons\";\n\nexport type MatrixMarkToken = {\n icon: IconComponent;\n tone: string;\n /** Progress-bar fill; absent for states a bar leaves as its track. */\n bar?: string;\n label: string;\n legend?: string;\n /** Whether a sub-step spells the outcome out beside its glyph. */\n attention: boolean;\n spin?: boolean;\n};\n\nexport const MATRIX_MARKS = {\n passed: { icon: UiPass, tone: \"text-emerald-600 dark:text-emerald-400\", bar: \"bg-emerald-500\", label: \"passed\", attention: false },\n warned: { icon: UiWarningCircle, tone: \"text-amber-600 dark:text-amber-400\", bar: \"bg-amber-400\", label: \"warned\", attention: true },\n skipped: { icon: UiSkipForward, tone: \"text-slate-400 dark:text-slate-500\", bar: \"bg-slate-300 dark:bg-slate-600\", label: \"skipped\", attention: false },\n running: { icon: UiLoader, tone: \"text-blue-600 dark:text-blue-400\", bar: \"bg-blue-500 animate-pulse\", label: \"running\", attention: true, spin: true },\n aborted: { icon: UiProhibit, tone: \"text-red-400 dark:text-red-300\", bar: \"bg-red-300 dark:bg-red-800\", label: \"aborted\", attention: true },\n failed: { icon: UiCircleX, tone: \"text-red-600 dark:text-red-400\", bar: \"bg-red-600\", label: \"failed\", attention: true },\n error: { icon: UiWarningTriangleFilled, tone: \"text-red-600 dark:text-red-400\", bar: \"bg-red-800\", label: \"error\", legend: \"error · never started\", attention: true },\n pending: { icon: UiHourglass, tone: \"text-muted-foreground\", label: \"pending\", legend: \"pending · queued\", attention: false },\n absent: { icon: UiCircleOutline, tone: \"text-muted-foreground/60\", label: \"not in this run\", attention: false },\n} satisfies Record<string, MatrixMarkToken>;\n\nexport type MatrixMarkKey = keyof typeof MATRIX_MARKS;\nexport type MatrixCounts = Partial<Record<MatrixMarkKey, number>>;\n\nexport const MATRIX_ORDER = Object.keys(MATRIX_MARKS) as readonly MatrixMarkKey[];\n\n/** The plan outcomes an environment header's progress bar fills, left to right. */\nexport const MATRIX_PLAN_BAR = [\"passed\", \"warned\", \"failed\", \"error\", \"running\"] as const;\n\n/** One environment's plan totals, as its matrix column header reads them. */\nexport type MatrixEnvCounts = {\n passed: number;\n warned: number;\n failed: number;\n error: number;\n running: number;\n queued: number;\n total: number;\n};\n\nexport function matrixMarkKey(outcome: string): MatrixMarkKey {\n if (!Object.hasOwn(MATRIX_MARKS, outcome)) throw new Error(`matrix has no mark for outcome \"${outcome}\"`);\n return outcome as MatrixMarkKey;\n}\n\n/**\n * Whether a mix holds only the outcome a mark beside it already shows, so\n * drawing both would repeat the glyph.\n */\nexport function repeatsMark(counts: MatrixCounts, mark: MatrixMarkKey): boolean {\n const nonZero = MATRIX_ORDER.filter((key) => (counts[key] ?? 0) > 0);\n return nonZero.length === 1 && nonZero[0] === mark;\n}\n\n/** A mark's progress-bar fill; static (print) drops its animate-* classes. */\nexport function matrixBarClass(mark: (typeof MATRIX_PLAN_BAR)[number], isStatic: boolean): string {\n const bar: string = MATRIX_MARKS[mark].bar;\n return isStatic ? bar.split(\" \").filter((c) => !c.startsWith(\"animate-\")).join(\" \") : bar;\n}\n\n/** The matrix's one duration format: 42s, 4m 12s, 1h 03m. */\nexport function formatMatrixDuration(ms: number): string {\n const s = Math.round(ms / 1000);\n if (s < 60) return `${s}s`;\n const m = Math.floor(s / 60);\n if (m < 60) return `${m}m ${String(s % 60).padStart(2, \"0\")}s`;\n return `${Math.floor(m / 60)}h ${String(m % 60).padStart(2, \"0\")}m`;\n}\n"],"mappings":";;;;;;;;;;AA+BA,IAAa,eAAe;CAC1B,QAAQ;EAAE,MAAMA,eAAAA;EAAQ,MAAM;EAA0C,KAAK;EAAkB,OAAO;EAAU,WAAW;CAAM;CACjI,QAAQ;EAAE,MAAMC,wBAAAA;EAAiB,MAAM;EAAsC,KAAK;EAAgB,OAAO;EAAU,WAAW;CAAK;CACnI,SAAS;EAAE,MAAMC,sBAAAA;EAAe,MAAM;EAAsC,KAAK;EAAkC,OAAO;EAAW,WAAW;CAAM;CACtJ,SAAS;EAAE,MAAMC,iBAAAA;EAAU,MAAM;EAAoC,KAAK;EAA6B,OAAO;EAAW,WAAW;EAAM,MAAM;CAAK;CACrJ,SAAS;EAAE,MAAMC,mBAAAA;EAAY,MAAM;EAAkC,KAAK;EAA8B,OAAO;EAAW,WAAW;CAAK;CAC1I,QAAQ;EAAE,MAAMC,kBAAAA;EAAW,MAAM;EAAkC,KAAK;EAAc,OAAO;EAAU,WAAW;CAAK;CACvH,OAAO;EAAE,MAAMC,0BAAAA;EAAyB,MAAM;EAAkC,KAAK;EAAc,OAAO;EAAS,QAAQ;EAAyB,WAAW;CAAK;CACpK,SAAS;EAAE,MAAMC,oBAAAA;EAAa,MAAM;EAAyB,OAAO;EAAW,QAAQ;EAAoB,WAAW;CAAM;CAC5H,QAAQ;EAAE,MAAMC,wBAAAA;EAAiB,MAAM;EAA4B,OAAO;EAAmB,WAAW;CAAM;AAChH;AAKA,IAAa,eAAe,OAAO,KAAK,YAAY;;AAGpD,IAAa,kBAAkB;CAAC;CAAU;CAAU;CAAU;CAAS;AAAS;AAahF,SAAgB,cAAc,SAAgC;CAC5D,IAAI,CAAC,OAAO,OAAO,cAAc,OAAO,GAAG,MAAM,IAAI,MAAM,mCAAmC,QAAQ,EAAE;CACxG,OAAO;AACT;;;;;AAMA,SAAgB,YAAY,QAAsB,MAA8B;CAC9E,MAAM,UAAU,aAAa,QAAQ,SAAS,OAAO,QAAQ,KAAK,CAAC;CACnE,OAAO,QAAQ,WAAW,KAAK,QAAQ,OAAO;AAChD;;AAGA,SAAgB,eAAe,MAAwC,UAA2B;CAChG,MAAM,MAAc,aAAa,KAAK,CAAC;CACvC,OAAO,WAAW,IAAI,MAAM,GAAG,CAAC,CAAC,QAAQ,MAAM,CAAC,EAAE,WAAW,UAAU,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI;AACxF;;AAGA,SAAgB,qBAAqB,IAAoB;CACvD,MAAM,IAAI,KAAK,MAAM,KAAK,GAAI;CAC9B,IAAI,IAAI,IAAI,OAAO,GAAG,EAAE;CACxB,MAAM,IAAI,KAAK,MAAM,IAAI,EAAE;CAC3B,IAAI,IAAI,IAAI,OAAO,GAAG,EAAE,IAAI,OAAO,IAAI,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE;CAC5D,OAAO,GAAG,KAAK,MAAM,IAAI,EAAE,EAAE,IAAI,OAAO,IAAI,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE;AACnE"}
1
+ {"version":3,"file":"matrix-marks.cjs","names":["UiPass","UiWarningCircle","UiSkipForward","UiLoader","UiProhibit","UiCircleX","UiWarningTriangleFilled","UiHourglass","UiCircleOutline"],"sources":["../../../src/data/test-runner/matrix-marks.ts"],"sourcesContent":["// The glyph vocabulary of a bulk test matrix (plans × environments): plan\n// cells, sub-steps, the environment header's verdict row and the legend all\n// read MATRIX_MARKS, in this order. The live web matrix and its printed report\n// draw from this one table. MatrixMarks.tsx renders it; this file holds only\n// the tokens and pure helpers (react/only-export-components).\n\nimport {\n UiCircleOutline,\n UiCircleX,\n UiHourglass,\n UiLoader,\n UiPass,\n UiProhibit,\n UiSkipForward,\n UiWarningCircle,\n UiWarningTriangleFilled,\n type IconComponent,\n} from \"../../icons\";\n\nexport type MatrixMarkToken = {\n icon: IconComponent;\n tone: string;\n /** Progress-bar fill; absent for states a bar leaves as its track. */\n bar?: string;\n label: string;\n legend?: string;\n /** Whether a sub-step spells the outcome out beside its glyph. */\n attention: boolean;\n spin?: boolean;\n};\n\nexport const MATRIX_MARKS = {\n passed: { icon: UiPass, tone: \"text-emerald-600 dark:text-emerald-400\", bar: \"bg-emerald-500\", label: \"passed\", attention: false },\n warned: { icon: UiWarningCircle, tone: \"text-amber-600 dark:text-amber-400\", bar: \"bg-amber-400\", label: \"warned\", attention: true },\n skipped: { icon: UiSkipForward, tone: \"text-slate-400 dark:text-slate-500\", bar: \"bg-slate-300 dark:bg-slate-600\", label: \"skipped\", attention: false },\n running: { icon: UiLoader, tone: \"text-blue-600 dark:text-blue-400\", bar: \"bg-blue-500 animate-pulse\", label: \"running\", attention: true, spin: true },\n aborted: { icon: UiProhibit, tone: \"text-red-400 dark:text-red-300\", bar: \"bg-red-300 dark:bg-red-800\", label: \"aborted\", attention: true },\n failed: { icon: UiCircleX, tone: \"text-red-600 dark:text-red-400\", bar: \"bg-red-600\", label: \"failed\", attention: true },\n error: { icon: UiWarningTriangleFilled, tone: \"text-red-600 dark:text-red-400\", bar: \"bg-red-800\", label: \"error\", legend: \"error · never started\", attention: true },\n pending: { icon: UiHourglass, tone: \"text-muted-foreground\", label: \"pending\", legend: \"pending · queued\", attention: false },\n absent: { icon: UiCircleOutline, tone: \"text-muted-foreground/60\", label: \"not in this run\", attention: false },\n} satisfies Record<string, MatrixMarkToken>;\n\nexport type MatrixMarkKey = keyof typeof MATRIX_MARKS;\nexport type MatrixCounts = Partial<Record<MatrixMarkKey, number>>;\n\nexport const MATRIX_ORDER = Object.keys(MATRIX_MARKS) as readonly MatrixMarkKey[];\n\n/** One environment's plan totals, as its matrix column header reads them. */\nexport type MatrixEnvCounts = {\n passed: number;\n warned: number;\n failed: number;\n error: number;\n running: number;\n queued: number;\n total: number;\n};\n\nexport function matrixMarkKey(outcome: string): MatrixMarkKey {\n if (!Object.hasOwn(MATRIX_MARKS, outcome)) throw new Error(`matrix has no mark for outcome \"${outcome}\"`);\n return outcome as MatrixMarkKey;\n}\n\n/**\n * Whether a mix holds only the outcome a mark beside it already shows, so\n * drawing both would repeat the glyph.\n */\nexport function repeatsMark(counts: MatrixCounts, mark: MatrixMarkKey): boolean {\n const nonZero = MATRIX_ORDER.filter((key) => (counts[key] ?? 0) > 0);\n return nonZero.length === 1 && nonZero[0] === mark;\n}\n\n/** A mark's progress-bar fill, the muted track for one with none; static (print) drops its animate-* classes. */\nexport function matrixBarClass(mark: MatrixMarkKey, isStatic: boolean): string {\n const bar: string = (MATRIX_MARKS[mark] as MatrixMarkToken).bar ?? \"bg-muted\";\n return isStatic ? bar.split(\" \").filter((c) => !c.startsWith(\"animate-\")).join(\" \") : bar;\n}\n\n/** The matrix's one duration format: 42s, 4m 12s, 1h 03m. */\nexport function formatMatrixDuration(ms: number): string {\n const s = Math.round(ms / 1000);\n if (s < 60) return `${s}s`;\n const m = Math.floor(s / 60);\n if (m < 60) return `${m}m ${String(s % 60).padStart(2, \"0\")}s`;\n return `${Math.floor(m / 60)}h ${String(m % 60).padStart(2, \"0\")}m`;\n}\n"],"mappings":";;;;;;;;;;AA+BA,IAAa,eAAe;CAC1B,QAAQ;EAAE,MAAMA,eAAAA;EAAQ,MAAM;EAA0C,KAAK;EAAkB,OAAO;EAAU,WAAW;CAAM;CACjI,QAAQ;EAAE,MAAMC,wBAAAA;EAAiB,MAAM;EAAsC,KAAK;EAAgB,OAAO;EAAU,WAAW;CAAK;CACnI,SAAS;EAAE,MAAMC,sBAAAA;EAAe,MAAM;EAAsC,KAAK;EAAkC,OAAO;EAAW,WAAW;CAAM;CACtJ,SAAS;EAAE,MAAMC,iBAAAA;EAAU,MAAM;EAAoC,KAAK;EAA6B,OAAO;EAAW,WAAW;EAAM,MAAM;CAAK;CACrJ,SAAS;EAAE,MAAMC,mBAAAA;EAAY,MAAM;EAAkC,KAAK;EAA8B,OAAO;EAAW,WAAW;CAAK;CAC1I,QAAQ;EAAE,MAAMC,kBAAAA;EAAW,MAAM;EAAkC,KAAK;EAAc,OAAO;EAAU,WAAW;CAAK;CACvH,OAAO;EAAE,MAAMC,0BAAAA;EAAyB,MAAM;EAAkC,KAAK;EAAc,OAAO;EAAS,QAAQ;EAAyB,WAAW;CAAK;CACpK,SAAS;EAAE,MAAMC,oBAAAA;EAAa,MAAM;EAAyB,OAAO;EAAW,QAAQ;EAAoB,WAAW;CAAM;CAC5H,QAAQ;EAAE,MAAMC,wBAAAA;EAAiB,MAAM;EAA4B,OAAO;EAAmB,WAAW;CAAM;AAChH;AAKA,IAAa,eAAe,OAAO,KAAK,YAAY;AAapD,SAAgB,cAAc,SAAgC;CAC5D,IAAI,CAAC,OAAO,OAAO,cAAc,OAAO,GAAG,MAAM,IAAI,MAAM,mCAAmC,QAAQ,EAAE;CACxG,OAAO;AACT;;;;;AAMA,SAAgB,YAAY,QAAsB,MAA8B;CAC9E,MAAM,UAAU,aAAa,QAAQ,SAAS,OAAO,QAAQ,KAAK,CAAC;CACnE,OAAO,QAAQ,WAAW,KAAK,QAAQ,OAAO;AAChD;;AAGA,SAAgB,eAAe,MAAqB,UAA2B;CAC7E,MAAM,MAAe,aAAa,KAAK,CAAqB,OAAO;CACnE,OAAO,WAAW,IAAI,MAAM,GAAG,CAAC,CAAC,QAAQ,MAAM,CAAC,EAAE,WAAW,UAAU,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI;AACxF;;AAGA,SAAgB,qBAAqB,IAAoB;CACvD,MAAM,IAAI,KAAK,MAAM,KAAK,GAAI;CAC9B,IAAI,IAAI,IAAI,OAAO,GAAG,EAAE;CACxB,MAAM,IAAI,KAAK,MAAM,IAAI,EAAE;CAC3B,IAAI,IAAI,IAAI,OAAO,GAAG,EAAE,IAAI,OAAO,IAAI,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE;CAC5D,OAAO,GAAG,KAAK,MAAM,IAAI,EAAE,EAAE,IAAI,OAAO,IAAI,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE;AACnE"}
@@ -129,8 +129,6 @@ export declare const MATRIX_MARKS: {
129
129
  export type MatrixMarkKey = keyof typeof MATRIX_MARKS;
130
130
  export type MatrixCounts = Partial<Record<MatrixMarkKey, number>>;
131
131
  export declare const MATRIX_ORDER: readonly MatrixMarkKey[];
132
- /** The plan outcomes an environment header's progress bar fills, left to right. */
133
- export declare const MATRIX_PLAN_BAR: readonly ["passed", "warned", "failed", "error", "running"];
134
132
  /** One environment's plan totals, as its matrix column header reads them. */
135
133
  export type MatrixEnvCounts = {
136
134
  passed: number;
@@ -147,8 +145,8 @@ export declare function matrixMarkKey(outcome: string): MatrixMarkKey;
147
145
  * drawing both would repeat the glyph.
148
146
  */
149
147
  export declare function repeatsMark(counts: MatrixCounts, mark: MatrixMarkKey): boolean;
150
- /** A mark's progress-bar fill; static (print) drops its animate-* classes. */
151
- export declare function matrixBarClass(mark: (typeof MATRIX_PLAN_BAR)[number], isStatic: boolean): string;
148
+ /** A mark's progress-bar fill, the muted track for one with none; static (print) drops its animate-* classes. */
149
+ export declare function matrixBarClass(mark: MatrixMarkKey, isStatic: boolean): string;
152
150
  /** The matrix's one duration format: 42s, 4m 12s, 1h 03m. */
153
151
  export declare function formatMatrixDuration(ms: number): string;
154
152
  //# sourceMappingURL=matrix-marks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"matrix-marks.d.ts","sourceRoot":"","sources":["../../../src/data/test-runner/matrix-marks.ts"],"names":[],"mappings":"AAMA,OAAO,EAUL,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAErB,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAUkB,CAAC;AAE5C,MAAM,MAAM,aAAa,GAAG,MAAM,OAAO,YAAY,CAAC;AACtD,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC;AAElE,eAAO,MAAM,YAAY,EAAgC,SAAS,aAAa,EAAE,CAAC;AAElF,mFAAmF;AACnF,eAAO,MAAM,eAAe,6DAA8D,CAAC;AAE3F,6EAA6E;AAC7E,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAG5D;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAG9E;AAED,8EAA8E;AAC9E,wBAAgB,cAAc,CAAC,IAAI,EAAE,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,CAGhG;AAED,6DAA6D;AAC7D,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAMvD"}
1
+ {"version":3,"file":"matrix-marks.d.ts","sourceRoot":"","sources":["../../../src/data/test-runner/matrix-marks.ts"],"names":[],"mappings":"AAMA,OAAO,EAUL,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAErB,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAUkB,CAAC;AAE5C,MAAM,MAAM,aAAa,GAAG,MAAM,OAAO,YAAY,CAAC;AACtD,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC;AAElE,eAAO,MAAM,YAAY,EAAgC,SAAS,aAAa,EAAE,CAAC;AAElF,6EAA6E;AAC7E,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAG5D;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAG9E;AAED,iHAAiH;AACjH,wBAAgB,cAAc,CAAC,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,CAG7E;AAED,6DAA6D;AAC7D,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAMvD"}
@@ -75,14 +75,6 @@ var MATRIX_MARKS = {
75
75
  }
76
76
  };
77
77
  var MATRIX_ORDER = Object.keys(MATRIX_MARKS);
78
- /** The plan outcomes an environment header's progress bar fills, left to right. */
79
- var MATRIX_PLAN_BAR = [
80
- "passed",
81
- "warned",
82
- "failed",
83
- "error",
84
- "running"
85
- ];
86
78
  function matrixMarkKey(outcome) {
87
79
  if (!Object.hasOwn(MATRIX_MARKS, outcome)) throw new Error(`matrix has no mark for outcome "${outcome}"`);
88
80
  return outcome;
@@ -95,9 +87,9 @@ function repeatsMark(counts, mark) {
95
87
  const nonZero = MATRIX_ORDER.filter((key) => (counts[key] ?? 0) > 0);
96
88
  return nonZero.length === 1 && nonZero[0] === mark;
97
89
  }
98
- /** A mark's progress-bar fill; static (print) drops its animate-* classes. */
90
+ /** A mark's progress-bar fill, the muted track for one with none; static (print) drops its animate-* classes. */
99
91
  function matrixBarClass(mark, isStatic) {
100
- const bar = MATRIX_MARKS[mark].bar;
92
+ const bar = MATRIX_MARKS[mark].bar ?? "bg-muted";
101
93
  return isStatic ? bar.split(" ").filter((c) => !c.startsWith("animate-")).join(" ") : bar;
102
94
  }
103
95
  /** The matrix's one duration format: 42s, 4m 12s, 1h 03m. */
@@ -108,6 +100,6 @@ function formatMatrixDuration(ms) {
108
100
  if (m < 60) return `${m}m ${String(s % 60).padStart(2, "0")}s`;
109
101
  return `${Math.floor(m / 60)}h ${String(m % 60).padStart(2, "0")}m`;
110
102
  }
111
- export { MATRIX_MARKS, MATRIX_ORDER, MATRIX_PLAN_BAR, formatMatrixDuration, matrixBarClass, matrixMarkKey, repeatsMark };
103
+ export { MATRIX_MARKS, MATRIX_ORDER, formatMatrixDuration, matrixBarClass, matrixMarkKey, repeatsMark };
112
104
 
113
105
  //# sourceMappingURL=matrix-marks.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"matrix-marks.js","names":[],"sources":["../../../src/data/test-runner/matrix-marks.ts"],"sourcesContent":["// The glyph vocabulary of a bulk test matrix (plans × environments): plan\n// cells, sub-steps, the environment header's verdict row and the legend all\n// read MATRIX_MARKS, in this order. The live web matrix and its printed report\n// draw from this one table. MatrixMarks.tsx renders it; this file holds only\n// the tokens and pure helpers (react/only-export-components).\n\nimport {\n UiCircleOutline,\n UiCircleX,\n UiHourglass,\n UiLoader,\n UiPass,\n UiProhibit,\n UiSkipForward,\n UiWarningCircle,\n UiWarningTriangleFilled,\n type IconComponent,\n} from \"../../icons\";\n\nexport type MatrixMarkToken = {\n icon: IconComponent;\n tone: string;\n /** Progress-bar fill; absent for states a bar leaves as its track. */\n bar?: string;\n label: string;\n legend?: string;\n /** Whether a sub-step spells the outcome out beside its glyph. */\n attention: boolean;\n spin?: boolean;\n};\n\nexport const MATRIX_MARKS = {\n passed: { icon: UiPass, tone: \"text-emerald-600 dark:text-emerald-400\", bar: \"bg-emerald-500\", label: \"passed\", attention: false },\n warned: { icon: UiWarningCircle, tone: \"text-amber-600 dark:text-amber-400\", bar: \"bg-amber-400\", label: \"warned\", attention: true },\n skipped: { icon: UiSkipForward, tone: \"text-slate-400 dark:text-slate-500\", bar: \"bg-slate-300 dark:bg-slate-600\", label: \"skipped\", attention: false },\n running: { icon: UiLoader, tone: \"text-blue-600 dark:text-blue-400\", bar: \"bg-blue-500 animate-pulse\", label: \"running\", attention: true, spin: true },\n aborted: { icon: UiProhibit, tone: \"text-red-400 dark:text-red-300\", bar: \"bg-red-300 dark:bg-red-800\", label: \"aborted\", attention: true },\n failed: { icon: UiCircleX, tone: \"text-red-600 dark:text-red-400\", bar: \"bg-red-600\", label: \"failed\", attention: true },\n error: { icon: UiWarningTriangleFilled, tone: \"text-red-600 dark:text-red-400\", bar: \"bg-red-800\", label: \"error\", legend: \"error · never started\", attention: true },\n pending: { icon: UiHourglass, tone: \"text-muted-foreground\", label: \"pending\", legend: \"pending · queued\", attention: false },\n absent: { icon: UiCircleOutline, tone: \"text-muted-foreground/60\", label: \"not in this run\", attention: false },\n} satisfies Record<string, MatrixMarkToken>;\n\nexport type MatrixMarkKey = keyof typeof MATRIX_MARKS;\nexport type MatrixCounts = Partial<Record<MatrixMarkKey, number>>;\n\nexport const MATRIX_ORDER = Object.keys(MATRIX_MARKS) as readonly MatrixMarkKey[];\n\n/** The plan outcomes an environment header's progress bar fills, left to right. */\nexport const MATRIX_PLAN_BAR = [\"passed\", \"warned\", \"failed\", \"error\", \"running\"] as const;\n\n/** One environment's plan totals, as its matrix column header reads them. */\nexport type MatrixEnvCounts = {\n passed: number;\n warned: number;\n failed: number;\n error: number;\n running: number;\n queued: number;\n total: number;\n};\n\nexport function matrixMarkKey(outcome: string): MatrixMarkKey {\n if (!Object.hasOwn(MATRIX_MARKS, outcome)) throw new Error(`matrix has no mark for outcome \"${outcome}\"`);\n return outcome as MatrixMarkKey;\n}\n\n/**\n * Whether a mix holds only the outcome a mark beside it already shows, so\n * drawing both would repeat the glyph.\n */\nexport function repeatsMark(counts: MatrixCounts, mark: MatrixMarkKey): boolean {\n const nonZero = MATRIX_ORDER.filter((key) => (counts[key] ?? 0) > 0);\n return nonZero.length === 1 && nonZero[0] === mark;\n}\n\n/** A mark's progress-bar fill; static (print) drops its animate-* classes. */\nexport function matrixBarClass(mark: (typeof MATRIX_PLAN_BAR)[number], isStatic: boolean): string {\n const bar: string = MATRIX_MARKS[mark].bar;\n return isStatic ? bar.split(\" \").filter((c) => !c.startsWith(\"animate-\")).join(\" \") : bar;\n}\n\n/** The matrix's one duration format: 42s, 4m 12s, 1h 03m. */\nexport function formatMatrixDuration(ms: number): string {\n const s = Math.round(ms / 1000);\n if (s < 60) return `${s}s`;\n const m = Math.floor(s / 60);\n if (m < 60) return `${m}m ${String(s % 60).padStart(2, \"0\")}s`;\n return `${Math.floor(m / 60)}h ${String(m % 60).padStart(2, \"0\")}m`;\n}\n"],"mappings":";;;;;;;;;;AA+BA,IAAa,eAAe;CAC1B,QAAQ;EAAE,MAAM;EAAQ,MAAM;EAA0C,KAAK;EAAkB,OAAO;EAAU,WAAW;CAAM;CACjI,QAAQ;EAAE,MAAM;EAAiB,MAAM;EAAsC,KAAK;EAAgB,OAAO;EAAU,WAAW;CAAK;CACnI,SAAS;EAAE,MAAM;EAAe,MAAM;EAAsC,KAAK;EAAkC,OAAO;EAAW,WAAW;CAAM;CACtJ,SAAS;EAAE,MAAM;EAAU,MAAM;EAAoC,KAAK;EAA6B,OAAO;EAAW,WAAW;EAAM,MAAM;CAAK;CACrJ,SAAS;EAAE,MAAM;EAAY,MAAM;EAAkC,KAAK;EAA8B,OAAO;EAAW,WAAW;CAAK;CAC1I,QAAQ;EAAE,MAAM;EAAW,MAAM;EAAkC,KAAK;EAAc,OAAO;EAAU,WAAW;CAAK;CACvH,OAAO;EAAE,MAAM;EAAyB,MAAM;EAAkC,KAAK;EAAc,OAAO;EAAS,QAAQ;EAAyB,WAAW;CAAK;CACpK,SAAS;EAAE,MAAM;EAAa,MAAM;EAAyB,OAAO;EAAW,QAAQ;EAAoB,WAAW;CAAM;CAC5H,QAAQ;EAAE,MAAM;EAAiB,MAAM;EAA4B,OAAO;EAAmB,WAAW;CAAM;AAChH;AAKA,IAAa,eAAe,OAAO,KAAK,YAAY;;AAGpD,IAAa,kBAAkB;CAAC;CAAU;CAAU;CAAU;CAAS;AAAS;AAahF,SAAgB,cAAc,SAAgC;CAC5D,IAAI,CAAC,OAAO,OAAO,cAAc,OAAO,GAAG,MAAM,IAAI,MAAM,mCAAmC,QAAQ,EAAE;CACxG,OAAO;AACT;;;;;AAMA,SAAgB,YAAY,QAAsB,MAA8B;CAC9E,MAAM,UAAU,aAAa,QAAQ,SAAS,OAAO,QAAQ,KAAK,CAAC;CACnE,OAAO,QAAQ,WAAW,KAAK,QAAQ,OAAO;AAChD;;AAGA,SAAgB,eAAe,MAAwC,UAA2B;CAChG,MAAM,MAAc,aAAa,KAAK,CAAC;CACvC,OAAO,WAAW,IAAI,MAAM,GAAG,CAAC,CAAC,QAAQ,MAAM,CAAC,EAAE,WAAW,UAAU,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI;AACxF;;AAGA,SAAgB,qBAAqB,IAAoB;CACvD,MAAM,IAAI,KAAK,MAAM,KAAK,GAAI;CAC9B,IAAI,IAAI,IAAI,OAAO,GAAG,EAAE;CACxB,MAAM,IAAI,KAAK,MAAM,IAAI,EAAE;CAC3B,IAAI,IAAI,IAAI,OAAO,GAAG,EAAE,IAAI,OAAO,IAAI,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE;CAC5D,OAAO,GAAG,KAAK,MAAM,IAAI,EAAE,EAAE,IAAI,OAAO,IAAI,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE;AACnE"}
1
+ {"version":3,"file":"matrix-marks.js","names":[],"sources":["../../../src/data/test-runner/matrix-marks.ts"],"sourcesContent":["// The glyph vocabulary of a bulk test matrix (plans × environments): plan\n// cells, sub-steps, the environment header's verdict row and the legend all\n// read MATRIX_MARKS, in this order. The live web matrix and its printed report\n// draw from this one table. MatrixMarks.tsx renders it; this file holds only\n// the tokens and pure helpers (react/only-export-components).\n\nimport {\n UiCircleOutline,\n UiCircleX,\n UiHourglass,\n UiLoader,\n UiPass,\n UiProhibit,\n UiSkipForward,\n UiWarningCircle,\n UiWarningTriangleFilled,\n type IconComponent,\n} from \"../../icons\";\n\nexport type MatrixMarkToken = {\n icon: IconComponent;\n tone: string;\n /** Progress-bar fill; absent for states a bar leaves as its track. */\n bar?: string;\n label: string;\n legend?: string;\n /** Whether a sub-step spells the outcome out beside its glyph. */\n attention: boolean;\n spin?: boolean;\n};\n\nexport const MATRIX_MARKS = {\n passed: { icon: UiPass, tone: \"text-emerald-600 dark:text-emerald-400\", bar: \"bg-emerald-500\", label: \"passed\", attention: false },\n warned: { icon: UiWarningCircle, tone: \"text-amber-600 dark:text-amber-400\", bar: \"bg-amber-400\", label: \"warned\", attention: true },\n skipped: { icon: UiSkipForward, tone: \"text-slate-400 dark:text-slate-500\", bar: \"bg-slate-300 dark:bg-slate-600\", label: \"skipped\", attention: false },\n running: { icon: UiLoader, tone: \"text-blue-600 dark:text-blue-400\", bar: \"bg-blue-500 animate-pulse\", label: \"running\", attention: true, spin: true },\n aborted: { icon: UiProhibit, tone: \"text-red-400 dark:text-red-300\", bar: \"bg-red-300 dark:bg-red-800\", label: \"aborted\", attention: true },\n failed: { icon: UiCircleX, tone: \"text-red-600 dark:text-red-400\", bar: \"bg-red-600\", label: \"failed\", attention: true },\n error: { icon: UiWarningTriangleFilled, tone: \"text-red-600 dark:text-red-400\", bar: \"bg-red-800\", label: \"error\", legend: \"error · never started\", attention: true },\n pending: { icon: UiHourglass, tone: \"text-muted-foreground\", label: \"pending\", legend: \"pending · queued\", attention: false },\n absent: { icon: UiCircleOutline, tone: \"text-muted-foreground/60\", label: \"not in this run\", attention: false },\n} satisfies Record<string, MatrixMarkToken>;\n\nexport type MatrixMarkKey = keyof typeof MATRIX_MARKS;\nexport type MatrixCounts = Partial<Record<MatrixMarkKey, number>>;\n\nexport const MATRIX_ORDER = Object.keys(MATRIX_MARKS) as readonly MatrixMarkKey[];\n\n/** One environment's plan totals, as its matrix column header reads them. */\nexport type MatrixEnvCounts = {\n passed: number;\n warned: number;\n failed: number;\n error: number;\n running: number;\n queued: number;\n total: number;\n};\n\nexport function matrixMarkKey(outcome: string): MatrixMarkKey {\n if (!Object.hasOwn(MATRIX_MARKS, outcome)) throw new Error(`matrix has no mark for outcome \"${outcome}\"`);\n return outcome as MatrixMarkKey;\n}\n\n/**\n * Whether a mix holds only the outcome a mark beside it already shows, so\n * drawing both would repeat the glyph.\n */\nexport function repeatsMark(counts: MatrixCounts, mark: MatrixMarkKey): boolean {\n const nonZero = MATRIX_ORDER.filter((key) => (counts[key] ?? 0) > 0);\n return nonZero.length === 1 && nonZero[0] === mark;\n}\n\n/** A mark's progress-bar fill, the muted track for one with none; static (print) drops its animate-* classes. */\nexport function matrixBarClass(mark: MatrixMarkKey, isStatic: boolean): string {\n const bar: string = (MATRIX_MARKS[mark] as MatrixMarkToken).bar ?? \"bg-muted\";\n return isStatic ? bar.split(\" \").filter((c) => !c.startsWith(\"animate-\")).join(\" \") : bar;\n}\n\n/** The matrix's one duration format: 42s, 4m 12s, 1h 03m. */\nexport function formatMatrixDuration(ms: number): string {\n const s = Math.round(ms / 1000);\n if (s < 60) return `${s}s`;\n const m = Math.floor(s / 60);\n if (m < 60) return `${m}m ${String(s % 60).padStart(2, \"0\")}s`;\n return `${Math.floor(m / 60)}h ${String(m % 60).padStart(2, \"0\")}m`;\n}\n"],"mappings":";;;;;;;;;;AA+BA,IAAa,eAAe;CAC1B,QAAQ;EAAE,MAAM;EAAQ,MAAM;EAA0C,KAAK;EAAkB,OAAO;EAAU,WAAW;CAAM;CACjI,QAAQ;EAAE,MAAM;EAAiB,MAAM;EAAsC,KAAK;EAAgB,OAAO;EAAU,WAAW;CAAK;CACnI,SAAS;EAAE,MAAM;EAAe,MAAM;EAAsC,KAAK;EAAkC,OAAO;EAAW,WAAW;CAAM;CACtJ,SAAS;EAAE,MAAM;EAAU,MAAM;EAAoC,KAAK;EAA6B,OAAO;EAAW,WAAW;EAAM,MAAM;CAAK;CACrJ,SAAS;EAAE,MAAM;EAAY,MAAM;EAAkC,KAAK;EAA8B,OAAO;EAAW,WAAW;CAAK;CAC1I,QAAQ;EAAE,MAAM;EAAW,MAAM;EAAkC,KAAK;EAAc,OAAO;EAAU,WAAW;CAAK;CACvH,OAAO;EAAE,MAAM;EAAyB,MAAM;EAAkC,KAAK;EAAc,OAAO;EAAS,QAAQ;EAAyB,WAAW;CAAK;CACpK,SAAS;EAAE,MAAM;EAAa,MAAM;EAAyB,OAAO;EAAW,QAAQ;EAAoB,WAAW;CAAM;CAC5H,QAAQ;EAAE,MAAM;EAAiB,MAAM;EAA4B,OAAO;EAAmB,WAAW;CAAM;AAChH;AAKA,IAAa,eAAe,OAAO,KAAK,YAAY;AAapD,SAAgB,cAAc,SAAgC;CAC5D,IAAI,CAAC,OAAO,OAAO,cAAc,OAAO,GAAG,MAAM,IAAI,MAAM,mCAAmC,QAAQ,EAAE;CACxG,OAAO;AACT;;;;;AAMA,SAAgB,YAAY,QAAsB,MAA8B;CAC9E,MAAM,UAAU,aAAa,QAAQ,SAAS,OAAO,QAAQ,KAAK,CAAC;CACnE,OAAO,QAAQ,WAAW,KAAK,QAAQ,OAAO;AAChD;;AAGA,SAAgB,eAAe,MAAqB,UAA2B;CAC7E,MAAM,MAAe,aAAa,KAAK,CAAqB,OAAO;CACnE,OAAO,WAAW,IAAI,MAAM,GAAG,CAAC,CAAC,QAAQ,MAAM,CAAC,EAAE,WAAW,UAAU,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI;AACxF;;AAGA,SAAgB,qBAAqB,IAAoB;CACvD,MAAM,IAAI,KAAK,MAAM,KAAK,GAAI;CAC9B,IAAI,IAAI,IAAI,OAAO,GAAG,EAAE;CACxB,MAAM,IAAI,KAAK,MAAM,IAAI,EAAE;CAC3B,IAAI,IAAI,IAAI,OAAO,GAAG,EAAE,IAAI,OAAO,IAAI,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE;CAC5D,OAAO,GAAG,KAAK,MAAM,IAAI,EAAE,EAAE,IAAI,OAAO,IAAI,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE;AACnE"}
@@ -14,9 +14,9 @@ function detectMode() {
14
14
  /** Resolve build + runtime version metadata. */
15
15
  function getVersionInfo() {
16
16
  return {
17
- commit: read(() => "84bbbe9a3", ""),
18
- tag: read(() => "clicky-ui@0.3.53", ""),
19
- date: read(() => "2026-10-27T17:38:02.772Z", ""),
17
+ commit: read(() => "ee67b513d", ""),
18
+ tag: read(() => "clicky-ui@0.3.54", ""),
19
+ date: read(() => "2026-11-01T17:35:12.318Z", ""),
20
20
  dirty: read(() => true, false),
21
21
  mode: detectMode()
22
22
  };
@@ -14,9 +14,9 @@ function detectMode() {
14
14
  /** Resolve build + runtime version metadata. */
15
15
  function getVersionInfo() {
16
16
  return {
17
- commit: read(() => "84bbbe9a3", ""),
18
- tag: read(() => "clicky-ui@0.3.53", ""),
19
- date: read(() => "2026-10-27T17:37:40.605Z", ""),
17
+ commit: read(() => "ee67b513d", ""),
18
+ tag: read(() => "clicky-ui@0.3.54", ""),
19
+ date: read(() => "2026-11-01T17:34:39.851Z", ""),
20
20
  dirty: read(() => true, false),
21
21
  mode: detectMode()
22
22
  };
package/dist/data.cjs CHANGED
@@ -883,12 +883,12 @@ exports.MARKDOWN_SYNTAX_DOCUMENT = require_markdown_syntax.MARKDOWN_SYNTAX_DOCUM
883
883
  exports.MARKDOWN_SYNTAX_SECTIONS = require_markdown_syntax.MARKDOWN_SYNTAX_SECTIONS;
884
884
  exports.MATRIX_MARKS = require_matrix_marks.MATRIX_MARKS;
885
885
  exports.MATRIX_ORDER = require_matrix_marks.MATRIX_ORDER;
886
- exports.MATRIX_PLAN_BAR = require_matrix_marks.MATRIX_PLAN_BAR;
887
886
  exports.MAX_INLINE_SELECTION_ACTIONS = require_selectionActionSplit.MAX_INLINE_SELECTION_ACTIONS;
888
887
  exports.Markdown = require_Markdown.Markdown;
889
888
  exports.MarkdownEditor = require_MarkdownEditor.MarkdownEditor;
890
889
  exports.MatrixElapsed = require_MatrixMarks.MatrixElapsed;
891
890
  exports.MatrixEnvHeader = require_MatrixMarks.MatrixEnvHeader;
891
+ exports.MatrixHeatmap = require_MatrixMarks.MatrixHeatmap;
892
892
  exports.MatrixLegend = require_MatrixMarks.MatrixLegend;
893
893
  exports.MatrixMark = require_MatrixMarks.MatrixMark;
894
894
  exports.MatrixMix = require_MatrixMarks.MatrixMix;