@quantumwake/terminal-ux-dashboard-components 0.1.13 → 0.1.15
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 +178 -105
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -9
- package/dist/index.d.ts +19 -9
- package/dist/index.js +178 -106
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/dist/index.cjs
CHANGED
|
@@ -13,11 +13,13 @@ var lucideReact = require('lucide-react');
|
|
|
13
13
|
var CodeMirror = require('@uiw/react-codemirror');
|
|
14
14
|
var langSql = require('@codemirror/lang-sql');
|
|
15
15
|
var autocomplete = require('@codemirror/autocomplete');
|
|
16
|
+
var GridLayout = require('react-grid-layout');
|
|
16
17
|
|
|
17
18
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
18
19
|
|
|
19
20
|
var PivotTableUI__default = /*#__PURE__*/_interopDefault(PivotTableUI);
|
|
20
21
|
var CodeMirror__default = /*#__PURE__*/_interopDefault(CodeMirror);
|
|
22
|
+
var GridLayout__default = /*#__PURE__*/_interopDefault(GridLayout);
|
|
21
23
|
|
|
22
24
|
// src/context/DashboardContext.tsx
|
|
23
25
|
var DashboardContext = react.createContext(null);
|
|
@@ -46,7 +48,9 @@ function useCapabilities() {
|
|
|
46
48
|
canAddPanel: !!c.addPanel,
|
|
47
49
|
canEditPanels: !!c.removePanel,
|
|
48
50
|
// Studio can recompute + persist a panel's precomputed result.
|
|
49
|
-
canRefresh: !!c.persistPanelData
|
|
51
|
+
canRefresh: !!c.persistPanelData,
|
|
52
|
+
// Studio can drag/resize panels and persist the grid layout.
|
|
53
|
+
canEditLayout: !!c.persistLayout
|
|
50
54
|
};
|
|
51
55
|
}
|
|
52
56
|
|
|
@@ -232,6 +236,7 @@ var DEFAULT_CHART_STYLE = {
|
|
|
232
236
|
legendHighlight: "",
|
|
233
237
|
// Tick overflow handling.
|
|
234
238
|
xTickRotation: -35,
|
|
239
|
+
yTickRotation: 0,
|
|
235
240
|
tickTruncate: 0,
|
|
236
241
|
// Series legend placement (charts that have one: pie, grouped bar).
|
|
237
242
|
legendAnchor: "right",
|
|
@@ -307,7 +312,7 @@ var axisLegend = (style, axis, columnName, opts2 = {}) => {
|
|
|
307
312
|
out.legendPosition = isX ? s.xLegendPosition : s.yLegendPosition;
|
|
308
313
|
out.legendOffset = isX ? s.xLegendOffset : s.yLegendOffset;
|
|
309
314
|
}
|
|
310
|
-
|
|
315
|
+
out.tickRotation = isX ? s.xTickRotation : s.yTickRotation;
|
|
311
316
|
if (opts2.numeric) out.format = (v) => Number(v).toLocaleString();
|
|
312
317
|
else if (s.tickTruncate > 0) out.format = (v) => truncate(v, s.tickTruncate);
|
|
313
318
|
return out;
|
|
@@ -616,11 +621,17 @@ function PivotView({ records }) {
|
|
|
616
621
|
)
|
|
617
622
|
] });
|
|
618
623
|
}
|
|
619
|
-
function
|
|
624
|
+
function Section({ title, children }) {
|
|
620
625
|
const { theme } = useDashboard();
|
|
621
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className:
|
|
622
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
623
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "
|
|
626
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `py-3 border-t ${theme.border} first:border-t-0 first:pt-0`, children: [
|
|
627
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[10px] uppercase tracking-wider text-midnight-text-muted/70 font-mono mb-2", children: title }),
|
|
628
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5", children })
|
|
629
|
+
] });
|
|
630
|
+
}
|
|
631
|
+
function Row({ label, children }) {
|
|
632
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-[88px_1fr] items-center gap-2 min-h-[30px]", children: [
|
|
633
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-mono text-midnight-text-muted truncate", title: label, children: label }),
|
|
634
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-end", children })
|
|
624
635
|
] });
|
|
625
636
|
}
|
|
626
637
|
function ColorControl({ value, onChange }) {
|
|
@@ -631,23 +642,29 @@ function ColorControl({ value, onChange }) {
|
|
|
631
642
|
type: "color",
|
|
632
643
|
value: /^#/.test(value) ? value : "#94a3b8",
|
|
633
644
|
onChange: (e) => onChange(e.target.value),
|
|
634
|
-
className: `w-9 h-6 bg-transparent border ${theme.border} cursor-pointer`
|
|
645
|
+
className: `w-9 h-6 bg-transparent border ${theme.border} cursor-pointer p-0`
|
|
635
646
|
}
|
|
636
647
|
);
|
|
637
648
|
}
|
|
638
|
-
function
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
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: [
|
|
644
664
|
value,
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
className: `w-20 px-2 py-1 text-xs ${theme.font} bg-midnight-surface border ${theme.border} text-midnight-text-body outline-none focus:border-midnight-accent`
|
|
649
|
-
}
|
|
650
|
-
);
|
|
665
|
+
unit
|
|
666
|
+
] })
|
|
667
|
+
] });
|
|
651
668
|
}
|
|
652
669
|
function TextControl({ value, onChange, placeholder }) {
|
|
653
670
|
const { theme } = useDashboard();
|
|
@@ -658,78 +675,79 @@ function TextControl({ value, onChange, placeholder }) {
|
|
|
658
675
|
value,
|
|
659
676
|
placeholder,
|
|
660
677
|
onChange: (e) => onChange(e.target.value),
|
|
661
|
-
className: `w-
|
|
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`
|
|
662
679
|
}
|
|
663
680
|
);
|
|
664
681
|
}
|
|
665
|
-
function
|
|
682
|
+
function Switch({ value, onChange }) {
|
|
666
683
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
667
|
-
"
|
|
684
|
+
"button",
|
|
668
685
|
{
|
|
669
|
-
type: "
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
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"}` })
|
|
673
692
|
}
|
|
674
693
|
);
|
|
675
694
|
}
|
|
676
695
|
function OptionalColor({ value, onChange, fallback = "#a78bfa" }) {
|
|
677
696
|
const on = !!value;
|
|
678
697
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
679
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
680
|
-
|
|
698
|
+
on && /* @__PURE__ */ jsxRuntime.jsx(ColorControl, { value, onChange }),
|
|
699
|
+
/* @__PURE__ */ jsxRuntime.jsx(Switch, { value: on, onChange: (v) => onChange(v ? fallback : "") })
|
|
681
700
|
] });
|
|
682
701
|
}
|
|
683
702
|
function Choice({ value, options, onChange }) {
|
|
684
703
|
const { theme } = useDashboard();
|
|
685
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
704
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
686
705
|
"select",
|
|
687
706
|
{
|
|
688
707
|
value,
|
|
689
708
|
onChange: (e) => onChange(e.target.value),
|
|
690
|
-
className: `w-full px-2 py-1 text-xs
|
|
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`,
|
|
691
710
|
children: options.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o, children: o }, o))
|
|
692
711
|
}
|
|
693
|
-
)
|
|
694
|
-
}
|
|
695
|
-
function Group({ children, last }) {
|
|
696
|
-
const { theme } = useDashboard();
|
|
697
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `space-y-2 pb-3 ${last ? "" : `mb-3 border-b ${theme.border}`}`, children });
|
|
712
|
+
);
|
|
698
713
|
}
|
|
699
714
|
function ChartStyleControls({ style, onChange }) {
|
|
700
715
|
const s = withStyleDefaults(style);
|
|
701
716
|
const set = (key, value) => onChange({ ...s, [key]: value });
|
|
702
717
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
703
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
718
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Section, { title: "Canvas", children: [
|
|
704
719
|
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Background", children: /* @__PURE__ */ jsxRuntime.jsx(ColorControl, { value: s.background, onChange: (v) => set("background", v) }) }),
|
|
705
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Text
|
|
706
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Grid
|
|
707
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Font size", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
720
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Text", children: /* @__PURE__ */ jsxRuntime.jsx(ColorControl, { value: s.textColor, onChange: (v) => set("textColor", v) }) }),
|
|
721
|
+
/* @__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(SliderControl, { value: s.fontSize, min: 6, max: 24, unit: "px", onChange: (v) => set("fontSize", v) }) })
|
|
708
723
|
] }),
|
|
709
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
710
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "X
|
|
711
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Show X
|
|
712
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Y
|
|
713
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Show Y
|
|
714
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "
|
|
715
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "
|
|
716
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "
|
|
717
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "X title pos", children: /* @__PURE__ */ jsxRuntime.jsx(Choice, { value: s.xLegendPosition, options: ["start", "middle", "end"], onChange: (v) => set("xLegendPosition", v) }) }),
|
|
718
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "X title offset", children: /* @__PURE__ */ jsxRuntime.jsx(NumberControl, { value: s.xLegendOffset, onChange: (v) => set("xLegendOffset", v) }) }),
|
|
719
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Y title pos", children: /* @__PURE__ */ jsxRuntime.jsx(Choice, { value: s.yLegendPosition, options: ["start", "middle", "end"], onChange: (v) => set("yLegendPosition", v) }) }),
|
|
720
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Y title offset", children: /* @__PURE__ */ jsxRuntime.jsx(NumberControl, { value: s.yLegendOffset, onChange: (v) => set("yLegendOffset", v) }) })
|
|
724
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Section, { title: "Axis titles", children: [
|
|
725
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "X title", children: /* @__PURE__ */ jsxRuntime.jsx(TextControl, { value: s.xAxisLabel, placeholder: "(column)", onChange: (v) => set("xAxisLabel", v) }) }),
|
|
726
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Show X", children: /* @__PURE__ */ jsxRuntime.jsx(Switch, { value: s.showXLegend, onChange: (v) => set("showXLegend", v) }) }),
|
|
727
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Y title", children: /* @__PURE__ */ jsxRuntime.jsx(TextControl, { value: s.yAxisLabel, placeholder: "(column)", onChange: (v) => set("yAxisLabel", v) }) }),
|
|
728
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Show Y", children: /* @__PURE__ */ jsxRuntime.jsx(Switch, { value: s.showYLegend, onChange: (v) => set("showYLegend", v) }) }),
|
|
729
|
+
/* @__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(Switch, { value: s.legendBold, onChange: (v) => set("legendBold", v) }) }),
|
|
731
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Highlight", children: /* @__PURE__ */ jsxRuntime.jsx(OptionalColor, { value: s.legendHighlight, onChange: (v) => set("legendHighlight", v) }) })
|
|
721
732
|
] }),
|
|
722
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
723
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "X
|
|
724
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "
|
|
733
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Section, { title: "Axis placement", children: [
|
|
734
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "X pos", children: /* @__PURE__ */ jsxRuntime.jsx(Choice, { value: s.xLegendPosition, options: ["start", "middle", "end"], onChange: (v) => set("xLegendPosition", v) }) }),
|
|
735
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "X offset", children: /* @__PURE__ */ jsxRuntime.jsx(SliderControl, { value: s.xLegendOffset, min: -80, max: 80, onChange: (v) => set("xLegendOffset", v) }) }),
|
|
736
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Y pos", children: /* @__PURE__ */ jsxRuntime.jsx(Choice, { value: s.yLegendPosition, options: ["start", "middle", "end"], onChange: (v) => set("yLegendPosition", v) }) }),
|
|
737
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Y offset", children: /* @__PURE__ */ jsxRuntime.jsx(SliderControl, { value: s.yLegendOffset, min: -80, max: 80, onChange: (v) => set("yLegendOffset", v) }) })
|
|
725
738
|
] }),
|
|
726
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
727
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "
|
|
728
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "
|
|
729
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
739
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Section, { title: "Ticks", children: [
|
|
740
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "X angle", children: /* @__PURE__ */ jsxRuntime.jsx(SliderControl, { value: s.xTickRotation, min: -90, max: 90, unit: "\xB0", onChange: (v) => set("xTickRotation", v) }) }),
|
|
741
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Y angle", children: /* @__PURE__ */ jsxRuntime.jsx(SliderControl, { value: s.yTickRotation, min: -90, max: 90, unit: "\xB0", onChange: (v) => set("yTickRotation", v) }) }),
|
|
742
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Truncate", children: /* @__PURE__ */ jsxRuntime.jsx(SliderControl, { value: s.tickTruncate, min: 0, max: 40, onChange: (v) => set("tickTruncate", v) }) })
|
|
743
|
+
] }),
|
|
744
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Section, { title: "Panel title", children: [
|
|
745
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Align", children: /* @__PURE__ */ jsxRuntime.jsx(Choice, { value: s.titleAlign, options: ["left", "center", "right"], onChange: (v) => set("titleAlign", v) }) }),
|
|
746
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Bold", children: /* @__PURE__ */ jsxRuntime.jsx(Switch, { value: s.titleBold, onChange: (v) => set("titleBold", v) }) }),
|
|
747
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Color", children: /* @__PURE__ */ jsxRuntime.jsx(OptionalColor, { value: s.titleColor, onChange: (v) => set("titleColor", v), fallback: "#e2e8f0" }) }),
|
|
748
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Background", children: /* @__PURE__ */ jsxRuntime.jsx(OptionalColor, { value: s.titleBackground, onChange: (v) => set("titleBackground", v), fallback: "#1e293b" }) })
|
|
749
|
+
] }),
|
|
750
|
+
/* @__PURE__ */ jsxRuntime.jsx(Section, { title: "Series legend", children: /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Position", children: /* @__PURE__ */ jsxRuntime.jsx(Choice, { value: s.legendAnchor, options: ["right", "top-left", "top-right", "bottom-left", "bottom-right", "none"], onChange: (v) => set("legendAnchor", v) }) }) })
|
|
733
751
|
] });
|
|
734
752
|
}
|
|
735
753
|
var AGGREGATES = [
|
|
@@ -1999,57 +2017,112 @@ function PanelContent({ panel, records, columns }) {
|
|
|
1999
2017
|
] });
|
|
2000
2018
|
}
|
|
2001
2019
|
}
|
|
2002
|
-
var
|
|
2020
|
+
var GRID_COLS = 12;
|
|
2021
|
+
var ROW_HEIGHT = 80;
|
|
2022
|
+
var GRID_MARGIN = 10;
|
|
2023
|
+
var DRAG_HANDLE = "panel-drag-handle";
|
|
2024
|
+
var RGL_CSS = `
|
|
2025
|
+
.react-grid-layout { position: relative; transition: height 200ms ease; }
|
|
2026
|
+
.react-grid-item { transition: all 200ms ease; transition-property: left, top, width, height; box-sizing: border-box; }
|
|
2027
|
+
.react-grid-item.cssTransforms { transition-property: transform, width, height; }
|
|
2028
|
+
.react-grid-item.resizing { transition: none; z-index: 3; will-change: width, height; }
|
|
2029
|
+
.react-grid-item.react-draggable-dragging { transition: none; z-index: 3; will-change: transform; }
|
|
2030
|
+
.react-grid-item.react-grid-placeholder { background: rgba(99,102,241,0.18); border: 1px dashed #6366f1; border-radius: 2px; transition-duration: 100ms; z-index: 2; user-select: none; }
|
|
2031
|
+
.react-grid-item > .react-resizable-handle { position: absolute; width: 18px; height: 18px; bottom: 0; right: 0; cursor: se-resize; }
|
|
2032
|
+
.react-grid-item > .react-resizable-handle::after { content: ''; position: absolute; right: 4px; bottom: 4px; width: 6px; height: 6px; border-right: 2px solid rgba(148,163,184,0.7); border-bottom: 2px solid rgba(148,163,184,0.7); }
|
|
2033
|
+
.${DRAG_HANDLE} { cursor: grab; }
|
|
2034
|
+
.react-grid-item.react-draggable-dragging .${DRAG_HANDLE} { cursor: grabbing; }
|
|
2035
|
+
`;
|
|
2036
|
+
var rglCssInjected = false;
|
|
2037
|
+
function useInjectRglCss() {
|
|
2038
|
+
react.useEffect(() => {
|
|
2039
|
+
if (rglCssInjected || typeof document === "undefined") return;
|
|
2040
|
+
const el = document.createElement("style");
|
|
2041
|
+
el.setAttribute("data-rgl", "dashboard-renderer");
|
|
2042
|
+
el.textContent = RGL_CSS;
|
|
2043
|
+
document.head.appendChild(el);
|
|
2044
|
+
rglCssInjected = true;
|
|
2045
|
+
}, []);
|
|
2046
|
+
}
|
|
2047
|
+
var GridLayoutWithWidth = GridLayout.WidthProvider(GridLayout__default.default);
|
|
2048
|
+
function buildLayout(panels) {
|
|
2049
|
+
let cx = 0, cy = 0, rowH = 0;
|
|
2050
|
+
return panels.map((p) => {
|
|
2051
|
+
const w = Math.min(Math.max(p.width || 6, 1), GRID_COLS);
|
|
2052
|
+
const h = Math.max(p.height || 4, 1);
|
|
2053
|
+
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 };
|
|
2055
|
+
}
|
|
2056
|
+
if (cx + w > GRID_COLS) {
|
|
2057
|
+
cx = 0;
|
|
2058
|
+
cy += rowH;
|
|
2059
|
+
rowH = 0;
|
|
2060
|
+
}
|
|
2061
|
+
const item = { i: p.id, x: cx, y: cy, w, h, minW: 2, minH: 2 };
|
|
2062
|
+
cx += w;
|
|
2063
|
+
rowH = Math.max(rowH, h);
|
|
2064
|
+
return item;
|
|
2065
|
+
});
|
|
2066
|
+
}
|
|
2003
2067
|
function DashboardRenderer({ dashboard, records, columns }) {
|
|
2004
|
-
const { theme, removePanel } = useDashboard();
|
|
2005
|
-
const { canEditPanels } = useCapabilities();
|
|
2068
|
+
const { theme, removePanel, persistLayout } = useDashboard();
|
|
2069
|
+
const { canEditPanels, canEditLayout } = useCapabilities();
|
|
2070
|
+
useInjectRglCss();
|
|
2071
|
+
const panels = dashboard?.panels ?? [];
|
|
2072
|
+
const layout = react.useMemo(() => buildLayout(panels), [panels]);
|
|
2073
|
+
const onLayoutChange = react.useCallback((next) => {
|
|
2074
|
+
if (!persistLayout) return;
|
|
2075
|
+
persistLayout(next.map((l) => ({ id: l.i, x: l.x, y: l.y, w: l.w, h: l.h })));
|
|
2076
|
+
}, [persistLayout]);
|
|
2006
2077
|
if (!dashboard) return null;
|
|
2007
2078
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4 p-2", children: [
|
|
2008
2079
|
dashboard.insights && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `border ${theme.border} bg-midnight-elevated px-4 py-3 flex items-start gap-3`, children: [
|
|
2009
2080
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "w-5 h-5 text-midnight-accent shrink-0 mt-0.5" }),
|
|
2010
2081
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: `text-sm ${theme.text} leading-relaxed`, children: dashboard.insights })
|
|
2011
2082
|
] }),
|
|
2012
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2083
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2084
|
+
GridLayoutWithWidth,
|
|
2085
|
+
{
|
|
2086
|
+
className: "layout",
|
|
2087
|
+
layout,
|
|
2088
|
+
cols: GRID_COLS,
|
|
2089
|
+
rowHeight: ROW_HEIGHT,
|
|
2090
|
+
margin: [GRID_MARGIN, GRID_MARGIN],
|
|
2091
|
+
isDraggable: canEditLayout,
|
|
2092
|
+
isResizable: canEditLayout,
|
|
2093
|
+
draggableHandle: `.${DRAG_HANDLE}`,
|
|
2094
|
+
onDragStop: onLayoutChange,
|
|
2095
|
+
onResizeStop: onLayoutChange,
|
|
2096
|
+
compactType: canEditLayout ? "vertical" : null,
|
|
2097
|
+
children: panels.map((panel) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `border ${theme.border} bg-midnight-surface flex flex-col overflow-hidden`, children: [
|
|
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))
|
|
2124
|
+
}
|
|
2125
|
+
)
|
|
2053
2126
|
] });
|
|
2054
2127
|
}
|
|
2055
2128
|
function ProfileSummary({ profile, theme }) {
|