@flanksource/clicky-ui 0.3.47 → 0.3.49
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/README.md +49 -0
- package/dist/comments/CommentSidePanel.cjs +10 -4
- package/dist/comments/CommentSidePanel.cjs.map +1 -1
- package/dist/comments/CommentSidePanel.d.ts +2 -0
- package/dist/comments/CommentSidePanel.d.ts.map +1 -1
- package/dist/comments/CommentSidePanel.js +10 -4
- package/dist/comments/CommentSidePanel.js.map +1 -1
- package/dist/comments/CommentThread.cjs +2 -0
- package/dist/comments/CommentThread.cjs.map +1 -1
- package/dist/comments/CommentThread.d.ts +2 -1
- package/dist/comments/CommentThread.d.ts.map +1 -1
- package/dist/comments/CommentThread.js +2 -0
- package/dist/comments/CommentThread.js.map +1 -1
- package/dist/comments/CommentThreadList.cjs +3 -0
- package/dist/comments/CommentThreadList.cjs.map +1 -1
- package/dist/comments/CommentThreadList.d.ts +3 -1
- package/dist/comments/CommentThreadList.d.ts.map +1 -1
- package/dist/comments/CommentThreadList.js +3 -0
- package/dist/comments/CommentThreadList.js.map +1 -1
- package/dist/data/CodeLine.cjs +4 -2
- package/dist/data/CodeLine.cjs.map +1 -1
- package/dist/data/CodeLine.d.ts.map +1 -1
- package/dist/data/CodeLine.js +4 -2
- package/dist/data/CodeLine.js.map +1 -1
- package/dist/data/DataTable.cjs +18 -8
- package/dist/data/DataTable.cjs.map +1 -1
- package/dist/data/DataTable.d.ts +4 -0
- package/dist/data/DataTable.d.ts.map +1 -1
- package/dist/data/DataTable.js +18 -8
- package/dist/data/DataTable.js.map +1 -1
- package/dist/data/SymbolBadge.cjs +61 -0
- package/dist/data/SymbolBadge.cjs.map +1 -0
- package/dist/data/SymbolBadge.d.ts +21 -0
- package/dist/data/SymbolBadge.d.ts.map +1 -0
- package/dist/data/SymbolBadge.js +61 -0
- package/dist/data/SymbolBadge.js.map +1 -0
- package/dist/data/TaskManager.cjs +183 -159
- package/dist/data/TaskManager.cjs.map +1 -1
- package/dist/data/TaskManager.d.ts +3 -1
- package/dist/data/TaskManager.d.ts.map +1 -1
- package/dist/data/TaskManager.js +185 -161
- package/dist/data/TaskManager.js.map +1 -1
- package/dist/data/TaskManagerButton.cjs +1 -0
- package/dist/data/TaskManagerButton.cjs.map +1 -1
- package/dist/data/TaskManagerButton.js +1 -0
- package/dist/data/TaskManagerButton.js.map +1 -1
- package/dist/data/TaskProgress.cjs +13 -7
- package/dist/data/TaskProgress.cjs.map +1 -1
- package/dist/data/TaskProgress.d.ts +3 -1
- package/dist/data/TaskProgress.d.ts.map +1 -1
- package/dist/data/TaskProgress.js +13 -7
- package/dist/data/TaskProgress.js.map +1 -1
- package/dist/data/test-runner/TestDetailPanel.cjs +26 -12
- package/dist/data/test-runner/TestDetailPanel.cjs.map +1 -1
- package/dist/data/test-runner/TestDetailPanel.d.ts.map +1 -1
- package/dist/data/test-runner/TestDetailPanel.js +27 -13
- package/dist/data/test-runner/TestDetailPanel.js.map +1 -1
- package/dist/data/test-runner/TestRunner.cjs +6 -0
- package/dist/data/test-runner/TestRunner.cjs.map +1 -1
- package/dist/data/test-runner/TestRunner.d.ts +3 -1
- package/dist/data/test-runner/TestRunner.d.ts.map +1 -1
- package/dist/data/test-runner/TestRunner.js +6 -0
- package/dist/data/test-runner/TestRunner.js.map +1 -1
- package/dist/data/test-runner/TestTreeNode.cjs +2 -1
- package/dist/data/test-runner/TestTreeNode.cjs.map +1 -1
- package/dist/data/test-runner/TestTreeNode.d.ts.map +1 -1
- package/dist/data/test-runner/TestTreeNode.js +2 -1
- package/dist/data/test-runner/TestTreeNode.js.map +1 -1
- package/dist/data/test-runner/adapter.cjs +4 -0
- package/dist/data/test-runner/adapter.cjs.map +1 -1
- package/dist/data/test-runner/adapter.d.ts +9 -0
- package/dist/data/test-runner/adapter.d.ts.map +1 -1
- package/dist/data/test-runner/adapter.js +4 -0
- package/dist/data/test-runner/adapter.js.map +1 -1
- package/dist/data/test-runner/context.cjs.map +1 -1
- package/dist/data/test-runner/context.d.ts +2 -0
- package/dist/data/test-runner/context.d.ts.map +1 -1
- package/dist/data/test-runner/context.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/marks.cjs +42 -1
- package/dist/data/test-runner/marks.cjs.map +1 -1
- package/dist/data/test-runner/marks.d.ts +10 -0
- package/dist/data/test-runner/marks.d.ts.map +1 -1
- package/dist/data/test-runner/marks.js +42 -1
- package/dist/data/test-runner/marks.js.map +1 -1
- package/dist/data/traces/ProcessTraceTree.cjs +93 -0
- package/dist/data/traces/ProcessTraceTree.cjs.map +1 -0
- package/dist/data/traces/ProcessTraceTree.d.ts +24 -0
- package/dist/data/traces/ProcessTraceTree.d.ts.map +1 -0
- package/dist/data/traces/ProcessTraceTree.js +93 -0
- package/dist/data/traces/ProcessTraceTree.js.map +1 -0
- package/dist/data/traces/Sparkline.cjs +23 -0
- package/dist/data/traces/Sparkline.cjs.map +1 -0
- package/dist/data/traces/Sparkline.d.ts +13 -0
- package/dist/data/traces/Sparkline.d.ts.map +1 -0
- package/dist/data/traces/Sparkline.js +23 -0
- package/dist/data/traces/Sparkline.js.map +1 -0
- package/dist/data/traces/SqlTraceTable.cjs +104 -0
- package/dist/data/traces/SqlTraceTable.cjs.map +1 -0
- package/dist/data/traces/SqlTraceTable.d.ts +19 -0
- package/dist/data/traces/SqlTraceTable.d.ts.map +1 -0
- package/dist/data/traces/SqlTraceTable.js +104 -0
- package/dist/data/traces/SqlTraceTable.js.map +1 -0
- package/dist/data/traces/TerminalCastPlayer.cjs +162 -0
- package/dist/data/traces/TerminalCastPlayer.cjs.map +1 -0
- package/dist/data/traces/TerminalCastPlayer.d.ts +21 -0
- package/dist/data/traces/TerminalCastPlayer.d.ts.map +1 -0
- package/dist/data/traces/TerminalCastPlayer.js +162 -0
- package/dist/data/traces/TerminalCastPlayer.js.map +1 -0
- package/dist/data/traces/TraceHarView.cjs +15 -0
- package/dist/data/traces/TraceHarView.cjs.map +1 -0
- package/dist/data/traces/TraceHarView.d.ts +13 -0
- package/dist/data/traces/TraceHarView.d.ts.map +1 -0
- package/dist/data/traces/TraceHarView.js +15 -0
- package/dist/data/traces/TraceHarView.js.map +1 -0
- package/dist/data/traces/TraceView.cjs +54 -0
- package/dist/data/traces/TraceView.cjs.map +1 -0
- package/dist/data/traces/TraceView.d.ts +18 -0
- package/dist/data/traces/TraceView.d.ts.map +1 -0
- package/dist/data/traces/TraceView.js +54 -0
- package/dist/data/traces/TraceView.js.map +1 -0
- package/dist/data/traces/cast.cjs +81 -0
- package/dist/data/traces/cast.cjs.map +1 -0
- package/dist/data/traces/cast.d.ts +9 -0
- package/dist/data/traces/cast.d.ts.map +1 -0
- package/dist/data/traces/cast.js +81 -0
- package/dist/data/traces/cast.js.map +1 -0
- package/dist/data/traces/fixtures.d.ts +8 -0
- package/dist/data/traces/fixtures.d.ts.map +1 -0
- package/dist/data/traces/har-adapter.cjs +83 -0
- package/dist/data/traces/har-adapter.cjs.map +1 -0
- package/dist/data/traces/har-adapter.d.ts +13 -0
- package/dist/data/traces/har-adapter.d.ts.map +1 -0
- package/dist/data/traces/har-adapter.js +83 -0
- package/dist/data/traces/har-adapter.js.map +1 -0
- package/dist/data/traces/index.d.ts +12 -0
- package/dist/data/traces/index.d.ts.map +1 -0
- package/dist/data/traces/process-tree.cjs +53 -0
- package/dist/data/traces/process-tree.cjs.map +1 -0
- package/dist/data/traces/process-tree.d.ts +21 -0
- package/dist/data/traces/process-tree.d.ts.map +1 -0
- package/dist/data/traces/process-tree.js +53 -0
- package/dist/data/traces/process-tree.js.map +1 -0
- package/dist/data/traces/sql-trace.cjs +39 -0
- package/dist/data/traces/sql-trace.cjs.map +1 -0
- package/dist/data/traces/sql-trace.d.ts +31 -0
- package/dist/data/traces/sql-trace.d.ts.map +1 -0
- package/dist/data/traces/sql-trace.js +39 -0
- package/dist/data/traces/sql-trace.js.map +1 -0
- package/dist/data/traces/terminal-screen.cjs +270 -0
- package/dist/data/traces/terminal-screen.cjs.map +1 -0
- package/dist/data/traces/terminal-screen.d.ts +45 -0
- package/dist/data/traces/terminal-screen.d.ts.map +1 -0
- package/dist/data/traces/terminal-screen.js +270 -0
- package/dist/data/traces/terminal-screen.js.map +1 -0
- package/dist/data/traces/terminal-timeline.cjs +48 -0
- package/dist/data/traces/terminal-timeline.cjs.map +1 -0
- package/dist/data/traces/terminal-timeline.d.ts +26 -0
- package/dist/data/traces/terminal-timeline.d.ts.map +1 -0
- package/dist/data/traces/terminal-timeline.js +48 -0
- package/dist/data/traces/terminal-timeline.js.map +1 -0
- package/dist/data/traces/types.d.ts +139 -0
- package/dist/data/traces/types.d.ts.map +1 -0
- package/dist/data/verification/VerificationResults.cjs +4 -0
- package/dist/data/verification/VerificationResults.cjs.map +1 -1
- package/dist/data/verification/VerificationResults.d.ts +3 -1
- package/dist/data/verification/VerificationResults.d.ts.map +1 -1
- package/dist/data/verification/VerificationResults.js +4 -0
- package/dist/data/verification/VerificationResults.js.map +1 -1
- package/dist/data/verification/adapterViews.cjs +12 -3
- package/dist/data/verification/adapterViews.cjs.map +1 -1
- package/dist/data/verification/adapterViews.d.ts +4 -1
- package/dist/data/verification/adapterViews.d.ts.map +1 -1
- package/dist/data/verification/adapterViews.js +12 -3
- package/dist/data/verification/adapterViews.js.map +1 -1
- package/dist/data/verification/adapters.cjs +53 -10
- package/dist/data/verification/adapters.cjs.map +1 -1
- package/dist/data/verification/adapters.d.ts +7 -1
- package/dist/data/verification/adapters.d.ts.map +1 -1
- package/dist/data/verification/adapters.js +53 -10
- package/dist/data/verification/adapters.js.map +1 -1
- package/dist/data/verification/index.d.ts +4 -2
- package/dist/data/verification/index.d.ts.map +1 -1
- package/dist/data/verification/stepKind.cjs +217 -0
- package/dist/data/verification/stepKind.cjs.map +1 -0
- package/dist/data/verification/stepKind.d.ts +87 -0
- package/dist/data/verification/stepKind.d.ts.map +1 -0
- package/dist/data/verification/stepKind.js +217 -0
- package/dist/data/verification/stepKind.js.map +1 -0
- package/dist/data/verification/stepKindViews.cjs +111 -0
- package/dist/data/verification/stepKindViews.cjs.map +1 -0
- package/dist/data/verification/stepKindViews.d.ts +18 -0
- package/dist/data/verification/stepKindViews.d.ts.map +1 -0
- package/dist/data/verification/stepKindViews.js +111 -0
- package/dist/data/verification/stepKindViews.js.map +1 -0
- package/dist/data/verification/verifyReportTests.cjs +1 -0
- package/dist/data/verification/verifyReportTests.cjs.map +1 -1
- package/dist/data/verification/verifyReportTests.d.ts +2 -1
- package/dist/data/verification/verifyReportTests.d.ts.map +1 -1
- package/dist/data/verification/verifyReportTests.js +1 -0
- package/dist/data/verification/verifyReportTests.js.map +1 -1
- package/dist/data/version-info.cjs +3 -3
- package/dist/data/version-info.cjs.map +1 -1
- package/dist/data/version-info.js +3 -3
- package/dist/data/version-info.js.map +1 -1
- package/dist/data.cjs +36 -0
- package/dist/data.cjs.map +1 -1
- package/dist/data.d.ts +2 -0
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +38 -2
- package/dist/data.js.map +1 -1
- package/dist/index.cjs +38 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +40 -2
- package/dist/index.js.map +1 -1
- package/dist/rpc/FilterForm.cjs +9 -0
- package/dist/rpc/FilterForm.cjs.map +1 -1
- package/dist/rpc/FilterForm.d.ts +5 -1
- package/dist/rpc/FilterForm.d.ts.map +1 -1
- package/dist/rpc/FilterForm.js +9 -0
- package/dist/rpc/FilterForm.js.map +1 -1
- package/dist/rpc/OperationArgsForm.cjs +153 -0
- package/dist/rpc/OperationArgsForm.cjs.map +1 -0
- package/dist/rpc/OperationArgsForm.d.ts +16 -0
- package/dist/rpc/OperationArgsForm.d.ts.map +1 -0
- package/dist/rpc/OperationArgsForm.js +153 -0
- package/dist/rpc/OperationArgsForm.js.map +1 -0
- package/dist/rpc/OperationScheduleDialog.cjs +61 -17
- package/dist/rpc/OperationScheduleDialog.cjs.map +1 -1
- package/dist/rpc/OperationScheduleDialog.d.ts +3 -0
- package/dist/rpc/OperationScheduleDialog.d.ts.map +1 -1
- package/dist/rpc/OperationScheduleDialog.js +62 -18
- package/dist/rpc/OperationScheduleDialog.js.map +1 -1
- package/dist/rpc/OperationSchedules.cjs +6 -1
- package/dist/rpc/OperationSchedules.cjs.map +1 -1
- package/dist/rpc/OperationSchedules.d.ts.map +1 -1
- package/dist/rpc/OperationSchedules.js +6 -1
- package/dist/rpc/OperationSchedules.js.map +1 -1
- package/dist/rpc/operation-schedule-model.cjs +0 -7
- package/dist/rpc/operation-schedule-model.cjs.map +1 -1
- package/dist/rpc/operation-schedule-model.d.ts +0 -2
- package/dist/rpc/operation-schedule-model.d.ts.map +1 -1
- package/dist/rpc/operation-schedule-model.js +0 -7
- package/dist/rpc/operation-schedule-model.js.map +1 -1
- package/dist/rpc/operation-schedule-types.d.ts +6 -1
- package/dist/rpc/operation-schedule-types.d.ts.map +1 -1
- package/dist/rpc.cjs +2 -0
- package/dist/rpc.cjs.map +1 -1
- package/dist/rpc.d.ts +1 -0
- package/dist/rpc.d.ts.map +1 -1
- package/dist/rpc.js +2 -0
- package/dist/rpc.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
|
@@ -21,12 +21,18 @@ const UiLogoOxc = require("../../icons/components/UiLogoOxc.cjs");
|
|
|
21
21
|
const UiLogoEslint = require("../../icons/components/UiLogoEslint.cjs");
|
|
22
22
|
const UiLogoGo = require("../../icons/components/UiLogoGo.cjs");
|
|
23
23
|
const UiSealCheck = require("../../icons/components/UiSealCheck.cjs");
|
|
24
|
+
const UiCursorClick = require("../../icons/components/UiCursorClick.cjs");
|
|
25
|
+
const UiLogoPlaywright = require("../../icons/components/UiLogoPlaywright.cjs");
|
|
26
|
+
const UiGlobe = require("../../icons/components/UiGlobe.cjs");
|
|
27
|
+
const UiRobotAi = require("../../icons/components/UiRobotAi.cjs");
|
|
28
|
+
const UiChatDots = require("../../icons/components/UiChatDots.cjs");
|
|
29
|
+
const UiClipboardText = require("../../icons/components/UiClipboardText.cjs");
|
|
30
|
+
const UiServer = require("../../icons/components/UiServer.cjs");
|
|
24
31
|
const UiDatabase = require("../../icons/components/UiDatabase.cjs");
|
|
25
32
|
const UiSparkles = require("../../icons/components/UiSparkles.cjs");
|
|
26
33
|
const UiListChecks = require("../../icons/components/UiListChecks.cjs");
|
|
27
34
|
const UiBeaker = require("../../icons/components/UiBeaker.cjs");
|
|
28
35
|
const UiTerminal = require("../../icons/components/UiTerminal.cjs");
|
|
29
|
-
const UiLogoPlaywright = require("../../icons/components/UiLogoPlaywright.cjs");
|
|
30
36
|
const UiLogoJest = require("../../icons/components/UiLogoJest.cjs");
|
|
31
37
|
const UiLogoVitest = require("../../icons/components/UiLogoVitest.cjs");
|
|
32
38
|
const LABEL = Object.fromEntries(status.STATUS_LABELS.map((s) => [s.key, s.label]));
|
|
@@ -88,6 +94,31 @@ const TEST_TOOLS = {
|
|
|
88
94
|
className: "text-violet-600 dark:text-violet-400"
|
|
89
95
|
},
|
|
90
96
|
query: { icon: UiDatabase.UiDatabase, label: "Query", kind: "fixture", className: MUTED },
|
|
97
|
+
// Typed step kinds (gavel fixtures/kind registry): the node's `framework`
|
|
98
|
+
// is the kind name. `ai` is the runner behind `verify` but is a prompt/CEL
|
|
99
|
+
// round-trip rather than an acceptance-criteria review, so it takes the
|
|
100
|
+
// same violet family with its own glyph and label.
|
|
101
|
+
services: { icon: UiServer.UiServer, label: "Services", kind: "fixture", className: MUTED },
|
|
102
|
+
todo: { icon: UiClipboardText.UiClipboardText, label: "TODO step", kind: "fixture", className: MUTED },
|
|
103
|
+
todo_prompt: { icon: UiChatDots.UiChatDots, label: "TODO prompt run", kind: "fixture", className: MUTED },
|
|
104
|
+
ai: {
|
|
105
|
+
icon: UiRobotAi.UiRobotAi,
|
|
106
|
+
label: "AI step",
|
|
107
|
+
kind: "fixture",
|
|
108
|
+
className: "text-violet-600 dark:text-violet-400"
|
|
109
|
+
},
|
|
110
|
+
browser: { icon: UiGlobe.UiGlobe, label: "Browser", kind: "fixture", className: MUTED },
|
|
111
|
+
// The fixture-step twin of the `playwright` test framework above; both
|
|
112
|
+
// arrive as framework "playwright", so toolKeyFor() picks this key when the
|
|
113
|
+
// node carries `detail.step`. Muted like every other fixture step, so the
|
|
114
|
+
// brand green stays on the spec results the framework reports.
|
|
115
|
+
"playwright-step": {
|
|
116
|
+
icon: UiLogoPlaywright.UiLogoPlaywright,
|
|
117
|
+
label: "Playwright step",
|
|
118
|
+
kind: "fixture",
|
|
119
|
+
className: MUTED
|
|
120
|
+
},
|
|
121
|
+
"agent-browser": { icon: UiCursorClick.UiCursorClick, label: "Agent browser", kind: "fixture", className: MUTED },
|
|
91
122
|
criterion: { icon: UiSealCheck.UiSealCheck, label: "Acceptance criterion", kind: "fixture", className: MUTED },
|
|
92
123
|
checklist: { icon: UiSealCheck.UiSealCheck, label: "Acceptance criteria", kind: "fixture", className: MUTED },
|
|
93
124
|
"golangci-lint": { icon: UiLogoGo.UiLogoGo, label: "golangci-lint", kind: "lint", className: GO },
|
|
@@ -136,8 +167,18 @@ const TEST_TOOLS = {
|
|
|
136
167
|
function toolMark(tool) {
|
|
137
168
|
return tool && TEST_TOOLS[tool] || null;
|
|
138
169
|
}
|
|
170
|
+
function hasStepInfo(detail) {
|
|
171
|
+
if (detail === null || typeof detail !== "object" || Array.isArray(detail)) return false;
|
|
172
|
+
const step = detail.step;
|
|
173
|
+
return step !== null && typeof step === "object" && !Array.isArray(step);
|
|
174
|
+
}
|
|
175
|
+
function toolKeyFor(node) {
|
|
176
|
+
if (node.framework === "playwright" && hasStepInfo(node.detail)) return "playwright-step";
|
|
177
|
+
return node.framework;
|
|
178
|
+
}
|
|
139
179
|
exports.LINT_SEVERITIES = LINT_SEVERITIES;
|
|
140
180
|
exports.TEST_OUTCOMES = TEST_OUTCOMES;
|
|
141
181
|
exports.TEST_TOOLS = TEST_TOOLS;
|
|
182
|
+
exports.toolKeyFor = toolKeyFor;
|
|
142
183
|
exports.toolMark = toolMark;
|
|
143
184
|
//# sourceMappingURL=marks.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"marks.cjs","sources":["../../../src/data/test-runner/marks.ts"],"sourcesContent":["// The shared iconography for test and lint results: what happened (outcome),\n// how bad a finding is (lint severity), and what produced it (tool).\n//\n// Every outcome has its own outline glyph, so a result never reads by colour\n// alone.\n// Tool marks are bundled Simple Icons brand glyphs (offline, no runtime icon\n// names), coloured per theme here because one brand hex can't hold up on both\n// light and dark surfaces.\n\nimport type { StaticIconComponent } from \"../Icon\";\nimport {\n UiCircleOutline,\n UiCircleX,\n UiBeaker,\n UiCopy,\n UiDatabase,\n UiInfo,\n UiKey,\n UiListChecks,\n UiLoader,\n UiLogoEslint,\n UiLogoGo,\n UiLogoJest,\n UiLogoMarkdown,\n UiLogoOxc,\n UiLogoPlaywright,\n UiLogoPython,\n UiLogoReact,\n UiLogoRuff,\n UiLogoTypescript,\n UiLogoVitest,\n UiPass,\n UiProhibit,\n UiSealCheck,\n UiSkipForward,\n UiSparkles,\n UiTerminal,\n UiTimer,\n UiWarningTriangle,\n} from \"../../icons\";\nimport { STATUS_LABELS, type TestOutcome } from \"./status\";\n\nexport type { TestOutcome } from \"./status\";\n\nexport type ResultMark = {\n icon: StaticIconComponent;\n label: string;\n /** Text colour classes for light and dark themes. */\n className: string;\n spin?: boolean;\n};\n\nconst LABEL = Object.fromEntries(STATUS_LABELS.map((s) => [s.key, s.label]));\n\nconst RED = \"text-red-600 dark:text-red-400\";\nconst AMBER = \"text-amber-600 dark:text-amber-400\";\n\nexport const TEST_OUTCOMES: Record<TestOutcome, ResultMark> = {\n failed: { icon: UiCircleX, label: LABEL.failed!, className: RED },\n errored: { icon: UiProhibit, label: \"Could not run\", className: RED },\n timedout: { icon: UiTimer, label: LABEL.timedout!, className: AMBER },\n warned: { icon: UiWarningTriangle, label: LABEL.warned!, className: AMBER },\n passed: {\n icon: UiPass,\n label: LABEL.passed!,\n className: \"text-emerald-600 dark:text-emerald-400\",\n },\n skipped: { icon: UiSkipForward, label: LABEL.skipped!, className: \"text-slate-500\" },\n pending: {\n icon: UiCircleOutline,\n label: LABEL.pending!,\n className: \"text-slate-400 dark:text-slate-500\",\n },\n running: {\n icon: UiLoader,\n label: LABEL.running!,\n className: \"text-blue-600 dark:text-blue-400\",\n spin: true,\n },\n};\n\nexport type LintSeverity = \"error\" | \"warning\" | \"info\";\n\n/** An error-severity finding fails the verdict and a warning warns it, so they share those outcomes' marks. */\nexport const LINT_SEVERITIES: Record<LintSeverity, ResultMark> = {\n error: { ...TEST_OUTCOMES.failed, label: \"Error\" },\n warning: { ...TEST_OUTCOMES.warned, label: \"Warning\" },\n info: { icon: UiInfo, label: \"Info\", className: \"text-sky-600 dark:text-sky-400\" },\n};\n\nexport type ToolKind = \"test\" | \"lint\" | \"fixture\" | \"runner\";\n\nexport type ToolMark = {\n icon: StaticIconComponent;\n label: string;\n kind: ToolKind;\n className: string;\n};\n\nconst GO = \"text-[#00add8]\";\nconst MARKDOWN = \"text-foreground\";\nconst MUTED = \"text-muted-foreground\";\n\n/**\n * Keyed by the identifiers gavel reports: testrunner/parsers Framework values\n * and each linter's Name(). A tool without a mark of its own takes its\n * language's (golangci-lint → Go, pyright → Python).\n */\nexport const TEST_TOOLS: Record<string, ToolMark> = {\n \"go test\": { icon: UiLogoGo, label: \"go test\", kind: \"test\", className: GO },\n ginkgo: { icon: UiLogoGo, label: \"Ginkgo\", kind: \"test\", className: GO },\n vitest: { icon: UiLogoVitest, label: \"Vitest\", kind: \"test\", className: \"text-[#6e9f18]\" },\n jest: { icon: UiLogoJest, label: \"Jest\", kind: \"test\", className: \"text-[#c21325] dark:text-[#e5576a]\" },\n playwright: {\n icon: UiLogoPlaywright,\n label: \"Playwright\",\n kind: \"test\",\n className: \"text-[#2ead33]\",\n },\n fixture: { icon: UiLogoMarkdown, label: \"Markdown fixture\", kind: \"test\", className: MARKDOWN },\n task: { icon: UiTerminal, label: \"Task\", kind: \"runner\", className: MUTED },\n // Fixture step types (gavel fixtures FixtureResult.Type) and the\n // \"checklist\" node verifyReportTests synthesizes for acceptance criteria.\n exec: { icon: UiTerminal, label: \"Command\", kind: \"fixture\", className: MUTED },\n test: { icon: UiBeaker, label: \"Test step\", kind: \"fixture\", className: MUTED },\n lint: { icon: UiListChecks, label: \"Lint step\", kind: \"fixture\", className: MUTED },\n verify: {\n icon: UiSparkles,\n label: \"AI review\",\n kind: \"fixture\",\n className: \"text-violet-600 dark:text-violet-400\",\n },\n query: { icon: UiDatabase, label: \"Query\", kind: \"fixture\", className: MUTED },\n criterion: { icon: UiSealCheck, label: \"Acceptance criterion\", kind: \"fixture\", className: MUTED },\n checklist: { icon: UiSealCheck, label: \"Acceptance criteria\", kind: \"fixture\", className: MUTED },\n \"golangci-lint\": { icon: UiLogoGo, label: \"golangci-lint\", kind: \"lint\", className: GO },\n eslint: {\n icon: UiLogoEslint,\n label: \"ESLint\",\n kind: \"lint\",\n className: \"text-[#4b32c3] dark:text-[#8080f2]\",\n },\n oxlint: {\n icon: UiLogoOxc,\n label: \"oxlint\",\n kind: \"lint\",\n className: \"text-[#0891b2] dark:text-[#00f7f1]\",\n },\n tsc: {\n icon: UiLogoTypescript,\n label: \"TypeScript compiler\",\n kind: \"lint\",\n className: \"text-[#3178c6]\",\n },\n markdownlint: { icon: UiLogoMarkdown, label: \"markdownlint\", kind: \"lint\", className: MARKDOWN },\n vale: { icon: UiLogoMarkdown, label: \"Vale (prose)\", kind: \"lint\", className: MARKDOWN },\n pyright: {\n icon: UiLogoPython,\n label: \"Pyright\",\n kind: \"lint\",\n className: \"text-[#3776ab] dark:text-[#ffd43b]\",\n },\n ruff: {\n icon: UiLogoRuff,\n label: \"Ruff\",\n kind: \"lint\",\n className: \"text-[#261230] dark:text-[#d7ff64]\",\n },\n // A secret scanner's finding is about a credential, not a language.\n betterleaks: { icon: UiKey, label: \"betterleaks (secrets)\", kind: \"lint\", className: MUTED },\n jscpd: { icon: UiCopy, label: \"jscpd (duplicate code)\", kind: \"lint\", className: MUTED },\n reactdoctor: {\n icon: UiLogoReact,\n label: \"React Doctor\",\n kind: \"lint\",\n className: \"text-[#0e7490] dark:text-[#61dafb]\",\n },\n};\n\n/** The tool's mark, or null for a tool the catalog doesn't know (render its name alone). */\nexport function toolMark(tool: string | undefined): ToolMark | null {\n return (tool && TEST_TOOLS[tool]) || null;\n}\n\n"],"names":["STATUS_LABELS","UiCircleX","UiProhibit","UiTimer","UiWarningTriangle","UiPass","UiSkipForward","UiCircleOutline","UiLoader","UiInfo","UiLogoGo","UiLogoVitest","UiLogoJest","UiLogoPlaywright","UiLogoMarkdown","UiTerminal","UiBeaker","UiListChecks","UiSparkles","UiDatabase","UiSealCheck","UiLogoEslint","UiLogoOxc","UiLogoTypescript","UiLogoPython","UiLogoRuff","UiKey","UiCopy","UiLogoReact"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"marks.cjs","sources":["../../../src/data/test-runner/marks.ts"],"sourcesContent":["// The shared iconography for test and lint results: what happened (outcome),\n// how bad a finding is (lint severity), and what produced it (tool).\n//\n// Every outcome has its own outline glyph, so a result never reads by colour\n// alone.\n// Tool marks are bundled Simple Icons brand glyphs (offline, no runtime icon\n// names), coloured per theme here because one brand hex can't hold up on both\n// light and dark surfaces.\n\nimport type { StaticIconComponent } from \"../Icon\";\nimport {\n UiCircleOutline,\n UiCircleX,\n UiBeaker,\n UiChatDots,\n UiClipboardText,\n UiCopy,\n UiCursorClick,\n UiDatabase,\n UiGlobe,\n UiInfo,\n UiKey,\n UiListChecks,\n UiLoader,\n UiLogoEslint,\n UiLogoGo,\n UiLogoJest,\n UiLogoMarkdown,\n UiLogoOxc,\n UiLogoPlaywright,\n UiLogoPython,\n UiLogoReact,\n UiLogoRuff,\n UiLogoTypescript,\n UiLogoVitest,\n UiPass,\n UiProhibit,\n UiRobotAi,\n UiSealCheck,\n UiServer,\n UiSkipForward,\n UiSparkles,\n UiTerminal,\n UiTimer,\n UiWarningTriangle,\n} from \"../../icons\";\nimport { STATUS_LABELS, type TestOutcome } from \"./status\";\n\nexport type { TestOutcome } from \"./status\";\n\nexport type ResultMark = {\n icon: StaticIconComponent;\n label: string;\n /** Text colour classes for light and dark themes. */\n className: string;\n spin?: boolean;\n};\n\nconst LABEL = Object.fromEntries(STATUS_LABELS.map((s) => [s.key, s.label]));\n\nconst RED = \"text-red-600 dark:text-red-400\";\nconst AMBER = \"text-amber-600 dark:text-amber-400\";\n\nexport const TEST_OUTCOMES: Record<TestOutcome, ResultMark> = {\n failed: { icon: UiCircleX, label: LABEL.failed!, className: RED },\n errored: { icon: UiProhibit, label: \"Could not run\", className: RED },\n timedout: { icon: UiTimer, label: LABEL.timedout!, className: AMBER },\n warned: { icon: UiWarningTriangle, label: LABEL.warned!, className: AMBER },\n passed: {\n icon: UiPass,\n label: LABEL.passed!,\n className: \"text-emerald-600 dark:text-emerald-400\",\n },\n skipped: { icon: UiSkipForward, label: LABEL.skipped!, className: \"text-slate-500\" },\n pending: {\n icon: UiCircleOutline,\n label: LABEL.pending!,\n className: \"text-slate-400 dark:text-slate-500\",\n },\n running: {\n icon: UiLoader,\n label: LABEL.running!,\n className: \"text-blue-600 dark:text-blue-400\",\n spin: true,\n },\n};\n\nexport type LintSeverity = \"error\" | \"warning\" | \"info\";\n\n/** An error-severity finding fails the verdict and a warning warns it, so they share those outcomes' marks. */\nexport const LINT_SEVERITIES: Record<LintSeverity, ResultMark> = {\n error: { ...TEST_OUTCOMES.failed, label: \"Error\" },\n warning: { ...TEST_OUTCOMES.warned, label: \"Warning\" },\n info: { icon: UiInfo, label: \"Info\", className: \"text-sky-600 dark:text-sky-400\" },\n};\n\nexport type ToolKind = \"test\" | \"lint\" | \"fixture\" | \"runner\";\n\nexport type ToolMark = {\n icon: StaticIconComponent;\n label: string;\n kind: ToolKind;\n className: string;\n};\n\nconst GO = \"text-[#00add8]\";\nconst MARKDOWN = \"text-foreground\";\nconst MUTED = \"text-muted-foreground\";\n\n/**\n * Keyed by the identifiers gavel reports: testrunner/parsers Framework values\n * and each linter's Name(). A tool without a mark of its own takes its\n * language's (golangci-lint → Go, pyright → Python).\n */\nexport const TEST_TOOLS: Record<string, ToolMark> = {\n \"go test\": { icon: UiLogoGo, label: \"go test\", kind: \"test\", className: GO },\n ginkgo: { icon: UiLogoGo, label: \"Ginkgo\", kind: \"test\", className: GO },\n vitest: { icon: UiLogoVitest, label: \"Vitest\", kind: \"test\", className: \"text-[#6e9f18]\" },\n jest: { icon: UiLogoJest, label: \"Jest\", kind: \"test\", className: \"text-[#c21325] dark:text-[#e5576a]\" },\n playwright: {\n icon: UiLogoPlaywright,\n label: \"Playwright\",\n kind: \"test\",\n className: \"text-[#2ead33]\",\n },\n fixture: { icon: UiLogoMarkdown, label: \"Markdown fixture\", kind: \"test\", className: MARKDOWN },\n task: { icon: UiTerminal, label: \"Task\", kind: \"runner\", className: MUTED },\n // Fixture step types (gavel fixtures FixtureResult.Type) and the\n // \"checklist\" node verifyReportTests synthesizes for acceptance criteria.\n exec: { icon: UiTerminal, label: \"Command\", kind: \"fixture\", className: MUTED },\n test: { icon: UiBeaker, label: \"Test step\", kind: \"fixture\", className: MUTED },\n lint: { icon: UiListChecks, label: \"Lint step\", kind: \"fixture\", className: MUTED },\n verify: {\n icon: UiSparkles,\n label: \"AI review\",\n kind: \"fixture\",\n className: \"text-violet-600 dark:text-violet-400\",\n },\n query: { icon: UiDatabase, label: \"Query\", kind: \"fixture\", className: MUTED },\n // Typed step kinds (gavel fixtures/kind registry): the node's `framework`\n // is the kind name. `ai` is the runner behind `verify` but is a prompt/CEL\n // round-trip rather than an acceptance-criteria review, so it takes the\n // same violet family with its own glyph and label.\n services: { icon: UiServer, label: \"Services\", kind: \"fixture\", className: MUTED },\n todo: { icon: UiClipboardText, label: \"TODO step\", kind: \"fixture\", className: MUTED },\n todo_prompt: { icon: UiChatDots, label: \"TODO prompt run\", kind: \"fixture\", className: MUTED },\n ai: {\n icon: UiRobotAi,\n label: \"AI step\",\n kind: \"fixture\",\n className: \"text-violet-600 dark:text-violet-400\",\n },\n browser: { icon: UiGlobe, label: \"Browser\", kind: \"fixture\", className: MUTED },\n // The fixture-step twin of the `playwright` test framework above; both\n // arrive as framework \"playwright\", so toolKeyFor() picks this key when the\n // node carries `detail.step`. Muted like every other fixture step, so the\n // brand green stays on the spec results the framework reports.\n \"playwright-step\": {\n icon: UiLogoPlaywright,\n label: \"Playwright step\",\n kind: \"fixture\",\n className: MUTED,\n },\n \"agent-browser\": { icon: UiCursorClick, label: \"Agent browser\", kind: \"fixture\", className: MUTED },\n criterion: { icon: UiSealCheck, label: \"Acceptance criterion\", kind: \"fixture\", className: MUTED },\n checklist: { icon: UiSealCheck, label: \"Acceptance criteria\", kind: \"fixture\", className: MUTED },\n \"golangci-lint\": { icon: UiLogoGo, label: \"golangci-lint\", kind: \"lint\", className: GO },\n eslint: {\n icon: UiLogoEslint,\n label: \"ESLint\",\n kind: \"lint\",\n className: \"text-[#4b32c3] dark:text-[#8080f2]\",\n },\n oxlint: {\n icon: UiLogoOxc,\n label: \"oxlint\",\n kind: \"lint\",\n className: \"text-[#0891b2] dark:text-[#00f7f1]\",\n },\n tsc: {\n icon: UiLogoTypescript,\n label: \"TypeScript compiler\",\n kind: \"lint\",\n className: \"text-[#3178c6]\",\n },\n markdownlint: { icon: UiLogoMarkdown, label: \"markdownlint\", kind: \"lint\", className: MARKDOWN },\n vale: { icon: UiLogoMarkdown, label: \"Vale (prose)\", kind: \"lint\", className: MARKDOWN },\n pyright: {\n icon: UiLogoPython,\n label: \"Pyright\",\n kind: \"lint\",\n className: \"text-[#3776ab] dark:text-[#ffd43b]\",\n },\n ruff: {\n icon: UiLogoRuff,\n label: \"Ruff\",\n kind: \"lint\",\n className: \"text-[#261230] dark:text-[#d7ff64]\",\n },\n // A secret scanner's finding is about a credential, not a language.\n betterleaks: { icon: UiKey, label: \"betterleaks (secrets)\", kind: \"lint\", className: MUTED },\n jscpd: { icon: UiCopy, label: \"jscpd (duplicate code)\", kind: \"lint\", className: MUTED },\n reactdoctor: {\n icon: UiLogoReact,\n label: \"React Doctor\",\n kind: \"lint\",\n className: \"text-[#0e7490] dark:text-[#61dafb]\",\n },\n};\n\n/** The tool's mark, or null for a tool the catalog doesn't know (render its name alone). */\nexport function toolMark(tool: string | undefined): ToolMark | null {\n return (tool && TEST_TOOLS[tool]) || null;\n}\n\nfunction hasStepInfo(detail: unknown): boolean {\n if (detail === null || typeof detail !== \"object\" || Array.isArray(detail)) return false;\n const step = (detail as Record<string, unknown>).step;\n return step !== null && typeof step === \"object\" && !Array.isArray(step);\n}\n\n/**\n * The TEST_TOOLS key for a node. A node's `framework` is the key, except that\n * \"playwright\" names both the test framework and the `playwright` fixture-step\n * kind: a node carrying `detail.step` (the fixture verifier's step id and\n * kind) is the step.\n */\nexport function toolKeyFor(node: { framework?: string | undefined; detail?: unknown }): string | undefined {\n if (node.framework === \"playwright\" && hasStepInfo(node.detail)) return \"playwright-step\";\n return node.framework;\n}\n\n"],"names":["STATUS_LABELS","UiCircleX","UiProhibit","UiTimer","UiWarningTriangle","UiPass","UiSkipForward","UiCircleOutline","UiLoader","UiInfo","UiLogoGo","UiLogoVitest","UiLogoJest","UiLogoPlaywright","UiLogoMarkdown","UiTerminal","UiBeaker","UiListChecks","UiSparkles","UiDatabase","UiServer","UiClipboardText","UiChatDots","UiRobotAi","UiGlobe","UiCursorClick","UiSealCheck","UiLogoEslint","UiLogoOxc","UiLogoTypescript","UiLogoPython","UiLogoRuff","UiKey","UiCopy","UiLogoReact"],"mappings":"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"}
|
|
@@ -27,4 +27,14 @@ export type ToolMark = {
|
|
|
27
27
|
export declare const TEST_TOOLS: Record<string, ToolMark>;
|
|
28
28
|
/** The tool's mark, or null for a tool the catalog doesn't know (render its name alone). */
|
|
29
29
|
export declare function toolMark(tool: string | undefined): ToolMark | null;
|
|
30
|
+
/**
|
|
31
|
+
* The TEST_TOOLS key for a node. A node's `framework` is the key, except that
|
|
32
|
+
* "playwright" names both the test framework and the `playwright` fixture-step
|
|
33
|
+
* kind: a node carrying `detail.step` (the fixture verifier's step id and
|
|
34
|
+
* kind) is the step.
|
|
35
|
+
*/
|
|
36
|
+
export declare function toolKeyFor(node: {
|
|
37
|
+
framework?: string | undefined;
|
|
38
|
+
detail?: unknown;
|
|
39
|
+
}): string | undefined;
|
|
30
40
|
//# sourceMappingURL=marks.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"marks.d.ts","sourceRoot":"","sources":["../../../src/data/test-runner/marks.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"marks.d.ts","sourceRoot":"","sources":["../../../src/data/test-runner/marks.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAqCnD,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AAE3D,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,mBAAmB,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAOF,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,WAAW,EAAE,UAAU,CAsBzD,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAExD,+GAA+G;AAC/G,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,YAAY,EAAE,UAAU,CAI5D,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE9D,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,mBAAmB,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,QAAQ,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAMF;;;;GAIG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CA8F/C,CAAC;AAEF,4FAA4F;AAC5F,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,IAAI,CAElE;AAQD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,GAAG,SAAS,CAGzG"}
|
|
@@ -19,12 +19,18 @@ import { UiLogoOxc } from "../../icons/components/UiLogoOxc.js";
|
|
|
19
19
|
import { UiLogoEslint } from "../../icons/components/UiLogoEslint.js";
|
|
20
20
|
import { UiLogoGo } from "../../icons/components/UiLogoGo.js";
|
|
21
21
|
import { UiSealCheck } from "../../icons/components/UiSealCheck.js";
|
|
22
|
+
import { UiCursorClick } from "../../icons/components/UiCursorClick.js";
|
|
23
|
+
import { UiLogoPlaywright } from "../../icons/components/UiLogoPlaywright.js";
|
|
24
|
+
import { UiGlobe } from "../../icons/components/UiGlobe.js";
|
|
25
|
+
import { UiRobotAi } from "../../icons/components/UiRobotAi.js";
|
|
26
|
+
import { UiChatDots } from "../../icons/components/UiChatDots.js";
|
|
27
|
+
import { UiClipboardText } from "../../icons/components/UiClipboardText.js";
|
|
28
|
+
import { UiServer } from "../../icons/components/UiServer.js";
|
|
22
29
|
import { UiDatabase } from "../../icons/components/UiDatabase.js";
|
|
23
30
|
import { UiSparkles } from "../../icons/components/UiSparkles.js";
|
|
24
31
|
import { UiListChecks } from "../../icons/components/UiListChecks.js";
|
|
25
32
|
import { UiBeaker } from "../../icons/components/UiBeaker.js";
|
|
26
33
|
import { UiTerminal } from "../../icons/components/UiTerminal.js";
|
|
27
|
-
import { UiLogoPlaywright } from "../../icons/components/UiLogoPlaywright.js";
|
|
28
34
|
import { UiLogoJest } from "../../icons/components/UiLogoJest.js";
|
|
29
35
|
import { UiLogoVitest } from "../../icons/components/UiLogoVitest.js";
|
|
30
36
|
const LABEL = Object.fromEntries(STATUS_LABELS.map((s) => [s.key, s.label]));
|
|
@@ -86,6 +92,31 @@ const TEST_TOOLS = {
|
|
|
86
92
|
className: "text-violet-600 dark:text-violet-400"
|
|
87
93
|
},
|
|
88
94
|
query: { icon: UiDatabase, label: "Query", kind: "fixture", className: MUTED },
|
|
95
|
+
// Typed step kinds (gavel fixtures/kind registry): the node's `framework`
|
|
96
|
+
// is the kind name. `ai` is the runner behind `verify` but is a prompt/CEL
|
|
97
|
+
// round-trip rather than an acceptance-criteria review, so it takes the
|
|
98
|
+
// same violet family with its own glyph and label.
|
|
99
|
+
services: { icon: UiServer, label: "Services", kind: "fixture", className: MUTED },
|
|
100
|
+
todo: { icon: UiClipboardText, label: "TODO step", kind: "fixture", className: MUTED },
|
|
101
|
+
todo_prompt: { icon: UiChatDots, label: "TODO prompt run", kind: "fixture", className: MUTED },
|
|
102
|
+
ai: {
|
|
103
|
+
icon: UiRobotAi,
|
|
104
|
+
label: "AI step",
|
|
105
|
+
kind: "fixture",
|
|
106
|
+
className: "text-violet-600 dark:text-violet-400"
|
|
107
|
+
},
|
|
108
|
+
browser: { icon: UiGlobe, label: "Browser", kind: "fixture", className: MUTED },
|
|
109
|
+
// The fixture-step twin of the `playwright` test framework above; both
|
|
110
|
+
// arrive as framework "playwright", so toolKeyFor() picks this key when the
|
|
111
|
+
// node carries `detail.step`. Muted like every other fixture step, so the
|
|
112
|
+
// brand green stays on the spec results the framework reports.
|
|
113
|
+
"playwright-step": {
|
|
114
|
+
icon: UiLogoPlaywright,
|
|
115
|
+
label: "Playwright step",
|
|
116
|
+
kind: "fixture",
|
|
117
|
+
className: MUTED
|
|
118
|
+
},
|
|
119
|
+
"agent-browser": { icon: UiCursorClick, label: "Agent browser", kind: "fixture", className: MUTED },
|
|
89
120
|
criterion: { icon: UiSealCheck, label: "Acceptance criterion", kind: "fixture", className: MUTED },
|
|
90
121
|
checklist: { icon: UiSealCheck, label: "Acceptance criteria", kind: "fixture", className: MUTED },
|
|
91
122
|
"golangci-lint": { icon: UiLogoGo, label: "golangci-lint", kind: "lint", className: GO },
|
|
@@ -134,10 +165,20 @@ const TEST_TOOLS = {
|
|
|
134
165
|
function toolMark(tool) {
|
|
135
166
|
return tool && TEST_TOOLS[tool] || null;
|
|
136
167
|
}
|
|
168
|
+
function hasStepInfo(detail) {
|
|
169
|
+
if (detail === null || typeof detail !== "object" || Array.isArray(detail)) return false;
|
|
170
|
+
const step = detail.step;
|
|
171
|
+
return step !== null && typeof step === "object" && !Array.isArray(step);
|
|
172
|
+
}
|
|
173
|
+
function toolKeyFor(node) {
|
|
174
|
+
if (node.framework === "playwright" && hasStepInfo(node.detail)) return "playwright-step";
|
|
175
|
+
return node.framework;
|
|
176
|
+
}
|
|
137
177
|
export {
|
|
138
178
|
LINT_SEVERITIES,
|
|
139
179
|
TEST_OUTCOMES,
|
|
140
180
|
TEST_TOOLS,
|
|
181
|
+
toolKeyFor,
|
|
141
182
|
toolMark
|
|
142
183
|
};
|
|
143
184
|
//# sourceMappingURL=marks.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"marks.js","sources":["../../../src/data/test-runner/marks.ts"],"sourcesContent":["// The shared iconography for test and lint results: what happened (outcome),\n// how bad a finding is (lint severity), and what produced it (tool).\n//\n// Every outcome has its own outline glyph, so a result never reads by colour\n// alone.\n// Tool marks are bundled Simple Icons brand glyphs (offline, no runtime icon\n// names), coloured per theme here because one brand hex can't hold up on both\n// light and dark surfaces.\n\nimport type { StaticIconComponent } from \"../Icon\";\nimport {\n UiCircleOutline,\n UiCircleX,\n UiBeaker,\n UiCopy,\n UiDatabase,\n UiInfo,\n UiKey,\n UiListChecks,\n UiLoader,\n UiLogoEslint,\n UiLogoGo,\n UiLogoJest,\n UiLogoMarkdown,\n UiLogoOxc,\n UiLogoPlaywright,\n UiLogoPython,\n UiLogoReact,\n UiLogoRuff,\n UiLogoTypescript,\n UiLogoVitest,\n UiPass,\n UiProhibit,\n UiSealCheck,\n UiSkipForward,\n UiSparkles,\n UiTerminal,\n UiTimer,\n UiWarningTriangle,\n} from \"../../icons\";\nimport { STATUS_LABELS, type TestOutcome } from \"./status\";\n\nexport type { TestOutcome } from \"./status\";\n\nexport type ResultMark = {\n icon: StaticIconComponent;\n label: string;\n /** Text colour classes for light and dark themes. */\n className: string;\n spin?: boolean;\n};\n\nconst LABEL = Object.fromEntries(STATUS_LABELS.map((s) => [s.key, s.label]));\n\nconst RED = \"text-red-600 dark:text-red-400\";\nconst AMBER = \"text-amber-600 dark:text-amber-400\";\n\nexport const TEST_OUTCOMES: Record<TestOutcome, ResultMark> = {\n failed: { icon: UiCircleX, label: LABEL.failed!, className: RED },\n errored: { icon: UiProhibit, label: \"Could not run\", className: RED },\n timedout: { icon: UiTimer, label: LABEL.timedout!, className: AMBER },\n warned: { icon: UiWarningTriangle, label: LABEL.warned!, className: AMBER },\n passed: {\n icon: UiPass,\n label: LABEL.passed!,\n className: \"text-emerald-600 dark:text-emerald-400\",\n },\n skipped: { icon: UiSkipForward, label: LABEL.skipped!, className: \"text-slate-500\" },\n pending: {\n icon: UiCircleOutline,\n label: LABEL.pending!,\n className: \"text-slate-400 dark:text-slate-500\",\n },\n running: {\n icon: UiLoader,\n label: LABEL.running!,\n className: \"text-blue-600 dark:text-blue-400\",\n spin: true,\n },\n};\n\nexport type LintSeverity = \"error\" | \"warning\" | \"info\";\n\n/** An error-severity finding fails the verdict and a warning warns it, so they share those outcomes' marks. */\nexport const LINT_SEVERITIES: Record<LintSeverity, ResultMark> = {\n error: { ...TEST_OUTCOMES.failed, label: \"Error\" },\n warning: { ...TEST_OUTCOMES.warned, label: \"Warning\" },\n info: { icon: UiInfo, label: \"Info\", className: \"text-sky-600 dark:text-sky-400\" },\n};\n\nexport type ToolKind = \"test\" | \"lint\" | \"fixture\" | \"runner\";\n\nexport type ToolMark = {\n icon: StaticIconComponent;\n label: string;\n kind: ToolKind;\n className: string;\n};\n\nconst GO = \"text-[#00add8]\";\nconst MARKDOWN = \"text-foreground\";\nconst MUTED = \"text-muted-foreground\";\n\n/**\n * Keyed by the identifiers gavel reports: testrunner/parsers Framework values\n * and each linter's Name(). A tool without a mark of its own takes its\n * language's (golangci-lint → Go, pyright → Python).\n */\nexport const TEST_TOOLS: Record<string, ToolMark> = {\n \"go test\": { icon: UiLogoGo, label: \"go test\", kind: \"test\", className: GO },\n ginkgo: { icon: UiLogoGo, label: \"Ginkgo\", kind: \"test\", className: GO },\n vitest: { icon: UiLogoVitest, label: \"Vitest\", kind: \"test\", className: \"text-[#6e9f18]\" },\n jest: { icon: UiLogoJest, label: \"Jest\", kind: \"test\", className: \"text-[#c21325] dark:text-[#e5576a]\" },\n playwright: {\n icon: UiLogoPlaywright,\n label: \"Playwright\",\n kind: \"test\",\n className: \"text-[#2ead33]\",\n },\n fixture: { icon: UiLogoMarkdown, label: \"Markdown fixture\", kind: \"test\", className: MARKDOWN },\n task: { icon: UiTerminal, label: \"Task\", kind: \"runner\", className: MUTED },\n // Fixture step types (gavel fixtures FixtureResult.Type) and the\n // \"checklist\" node verifyReportTests synthesizes for acceptance criteria.\n exec: { icon: UiTerminal, label: \"Command\", kind: \"fixture\", className: MUTED },\n test: { icon: UiBeaker, label: \"Test step\", kind: \"fixture\", className: MUTED },\n lint: { icon: UiListChecks, label: \"Lint step\", kind: \"fixture\", className: MUTED },\n verify: {\n icon: UiSparkles,\n label: \"AI review\",\n kind: \"fixture\",\n className: \"text-violet-600 dark:text-violet-400\",\n },\n query: { icon: UiDatabase, label: \"Query\", kind: \"fixture\", className: MUTED },\n criterion: { icon: UiSealCheck, label: \"Acceptance criterion\", kind: \"fixture\", className: MUTED },\n checklist: { icon: UiSealCheck, label: \"Acceptance criteria\", kind: \"fixture\", className: MUTED },\n \"golangci-lint\": { icon: UiLogoGo, label: \"golangci-lint\", kind: \"lint\", className: GO },\n eslint: {\n icon: UiLogoEslint,\n label: \"ESLint\",\n kind: \"lint\",\n className: \"text-[#4b32c3] dark:text-[#8080f2]\",\n },\n oxlint: {\n icon: UiLogoOxc,\n label: \"oxlint\",\n kind: \"lint\",\n className: \"text-[#0891b2] dark:text-[#00f7f1]\",\n },\n tsc: {\n icon: UiLogoTypescript,\n label: \"TypeScript compiler\",\n kind: \"lint\",\n className: \"text-[#3178c6]\",\n },\n markdownlint: { icon: UiLogoMarkdown, label: \"markdownlint\", kind: \"lint\", className: MARKDOWN },\n vale: { icon: UiLogoMarkdown, label: \"Vale (prose)\", kind: \"lint\", className: MARKDOWN },\n pyright: {\n icon: UiLogoPython,\n label: \"Pyright\",\n kind: \"lint\",\n className: \"text-[#3776ab] dark:text-[#ffd43b]\",\n },\n ruff: {\n icon: UiLogoRuff,\n label: \"Ruff\",\n kind: \"lint\",\n className: \"text-[#261230] dark:text-[#d7ff64]\",\n },\n // A secret scanner's finding is about a credential, not a language.\n betterleaks: { icon: UiKey, label: \"betterleaks (secrets)\", kind: \"lint\", className: MUTED },\n jscpd: { icon: UiCopy, label: \"jscpd (duplicate code)\", kind: \"lint\", className: MUTED },\n reactdoctor: {\n icon: UiLogoReact,\n label: \"React Doctor\",\n kind: \"lint\",\n className: \"text-[#0e7490] dark:text-[#61dafb]\",\n },\n};\n\n/** The tool's mark, or null for a tool the catalog doesn't know (render its name alone). */\nexport function toolMark(tool: string | undefined): ToolMark | null {\n return (tool && TEST_TOOLS[tool]) || null;\n}\n\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"marks.js","sources":["../../../src/data/test-runner/marks.ts"],"sourcesContent":["// The shared iconography for test and lint results: what happened (outcome),\n// how bad a finding is (lint severity), and what produced it (tool).\n//\n// Every outcome has its own outline glyph, so a result never reads by colour\n// alone.\n// Tool marks are bundled Simple Icons brand glyphs (offline, no runtime icon\n// names), coloured per theme here because one brand hex can't hold up on both\n// light and dark surfaces.\n\nimport type { StaticIconComponent } from \"../Icon\";\nimport {\n UiCircleOutline,\n UiCircleX,\n UiBeaker,\n UiChatDots,\n UiClipboardText,\n UiCopy,\n UiCursorClick,\n UiDatabase,\n UiGlobe,\n UiInfo,\n UiKey,\n UiListChecks,\n UiLoader,\n UiLogoEslint,\n UiLogoGo,\n UiLogoJest,\n UiLogoMarkdown,\n UiLogoOxc,\n UiLogoPlaywright,\n UiLogoPython,\n UiLogoReact,\n UiLogoRuff,\n UiLogoTypescript,\n UiLogoVitest,\n UiPass,\n UiProhibit,\n UiRobotAi,\n UiSealCheck,\n UiServer,\n UiSkipForward,\n UiSparkles,\n UiTerminal,\n UiTimer,\n UiWarningTriangle,\n} from \"../../icons\";\nimport { STATUS_LABELS, type TestOutcome } from \"./status\";\n\nexport type { TestOutcome } from \"./status\";\n\nexport type ResultMark = {\n icon: StaticIconComponent;\n label: string;\n /** Text colour classes for light and dark themes. */\n className: string;\n spin?: boolean;\n};\n\nconst LABEL = Object.fromEntries(STATUS_LABELS.map((s) => [s.key, s.label]));\n\nconst RED = \"text-red-600 dark:text-red-400\";\nconst AMBER = \"text-amber-600 dark:text-amber-400\";\n\nexport const TEST_OUTCOMES: Record<TestOutcome, ResultMark> = {\n failed: { icon: UiCircleX, label: LABEL.failed!, className: RED },\n errored: { icon: UiProhibit, label: \"Could not run\", className: RED },\n timedout: { icon: UiTimer, label: LABEL.timedout!, className: AMBER },\n warned: { icon: UiWarningTriangle, label: LABEL.warned!, className: AMBER },\n passed: {\n icon: UiPass,\n label: LABEL.passed!,\n className: \"text-emerald-600 dark:text-emerald-400\",\n },\n skipped: { icon: UiSkipForward, label: LABEL.skipped!, className: \"text-slate-500\" },\n pending: {\n icon: UiCircleOutline,\n label: LABEL.pending!,\n className: \"text-slate-400 dark:text-slate-500\",\n },\n running: {\n icon: UiLoader,\n label: LABEL.running!,\n className: \"text-blue-600 dark:text-blue-400\",\n spin: true,\n },\n};\n\nexport type LintSeverity = \"error\" | \"warning\" | \"info\";\n\n/** An error-severity finding fails the verdict and a warning warns it, so they share those outcomes' marks. */\nexport const LINT_SEVERITIES: Record<LintSeverity, ResultMark> = {\n error: { ...TEST_OUTCOMES.failed, label: \"Error\" },\n warning: { ...TEST_OUTCOMES.warned, label: \"Warning\" },\n info: { icon: UiInfo, label: \"Info\", className: \"text-sky-600 dark:text-sky-400\" },\n};\n\nexport type ToolKind = \"test\" | \"lint\" | \"fixture\" | \"runner\";\n\nexport type ToolMark = {\n icon: StaticIconComponent;\n label: string;\n kind: ToolKind;\n className: string;\n};\n\nconst GO = \"text-[#00add8]\";\nconst MARKDOWN = \"text-foreground\";\nconst MUTED = \"text-muted-foreground\";\n\n/**\n * Keyed by the identifiers gavel reports: testrunner/parsers Framework values\n * and each linter's Name(). A tool without a mark of its own takes its\n * language's (golangci-lint → Go, pyright → Python).\n */\nexport const TEST_TOOLS: Record<string, ToolMark> = {\n \"go test\": { icon: UiLogoGo, label: \"go test\", kind: \"test\", className: GO },\n ginkgo: { icon: UiLogoGo, label: \"Ginkgo\", kind: \"test\", className: GO },\n vitest: { icon: UiLogoVitest, label: \"Vitest\", kind: \"test\", className: \"text-[#6e9f18]\" },\n jest: { icon: UiLogoJest, label: \"Jest\", kind: \"test\", className: \"text-[#c21325] dark:text-[#e5576a]\" },\n playwright: {\n icon: UiLogoPlaywright,\n label: \"Playwright\",\n kind: \"test\",\n className: \"text-[#2ead33]\",\n },\n fixture: { icon: UiLogoMarkdown, label: \"Markdown fixture\", kind: \"test\", className: MARKDOWN },\n task: { icon: UiTerminal, label: \"Task\", kind: \"runner\", className: MUTED },\n // Fixture step types (gavel fixtures FixtureResult.Type) and the\n // \"checklist\" node verifyReportTests synthesizes for acceptance criteria.\n exec: { icon: UiTerminal, label: \"Command\", kind: \"fixture\", className: MUTED },\n test: { icon: UiBeaker, label: \"Test step\", kind: \"fixture\", className: MUTED },\n lint: { icon: UiListChecks, label: \"Lint step\", kind: \"fixture\", className: MUTED },\n verify: {\n icon: UiSparkles,\n label: \"AI review\",\n kind: \"fixture\",\n className: \"text-violet-600 dark:text-violet-400\",\n },\n query: { icon: UiDatabase, label: \"Query\", kind: \"fixture\", className: MUTED },\n // Typed step kinds (gavel fixtures/kind registry): the node's `framework`\n // is the kind name. `ai` is the runner behind `verify` but is a prompt/CEL\n // round-trip rather than an acceptance-criteria review, so it takes the\n // same violet family with its own glyph and label.\n services: { icon: UiServer, label: \"Services\", kind: \"fixture\", className: MUTED },\n todo: { icon: UiClipboardText, label: \"TODO step\", kind: \"fixture\", className: MUTED },\n todo_prompt: { icon: UiChatDots, label: \"TODO prompt run\", kind: \"fixture\", className: MUTED },\n ai: {\n icon: UiRobotAi,\n label: \"AI step\",\n kind: \"fixture\",\n className: \"text-violet-600 dark:text-violet-400\",\n },\n browser: { icon: UiGlobe, label: \"Browser\", kind: \"fixture\", className: MUTED },\n // The fixture-step twin of the `playwright` test framework above; both\n // arrive as framework \"playwright\", so toolKeyFor() picks this key when the\n // node carries `detail.step`. Muted like every other fixture step, so the\n // brand green stays on the spec results the framework reports.\n \"playwright-step\": {\n icon: UiLogoPlaywright,\n label: \"Playwright step\",\n kind: \"fixture\",\n className: MUTED,\n },\n \"agent-browser\": { icon: UiCursorClick, label: \"Agent browser\", kind: \"fixture\", className: MUTED },\n criterion: { icon: UiSealCheck, label: \"Acceptance criterion\", kind: \"fixture\", className: MUTED },\n checklist: { icon: UiSealCheck, label: \"Acceptance criteria\", kind: \"fixture\", className: MUTED },\n \"golangci-lint\": { icon: UiLogoGo, label: \"golangci-lint\", kind: \"lint\", className: GO },\n eslint: {\n icon: UiLogoEslint,\n label: \"ESLint\",\n kind: \"lint\",\n className: \"text-[#4b32c3] dark:text-[#8080f2]\",\n },\n oxlint: {\n icon: UiLogoOxc,\n label: \"oxlint\",\n kind: \"lint\",\n className: \"text-[#0891b2] dark:text-[#00f7f1]\",\n },\n tsc: {\n icon: UiLogoTypescript,\n label: \"TypeScript compiler\",\n kind: \"lint\",\n className: \"text-[#3178c6]\",\n },\n markdownlint: { icon: UiLogoMarkdown, label: \"markdownlint\", kind: \"lint\", className: MARKDOWN },\n vale: { icon: UiLogoMarkdown, label: \"Vale (prose)\", kind: \"lint\", className: MARKDOWN },\n pyright: {\n icon: UiLogoPython,\n label: \"Pyright\",\n kind: \"lint\",\n className: \"text-[#3776ab] dark:text-[#ffd43b]\",\n },\n ruff: {\n icon: UiLogoRuff,\n label: \"Ruff\",\n kind: \"lint\",\n className: \"text-[#261230] dark:text-[#d7ff64]\",\n },\n // A secret scanner's finding is about a credential, not a language.\n betterleaks: { icon: UiKey, label: \"betterleaks (secrets)\", kind: \"lint\", className: MUTED },\n jscpd: { icon: UiCopy, label: \"jscpd (duplicate code)\", kind: \"lint\", className: MUTED },\n reactdoctor: {\n icon: UiLogoReact,\n label: \"React Doctor\",\n kind: \"lint\",\n className: \"text-[#0e7490] dark:text-[#61dafb]\",\n },\n};\n\n/** The tool's mark, or null for a tool the catalog doesn't know (render its name alone). */\nexport function toolMark(tool: string | undefined): ToolMark | null {\n return (tool && TEST_TOOLS[tool]) || null;\n}\n\nfunction hasStepInfo(detail: unknown): boolean {\n if (detail === null || typeof detail !== \"object\" || Array.isArray(detail)) return false;\n const step = (detail as Record<string, unknown>).step;\n return step !== null && typeof step === \"object\" && !Array.isArray(step);\n}\n\n/**\n * The TEST_TOOLS key for a node. A node's `framework` is the key, except that\n * \"playwright\" names both the test framework and the `playwright` fixture-step\n * kind: a node carrying `detail.step` (the fixture verifier's step id and\n * kind) is the step.\n */\nexport function toolKeyFor(node: { framework?: string | undefined; detail?: unknown }): string | undefined {\n if (node.framework === \"playwright\" && hasStepInfo(node.detail)) return \"playwright-step\";\n return node.framework;\n}\n\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
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 format = require("../../lib/format.cjs");
|
|
6
|
+
const utils$1 = require("../../lib/utils.cjs");
|
|
7
|
+
const utils = require("../diagnostics/utils.cjs");
|
|
8
|
+
const Icon = require("../Icon.cjs");
|
|
9
|
+
const Tree = require("../Tree.cjs");
|
|
10
|
+
const processTree = require("./process-tree.cjs");
|
|
11
|
+
const Sparkline = require("./Sparkline.cjs");
|
|
12
|
+
const UiServerProcess = require("../../icons/components/UiServerProcess.cjs");
|
|
13
|
+
const UiDebug = require("../../icons/components/UiDebug.cjs");
|
|
14
|
+
const OPEN_DEPTH = 2;
|
|
15
|
+
function lifetimeMs(row) {
|
|
16
|
+
const end = row.exitedAt ?? row.lastSeenAt;
|
|
17
|
+
return Date.parse(end) - Date.parse(row.startedAt);
|
|
18
|
+
}
|
|
19
|
+
function ProcessRow({ node, selected, series }) {
|
|
20
|
+
const { row, exited } = node;
|
|
21
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
22
|
+
"div",
|
|
23
|
+
{
|
|
24
|
+
"data-process-key": row.key,
|
|
25
|
+
...exited ? { "data-exited": "true" } : {},
|
|
26
|
+
className: utils$1.cn("flex min-w-0 flex-1 items-center gap-1.5", exited && "opacity-60"),
|
|
27
|
+
title: row.command,
|
|
28
|
+
children: [
|
|
29
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
30
|
+
Icon.Icon,
|
|
31
|
+
{
|
|
32
|
+
icon: row.isRoot ? UiServerProcess.UiServerProcess : UiDebug.UiDebug,
|
|
33
|
+
className: row.isRoot ? "text-base text-blue-600" : "text-base text-muted-foreground"
|
|
34
|
+
}
|
|
35
|
+
),
|
|
36
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: utils$1.cn("truncate", selected ? "font-semibold text-primary" : "font-medium text-foreground"), children: utils.processLabel({ pid: row.pid, name: row.name, command: row.command }) }),
|
|
37
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "shrink-0 text-xs text-muted-foreground", children: [
|
|
38
|
+
"pid ",
|
|
39
|
+
row.pid
|
|
40
|
+
] }),
|
|
41
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1" }),
|
|
42
|
+
series ? /* @__PURE__ */ jsxRuntime.jsx(Sparkline.Sparkline, { values: series, label: `CPU % over ${series.length} samples` }) : null,
|
|
43
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: utils$1.cn("inline-flex shrink-0 items-center gap-1 text-xs", utils.processStateColor(row.status)), children: [
|
|
44
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { icon: utils.processStateIcon(row.status) }),
|
|
45
|
+
row.status
|
|
46
|
+
] }),
|
|
47
|
+
exited ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
48
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-xs tabular-nums text-muted-foreground", title: "Lifetime", children: format.formatDuration(lifetimeMs(row)) }),
|
|
49
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-xs tabular-nums text-muted-foreground", title: "Peak CPU", children: `peak ${row.peakCpuPercent.toFixed(1)}%` }),
|
|
50
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-xs tabular-nums text-muted-foreground", title: "Peak RSS", children: `peak ${format.formatBytes(row.peakRssBytes)}` })
|
|
51
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
52
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-xs tabular-nums text-muted-foreground", title: `Peak ${row.peakCpuPercent.toFixed(1)}%`, children: `${row.cpuPercent.toFixed(1)}%` }),
|
|
53
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-xs tabular-nums text-muted-foreground", title: `Peak ${format.formatBytes(row.peakRssBytes)}`, children: format.formatBytes(row.rssBytes) })
|
|
54
|
+
] })
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
function ProcessTraceTree({
|
|
60
|
+
nodes,
|
|
61
|
+
samples,
|
|
62
|
+
onSelect,
|
|
63
|
+
selectedKey,
|
|
64
|
+
emptyLabel = "No processes recorded",
|
|
65
|
+
className
|
|
66
|
+
}) {
|
|
67
|
+
const roots = react.useMemo(() => processTree.buildProcessForest(nodes), [nodes]);
|
|
68
|
+
const series = react.useMemo(() => processTree.cpuSeriesByKey(samples ?? []), [samples]);
|
|
69
|
+
const selected = react.useMemo(
|
|
70
|
+
() => selectedKey ? processTree.flattenForest(roots).find((node) => node.row.key === selectedKey) ?? null : null,
|
|
71
|
+
[roots, selectedKey]
|
|
72
|
+
);
|
|
73
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
74
|
+
Tree.Tree,
|
|
75
|
+
{
|
|
76
|
+
roots,
|
|
77
|
+
...className ? { className } : {},
|
|
78
|
+
ariaLabel: "Process tree",
|
|
79
|
+
empty: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-density-6 text-center text-muted-foreground text-sm", children: emptyLabel }),
|
|
80
|
+
getChildren: (node) => node.children,
|
|
81
|
+
getKey: (node) => node.row.key,
|
|
82
|
+
getSearchText: (node) => `${node.row.name} ${node.row.command} ${node.row.pid}`,
|
|
83
|
+
selected,
|
|
84
|
+
revealSelected: true,
|
|
85
|
+
defaultOpen: (_node, depth) => depth < OPEN_DEPTH,
|
|
86
|
+
onSelect: (node) => onSelect(node.row.key),
|
|
87
|
+
renderRow: ({ node, selected: isSelected }) => /* @__PURE__ */ jsxRuntime.jsx(ProcessRow, { node, selected: isSelected, series: series.get(node.row.key) }),
|
|
88
|
+
rowClass: (_node, isSelected) => isSelected ? "bg-primary/10 border-l-2 border-primary" : "hover:bg-accent"
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
exports.ProcessTraceTree = ProcessTraceTree;
|
|
93
|
+
//# sourceMappingURL=ProcessTraceTree.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProcessTraceTree.cjs","sources":["../../../src/data/traces/ProcessTraceTree.tsx"],"sourcesContent":["import { useMemo } from \"react\";\nimport { UiDebug, UiServerProcess } from \"../../icons\";\nimport { formatBytes, formatDuration } from \"../../lib/format\";\nimport { cn } from \"../../lib/utils\";\nimport { processLabel, processStateColor, processStateIcon } from \"../diagnostics/utils\";\nimport { Icon } from \"../Icon\";\nimport { Tree } from \"../Tree\";\nimport { buildProcessForest, cpuSeriesByKey, flattenForest, type ProcessTreeNode } from \"./process-tree\";\nimport { Sparkline } from \"./Sparkline\";\nimport type { ProcessNodeRow, ProcessSampleRow } from \"./types\";\n\n/** Roots and their direct children start open; deeper levels open on demand or to reveal the selection. */\nconst OPEN_DEPTH = 2;\n\nexport type ProcessTraceTreeProps = {\n /** `process_tree` trace records, one per process. */\n nodes: ProcessNodeRow[];\n /** `process_samples` records; a process with at least two shows a CPU sparkline. */\n samples?: ProcessSampleRow[];\n /** Called with the `key` of the clicked process. */\n onSelect: (key: string) => void;\n /** `key` of the selected process. */\n selectedKey?: string | null;\n /** Shown when there are no processes. */\n emptyLabel?: string;\n /** Classes applied to the tree root. */\n className?: string;\n};\n\nfunction lifetimeMs(row: ProcessNodeRow): number {\n const end = row.exitedAt ?? row.lastSeenAt;\n return Date.parse(end) - Date.parse(row.startedAt);\n}\n\nfunction ProcessRow({ node, selected, series }: { node: ProcessTreeNode; selected: boolean; series: number[] | undefined }) {\n const { row, exited } = node;\n return (\n <div\n data-process-key={row.key}\n {...(exited ? { \"data-exited\": \"true\" } : {})}\n className={cn(\"flex min-w-0 flex-1 items-center gap-1.5\", exited && \"opacity-60\")}\n title={row.command}\n >\n <Icon\n icon={row.isRoot ? UiServerProcess : UiDebug}\n className={row.isRoot ? \"text-base text-blue-600\" : \"text-base text-muted-foreground\"}\n />\n <span className={cn(\"truncate\", selected ? \"font-semibold text-primary\" : \"font-medium text-foreground\")}>\n {processLabel({ pid: row.pid, name: row.name, command: row.command })}\n </span>\n <span className=\"shrink-0 text-xs text-muted-foreground\">pid {row.pid}</span>\n <span className=\"flex-1\" />\n {series ? <Sparkline values={series} label={`CPU % over ${series.length} samples`} /> : null}\n <span className={cn(\"inline-flex shrink-0 items-center gap-1 text-xs\", processStateColor(row.status))}>\n <Icon icon={processStateIcon(row.status)} />\n {row.status}\n </span>\n {exited ? (\n <>\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\" title=\"Lifetime\">\n {formatDuration(lifetimeMs(row))}\n </span>\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\" title=\"Peak CPU\">\n {`peak ${row.peakCpuPercent.toFixed(1)}%`}\n </span>\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\" title=\"Peak RSS\">\n {`peak ${formatBytes(row.peakRssBytes)}`}\n </span>\n </>\n ) : (\n <>\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\" title={`Peak ${row.peakCpuPercent.toFixed(1)}%`}>\n {`${row.cpuPercent.toFixed(1)}%`}\n </span>\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\" title={`Peak ${formatBytes(row.peakRssBytes)}`}>\n {formatBytes(row.rssBytes)}\n </span>\n </>\n )}\n </div>\n );\n}\n\n/**\n * The process tree of a `process_tree` trace: a forest keyed by `key` /\n * `parentKey`, where a process whose parent was never recorded is a root.\n * Exited processes are dimmed and show their lifetime and peak usage. It is\n * built on the same `Tree` primitive and process helpers as `DiagnosticsTree`,\n * which cannot take a forest, key selection or exit information.\n */\nexport function ProcessTraceTree({\n nodes,\n samples,\n onSelect,\n selectedKey,\n emptyLabel = \"No processes recorded\",\n className,\n}: ProcessTraceTreeProps) {\n const roots = useMemo(() => buildProcessForest(nodes), [nodes]);\n const series = useMemo(() => cpuSeriesByKey(samples ?? []), [samples]);\n const selected = useMemo(\n () => (selectedKey ? (flattenForest(roots).find((node) => node.row.key === selectedKey) ?? null) : null),\n [roots, selectedKey],\n );\n\n return (\n <Tree<ProcessTreeNode>\n roots={roots}\n {...(className ? { className } : {})}\n ariaLabel=\"Process tree\"\n empty={<div className=\"p-density-6 text-center text-muted-foreground text-sm\">{emptyLabel}</div>}\n getChildren={(node) => node.children}\n getKey={(node) => node.row.key}\n getSearchText={(node) => `${node.row.name} ${node.row.command} ${node.row.pid}`}\n selected={selected}\n revealSelected\n defaultOpen={(_node, depth) => depth < OPEN_DEPTH}\n onSelect={(node) => onSelect(node.row.key)}\n renderRow={({ node, selected: isSelected }) => (\n <ProcessRow node={node} selected={isSelected} series={series.get(node.row.key)} />\n )}\n rowClass={(_node, isSelected) =>\n isSelected ? \"bg-primary/10 border-l-2 border-primary\" : \"hover:bg-accent\"\n }\n />\n );\n}\n"],"names":["jsxs","cn","jsx","Icon","UiServerProcess","UiDebug","processLabel","Sparkline","processStateColor","processStateIcon","Fragment","formatDuration","formatBytes","useMemo","buildProcessForest","cpuSeriesByKey","flattenForest","Tree"],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ProcessNodeRow, ProcessSampleRow } from './types.js';
|
|
2
|
+
export type ProcessTraceTreeProps = {
|
|
3
|
+
/** `process_tree` trace records, one per process. */
|
|
4
|
+
nodes: ProcessNodeRow[];
|
|
5
|
+
/** `process_samples` records; a process with at least two shows a CPU sparkline. */
|
|
6
|
+
samples?: ProcessSampleRow[];
|
|
7
|
+
/** Called with the `key` of the clicked process. */
|
|
8
|
+
onSelect: (key: string) => void;
|
|
9
|
+
/** `key` of the selected process. */
|
|
10
|
+
selectedKey?: string | null;
|
|
11
|
+
/** Shown when there are no processes. */
|
|
12
|
+
emptyLabel?: string;
|
|
13
|
+
/** Classes applied to the tree root. */
|
|
14
|
+
className?: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* The process tree of a `process_tree` trace: a forest keyed by `key` /
|
|
18
|
+
* `parentKey`, where a process whose parent was never recorded is a root.
|
|
19
|
+
* Exited processes are dimmed and show their lifetime and peak usage. It is
|
|
20
|
+
* built on the same `Tree` primitive and process helpers as `DiagnosticsTree`,
|
|
21
|
+
* which cannot take a forest, key selection or exit information.
|
|
22
|
+
*/
|
|
23
|
+
export declare function ProcessTraceTree({ nodes, samples, onSelect, selectedKey, emptyLabel, className, }: ProcessTraceTreeProps): import("react").JSX.Element;
|
|
24
|
+
//# sourceMappingURL=ProcessTraceTree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProcessTraceTree.d.ts","sourceRoot":"","sources":["../../../src/data/traces/ProcessTraceTree.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAKhE,MAAM,MAAM,qBAAqB,GAAG;IAClC,qDAAqD;IACrD,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,oFAAoF;IACpF,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC7B,oDAAoD;IACpD,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAwDF;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,OAAO,EACP,QAAQ,EACR,WAAW,EACX,UAAoC,EACpC,SAAS,GACV,EAAE,qBAAqB,+BA6BvB"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import { formatDuration, formatBytes } from "../../lib/format.js";
|
|
4
|
+
import { cn } from "../../lib/utils.js";
|
|
5
|
+
import { processLabel, processStateIcon, processStateColor } from "../diagnostics/utils.js";
|
|
6
|
+
import { Icon } from "../Icon.js";
|
|
7
|
+
import { Tree } from "../Tree.js";
|
|
8
|
+
import { buildProcessForest, cpuSeriesByKey, flattenForest } from "./process-tree.js";
|
|
9
|
+
import { Sparkline } from "./Sparkline.js";
|
|
10
|
+
import { UiServerProcess } from "../../icons/components/UiServerProcess.js";
|
|
11
|
+
import { UiDebug } from "../../icons/components/UiDebug.js";
|
|
12
|
+
const OPEN_DEPTH = 2;
|
|
13
|
+
function lifetimeMs(row) {
|
|
14
|
+
const end = row.exitedAt ?? row.lastSeenAt;
|
|
15
|
+
return Date.parse(end) - Date.parse(row.startedAt);
|
|
16
|
+
}
|
|
17
|
+
function ProcessRow({ node, selected, series }) {
|
|
18
|
+
const { row, exited } = node;
|
|
19
|
+
return /* @__PURE__ */ jsxs(
|
|
20
|
+
"div",
|
|
21
|
+
{
|
|
22
|
+
"data-process-key": row.key,
|
|
23
|
+
...exited ? { "data-exited": "true" } : {},
|
|
24
|
+
className: cn("flex min-w-0 flex-1 items-center gap-1.5", exited && "opacity-60"),
|
|
25
|
+
title: row.command,
|
|
26
|
+
children: [
|
|
27
|
+
/* @__PURE__ */ jsx(
|
|
28
|
+
Icon,
|
|
29
|
+
{
|
|
30
|
+
icon: row.isRoot ? UiServerProcess : UiDebug,
|
|
31
|
+
className: row.isRoot ? "text-base text-blue-600" : "text-base text-muted-foreground"
|
|
32
|
+
}
|
|
33
|
+
),
|
|
34
|
+
/* @__PURE__ */ jsx("span", { className: cn("truncate", selected ? "font-semibold text-primary" : "font-medium text-foreground"), children: processLabel({ pid: row.pid, name: row.name, command: row.command }) }),
|
|
35
|
+
/* @__PURE__ */ jsxs("span", { className: "shrink-0 text-xs text-muted-foreground", children: [
|
|
36
|
+
"pid ",
|
|
37
|
+
row.pid
|
|
38
|
+
] }),
|
|
39
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1" }),
|
|
40
|
+
series ? /* @__PURE__ */ jsx(Sparkline, { values: series, label: `CPU % over ${series.length} samples` }) : null,
|
|
41
|
+
/* @__PURE__ */ jsxs("span", { className: cn("inline-flex shrink-0 items-center gap-1 text-xs", processStateColor(row.status)), children: [
|
|
42
|
+
/* @__PURE__ */ jsx(Icon, { icon: processStateIcon(row.status) }),
|
|
43
|
+
row.status
|
|
44
|
+
] }),
|
|
45
|
+
exited ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
46
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs tabular-nums text-muted-foreground", title: "Lifetime", children: formatDuration(lifetimeMs(row)) }),
|
|
47
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs tabular-nums text-muted-foreground", title: "Peak CPU", children: `peak ${row.peakCpuPercent.toFixed(1)}%` }),
|
|
48
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs tabular-nums text-muted-foreground", title: "Peak RSS", children: `peak ${formatBytes(row.peakRssBytes)}` })
|
|
49
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
50
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs tabular-nums text-muted-foreground", title: `Peak ${row.peakCpuPercent.toFixed(1)}%`, children: `${row.cpuPercent.toFixed(1)}%` }),
|
|
51
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs tabular-nums text-muted-foreground", title: `Peak ${formatBytes(row.peakRssBytes)}`, children: formatBytes(row.rssBytes) })
|
|
52
|
+
] })
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
function ProcessTraceTree({
|
|
58
|
+
nodes,
|
|
59
|
+
samples,
|
|
60
|
+
onSelect,
|
|
61
|
+
selectedKey,
|
|
62
|
+
emptyLabel = "No processes recorded",
|
|
63
|
+
className
|
|
64
|
+
}) {
|
|
65
|
+
const roots = useMemo(() => buildProcessForest(nodes), [nodes]);
|
|
66
|
+
const series = useMemo(() => cpuSeriesByKey(samples ?? []), [samples]);
|
|
67
|
+
const selected = useMemo(
|
|
68
|
+
() => selectedKey ? flattenForest(roots).find((node) => node.row.key === selectedKey) ?? null : null,
|
|
69
|
+
[roots, selectedKey]
|
|
70
|
+
);
|
|
71
|
+
return /* @__PURE__ */ jsx(
|
|
72
|
+
Tree,
|
|
73
|
+
{
|
|
74
|
+
roots,
|
|
75
|
+
...className ? { className } : {},
|
|
76
|
+
ariaLabel: "Process tree",
|
|
77
|
+
empty: /* @__PURE__ */ jsx("div", { className: "p-density-6 text-center text-muted-foreground text-sm", children: emptyLabel }),
|
|
78
|
+
getChildren: (node) => node.children,
|
|
79
|
+
getKey: (node) => node.row.key,
|
|
80
|
+
getSearchText: (node) => `${node.row.name} ${node.row.command} ${node.row.pid}`,
|
|
81
|
+
selected,
|
|
82
|
+
revealSelected: true,
|
|
83
|
+
defaultOpen: (_node, depth) => depth < OPEN_DEPTH,
|
|
84
|
+
onSelect: (node) => onSelect(node.row.key),
|
|
85
|
+
renderRow: ({ node, selected: isSelected }) => /* @__PURE__ */ jsx(ProcessRow, { node, selected: isSelected, series: series.get(node.row.key) }),
|
|
86
|
+
rowClass: (_node, isSelected) => isSelected ? "bg-primary/10 border-l-2 border-primary" : "hover:bg-accent"
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
export {
|
|
91
|
+
ProcessTraceTree
|
|
92
|
+
};
|
|
93
|
+
//# sourceMappingURL=ProcessTraceTree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProcessTraceTree.js","sources":["../../../src/data/traces/ProcessTraceTree.tsx"],"sourcesContent":["import { useMemo } from \"react\";\nimport { UiDebug, UiServerProcess } from \"../../icons\";\nimport { formatBytes, formatDuration } from \"../../lib/format\";\nimport { cn } from \"../../lib/utils\";\nimport { processLabel, processStateColor, processStateIcon } from \"../diagnostics/utils\";\nimport { Icon } from \"../Icon\";\nimport { Tree } from \"../Tree\";\nimport { buildProcessForest, cpuSeriesByKey, flattenForest, type ProcessTreeNode } from \"./process-tree\";\nimport { Sparkline } from \"./Sparkline\";\nimport type { ProcessNodeRow, ProcessSampleRow } from \"./types\";\n\n/** Roots and their direct children start open; deeper levels open on demand or to reveal the selection. */\nconst OPEN_DEPTH = 2;\n\nexport type ProcessTraceTreeProps = {\n /** `process_tree` trace records, one per process. */\n nodes: ProcessNodeRow[];\n /** `process_samples` records; a process with at least two shows a CPU sparkline. */\n samples?: ProcessSampleRow[];\n /** Called with the `key` of the clicked process. */\n onSelect: (key: string) => void;\n /** `key` of the selected process. */\n selectedKey?: string | null;\n /** Shown when there are no processes. */\n emptyLabel?: string;\n /** Classes applied to the tree root. */\n className?: string;\n};\n\nfunction lifetimeMs(row: ProcessNodeRow): number {\n const end = row.exitedAt ?? row.lastSeenAt;\n return Date.parse(end) - Date.parse(row.startedAt);\n}\n\nfunction ProcessRow({ node, selected, series }: { node: ProcessTreeNode; selected: boolean; series: number[] | undefined }) {\n const { row, exited } = node;\n return (\n <div\n data-process-key={row.key}\n {...(exited ? { \"data-exited\": \"true\" } : {})}\n className={cn(\"flex min-w-0 flex-1 items-center gap-1.5\", exited && \"opacity-60\")}\n title={row.command}\n >\n <Icon\n icon={row.isRoot ? UiServerProcess : UiDebug}\n className={row.isRoot ? \"text-base text-blue-600\" : \"text-base text-muted-foreground\"}\n />\n <span className={cn(\"truncate\", selected ? \"font-semibold text-primary\" : \"font-medium text-foreground\")}>\n {processLabel({ pid: row.pid, name: row.name, command: row.command })}\n </span>\n <span className=\"shrink-0 text-xs text-muted-foreground\">pid {row.pid}</span>\n <span className=\"flex-1\" />\n {series ? <Sparkline values={series} label={`CPU % over ${series.length} samples`} /> : null}\n <span className={cn(\"inline-flex shrink-0 items-center gap-1 text-xs\", processStateColor(row.status))}>\n <Icon icon={processStateIcon(row.status)} />\n {row.status}\n </span>\n {exited ? (\n <>\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\" title=\"Lifetime\">\n {formatDuration(lifetimeMs(row))}\n </span>\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\" title=\"Peak CPU\">\n {`peak ${row.peakCpuPercent.toFixed(1)}%`}\n </span>\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\" title=\"Peak RSS\">\n {`peak ${formatBytes(row.peakRssBytes)}`}\n </span>\n </>\n ) : (\n <>\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\" title={`Peak ${row.peakCpuPercent.toFixed(1)}%`}>\n {`${row.cpuPercent.toFixed(1)}%`}\n </span>\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\" title={`Peak ${formatBytes(row.peakRssBytes)}`}>\n {formatBytes(row.rssBytes)}\n </span>\n </>\n )}\n </div>\n );\n}\n\n/**\n * The process tree of a `process_tree` trace: a forest keyed by `key` /\n * `parentKey`, where a process whose parent was never recorded is a root.\n * Exited processes are dimmed and show their lifetime and peak usage. It is\n * built on the same `Tree` primitive and process helpers as `DiagnosticsTree`,\n * which cannot take a forest, key selection or exit information.\n */\nexport function ProcessTraceTree({\n nodes,\n samples,\n onSelect,\n selectedKey,\n emptyLabel = \"No processes recorded\",\n className,\n}: ProcessTraceTreeProps) {\n const roots = useMemo(() => buildProcessForest(nodes), [nodes]);\n const series = useMemo(() => cpuSeriesByKey(samples ?? []), [samples]);\n const selected = useMemo(\n () => (selectedKey ? (flattenForest(roots).find((node) => node.row.key === selectedKey) ?? null) : null),\n [roots, selectedKey],\n );\n\n return (\n <Tree<ProcessTreeNode>\n roots={roots}\n {...(className ? { className } : {})}\n ariaLabel=\"Process tree\"\n empty={<div className=\"p-density-6 text-center text-muted-foreground text-sm\">{emptyLabel}</div>}\n getChildren={(node) => node.children}\n getKey={(node) => node.row.key}\n getSearchText={(node) => `${node.row.name} ${node.row.command} ${node.row.pid}`}\n selected={selected}\n revealSelected\n defaultOpen={(_node, depth) => depth < OPEN_DEPTH}\n onSelect={(node) => onSelect(node.row.key)}\n renderRow={({ node, selected: isSelected }) => (\n <ProcessRow node={node} selected={isSelected} series={series.get(node.row.key)} />\n )}\n rowClass={(_node, isSelected) =>\n isSelected ? \"bg-primary/10 border-l-2 border-primary\" : \"hover:bg-accent\"\n }\n />\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const utils = require("../../lib/utils.cjs");
|
|
5
|
+
const processTree = require("./process-tree.cjs");
|
|
6
|
+
function Sparkline({ values, label, width = 64, height = 16, className }) {
|
|
7
|
+
const points = processTree.sparklinePoints(values, width, height);
|
|
8
|
+
if (!points) return null;
|
|
9
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10
|
+
"svg",
|
|
11
|
+
{
|
|
12
|
+
role: "img",
|
|
13
|
+
"aria-label": label,
|
|
14
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
15
|
+
width,
|
|
16
|
+
height,
|
|
17
|
+
className: utils.cn("shrink-0 overflow-visible text-primary", className),
|
|
18
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points, fill: "none", stroke: "currentColor", strokeWidth: 1.25, strokeLinejoin: "round" })
|
|
19
|
+
}
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
exports.Sparkline = Sparkline;
|
|
23
|
+
//# sourceMappingURL=Sparkline.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Sparkline.cjs","sources":["../../../src/data/traces/Sparkline.tsx"],"sourcesContent":["import { cn } from \"../../lib/utils\";\nimport { sparklinePoints } from \"./process-tree\";\n\nexport type SparklineProps = {\n /** Values in order; at least two are needed to draw a line. */\n values: number[];\n /** Accessible description of what the line plots. */\n label: string;\n width?: number;\n height?: number;\n /** Classes applied to the svg; the stroke follows the text colour. */\n className?: string;\n};\n\n/** A dependency-free inline SVG line, scaled so the largest value touches the top. */\nexport function Sparkline({ values, label, width = 64, height = 16, className }: SparklineProps) {\n const points = sparklinePoints(values, width, height);\n if (!points) return null;\n return (\n <svg\n role=\"img\"\n aria-label={label}\n viewBox={`0 0 ${width} ${height}`}\n width={width}\n height={height}\n className={cn(\"shrink-0 overflow-visible text-primary\", className)}\n >\n <polyline points={points} fill=\"none\" stroke=\"currentColor\" strokeWidth={1.25} strokeLinejoin=\"round\" />\n </svg>\n );\n}\n"],"names":["sparklinePoints","jsx","cn"],"mappings":";;;;;AAeO,SAAS,UAAU,EAAE,QAAQ,OAAO,QAAQ,IAAI,SAAS,IAAI,aAA6B;AAC/F,QAAM,SAASA,YAAAA,gBAAgB,QAAQ,OAAO,MAAM;AACpD,MAAI,CAAC,OAAQ,QAAO;AACpB,SACEC,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAY;AAAA,MACZ,SAAS,OAAO,KAAK,IAAI,MAAM;AAAA,MAC/B;AAAA,MACA;AAAA,MACA,WAAWC,MAAAA,GAAG,0CAA0C,SAAS;AAAA,MAEjE,UAAAD,2BAAAA,IAAC,YAAA,EAAS,QAAgB,MAAK,QAAO,QAAO,gBAAe,aAAa,MAAM,gBAAe,QAAA,CAAQ;AAAA,IAAA;AAAA,EAAA;AAG5G;;"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type SparklineProps = {
|
|
2
|
+
/** Values in order; at least two are needed to draw a line. */
|
|
3
|
+
values: number[];
|
|
4
|
+
/** Accessible description of what the line plots. */
|
|
5
|
+
label: string;
|
|
6
|
+
width?: number;
|
|
7
|
+
height?: number;
|
|
8
|
+
/** Classes applied to the svg; the stroke follows the text colour. */
|
|
9
|
+
className?: string;
|
|
10
|
+
};
|
|
11
|
+
/** A dependency-free inline SVG line, scaled so the largest value touches the top. */
|
|
12
|
+
export declare function Sparkline({ values, label, width, height, className }: SparklineProps): import("react").JSX.Element | null;
|
|
13
|
+
//# sourceMappingURL=Sparkline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Sparkline.d.ts","sourceRoot":"","sources":["../../../src/data/traces/Sparkline.tsx"],"names":[],"mappings":"AAGA,MAAM,MAAM,cAAc,GAAG;IAC3B,+DAA+D;IAC/D,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,qDAAqD;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,sFAAsF;AACtF,wBAAgB,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,KAAU,EAAE,MAAW,EAAE,SAAS,EAAE,EAAE,cAAc,sCAe9F"}
|