@flanksource/clicky-ui 0.2.12 → 0.2.13
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/components/Combobox.cjs +47 -33
- package/dist/components/Combobox.cjs.map +1 -1
- package/dist/components/Combobox.d.ts +12 -0
- package/dist/components/Combobox.d.ts.map +1 -1
- package/dist/components/Combobox.js +48 -34
- package/dist/components/Combobox.js.map +1 -1
- package/dist/components/IconButton.cjs +26 -0
- package/dist/components/IconButton.cjs.map +1 -0
- package/dist/components/IconButton.d.ts +25 -0
- package/dist/components/IconButton.d.ts.map +1 -0
- package/dist/components/IconButton.js +26 -0
- package/dist/components/IconButton.js.map +1 -0
- package/dist/components/SecretKeySelector.cjs +151 -0
- package/dist/components/SecretKeySelector.cjs.map +1 -0
- package/dist/components/SecretKeySelector.d.ts +47 -0
- package/dist/components/SecretKeySelector.d.ts.map +1 -0
- package/dist/components/SecretKeySelector.js +151 -0
- package/dist/components/SecretKeySelector.js.map +1 -0
- package/dist/components/WorkloadPicker.cjs +144 -0
- package/dist/components/WorkloadPicker.cjs.map +1 -0
- package/dist/components/WorkloadPicker.d.ts +52 -0
- package/dist/components/WorkloadPicker.d.ts.map +1 -0
- package/dist/components/WorkloadPicker.js +144 -0
- package/dist/components/WorkloadPicker.js.map +1 -0
- package/dist/components/icon-menu-picker.cjs +83 -112
- package/dist/components/icon-menu-picker.cjs.map +1 -1
- package/dist/components/icon-menu-picker.d.ts.map +1 -1
- package/dist/components/icon-menu-picker.js +85 -114
- package/dist/components/icon-menu-picker.js.map +1 -1
- package/dist/components.cjs +10 -0
- package/dist/components.cjs.map +1 -1
- package/dist/components.d.ts +3 -0
- package/dist/components.d.ts.map +1 -1
- package/dist/components.js +11 -1
- package/dist/components.js.map +1 -1
- package/dist/data/Clicky.cjs +1 -1
- package/dist/data/Clicky.cjs.map +1 -1
- package/dist/data/Clicky.js +1 -1
- package/dist/data/Clicky.js.map +1 -1
- package/dist/data/Version.cjs +42 -0
- package/dist/data/Version.cjs.map +1 -0
- package/dist/data/Version.d.ts +36 -0
- package/dist/data/Version.d.ts.map +1 -0
- package/dist/data/Version.js +42 -0
- package/dist/data/Version.js.map +1 -0
- package/dist/data/test-runner/TestDetailPanel.cjs +165 -0
- package/dist/data/test-runner/TestDetailPanel.cjs.map +1 -0
- package/dist/data/test-runner/TestDetailPanel.d.ts +7 -0
- package/dist/data/test-runner/TestDetailPanel.d.ts.map +1 -0
- package/dist/data/test-runner/TestDetailPanel.js +165 -0
- package/dist/data/test-runner/TestDetailPanel.js.map +1 -0
- package/dist/data/test-runner/TestFailureDetail.cjs +78 -0
- package/dist/data/test-runner/TestFailureDetail.cjs.map +1 -0
- package/dist/data/test-runner/TestFailureDetail.d.ts +14 -0
- package/dist/data/test-runner/TestFailureDetail.d.ts.map +1 -0
- package/dist/data/test-runner/TestFailureDetail.js +78 -0
- package/dist/data/test-runner/TestFailureDetail.js.map +1 -0
- package/dist/data/test-runner/TestFilterBar.cjs +108 -0
- package/dist/data/test-runner/TestFilterBar.cjs.map +1 -0
- package/dist/data/test-runner/TestFilterBar.d.ts +15 -0
- package/dist/data/test-runner/TestFilterBar.d.ts.map +1 -0
- package/dist/data/test-runner/TestFilterBar.js +108 -0
- package/dist/data/test-runner/TestFilterBar.js.map +1 -0
- package/dist/data/test-runner/TestRunSummary.cjs +81 -0
- package/dist/data/test-runner/TestRunSummary.cjs.map +1 -0
- package/dist/data/test-runner/TestRunSummary.d.ts +19 -0
- package/dist/data/test-runner/TestRunSummary.d.ts.map +1 -0
- package/dist/data/test-runner/TestRunSummary.js +81 -0
- package/dist/data/test-runner/TestRunSummary.js.map +1 -0
- package/dist/data/test-runner/TestRunner.cjs +143 -0
- package/dist/data/test-runner/TestRunner.cjs.map +1 -0
- package/dist/data/test-runner/TestRunner.d.ts +42 -0
- package/dist/data/test-runner/TestRunner.d.ts.map +1 -0
- package/dist/data/test-runner/TestRunner.fixtures.d.ts +26 -0
- package/dist/data/test-runner/TestRunner.fixtures.d.ts.map +1 -0
- package/dist/data/test-runner/TestRunner.js +143 -0
- package/dist/data/test-runner/TestRunner.js.map +1 -0
- package/dist/data/test-runner/TestTree.cjs +42 -0
- package/dist/data/test-runner/TestTree.cjs.map +1 -0
- package/dist/data/test-runner/TestTree.d.ts +9 -0
- package/dist/data/test-runner/TestTree.d.ts.map +1 -0
- package/dist/data/test-runner/TestTree.js +42 -0
- package/dist/data/test-runner/TestTree.js.map +1 -0
- package/dist/data/test-runner/TestTreeNode.cjs +99 -0
- package/dist/data/test-runner/TestTreeNode.cjs.map +1 -0
- package/dist/data/test-runner/TestTreeNode.d.ts +12 -0
- package/dist/data/test-runner/TestTreeNode.d.ts.map +1 -0
- package/dist/data/test-runner/TestTreeNode.js +99 -0
- package/dist/data/test-runner/TestTreeNode.js.map +1 -0
- package/dist/data/test-runner/adapter.cjs +57 -0
- package/dist/data/test-runner/adapter.cjs.map +1 -0
- package/dist/data/test-runner/adapter.d.ts +60 -0
- package/dist/data/test-runner/adapter.d.ts.map +1 -0
- package/dist/data/test-runner/adapter.js +57 -0
- package/dist/data/test-runner/adapter.js.map +1 -0
- package/dist/data/test-runner/context.cjs +15 -0
- package/dist/data/test-runner/context.cjs.map +1 -0
- package/dist/data/test-runner/context.d.ts +40 -0
- package/dist/data/test-runner/context.d.ts.map +1 -0
- package/dist/data/test-runner/context.js +15 -0
- package/dist/data/test-runner/context.js.map +1 -0
- package/dist/data/test-runner/filterState.cjs +47 -0
- package/dist/data/test-runner/filterState.cjs.map +1 -0
- package/dist/data/test-runner/filterState.d.ts +14 -0
- package/dist/data/test-runner/filterState.d.ts.map +1 -0
- package/dist/data/test-runner/filterState.js +47 -0
- package/dist/data/test-runner/filterState.js.map +1 -0
- package/dist/data/test-runner/frameworkIcon.cjs +27 -0
- package/dist/data/test-runner/frameworkIcon.cjs.map +1 -0
- package/dist/data/test-runner/frameworkIcon.d.ts +3 -0
- package/dist/data/test-runner/frameworkIcon.d.ts.map +1 -0
- package/dist/data/test-runner/frameworkIcon.js +27 -0
- package/dist/data/test-runner/frameworkIcon.js.map +1 -0
- package/dist/data/test-runner/index.d.ts +14 -0
- package/dist/data/test-runner/index.d.ts.map +1 -0
- package/dist/data/test-runner/status.cjs +234 -0
- package/dist/data/test-runner/status.cjs.map +1 -0
- package/dist/data/test-runner/status.d.ts +52 -0
- package/dist/data/test-runner/status.d.ts.map +1 -0
- package/dist/data/test-runner/status.js +234 -0
- package/dist/data/test-runner/status.js.map +1 -0
- package/dist/data/test-runner/types.d.ts +148 -0
- package/dist/data/test-runner/types.d.ts.map +1 -0
- package/dist/data/version-info.cjs +26 -0
- package/dist/data/version-info.cjs.map +1 -0
- package/dist/data/version-info.d.ts +11 -0
- package/dist/data/version-info.d.ts.map +1 -0
- package/dist/data/version-info.js +26 -0
- package/dist/data/version-info.js.map +1 -0
- package/dist/data.cjs +49 -0
- package/dist/data.cjs.map +1 -1
- package/dist/data.d.ts +3 -0
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +50 -1
- package/dist/data.js.map +1 -1
- package/dist/index.cjs +59 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +60 -1
- package/dist/index.js.map +1 -1
- package/dist/overlay/DropdownMenu.cjs +57 -30
- package/dist/overlay/DropdownMenu.cjs.map +1 -1
- package/dist/overlay/DropdownMenu.d.ts.map +1 -1
- package/dist/overlay/DropdownMenu.js +57 -30
- package/dist/overlay/DropdownMenu.js.map +1 -1
- package/dist/overlay/Modal.cjs +62 -6
- package/dist/overlay/Modal.cjs.map +1 -1
- package/dist/overlay/Modal.d.ts +19 -1
- package/dist/overlay/Modal.d.ts.map +1 -1
- package/dist/overlay/Modal.js +62 -6
- package/dist/overlay/Modal.js.map +1 -1
- package/dist/rpc/CommandForm.cjs +2 -2
- package/dist/rpc/CommandForm.cjs.map +1 -1
- package/dist/rpc/CommandForm.d.ts.map +1 -1
- package/dist/rpc/CommandForm.js +3 -3
- package/dist/rpc/CommandForm.js.map +1 -1
- package/dist/rpc/formMetadata.cjs +5 -4
- package/dist/rpc/formMetadata.cjs.map +1 -1
- package/dist/rpc/formMetadata.d.ts.map +1 -1
- package/dist/rpc/formMetadata.js +6 -5
- package/dist/rpc/formMetadata.js.map +1 -1
- package/dist/rpc/types.cjs +4 -0
- package/dist/rpc/types.cjs.map +1 -1
- package/dist/rpc/types.d.ts +10 -0
- package/dist/rpc/types.d.ts.map +1 -1
- package/dist/rpc/types.js +5 -1
- package/dist/rpc/types.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const react = require("react");
|
|
5
|
+
const Icon = require("../Icon.cjs");
|
|
6
|
+
const SplitPane = require("../../layout/SplitPane.cjs");
|
|
7
|
+
const utils = require("../../lib/utils.cjs");
|
|
8
|
+
const status = require("./status.cjs");
|
|
9
|
+
const adapter = require("./adapter.cjs");
|
|
10
|
+
const context = require("./context.cjs");
|
|
11
|
+
const TestTree = require("./TestTree.cjs");
|
|
12
|
+
const TestDetailPanel = require("./TestDetailPanel.cjs");
|
|
13
|
+
const TestRunSummary = require("./TestRunSummary.cjs");
|
|
14
|
+
const TestFilterBar = require("./TestFilterBar.cjs");
|
|
15
|
+
const UiBeaker = require("../../icons/components/UiBeaker.cjs");
|
|
16
|
+
function counts(tests) {
|
|
17
|
+
return tests.reduce(
|
|
18
|
+
(acc, t) => {
|
|
19
|
+
const s = status.sumNonTaskTests(t);
|
|
20
|
+
Object.keys(acc).forEach((k) => acc[k] += s[k]);
|
|
21
|
+
return acc;
|
|
22
|
+
},
|
|
23
|
+
{ total: 0, passed: 0, failed: 0, warned: 0, skipped: 0, pending: 0, running: 0, timedout: 0 }
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
function toRegistry(adapters) {
|
|
27
|
+
if (adapters instanceof adapter.TestNodeAdapterRegistry) return adapters;
|
|
28
|
+
return adapter.createTestRunnerRegistry(adapters ?? []);
|
|
29
|
+
}
|
|
30
|
+
function TestRunner({
|
|
31
|
+
tests,
|
|
32
|
+
selected,
|
|
33
|
+
filters,
|
|
34
|
+
expandAll,
|
|
35
|
+
done,
|
|
36
|
+
runMeta,
|
|
37
|
+
status: status$1,
|
|
38
|
+
statusText,
|
|
39
|
+
now,
|
|
40
|
+
busy,
|
|
41
|
+
onSelect,
|
|
42
|
+
onFiltersChange,
|
|
43
|
+
onExpandAllChange,
|
|
44
|
+
onRerun,
|
|
45
|
+
onStop,
|
|
46
|
+
adapters,
|
|
47
|
+
headerSlot,
|
|
48
|
+
defaultSplit = 45,
|
|
49
|
+
startTime,
|
|
50
|
+
endTime,
|
|
51
|
+
className
|
|
52
|
+
}) {
|
|
53
|
+
const registry = react.useMemo(() => toRegistry(adapters), [adapters]);
|
|
54
|
+
const ctx = react.useMemo(
|
|
55
|
+
() => ({
|
|
56
|
+
tests,
|
|
57
|
+
selected,
|
|
58
|
+
runMeta,
|
|
59
|
+
status: status$1,
|
|
60
|
+
done,
|
|
61
|
+
now,
|
|
62
|
+
filters,
|
|
63
|
+
expandAll,
|
|
64
|
+
busy: busy ?? {},
|
|
65
|
+
onSelect,
|
|
66
|
+
onFiltersChange,
|
|
67
|
+
onExpandAllChange,
|
|
68
|
+
onRerun,
|
|
69
|
+
onStop,
|
|
70
|
+
adapters: registry
|
|
71
|
+
}),
|
|
72
|
+
[
|
|
73
|
+
tests,
|
|
74
|
+
selected,
|
|
75
|
+
runMeta,
|
|
76
|
+
status$1,
|
|
77
|
+
done,
|
|
78
|
+
now,
|
|
79
|
+
filters,
|
|
80
|
+
expandAll,
|
|
81
|
+
busy,
|
|
82
|
+
onSelect,
|
|
83
|
+
onFiltersChange,
|
|
84
|
+
onExpandAllChange,
|
|
85
|
+
onRerun,
|
|
86
|
+
onStop,
|
|
87
|
+
registry
|
|
88
|
+
]
|
|
89
|
+
);
|
|
90
|
+
const frameworks = react.useMemo(() => status.collectFrameworks(tests), [tests]);
|
|
91
|
+
const filterCounts = react.useMemo(() => counts(tests), [tests]);
|
|
92
|
+
const hasContent = tests.length > 0;
|
|
93
|
+
return /* @__PURE__ */ jsxRuntime.jsx(context.TestRunnerProvider, { value: ctx, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: utils.cn("flex h-full min-h-0 flex-col bg-background", className), children: [
|
|
94
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-b border-border bg-card px-density-4 py-density-3", children: [
|
|
95
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3", children: [
|
|
96
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
97
|
+
/* @__PURE__ */ jsxRuntime.jsxs("h1", { className: "inline-flex items-center gap-1.5 text-lg font-bold", children: [
|
|
98
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { icon: UiBeaker.UiBeaker, className: "text-primary" }),
|
|
99
|
+
"Test Results"
|
|
100
|
+
] }),
|
|
101
|
+
statusText && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: statusText })
|
|
102
|
+
] }),
|
|
103
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
104
|
+
headerSlot,
|
|
105
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
106
|
+
TestRunSummary.TestRunSummary,
|
|
107
|
+
{
|
|
108
|
+
tests,
|
|
109
|
+
startTime,
|
|
110
|
+
endTime,
|
|
111
|
+
done,
|
|
112
|
+
now,
|
|
113
|
+
runMeta
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
] })
|
|
117
|
+
] }),
|
|
118
|
+
hasContent && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
119
|
+
TestFilterBar.TestFilterBar,
|
|
120
|
+
{
|
|
121
|
+
filters,
|
|
122
|
+
onChange: onFiltersChange,
|
|
123
|
+
counts: filterCounts,
|
|
124
|
+
frameworks
|
|
125
|
+
}
|
|
126
|
+
) })
|
|
127
|
+
] }),
|
|
128
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
129
|
+
SplitPane.SplitPane,
|
|
130
|
+
{
|
|
131
|
+
className: "min-h-0 flex-1",
|
|
132
|
+
defaultSplit,
|
|
133
|
+
minLeft: 25,
|
|
134
|
+
minRight: 30,
|
|
135
|
+
leftClass: "border-r-2 border-border bg-muted/30",
|
|
136
|
+
left: /* @__PURE__ */ jsxRuntime.jsx(TestTree.TestTree, {}),
|
|
137
|
+
right: /* @__PURE__ */ jsxRuntime.jsx(TestDetailPanel.TestDetailPanel, {})
|
|
138
|
+
}
|
|
139
|
+
)
|
|
140
|
+
] }) });
|
|
141
|
+
}
|
|
142
|
+
exports.TestRunner = TestRunner;
|
|
143
|
+
//# sourceMappingURL=TestRunner.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TestRunner.cjs","sources":["../../../src/data/test-runner/TestRunner.tsx"],"sourcesContent":["import { useMemo, type ReactNode } from \"react\";\nimport { Icon } from \"../Icon\";\nimport { SplitPane } from \"../../layout/SplitPane\";\nimport { cn } from \"../../lib/utils\";\nimport { UiBeaker } from \"../../icons\";\nimport type { RunMeta, SnapshotStatus, Test } from \"./types\";\nimport { collectFrameworks, sumNonTaskTests, type StatusCounts } from \"./status\";\nimport { type TestFilters } from \"./filterState\";\nimport {\n createTestRunnerRegistry,\n type TestNodeAdapter,\n TestNodeAdapterRegistry,\n} from \"./adapter\";\nimport { TestRunnerProvider, type TestRunnerContext } from \"./context\";\nimport { TestTree } from \"./TestTree\";\nimport { TestDetailPanel } from \"./TestDetailPanel\";\nimport { TestRunSummary } from \"./TestRunSummary\";\nimport { TestFilterBar } from \"./TestFilterBar\";\n\nexport type TestRunnerProps = {\n tests: Test[];\n selected: Test | null;\n filters: TestFilters;\n expandAll: boolean | null;\n done: boolean;\n runMeta?: RunMeta;\n status?: SnapshotStatus;\n /** Free-form status line shown next to the title (e.g. \"Running tests...\"). */\n statusText?: string;\n now?: number;\n busy?: { rerun?: boolean; stop?: boolean };\n\n onSelect: (node: Test | null) => void;\n onFiltersChange: (next: TestFilters) => void;\n onExpandAllChange: (next: boolean | null) => void;\n onRerun?: (node: Test) => void;\n onStop?: (node: Test) => void;\n\n /** Domain node adapters, or a pre-built registry. Defaults to default-only. */\n adapters?: TestNodeAdapter[] | TestNodeAdapterRegistry;\n /** Extra header content (e.g. export/download controls owned by the host). */\n headerSlot?: ReactNode;\n /** Initial left-pane width percentage. */\n defaultSplit?: number;\n startTime?: number | null;\n endTime?: number | null;\n className?: string;\n};\n\nfunction counts(tests: Test[]): StatusCounts {\n return tests.reduce(\n (acc, t) => {\n const s = sumNonTaskTests(t);\n (Object.keys(acc) as (keyof StatusCounts)[]).forEach((k) => (acc[k] += s[k]));\n return acc;\n },\n { total: 0, passed: 0, failed: 0, warned: 0, skipped: 0, pending: 0, running: 0, timedout: 0 },\n );\n}\n\nfunction toRegistry(\n adapters: TestNodeAdapter[] | TestNodeAdapterRegistry | undefined,\n): TestNodeAdapterRegistry {\n if (adapters instanceof TestNodeAdapterRegistry) return adapters;\n return createTestRunnerRegistry(adapters ?? []);\n}\n\n/**\n * Top-level, pure-presentational test runner: a summary/filter header over a\n * resizable tree + detail split. All data and handlers flow in via props and\n * are exposed to sub-components through a single `TestRunnerContext`. Domain\n * rendering is pluggable via node adapters; no fetch/SSE/routing lives here.\n */\nexport function TestRunner({\n tests,\n selected,\n filters,\n expandAll,\n done,\n runMeta,\n status,\n statusText,\n now,\n busy,\n onSelect,\n onFiltersChange,\n onExpandAllChange,\n onRerun,\n onStop,\n adapters,\n headerSlot,\n defaultSplit = 45,\n startTime,\n endTime,\n className,\n}: TestRunnerProps) {\n const registry = useMemo(() => toRegistry(adapters), [adapters]);\n\n const ctx: TestRunnerContext = useMemo(\n () => ({\n tests,\n selected,\n runMeta,\n status,\n done,\n now,\n filters,\n expandAll,\n busy: busy ?? {},\n onSelect,\n onFiltersChange,\n onExpandAllChange,\n onRerun,\n onStop,\n adapters: registry,\n }),\n [\n tests,\n selected,\n runMeta,\n status,\n done,\n now,\n filters,\n expandAll,\n busy,\n onSelect,\n onFiltersChange,\n onExpandAllChange,\n onRerun,\n onStop,\n registry,\n ],\n );\n\n const frameworks = useMemo(() => collectFrameworks(tests), [tests]);\n const filterCounts = useMemo(() => counts(tests), [tests]);\n const hasContent = tests.length > 0;\n\n return (\n <TestRunnerProvider value={ctx}>\n <div className={cn(\"flex h-full min-h-0 flex-col bg-background\", className)}>\n <div className=\"border-b border-border bg-card px-density-4 py-density-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex items-center gap-3\">\n <h1 className=\"inline-flex items-center gap-1.5 text-lg font-bold\">\n <Icon icon={UiBeaker} className=\"text-primary\" />\n Test Results\n </h1>\n {statusText && <span className=\"text-sm text-muted-foreground\">{statusText}</span>}\n </div>\n <div className=\"flex items-center gap-3\">\n {headerSlot}\n <TestRunSummary\n tests={tests}\n startTime={startTime}\n endTime={endTime}\n done={done}\n now={now}\n runMeta={runMeta}\n />\n </div>\n </div>\n {hasContent && (\n <div className=\"mt-2\">\n <TestFilterBar\n filters={filters}\n onChange={onFiltersChange}\n counts={filterCounts}\n frameworks={frameworks}\n />\n </div>\n )}\n </div>\n\n <SplitPane\n className=\"min-h-0 flex-1\"\n defaultSplit={defaultSplit}\n minLeft={25}\n minRight={30}\n leftClass=\"border-r-2 border-border bg-muted/30\"\n left={<TestTree />}\n right={<TestDetailPanel />}\n />\n </div>\n </TestRunnerProvider>\n );\n}\n"],"names":["sumNonTaskTests","TestNodeAdapterRegistry","createTestRunnerRegistry","status","useMemo","collectFrameworks","jsx","TestRunnerProvider","jsxs","cn","Icon","UiBeaker","TestRunSummary","TestFilterBar","SplitPane","TestTree","TestDetailPanel"],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { RunMeta, SnapshotStatus, Test } from './types';
|
|
3
|
+
import { TestFilters } from './filterState';
|
|
4
|
+
import { TestNodeAdapter, TestNodeAdapterRegistry } from './adapter';
|
|
5
|
+
export type TestRunnerProps = {
|
|
6
|
+
tests: Test[];
|
|
7
|
+
selected: Test | null;
|
|
8
|
+
filters: TestFilters;
|
|
9
|
+
expandAll: boolean | null;
|
|
10
|
+
done: boolean;
|
|
11
|
+
runMeta?: RunMeta;
|
|
12
|
+
status?: SnapshotStatus;
|
|
13
|
+
/** Free-form status line shown next to the title (e.g. "Running tests..."). */
|
|
14
|
+
statusText?: string;
|
|
15
|
+
now?: number;
|
|
16
|
+
busy?: {
|
|
17
|
+
rerun?: boolean;
|
|
18
|
+
stop?: boolean;
|
|
19
|
+
};
|
|
20
|
+
onSelect: (node: Test | null) => void;
|
|
21
|
+
onFiltersChange: (next: TestFilters) => void;
|
|
22
|
+
onExpandAllChange: (next: boolean | null) => void;
|
|
23
|
+
onRerun?: (node: Test) => void;
|
|
24
|
+
onStop?: (node: Test) => void;
|
|
25
|
+
/** Domain node adapters, or a pre-built registry. Defaults to default-only. */
|
|
26
|
+
adapters?: TestNodeAdapter[] | TestNodeAdapterRegistry;
|
|
27
|
+
/** Extra header content (e.g. export/download controls owned by the host). */
|
|
28
|
+
headerSlot?: ReactNode;
|
|
29
|
+
/** Initial left-pane width percentage. */
|
|
30
|
+
defaultSplit?: number;
|
|
31
|
+
startTime?: number | null;
|
|
32
|
+
endTime?: number | null;
|
|
33
|
+
className?: string;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Top-level, pure-presentational test runner: a summary/filter header over a
|
|
37
|
+
* resizable tree + detail split. All data and handlers flow in via props and
|
|
38
|
+
* are exposed to sub-components through a single `TestRunnerContext`. Domain
|
|
39
|
+
* rendering is pluggable via node adapters; no fetch/SSE/routing lives here.
|
|
40
|
+
*/
|
|
41
|
+
export declare function TestRunner({ tests, selected, filters, expandAll, done, runMeta, status, statusText, now, busy, onSelect, onFiltersChange, onExpandAllChange, onRerun, onStop, adapters, headerSlot, defaultSplit, startTime, endTime, className, }: TestRunnerProps): import("react/jsx-runtime").JSX.Element;
|
|
42
|
+
//# sourceMappingURL=TestRunner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TestRunner.d.ts","sourceRoot":"","sources":["../../../src/data/test-runner/TestRunner.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAKhD,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE7D,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAEL,KAAK,eAAe,EACpB,uBAAuB,EACxB,MAAM,WAAW,CAAC;AAOnB,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,WAAW,CAAC;IACrB,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAE3C,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC;IACtC,eAAe,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;IAC7C,iBAAiB,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,CAAC;IAClD,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC/B,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAE9B,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,eAAe,EAAE,GAAG,uBAAuB,CAAC;IACvD,8EAA8E;IAC9E,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,0CAA0C;IAC1C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAoBF;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,OAAO,EACP,SAAS,EACT,IAAI,EACJ,OAAO,EACP,MAAM,EACN,UAAU,EACV,GAAG,EACH,IAAI,EACJ,QAAQ,EACR,eAAe,EACf,iBAAiB,EACjB,OAAO,EACP,MAAM,EACN,QAAQ,EACR,UAAU,EACV,YAAiB,EACjB,SAAS,EACT,OAAO,EACP,SAAS,GACV,EAAE,eAAe,2CA4FjB"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { TestNodeAdapter } from './adapter';
|
|
2
|
+
import { Test } from './types';
|
|
3
|
+
/** A completed, mixed-status run across go test, ginkgo and fixture frameworks. */
|
|
4
|
+
export declare const completedTests: Test[];
|
|
5
|
+
/** Same forest, but as an in-flight run: some running, some queued. */
|
|
6
|
+
export declare const runningTests: Test[];
|
|
7
|
+
/**
|
|
8
|
+
* A suite whose leaves carry very large payloads: a 6×4 deep object, a
|
|
9
|
+
* 500-row array, and an 800-line log — to stress JsonView, LogViewer, and the
|
|
10
|
+
* detail pane's independent scrolling.
|
|
11
|
+
*/
|
|
12
|
+
export declare const largeDetailTests: Test[];
|
|
13
|
+
/**
|
|
14
|
+
* A very large forest (4 roots × depth 4 × breadth 4 ≈ several hundred nodes)
|
|
15
|
+
* whose every leaf carries the LargePayloads-sized detail (deep object +
|
|
16
|
+
* 500-row array + 800-line log). Used for the dialog stress test: a long
|
|
17
|
+
* scrolling tree on the left and very large detail payloads on the right.
|
|
18
|
+
*/
|
|
19
|
+
export declare const largeTreeTests: Test[];
|
|
20
|
+
/**
|
|
21
|
+
* Demo adapter proving the registry extension point: nodes named "setup" get a
|
|
22
|
+
* custom detail body, an extra "Context" tab, and a node action — the seam that
|
|
23
|
+
* lets a downstream host drop its DetailPanel wrapper.
|
|
24
|
+
*/
|
|
25
|
+
export declare const setupAdapter: TestNodeAdapter;
|
|
26
|
+
//# sourceMappingURL=TestRunner.fixtures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TestRunner.fixtures.d.ts","sourceRoot":"","sources":["../../../src/data/test-runner/TestRunner.fixtures.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAIpC,mFAAmF;AACnF,eAAO,MAAM,cAAc,EAAE,IAAI,EAmFhC,CAAC;AAEF,uEAAuE;AACvE,eAAO,MAAM,YAAY,EAAE,IAAI,EA+B9B,CAAC;AAsCF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,IAAI,EA0BlC,CAAC;AAwDF;;;;;GAKG;AACH,eAAO,MAAM,cAAc,EAAE,IAAI,EAEhC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,YAAY,EAAE,eA0C1B,CAAC"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import { Icon } from "../Icon.js";
|
|
4
|
+
import { SplitPane } from "../../layout/SplitPane.js";
|
|
5
|
+
import { cn } from "../../lib/utils.js";
|
|
6
|
+
import { collectFrameworks, sumNonTaskTests } from "./status.js";
|
|
7
|
+
import { TestNodeAdapterRegistry, createTestRunnerRegistry } from "./adapter.js";
|
|
8
|
+
import { TestRunnerProvider } from "./context.js";
|
|
9
|
+
import { TestTree } from "./TestTree.js";
|
|
10
|
+
import { TestDetailPanel } from "./TestDetailPanel.js";
|
|
11
|
+
import { TestRunSummary } from "./TestRunSummary.js";
|
|
12
|
+
import { TestFilterBar } from "./TestFilterBar.js";
|
|
13
|
+
import { UiBeaker } from "../../icons/components/UiBeaker.js";
|
|
14
|
+
function counts(tests) {
|
|
15
|
+
return tests.reduce(
|
|
16
|
+
(acc, t) => {
|
|
17
|
+
const s = sumNonTaskTests(t);
|
|
18
|
+
Object.keys(acc).forEach((k) => acc[k] += s[k]);
|
|
19
|
+
return acc;
|
|
20
|
+
},
|
|
21
|
+
{ total: 0, passed: 0, failed: 0, warned: 0, skipped: 0, pending: 0, running: 0, timedout: 0 }
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
function toRegistry(adapters) {
|
|
25
|
+
if (adapters instanceof TestNodeAdapterRegistry) return adapters;
|
|
26
|
+
return createTestRunnerRegistry(adapters ?? []);
|
|
27
|
+
}
|
|
28
|
+
function TestRunner({
|
|
29
|
+
tests,
|
|
30
|
+
selected,
|
|
31
|
+
filters,
|
|
32
|
+
expandAll,
|
|
33
|
+
done,
|
|
34
|
+
runMeta,
|
|
35
|
+
status,
|
|
36
|
+
statusText,
|
|
37
|
+
now,
|
|
38
|
+
busy,
|
|
39
|
+
onSelect,
|
|
40
|
+
onFiltersChange,
|
|
41
|
+
onExpandAllChange,
|
|
42
|
+
onRerun,
|
|
43
|
+
onStop,
|
|
44
|
+
adapters,
|
|
45
|
+
headerSlot,
|
|
46
|
+
defaultSplit = 45,
|
|
47
|
+
startTime,
|
|
48
|
+
endTime,
|
|
49
|
+
className
|
|
50
|
+
}) {
|
|
51
|
+
const registry = useMemo(() => toRegistry(adapters), [adapters]);
|
|
52
|
+
const ctx = useMemo(
|
|
53
|
+
() => ({
|
|
54
|
+
tests,
|
|
55
|
+
selected,
|
|
56
|
+
runMeta,
|
|
57
|
+
status,
|
|
58
|
+
done,
|
|
59
|
+
now,
|
|
60
|
+
filters,
|
|
61
|
+
expandAll,
|
|
62
|
+
busy: busy ?? {},
|
|
63
|
+
onSelect,
|
|
64
|
+
onFiltersChange,
|
|
65
|
+
onExpandAllChange,
|
|
66
|
+
onRerun,
|
|
67
|
+
onStop,
|
|
68
|
+
adapters: registry
|
|
69
|
+
}),
|
|
70
|
+
[
|
|
71
|
+
tests,
|
|
72
|
+
selected,
|
|
73
|
+
runMeta,
|
|
74
|
+
status,
|
|
75
|
+
done,
|
|
76
|
+
now,
|
|
77
|
+
filters,
|
|
78
|
+
expandAll,
|
|
79
|
+
busy,
|
|
80
|
+
onSelect,
|
|
81
|
+
onFiltersChange,
|
|
82
|
+
onExpandAllChange,
|
|
83
|
+
onRerun,
|
|
84
|
+
onStop,
|
|
85
|
+
registry
|
|
86
|
+
]
|
|
87
|
+
);
|
|
88
|
+
const frameworks = useMemo(() => collectFrameworks(tests), [tests]);
|
|
89
|
+
const filterCounts = useMemo(() => counts(tests), [tests]);
|
|
90
|
+
const hasContent = tests.length > 0;
|
|
91
|
+
return /* @__PURE__ */ jsx(TestRunnerProvider, { value: ctx, children: /* @__PURE__ */ jsxs("div", { className: cn("flex h-full min-h-0 flex-col bg-background", className), children: [
|
|
92
|
+
/* @__PURE__ */ jsxs("div", { className: "border-b border-border bg-card px-density-4 py-density-3", children: [
|
|
93
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
|
|
94
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
95
|
+
/* @__PURE__ */ jsxs("h1", { className: "inline-flex items-center gap-1.5 text-lg font-bold", children: [
|
|
96
|
+
/* @__PURE__ */ jsx(Icon, { icon: UiBeaker, className: "text-primary" }),
|
|
97
|
+
"Test Results"
|
|
98
|
+
] }),
|
|
99
|
+
statusText && /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: statusText })
|
|
100
|
+
] }),
|
|
101
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
102
|
+
headerSlot,
|
|
103
|
+
/* @__PURE__ */ jsx(
|
|
104
|
+
TestRunSummary,
|
|
105
|
+
{
|
|
106
|
+
tests,
|
|
107
|
+
startTime,
|
|
108
|
+
endTime,
|
|
109
|
+
done,
|
|
110
|
+
now,
|
|
111
|
+
runMeta
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
] })
|
|
115
|
+
] }),
|
|
116
|
+
hasContent && /* @__PURE__ */ jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsx(
|
|
117
|
+
TestFilterBar,
|
|
118
|
+
{
|
|
119
|
+
filters,
|
|
120
|
+
onChange: onFiltersChange,
|
|
121
|
+
counts: filterCounts,
|
|
122
|
+
frameworks
|
|
123
|
+
}
|
|
124
|
+
) })
|
|
125
|
+
] }),
|
|
126
|
+
/* @__PURE__ */ jsx(
|
|
127
|
+
SplitPane,
|
|
128
|
+
{
|
|
129
|
+
className: "min-h-0 flex-1",
|
|
130
|
+
defaultSplit,
|
|
131
|
+
minLeft: 25,
|
|
132
|
+
minRight: 30,
|
|
133
|
+
leftClass: "border-r-2 border-border bg-muted/30",
|
|
134
|
+
left: /* @__PURE__ */ jsx(TestTree, {}),
|
|
135
|
+
right: /* @__PURE__ */ jsx(TestDetailPanel, {})
|
|
136
|
+
}
|
|
137
|
+
)
|
|
138
|
+
] }) });
|
|
139
|
+
}
|
|
140
|
+
export {
|
|
141
|
+
TestRunner
|
|
142
|
+
};
|
|
143
|
+
//# sourceMappingURL=TestRunner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TestRunner.js","sources":["../../../src/data/test-runner/TestRunner.tsx"],"sourcesContent":["import { useMemo, type ReactNode } from \"react\";\nimport { Icon } from \"../Icon\";\nimport { SplitPane } from \"../../layout/SplitPane\";\nimport { cn } from \"../../lib/utils\";\nimport { UiBeaker } from \"../../icons\";\nimport type { RunMeta, SnapshotStatus, Test } from \"./types\";\nimport { collectFrameworks, sumNonTaskTests, type StatusCounts } from \"./status\";\nimport { type TestFilters } from \"./filterState\";\nimport {\n createTestRunnerRegistry,\n type TestNodeAdapter,\n TestNodeAdapterRegistry,\n} from \"./adapter\";\nimport { TestRunnerProvider, type TestRunnerContext } from \"./context\";\nimport { TestTree } from \"./TestTree\";\nimport { TestDetailPanel } from \"./TestDetailPanel\";\nimport { TestRunSummary } from \"./TestRunSummary\";\nimport { TestFilterBar } from \"./TestFilterBar\";\n\nexport type TestRunnerProps = {\n tests: Test[];\n selected: Test | null;\n filters: TestFilters;\n expandAll: boolean | null;\n done: boolean;\n runMeta?: RunMeta;\n status?: SnapshotStatus;\n /** Free-form status line shown next to the title (e.g. \"Running tests...\"). */\n statusText?: string;\n now?: number;\n busy?: { rerun?: boolean; stop?: boolean };\n\n onSelect: (node: Test | null) => void;\n onFiltersChange: (next: TestFilters) => void;\n onExpandAllChange: (next: boolean | null) => void;\n onRerun?: (node: Test) => void;\n onStop?: (node: Test) => void;\n\n /** Domain node adapters, or a pre-built registry. Defaults to default-only. */\n adapters?: TestNodeAdapter[] | TestNodeAdapterRegistry;\n /** Extra header content (e.g. export/download controls owned by the host). */\n headerSlot?: ReactNode;\n /** Initial left-pane width percentage. */\n defaultSplit?: number;\n startTime?: number | null;\n endTime?: number | null;\n className?: string;\n};\n\nfunction counts(tests: Test[]): StatusCounts {\n return tests.reduce(\n (acc, t) => {\n const s = sumNonTaskTests(t);\n (Object.keys(acc) as (keyof StatusCounts)[]).forEach((k) => (acc[k] += s[k]));\n return acc;\n },\n { total: 0, passed: 0, failed: 0, warned: 0, skipped: 0, pending: 0, running: 0, timedout: 0 },\n );\n}\n\nfunction toRegistry(\n adapters: TestNodeAdapter[] | TestNodeAdapterRegistry | undefined,\n): TestNodeAdapterRegistry {\n if (adapters instanceof TestNodeAdapterRegistry) return adapters;\n return createTestRunnerRegistry(adapters ?? []);\n}\n\n/**\n * Top-level, pure-presentational test runner: a summary/filter header over a\n * resizable tree + detail split. All data and handlers flow in via props and\n * are exposed to sub-components through a single `TestRunnerContext`. Domain\n * rendering is pluggable via node adapters; no fetch/SSE/routing lives here.\n */\nexport function TestRunner({\n tests,\n selected,\n filters,\n expandAll,\n done,\n runMeta,\n status,\n statusText,\n now,\n busy,\n onSelect,\n onFiltersChange,\n onExpandAllChange,\n onRerun,\n onStop,\n adapters,\n headerSlot,\n defaultSplit = 45,\n startTime,\n endTime,\n className,\n}: TestRunnerProps) {\n const registry = useMemo(() => toRegistry(adapters), [adapters]);\n\n const ctx: TestRunnerContext = useMemo(\n () => ({\n tests,\n selected,\n runMeta,\n status,\n done,\n now,\n filters,\n expandAll,\n busy: busy ?? {},\n onSelect,\n onFiltersChange,\n onExpandAllChange,\n onRerun,\n onStop,\n adapters: registry,\n }),\n [\n tests,\n selected,\n runMeta,\n status,\n done,\n now,\n filters,\n expandAll,\n busy,\n onSelect,\n onFiltersChange,\n onExpandAllChange,\n onRerun,\n onStop,\n registry,\n ],\n );\n\n const frameworks = useMemo(() => collectFrameworks(tests), [tests]);\n const filterCounts = useMemo(() => counts(tests), [tests]);\n const hasContent = tests.length > 0;\n\n return (\n <TestRunnerProvider value={ctx}>\n <div className={cn(\"flex h-full min-h-0 flex-col bg-background\", className)}>\n <div className=\"border-b border-border bg-card px-density-4 py-density-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex items-center gap-3\">\n <h1 className=\"inline-flex items-center gap-1.5 text-lg font-bold\">\n <Icon icon={UiBeaker} className=\"text-primary\" />\n Test Results\n </h1>\n {statusText && <span className=\"text-sm text-muted-foreground\">{statusText}</span>}\n </div>\n <div className=\"flex items-center gap-3\">\n {headerSlot}\n <TestRunSummary\n tests={tests}\n startTime={startTime}\n endTime={endTime}\n done={done}\n now={now}\n runMeta={runMeta}\n />\n </div>\n </div>\n {hasContent && (\n <div className=\"mt-2\">\n <TestFilterBar\n filters={filters}\n onChange={onFiltersChange}\n counts={filterCounts}\n frameworks={frameworks}\n />\n </div>\n )}\n </div>\n\n <SplitPane\n className=\"min-h-0 flex-1\"\n defaultSplit={defaultSplit}\n minLeft={25}\n minRight={30}\n leftClass=\"border-r-2 border-border bg-muted/30\"\n left={<TestTree />}\n right={<TestDetailPanel />}\n />\n </div>\n </TestRunnerProvider>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const Tree = require("../Tree.cjs");
|
|
5
|
+
const utils = require("../../lib/utils.cjs");
|
|
6
|
+
const context = require("./context.cjs");
|
|
7
|
+
const status = require("./status.cjs");
|
|
8
|
+
const TestTreeNode = require("./TestTreeNode.cjs");
|
|
9
|
+
const nodeKey = /* @__PURE__ */ (() => {
|
|
10
|
+
const cache = /* @__PURE__ */ new WeakMap();
|
|
11
|
+
let counter = 0;
|
|
12
|
+
return (node) => {
|
|
13
|
+
if (node.route_path) return node.route_path;
|
|
14
|
+
let key = cache.get(node);
|
|
15
|
+
if (!key) {
|
|
16
|
+
key = `tn-${counter++}-${node.name}`;
|
|
17
|
+
cache.set(node, key);
|
|
18
|
+
}
|
|
19
|
+
return key;
|
|
20
|
+
};
|
|
21
|
+
})();
|
|
22
|
+
function TestTree({ className }) {
|
|
23
|
+
const runner = context.useTestRunner();
|
|
24
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
25
|
+
Tree.Tree,
|
|
26
|
+
{
|
|
27
|
+
className: utils.cn("min-h-0", className),
|
|
28
|
+
roots: runner.tests,
|
|
29
|
+
getKey: nodeKey,
|
|
30
|
+
getChildren: (node) => node.children,
|
|
31
|
+
selected: runner.selected,
|
|
32
|
+
onSelect: (node) => runner.onSelect(node === runner.selected ? null : node),
|
|
33
|
+
expandAll: runner.expandAll,
|
|
34
|
+
onExpandAllChange: runner.onExpandAllChange,
|
|
35
|
+
defaultOpen: (node, depth) => depth < 1 || status.hasFailed(node),
|
|
36
|
+
getSearchText: (node) => `${node.name} ${node.framework ?? ""}`,
|
|
37
|
+
renderRow: ({ node, selected }) => /* @__PURE__ */ jsxRuntime.jsx(TestTreeNode.TestTreeNode, { node, selected })
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
exports.TestTree = TestTree;
|
|
42
|
+
//# sourceMappingURL=TestTree.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TestTree.cjs","sources":["../../../src/data/test-runner/TestTree.tsx"],"sourcesContent":["import { Tree } from \"../Tree\";\nimport { cn } from \"../../lib/utils\";\nimport type { Test } from \"./types\";\nimport { useTestRunner } from \"./context\";\nimport { hasFailed } from \"./status\";\nimport { TestTreeNode } from \"./TestTreeNode\";\n\nconst nodeKey = (() => {\n // Tests carry no guaranteed id; derive a stable per-render key from route_path\n // when present, else the node's name path. A WeakMap keeps keys stable across\n // re-renders for the same object identity.\n const cache = new WeakMap<Test, string>();\n let counter = 0;\n return (node: Test): string => {\n if (node.route_path) return node.route_path;\n let key = cache.get(node);\n if (!key) {\n key = `tn-${counter++}-${node.name}`;\n cache.set(node, key);\n }\n return key;\n };\n})();\n\n/**\n * The left pane: the test forest rendered through the clicky `Tree`. Selection,\n * handlers and adapters all come from the runner context; failing branches and\n * the top level open by default.\n */\nexport function TestTree({ className }: { className?: string }) {\n const runner = useTestRunner();\n return (\n <Tree<Test>\n className={cn(\"min-h-0\", className)}\n roots={runner.tests}\n getKey={nodeKey}\n getChildren={(node) => node.children}\n selected={runner.selected}\n onSelect={(node) => runner.onSelect(node === runner.selected ? null : node)}\n expandAll={runner.expandAll}\n onExpandAllChange={runner.onExpandAllChange}\n defaultOpen={(node, depth) => depth < 1 || hasFailed(node)}\n getSearchText={(node) => `${node.name} ${node.framework ?? \"\"}`}\n renderRow={({ node, selected }) => <TestTreeNode node={node} selected={selected} />}\n />\n );\n}\n"],"names":["useTestRunner","jsx","Tree","cn","hasFailed","TestTreeNode"],"mappings":";;;;;;;;AAOA,MAAM,UAAW,uBAAM;AAIrB,QAAM,4BAAY,QAAA;AAClB,MAAI,UAAU;AACd,SAAO,CAAC,SAAuB;AAC7B,QAAI,KAAK,WAAY,QAAO,KAAK;AACjC,QAAI,MAAM,MAAM,IAAI,IAAI;AACxB,QAAI,CAAC,KAAK;AACR,YAAM,MAAM,SAAS,IAAI,KAAK,IAAI;AAClC,YAAM,IAAI,MAAM,GAAG;AAAA,IACrB;AACA,WAAO;AAAA,EACT;AACF,GAAA;AAOO,SAAS,SAAS,EAAE,aAAqC;AAC9D,QAAM,SAASA,QAAAA,cAAA;AACf,SACEC,2BAAAA;AAAAA,IAACC,KAAAA;AAAAA,IAAA;AAAA,MACC,WAAWC,MAAAA,GAAG,WAAW,SAAS;AAAA,MAClC,OAAO,OAAO;AAAA,MACd,QAAQ;AAAA,MACR,aAAa,CAAC,SAAS,KAAK;AAAA,MAC5B,UAAU,OAAO;AAAA,MACjB,UAAU,CAAC,SAAS,OAAO,SAAS,SAAS,OAAO,WAAW,OAAO,IAAI;AAAA,MAC1E,WAAW,OAAO;AAAA,MAClB,mBAAmB,OAAO;AAAA,MAC1B,aAAa,CAAC,MAAM,UAAU,QAAQ,KAAKC,OAAAA,UAAU,IAAI;AAAA,MACzD,eAAe,CAAC,SAAS,GAAG,KAAK,IAAI,IAAI,KAAK,aAAa,EAAE;AAAA,MAC7D,WAAW,CAAC,EAAE,MAAM,eAAeH,2BAAAA,IAACI,aAAAA,cAAA,EAAa,MAAY,SAAA,CAAoB;AAAA,IAAA;AAAA,EAAA;AAGvF;;"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The left pane: the test forest rendered through the clicky `Tree`. Selection,
|
|
3
|
+
* handlers and adapters all come from the runner context; failing branches and
|
|
4
|
+
* the top level open by default.
|
|
5
|
+
*/
|
|
6
|
+
export declare function TestTree({ className }: {
|
|
7
|
+
className?: string;
|
|
8
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
//# sourceMappingURL=TestTree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TestTree.d.ts","sourceRoot":"","sources":["../../../src/data/test-runner/TestTree.tsx"],"names":[],"mappings":"AAwBA;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,2CAiB7D"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Tree } from "../Tree.js";
|
|
3
|
+
import { cn } from "../../lib/utils.js";
|
|
4
|
+
import { useTestRunner } from "./context.js";
|
|
5
|
+
import { hasFailed } from "./status.js";
|
|
6
|
+
import { TestTreeNode } from "./TestTreeNode.js";
|
|
7
|
+
const nodeKey = /* @__PURE__ */ (() => {
|
|
8
|
+
const cache = /* @__PURE__ */ new WeakMap();
|
|
9
|
+
let counter = 0;
|
|
10
|
+
return (node) => {
|
|
11
|
+
if (node.route_path) return node.route_path;
|
|
12
|
+
let key = cache.get(node);
|
|
13
|
+
if (!key) {
|
|
14
|
+
key = `tn-${counter++}-${node.name}`;
|
|
15
|
+
cache.set(node, key);
|
|
16
|
+
}
|
|
17
|
+
return key;
|
|
18
|
+
};
|
|
19
|
+
})();
|
|
20
|
+
function TestTree({ className }) {
|
|
21
|
+
const runner = useTestRunner();
|
|
22
|
+
return /* @__PURE__ */ jsx(
|
|
23
|
+
Tree,
|
|
24
|
+
{
|
|
25
|
+
className: cn("min-h-0", className),
|
|
26
|
+
roots: runner.tests,
|
|
27
|
+
getKey: nodeKey,
|
|
28
|
+
getChildren: (node) => node.children,
|
|
29
|
+
selected: runner.selected,
|
|
30
|
+
onSelect: (node) => runner.onSelect(node === runner.selected ? null : node),
|
|
31
|
+
expandAll: runner.expandAll,
|
|
32
|
+
onExpandAllChange: runner.onExpandAllChange,
|
|
33
|
+
defaultOpen: (node, depth) => depth < 1 || hasFailed(node),
|
|
34
|
+
getSearchText: (node) => `${node.name} ${node.framework ?? ""}`,
|
|
35
|
+
renderRow: ({ node, selected }) => /* @__PURE__ */ jsx(TestTreeNode, { node, selected })
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
export {
|
|
40
|
+
TestTree
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=TestTree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TestTree.js","sources":["../../../src/data/test-runner/TestTree.tsx"],"sourcesContent":["import { Tree } from \"../Tree\";\nimport { cn } from \"../../lib/utils\";\nimport type { Test } from \"./types\";\nimport { useTestRunner } from \"./context\";\nimport { hasFailed } from \"./status\";\nimport { TestTreeNode } from \"./TestTreeNode\";\n\nconst nodeKey = (() => {\n // Tests carry no guaranteed id; derive a stable per-render key from route_path\n // when present, else the node's name path. A WeakMap keeps keys stable across\n // re-renders for the same object identity.\n const cache = new WeakMap<Test, string>();\n let counter = 0;\n return (node: Test): string => {\n if (node.route_path) return node.route_path;\n let key = cache.get(node);\n if (!key) {\n key = `tn-${counter++}-${node.name}`;\n cache.set(node, key);\n }\n return key;\n };\n})();\n\n/**\n * The left pane: the test forest rendered through the clicky `Tree`. Selection,\n * handlers and adapters all come from the runner context; failing branches and\n * the top level open by default.\n */\nexport function TestTree({ className }: { className?: string }) {\n const runner = useTestRunner();\n return (\n <Tree<Test>\n className={cn(\"min-h-0\", className)}\n roots={runner.tests}\n getKey={nodeKey}\n getChildren={(node) => node.children}\n selected={runner.selected}\n onSelect={(node) => runner.onSelect(node === runner.selected ? null : node)}\n expandAll={runner.expandAll}\n onExpandAllChange={runner.onExpandAllChange}\n defaultOpen={(node, depth) => depth < 1 || hasFailed(node)}\n getSearchText={(node) => `${node.name} ${node.framework ?? \"\"}`}\n renderRow={({ node, selected }) => <TestTreeNode node={node} selected={selected} />}\n />\n );\n}\n"],"names":[],"mappings":";;;;;;AAOA,MAAM,UAAW,uBAAM;AAIrB,QAAM,4BAAY,QAAA;AAClB,MAAI,UAAU;AACd,SAAO,CAAC,SAAuB;AAC7B,QAAI,KAAK,WAAY,QAAO,KAAK;AACjC,QAAI,MAAM,MAAM,IAAI,IAAI;AACxB,QAAI,CAAC,KAAK;AACR,YAAM,MAAM,SAAS,IAAI,KAAK,IAAI;AAClC,YAAM,IAAI,MAAM,GAAG;AAAA,IACrB;AACA,WAAO;AAAA,EACT;AACF,GAAA;AAOO,SAAS,SAAS,EAAE,aAAqC;AAC9D,QAAM,SAAS,cAAA;AACf,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW,GAAG,WAAW,SAAS;AAAA,MAClC,OAAO,OAAO;AAAA,MACd,QAAQ;AAAA,MACR,aAAa,CAAC,SAAS,KAAK;AAAA,MAC5B,UAAU,OAAO;AAAA,MACjB,UAAU,CAAC,SAAS,OAAO,SAAS,SAAS,OAAO,WAAW,OAAO,IAAI;AAAA,MAC1E,WAAW,OAAO;AAAA,MAClB,mBAAmB,OAAO;AAAA,MAC1B,aAAa,CAAC,MAAM,UAAU,QAAQ,KAAK,UAAU,IAAI;AAAA,MACzD,eAAe,CAAC,SAAS,GAAG,KAAK,IAAI,IAAI,KAAK,aAAa,EAAE;AAAA,MAC7D,WAAW,CAAC,EAAE,MAAM,eAAe,oBAAC,cAAA,EAAa,MAAY,SAAA,CAAoB;AAAA,IAAA;AAAA,EAAA;AAGvF;"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const Icon = require("../Icon.cjs");
|
|
5
|
+
const Badge = require("../Badge.cjs");
|
|
6
|
+
const IconButton = require("../../components/IconButton.cjs");
|
|
7
|
+
const utils = require("../../lib/utils.cjs");
|
|
8
|
+
const context = require("./context.cjs");
|
|
9
|
+
const status = require("./status.cjs");
|
|
10
|
+
const frameworkIcon = require("./frameworkIcon.cjs");
|
|
11
|
+
const UiStop = require("../../icons/components/UiStop.cjs");
|
|
12
|
+
const UiRefresh = require("../../icons/components/UiRefresh.cjs");
|
|
13
|
+
const NAME_TONE = {
|
|
14
|
+
failed: "text-red-600 dark:text-red-400",
|
|
15
|
+
timedout: "text-amber-600 dark:text-amber-400",
|
|
16
|
+
warned: "text-amber-600 dark:text-amber-400",
|
|
17
|
+
running: "text-blue-600 dark:text-blue-400",
|
|
18
|
+
skipped: "text-yellow-700 dark:text-yellow-500",
|
|
19
|
+
pending: "text-muted-foreground",
|
|
20
|
+
passed: "text-foreground"
|
|
21
|
+
};
|
|
22
|
+
function CountBadges({ node }) {
|
|
23
|
+
const s = status.sum(node);
|
|
24
|
+
if (s.total === 0) return null;
|
|
25
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex shrink-0 items-center gap-1", children: [
|
|
26
|
+
s.passed > 0 && /* @__PURE__ */ jsxRuntime.jsx(Badge.Badge, { tone: "success", variant: "solid", size: "xxs", count: s.passed }),
|
|
27
|
+
s.failed > 0 && /* @__PURE__ */ jsxRuntime.jsx(Badge.Badge, { tone: "danger", variant: "solid", size: "xxs", count: s.failed }),
|
|
28
|
+
s.timedout > 0 && /* @__PURE__ */ jsxRuntime.jsx(Badge.Badge, { tone: "warning", variant: "solid", size: "xxs", count: s.timedout }),
|
|
29
|
+
s.skipped > 0 && /* @__PURE__ */ jsxRuntime.jsx(Badge.Badge, { tone: "warning", variant: "soft", size: "xxs", count: s.skipped }),
|
|
30
|
+
s.running > 0 && /* @__PURE__ */ jsxRuntime.jsx(Badge.Badge, { tone: "info", variant: "solid", size: "xxs", count: s.running }),
|
|
31
|
+
s.pending > 0 && /* @__PURE__ */ jsxRuntime.jsx(Badge.Badge, { tone: "neutral", variant: "soft", size: "xxs", count: s.pending })
|
|
32
|
+
] });
|
|
33
|
+
}
|
|
34
|
+
function TestTreeNode({ node, selected }) {
|
|
35
|
+
var _a, _b, _c;
|
|
36
|
+
const runner = context.useTestRunner();
|
|
37
|
+
const hasChildren = (((_a = node.children) == null ? void 0 : _a.length) ?? 0) > 0;
|
|
38
|
+
const status$1 = status.testStatus(node);
|
|
39
|
+
const fwIcon = frameworkIcon.frameworkIcon(node.framework);
|
|
40
|
+
const fwAdapter = runner.adapters.resolveFrameworkIcon(node, runner);
|
|
41
|
+
const fwNode = (_b = fwAdapter == null ? void 0 : fwAdapter.renderFrameworkIcon) == null ? void 0 : _b.call(fwAdapter, { node, runner });
|
|
42
|
+
const leadingAdapter = runner.adapters.resolveRowLeading(node, runner);
|
|
43
|
+
const dur = node.duration || (hasChildren ? status.totalDuration(node) : 0);
|
|
44
|
+
const canRerun = !!runner.onRerun && node.framework !== "task";
|
|
45
|
+
const canStop = !!runner.onStop && !!node.can_stop && !!node.task_id;
|
|
46
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
47
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { icon: status.statusIconFor(node), className: utils.cn("shrink-0", node.running && "animate-spin") }),
|
|
48
|
+
fwNode != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex shrink-0 items-center text-sm opacity-60", children: fwNode }) : fwIcon && /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { icon: fwIcon, className: "shrink-0 text-sm opacity-60" }),
|
|
49
|
+
(_c = leadingAdapter == null ? void 0 : leadingAdapter.renderRowLeading) == null ? void 0 : _c.call(leadingAdapter, { node, runner }),
|
|
50
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
51
|
+
"span",
|
|
52
|
+
{
|
|
53
|
+
className: utils.cn(
|
|
54
|
+
"truncate",
|
|
55
|
+
selected ? "font-semibold" : "font-medium",
|
|
56
|
+
status$1 && NAME_TONE[status$1] || "text-foreground"
|
|
57
|
+
),
|
|
58
|
+
children: status.humanizeName(node.name, node.framework)
|
|
59
|
+
}
|
|
60
|
+
),
|
|
61
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1" }),
|
|
62
|
+
node.progress && node.progress.total > 0 && !node.passed && !node.failed && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex shrink-0 items-center gap-1 text-xs text-blue-600 dark:text-blue-400", children: [
|
|
63
|
+
node.progress.phase && /* @__PURE__ */ jsxRuntime.jsx("span", { children: node.progress.phase }),
|
|
64
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "tabular-nums", children: [
|
|
65
|
+
node.progress.done,
|
|
66
|
+
"/",
|
|
67
|
+
node.progress.total
|
|
68
|
+
] })
|
|
69
|
+
] }),
|
|
70
|
+
dur > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-xs text-muted-foreground", children: status.formatTestDuration(dur) }),
|
|
71
|
+
hasChildren && /* @__PURE__ */ jsxRuntime.jsx(CountBadges, { node }),
|
|
72
|
+
canStop && /* @__PURE__ */ jsxRuntime.jsx(
|
|
73
|
+
IconButton.IconButton,
|
|
74
|
+
{
|
|
75
|
+
icon: UiStop.UiStop,
|
|
76
|
+
label: "Stop",
|
|
77
|
+
disabled: runner.busy.stop,
|
|
78
|
+
onClick: (e) => {
|
|
79
|
+
e.stopPropagation();
|
|
80
|
+
runner.onStop(node);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
),
|
|
84
|
+
canRerun && /* @__PURE__ */ jsxRuntime.jsx(
|
|
85
|
+
IconButton.IconButton,
|
|
86
|
+
{
|
|
87
|
+
icon: UiRefresh.UiRefresh,
|
|
88
|
+
label: "Rerun",
|
|
89
|
+
disabled: runner.busy.rerun,
|
|
90
|
+
onClick: (e) => {
|
|
91
|
+
e.stopPropagation();
|
|
92
|
+
runner.onRerun(node);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
)
|
|
96
|
+
] });
|
|
97
|
+
}
|
|
98
|
+
exports.TestTreeNode = TestTreeNode;
|
|
99
|
+
//# sourceMappingURL=TestTreeNode.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TestTreeNode.cjs","sources":["../../../src/data/test-runner/TestTreeNode.tsx"],"sourcesContent":["import { Icon } from \"../Icon\";\nimport { Badge } from \"../Badge\";\nimport { IconButton } from \"../../components/IconButton\";\nimport { UiRefresh, UiStop } from \"../../icons\";\nimport { cn } from \"../../lib/utils\";\nimport type { Test } from \"./types\";\nimport { useTestRunner } from \"./context\";\nimport {\n formatTestDuration,\n humanizeName,\n statusIconFor,\n sum,\n testStatus,\n totalDuration,\n} from \"./status\";\nimport { frameworkIcon } from \"./frameworkIcon\";\n\nconst NAME_TONE: Record<string, string> = {\n failed: \"text-red-600 dark:text-red-400\",\n timedout: \"text-amber-600 dark:text-amber-400\",\n warned: \"text-amber-600 dark:text-amber-400\",\n running: \"text-blue-600 dark:text-blue-400\",\n skipped: \"text-yellow-700 dark:text-yellow-500\",\n pending: \"text-muted-foreground\",\n passed: \"text-foreground\",\n};\n\n/** Per-status roll-up count badges shown on a container row. */\nfunction CountBadges({ node }: { node: Test }) {\n const s = sum(node);\n if (s.total === 0) return null;\n return (\n <span className=\"flex shrink-0 items-center gap-1\">\n {s.passed > 0 && <Badge tone=\"success\" variant=\"solid\" size=\"xxs\" count={s.passed} />}\n {s.failed > 0 && <Badge tone=\"danger\" variant=\"solid\" size=\"xxs\" count={s.failed} />}\n {s.timedout > 0 && <Badge tone=\"warning\" variant=\"solid\" size=\"xxs\" count={s.timedout} />}\n {s.skipped > 0 && <Badge tone=\"warning\" variant=\"soft\" size=\"xxs\" count={s.skipped} />}\n {s.running > 0 && <Badge tone=\"info\" variant=\"solid\" size=\"xxs\" count={s.running} />}\n {s.pending > 0 && <Badge tone=\"neutral\" variant=\"soft\" size=\"xxs\" count={s.pending} />}\n </span>\n );\n}\n\n/**\n * Renders one test tree row: status icon, optional adapter decoration + framework\n * icon, status-colored name, duration, per-status count badges, and (when the\n * runner exposes the handlers) rerun/stop buttons. Designed as the `renderRow`\n * for the clicky `Tree`.\n */\nexport function TestTreeNode({ node, selected }: { node: Test; selected: boolean }) {\n const runner = useTestRunner();\n const hasChildren = (node.children?.length ?? 0) > 0;\n const status = testStatus(node);\n const fwIcon = frameworkIcon(node.framework);\n const fwAdapter = runner.adapters.resolveFrameworkIcon(node, runner);\n const fwNode = fwAdapter?.renderFrameworkIcon?.({ node, runner });\n const leadingAdapter = runner.adapters.resolveRowLeading(node, runner);\n const dur = node.duration || (hasChildren ? totalDuration(node) : 0);\n const canRerun = !!runner.onRerun && node.framework !== \"task\";\n const canStop = !!runner.onStop && !!node.can_stop && !!node.task_id;\n\n return (\n <>\n <Icon icon={statusIconFor(node)} className={cn(\"shrink-0\", node.running && \"animate-spin\")} />\n\n {fwNode != null ? (\n <span className=\"flex shrink-0 items-center text-sm opacity-60\">{fwNode}</span>\n ) : (\n fwIcon && <Icon icon={fwIcon} className=\"shrink-0 text-sm opacity-60\" />\n )}\n\n {leadingAdapter?.renderRowLeading?.({ node, runner })}\n\n <span\n className={cn(\n \"truncate\",\n selected ? \"font-semibold\" : \"font-medium\",\n (status && NAME_TONE[status]) || \"text-foreground\",\n )}\n >\n {humanizeName(node.name, node.framework)}\n </span>\n\n <span className=\"flex-1\" />\n\n {node.progress && node.progress.total > 0 && !node.passed && !node.failed && (\n <span className=\"flex shrink-0 items-center gap-1 text-xs text-blue-600 dark:text-blue-400\">\n {node.progress.phase && <span>{node.progress.phase}</span>}\n <span className=\"tabular-nums\">\n {node.progress.done}/{node.progress.total}\n </span>\n </span>\n )}\n\n {dur > 0 && (\n <span className=\"shrink-0 text-xs text-muted-foreground\">{formatTestDuration(dur)}</span>\n )}\n\n {hasChildren && <CountBadges node={node} />}\n\n {canStop && (\n <IconButton\n icon={UiStop}\n label=\"Stop\"\n disabled={runner.busy.stop}\n onClick={(e) => {\n e.stopPropagation();\n runner.onStop!(node);\n }}\n />\n )}\n\n {canRerun && (\n <IconButton\n icon={UiRefresh}\n label=\"Rerun\"\n disabled={runner.busy.rerun}\n onClick={(e) => {\n e.stopPropagation();\n runner.onRerun!(node);\n }}\n />\n )}\n </>\n );\n}\n"],"names":["sum","jsxs","jsx","Badge","useTestRunner","status","testStatus","frameworkIcon","totalDuration","Fragment","Icon","statusIconFor","cn","humanizeName","formatTestDuration","IconButton","UiStop","UiRefresh"],"mappings":"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"}
|