@flanksource/clicky-ui 0.3.53 → 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.
- package/dist/data/TaskManager.cjs +39 -32
- package/dist/data/TaskManager.cjs.map +1 -1
- package/dist/data/TaskManager.d.ts +6 -1
- package/dist/data/TaskManager.d.ts.map +1 -1
- package/dist/data/TaskManager.js +39 -32
- package/dist/data/TaskManager.js.map +1 -1
- package/dist/data/clicky-export/ClickyExportDialog.cjs +4 -3
- package/dist/data/clicky-export/ClickyExportDialog.cjs.map +1 -1
- package/dist/data/clicky-export/ClickyExportDialog.d.ts +4 -1
- package/dist/data/clicky-export/ClickyExportDialog.d.ts.map +1 -1
- package/dist/data/clicky-export/ClickyExportDialog.js +4 -3
- package/dist/data/clicky-export/ClickyExportDialog.js.map +1 -1
- package/dist/data/test-runner/MatrixMarks.cjs +26 -14
- package/dist/data/test-runner/MatrixMarks.cjs.map +1 -1
- package/dist/data/test-runner/MatrixMarks.d.ts +18 -2
- package/dist/data/test-runner/MatrixMarks.d.ts.map +1 -1
- package/dist/data/test-runner/MatrixMarks.js +27 -16
- package/dist/data/test-runner/MatrixMarks.js.map +1 -1
- package/dist/data/test-runner/index.d.ts +2 -2
- package/dist/data/test-runner/index.d.ts.map +1 -1
- package/dist/data/test-runner/matrix-marks.cjs +2 -11
- package/dist/data/test-runner/matrix-marks.cjs.map +1 -1
- package/dist/data/test-runner/matrix-marks.d.ts +2 -4
- package/dist/data/test-runner/matrix-marks.d.ts.map +1 -1
- package/dist/data/test-runner/matrix-marks.js +3 -11
- package/dist/data/test-runner/matrix-marks.js.map +1 -1
- package/dist/data/version-info.cjs +3 -3
- package/dist/data/version-info.js +3 -3
- package/dist/data.cjs +1 -1
- package/dist/data.js +3 -3
- package/dist/hooks/use-task-run.cjs +22 -9
- package/dist/hooks/use-task-run.cjs.map +1 -1
- package/dist/hooks/use-task-run.d.ts +2 -0
- package/dist/hooks/use-task-run.d.ts.map +1 -1
- package/dist/hooks/use-task-run.js +22 -9
- package/dist/hooks/use-task-run.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +3 -3
- package/dist/styles.css +1 -1
- package/package.json +1 -1
|
@@ -12,7 +12,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
12
12
|
* every range — which pushed everything else in that menu out of reach and
|
|
13
13
|
* still truncated the one thing worth reading: what each range costs.
|
|
14
14
|
*/
|
|
15
|
-
function ClickyExportDialog({ open, onClose, title = "Export", formats, scopes, onDownload }) {
|
|
15
|
+
function ClickyExportDialog({ open, onClose, title = "Export", formats, scopes, onDownload, pendingContent, allowCloseWhilePending = false }) {
|
|
16
16
|
const [format, setFormat] = useState(formats[0]?.format);
|
|
17
17
|
const [scope, setScope] = useState(scopes[0]?.scope);
|
|
18
18
|
const [pending, setPending] = useState(false);
|
|
@@ -48,8 +48,8 @@ function ClickyExportDialog({ open, onClose, title = "Export", formats, scopes,
|
|
|
48
48
|
children: [/* @__PURE__ */ jsx(Button, {
|
|
49
49
|
variant: "outline",
|
|
50
50
|
onClick: onClose,
|
|
51
|
-
disabled: pending,
|
|
52
|
-
children: "Cancel"
|
|
51
|
+
disabled: pending && !allowCloseWhilePending,
|
|
52
|
+
children: pending && allowCloseWhilePending ? "Continue in background" : "Cancel"
|
|
53
53
|
}), /* @__PURE__ */ jsx(Button, {
|
|
54
54
|
onClick: () => void download(),
|
|
55
55
|
loading: pending,
|
|
@@ -60,6 +60,7 @@ function ClickyExportDialog({ open, onClose, title = "Export", formats, scopes,
|
|
|
60
60
|
children: /* @__PURE__ */ jsxs("div", {
|
|
61
61
|
className: "space-y-4",
|
|
62
62
|
children: [
|
|
63
|
+
pending && pendingContent,
|
|
63
64
|
error && /* @__PURE__ */ jsx("div", {
|
|
64
65
|
role: "alert",
|
|
65
66
|
className: "rounded-md border border-destructive/40 bg-destructive/5 p-3 text-sm text-destructive",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClickyExportDialog.js","names":[],"sources":["../../../src/data/clicky-export/ClickyExportDialog.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport { Button } from \"../../components/button\";\nimport { Modal } from \"../../overlay/Modal\";\nimport { Icon, type StaticIconComponent } from \"../Icon\";\nimport { cn } from \"../../lib/utils\";\n\n/** One format the endpoint advertises, already resolved for display. */\nexport type ClickyExportFormatOption = {\n /** Value handed back to `onDownload`. */\n format: string;\n label: string;\n /** What the format is for. */\n description?: string | undefined;\n icon?: StaticIconComponent | undefined;\n iconClassName?: string | undefined;\n};\n\n/** One result range the endpoint advertises. */\nexport type ClickyExportScopeOption = {\n /** Value handed back to `onDownload`; undefined for a legacy endpoint. */\n scope: string | undefined;\n label: string;\n /**\n * What this range costs or caps — \"Limited to 1,000 rows\", \"Streams rows as\n * they are read\". Per format, because a PDF's ceiling is not a CSV's.\n */\n note?: ((format: string) => string | undefined) | undefined;\n};\n\nexport type ClickyExportDialogProps = {\n open: boolean;\n onClose: () => void;\n title?: string;\n formats: ClickyExportFormatOption[];\n scopes: ClickyExportScopeOption[];\n /** Runs the export. Rejecting shows the reason without closing the dialog. */\n onDownload: (request: {\n format: string;\n scope: string | undefined;\n }) => Promise<void> | void;\n};\n\n/**\n * ClickyExportDialog picks a format and a range, then downloads.\n *\n * It exists because the same choice as a menu was 16 rows — every format times\n * every range — which pushed everything else in that menu out of reach and\n * still truncated the one thing worth reading: what each range costs.\n */\nexport function ClickyExportDialog({\n open,\n onClose,\n title = \"Export\",\n formats,\n scopes,\n onDownload,\n}: ClickyExportDialogProps) {\n const [format, setFormat] = useState(formats[0]?.format);\n const [scope, setScope] = useState(scopes[0]?.scope);\n const [pending, setPending] = useState(false);\n const [error, setError] = useState(\"\");\n\n // Reopening starts from a clean slate: the error belongs to the attempt that\n // produced it, not to the next one.\n useEffect(() => {\n if (open) setError(\"\");\n }, [open]);\n\n const activeScope = scopes.find((option) => option.scope === scope);\n\n const download = async () => {\n if (!format) return;\n setPending(true);\n setError(\"\");\n try {\n await onDownload({ format, scope });\n onClose();\n } catch (cause) {\n setError(cause instanceof Error ? cause.message : \"The export failed\");\n } finally {\n setPending(false);\n }\n };\n\n return (\n <Modal\n open={open}\n onClose={onClose}\n title={title}\n size=\"lg\"\n closeOnEsc\n footer={\n <div className=\"flex items-center justify-end gap-2\">\n <Button variant=\"outline\" onClick={onClose} disabled={pending}>\n Cancel\n </Button>\n <Button\n onClick={() => void download()}\n loading={pending}\n disabled={!format}\n >\n Download\n </Button>\n </div>\n }\n >\n <div className=\"space-y-4\">\n {error && (\n <div\n role=\"alert\"\n className=\"rounded-md border border-destructive/40 bg-destructive/5 p-3 text-sm text-destructive\"\n >\n {error}\n </div>\n )}\n\n {scopes.length > 1 ? (\n <fieldset>\n <legend className=\"mb-1.5 text-[11px] font-medium uppercase tracking-wide text-muted-foreground\">\n Rows\n </legend>\n <div className=\"flex flex-wrap gap-2\">\n {scopes.map((option) => (\n <label\n key={option.scope ?? \"default\"}\n className={cn(\n \"cursor-pointer rounded-md border px-3 py-1.5 text-sm transition-colors\",\n option.scope === scope\n ? \"border-foreground/20 bg-accent text-accent-foreground\"\n : \"border-input hover:bg-accent hover:text-accent-foreground\",\n )}\n >\n <input\n type=\"radio\"\n name=\"clicky-export-scope\"\n // Named explicitly: the input is visually hidden behind its\n // own styled label, so nothing else gives it a name.\n aria-label={option.label}\n className=\"sr-only\"\n checked={option.scope === scope}\n onChange={() => setScope(option.scope)}\n />\n {option.label}\n </label>\n ))}\n </div>\n </fieldset>\n ) : (\n scopes[0]?.label && (\n <p className=\"text-sm text-muted-foreground\">{scopes[0].label}</p>\n )\n )}\n\n <fieldset>\n <legend className=\"mb-1.5 text-[11px] font-medium uppercase tracking-wide text-muted-foreground\">\n Format\n </legend>\n <div className=\"grid gap-1 sm:grid-cols-2\">\n {formats.map((option) => {\n const note = activeScope?.note?.(option.format);\n return (\n <label\n key={option.format}\n className={cn(\n \"flex cursor-pointer items-start gap-2 rounded-md border px-3 py-2 text-left transition-colors\",\n option.format === format\n ? \"border-foreground/20 bg-accent text-accent-foreground\"\n : \"border-transparent hover:bg-accent hover:text-accent-foreground\",\n )}\n >\n <input\n type=\"radio\"\n name=\"clicky-export-format\"\n aria-label={option.label}\n className=\"sr-only\"\n checked={option.format === format}\n onChange={() => setFormat(option.format)}\n />\n {option.icon && (\n <Icon\n icon={option.icon}\n className={cn(\n \"mt-0.5 shrink-0 text-sm\",\n option.iconClassName ?? \"text-muted-foreground\",\n )}\n />\n )}\n <span className=\"min-w-0\">\n <span className=\"block text-sm font-medium\">\n {option.label}\n </span>\n {option.description && (\n <span className=\"mt-0.5 block text-xs text-muted-foreground\">\n {option.description}\n </span>\n )}\n {note && (\n <span className=\"mt-0.5 block text-xs text-amber-700 [[data-theme=dark]_&]:text-amber-400\">\n {note}\n </span>\n )}\n </span>\n </label>\n );\n })}\n </div>\n </fieldset>\n\n </div>\n </Modal>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ClickyExportDialog.js","names":[],"sources":["../../../src/data/clicky-export/ClickyExportDialog.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { Button } from \"../../components/button\";\nimport { Modal } from \"../../overlay/Modal\";\nimport { Icon, type StaticIconComponent } from \"../Icon\";\nimport { cn } from \"../../lib/utils\";\n\n/** One format the endpoint advertises, already resolved for display. */\nexport type ClickyExportFormatOption = {\n /** Value handed back to `onDownload`. */\n format: string;\n label: string;\n /** What the format is for. */\n description?: string | undefined;\n icon?: StaticIconComponent | undefined;\n iconClassName?: string | undefined;\n};\n\n/** One result range the endpoint advertises. */\nexport type ClickyExportScopeOption = {\n /** Value handed back to `onDownload`; undefined for a legacy endpoint. */\n scope: string | undefined;\n label: string;\n /**\n * What this range costs or caps — \"Limited to 1,000 rows\", \"Streams rows as\n * they are read\". Per format, because a PDF's ceiling is not a CSV's.\n */\n note?: ((format: string) => string | undefined) | undefined;\n};\n\nexport type ClickyExportDialogProps = {\n open: boolean;\n onClose: () => void;\n title?: string;\n formats: ClickyExportFormatOption[];\n scopes: ClickyExportScopeOption[];\n pendingContent?: ReactNode;\n allowCloseWhilePending?: boolean;\n /** Runs the export. Rejecting shows the reason without closing the dialog. */\n onDownload: (request: {\n format: string;\n scope: string | undefined;\n }) => Promise<void> | void;\n};\n\n/**\n * ClickyExportDialog picks a format and a range, then downloads.\n *\n * It exists because the same choice as a menu was 16 rows — every format times\n * every range — which pushed everything else in that menu out of reach and\n * still truncated the one thing worth reading: what each range costs.\n */\nexport function ClickyExportDialog({\n open,\n onClose,\n title = \"Export\",\n formats,\n scopes,\n onDownload,\n pendingContent,\n allowCloseWhilePending = false,\n}: ClickyExportDialogProps) {\n const [format, setFormat] = useState(formats[0]?.format);\n const [scope, setScope] = useState(scopes[0]?.scope);\n const [pending, setPending] = useState(false);\n const [error, setError] = useState(\"\");\n\n // Reopening starts from a clean slate: the error belongs to the attempt that\n // produced it, not to the next one.\n useEffect(() => {\n if (open) setError(\"\");\n }, [open]);\n\n const activeScope = scopes.find((option) => option.scope === scope);\n\n const download = async () => {\n if (!format) return;\n setPending(true);\n setError(\"\");\n try {\n await onDownload({ format, scope });\n onClose();\n } catch (cause) {\n setError(cause instanceof Error ? cause.message : \"The export failed\");\n } finally {\n setPending(false);\n }\n };\n\n return (\n <Modal\n open={open}\n onClose={onClose}\n title={title}\n size=\"lg\"\n closeOnEsc\n footer={\n <div className=\"flex items-center justify-end gap-2\">\n <Button variant=\"outline\" onClick={onClose} disabled={pending && !allowCloseWhilePending}>\n {pending && allowCloseWhilePending ? \"Continue in background\" : \"Cancel\"}\n </Button>\n <Button\n onClick={() => void download()}\n loading={pending}\n disabled={!format}\n >\n Download\n </Button>\n </div>\n }\n >\n <div className=\"space-y-4\">\n {pending && pendingContent}\n {error && (\n <div\n role=\"alert\"\n className=\"rounded-md border border-destructive/40 bg-destructive/5 p-3 text-sm text-destructive\"\n >\n {error}\n </div>\n )}\n\n {scopes.length > 1 ? (\n <fieldset>\n <legend className=\"mb-1.5 text-[11px] font-medium uppercase tracking-wide text-muted-foreground\">\n Rows\n </legend>\n <div className=\"flex flex-wrap gap-2\">\n {scopes.map((option) => (\n <label\n key={option.scope ?? \"default\"}\n className={cn(\n \"cursor-pointer rounded-md border px-3 py-1.5 text-sm transition-colors\",\n option.scope === scope\n ? \"border-foreground/20 bg-accent text-accent-foreground\"\n : \"border-input hover:bg-accent hover:text-accent-foreground\",\n )}\n >\n <input\n type=\"radio\"\n name=\"clicky-export-scope\"\n // Named explicitly: the input is visually hidden behind its\n // own styled label, so nothing else gives it a name.\n aria-label={option.label}\n className=\"sr-only\"\n checked={option.scope === scope}\n onChange={() => setScope(option.scope)}\n />\n {option.label}\n </label>\n ))}\n </div>\n </fieldset>\n ) : (\n scopes[0]?.label && (\n <p className=\"text-sm text-muted-foreground\">{scopes[0].label}</p>\n )\n )}\n\n <fieldset>\n <legend className=\"mb-1.5 text-[11px] font-medium uppercase tracking-wide text-muted-foreground\">\n Format\n </legend>\n <div className=\"grid gap-1 sm:grid-cols-2\">\n {formats.map((option) => {\n const note = activeScope?.note?.(option.format);\n return (\n <label\n key={option.format}\n className={cn(\n \"flex cursor-pointer items-start gap-2 rounded-md border px-3 py-2 text-left transition-colors\",\n option.format === format\n ? \"border-foreground/20 bg-accent text-accent-foreground\"\n : \"border-transparent hover:bg-accent hover:text-accent-foreground\",\n )}\n >\n <input\n type=\"radio\"\n name=\"clicky-export-format\"\n aria-label={option.label}\n className=\"sr-only\"\n checked={option.format === format}\n onChange={() => setFormat(option.format)}\n />\n {option.icon && (\n <Icon\n icon={option.icon}\n className={cn(\n \"mt-0.5 shrink-0 text-sm\",\n option.iconClassName ?? \"text-muted-foreground\",\n )}\n />\n )}\n <span className=\"min-w-0\">\n <span className=\"block text-sm font-medium\">\n {option.label}\n </span>\n {option.description && (\n <span className=\"mt-0.5 block text-xs text-muted-foreground\">\n {option.description}\n </span>\n )}\n {note && (\n <span className=\"mt-0.5 block text-xs text-amber-700 [[data-theme=dark]_&]:text-amber-400\">\n {note}\n </span>\n )}\n </span>\n </label>\n );\n })}\n </div>\n </fieldset>\n\n </div>\n </Modal>\n );\n}\n"],"mappings":"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"}
|
|
@@ -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
|
|
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)(
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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
|
|
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":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
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 {
|
|
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
|
|
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(
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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":"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"}
|
|
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,
|
|
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":"AAGA,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EACL,oBAAoB,EACpB,KAAK,mBAAmB,EACxB,KAAK,cAAc,GACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAChG,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAEzE,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,KAAK,iBAAiB,GACvB,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAEjF,OAAO,EACL,uBAAuB,EACvB,wBAAwB,EACxB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,aAAa,GACnB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,UAAU,EACV,cAAc,EACd,aAAa,EACb,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,KAAK,YAAY,GAClB,MAAM,QAAQ,CAAC;AAEhB,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,GAAG,EACH,eAAe,EACf,qBAAqB,EACrB,aAAa,EACb,SAAS,EACT,UAAU,EACV,UAAU,EACV,aAAa,EACb,UAAU,EACV,KAAK,WAAW,EAChB,aAAa,EACb,kBAAkB,EAClB,WAAW,EACX,YAAY,EACZ,iBAAiB,EACjB,yBAAyB,EACzB,WAAW,GACZ,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,aAAa,EACb,eAAe,EACf,UAAU,EACV,QAAQ,EACR,UAAU,EACV,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,KAAK,QAAQ,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEtE,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,
|
|
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/**
|
|
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:
|
|
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,
|
|
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,
|
|
103
|
+
export { MATRIX_MARKS, MATRIX_ORDER, formatMatrixDuration, matrixBarClass, matrixMarkKey, repeatsMark };
|
|
112
104
|
|
|
113
105
|
//# sourceMappingURL=matrix-marks.js.map
|