@quantumwake/terminal-ux-dashboard-components 0.1.15 → 0.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +194 -141
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +195 -142
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
package/dist/index.cjs
CHANGED
|
@@ -9,6 +9,7 @@ var scatterplot = require('@nivo/scatterplot');
|
|
|
9
9
|
var heatmap = require('@nivo/heatmap');
|
|
10
10
|
var PivotTableUI = require('react-pivottable/PivotTableUI');
|
|
11
11
|
require('react-pivottable/pivottable.css');
|
|
12
|
+
var terminalUxComponents = require('@quantumwake/terminal-ux-components');
|
|
12
13
|
var lucideReact = require('lucide-react');
|
|
13
14
|
var CodeMirror = require('@uiw/react-codemirror');
|
|
14
15
|
var langSql = require('@codemirror/lang-sql');
|
|
@@ -235,9 +236,15 @@ var DEFAULT_CHART_STYLE = {
|
|
|
235
236
|
legendBold: false,
|
|
236
237
|
legendHighlight: "",
|
|
237
238
|
// Tick overflow handling.
|
|
238
|
-
xTickRotation:
|
|
239
|
+
xTickRotation: 0,
|
|
239
240
|
yTickRotation: 0,
|
|
240
241
|
tickTruncate: 0,
|
|
242
|
+
tickWrap: true,
|
|
243
|
+
tickWrapWidth: 14,
|
|
244
|
+
// Table cells.
|
|
245
|
+
cellWrap: true,
|
|
246
|
+
cellPrecision: 2,
|
|
247
|
+
cellTruncate: 0,
|
|
241
248
|
// Series legend placement (charts that have one: pie, grouped bar).
|
|
242
249
|
legendAnchor: "right",
|
|
243
250
|
// Panel title (rendered by DashboardRenderer's panel header).
|
|
@@ -362,6 +369,78 @@ function MetricView({ records, config, value: presetValue }) {
|
|
|
362
369
|
function InsightView({ config }) {
|
|
363
370
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full p-4 overflow-auto", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-midnight-text-body leading-relaxed whitespace-pre-wrap", children: config.text }) });
|
|
364
371
|
}
|
|
372
|
+
function formatVal(value, s, numeric) {
|
|
373
|
+
let str = numeric ? Number(value).toLocaleString() : String(value);
|
|
374
|
+
if (s.tickTruncate > 0 && str.length > s.tickTruncate) str = `${str.slice(0, s.tickTruncate)}\u2026`;
|
|
375
|
+
return str;
|
|
376
|
+
}
|
|
377
|
+
function wrapText(str, width) {
|
|
378
|
+
if (width <= 0 || str.length <= width) return [str];
|
|
379
|
+
const words = str.split(/\s+/);
|
|
380
|
+
const lines = [];
|
|
381
|
+
let cur = "";
|
|
382
|
+
const push = (t) => {
|
|
383
|
+
if (t) lines.push(t);
|
|
384
|
+
};
|
|
385
|
+
for (const w of words) {
|
|
386
|
+
if (w.length > width) {
|
|
387
|
+
push(cur);
|
|
388
|
+
cur = "";
|
|
389
|
+
for (let i = 0; i < w.length; i += width) lines.push(w.slice(i, i + width));
|
|
390
|
+
continue;
|
|
391
|
+
}
|
|
392
|
+
if (!cur) cur = w;
|
|
393
|
+
else if (cur.length + 1 + w.length <= width) cur += ` ${w}`;
|
|
394
|
+
else {
|
|
395
|
+
push(cur);
|
|
396
|
+
cur = w;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
push(cur);
|
|
400
|
+
if (lines.length > 4) {
|
|
401
|
+
const kept = lines.slice(0, 4);
|
|
402
|
+
kept[3] = `${kept[3].slice(0, Math.max(0, width - 1))}\u2026`;
|
|
403
|
+
return kept;
|
|
404
|
+
}
|
|
405
|
+
return lines;
|
|
406
|
+
}
|
|
407
|
+
function makeAxis(style, axis, columnName, opts2 = {}) {
|
|
408
|
+
const s = withStyleDefaults(style);
|
|
409
|
+
const isX = axis === "x";
|
|
410
|
+
const numeric = !!opts2.numeric;
|
|
411
|
+
const show = isX ? s.showXLegend : s.showYLegend;
|
|
412
|
+
const label = (isX ? s.xAxisLabel : s.yAxisLabel) || columnName;
|
|
413
|
+
const rotate = isX ? s.xTickRotation : s.yTickRotation;
|
|
414
|
+
const out = { tickSize: 5, tickPadding: 5 };
|
|
415
|
+
if (show && label) {
|
|
416
|
+
out.legend = label;
|
|
417
|
+
out.legendPosition = isX ? s.xLegendPosition : s.yLegendPosition;
|
|
418
|
+
out.legendOffset = isX ? s.xLegendOffset : s.yLegendOffset;
|
|
419
|
+
}
|
|
420
|
+
if (s.tickWrap) {
|
|
421
|
+
out.renderTick = (tick) => {
|
|
422
|
+
const lines = wrapText(formatVal(tick.value, s, numeric), s.tickWrapWidth);
|
|
423
|
+
const firstDy = isX ? "0" : `${-((lines.length - 1) * 0.55)}em`;
|
|
424
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("g", { transform: `translate(${tick.x},${tick.y})`, children: [
|
|
425
|
+
/* @__PURE__ */ jsxRuntime.jsx("line", { x2: isX ? 0 : -5, y2: isX ? 5 : 0, style: { stroke: s.textColor, strokeWidth: 1, opacity: 0.3 } }),
|
|
426
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
427
|
+
"text",
|
|
428
|
+
{
|
|
429
|
+
transform: `translate(${tick.textX},${tick.textY}) rotate(${rotate})`,
|
|
430
|
+
textAnchor: tick.textAnchor,
|
|
431
|
+
dominantBaseline: tick.textBaseline,
|
|
432
|
+
style: { fill: s.textColor, fontSize: s.fontSize },
|
|
433
|
+
children: lines.map((ln, i) => /* @__PURE__ */ jsxRuntime.jsx("tspan", { x: 0, dy: i === 0 ? firstDy : "1.1em", children: ln }, i))
|
|
434
|
+
}
|
|
435
|
+
)
|
|
436
|
+
] });
|
|
437
|
+
};
|
|
438
|
+
} else {
|
|
439
|
+
out.tickRotation = rotate;
|
|
440
|
+
out.format = (v) => formatVal(v, s, numeric);
|
|
441
|
+
}
|
|
442
|
+
return out;
|
|
443
|
+
}
|
|
365
444
|
function BarView({ records, groupColumn, valueColumn, aggFn = "count", data: presetData, style }) {
|
|
366
445
|
const computed = react.useMemo(() => {
|
|
367
446
|
if (presetData || !records) return [];
|
|
@@ -369,7 +448,7 @@ function BarView({ records, groupColumn, valueColumn, aggFn = "count", data: pre
|
|
|
369
448
|
return Object.entries(groups).map(([key, recs]) => ({ group: key, value: aggregate(recs, valueColumn, aggFn) })).sort((a, b) => b.value - a.value).slice(0, 50);
|
|
370
449
|
}, [records, groupColumn, valueColumn, aggFn, presetData]);
|
|
371
450
|
const data = presetData || computed;
|
|
372
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full min-h-[
|
|
451
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full min-h-[160px]", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
373
452
|
bar.ResponsiveBar,
|
|
374
453
|
{
|
|
375
454
|
data,
|
|
@@ -379,8 +458,8 @@ function BarView({ records, groupColumn, valueColumn, aggFn = "count", data: pre
|
|
|
379
458
|
padding: 0.3,
|
|
380
459
|
colors: ["rgba(74, 222, 128, 0.8)"],
|
|
381
460
|
borderColor: { from: "color", modifiers: [["darker", 1.6]] },
|
|
382
|
-
axisBottom:
|
|
383
|
-
axisLeft:
|
|
461
|
+
axisBottom: makeAxis(style, "x", groupColumn),
|
|
462
|
+
axisLeft: makeAxis(style, "y", valueColumn, { numeric: true }),
|
|
384
463
|
labelSkipWidth: 12,
|
|
385
464
|
labelSkipHeight: 12,
|
|
386
465
|
labelTextColor: { from: "color", modifiers: [["darker", 3]] },
|
|
@@ -401,7 +480,7 @@ function PieView({ records, groupColumn, data: presetData, style }) {
|
|
|
401
480
|
}, [records, groupColumn, presetData]);
|
|
402
481
|
const data = presetData || computed;
|
|
403
482
|
const legend = legendConfig(style);
|
|
404
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full min-h-[
|
|
483
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full min-h-[160px]", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
405
484
|
pie.ResponsivePie,
|
|
406
485
|
{
|
|
407
486
|
data,
|
|
@@ -437,7 +516,7 @@ function LineView({ records, xColumn, yColumn, data: presetData, style }) {
|
|
|
437
516
|
}];
|
|
438
517
|
}, [records, xColumn, yColumn, presetData]);
|
|
439
518
|
const data = presetData || computed;
|
|
440
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full min-h-[
|
|
519
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full min-h-[160px]", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
441
520
|
line.ResponsiveLine,
|
|
442
521
|
{
|
|
443
522
|
data,
|
|
@@ -453,8 +532,8 @@ function LineView({ records, xColumn, yColumn, data: presetData, style }) {
|
|
|
453
532
|
pointBorderWidth: 2,
|
|
454
533
|
pointBorderColor: { from: "serieColor" },
|
|
455
534
|
enableGridX: false,
|
|
456
|
-
axisBottom:
|
|
457
|
-
axisLeft:
|
|
535
|
+
axisBottom: makeAxis(style, "x", xColumn),
|
|
536
|
+
axisLeft: makeAxis(style, "y", yColumn, { numeric: true }),
|
|
458
537
|
useMesh: true,
|
|
459
538
|
theme: buildNivoTheme(style)
|
|
460
539
|
}
|
|
@@ -467,7 +546,7 @@ function ScatterView({ records, xColumn, yColumn, data: presetData, style }) {
|
|
|
467
546
|
return [{ id: `${xColumn} vs ${yColumn}`, data: points }];
|
|
468
547
|
}, [records, xColumn, yColumn, presetData]);
|
|
469
548
|
const data = presetData || computed;
|
|
470
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full min-h-[
|
|
549
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full min-h-[160px]", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
471
550
|
scatterplot.ResponsiveScatterPlot,
|
|
472
551
|
{
|
|
473
552
|
data,
|
|
@@ -476,8 +555,8 @@ function ScatterView({ records, xColumn, yColumn, data: presetData, style }) {
|
|
|
476
555
|
yScale: { type: "linear", min: "auto", max: "auto" },
|
|
477
556
|
colors: ["rgba(167, 139, 250, 0.7)"],
|
|
478
557
|
nodeSize: 6,
|
|
479
|
-
axisBottom:
|
|
480
|
-
axisLeft:
|
|
558
|
+
axisBottom: makeAxis(style, "x", xColumn, { numeric: true }),
|
|
559
|
+
axisLeft: makeAxis(style, "y", yColumn, { numeric: true }),
|
|
481
560
|
useMesh: true,
|
|
482
561
|
theme: buildNivoTheme(style)
|
|
483
562
|
}
|
|
@@ -571,7 +650,7 @@ function HeatmapView({
|
|
|
571
650
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-8 text-center text-midnight-text-muted", children: "Not enough distinct values for a heatmap" });
|
|
572
651
|
}
|
|
573
652
|
const margin = showTotals ? { top: 60, right: 70, bottom: 60, left: 100 } : { top: 60, right: 20, bottom: 20, left: 100 };
|
|
574
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full min-h-[
|
|
653
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full min-h-[160px]", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
575
654
|
heatmap.ResponsiveHeatMap,
|
|
576
655
|
{
|
|
577
656
|
data,
|
|
@@ -622,73 +701,25 @@ function PivotView({ records }) {
|
|
|
622
701
|
] });
|
|
623
702
|
}
|
|
624
703
|
function Section({ title, children }) {
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
628
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5", children })
|
|
704
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-midnight-border font-mono", style: { paddingTop: 12, paddingBottom: 12 }, children: [
|
|
705
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "uppercase tracking-wider text-midnight-text-subdued", style: { fontSize: 10, marginBottom: 8 }, children: title }),
|
|
706
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", rowGap: 6 }, children })
|
|
629
707
|
] });
|
|
630
708
|
}
|
|
631
709
|
function Row({ label, children }) {
|
|
632
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", {
|
|
710
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "grid", gridTemplateColumns: "84px minmax(0, 1fr)", alignItems: "center", columnGap: 8, height: 32 }, children: [
|
|
633
711
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-mono text-midnight-text-muted truncate", title: label, children: label }),
|
|
634
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
712
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", alignItems: "center", justifyContent: "flex-end", width: "100%", minWidth: 0 }, children })
|
|
635
713
|
] });
|
|
636
714
|
}
|
|
637
715
|
function ColorControl({ value, onChange }) {
|
|
638
|
-
const { theme } = useDashboard();
|
|
639
716
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
640
717
|
"input",
|
|
641
718
|
{
|
|
642
719
|
type: "color",
|
|
643
720
|
value: /^#/.test(value) ? value : "#94a3b8",
|
|
644
721
|
onChange: (e) => onChange(e.target.value),
|
|
645
|
-
className:
|
|
646
|
-
}
|
|
647
|
-
);
|
|
648
|
-
}
|
|
649
|
-
function SliderControl({ value, onChange, min, max, step = 1, unit = "" }) {
|
|
650
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 w-full", children: [
|
|
651
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
652
|
-
"input",
|
|
653
|
-
{
|
|
654
|
-
type: "range",
|
|
655
|
-
min,
|
|
656
|
-
max,
|
|
657
|
-
step,
|
|
658
|
-
value,
|
|
659
|
-
onChange: (e) => onChange(Number(e.target.value)),
|
|
660
|
-
className: "flex-1 h-1 accent-midnight-accent cursor-pointer"
|
|
661
|
-
}
|
|
662
|
-
),
|
|
663
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "w-10 shrink-0 text-right text-[11px] font-mono tabular-nums text-midnight-text-body", children: [
|
|
664
|
-
value,
|
|
665
|
-
unit
|
|
666
|
-
] })
|
|
667
|
-
] });
|
|
668
|
-
}
|
|
669
|
-
function TextControl({ value, onChange, placeholder }) {
|
|
670
|
-
const { theme } = useDashboard();
|
|
671
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
672
|
-
"input",
|
|
673
|
-
{
|
|
674
|
-
type: "text",
|
|
675
|
-
value,
|
|
676
|
-
placeholder,
|
|
677
|
-
onChange: (e) => onChange(e.target.value),
|
|
678
|
-
className: `w-full px-2 py-1 text-xs font-mono bg-midnight-surface border ${theme.border} text-midnight-text-body outline-none focus:border-midnight-accent transition-colors`
|
|
679
|
-
}
|
|
680
|
-
);
|
|
681
|
-
}
|
|
682
|
-
function Switch({ value, onChange }) {
|
|
683
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
684
|
-
"button",
|
|
685
|
-
{
|
|
686
|
-
type: "button",
|
|
687
|
-
role: "switch",
|
|
688
|
-
"aria-checked": value,
|
|
689
|
-
onClick: () => onChange(!value),
|
|
690
|
-
className: `relative inline-flex h-4 w-7 shrink-0 items-center rounded-full transition-colors ${value ? "bg-midnight-accent" : "bg-midnight-border"}`,
|
|
691
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: `inline-block h-3 w-3 transform rounded-full bg-white transition-transform ${value ? "translate-x-3.5" : "translate-x-0.5"}` })
|
|
722
|
+
className: "w-9 h-6 bg-transparent border border-midnight-border cursor-pointer p-0"
|
|
692
723
|
}
|
|
693
724
|
);
|
|
694
725
|
}
|
|
@@ -696,21 +727,9 @@ function OptionalColor({ value, onChange, fallback = "#a78bfa" }) {
|
|
|
696
727
|
const on = !!value;
|
|
697
728
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
698
729
|
on && /* @__PURE__ */ jsxRuntime.jsx(ColorControl, { value, onChange }),
|
|
699
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
730
|
+
/* @__PURE__ */ jsxRuntime.jsx(terminalUxComponents.TerminalToggle, { size: "small", checked: on, onChange: (v) => onChange(v ? fallback : "") })
|
|
700
731
|
] });
|
|
701
732
|
}
|
|
702
|
-
function Choice({ value, options, onChange }) {
|
|
703
|
-
const { theme } = useDashboard();
|
|
704
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
705
|
-
"select",
|
|
706
|
-
{
|
|
707
|
-
value,
|
|
708
|
-
onChange: (e) => onChange(e.target.value),
|
|
709
|
-
className: `w-full px-2 py-1 text-xs font-mono bg-midnight-surface border ${theme.border} text-midnight-text-body outline-none focus:border-midnight-accent transition-colors`,
|
|
710
|
-
children: options.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o, children: o }, o))
|
|
711
|
-
}
|
|
712
|
-
);
|
|
713
|
-
}
|
|
714
733
|
function ChartStyleControls({ style, onChange }) {
|
|
715
734
|
const s = withStyleDefaults(style);
|
|
716
735
|
const set = (key, value) => onChange({ ...s, [key]: value });
|
|
@@ -719,35 +738,42 @@ function ChartStyleControls({ style, onChange }) {
|
|
|
719
738
|
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Background", children: /* @__PURE__ */ jsxRuntime.jsx(ColorControl, { value: s.background, onChange: (v) => set("background", v) }) }),
|
|
720
739
|
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Text", children: /* @__PURE__ */ jsxRuntime.jsx(ColorControl, { value: s.textColor, onChange: (v) => set("textColor", v) }) }),
|
|
721
740
|
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Grid", children: /* @__PURE__ */ jsxRuntime.jsx(ColorControl, { value: s.gridColor, onChange: (v) => set("gridColor", v) }) }),
|
|
722
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Font size", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
741
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Font size", children: /* @__PURE__ */ jsxRuntime.jsx(terminalUxComponents.TerminalSlider, { value: s.fontSize, min: 6, max: 24, unit: "px", onChange: (v) => set("fontSize", v) }) })
|
|
723
742
|
] }),
|
|
724
743
|
/* @__PURE__ */ jsxRuntime.jsxs(Section, { title: "Axis titles", children: [
|
|
725
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "X title", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
726
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Show X", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
727
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Y title", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
728
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Show Y", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
744
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "X title", children: /* @__PURE__ */ jsxRuntime.jsx(terminalUxComponents.TerminalInput, { size: "small", value: s.xAxisLabel, placeholder: "(column)", onChange: (e) => set("xAxisLabel", e.target.value) }) }),
|
|
745
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Show X", children: /* @__PURE__ */ jsxRuntime.jsx(terminalUxComponents.TerminalToggle, { size: "small", checked: s.showXLegend, onChange: (v) => set("showXLegend", v) }) }),
|
|
746
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Y title", children: /* @__PURE__ */ jsxRuntime.jsx(terminalUxComponents.TerminalInput, { size: "small", value: s.yAxisLabel, placeholder: "(column)", onChange: (e) => set("yAxisLabel", e.target.value) }) }),
|
|
747
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Show Y", children: /* @__PURE__ */ jsxRuntime.jsx(terminalUxComponents.TerminalToggle, { size: "small", checked: s.showYLegend, onChange: (v) => set("showYLegend", v) }) }),
|
|
729
748
|
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Color", children: /* @__PURE__ */ jsxRuntime.jsx(ColorControl, { value: s.legendColor, onChange: (v) => set("legendColor", v) }) }),
|
|
730
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Bold", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
749
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Bold", children: /* @__PURE__ */ jsxRuntime.jsx(terminalUxComponents.TerminalToggle, { size: "small", checked: s.legendBold, onChange: (v) => set("legendBold", v) }) }),
|
|
731
750
|
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Highlight", children: /* @__PURE__ */ jsxRuntime.jsx(OptionalColor, { value: s.legendHighlight, onChange: (v) => set("legendHighlight", v) }) })
|
|
732
751
|
] }),
|
|
733
752
|
/* @__PURE__ */ jsxRuntime.jsxs(Section, { title: "Axis placement", children: [
|
|
734
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "X pos", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
735
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "X offset", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
736
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Y pos", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
737
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Y offset", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
753
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "X pos", children: /* @__PURE__ */ jsxRuntime.jsx(terminalUxComponents.TerminalSelect, { size: "small", value: s.xLegendPosition, options: ["start", "middle", "end"], onChange: (v) => set("xLegendPosition", v) }) }),
|
|
754
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "X offset", children: /* @__PURE__ */ jsxRuntime.jsx(terminalUxComponents.TerminalSlider, { value: s.xLegendOffset, min: -80, max: 80, onChange: (v) => set("xLegendOffset", v) }) }),
|
|
755
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Y pos", children: /* @__PURE__ */ jsxRuntime.jsx(terminalUxComponents.TerminalSelect, { size: "small", value: s.yLegendPosition, options: ["start", "middle", "end"], onChange: (v) => set("yLegendPosition", v) }) }),
|
|
756
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Y offset", children: /* @__PURE__ */ jsxRuntime.jsx(terminalUxComponents.TerminalSlider, { value: s.yLegendOffset, min: -80, max: 80, onChange: (v) => set("yLegendOffset", v) }) })
|
|
738
757
|
] }),
|
|
739
758
|
/* @__PURE__ */ jsxRuntime.jsxs(Section, { title: "Ticks", children: [
|
|
740
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "
|
|
741
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "
|
|
742
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "
|
|
759
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Wrap", children: /* @__PURE__ */ jsxRuntime.jsx(terminalUxComponents.TerminalToggle, { size: "small", checked: s.tickWrap, onChange: (v) => set("tickWrap", v) }) }),
|
|
760
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Wrap width", children: /* @__PURE__ */ jsxRuntime.jsx(terminalUxComponents.TerminalSlider, { value: s.tickWrapWidth, min: 4, max: 40, onChange: (v) => set("tickWrapWidth", v) }) }),
|
|
761
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "X angle", children: /* @__PURE__ */ jsxRuntime.jsx(terminalUxComponents.TerminalSlider, { value: s.xTickRotation, min: -90, max: 90, unit: "\xB0", onChange: (v) => set("xTickRotation", v) }) }),
|
|
762
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Y angle", children: /* @__PURE__ */ jsxRuntime.jsx(terminalUxComponents.TerminalSlider, { value: s.yTickRotation, min: -90, max: 90, unit: "\xB0", onChange: (v) => set("yTickRotation", v) }) }),
|
|
763
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Truncate", children: /* @__PURE__ */ jsxRuntime.jsx(terminalUxComponents.TerminalSlider, { value: s.tickTruncate, min: 0, max: 40, onChange: (v) => set("tickTruncate", v) }) })
|
|
764
|
+
] }),
|
|
765
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Section, { title: "Table cells", children: [
|
|
766
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Wrap", children: /* @__PURE__ */ jsxRuntime.jsx(terminalUxComponents.TerminalToggle, { size: "small", checked: s.cellWrap, onChange: (v) => set("cellWrap", v) }) }),
|
|
767
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Decimals", children: /* @__PURE__ */ jsxRuntime.jsx(terminalUxComponents.TerminalSlider, { value: s.cellPrecision, min: 0, max: 8, onChange: (v) => set("cellPrecision", v) }) }),
|
|
768
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Truncate", children: /* @__PURE__ */ jsxRuntime.jsx(terminalUxComponents.TerminalSlider, { value: s.cellTruncate, min: 0, max: 80, onChange: (v) => set("cellTruncate", v) }) })
|
|
743
769
|
] }),
|
|
744
770
|
/* @__PURE__ */ jsxRuntime.jsxs(Section, { title: "Panel title", children: [
|
|
745
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Align", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
746
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Bold", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
771
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Align", children: /* @__PURE__ */ jsxRuntime.jsx(terminalUxComponents.TerminalSelect, { size: "small", value: s.titleAlign, options: ["left", "center", "right"], onChange: (v) => set("titleAlign", v) }) }),
|
|
772
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Bold", children: /* @__PURE__ */ jsxRuntime.jsx(terminalUxComponents.TerminalToggle, { size: "small", checked: s.titleBold, onChange: (v) => set("titleBold", v) }) }),
|
|
747
773
|
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Color", children: /* @__PURE__ */ jsxRuntime.jsx(OptionalColor, { value: s.titleColor, onChange: (v) => set("titleColor", v), fallback: "#e2e8f0" }) }),
|
|
748
774
|
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Background", children: /* @__PURE__ */ jsxRuntime.jsx(OptionalColor, { value: s.titleBackground, onChange: (v) => set("titleBackground", v), fallback: "#1e293b" }) })
|
|
749
775
|
] }),
|
|
750
|
-
/* @__PURE__ */ jsxRuntime.jsx(Section, { title: "Series legend", children: /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Position", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
776
|
+
/* @__PURE__ */ jsxRuntime.jsx(Section, { title: "Series legend", children: /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Position", children: /* @__PURE__ */ jsxRuntime.jsx(terminalUxComponents.TerminalSelect, { size: "small", value: s.legendAnchor, options: ["right", "top-left", "top-right", "bottom-left", "bottom-right", "none"], onChange: (v) => set("legendAnchor", v) }) }) })
|
|
751
777
|
] });
|
|
752
778
|
}
|
|
753
779
|
var AGGREGATES = [
|
|
@@ -1355,7 +1381,7 @@ var GroupedBarChart = ({ records, xFields = [], yFields = [], groupField, data:
|
|
|
1355
1381
|
const keys = presetKeys || yFields.map((yf) => `${yf.agg}(${yf.name})`);
|
|
1356
1382
|
const colors = ["rgba(74,222,128,0.8)", "rgba(96,165,250,0.8)", "rgba(251,146,60,0.8)", "rgba(167,139,250,0.8)", "rgba(248,113,113,0.8)"];
|
|
1357
1383
|
const legend = legendConfig(style);
|
|
1358
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full min-h-[
|
|
1384
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full min-h-[160px]", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1359
1385
|
bar.ResponsiveBar,
|
|
1360
1386
|
{
|
|
1361
1387
|
data,
|
|
@@ -1365,8 +1391,8 @@ var GroupedBarChart = ({ records, xFields = [], yFields = [], groupField, data:
|
|
|
1365
1391
|
margin: { top: 20, right: 120, bottom: 60, left: 60 },
|
|
1366
1392
|
padding: 0.3,
|
|
1367
1393
|
colors: colors.slice(0, keys.length),
|
|
1368
|
-
axisBottom:
|
|
1369
|
-
axisLeft:
|
|
1394
|
+
axisBottom: makeAxis(style, "x", xFields[0]?.name || ""),
|
|
1395
|
+
axisLeft: makeAxis(style, "y", "", { numeric: true }),
|
|
1370
1396
|
labelSkipWidth: 12,
|
|
1371
1397
|
labelSkipHeight: 12,
|
|
1372
1398
|
labelTextColor: { from: "color", modifiers: [["darker", 3]] },
|
|
@@ -1472,6 +1498,7 @@ function ChartBuilder({ records, columns, stateId, onSave }) {
|
|
|
1472
1498
|
const [style, setStyle] = react.useState(DEFAULT_CHART_STYLE);
|
|
1473
1499
|
const [showStyle, setShowStyle] = react.useState(false);
|
|
1474
1500
|
const [showFields, setShowFields] = react.useState(false);
|
|
1501
|
+
const [fillContainer, setFillContainer] = react.useState(false);
|
|
1475
1502
|
const [sqlRows, setSqlRows] = react.useState(null);
|
|
1476
1503
|
const [sqlLoading, setSqlLoading] = react.useState(false);
|
|
1477
1504
|
const [sqlError, setSqlError] = react.useState(null);
|
|
@@ -1586,12 +1613,13 @@ function ChartBuilder({ records, columns, stateId, onSave }) {
|
|
|
1586
1613
|
}
|
|
1587
1614
|
}
|
|
1588
1615
|
config.style = style;
|
|
1616
|
+
config.fill = fillContainer;
|
|
1589
1617
|
onSave({
|
|
1590
1618
|
title: title || `${chartType} chart`,
|
|
1591
1619
|
type: chartType === "grouped-bar" ? "bar" : chartType,
|
|
1592
1620
|
config,
|
|
1593
|
-
width: 6,
|
|
1594
|
-
height: 2
|
|
1621
|
+
width: fillContainer ? 12 : 6,
|
|
1622
|
+
height: fillContainer ? 8 : 2
|
|
1595
1623
|
});
|
|
1596
1624
|
};
|
|
1597
1625
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full", children: [
|
|
@@ -1747,6 +1775,10 @@ function ChartBuilder({ records, columns, stateId, onSave }) {
|
|
|
1747
1775
|
className: "w-full mb-2 px-2 py-1 text-xs font-mono bg-midnight-surface border border-midnight-border text-midnight-text-body outline-none focus:border-midnight-accent transition-colors"
|
|
1748
1776
|
}
|
|
1749
1777
|
),
|
|
1778
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
|
|
1779
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-mono text-midnight-text-muted", title: "Span the full dashboard width and height", children: "Maximize size" }),
|
|
1780
|
+
/* @__PURE__ */ jsxRuntime.jsx(terminalUxComponents.TerminalToggle, { size: "small", checked: fillContainer, onChange: setFillContainer })
|
|
1781
|
+
] }),
|
|
1750
1782
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1751
1783
|
"button",
|
|
1752
1784
|
{
|
|
@@ -1843,14 +1875,26 @@ function panelSql(type, config) {
|
|
|
1843
1875
|
if (SQL_CHART_TYPES.has(type)) return buildChartSQL(panelToChartConfig(type, config)) || "";
|
|
1844
1876
|
return "";
|
|
1845
1877
|
}
|
|
1846
|
-
function
|
|
1878
|
+
function formatCell(value, s) {
|
|
1879
|
+
if (value == null) return "";
|
|
1880
|
+
if (typeof value === "object") return JSON.stringify(value);
|
|
1881
|
+
let str;
|
|
1882
|
+
const n = typeof value === "number" ? value : Number(value);
|
|
1883
|
+
if (value !== "" && typeof value !== "boolean" && Number.isFinite(n)) {
|
|
1884
|
+
str = Number.isInteger(n) ? n.toLocaleString() : n.toLocaleString(void 0, { minimumFractionDigits: s.cellPrecision, maximumFractionDigits: s.cellPrecision });
|
|
1885
|
+
} else {
|
|
1886
|
+
str = String(value);
|
|
1887
|
+
}
|
|
1888
|
+
if (s.cellTruncate > 0 && str.length > s.cellTruncate) str = `${str.slice(0, s.cellTruncate)}\u2026`;
|
|
1889
|
+
return str;
|
|
1890
|
+
}
|
|
1891
|
+
function DataTable({ rows, columns, style }) {
|
|
1892
|
+
const s = withStyleDefaults(style);
|
|
1847
1893
|
const colNames = columns?.length ? columns : rows[0] ? Object.keys(rows[0]) : [];
|
|
1894
|
+
const cellCls = s.cellWrap ? "px-2 py-1 text-midnight-text-body align-top whitespace-normal break-words max-w-[280px]" : "px-2 py-1 text-midnight-text-body truncate max-w-[200px]";
|
|
1848
1895
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-auto h-full text-xs", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full", children: [
|
|
1849
1896
|
/* @__PURE__ */ jsxRuntime.jsx("thead", { className: "sticky top-0 bg-midnight-elevated", children: /* @__PURE__ */ jsxRuntime.jsx("tr", { children: colNames.map((n) => /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-2 py-1 text-left text-midnight-text-muted font-mono border-b border-midnight-border", children: n }, n)) }) }),
|
|
1850
|
-
/* @__PURE__ */ jsxRuntime.jsx("tbody", { children: rows.map((r, i) => /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "border-b border-dashed border-midnight-border hover:bg-midnight-raised", children: colNames.map((n) => {
|
|
1851
|
-
const cellValue = r[n];
|
|
1852
|
-
return /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-2 py-1 text-midnight-text-body truncate max-w-[200px]", children: cellValue == null ? "" : typeof cellValue === "object" ? JSON.stringify(cellValue) : String(cellValue) }, n);
|
|
1853
|
-
}) }, i)) })
|
|
1897
|
+
/* @__PURE__ */ jsxRuntime.jsx("tbody", { children: rows.map((r, i) => /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "border-b border-dashed border-midnight-border hover:bg-midnight-raised", children: colNames.map((n) => /* @__PURE__ */ jsxRuntime.jsx("td", { className: cellCls, children: formatCell(r[n], s) }, n)) }, i)) })
|
|
1854
1898
|
] }) });
|
|
1855
1899
|
}
|
|
1856
1900
|
function SqlPanel({ panel }) {
|
|
@@ -1945,7 +1989,7 @@ function SqlPanel({ panel }) {
|
|
|
1945
1989
|
const v = first ? Object.values(first)[0] : 0;
|
|
1946
1990
|
chart = /* @__PURE__ */ jsxRuntime.jsx(MetricView, { value: Number(v) || 0, config: { column: config.column || "", agg: config.agg, label: config.label } });
|
|
1947
1991
|
} else if (chartType === "table") {
|
|
1948
|
-
chart = /* @__PURE__ */ jsxRuntime.jsx(DataTable, { rows, columns: config.columns });
|
|
1992
|
+
chart = /* @__PURE__ */ jsxRuntime.jsx(DataTable, { rows, columns: config.columns, style: config.style });
|
|
1949
1993
|
} else {
|
|
1950
1994
|
const shaped = shapeChartData(chartType, rows, { yFields: config.yFields || [] });
|
|
1951
1995
|
switch (chartType) {
|
|
@@ -2009,7 +2053,7 @@ function PanelContent({ panel, records, columns }) {
|
|
|
2009
2053
|
case "insight":
|
|
2010
2054
|
return /* @__PURE__ */ jsxRuntime.jsx(InsightView, { config: { text: config.text } });
|
|
2011
2055
|
case "table":
|
|
2012
|
-
return /* @__PURE__ */ jsxRuntime.jsx(DataTable, { rows: (records || []).slice(0, 50), columns: config.columns || columns?.map((c) => c.name) });
|
|
2056
|
+
return /* @__PURE__ */ jsxRuntime.jsx(DataTable, { rows: (records || []).slice(0, 50), columns: config.columns || columns?.map((c) => c.name), style: config.style });
|
|
2013
2057
|
default:
|
|
2014
2058
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 text-xs text-midnight-text-muted", children: [
|
|
2015
2059
|
"Unknown panel type: ",
|
|
@@ -2048,10 +2092,11 @@ var GridLayoutWithWidth = GridLayout.WidthProvider(GridLayout__default.default);
|
|
|
2048
2092
|
function buildLayout(panels) {
|
|
2049
2093
|
let cx = 0, cy = 0, rowH = 0;
|
|
2050
2094
|
return panels.map((p) => {
|
|
2051
|
-
const
|
|
2052
|
-
const
|
|
2095
|
+
const fill = !!p.config?.fill;
|
|
2096
|
+
const w = fill ? GRID_COLS : Math.min(Math.max(p.width || 6, 1), GRID_COLS);
|
|
2097
|
+
const h = fill ? Math.max(p.height || 8, 6) : Math.max(p.height || 4, 1);
|
|
2053
2098
|
if (typeof p.x === "number" && typeof p.y === "number") {
|
|
2054
|
-
return { i: p.id, x: p.x, y: p.y, w, h, minW: 2, minH: 2 };
|
|
2099
|
+
return { i: p.id, x: fill ? 0 : p.x, y: p.y, w, h, minW: 2, minH: 2 };
|
|
2055
2100
|
}
|
|
2056
2101
|
if (cx + w > GRID_COLS) {
|
|
2057
2102
|
cx = 0;
|
|
@@ -2075,11 +2120,45 @@ function DashboardRenderer({ dashboard, records, columns }) {
|
|
|
2075
2120
|
persistLayout(next.map((l) => ({ id: l.i, x: l.x, y: l.y, w: l.w, h: l.h })));
|
|
2076
2121
|
}, [persistLayout]);
|
|
2077
2122
|
if (!dashboard) return null;
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2081
|
-
|
|
2123
|
+
const panelFrame = (panel, draggable) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `border ${theme.border} bg-midnight-surface flex flex-col overflow-hidden h-full`, children: [
|
|
2124
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center justify-between px-3 py-1.5 border-b ${theme.border} bg-midnight-elevated ${draggable ? DRAG_HANDLE : ""}`, children: [
|
|
2125
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2126
|
+
"span",
|
|
2127
|
+
{
|
|
2128
|
+
className: "flex-1 text-xs font-mono text-midnight-text-body truncate px-1",
|
|
2129
|
+
style: {
|
|
2130
|
+
textAlign: panel.config?.style?.titleAlign || "left",
|
|
2131
|
+
fontWeight: panel.config?.style?.titleBold ? 700 : void 0,
|
|
2132
|
+
background: panel.config?.style?.titleBackground || void 0,
|
|
2133
|
+
color: panel.config?.style?.titleColor || void 0
|
|
2134
|
+
},
|
|
2135
|
+
children: panel.title || panel.type
|
|
2136
|
+
}
|
|
2137
|
+
),
|
|
2138
|
+
canEditPanels && removePanel && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2139
|
+
"button",
|
|
2140
|
+
{
|
|
2141
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
2142
|
+
onClick: () => removePanel(panel.id),
|
|
2143
|
+
className: "p-0.5 hover:bg-midnight-raised text-midnight-text-muted hover:text-midnight-text-body transition-colors",
|
|
2144
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3 h-3" })
|
|
2145
|
+
}
|
|
2146
|
+
)
|
|
2082
2147
|
] }),
|
|
2148
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntime.jsx(react.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(ViewLoading, {}), children: /* @__PURE__ */ jsxRuntime.jsx(PanelContent, { panel, records, columns }) }) })
|
|
2149
|
+
] }, panel.id);
|
|
2150
|
+
const insightsBanner = dashboard.insights ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `border ${theme.border} bg-midnight-elevated px-4 py-3 flex items-start gap-3`, children: [
|
|
2151
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "w-5 h-5 text-midnight-accent shrink-0 mt-0.5" }),
|
|
2152
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-sm ${theme.text} leading-relaxed`, children: dashboard.insights })
|
|
2153
|
+
] }) : null;
|
|
2154
|
+
if (panels.length === 1) {
|
|
2155
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4 p-2 h-full min-h-[60vh]", children: [
|
|
2156
|
+
insightsBanner,
|
|
2157
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0", children: panelFrame(panels[0], false) })
|
|
2158
|
+
] });
|
|
2159
|
+
}
|
|
2160
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4 p-2", children: [
|
|
2161
|
+
insightsBanner,
|
|
2083
2162
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2084
2163
|
GridLayoutWithWidth,
|
|
2085
2164
|
{
|
|
@@ -2094,33 +2173,7 @@ function DashboardRenderer({ dashboard, records, columns }) {
|
|
|
2094
2173
|
onDragStop: onLayoutChange,
|
|
2095
2174
|
onResizeStop: onLayoutChange,
|
|
2096
2175
|
compactType: canEditLayout ? "vertical" : null,
|
|
2097
|
-
children: panels.map((panel) =>
|
|
2098
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center justify-between px-3 py-1.5 border-b ${theme.border} bg-midnight-elevated ${canEditLayout ? DRAG_HANDLE : ""}`, children: [
|
|
2099
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2100
|
-
"span",
|
|
2101
|
-
{
|
|
2102
|
-
className: "flex-1 text-xs font-mono text-midnight-text-body truncate px-1",
|
|
2103
|
-
style: {
|
|
2104
|
-
textAlign: panel.config?.style?.titleAlign || "left",
|
|
2105
|
-
fontWeight: panel.config?.style?.titleBold ? 700 : void 0,
|
|
2106
|
-
background: panel.config?.style?.titleBackground || void 0,
|
|
2107
|
-
color: panel.config?.style?.titleColor || void 0
|
|
2108
|
-
},
|
|
2109
|
-
children: panel.title || panel.type
|
|
2110
|
-
}
|
|
2111
|
-
),
|
|
2112
|
-
canEditPanels && removePanel && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2113
|
-
"button",
|
|
2114
|
-
{
|
|
2115
|
-
onMouseDown: (e) => e.stopPropagation(),
|
|
2116
|
-
onClick: () => removePanel(panel.id),
|
|
2117
|
-
className: "p-0.5 hover:bg-midnight-raised text-midnight-text-muted hover:text-midnight-text-body transition-colors",
|
|
2118
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-3 h-3" })
|
|
2119
|
-
}
|
|
2120
|
-
)
|
|
2121
|
-
] }),
|
|
2122
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntime.jsx(react.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(ViewLoading, {}), children: /* @__PURE__ */ jsxRuntime.jsx(PanelContent, { panel, records, columns }) }) })
|
|
2123
|
-
] }, panel.id))
|
|
2176
|
+
children: panels.map((panel) => panelFrame(panel, canEditLayout))
|
|
2124
2177
|
}
|
|
2125
2178
|
)
|
|
2126
2179
|
] });
|