@quantumwake/terminal-ux-dashboard-components 0.1.2 → 0.1.5
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 +93 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -2
- package/dist/index.d.ts +14 -2
- package/dist/index.js +95 -27
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -38,6 +38,7 @@ function useCapabilities() {
|
|
|
38
38
|
canDelete: !!c.deleteDashboard,
|
|
39
39
|
canAnalyze: !!c.analyzeDataset,
|
|
40
40
|
canRefine: !!c.refineDashboard,
|
|
41
|
+
canNew: !!c.newDashboard,
|
|
41
42
|
canAddPanel: !!c.addPanel,
|
|
42
43
|
canEditPanels: !!c.removePanel
|
|
43
44
|
};
|
|
@@ -648,18 +649,19 @@ var renderCell = (v) => {
|
|
|
648
649
|
if (typeof v === "boolean") return v ? "true" : "false";
|
|
649
650
|
return String(v);
|
|
650
651
|
};
|
|
651
|
-
function SqlConsole({ columns = [], stateId }) {
|
|
652
|
+
function SqlConsole({ columns = [], stateId, defaultColumnsOpen = false, defaultSql = DEFAULT_SQL, autoRun = false }) {
|
|
652
653
|
const { theme, runQuery } = useDashboard();
|
|
653
|
-
const [sql, setSql] = react.useState(
|
|
654
|
+
const [sql, setSql] = react.useState(defaultSql);
|
|
654
655
|
const [result, setResult] = react.useState(null);
|
|
655
656
|
const [error, setError] = react.useState(null);
|
|
656
657
|
const [running, setRunning] = react.useState(false);
|
|
657
|
-
const
|
|
658
|
-
|
|
658
|
+
const [columnsOpen, setColumnsOpen] = react.useState(defaultColumnsOpen);
|
|
659
|
+
const run = async (text = sql) => {
|
|
660
|
+
if (running || !text.trim()) return;
|
|
659
661
|
setRunning(true);
|
|
660
662
|
setError(null);
|
|
661
663
|
try {
|
|
662
|
-
const data = await runQuery(
|
|
664
|
+
const data = await runQuery(text, stateId);
|
|
663
665
|
setResult({ columns: data.columns || [], rows: data.rows || [] });
|
|
664
666
|
} catch (err) {
|
|
665
667
|
setResult(null);
|
|
@@ -668,6 +670,11 @@ function SqlConsole({ columns = [], stateId }) {
|
|
|
668
670
|
setRunning(false);
|
|
669
671
|
}
|
|
670
672
|
};
|
|
673
|
+
react.useEffect(() => {
|
|
674
|
+
if (!autoRun || !stateId) return;
|
|
675
|
+
setSql(defaultSql);
|
|
676
|
+
void run(defaultSql);
|
|
677
|
+
}, [stateId, autoRun, defaultSql]);
|
|
671
678
|
const onKeyDown = (e) => {
|
|
672
679
|
if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
|
|
673
680
|
e.preventDefault();
|
|
@@ -708,19 +715,34 @@ function SqlConsole({ columns = [], stateId }) {
|
|
|
708
715
|
placeholder: "SELECT ... FROM data"
|
|
709
716
|
}
|
|
710
717
|
),
|
|
711
|
-
columns.length > 0 && /* @__PURE__ */ jsxRuntime.
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
718
|
+
columns.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2", children: [
|
|
719
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
720
|
+
"button",
|
|
721
|
+
{
|
|
722
|
+
onClick: () => setColumnsOpen((o) => !o),
|
|
723
|
+
className: "flex items-center gap-1 text-[11px] font-mono text-midnight-text-muted hover:text-midnight-text-body transition-colors",
|
|
724
|
+
children: [
|
|
725
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: `w-3 h-3 transition-transform ${columnsOpen ? "" : "-rotate-90"}` }),
|
|
726
|
+
"Columns (",
|
|
727
|
+
columns.length,
|
|
728
|
+
")"
|
|
729
|
+
]
|
|
730
|
+
}
|
|
731
|
+
),
|
|
732
|
+
columnsOpen && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1.5 flex flex-wrap gap-1", children: columns.map((c) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
733
|
+
"button",
|
|
734
|
+
{
|
|
735
|
+
title: `Insert ${c.name}`,
|
|
736
|
+
onClick: () => setSql((s) => `${s}${s.endsWith(" ") || s.endsWith("\n") || !s ? "" : " "}${c.name}`),
|
|
737
|
+
className: "px-1.5 py-0.5 border border-midnight-border text-[11px] font-mono text-midnight-text-muted hover:bg-midnight-raised transition-colors",
|
|
738
|
+
children: [
|
|
739
|
+
c.name,
|
|
740
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-50 ml-1", children: c.type })
|
|
741
|
+
]
|
|
742
|
+
},
|
|
743
|
+
c.name
|
|
744
|
+
)) })
|
|
745
|
+
] })
|
|
724
746
|
] }),
|
|
725
747
|
(result || error) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex items-center gap-4 px-3 py-1.5 border-b ${theme.border} text-xs font-mono shrink-0 ${error ? "text-red-400" : "text-midnight-text-muted"}`, children: error ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1.5", children: [
|
|
726
748
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "w-3.5 h-3.5" }),
|
|
@@ -1611,6 +1633,11 @@ function ModeTab({ active, onClick, icon: Icon, label }) {
|
|
|
1611
1633
|
}
|
|
1612
1634
|
);
|
|
1613
1635
|
}
|
|
1636
|
+
var MODE_TABS = [
|
|
1637
|
+
{ mode: "dashboard", icon: lucideReact.Sparkles, label: "Dashboard" },
|
|
1638
|
+
{ mode: "builder", icon: lucideReact.BarChart3, label: "Chart Builder" },
|
|
1639
|
+
{ mode: "sql", icon: lucideReact.Terminal, label: "SQL" }
|
|
1640
|
+
];
|
|
1614
1641
|
function DataExplorer({
|
|
1615
1642
|
records,
|
|
1616
1643
|
columns,
|
|
@@ -1622,12 +1649,15 @@ function DataExplorer({
|
|
|
1622
1649
|
savedDashboards = [],
|
|
1623
1650
|
loading = false,
|
|
1624
1651
|
analyzing = false,
|
|
1652
|
+
defaultMode = "dashboard",
|
|
1653
|
+
tabs = ["dashboard", "builder", "sql"],
|
|
1625
1654
|
onSelectState,
|
|
1626
1655
|
onRefreshStates
|
|
1627
1656
|
}) {
|
|
1628
|
-
const { theme, addPanel, saveDashboard, listDashboards, searchDashboards, loadDashboard, deleteDashboard, analyzeDataset, refineDashboard } = useDashboard();
|
|
1657
|
+
const { theme, newDashboard, addPanel, saveDashboard, listDashboards, searchDashboards, loadDashboard, deleteDashboard, analyzeDataset, refineDashboard } = useDashboard();
|
|
1629
1658
|
const caps = useCapabilities();
|
|
1630
|
-
const
|
|
1659
|
+
const visibleTabs = MODE_TABS.filter((t) => tabs.includes(t.mode));
|
|
1660
|
+
const [mode, setMode] = react.useState(tabs.includes(defaultMode) ? defaultMode : tabs[0] ?? "sql");
|
|
1631
1661
|
const [fullscreen, setFullscreen] = react.useState(false);
|
|
1632
1662
|
const [showSaved, setShowSaved] = react.useState(false);
|
|
1633
1663
|
const [saveName, setSaveName] = react.useState("");
|
|
@@ -1692,9 +1722,22 @@ function DataExplorer({
|
|
|
1692
1722
|
)
|
|
1693
1723
|
] }),
|
|
1694
1724
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 mb-3 shrink-0", children: [
|
|
1695
|
-
/* @__PURE__ */ jsxRuntime.jsx(ModeTab, { active: mode ===
|
|
1696
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1697
|
-
|
|
1725
|
+
visibleTabs.map((t) => /* @__PURE__ */ jsxRuntime.jsx(ModeTab, { active: mode === t.mode, onClick: () => setMode(t.mode), icon: t.icon, label: t.label }, t.mode)),
|
|
1726
|
+
caps.canNew && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1727
|
+
"button",
|
|
1728
|
+
{
|
|
1729
|
+
onClick: () => {
|
|
1730
|
+
newDashboard?.();
|
|
1731
|
+
setMode("builder");
|
|
1732
|
+
},
|
|
1733
|
+
title: "Start a new dashboard",
|
|
1734
|
+
className: "flex items-center gap-1 px-2 py-1 text-xs font-mono border border-midnight-border text-midnight-text-muted hover:bg-midnight-raised hover:text-midnight-accent transition-colors",
|
|
1735
|
+
children: [
|
|
1736
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "w-3.5 h-3.5" }),
|
|
1737
|
+
" New Dashboard"
|
|
1738
|
+
]
|
|
1739
|
+
}
|
|
1740
|
+
),
|
|
1698
1741
|
showPersistence && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 ml-auto", children: [
|
|
1699
1742
|
caps.canSave && showSaveInput && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1700
1743
|
"input",
|
|
@@ -1763,14 +1806,39 @@ function DataExplorer({
|
|
|
1763
1806
|
)
|
|
1764
1807
|
] }, d.id))
|
|
1765
1808
|
] }),
|
|
1766
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `border ${theme.border} bg-midnight-surface flex-1 flex flex-col min-h-0`, children: mode === "sql" ? /* @__PURE__ */ jsxRuntime.jsx(SqlConsole, { columns, stateId: activeStateId ?? void 0 }) : mode === "builder" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1809
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `border ${theme.border} bg-midnight-surface flex-1 flex flex-col min-h-0`, children: mode === "sql" ? /* @__PURE__ */ jsxRuntime.jsx(SqlConsole, { columns, stateId: activeStateId ?? void 0 }) : mode === "builder" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1810
|
+
ChartBuilder,
|
|
1811
|
+
{
|
|
1812
|
+
records,
|
|
1813
|
+
columns,
|
|
1814
|
+
stateId: activeStateId ?? void 0,
|
|
1815
|
+
onSave: addPanel ? (panel) => {
|
|
1816
|
+
addPanel(panel);
|
|
1817
|
+
setMode("dashboard");
|
|
1818
|
+
} : void 0
|
|
1819
|
+
}
|
|
1820
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1767
1821
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0 overflow-auto", children: dashboard ? /* @__PURE__ */ jsxRuntime.jsx(DashboardRenderer, { dashboard, records, columns }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center h-full gap-4 text-midnight-text-muted", children: [
|
|
1768
1822
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "w-8 h-8" }),
|
|
1769
1823
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm", children: caps.canAnalyze ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1770
1824
|
"Click ",
|
|
1771
1825
|
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: "Auto-Analyze" }),
|
|
1772
1826
|
" to generate an AI dashboard"
|
|
1773
|
-
] }) : "No dashboard to display" })
|
|
1827
|
+
] }) : caps.canNew ? "Start a new dashboard, then add charts from the Chart Builder" : "No dashboard to display" }),
|
|
1828
|
+
caps.canNew && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1829
|
+
"button",
|
|
1830
|
+
{
|
|
1831
|
+
onClick: () => {
|
|
1832
|
+
newDashboard?.();
|
|
1833
|
+
setMode("builder");
|
|
1834
|
+
},
|
|
1835
|
+
className: "flex items-center gap-1.5 px-3 py-1.5 text-xs font-mono border border-midnight-accent text-midnight-accent hover:bg-midnight-accent/10 transition-colors",
|
|
1836
|
+
children: [
|
|
1837
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "w-4 h-4" }),
|
|
1838
|
+
" Create Dashboard"
|
|
1839
|
+
]
|
|
1840
|
+
}
|
|
1841
|
+
)
|
|
1774
1842
|
] }) }),
|
|
1775
1843
|
dashboard && caps.canRefine && refineDashboard && /* @__PURE__ */ jsxRuntime.jsx(ChatInput, { onSend: refineDashboard, loading: analyzing, theme })
|
|
1776
1844
|
] }) })
|