@burdenoff/microfe-bigconsole 2026.716.4 → 2026.717.1

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.
@@ -7,10 +7,10 @@ import { BigConsoleRoutes as o } from "./BigConsoleRoutes.js";
7
7
  import { BigConsoleProvider as s } from "./context/BigConsoleContext.js";
8
8
  import "./context/index.js";
9
9
  import { BigConsoleQuotaProvider as c } from "./providers/BigConsoleQuotaProvider.js";
10
- import l from "./components/preview/AiPreviewPanel.js";
11
- import u from "./components/DrilldownModal.js";
12
- import d from "./hooks/useFilterUrlSync.js";
13
- import f from "./components/DrilldownDashboardRenderer.js";
10
+ import l from "./hooks/useFilterUrlSync.js";
11
+ import u from "./components/DrilldownDashboardRenderer.js";
12
+ import d from "./components/preview/AiPreviewPanel.js";
13
+ import f from "./components/DrilldownModal.js";
14
14
  import { useCallback as p, useEffect as m, useLayoutEffect as h, useRef as g, useState as _ } from "react";
15
15
  import { useSearchParams as v } from "react-router-dom";
16
16
  import { ErrorBoundary as y } from "@burdenoff/fe-libs/shared/components";
@@ -157,7 +157,7 @@ var F = i, I = r, L = a, R = /* @__PURE__ */ new Set(), z = (r) => {
157
157
  r.productName
158
158
  ]);
159
159
  let [X, Z] = v(), Q = e((e) => e.isOpen), $ = e((e) => e.closeModal);
