@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
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../../lib/utils.js";
|
|
3
|
+
import { sparklinePoints } from "./process-tree.js";
|
|
4
|
+
function Sparkline({ values, label, width = 64, height = 16, className }) {
|
|
5
|
+
const points = sparklinePoints(values, width, height);
|
|
6
|
+
if (!points) return null;
|
|
7
|
+
return /* @__PURE__ */ jsx(
|
|
8
|
+
"svg",
|
|
9
|
+
{
|
|
10
|
+
role: "img",
|
|
11
|
+
"aria-label": label,
|
|
12
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
13
|
+
width,
|
|
14
|
+
height,
|
|
15
|
+
className: cn("shrink-0 overflow-visible text-primary", className),
|
|
16
|
+
children: /* @__PURE__ */ jsx("polyline", { points, fill: "none", stroke: "currentColor", strokeWidth: 1.25, strokeLinejoin: "round" })
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
Sparkline
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=Sparkline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Sparkline.js","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":[],"mappings":";;;AAeO,SAAS,UAAU,EAAE,QAAQ,OAAO,QAAQ,IAAI,SAAS,IAAI,aAA6B;AAC/F,QAAM,SAAS,gBAAgB,QAAQ,OAAO,MAAM;AACpD,MAAI,CAAC,OAAQ,QAAO;AACpB,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAY;AAAA,MACZ,SAAS,OAAO,KAAK,IAAI,MAAM;AAAA,MAC/B;AAAA,MACA;AAAA,MACA,WAAW,GAAG,0CAA0C,SAAS;AAAA,MAEjE,UAAA,oBAAC,YAAA,EAAS,QAAgB,MAAK,QAAO,QAAO,gBAAe,aAAa,MAAM,gBAAe,QAAA,CAAQ;AAAA,IAAA;AAAA,EAAA;AAG5G;"}
|
|
@@ -0,0 +1,104 @@
|
|
|
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 Switch = require("../../components/Switch.cjs");
|
|
6
|
+
const utils = require("../../lib/utils.cjs");
|
|
7
|
+
const Badge = require("../Badge.cjs");
|
|
8
|
+
const CodeBlock = require("../CodeBlock.cjs");
|
|
9
|
+
const DataTable = require("../DataTable.cjs");
|
|
10
|
+
const JsonView = require("../JsonView.cjs");
|
|
11
|
+
const sqlTrace = require("./sql-trace.cjs");
|
|
12
|
+
const COLUMNS = [
|
|
13
|
+
{ key: "startedAt", label: "Time", kind: "timestamp", shrink: true },
|
|
14
|
+
{
|
|
15
|
+
key: "op",
|
|
16
|
+
label: "Op",
|
|
17
|
+
shrink: true,
|
|
18
|
+
filterable: true,
|
|
19
|
+
render: (value) => /* @__PURE__ */ jsxRuntime.jsx(Badge.Badge, { variant: "soft", tone: "neutral", size: "xs", className: "font-mono", children: String(value) })
|
|
20
|
+
},
|
|
21
|
+
{ key: "tables", label: "Tables", kind: "tags", shrink: true },
|
|
22
|
+
{
|
|
23
|
+
key: "sql",
|
|
24
|
+
label: "SQL",
|
|
25
|
+
grow: true,
|
|
26
|
+
render: (_value, row) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-density-2", children: [
|
|
27
|
+
/* @__PURE__ */ jsxRuntime.jsx(CodeBlock.CodeBlock, { inline: true, language: "sql", source: row.sql }),
|
|
28
|
+
row.count > 1 ? /* @__PURE__ */ jsxRuntime.jsx("span", { title: `${row.count} executions`, children: /* @__PURE__ */ jsxRuntime.jsx(Badge.Badge, { variant: "soft", tone: "info", size: "xs", children: `×${row.count}` }) }) : null
|
|
29
|
+
] })
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
key: "durationMs",
|
|
33
|
+
label: "Duration",
|
|
34
|
+
align: "right",
|
|
35
|
+
shrink: true,
|
|
36
|
+
render: (value, row) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", title: row.count > 1 ? `${row.count} executions in total` : void 0, children: sqlTrace.formatStatementDuration(Number(value)) }),
|
|
37
|
+
sortValue: (value) => Number(value)
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
key: "rows",
|
|
41
|
+
label: "Rows",
|
|
42
|
+
align: "right",
|
|
43
|
+
shrink: true,
|
|
44
|
+
render: (value) => Number(value) < 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "—" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: String(value) }),
|
|
45
|
+
sortValue: (value) => Number(value)
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
key: "error",
|
|
49
|
+
label: "Error",
|
|
50
|
+
grow: true,
|
|
51
|
+
render: (value, row) => value ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "truncate text-destructive", title: String(value), children: [
|
|
52
|
+
String(value),
|
|
53
|
+
row.count > 1 ? ` (${row.failed} of ${row.count} failed)` : ""
|
|
54
|
+
] }) : null
|
|
55
|
+
}
|
|
56
|
+
];
|
|
57
|
+
function StatementDetails({ row }) {
|
|
58
|
+
var _a;
|
|
59
|
+
const [first] = row.occurrences;
|
|
60
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-density-3", children: [
|
|
61
|
+
/* @__PURE__ */ jsxRuntime.jsx(CodeBlock.CodeBlock, { language: "sql", source: row.sql, copyable: true }),
|
|
62
|
+
row.error ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
63
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-1 font-semibold text-foreground", children: "Error" }),
|
|
64
|
+
/* @__PURE__ */ jsxRuntime.jsx("pre", { className: "whitespace-pre-wrap break-all text-destructive", children: row.error })
|
|
65
|
+
] }) : null,
|
|
66
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground", children: [
|
|
67
|
+
first.connection,
|
|
68
|
+
" · ",
|
|
69
|
+
first.driver,
|
|
70
|
+
((_a = first.truncated) == null ? void 0 : _a.length) ? ` · truncated: ${first.truncated.join(", ")}` : ""
|
|
71
|
+
] }),
|
|
72
|
+
row.count > 1 ? /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-1 text-xs", "aria-label": "Executions", children: row.occurrences.map((occurrence, index) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: utils.cn("flex items-baseline gap-density-3", occurrence.error && "text-destructive"), children: [
|
|
73
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums text-muted-foreground", children: occurrence.startedAt }),
|
|
74
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: sqlTrace.formatStatementDuration(occurrence.durationMs) }),
|
|
75
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: occurrence.rows < 0 ? "— rows" : `${occurrence.rows} rows` }),
|
|
76
|
+
occurrence.args ? /* @__PURE__ */ jsxRuntime.jsx("code", { className: "font-mono", children: JSON.stringify(occurrence.args) }) : null,
|
|
77
|
+
occurrence.error ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: occurrence.error }) : null
|
|
78
|
+
] }, index)) }) : first.args ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
79
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-1 font-semibold text-foreground", children: "Arguments" }),
|
|
80
|
+
/* @__PURE__ */ jsxRuntime.jsx(JsonView.JsonView, { data: first.args })
|
|
81
|
+
] }) : null
|
|
82
|
+
] });
|
|
83
|
+
}
|
|
84
|
+
function SqlTraceTable({ rows, groupRepeated = true, emptyLabel = "No SQL statements recorded", className }) {
|
|
85
|
+
const [group, setGroup] = react.useState(groupRepeated);
|
|
86
|
+
const displayRows = react.useMemo(() => sqlTrace.groupStatements(rows, { group }), [rows, group]);
|
|
87
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: utils.cn("flex h-full min-h-0 flex-col gap-density-2", className), children: [
|
|
88
|
+
/* @__PURE__ */ jsxRuntime.jsx(Switch.Switch, { checked: group, onChange: setGroup, label: "Group repeated statements", className: "self-start px-density-2" }),
|
|
89
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
90
|
+
DataTable.DataTable,
|
|
91
|
+
{
|
|
92
|
+
data: displayRows,
|
|
93
|
+
columns: COLUMNS,
|
|
94
|
+
autoFilter: true,
|
|
95
|
+
emptyMessage: emptyLabel,
|
|
96
|
+
globalFilterPlaceholder: "Filter SQL, table, or error…",
|
|
97
|
+
getRowId: (row) => row.id,
|
|
98
|
+
renderExpandedRow: (row) => /* @__PURE__ */ jsxRuntime.jsx(StatementDetails, { row })
|
|
99
|
+
}
|
|
100
|
+
)
|
|
101
|
+
] });
|
|
102
|
+
}
|
|
103
|
+
exports.SqlTraceTable = SqlTraceTable;
|
|
104
|
+
//# sourceMappingURL=SqlTraceTable.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SqlTraceTable.cjs","sources":["../../../src/data/traces/SqlTraceTable.tsx"],"sourcesContent":["import { useMemo, useState } from \"react\";\nimport { Switch } from \"../../components/Switch\";\nimport { cn } from \"../../lib/utils\";\nimport { Badge } from \"../Badge\";\nimport { CodeBlock } from \"../CodeBlock\";\nimport { DataTable, type DataTableColumn } from \"../DataTable\";\nimport { JsonView } from \"../JsonView\";\nimport { formatStatementDuration, groupStatements, type SqlDisplayRow } from \"./sql-trace\";\nimport type { SqlStatementRow } from \"./types\";\n\nexport type SqlTraceTableProps = {\n /** `pg_proxy` / `sql_statements` trace records. */\n rows: SqlStatementRow[];\n /** Start with statements sharing a `repeatKey` collapsed into one counted row. Defaults to true. */\n groupRepeated?: boolean;\n /** Shown when there are no statements. */\n emptyLabel?: string;\n /** Classes applied to the table root. */\n className?: string;\n};\n\nconst COLUMNS: DataTableColumn<SqlDisplayRow>[] = [\n { key: \"startedAt\", label: \"Time\", kind: \"timestamp\", shrink: true },\n {\n key: \"op\",\n label: \"Op\",\n shrink: true,\n filterable: true,\n render: (value) => (\n <Badge variant=\"soft\" tone=\"neutral\" size=\"xs\" className=\"font-mono\">\n {String(value)}\n </Badge>\n ),\n },\n { key: \"tables\", label: \"Tables\", kind: \"tags\", shrink: true },\n {\n key: \"sql\",\n label: \"SQL\",\n grow: true,\n render: (_value, row) => (\n <span className=\"flex min-w-0 items-center gap-density-2\">\n <CodeBlock inline language=\"sql\" source={row.sql} />\n {row.count > 1 ? (\n <span title={`${row.count} executions`}>\n <Badge variant=\"soft\" tone=\"info\" size=\"xs\">\n {`×${row.count}`}\n </Badge>\n </span>\n ) : null}\n </span>\n ),\n },\n {\n key: \"durationMs\",\n label: \"Duration\",\n align: \"right\",\n shrink: true,\n render: (value, row) => (\n <span className=\"tabular-nums\" title={row.count > 1 ? `${row.count} executions in total` : undefined}>\n {formatStatementDuration(Number(value))}\n </span>\n ),\n sortValue: (value) => Number(value),\n },\n {\n key: \"rows\",\n label: \"Rows\",\n align: \"right\",\n shrink: true,\n render: (value) => (Number(value) < 0 ? <span className=\"text-muted-foreground\">—</span> : <span className=\"tabular-nums\">{String(value)}</span>),\n sortValue: (value) => Number(value),\n },\n {\n key: \"error\",\n label: \"Error\",\n grow: true,\n render: (value, row) =>\n value ? (\n <span className=\"truncate text-destructive\" title={String(value)}>\n {String(value)}\n {row.count > 1 ? ` (${row.failed} of ${row.count} failed)` : \"\"}\n </span>\n ) : null,\n },\n];\n\nfunction StatementDetails({ row }: { row: SqlDisplayRow }) {\n const [first] = row.occurrences as [SqlStatementRow, ...SqlStatementRow[]];\n return (\n <div className=\"space-y-density-3\">\n <CodeBlock language=\"sql\" source={row.sql} copyable />\n {row.error ? (\n <div>\n <div className=\"mb-1 font-semibold text-foreground\">Error</div>\n <pre className=\"whitespace-pre-wrap break-all text-destructive\">{row.error}</pre>\n </div>\n ) : null}\n <div className=\"text-xs text-muted-foreground\">\n {first.connection} · {first.driver}\n {first.truncated?.length ? ` · truncated: ${first.truncated.join(\", \")}` : \"\"}\n </div>\n {row.count > 1 ? (\n <ul className=\"space-y-1 text-xs\" aria-label=\"Executions\">\n {row.occurrences.map((occurrence, index) => (\n <li key={index} className={cn(\"flex items-baseline gap-density-3\", occurrence.error && \"text-destructive\")}>\n <span className=\"tabular-nums text-muted-foreground\">{occurrence.startedAt}</span>\n <span className=\"tabular-nums\">{formatStatementDuration(occurrence.durationMs)}</span>\n <span className=\"tabular-nums\">{occurrence.rows < 0 ? \"— rows\" : `${occurrence.rows} rows`}</span>\n {occurrence.args ? <code className=\"font-mono\">{JSON.stringify(occurrence.args)}</code> : null}\n {occurrence.error ? <span>{occurrence.error}</span> : null}\n </li>\n ))}\n </ul>\n ) : first.args ? (\n <div>\n <div className=\"mb-1 font-semibold text-foreground\">Arguments</div>\n <JsonView data={first.args} />\n </div>\n ) : null}\n </div>\n );\n}\n\n/**\n * `pg_proxy` / `sql_statements` records as a DataTable: time, op, tables, SQL,\n * duration, rows and error. Statements that differ only by their values share a\n * `repeatKey` and collapse into one row with a count badge and their total\n * duration; the switch above the table shows each execution instead.\n */\nexport function SqlTraceTable({ rows, groupRepeated = true, emptyLabel = \"No SQL statements recorded\", className }: SqlTraceTableProps) {\n const [group, setGroup] = useState(groupRepeated);\n const displayRows = useMemo(() => groupStatements(rows, { group }), [rows, group]);\n return (\n <div className={cn(\"flex h-full min-h-0 flex-col gap-density-2\", className)}>\n <Switch checked={group} onChange={setGroup} label=\"Group repeated statements\" className=\"self-start px-density-2\" />\n <DataTable\n data={displayRows}\n columns={COLUMNS}\n autoFilter\n emptyMessage={emptyLabel}\n globalFilterPlaceholder=\"Filter SQL, table, or error…\"\n getRowId={(row) => row.id}\n renderExpandedRow={(row) => <StatementDetails row={row} />}\n />\n </div>\n );\n}\n"],"names":["jsx","Badge","jsxs","CodeBlock","formatStatementDuration","cn","JsonView","useState","useMemo","groupStatements","Switch","DataTable"],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { SqlStatementRow } from './types.js';
|
|
2
|
+
export type SqlTraceTableProps = {
|
|
3
|
+
/** `pg_proxy` / `sql_statements` trace records. */
|
|
4
|
+
rows: SqlStatementRow[];
|
|
5
|
+
/** Start with statements sharing a `repeatKey` collapsed into one counted row. Defaults to true. */
|
|
6
|
+
groupRepeated?: boolean;
|
|
7
|
+
/** Shown when there are no statements. */
|
|
8
|
+
emptyLabel?: string;
|
|
9
|
+
/** Classes applied to the table root. */
|
|
10
|
+
className?: string;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* `pg_proxy` / `sql_statements` records as a DataTable: time, op, tables, SQL,
|
|
14
|
+
* duration, rows and error. Statements that differ only by their values share a
|
|
15
|
+
* `repeatKey` and collapse into one row with a count badge and their total
|
|
16
|
+
* duration; the switch above the table shows each execution instead.
|
|
17
|
+
*/
|
|
18
|
+
export declare function SqlTraceTable({ rows, groupRepeated, emptyLabel, className }: SqlTraceTableProps): import("react").JSX.Element;
|
|
19
|
+
//# sourceMappingURL=SqlTraceTable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SqlTraceTable.d.ts","sourceRoot":"","sources":["../../../src/data/traces/SqlTraceTable.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,MAAM,MAAM,kBAAkB,GAAG;IAC/B,mDAAmD;IACnD,IAAI,EAAE,eAAe,EAAE,CAAC;IACxB,oGAAoG;IACpG,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,0CAA0C;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAwGF;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,EAAE,IAAI,EAAE,aAAoB,EAAE,UAAyC,EAAE,SAAS,EAAE,EAAE,kBAAkB,+BAiBrI"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useMemo } from "react";
|
|
3
|
+
import { Switch } from "../../components/Switch.js";
|
|
4
|
+
import { cn } from "../../lib/utils.js";
|
|
5
|
+
import { Badge } from "../Badge.js";
|
|
6
|
+
import { CodeBlock } from "../CodeBlock.js";
|
|
7
|
+
import { DataTable } from "../DataTable.js";
|
|
8
|
+
import { JsonView } from "../JsonView.js";
|
|
9
|
+
import { groupStatements, formatStatementDuration } from "./sql-trace.js";
|
|
10
|
+
const COLUMNS = [
|
|
11
|
+
{ key: "startedAt", label: "Time", kind: "timestamp", shrink: true },
|
|
12
|
+
{
|
|
13
|
+
key: "op",
|
|
14
|
+
label: "Op",
|
|
15
|
+
shrink: true,
|
|
16
|
+
filterable: true,
|
|
17
|
+
render: (value) => /* @__PURE__ */ jsx(Badge, { variant: "soft", tone: "neutral", size: "xs", className: "font-mono", children: String(value) })
|
|
18
|
+
},
|
|
19
|
+
{ key: "tables", label: "Tables", kind: "tags", shrink: true },
|
|
20
|
+
{
|
|
21
|
+
key: "sql",
|
|
22
|
+
label: "SQL",
|
|
23
|
+
grow: true,
|
|
24
|
+
render: (_value, row) => /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 items-center gap-density-2", children: [
|
|
25
|
+
/* @__PURE__ */ jsx(CodeBlock, { inline: true, language: "sql", source: row.sql }),
|
|
26
|
+
row.count > 1 ? /* @__PURE__ */ jsx("span", { title: `${row.count} executions`, children: /* @__PURE__ */ jsx(Badge, { variant: "soft", tone: "info", size: "xs", children: `×${row.count}` }) }) : null
|
|
27
|
+
] })
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
key: "durationMs",
|
|
31
|
+
label: "Duration",
|
|
32
|
+
align: "right",
|
|
33
|
+
shrink: true,
|
|
34
|
+
render: (value, row) => /* @__PURE__ */ jsx("span", { className: "tabular-nums", title: row.count > 1 ? `${row.count} executions in total` : void 0, children: formatStatementDuration(Number(value)) }),
|
|
35
|
+
sortValue: (value) => Number(value)
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
key: "rows",
|
|
39
|
+
label: "Rows",
|
|
40
|
+
align: "right",
|
|
41
|
+
shrink: true,
|
|
42
|
+
render: (value) => Number(value) < 0 ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "—" }) : /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: String(value) }),
|
|
43
|
+
sortValue: (value) => Number(value)
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
key: "error",
|
|
47
|
+
label: "Error",
|
|
48
|
+
grow: true,
|
|
49
|
+
render: (value, row) => value ? /* @__PURE__ */ jsxs("span", { className: "truncate text-destructive", title: String(value), children: [
|
|
50
|
+
String(value),
|
|
51
|
+
row.count > 1 ? ` (${row.failed} of ${row.count} failed)` : ""
|
|
52
|
+
] }) : null
|
|
53
|
+
}
|
|
54
|
+
];
|
|
55
|
+
function StatementDetails({ row }) {
|
|
56
|
+
var _a;
|
|
57
|
+
const [first] = row.occurrences;
|
|
58
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-density-3", children: [
|
|
59
|
+
/* @__PURE__ */ jsx(CodeBlock, { language: "sql", source: row.sql, copyable: true }),
|
|
60
|
+
row.error ? /* @__PURE__ */ jsxs("div", { children: [
|
|
61
|
+
/* @__PURE__ */ jsx("div", { className: "mb-1 font-semibold text-foreground", children: "Error" }),
|
|
62
|
+
/* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap break-all text-destructive", children: row.error })
|
|
63
|
+
] }) : null,
|
|
64
|
+
/* @__PURE__ */ jsxs("div", { className: "text-xs text-muted-foreground", children: [
|
|
65
|
+
first.connection,
|
|
66
|
+
" · ",
|
|
67
|
+
first.driver,
|
|
68
|
+
((_a = first.truncated) == null ? void 0 : _a.length) ? ` · truncated: ${first.truncated.join(", ")}` : ""
|
|
69
|
+
] }),
|
|
70
|
+
row.count > 1 ? /* @__PURE__ */ jsx("ul", { className: "space-y-1 text-xs", "aria-label": "Executions", children: row.occurrences.map((occurrence, index) => /* @__PURE__ */ jsxs("li", { className: cn("flex items-baseline gap-density-3", occurrence.error && "text-destructive"), children: [
|
|
71
|
+
/* @__PURE__ */ jsx("span", { className: "tabular-nums text-muted-foreground", children: occurrence.startedAt }),
|
|
72
|
+
/* @__PURE__ */ jsx("span", { className: "tabular-nums", children: formatStatementDuration(occurrence.durationMs) }),
|
|
73
|
+
/* @__PURE__ */ jsx("span", { className: "tabular-nums", children: occurrence.rows < 0 ? "— rows" : `${occurrence.rows} rows` }),
|
|
74
|
+
occurrence.args ? /* @__PURE__ */ jsx("code", { className: "font-mono", children: JSON.stringify(occurrence.args) }) : null,
|
|
75
|
+
occurrence.error ? /* @__PURE__ */ jsx("span", { children: occurrence.error }) : null
|
|
76
|
+
] }, index)) }) : first.args ? /* @__PURE__ */ jsxs("div", { children: [
|
|
77
|
+
/* @__PURE__ */ jsx("div", { className: "mb-1 font-semibold text-foreground", children: "Arguments" }),
|
|
78
|
+
/* @__PURE__ */ jsx(JsonView, { data: first.args })
|
|
79
|
+
] }) : null
|
|
80
|
+
] });
|
|
81
|
+
}
|
|
82
|
+
function SqlTraceTable({ rows, groupRepeated = true, emptyLabel = "No SQL statements recorded", className }) {
|
|
83
|
+
const [group, setGroup] = useState(groupRepeated);
|
|
84
|
+
const displayRows = useMemo(() => groupStatements(rows, { group }), [rows, group]);
|
|
85
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex h-full min-h-0 flex-col gap-density-2", className), children: [
|
|
86
|
+
/* @__PURE__ */ jsx(Switch, { checked: group, onChange: setGroup, label: "Group repeated statements", className: "self-start px-density-2" }),
|
|
87
|
+
/* @__PURE__ */ jsx(
|
|
88
|
+
DataTable,
|
|
89
|
+
{
|
|
90
|
+
data: displayRows,
|
|
91
|
+
columns: COLUMNS,
|
|
92
|
+
autoFilter: true,
|
|
93
|
+
emptyMessage: emptyLabel,
|
|
94
|
+
globalFilterPlaceholder: "Filter SQL, table, or error…",
|
|
95
|
+
getRowId: (row) => row.id,
|
|
96
|
+
renderExpandedRow: (row) => /* @__PURE__ */ jsx(StatementDetails, { row })
|
|
97
|
+
}
|
|
98
|
+
)
|
|
99
|
+
] });
|
|
100
|
+
}
|
|
101
|
+
export {
|
|
102
|
+
SqlTraceTable
|
|
103
|
+
};
|
|
104
|
+
//# sourceMappingURL=SqlTraceTable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SqlTraceTable.js","sources":["../../../src/data/traces/SqlTraceTable.tsx"],"sourcesContent":["import { useMemo, useState } from \"react\";\nimport { Switch } from \"../../components/Switch\";\nimport { cn } from \"../../lib/utils\";\nimport { Badge } from \"../Badge\";\nimport { CodeBlock } from \"../CodeBlock\";\nimport { DataTable, type DataTableColumn } from \"../DataTable\";\nimport { JsonView } from \"../JsonView\";\nimport { formatStatementDuration, groupStatements, type SqlDisplayRow } from \"./sql-trace\";\nimport type { SqlStatementRow } from \"./types\";\n\nexport type SqlTraceTableProps = {\n /** `pg_proxy` / `sql_statements` trace records. */\n rows: SqlStatementRow[];\n /** Start with statements sharing a `repeatKey` collapsed into one counted row. Defaults to true. */\n groupRepeated?: boolean;\n /** Shown when there are no statements. */\n emptyLabel?: string;\n /** Classes applied to the table root. */\n className?: string;\n};\n\nconst COLUMNS: DataTableColumn<SqlDisplayRow>[] = [\n { key: \"startedAt\", label: \"Time\", kind: \"timestamp\", shrink: true },\n {\n key: \"op\",\n label: \"Op\",\n shrink: true,\n filterable: true,\n render: (value) => (\n <Badge variant=\"soft\" tone=\"neutral\" size=\"xs\" className=\"font-mono\">\n {String(value)}\n </Badge>\n ),\n },\n { key: \"tables\", label: \"Tables\", kind: \"tags\", shrink: true },\n {\n key: \"sql\",\n label: \"SQL\",\n grow: true,\n render: (_value, row) => (\n <span className=\"flex min-w-0 items-center gap-density-2\">\n <CodeBlock inline language=\"sql\" source={row.sql} />\n {row.count > 1 ? (\n <span title={`${row.count} executions`}>\n <Badge variant=\"soft\" tone=\"info\" size=\"xs\">\n {`×${row.count}`}\n </Badge>\n </span>\n ) : null}\n </span>\n ),\n },\n {\n key: \"durationMs\",\n label: \"Duration\",\n align: \"right\",\n shrink: true,\n render: (value, row) => (\n <span className=\"tabular-nums\" title={row.count > 1 ? `${row.count} executions in total` : undefined}>\n {formatStatementDuration(Number(value))}\n </span>\n ),\n sortValue: (value) => Number(value),\n },\n {\n key: \"rows\",\n label: \"Rows\",\n align: \"right\",\n shrink: true,\n render: (value) => (Number(value) < 0 ? <span className=\"text-muted-foreground\">—</span> : <span className=\"tabular-nums\">{String(value)}</span>),\n sortValue: (value) => Number(value),\n },\n {\n key: \"error\",\n label: \"Error\",\n grow: true,\n render: (value, row) =>\n value ? (\n <span className=\"truncate text-destructive\" title={String(value)}>\n {String(value)}\n {row.count > 1 ? ` (${row.failed} of ${row.count} failed)` : \"\"}\n </span>\n ) : null,\n },\n];\n\nfunction StatementDetails({ row }: { row: SqlDisplayRow }) {\n const [first] = row.occurrences as [SqlStatementRow, ...SqlStatementRow[]];\n return (\n <div className=\"space-y-density-3\">\n <CodeBlock language=\"sql\" source={row.sql} copyable />\n {row.error ? (\n <div>\n <div className=\"mb-1 font-semibold text-foreground\">Error</div>\n <pre className=\"whitespace-pre-wrap break-all text-destructive\">{row.error}</pre>\n </div>\n ) : null}\n <div className=\"text-xs text-muted-foreground\">\n {first.connection} · {first.driver}\n {first.truncated?.length ? ` · truncated: ${first.truncated.join(\", \")}` : \"\"}\n </div>\n {row.count > 1 ? (\n <ul className=\"space-y-1 text-xs\" aria-label=\"Executions\">\n {row.occurrences.map((occurrence, index) => (\n <li key={index} className={cn(\"flex items-baseline gap-density-3\", occurrence.error && \"text-destructive\")}>\n <span className=\"tabular-nums text-muted-foreground\">{occurrence.startedAt}</span>\n <span className=\"tabular-nums\">{formatStatementDuration(occurrence.durationMs)}</span>\n <span className=\"tabular-nums\">{occurrence.rows < 0 ? \"— rows\" : `${occurrence.rows} rows`}</span>\n {occurrence.args ? <code className=\"font-mono\">{JSON.stringify(occurrence.args)}</code> : null}\n {occurrence.error ? <span>{occurrence.error}</span> : null}\n </li>\n ))}\n </ul>\n ) : first.args ? (\n <div>\n <div className=\"mb-1 font-semibold text-foreground\">Arguments</div>\n <JsonView data={first.args} />\n </div>\n ) : null}\n </div>\n );\n}\n\n/**\n * `pg_proxy` / `sql_statements` records as a DataTable: time, op, tables, SQL,\n * duration, rows and error. Statements that differ only by their values share a\n * `repeatKey` and collapse into one row with a count badge and their total\n * duration; the switch above the table shows each execution instead.\n */\nexport function SqlTraceTable({ rows, groupRepeated = true, emptyLabel = \"No SQL statements recorded\", className }: SqlTraceTableProps) {\n const [group, setGroup] = useState(groupRepeated);\n const displayRows = useMemo(() => groupStatements(rows, { group }), [rows, group]);\n return (\n <div className={cn(\"flex h-full min-h-0 flex-col gap-density-2\", className)}>\n <Switch checked={group} onChange={setGroup} label=\"Group repeated statements\" className=\"self-start px-density-2\" />\n <DataTable\n data={displayRows}\n columns={COLUMNS}\n autoFilter\n emptyMessage={emptyLabel}\n globalFilterPlaceholder=\"Filter SQL, table, or error…\"\n getRowId={(row) => row.id}\n renderExpandedRow={(row) => <StatementDetails row={row} />}\n />\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,162 @@
|
|
|
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 button = require("../../components/button.cjs");
|
|
6
|
+
const SegmentedControl = require("../../components/SegmentedControl.cjs");
|
|
7
|
+
const utils = require("../../lib/utils.cjs");
|
|
8
|
+
const AnsiHtml = require("../AnsiHtml.cjs");
|
|
9
|
+
const Badge = require("../Badge.cjs");
|
|
10
|
+
const Icon = require("../Icon.cjs");
|
|
11
|
+
const cast = require("./cast.cjs");
|
|
12
|
+
const terminalScreen = require("./terminal-screen.cjs");
|
|
13
|
+
const terminalTimeline = require("./terminal-timeline.cjs");
|
|
14
|
+
const UiPause = require("../../icons/components/UiPause.cjs");
|
|
15
|
+
const UiPlay = require("../../icons/components/UiPlay.cjs");
|
|
16
|
+
const UiSkipForward = require("../../icons/components/UiSkipForward.cjs");
|
|
17
|
+
const TICK_MS = 50;
|
|
18
|
+
const SPEEDS = ["1", "2", "4"];
|
|
19
|
+
const SPEED_OPTIONS = SPEEDS.map((speed) => ({ id: speed, label: `${speed}x` }));
|
|
20
|
+
const VIEW_OPTIONS = [
|
|
21
|
+
{ id: "replay", label: "Replay" },
|
|
22
|
+
{ id: "settled", label: "Settled screen" }
|
|
23
|
+
];
|
|
24
|
+
function resolveEvents(events, castText) {
|
|
25
|
+
if (events === void 0 === (castText === void 0)) {
|
|
26
|
+
throw new Error("TerminalCastPlayer takes either events or castText, not both or neither");
|
|
27
|
+
}
|
|
28
|
+
return events ?? cast.parseCast(castText);
|
|
29
|
+
}
|
|
30
|
+
function seconds(value) {
|
|
31
|
+
return `${value.toFixed(1)}s`;
|
|
32
|
+
}
|
|
33
|
+
function ExitBadge({ exit }) {
|
|
34
|
+
if (exit.exitCode === void 0) return /* @__PURE__ */ jsxRuntime.jsx(Badge.Badge, { variant: "outline", tone: "neutral", size: "sm", children: "exited" });
|
|
35
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Badge.Badge, { variant: "soft", tone: exit.exitCode === 0 ? "success" : "danger", size: "sm", className: "font-mono", children: `exit ${exit.exitCode}` });
|
|
36
|
+
}
|
|
37
|
+
function useReplayScreen(timeline, position) {
|
|
38
|
+
const cache = react.useRef(void 0);
|
|
39
|
+
const count = terminalTimeline.stepCountAt(timeline.steps, position);
|
|
40
|
+
return react.useMemo(() => {
|
|
41
|
+
var _a;
|
|
42
|
+
const previous = ((_a = cache.current) == null ? void 0 : _a.timeline) === timeline ? cache.current.replay : void 0;
|
|
43
|
+
const replay = terminalTimeline.replayTo(previous, timeline, count);
|
|
44
|
+
cache.current = { timeline, replay };
|
|
45
|
+
return { ansi: terminalScreen.screenToAnsi(replay.screen), cols: replay.screen.width, rows: replay.screen.height };
|
|
46
|
+
}, [timeline, count]);
|
|
47
|
+
}
|
|
48
|
+
function TerminalCastPlayer({
|
|
49
|
+
events,
|
|
50
|
+
castText,
|
|
51
|
+
autoPlay = false,
|
|
52
|
+
emptyLabel = "No terminal output recorded",
|
|
53
|
+
className
|
|
54
|
+
}) {
|
|
55
|
+
var _a, _b;
|
|
56
|
+
const timeline = react.useMemo(() => terminalTimeline.buildTimeline(resolveEvents(events, castText)), [events, castText]);
|
|
57
|
+
const [position, setPosition] = react.useState(0);
|
|
58
|
+
const [playing, setPlaying] = react.useState(autoPlay);
|
|
59
|
+
const [speed, setSpeed] = react.useState("1");
|
|
60
|
+
const [view, setView] = react.useState("replay");
|
|
61
|
+
const replay = useReplayScreen(timeline, position);
|
|
62
|
+
react.useEffect(() => {
|
|
63
|
+
if (!playing) return;
|
|
64
|
+
let last = Date.now();
|
|
65
|
+
const timer = setInterval(() => {
|
|
66
|
+
const now = Date.now();
|
|
67
|
+
const elapsed = (now - last) / 1e3;
|
|
68
|
+
last = now;
|
|
69
|
+
setPosition((current) => Math.min(timeline.duration, current + elapsed * Number(speed)));
|
|
70
|
+
}, TICK_MS);
|
|
71
|
+
return () => clearInterval(timer);
|
|
72
|
+
}, [playing, speed, timeline.duration]);
|
|
73
|
+
react.useEffect(() => {
|
|
74
|
+
if (playing && position >= timeline.duration) setPlaying(false);
|
|
75
|
+
}, [playing, position, timeline.duration]);
|
|
76
|
+
if (timeline.steps.length === 0 && timeline.settled === void 0) {
|
|
77
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-density-6 text-center text-muted-foreground text-sm", children: emptyLabel });
|
|
78
|
+
}
|
|
79
|
+
const hasSettled = timeline.settled !== void 0;
|
|
80
|
+
const showSettled = view === "settled" && hasSettled;
|
|
81
|
+
const play = () => {
|
|
82
|
+
if (position >= timeline.duration) setPosition(0);
|
|
83
|
+
setPlaying(true);
|
|
84
|
+
};
|
|
85
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: utils.cn("flex min-h-0 flex-col gap-density-2", className), children: [
|
|
86
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-density-2 text-xs text-muted-foreground", children: [
|
|
87
|
+
((_a = timeline.exit) == null ? void 0 : _a.command) ? /* @__PURE__ */ jsxRuntime.jsx("code", { className: "font-mono text-foreground", children: timeline.exit.command }) : null,
|
|
88
|
+
timeline.exit ? /* @__PURE__ */ jsxRuntime.jsx(ExitBadge, { exit: timeline.exit }) : null,
|
|
89
|
+
((_b = timeline.exit) == null ? void 0 : _b.truncated) ? /* @__PURE__ */ jsxRuntime.jsx("span", { title: "Size caps or a full buffer stopped some output events being recorded", children: /* @__PURE__ */ jsxRuntime.jsx(Badge.Badge, { variant: "soft", tone: "warning", size: "sm", children: "output truncated" }) }) : null,
|
|
90
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: `${timeline.width}x${timeline.height}` }),
|
|
91
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1" }),
|
|
92
|
+
hasSettled && timeline.steps.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(SegmentedControl.SegmentedControl, { size: "sm", "aria-label": "Screen view", value: view, options: VIEW_OPTIONS, onChange: setView }) : null
|
|
93
|
+
] }),
|
|
94
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
95
|
+
"div",
|
|
96
|
+
{
|
|
97
|
+
role: "region",
|
|
98
|
+
"aria-label": "Terminal screen",
|
|
99
|
+
"data-cols": showSettled ? void 0 : replay.cols,
|
|
100
|
+
className: "overflow-auto rounded border bg-black p-density-2",
|
|
101
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
102
|
+
AnsiHtml.AnsiHtml,
|
|
103
|
+
{
|
|
104
|
+
text: showSettled ? timeline.settled : replay.ansi,
|
|
105
|
+
className: "font-mono text-xs leading-5 whitespace-pre text-gray-100"
|
|
106
|
+
}
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
),
|
|
110
|
+
timeline.steps.length > 0 && !showSettled ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-density-2", children: [
|
|
111
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
112
|
+
button.Button,
|
|
113
|
+
{
|
|
114
|
+
variant: "ghost",
|
|
115
|
+
size: "icon",
|
|
116
|
+
"aria-label": playing ? "Pause" : "Play",
|
|
117
|
+
onClick: playing ? () => setPlaying(false) : play,
|
|
118
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { icon: playing ? UiPause.UiPause : UiPlay.UiPlay })
|
|
119
|
+
}
|
|
120
|
+
),
|
|
121
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
122
|
+
"input",
|
|
123
|
+
{
|
|
124
|
+
type: "range",
|
|
125
|
+
"aria-label": "Seek",
|
|
126
|
+
className: "min-w-0 flex-1 accent-primary",
|
|
127
|
+
min: 0,
|
|
128
|
+
max: timeline.duration,
|
|
129
|
+
step: "any",
|
|
130
|
+
value: position,
|
|
131
|
+
onChange: (event) => setPosition(Number(event.target.value))
|
|
132
|
+
}
|
|
133
|
+
),
|
|
134
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-xs tabular-nums text-muted-foreground", children: `${seconds(position)} / ${seconds(timeline.duration)}` }),
|
|
135
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
136
|
+
SegmentedControl.SegmentedControl,
|
|
137
|
+
{
|
|
138
|
+
size: "sm",
|
|
139
|
+
"aria-label": "Playback speed",
|
|
140
|
+
value: speed,
|
|
141
|
+
options: SPEED_OPTIONS,
|
|
142
|
+
onChange: setSpeed
|
|
143
|
+
}
|
|
144
|
+
),
|
|
145
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
146
|
+
button.Button,
|
|
147
|
+
{
|
|
148
|
+
variant: "ghost",
|
|
149
|
+
size: "icon",
|
|
150
|
+
"aria-label": "Jump to end",
|
|
151
|
+
onClick: () => {
|
|
152
|
+
setPlaying(false);
|
|
153
|
+
setPosition(timeline.duration);
|
|
154
|
+
},
|
|
155
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { icon: UiSkipForward.UiSkipForward })
|
|
156
|
+
}
|
|
157
|
+
)
|
|
158
|
+
] }) : null
|
|
159
|
+
] });
|
|
160
|
+
}
|
|
161
|
+
exports.TerminalCastPlayer = TerminalCastPlayer;
|
|
162
|
+
//# sourceMappingURL=TerminalCastPlayer.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TerminalCastPlayer.cjs","sources":["../../../src/data/traces/TerminalCastPlayer.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from \"react\";\nimport { Button } from \"../../components/button\";\nimport { SegmentedControl } from \"../../components/SegmentedControl\";\nimport { UiPause, UiPlay, UiSkipForward } from \"../../icons\";\nimport { cn } from \"../../lib/utils\";\nimport { AnsiHtml } from \"../AnsiHtml\";\nimport { Badge } from \"../Badge\";\nimport { Icon } from \"../Icon\";\nimport { parseCast } from \"./cast\";\nimport { screenToAnsi } from \"./terminal-screen\";\nimport {\n buildTimeline,\n replayTo,\n stepCountAt,\n type ScreenReplay,\n type TerminalTimeline,\n} from \"./terminal-timeline\";\nimport type { TerminalEvent } from \"./types\";\n\nconst TICK_MS = 50;\nconst SPEEDS = [\"1\", \"2\", \"4\"] as const;\ntype Speed = (typeof SPEEDS)[number];\ntype View = \"replay\" | \"settled\";\n\nconst SPEED_OPTIONS = SPEEDS.map((speed) => ({ id: speed, label: `${speed}x` }));\nconst VIEW_OPTIONS: { id: View; label: string }[] = [\n { id: \"replay\", label: \"Replay\" },\n { id: \"settled\", label: \"Settled screen\" },\n];\n\nexport type TerminalCastPlayerProps = {\n /** `terminal` trace records. Give this or `castText`. */\n events?: TerminalEvent[];\n /** An asciinema v2 cast, such as a downloaded `.cast`. Give this or `events`. */\n castText?: string;\n /** Start playing on mount. */\n autoPlay?: boolean;\n /** Shown when the session recorded no events. */\n emptyLabel?: string;\n /** Classes applied to the player root. */\n className?: string;\n};\n\nfunction resolveEvents(events: TerminalEvent[] | undefined, castText: string | undefined): TerminalEvent[] {\n if ((events === undefined) === (castText === undefined)) {\n throw new Error(\"TerminalCastPlayer takes either events or castText, not both or neither\");\n }\n return events ?? parseCast(castText!);\n}\n\nfunction seconds(value: number): string {\n return `${value.toFixed(1)}s`;\n}\n\nfunction ExitBadge({ exit }: { exit: TerminalEvent }) {\n if (exit.exitCode === undefined) return <Badge variant=\"outline\" tone=\"neutral\" size=\"sm\">exited</Badge>;\n return (\n <Badge variant=\"soft\" tone={exit.exitCode === 0 ? \"success\" : \"danger\"} size=\"sm\" className=\"font-mono\">\n {`exit ${exit.exitCode}`}\n </Badge>\n );\n}\n\n/** Feeds the timeline to a screen as the position moves, reusing the screen while moving forward. */\nfunction useReplayScreen(timeline: TerminalTimeline, position: number) {\n const cache = useRef<{ timeline: TerminalTimeline; replay: ScreenReplay } | undefined>(undefined);\n const count = stepCountAt(timeline.steps, position);\n return useMemo(() => {\n const previous = cache.current?.timeline === timeline ? cache.current.replay : undefined;\n const replay = replayTo(previous, timeline, count);\n cache.current = { timeline, replay };\n return { ansi: screenToAnsi(replay.screen), cols: replay.screen.width, rows: replay.screen.height };\n }, [timeline, count]);\n}\n\n/**\n * Replays a `terminal` trace: output events over time with play/pause, a\n * scrubber, 1x/2x/4x speed and jump-to-end, honouring resizes. A downloaded\n * asciinema cast renders the same way through `castText`. When the capture\n * settled a screen, it is offered as the \"Settled screen\" view.\n */\nexport function TerminalCastPlayer({\n events,\n castText,\n autoPlay = false,\n emptyLabel = \"No terminal output recorded\",\n className,\n}: TerminalCastPlayerProps) {\n const timeline = useMemo(() => buildTimeline(resolveEvents(events, castText)), [events, castText]);\n const [position, setPosition] = useState(0);\n const [playing, setPlaying] = useState(autoPlay);\n const [speed, setSpeed] = useState<Speed>(\"1\");\n const [view, setView] = useState<View>(\"replay\");\n const replay = useReplayScreen(timeline, position);\n\n useEffect(() => {\n if (!playing) return;\n let last = Date.now();\n const timer = setInterval(() => {\n const now = Date.now();\n const elapsed = (now - last) / 1000;\n last = now;\n setPosition((current) => Math.min(timeline.duration, current + elapsed * Number(speed)));\n }, TICK_MS);\n return () => clearInterval(timer);\n }, [playing, speed, timeline.duration]);\n\n useEffect(() => {\n if (playing && position >= timeline.duration) setPlaying(false);\n }, [playing, position, timeline.duration]);\n\n if (timeline.steps.length === 0 && timeline.settled === undefined) {\n return <div className=\"p-density-6 text-center text-muted-foreground text-sm\">{emptyLabel}</div>;\n }\n\n const hasSettled = timeline.settled !== undefined;\n const showSettled = view === \"settled\" && hasSettled;\n const play = () => {\n if (position >= timeline.duration) setPosition(0);\n setPlaying(true);\n };\n\n return (\n <div className={cn(\"flex min-h-0 flex-col gap-density-2\", className)}>\n <div className=\"flex flex-wrap items-center gap-density-2 text-xs text-muted-foreground\">\n {timeline.exit?.command ? <code className=\"font-mono text-foreground\">{timeline.exit.command}</code> : null}\n {timeline.exit ? <ExitBadge exit={timeline.exit} /> : null}\n {timeline.exit?.truncated ? (\n <span title=\"Size caps or a full buffer stopped some output events being recorded\">\n <Badge variant=\"soft\" tone=\"warning\" size=\"sm\">output truncated</Badge>\n </span>\n ) : null}\n <span className=\"tabular-nums\">{`${timeline.width}x${timeline.height}`}</span>\n <span className=\"flex-1\" />\n {hasSettled && timeline.steps.length > 0 ? (\n <SegmentedControl size=\"sm\" aria-label=\"Screen view\" value={view} options={VIEW_OPTIONS} onChange={setView} />\n ) : null}\n </div>\n\n <div\n role=\"region\"\n aria-label=\"Terminal screen\"\n data-cols={showSettled ? undefined : replay.cols}\n className=\"overflow-auto rounded border bg-black p-density-2\"\n >\n <AnsiHtml\n text={showSettled ? timeline.settled! : replay.ansi}\n className=\"font-mono text-xs leading-5 whitespace-pre text-gray-100\"\n />\n </div>\n\n {timeline.steps.length > 0 && !showSettled ? (\n <div className=\"flex items-center gap-density-2\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={playing ? \"Pause\" : \"Play\"}\n onClick={playing ? () => setPlaying(false) : play}\n >\n <Icon icon={playing ? UiPause : UiPlay} />\n </Button>\n <input\n type=\"range\"\n aria-label=\"Seek\"\n className=\"min-w-0 flex-1 accent-primary\"\n min={0}\n max={timeline.duration}\n step=\"any\"\n value={position}\n onChange={(event) => setPosition(Number(event.target.value))}\n />\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\">\n {`${seconds(position)} / ${seconds(timeline.duration)}`}\n </span>\n <SegmentedControl\n size=\"sm\"\n aria-label=\"Playback speed\"\n value={speed}\n options={SPEED_OPTIONS}\n onChange={setSpeed}\n />\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label=\"Jump to end\"\n onClick={() => {\n setPlaying(false);\n setPosition(timeline.duration);\n }}\n >\n <Icon icon={UiSkipForward} />\n </Button>\n </div>\n ) : null}\n </div>\n );\n}\n"],"names":["parseCast","jsx","Badge","useRef","stepCountAt","useMemo","replayTo","screenToAnsi","buildTimeline","useState","useEffect","cn","jsxs","SegmentedControl","AnsiHtml","Button","Icon","UiPause","UiPlay","UiSkipForward"],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { TerminalEvent } from './types.js';
|
|
2
|
+
export type TerminalCastPlayerProps = {
|
|
3
|
+
/** `terminal` trace records. Give this or `castText`. */
|
|
4
|
+
events?: TerminalEvent[];
|
|
5
|
+
/** An asciinema v2 cast, such as a downloaded `.cast`. Give this or `events`. */
|
|
6
|
+
castText?: string;
|
|
7
|
+
/** Start playing on mount. */
|
|
8
|
+
autoPlay?: boolean;
|
|
9
|
+
/** Shown when the session recorded no events. */
|
|
10
|
+
emptyLabel?: string;
|
|
11
|
+
/** Classes applied to the player root. */
|
|
12
|
+
className?: string;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Replays a `terminal` trace: output events over time with play/pause, a
|
|
16
|
+
* scrubber, 1x/2x/4x speed and jump-to-end, honouring resizes. A downloaded
|
|
17
|
+
* asciinema cast renders the same way through `castText`. When the capture
|
|
18
|
+
* settled a screen, it is offered as the "Settled screen" view.
|
|
19
|
+
*/
|
|
20
|
+
export declare function TerminalCastPlayer({ events, castText, autoPlay, emptyLabel, className, }: TerminalCastPlayerProps): import("react").JSX.Element;
|
|
21
|
+
//# sourceMappingURL=TerminalCastPlayer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TerminalCastPlayer.d.ts","sourceRoot":"","sources":["../../../src/data/traces/TerminalCastPlayer.tsx"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAa7C,MAAM,MAAM,uBAAuB,GAAG;IACpC,yDAAyD;IACzD,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC;IACzB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8BAA8B;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,iDAAiD;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAkCF;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,QAAQ,EACR,QAAgB,EAChB,UAA0C,EAC1C,SAAS,GACV,EAAE,uBAAuB,+BA6GzB"}
|