160
- d();
160
+ l();
161
161
  let te = p(() => {
162
162
  $();
163
163
  let e = new URLSearchParams(X);
@@ -174,7 +174,7 @@ var F = i, I = r, L = a, R = /* @__PURE__ */ new Set(), z = (r) => {
174
174
  return;
175
175
  }
176
176
  window.location.assign("/billing");
177
- }, [B]), re = p((e, t) => /* @__PURE__ */ E(f, {
177
+ }, [B]), re = p((e, t) => /* @__PURE__ */ E(u, {
178
178
  dashboardId: e,
179
179
  params: t
180
180
  }), []);
@@ -194,9 +194,9 @@ var F = i, I = r, L = a, R = /* @__PURE__ */ new Set(), z = (r) => {
194
194
  children: /* @__PURE__ */ E(n, {
195
195
  basePath: z,
196
196
  children: /* @__PURE__ */ D(t, { children: [
197
- /* @__PURE__ */ E(l, {}),
197
+ /* @__PURE__ */ E(d, {}),
198
198
  /* @__PURE__ */ E(o, { ...r }),
199
- Q && /* @__PURE__ */ E(u, {
199
+ Q && /* @__PURE__ */ E(f, {
200
200
  onClose: te,
201
201
  renderDashboard: re
202
202
  })
@@ -5,9 +5,9 @@ import { CrossFilterProvider as n } from "../../contexts/CrossFilterContext.js";
5
5
  import "../../contexts/index.js";
6
6
  import { useBigConsole as r } from "../../context/BigConsoleContext.js";
7
7
  import "../../context/index.js";
8
- import i from "../../hooks/useWidgetOperations.js";
9
- import { getWidgetDefinition as a } from "../widgets/WidgetRegistry.js";
10
- import o from "../../hooks/useWidgetCatalog.js";
8
+ import { getWidgetDefinition as i } from "../widgets/WidgetRegistry.js";
9
+ import a from "../../hooks/useWidgetCatalog.js";
10
+ import o from "../../hooks/useWidgetOperations.js";
11
11
  import s from "../../hooks/useDashboardImageExport.js";
12
12
  import { useInstalledWidgets as c } from "../../hooks/useInstalledWidgets.js";
13
13
  import l from "./DashboardGrid.js";
@@ -32,14 +32,14 @@ var v = f(function({ dashboardId: f, pageId: v, title: y, onPaste: le, onSave: u
32
32
  apiGatewayUrl: P,
33
33
  authToken: F,
34
34
  enabled: M
35
- }), { definitions: Ee } = o({
35
+ }), { definitions: Ee } = a({
36
36
  workspaceId: N,
37
37
  apiGatewayUrl: P,
38
38
  authToken: F,
39
39
  enabled: M
40
40
  }), I = t((e) => e.zoomLevel), L = t((e) => e.sidebarCollapsed), R = t((e) => e.toggleSidebar), z = !L, B = t((e) => e.setGlobalFilterValues), De = p((e) => {
41
41
  B(e);
42
- }, [B]), { createWidget: V } = i(v, f, { skipFetch: !0 }), H = e((e) => e.widgets), U = ce(() => {
42
+ }, [B]), { createWidget: V } = o(v, f, { skipFetch: !0 }), H = e((e) => e.widgets), U = ce(() => {
43
43
  let e = Array.from(H.values());
44
44
  return v ? e.filter((e) => e.pageId === v) : e;
45
45
  }, [H, v]), Oe = e((e) => e.selectedWidgetId), W = e((e) => e.selectWidget), G = e((e) => e.addWidget), K = e((e) => e.updateWidgetPosition), q = e((e) => e.configPanelOpen), ke = e((e) => e.closeConfigPanel);
@@ -68,14 +68,14 @@ var v = f(function({ dashboardId: f, pageId: v, title: y, onPaste: le, onSave: u
68
68
  W(e);
69
69
  }, [W]), Y = p(async (e, t) => {
70
70
  D(null);
71
- let n = t?.definition || (e.type ? a(e.type) : null), r = {
71
+ let n = t?.definition || (e.type ? i(e.type) : null), r = {
72
72
  width: n?.defaultSize?.width ?? 4,
73
73
  height: n?.defaultSize?.height ?? 4
74
- }, i;
75
- if (t?.position) i = t.position;
74
+ }, a;
75
+ if (t?.position) a = t.position;
76
76
  else {
77
77
  let { x: e, y: t } = oe(U, r, { cols: 12 });
78
- i = {
78
+ a = {
79
79
  x: e,
80
80
  y: t,
81
81
  width: r.width,
@@ -93,7 +93,7 @@ var v = f(function({ dashboardId: f, pageId: v, title: y, onPaste: le, onSave: u
93
93
  renderer: e.renderer,
94
94
  template: e.template,
95
95
  config: e.config || {},
96
- position: i,
96
+ position: a,
97
97
  refreshInterval: e.refreshInterval ?? void 0,
98
98
  dataSinkId: o.dataSinkId,
99
99
  parserId: o.parserId
@@ -116,11 +116,11 @@ var v = f(function({ dashboardId: f, pageId: v, title: y, onPaste: le, onSave: u
116
116
  template: e.template,
117
117
  refreshInterval: e.refreshInterval,
118
118
  config: e.config || {},
119
- position: i,
120
- positionX: i.x,
121
- positionY: i.y,
122
- positionWidth: i.width,
123
- positionHeight: i.height,
119
+ position: a,
120
+ positionX: a.x,
121
+ positionY: a.y,
122
+ positionWidth: a.width,
123
+ positionHeight: a.height,
124
124
  dataSinkId: o.dataSinkId,
125
125
  parserId: o.parserId,
126
126
  translations: [],
@@ -146,19 +146,19 @@ var v = f(function({ dashboardId: f, pageId: v, title: y, onPaste: le, onSave: u
146
146
  if (!t) return;
147
147
  let n = JSON.parse(t);
148
148
  if (!n || typeof n != "object" || !("type" in n)) return;
149
- let r = n, i = a(r.type), o = null;
149
+ let r = n, a = i(r.type), o = null;
150
150
  r.defaultConfig && r.category && (o = {
151
- ...i,
152
- name: r.name || i.name,
151
+ ...a,
152
+ name: r.name || a.name,
153
153
  category: r.category,
154
154
  defaultConfig: r.defaultConfig,
155
- defaultSize: r.defaultSize || i.defaultSize
155
+ defaultSize: r.defaultSize || a.defaultSize
156
156
  });
157
157
  let s = S.current?.getBoundingClientRect();
158
158
  if (!s) return;
159
159
  let c = {
160
- width: i.defaultSize.width,
161
- height: i.defaultSize.height
160
+ width: a.defaultSize.width,
161
+ height: a.defaultSize.height
162
162
  }, { x: l, y: u } = ae(e.clientX, e.clientY, s, w, c, { cols: 12 }), d = {
163
163
  x: l,
164
164
  y: u,
@@ -167,8 +167,8 @@ var v = f(function({ dashboardId: f, pageId: v, title: y, onPaste: le, onSave: u
167
167
  };
168
168
  Y({
169
169
  type: r.type,
170
- title: r.name || i.name,
171
- config: r.defaultConfig || i.defaultConfig
170
+ title: r.name || a.name,
171
+ config: r.defaultConfig || a.defaultConfig
172
172
  }, {
173
173
  position: d,
174
174
  definition: o
@@ -179,7 +179,7 @@ var v = f(function({ dashboardId: f, pageId: v, title: y, onPaste: le, onSave: u
179
179
  }, [w, Y]), Pe = p((e) => {
180
180
  e.preventDefault(), e.dataTransfer.dropEffect = "copy";
181
181
  }, []), Fe = p((e, t) => {
182
- let n = t || a(e);
182
+ let n = t || i(e);
183
183
  Y({
184
184
  type: e,
185
185
  title: n.name,
@@ -0,0 +1,116 @@
1
+ import e from "../datasink/DataSinkTableViewer.js";
2
+ import t from "../../hooks/useWidgetOperations.js";
3
+ import n from "../../hooks/useDataSinkOperations.js";
4
+ import r from "../../hooks/useParserOperations.js";
5
+ import i from "../widgets/WidgetWrapper.js";
6
+ import a from "../DrilldownDashboardRenderer.js";
7
+ import { useEffect as o, useRef as s, useState as c } from "react";
8
+ import { Spinner as l } from "@burdenoff/fe-libs/ui";
9
+ import { jsx as u, jsxs as d } from "react/jsx-runtime";
10
+ //#region src/bigconsole/components/preview/AiPreviewContent.tsx
11
+ var f = 4e3, p = 6e4;
12
+ function m({ label: e }) {
13
+ return /* @__PURE__ */ d("div", {
14
+ className: "flex items-center gap-2 px-1 py-8 text-sm text-text-muted",
15
+ children: [/* @__PURE__ */ u(l, { className: "size-4" }), e]
16
+ });
17
+ }
18
+ function h({ text: e }) {
19
+ return /* @__PURE__ */ u("p", {
20
+ className: "px-1 py-8 text-sm text-text-muted",
21
+ children: e
22
+ });
23
+ }
24
+ function g(e, t, n) {
25
+ let [r, i] = c(null), [a, l] = c(!0), u = s(e);
26
+ return u.current = e, o(() => {
27
+ if (!t) {
28
+ l(!1);
29
+ return;
30
+ }
31
+ let e = !1, r = Date.now(), a = async () => {
32
+ let t = await u.current();
33
+ e || (t != null && i(t), l(!1));
34
+ };
35
+ a();
36
+ let o = window.setInterval(() => {
37
+ !n || Date.now() - r > p || typeof document < "u" && document.visibilityState !== "visible" || a();
38
+ }, f);
39
+ return () => {
40
+ e = !0, window.clearInterval(o);
41
+ };
42
+ }, [t, n]), {
43
+ data: r,
44
+ loading: a
45
+ };
46
+ }
47
+ function _({ id: t, live: r }) {
48
+ let { getDataSinkData: i } = n({ skipFetch: !0 }), { data: a, loading: o } = g(async () => {
49
+ let e = await i({ id: t }, { limit: 50 });
50
+ return e ? e.raw : null;
51
+ }, t, r);
52
+ return t ? o ? /* @__PURE__ */ u(m, { label: "Loading the data sink’s data…" }) : /* @__PURE__ */ u("div", {
53
+ "data-testid": "ai-preview-content-datasink",
54
+ children: /* @__PURE__ */ u(e, {
55
+ data: a,
56
+ maxHeight: "300px"
57
+ })
58
+ }) : /* @__PURE__ */ u(h, { text: "Waiting for the data sink to be created…" });
59
+ }
60
+ function v({ dashboardId: e }) {
61
+ return e ? /* @__PURE__ */ u("div", {
62
+ "data-testid": "ai-preview-content-dashboard",
63
+ className: "max-h-[340px] overflow-y-auto",
64
+ children: /* @__PURE__ */ u(a, {
65
+ dashboardId: e,
66
+ params: {}
67
+ })
68
+ }) : /* @__PURE__ */ u(h, { text: "Waiting for the dashboard to be created…" });
69
+ }
70
+ function y({ parserId: t, live: n }) {
71
+ let { executeParser: i } = r({ skipFetch: !0 }), { data: a, loading: o } = g(async () => {
72
+ let e = await i(t ?? "");
73
+ return e ? e.output : null;
74
+ }, t, n);
75
+ return t ? o ? /* @__PURE__ */ u(m, { label: "Running the parser…" }) : /* @__PURE__ */ d("div", {
76
+ "data-testid": "ai-preview-content-parser",
77
+ children: [/* @__PURE__ */ u("p", {
78
+ className: "mb-2 px-1 text-xs text-text-muted",
79
+ children: "Parser output (transformed rows):"
80
+ }), /* @__PURE__ */ u(e, {
81
+ data: a,
82
+ maxHeight: "280px"
83
+ })]
84
+ }) : /* @__PURE__ */ u(h, { text: "No parser in this build — the rows were already shaped." });
85
+ }
86
+ function b(e) {
87
+ let t = e.toUpperCase();
88
+ return t.includes("METRIC") || t.includes("KPI") || t.includes("CARD") || t.includes("STAT") ? 160 : t.includes("TABLE") || t.includes("LIST") ? 280 : 320;
89
+ }
90
+ function x({ dashboardId: e, live: n }) {
91
+ let { widgets: r, loading: a, refetch: c } = t(void 0, e, { skipFetch: !e }), l = s(c);
92
+ return l.current = c, o(() => {
93
+ if (!e) return;
94
+ let t = Date.now(), r = window.setInterval(() => {
95
+ !n || Date.now() - t > p || typeof document < "u" && document.visibilityState !== "visible" || l.current();
96
+ }, f);
97
+ return () => window.clearInterval(r);
98
+ }, [e, n]), e ? a && r.length === 0 ? /* @__PURE__ */ u(m, { label: "Loading widgets…" }) : r.length === 0 ? /* @__PURE__ */ u(h, { text: "No widgets on this dashboard yet." }) : /* @__PURE__ */ u("div", {
99
+ "data-testid": "ai-preview-content-widget",
100
+ className: "space-y-3",
101
+ children: r.map((e) => /* @__PURE__ */ u("div", {
102
+ className: "overflow-hidden rounded-md border border-border-subtle bg-bg-surface",
103
+ style: { height: b(e.type) },
104
+ children: /* @__PURE__ */ u(i, {
105
+ widget: e,
106
+ isLoading: !1,
107
+ error: null,
108
+ filterValues: {}
109
+ })
110
+ }, e.id))
111
+ }) : /* @__PURE__ */ u(h, { text: "Waiting for the dashboard — widgets live on it." });
112
+ }
113
+ //#endregion
114
+ export { v as DashboardContent, _ as DataSinkContent, y as ParserContent, x as WidgetsContent };
115
+
116
+ //# sourceMappingURL=AiPreviewContent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AiPreviewContent.js","names":[],"sources":["../../../../src/bigconsole/components/preview/AiPreviewContent.tsx"],"sourcesContent":["/**\n * Live content renderers for the AI preview tabs.\n *\n * Each tab shows the REAL content of the entity the assistant just built —\n * the data sink's rows, the live dashboard, the parser's transformed output,\n * the rendered widget charts — not a list with an Open button. They reuse the\n * same components the real pages use (DataSinkTableViewer, DrilldownDashboard-\n * Renderer, WidgetWrapper) so what you see in the preview is what you get.\n *\n * These require Apollo + the BigConsole providers, which is why they live only\n * in the full AiPreviewPanel (mounted inside BigConsoleRoot), never in the\n * store-only app-shell mini panel.\n */\nimport { useEffect, useRef, useState } from 'react';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\n\nimport { DataSinkTableViewer } from '../datasink/DataSinkTableViewer';\nimport { DrilldownDashboardRenderer } from '../DrilldownDashboardRenderer';\nimport { WidgetWrapper } from '../widgets/WidgetWrapper';\nimport { useDataSinkOperations } from '../../hooks/useDataSinkOperations';\nimport { useParserOperations } from '../../hooks/useParserOperations';\nimport { useWidgetOperations } from '../../hooks/useWidgetOperations';\n\n/** While the build is live, re-pull content on this cadence so it fills in. */\nconst CONTENT_POLL_MS = 4000;\n/** Stop the live re-pull after this long even if the turn is still running. */\nconst CONTENT_POLL_WINDOW_MS = 60_000;\n\nfunction CenteredSpinner({ label }: { label: string }) {\n return (\n <div className=\"flex items-center gap-2 px-1 py-8 text-sm text-text-muted\">\n <Spinner className=\"size-4\" />\n {label}\n </div>\n );\n}\n\nfunction Waiting({ text }: { text: string }) {\n return <p className=\"px-1 py-8 text-sm text-text-muted\">{text}</p>;\n}\n\n/**\n * Fetch-on-mount, then re-fetch every CONTENT_POLL_MS while `live`, bounded to\n * CONTENT_POLL_WINDOW_MS. Returns { data, loading, done }. `fetcher` must be\n * stable-ish; we hold it in a ref so the effect keys only on `key`/`live`.\n */\nfunction useLiveContent<T>(fetcher: () => Promise<T | null>, key: string | undefined, live: boolean) {\n const [data, setData] = useState<T | null>(null);\n const [loading, setLoading] = useState(true);\n const fetcherRef = useRef(fetcher);\n fetcherRef.current = fetcher;\n\n useEffect(() => {\n if (!key) {\n setLoading(false);\n return;\n }\n let cancelled = false;\n const startedAt = Date.now();\n const pull = async () => {\n const result = await fetcherRef.current();\n if (cancelled) return;\n if (result !== null && result !== undefined) setData(result);\n setLoading(false);\n };\n void pull();\n const intervalId = window.setInterval(() => {\n if (!live || Date.now() - startedAt > CONTENT_POLL_WINDOW_MS) return;\n if (typeof document !== 'undefined' && document.visibilityState !== 'visible') return;\n void pull();\n }, CONTENT_POLL_MS);\n return () => {\n cancelled = true;\n window.clearInterval(intervalId);\n };\n }, [key, live]);\n\n return { data, loading };\n}\n\nexport function DataSinkContent({ id, live }: { id?: string; live: boolean }) {\n const { getDataSinkData } = useDataSinkOperations({ skipFetch: true });\n const { data, loading } = useLiveContent(\n async () => {\n const res = await getDataSinkData({ id }, { limit: 50 });\n return res ? res.raw : null;\n },\n id,\n live\n );\n\n if (!id) return <Waiting text=\"Waiting for the data sink to be created…\" />;\n if (loading) return <CenteredSpinner label=\"Loading the data sink’s data…\" />;\n return (\n <div data-testid=\"ai-preview-content-datasink\">\n <DataSinkTableViewer data={data} maxHeight=\"300px\" />\n </div>\n );\n}\n\nexport function DashboardContent({ dashboardId }: { dashboardId?: string }) {\n if (!dashboardId) return <Waiting text=\"Waiting for the dashboard to be created…\" />;\n return (\n <div data-testid=\"ai-preview-content-dashboard\" className=\"max-h-[340px] overflow-y-auto\">\n <DrilldownDashboardRenderer dashboardId={dashboardId} params={{}} />\n </div>\n );\n}\n\nexport function ParserContent({ parserId, live }: { parserId?: string; live: boolean }) {\n const { executeParser } = useParserOperations({ skipFetch: true });\n const { data, loading } = useLiveContent(\n async () => {\n const res = await executeParser(parserId ?? '');\n return res ? res.output : null;\n },\n parserId,\n live\n );\n\n if (!parserId) return <Waiting text=\"No parser in this build — the rows were already shaped.\" />;\n if (loading) return <CenteredSpinner label=\"Running the parser…\" />;\n return (\n <div data-testid=\"ai-preview-content-parser\">\n <p className=\"mb-2 px-1 text-xs text-text-muted\">Parser output (transformed rows):</p>\n <DataSinkTableViewer data={data} maxHeight=\"280px\" />\n </div>\n );\n}\n\n/** Recharts needs a definite pixel height or it renders 0px tall. */\nfunction widgetBoxHeight(type: string): number {\n const t = type.toUpperCase();\n if (t.includes('METRIC') || t.includes('KPI') || t.includes('CARD') || t.includes('STAT')) return 160;\n if (t.includes('TABLE') || t.includes('LIST')) return 280;\n return 320;\n}\n\nexport function WidgetsContent({ dashboardId, live }: { dashboardId?: string; live: boolean }) {\n const { widgets, loading, refetch } = useWidgetOperations(undefined, dashboardId, {\n skipFetch: !dashboardId,\n });\n\n const refetchRef = useRef(refetch);\n refetchRef.current = refetch;\n useEffect(() => {\n if (!dashboardId) return;\n const startedAt = Date.now();\n const intervalId = window.setInterval(() => {\n if (!live || Date.now() - startedAt > CONTENT_POLL_WINDOW_MS) return;\n if (typeof document !== 'undefined' && document.visibilityState !== 'visible') return;\n void refetchRef.current();\n }, CONTENT_POLL_MS);\n return () => window.clearInterval(intervalId);\n }, [dashboardId, live]);\n\n if (!dashboardId) return <Waiting text=\"Waiting for the dashboard — widgets live on it.\" />;\n if (loading && widgets.length === 0) return <CenteredSpinner label=\"Loading widgets…\" />;\n if (widgets.length === 0) return <Waiting text=\"No widgets on this dashboard yet.\" />;\n\n return (\n <div data-testid=\"ai-preview-content-widget\" className=\"space-y-3\">\n {widgets.map((widget) => (\n <div\n key={widget.id}\n className=\"overflow-hidden rounded-md border border-border-subtle bg-bg-surface\"\n style={{ height: widgetBoxHeight(widget.type) }}\n >\n <WidgetWrapper widget={widget} isLoading={false} error={null} filterValues={{}} />\n </div>\n ))}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,89 +1,45 @@
1
1
  import { useBigConsoleNavigate as e } from "../../context/BigConsoleContext.js";
2
2
  import "../../context/index.js";
3
3
  import { PREVIEW_STEPS as t, useAssistantRunStore as n } from "../../assistant/assistantRunStore.js";
4
- import r from "../../hooks/useDashboardOperations.js";
5
- import i from "../../hooks/useDataSinkOperations.js";
6
- import a from "../../hooks/useParserOperations.js";
7
- import o from "../../hooks/useWidgetOperations.js";
8
- import { EmptyOrLoading as s, StepRail as ee, formatAgo as c, useAssistantSidebarWidth as te } from "./previewShared.js";
9
- import { useEffect as l, useMemo as u, useRef as d, useState as f } from "react";
10
- import { Loader2 as p, Sparkles as m, X as h } from "lucide-react";
11
- import { Badge as g, Button as _, Tabs as ne, TabsContent as v, TabsList as y, TabsTrigger as b } from "@burdenoff/fe-libs/ui";
4
+ import { StepRail as r, formatAgo as i, useAssistantSidebarWidth as a } from "./previewShared.js";
5
+ import { DashboardContent as o, DataSinkContent as s, ParserContent as c, WidgetsContent as l } from "./AiPreviewContent.js";
6
+ import { useEffect as u, useState as d } from "react";
7
+ import { ArrowUpRight as f, Loader2 as p, Sparkles as m, X as h } from "lucide-react";
8
+ import { Button as g, Tabs as _, TabsContent as v, TabsList as y, TabsTrigger as b } from "@burdenoff/fe-libs/ui";
12
9
  import { jsx as x, jsxs as S } from "react/jsx-runtime";
13
10
  //#region src/bigconsole/components/preview/AiPreviewPanel.tsx
14
- var C = 3500, w = 3e4, T = "default";
15
- function E({ id: e, title: t, meta: n, isNew: r, onOpen: i }) {
11
+ function C({ label: e, onOpen: t }) {
16
12
  return /* @__PURE__ */ S("div", {
17
- "data-testid": "ai-preview-row",
18
- "data-entity-id": e,
19
- className: ["flex items-center justify-between gap-3 rounded-md border px-3 py-2", r ? "border-status-success-border bg-status-success-bg/30" : "border-border-subtle bg-bg-surface"].join(" "),
20
- children: [/* @__PURE__ */ S("div", {
21
- className: "min-w-0",
22
- children: [/* @__PURE__ */ x("p", {
23
- className: "truncate text-sm font-medium text-text-primary",
24
- children: t
25
- }), n ? /* @__PURE__ */ x("p", {
26
- className: "truncate text-xs text-text-muted",
27
- children: n
28
- }) : null]
29
- }), /* @__PURE__ */ S("div", {
30
- className: "flex shrink-0 items-center gap-2",
31
- children: [r ? /* @__PURE__ */ S(g, {
32
- className: "bg-status-success-bg text-status-success-text",
33
- children: [/* @__PURE__ */ x(m, { className: "mr-1 size-3" }), "just built"]
34
- }) : null, i ? /* @__PURE__ */ x(_, {
35
- size: "sm",
36
- variant: "ghost",
37
- onClick: i,
38
- children: "Open"
39
- }) : null]
40
- })]
13
+ className: "mb-2 flex items-center justify-between gap-2",
14
+ children: [/* @__PURE__ */ x("span", {
15
+ className: "text-xs font-semibold uppercase tracking-wide text-text-muted",
16
+ children: e
17
+ }), t ? /* @__PURE__ */ S(g, {
18
+ size: "sm",
19
+ variant: "outline",
20
+ onClick: t,
21
+ "data-testid": "ai-preview-open-entity",
22
+ children: ["Open", /* @__PURE__ */ x(f, { className: "ml-1 size-3.5" })]
23
+ }) : null]
41
24
  });
42
25
  }
43
- function D() {
44
- let g = e(), D = n((e) => e.isRunning), O = n((e) => e.previewOpen), k = n((e) => e.hasRun), A = n((e) => e.steps), j = n((e) => e.entityIds), M = n((e) => e.caption), N = n((e) => e.error), P = n((e) => e.updatedAt), F = n((e) => e.openPreview), I = n((e) => e.closePreview), L = n((e) => e.setRichMounted);
45
- l(() => (L(!0), () => L(!1)), [L]);
46
- let [R, z] = f("datasink"), [B, V] = f(() => Date.now()), H = j.dashboard, U = i({ skipFetch: !0 }), W = r(), G = a({
47
- consoleId: H ?? T,
48
- skipFetch: !0
49
- }), K = o(void 0, H, { skipFetch: !H }), q = d({
50
- sinks: U.refetch,
51
- dashboards: W.refetch,
52
- parsers: G.refetch,
53
- widgets: K.refetch
54
- });
55
- q.current = {
56
- sinks: U.refetch,
57
- dashboards: W.refetch,
58
- parsers: G.refetch,
59
- widgets: K.refetch
60
- }, l(() => {
61
- if (!k) return;
62
- let e = Infinity;
63
- D || (e = Date.now() + w);
64
- let t = () => {
65
- typeof document < "u" && document.visibilityState !== "visible" || Date.now() > e || (q.current.sinks(), q.current.dashboards(), H && (q.current.parsers(), q.current.widgets()), V(Date.now()));
66
- };
67
- t();
68
- let n = window.setInterval(t, C), r = () => {
69
- document.visibilityState === "visible" && t();
70
- };
71
- return document.addEventListener("visibilitychange", r), () => {
72
- window.clearInterval(n), document.removeEventListener("visibilitychange", r);
73
- };
74
- }, [
75
- k,
76
- D,
77
- H
78
- ]), l(() => {
79
- let e = t.find((e) => A[e] === "running");
80
- e && z(e);
81
- }, [A]);
82
- let J = P ? Math.max(0, Math.floor((B - P) / 1e3)) : 0, Y = te(), X = u(() => U.dataSinks.slice(0, 25), [U.dataSinks]), Z = u(() => W.dashboards.slice(0, 25), [W.dashboards]), Q = u(() => G.parsers.slice(0, 25), [G.parsers]), $ = u(() => K.widgets.slice(0, 25), [K.widgets]);
83
- return k ? O ? /* @__PURE__ */ S("section", {
26
+ function w() {
27
+ let f = e(), w = n((e) => e.isRunning), T = n((e) => e.previewOpen), E = n((e) => e.hasRun), D = n((e) => e.steps), O = n((e) => e.entityIds), k = n((e) => e.caption), A = n((e) => e.error), j = n((e) => e.updatedAt), M = n((e) => e.openPreview), N = n((e) => e.closePreview), P = n((e) => e.setRichMounted);
28
+ u(() => (P(!0), () => P(!1)), [P]);
29
+ let [F, I] = d("datasink"), [L, R] = d(() => Date.now()), z = O.dashboard;
30
+ u(() => {
31
+ if (!w) return;
32
+ let e = window.setInterval(() => R(Date.now()), 1e3);
33
+ return () => window.clearInterval(e);
34
+ }, [w]), u(() => {
35
+ let e = t.find((e) => D[e] === "running");
36
+ e && I(e);
37
+ }, [D]);
38
+ let B = j ? Math.max(0, Math.floor((L - j) / 1e3)) : 0, V = a();
39
+ return E ? T ? /* @__PURE__ */ S("section", {
84
40
  "data-testid": "ai-preview-panel",
85
41
  "aria-label": "AI preview",
86
- style: { marginRight: Y ? Y + 16 : void 0 },
42
+ style: { marginRight: V ? V + 16 : void 0 },
87
43
  className: "mx-4 mt-3 overflow-hidden rounded-lg border border-border-default bg-bg-sunken shadow-sm md:mx-6",
88
44
  children: [
89
45
  /* @__PURE__ */ S("div", {
@@ -96,7 +52,7 @@ function D() {
96
52
  className: "truncate text-sm font-semibold text-text-primary",
97
53
  children: "AI Preview"
98
54
  }),
99
- D ? /* @__PURE__ */ S("span", {
55
+ w ? /* @__PURE__ */ S("span", {
100
56
  className: "inline-flex items-center gap-1.5 rounded-full bg-status-success-bg px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-status-success-text",
101
57
  "data-testid": "ai-preview-live",
102
58
  children: [/* @__PURE__ */ S("span", {
@@ -108,17 +64,17 @@ function D() {
108
64
  className: "truncate text-xs text-text-muted",
109
65
  "data-testid": "ai-preview-ago",
110
66
  children: [
111
- D ? M || "Working…" : N ? "Stopped" : "Done",
67
+ w ? k || "Working…" : A ? "Stopped" : "Done",
112
68
  " · updated",
113
69
  " ",
114
- c(J)
70
+ i(B)
115
71
  ]
116
72
  })
117
73
  ]
118
- }), /* @__PURE__ */ x(_, {
74
+ }), /* @__PURE__ */ x(g, {
119
75
  size: "sm",
120
76
  variant: "ghost",
121
- onClick: I,
77
+ onClick: N,
122
78
  "aria-label": "Close preview",
123
79
  "data-testid": "ai-preview-close",
124
80
  children: /* @__PURE__ */ x(h, { className: "size-4" })
@@ -126,126 +82,101 @@ function D() {
126
82
  }),
127
83
  /* @__PURE__ */ x("div", {
128
84
  className: "border-b border-border-subtle px-3 py-2",
129
- children: /* @__PURE__ */ x(ee, { steps: A })
85
+ children: /* @__PURE__ */ x(r, { steps: D })
130
86
  }),
131
- /* @__PURE__ */ S(ne, {
132
- value: R,
133
- onValueChange: (e) => z(e),
87
+ /* @__PURE__ */ S(_, {
88
+ value: F,
89
+ onValueChange: (e) => I(e),
134
90
  children: [/* @__PURE__ */ S(y, {
135
91
  className: "mx-3 mt-2",
136
92
  children: [
137
93
  /* @__PURE__ */ x(b, {
138
94
  value: "datasink",
139
95
  "data-testid": "ai-preview-tab-datasink",
140
- children: "Data Sinks"
96
+ children: "Data Sink"
141
97
  }),
142
98
  /* @__PURE__ */ x(b, {
143
99
  value: "dashboard",
144
100
  "data-testid": "ai-preview-tab-dashboard",
145
- children: "Dashboards"
101
+ children: "Dashboard"
146
102
  }),
147
103
  /* @__PURE__ */ x(b, {
148
104
  value: "parser",
149
105
  "data-testid": "ai-preview-tab-parser",
150
- children: "Parsers"
106
+ children: "Parser"
151
107
  }),
152
108
  /* @__PURE__ */ x(b, {
153
109
  value: "widget",
154
110
  "data-testid": "ai-preview-tab-widget",
155
- children: "Widgets"
111
+ children: "Widget"
156
112
  })
157
113
  ]
158
114
  }), /* @__PURE__ */ S("div", {
159
- className: "max-h-[320px] overflow-y-auto p-3",
115
+ className: "max-h-[440px] overflow-y-auto p-3",
160
116
  children: [
161
- /* @__PURE__ */ x(v, {
117
+ /* @__PURE__ */ S(v, {
162
118
  value: "datasink",
163
- className: "space-y-2",
164
- children: X.length === 0 ? /* @__PURE__ */ x(s, {
165
- loading: U.loading,
166
- empty: "No data sinks yet."
167
- }) : X.map((e) => /* @__PURE__ */ x(E, {
168
- id: e.id,
169
- title: e.name ?? e.key,
170
- meta: e.status,
171
- isNew: e.id === j.datasink,
172
- onOpen: () => g(`/datasinks/${e.id}`)
173
- }, e.id))
119
+ children: [/* @__PURE__ */ x(C, {
120
+ label: "Data Sink",
121
+ onOpen: O.datasink ? () => f(`/datasinks/${O.datasink}`) : void 0
122
+ }), /* @__PURE__ */ x(s, {
123
+ id: O.datasink,
124
+ live: w
125
+ })]
174
126
  }),
175
- /* @__PURE__ */ x(v, {
127
+ /* @__PURE__ */ S(v, {
176
128
  value: "dashboard",
177
- className: "space-y-2",
178
- children: Z.length === 0 ? /* @__PURE__ */ x(s, {
179
- loading: W.loading,
180
- empty: "No dashboards yet."
181
- }) : Z.map((e) => /* @__PURE__ */ x(E, {
182
- id: e.id,
183
- title: e.name,
184
- meta: `${String(e.widgetCount ?? 0)} widget(s)`,
185
- isNew: e.id === j.dashboard,
186
- onOpen: () => g(`/dashboards/${e.id}`)
187
- }, e.id))
129
+ children: [/* @__PURE__ */ x(C, {
130
+ label: "Dashboard",
131
+ onOpen: O.dashboard ? () => f(`/dashboards/${O.dashboard}`) : void 0
132
+ }), /* @__PURE__ */ x(o, { dashboardId: O.dashboard })]
188
133
  }),
189
- /* @__PURE__ */ x(v, {
134
+ /* @__PURE__ */ S(v, {
190
135
  value: "parser",
191
- className: "space-y-2",
192
- children: H ? Q.length === 0 ? /* @__PURE__ */ x(s, {
193
- loading: G.loading,
194
- empty: "No parsers on this dashboard yet."
195
- }) : Q.map((e) => /* @__PURE__ */ x(E, {
196
- id: e.id,
197
- title: e.name,
198
- meta: `${e.type} · ${e.status}`,
199
- isNew: e.id === j.parser,
200
- onOpen: () => g(`/parsers/${e.id}`)
201
- }, e.id)) : /* @__PURE__ */ x("p", {
202
- className: "px-1 py-6 text-sm text-text-muted",
203
- children: "Parsers are listed per dashboard — waiting for the dashboard to be created."
204
- })
136
+ children: [/* @__PURE__ */ x(C, {
137
+ label: "Parser",
138
+ onOpen: O.parser ? () => f(`/parsers/${O.parser}`) : void 0
139
+ }), /* @__PURE__ */ x(c, {
140
+ parserId: O.parser,
141
+ live: w
142
+ })]
205
143
  }),
206
- /* @__PURE__ */ x(v, {
144
+ /* @__PURE__ */ S(v, {
207
145
  value: "widget",
208
- className: "space-y-2",
209
- children: H ? $.length === 0 ? /* @__PURE__ */ x(s, {
210
- loading: K.loading,
211
- empty: "No widgets on this dashboard yet."
212
- }) : $.map((e) => /* @__PURE__ */ x(E, {
213
- id: e.id,
214
- title: e.title,
215
- meta: e.type,
216
- isNew: e.id === $[$.length - 1]?.id && A.widget === "done",
217
- onOpen: () => g(`/dashboards/${H}`)
218
- }, e.id)) : /* @__PURE__ */ x("p", {
219
- className: "px-1 py-6 text-sm text-text-muted",
220
- children: "Widgets live on a dashboard — waiting for the dashboard to be created."
221
- })
146
+ children: [/* @__PURE__ */ x(C, {
147
+ label: "Widget",
148
+ onOpen: z ? () => f(`/dashboards/${z}`) : void 0
149
+ }), /* @__PURE__ */ x(l, {
150
+ dashboardId: z,
151
+ live: w
152
+ })]
222
153
  })
223
154
  ]
224
155
  })]
225
156
  }),
226
- N ? /* @__PURE__ */ x("p", {
157
+ A ? /* @__PURE__ */ x("p", {
227
158
  className: "border-t border-border-subtle px-3 py-2 text-xs text-status-error-text",
228
159
  "data-testid": "ai-preview-error",
229
- children: N
160
+ children: A
230
161
  }) : null
231
162
  ]
232
163
  }) : /* @__PURE__ */ x("div", {
233
164
  className: "flex justify-end px-4 pt-3 md:px-6",
234
- style: { marginRight: Y },
235
- children: /* @__PURE__ */ S(_, {
165
+ style: { marginRight: V },
166
+ children: /* @__PURE__ */ S(g, {
236
167
  size: "sm",
237
168
  variant: "outline",
238
- onClick: F,
169
+ onClick: M,
239
170
  "data-testid": "ai-preview-open",
240
171
  children: [
241
172
  /* @__PURE__ */ x(m, { className: "mr-1.5 size-4" }),
242
173
  "Preview",
243
- D ? /* @__PURE__ */ x(p, { className: "ml-1.5 size-3.5 animate-spin" }) : null
174
+ w ? /* @__PURE__ */ x(p, { className: "ml-1.5 size-3.5 animate-spin" }) : null
244
175
  ]
245
176
  })
246
177
  }) : null;
247
178
  }
248
179
  //#endregion
249
- export { D as default };
180
+ export { w as default };
250
181
 
251
182
  //# sourceMappingURL=AiPreviewPanel.js.map