@burdenoff/microfe-bigconsole 2026.617.1 → 2026.622.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.
@@ -0,0 +1,87 @@
1
+ import { memo as e, useEffect as t, useMemo as n, useState as r } from "react";
2
+ import { jsx as i, jsxs as a } from "react/jsx-runtime";
3
+ //#region src/bigconsole/components/dashboard/LiveBoardBanner.tsx
4
+ function o(e) {
5
+ let t = null;
6
+ for (let n of e) {
7
+ let e = n.refreshInterval;
8
+ typeof e == "number" && e > 0 && (t = t === null ? e : Math.min(t, e));
9
+ }
10
+ return t;
11
+ }
12
+ function s(e) {
13
+ if (e <= 0) return "just now";
14
+ if (e < 60) return `${e}s ago`;
15
+ let t = Math.floor(e / 60), n = e % 60;
16
+ return n === 0 ? `${t}m ago` : `${t}m ${n}s ago`;
17
+ }
18
+ var c = e(function({ widgets: e, isEditMode: c = !1 }) {
19
+ let l = n(() => o(e), [e]), [u, d] = r(() => Date.now()), [f, p] = r(0);
20
+ if (t(() => {
21
+ if (c || !l) return;
22
+ d(Date.now()), p(0);
23
+ let e = setInterval(() => {
24
+ p((e) => {
25
+ let t = e + 1;
26
+ return t >= l ? (d(Date.now()), 0) : t;
27
+ });
28
+ }, 1e3);
29
+ return () => clearInterval(e);
30
+ }, [
31
+ c,
32
+ l,
33
+ e.length
34
+ ]), c || !l) return null;
35
+ let m = new Date(u).toLocaleTimeString([], {
36
+ hour: "2-digit",
37
+ minute: "2-digit",
38
+ second: "2-digit"
39
+ });
40
+ return /* @__PURE__ */ a("div", {
41
+ className: "flex items-center justify-between gap-3 px-4 py-1.5 border-b border-border-default bg-status-success-bg flex-shrink-0",
42
+ role: "status",
43
+ "aria-live": "polite",
44
+ "data-testid": "live-board-banner",
45
+ children: [/* @__PURE__ */ a("div", {
46
+ className: "flex items-center gap-2 min-w-0",
47
+ children: [
48
+ /* @__PURE__ */ a("span", {
49
+ className: "relative flex h-2.5 w-2.5 flex-shrink-0",
50
+ "aria-hidden": "true",
51
+ children: [/* @__PURE__ */ i("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-status-success-text opacity-60" }), /* @__PURE__ */ i("span", { className: "relative inline-flex rounded-full h-2.5 w-2.5 bg-status-success-text" })]
52
+ }),
53
+ /* @__PURE__ */ i("span", {
54
+ className: "text-xs font-semibold uppercase tracking-wide text-status-success-text",
55
+ children: "Live"
56
+ }),
57
+ /* @__PURE__ */ a("span", {
58
+ className: "text-xs text-text-secondary truncate",
59
+ children: [
60
+ "Auto-refreshing every ",
61
+ l,
62
+ "s — no reload needed"
63
+ ]
64
+ })
65
+ ]
66
+ }), /* @__PURE__ */ a("div", {
67
+ className: "flex items-center gap-1.5 flex-shrink-0",
68
+ children: [/* @__PURE__ */ a("span", {
69
+ className: "text-xs text-text-tertiary",
70
+ "data-testid": "live-board-asof",
71
+ children: ["As of ", m]
72
+ }), /* @__PURE__ */ a("span", {
73
+ className: "text-xs text-text-tertiary tabular-nums",
74
+ "data-testid": "live-board-ago",
75
+ children: [
76
+ "(updated ",
77
+ s(f),
78
+ ")"
79
+ ]
80
+ })]
81
+ })]
82
+ });
83
+ });
84
+ //#endregion
85
+ export { c as default };
86
+
87
+ //# sourceMappingURL=LiveBoardBanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LiveBoardBanner.js","names":[],"sources":["../../../../src/bigconsole/components/dashboard/LiveBoardBanner.tsx"],"sourcesContent":["/**\n * LiveBoardBanner\n *\n * Wall-display \"live\" freshness indicator for auto-refreshing boards\n * (BC-PFC-07 — Live Bed Board). It surfaces, to the operator standing in front\n * of a wall display, that the board is updating itself on a fixed cadence and\n * how stale the data on screen is right now.\n *\n * WHY THIS EXISTS (and why it is polling, not a WebSocket subscription):\n * The Live Bed Board spec wants push-based GraphQL subscriptions\n * (`dataSinkDataUpdated` / `dataSinkUpdated`) with a MANDATORY 30s poll\n * fallback for transports that lack a WebSocket upgrade. In this deployment\n * the subscription transport is genuinely absent — the backend GraphQL server\n * (`@burdenoff/be-sdk` createServer) is HTTP-only with no graphql-ws transport\n * or PubSub, and the two sink subscriptions are declared in the SDL but have\n * no resolvers. So the board runs on the spec's own fallback path: each data\n * widget carries `refreshInterval` (30s on the Live Bed Board), which\n * `useWidgetData` turns into an Apollo `pollInterval`. This banner makes that\n * cadence visible and ticks an \"updated …s ago\" clock between polls.\n *\n * It is intentionally generic: it lights up for ANY board whose visible widgets\n * declare a refresh interval (not just the bed board), and stays hidden in edit\n * mode and on static boards. Semantic status tokens only — no raw colors — so\n * it themes correctly on light / dark / high-contrast wall displays.\n */\n\nimport { type FC, memo, useEffect, useMemo, useState } from 'react';\nimport type { Widget } from '../../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface LiveBoardBannerProps {\n /** Widgets currently rendered on the active page */\n widgets: Widget[];\n /** Hide the banner while the dashboard is being edited */\n isEditMode?: boolean;\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * The board's live cadence is the SHORTEST positive refreshInterval among the\n * visible widgets (in seconds). A board with no refreshing widget is static and\n * the banner does not render.\n */\nfunction deriveRefreshSeconds(widgets: Widget[]): number | null {\n let min: number | null = null;\n for (const w of widgets) {\n const interval = (w as { refreshInterval?: number | null }).refreshInterval;\n if (typeof interval === 'number' && interval > 0) {\n min = min === null ? interval : Math.min(min, interval);\n }\n }\n return min;\n}\n\nfunction formatAgo(seconds: number): string {\n if (seconds <= 0) return 'just now';\n if (seconds < 60) return `${seconds}s ago`;\n const mins = Math.floor(seconds / 60);\n const rem = seconds % 60;\n return rem === 0 ? `${mins}m ago` : `${mins}m ${rem}s ago`;\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const LiveBoardBanner: FC<LiveBoardBannerProps> = memo(function LiveBoardBanner({\n widgets,\n isEditMode = false,\n}) {\n const refreshSeconds = useMemo(() => deriveRefreshSeconds(widgets), [widgets]);\n\n // Anchor each refresh cycle. We cannot observe each widget's individual poll\n // completion from here, but every widget on the board shares the same cadence,\n // so we model the board's \"as of\" clock as a cycle anchored to mount and\n // advanced every `refreshSeconds`. This keeps the displayed freshness honest\n // (it never claims to be fresher than the poll cadence allows).\n const [lastRefreshAt, setLastRefreshAt] = useState<number>(() => Date.now());\n const [agoSeconds, setAgoSeconds] = useState(0);\n\n useEffect(() => {\n if (isEditMode || !refreshSeconds) return;\n // Reset the cycle whenever the cadence or the widget set changes.\n setLastRefreshAt(Date.now());\n setAgoSeconds(0);\n\n const tick = setInterval(() => {\n setAgoSeconds((prev) => {\n const next = prev + 1;\n if (next >= refreshSeconds) {\n // A poll cycle completed — the widgets have just re-fetched.\n setLastRefreshAt(Date.now());\n return 0;\n }\n return next;\n });\n }, 1000);\n\n return () => clearInterval(tick);\n }, [isEditMode, refreshSeconds, widgets.length]);\n\n if (isEditMode || !refreshSeconds) return null;\n\n const asOf = new Date(lastRefreshAt).toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n });\n\n return (\n <div\n className=\"flex items-center justify-between gap-3 px-4 py-1.5 border-b border-border-default bg-status-success-bg flex-shrink-0\"\n role=\"status\"\n aria-live=\"polite\"\n data-testid=\"live-board-banner\"\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n <span className=\"relative flex h-2.5 w-2.5 flex-shrink-0\" aria-hidden=\"true\">\n <span className=\"animate-ping absolute inline-flex h-full w-full rounded-full bg-status-success-text opacity-60\" />\n <span className=\"relative inline-flex rounded-full h-2.5 w-2.5 bg-status-success-text\" />\n </span>\n <span className=\"text-xs font-semibold uppercase tracking-wide text-status-success-text\">Live</span>\n <span className=\"text-xs text-text-secondary truncate\">\n Auto-refreshing every {refreshSeconds}s — no reload needed\n </span>\n </div>\n <div className=\"flex items-center gap-1.5 flex-shrink-0\">\n <span className=\"text-xs text-text-tertiary\" data-testid=\"live-board-asof\">\n As of {asOf}\n </span>\n <span className=\"text-xs text-text-tertiary tabular-nums\" data-testid=\"live-board-ago\">\n (updated {formatAgo(agoSeconds)})\n </span>\n </div>\n </div>\n );\n});\n\nexport default LiveBoardBanner;\n"],"mappings":";;;AAiDA,SAAS,EAAqB,GAAkC;CAC9D,IAAI,IAAqB;AACzB,MAAK,IAAM,KAAK,GAAS;EACvB,IAAM,IAAY,EAA0C;AAC5D,EAAI,OAAO,KAAa,YAAY,IAAW,MAC7C,IAAM,MAAQ,OAAO,IAAW,KAAK,IAAI,GAAK,EAAS;;AAG3D,QAAO;;AAGT,SAAS,EAAU,GAAyB;AAC1C,KAAI,KAAW,EAAG,QAAO;AACzB,KAAI,IAAU,GAAI,QAAO,GAAG,EAAQ;CACpC,IAAM,IAAO,KAAK,MAAM,IAAU,GAAG,EAC/B,IAAM,IAAU;AACtB,QAAO,MAAQ,IAAI,GAAG,EAAK,SAAS,GAAG,EAAK,IAAI,EAAI;;AAOtD,IAAa,IAA4C,EAAK,SAAyB,EACrF,YACA,gBAAa,MACZ;CACD,IAAM,IAAiB,QAAc,EAAqB,EAAQ,EAAE,CAAC,EAAQ,CAAC,EAOxE,CAAC,GAAe,KAAoB,QAAuB,KAAK,KAAK,CAAC,EACtE,CAAC,GAAY,KAAiB,EAAS,EAAE;AAuB/C,KArBA,QAAgB;AACd,MAAI,KAAc,CAAC,EAAgB;AAGnC,EADA,EAAiB,KAAK,KAAK,CAAC,EAC5B,EAAc,EAAE;EAEhB,IAAM,IAAO,kBAAkB;AAC7B,MAAe,MAAS;IACtB,IAAM,IAAO,IAAO;AAMpB,WALI,KAAQ,KAEV,EAAiB,KAAK,KAAK,CAAC,EACrB,KAEF;KACP;KACD,IAAK;AAER,eAAa,cAAc,EAAK;IAC/B;EAAC;EAAY;EAAgB,EAAQ;EAAO,CAAC,EAE5C,KAAc,CAAC,EAAgB,QAAO;CAE1C,IAAM,IAAO,IAAI,KAAK,EAAc,CAAC,mBAAmB,EAAE,EAAE;EAC1D,MAAM;EACN,QAAQ;EACR,QAAQ;EACT,CAAC;AAEF,QACE,kBAAC,OAAD;EACE,WAAU;EACV,MAAK;EACL,aAAU;EACV,eAAY;YAJd,CAME,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,QAAD;KAAM,WAAU;KAA0C,eAAY;eAAtE,CACE,kBAAC,QAAD,EAAM,WAAU,kGAAmG,CAAA,EACnH,kBAAC,QAAD,EAAM,WAAU,wEAAyE,CAAA,CACpF;;IACP,kBAAC,QAAD;KAAM,WAAU;eAAyE;KAAW,CAAA;IACpG,kBAAC,QAAD;KAAM,WAAU;eAAhB;MAAuD;MAC9B;MAAe;MACjC;;IACH;MACN,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,QAAD;IAAM,WAAU;IAA6B,eAAY;cAAzD,CAA2E,UAClE,EACF;OACP,kBAAC,QAAD;IAAM,WAAU;IAA0C,eAAY;cAAtE;KAAuF;KAC3E,EAAU,EAAW;KAAC;KAC3B;MACH;KACF;;EAER"}
@@ -6,6 +6,7 @@ import "./GlobalFiltersBar/FilterChip.js";
6
6
  import "./GlobalFiltersBar/FilterEditor.js";
7
7
  import "./GlobalFiltersBar/GlobalFiltersBar.js";
8
8
  import "./GlobalFiltersBar/index.js";
9
+ import "./LiveBoardBanner.js";
9
10
  import "./PageTabsManager/PageTabsManager.js";
10
11
  import "./PageTabsManager/index.js";
11
12
  import "./ShareDialog/ShareDialog.js";
@@ -20,7 +20,7 @@ import "./widget-actions/index.js";
20
20
  import { Suspense as l, lazy as u, memo as d, useCallback as f, useEffect as fe, useMemo as p, useRef as m, useState as h } from "react";
21
21
  import { jsx as g, jsxs as pe } from "react/jsx-runtime";
22
22
  //#region src/bigconsole/components/widgets/WidgetWrapper.tsx
23
- var me = u(() => import("./metric-card/index.js").then((e) => ({ default: e.MetricCardWidget }))), he = u(() => import("./chart/index.js").then((e) => ({ default: e.ChartWidget }))), ge = u(() => import("./table/index.js").then((e) => ({ default: e.TableWidget }))), _e = u(() => import("./pivot-table/index.js").then((e) => ({ default: e.PivotTableWidget }))), ve = u(() => import("./gauge/index.js").then((e) => ({ default: e.GaugeWidget }))), ye = u(() => import("./progress/index.js").then((e) => ({ default: e.ProgressWidget }))), be = u(() => import("./list/index.js").then((e) => ({ default: e.ListWidget }))), xe = u(() => import("./heatmap/index.js").then((e) => ({ default: e.HeatmapWidget }))), Se = u(() => import("./calendar/index.js").then((e) => ({ default: e.CalendarWidget }))), Ce = u(() => import("./kanban/index.js").then((e) => ({ default: e.KanbanWidget }))), we = u(() => import("./timeline/index.js").then((e) => ({ default: e.TimelineWidget }))), Te = u(() => import("./kpi-comparison/index.js").then((e) => ({ default: e.KPIComparisonWidget }))), Ee = u(() => import("./text-widget/index.js").then((e) => ({ default: e.TextWidget }))), De = u(() => import("./map-widget/index.js").then((e) => ({ default: e.MapWidget }))), Oe = u(() => import("./iframe-widget/index.js").then((e) => ({ default: e.IframeWidget }))), ke = u(() => import("./custom/index.js").then((e) => ({ default: e.CustomWidget }))), Ae = u(() => import("./adaptive-card/index.js").then((e) => ({ default: e.AdaptiveCardWidget }))), je = u(() => import("./comments/WidgetComments.js").then((e) => ({ default: e.WidgetComments })));
23
+ var me = u(() => import("./metric-card/index.js").then((e) => ({ default: e.MetricCardWidget }))), he = u(() => import("./chart/index.js").then((e) => ({ default: e.ChartWidget }))), ge = u(() => import("./table/index.js").then((e) => ({ default: e.TableWidget }))), _e = u(() => import("./pivot-table/index.js").then((e) => ({ default: e.PivotTableWidget }))), ve = u(() => import("./gauge/index.js").then((e) => ({ default: e.GaugeWidget }))), ye = u(() => import("./progress/index.js").then((e) => ({ default: e.ProgressWidget }))), be = u(() => import("./list/index.js").then((e) => ({ default: e.ListWidget }))), xe = u(() => import("./heatmap/index.js").then((e) => ({ default: e.HeatmapWidget }))), Se = u(() => import("./retention/index.js").then((e) => ({ default: e.RetentionWidget }))), Ce = u(() => import("./calendar/index.js").then((e) => ({ default: e.CalendarWidget }))), we = u(() => import("./kanban/index.js").then((e) => ({ default: e.KanbanWidget }))), Te = u(() => import("./timeline/index.js").then((e) => ({ default: e.TimelineWidget }))), Ee = u(() => import("./kpi-comparison/index.js").then((e) => ({ default: e.KPIComparisonWidget }))), De = u(() => import("./text-widget/index.js").then((e) => ({ default: e.TextWidget }))), Oe = u(() => import("./map-widget/index.js").then((e) => ({ default: e.MapWidget }))), ke = u(() => import("./iframe-widget/index.js").then((e) => ({ default: e.IframeWidget }))), Ae = u(() => import("./custom/index.js").then((e) => ({ default: e.CustomWidget }))), je = u(() => import("./adaptive-card/index.js").then((e) => ({ default: e.AdaptiveCardWidget }))), Me = u(() => import("./comments/WidgetComments.js").then((e) => ({ default: e.WidgetComments })));
24
24
  function _(e, t) {
25
25
  if (e.widget.id !== t.widget.id || e.widget.updatedAt !== t.widget.updatedAt || e.isLoading !== t.isLoading || e.error !== t.error || (e.actions?.length ?? 0) !== (t.actions?.length ?? 0)) return !1;
26
26
  if (e.actions && t.actions) {
@@ -28,9 +28,9 @@ function _(e, t) {
28
28
  }
29
29
  return !(e.data !== t.data || JSON.stringify(e.filterValues) !== JSON.stringify(t.filterValues));
30
30
  }
31
- var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoading: Me, error: Ne, onRefresh: y, onDrilldown: Pe, actions: b, onAction: x, filterValues: S }) {
32
- let C = r((e) => e.viewMode === "edit"), w = t((e) => e.selectWidget), T = e(u.id), E = n(u.id), D = i(), Fe = !!u.dataSinkId || !!u.datasetId || !!u.parserId, { data: O, loading: Ie } = a(u.id, {
33
- skip: !Fe,
31
+ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoading: Ne, error: Pe, onRefresh: y, onDrilldown: Fe, actions: b, onAction: x, filterValues: S }) {
32
+ let C = r((e) => e.viewMode === "edit"), w = t((e) => e.selectWidget), T = e(u.id), E = n(u.id), D = i(), Ie = !!u.dataSinkId || !!u.datasetId || !!u.parserId, { data: O, loading: Le } = a(u.id, {
33
+ skip: !Ie,
34
34
  pollInterval: (u.refreshInterval ?? 0) * 1e3 || 0
35
35
  }), k = p(() => {
36
36
  if (typeof window > "u") return {};
@@ -48,21 +48,21 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
48
48
  k,
49
49
  D,
50
50
  S
51
- ]), j = Object.keys(A).length > 0, M = Me ?? (Ie && !O) ?? E.isLoading, N = Ne ?? E.errorMessage, Le = o(u.type), P = m(y);
51
+ ]), j = Object.keys(A).length > 0, M = Ne ?? (Le && !O) ?? E.isLoading, N = Pe ?? E.errorMessage, Re = o(u.type), P = m(y);
52
52
  fe(() => {
53
53
  P.current = y;
54
54
  }, [y]);
55
55
  let F = f(async () => {
56
56
  P.current && await P.current();
57
- }, []), { timeUntilRefresh: Re, isPaused: ze } = te({
57
+ }, []), { timeUntilRefresh: ze, isPaused: Be } = te({
58
58
  widgetId: u.id,
59
59
  refreshInterval: u.refreshInterval,
60
60
  onRefresh: F,
61
61
  enabled: !C && !!u.refreshInterval
62
- }), I = m(null), [L, R] = h(!1), [z, Be] = h(!1), { count: Ve } = ne(u.id, z), He = f(() => {
62
+ }), I = m(null), [L, R] = h(!1), [z, Ve] = h(!1), { count: He } = ne(u.id, z), Ue = f(() => {
63
63
  R((e) => {
64
64
  let t = !e;
65
- return t && Be(!0), t;
65
+ return t && Ve(!0), t;
66
66
  });
67
67
  }, []), B = p(() => {
68
68
  if (_ && Array.isArray(_)) return _;
@@ -73,7 +73,7 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
73
73
  if (Array.isArray(t)) return t;
74
74
  }
75
75
  return null;
76
- }, [_, u]), { exportCSV: Ue, exportPNG: We } = re(u, {
76
+ }, [_, u]), { exportCSV: We, exportPNG: Ge } = re(u, {
77
77
  data: B,
78
78
  containerRef: I
79
79
  }), V = f((e) => {
@@ -121,6 +121,7 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
121
121
  if (i) return e[i];
122
122
  }
123
123
  }, a = (e) => e.filter((e) => {
124
+ if (typeof e != "object" || !e || Array.isArray(e)) return !0;
124
125
  for (let [n, a] of Object.entries(t)) {
125
126
  if (a == null || a === "") continue;
126
127
  let t = i(e, n);
@@ -168,7 +169,7 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
168
169
  }
169
170
  }
170
171
  }
171
- if (!n) return !1;
172
+ if (!n) continue;
172
173
  }
173
174
  }
174
175
  return !0;
@@ -236,6 +237,13 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
236
237
  V(n) && (e = n);
237
238
  } catch {}
238
239
  }
240
+ if (e && typeof e == "object" && !Array.isArray(e)) {
241
+ let t = u.config, n = t?.dataKey ?? t?.dataPath ?? t?.seriesPath;
242
+ if (n && typeof n == "string") {
243
+ let t = n.split(".").reduce((e, t) => e && typeof e == "object" ? e[t] : void 0, e);
244
+ t != null && V(t) && (e = t);
245
+ }
246
+ }
239
247
  return j && e ? H(e) : e;
240
248
  }, [
241
249
  _,
@@ -246,7 +254,7 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
246
254
  A,
247
255
  V
248
256
  ]), W = p(() => U ?? null, [U]), { executeDrilldown: G, canDrilldown: K } = ie({ onDrilldown: (e, t) => {
249
- Pe?.(e);
257
+ Fe?.(e);
250
258
  } }), q = p(() => K(u), [u, K]), J = f((e) => {
251
259
  if (!u.drilldown?.enabled) return;
252
260
  let t = {
@@ -266,12 +274,12 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
266
274
  W,
267
275
  D,
268
276
  G
269
- ]), Y = m(null), Ge = f((e) => {
277
+ ]), Y = m(null), Ke = f((e) => {
270
278
  Y.current = {
271
279
  x: e.clientX,
272
280
  y: e.clientY
273
281
  };
274
- }, []), Ke = f((e) => {
282
+ }, []), qe = f((e) => {
275
283
  if (e.stopPropagation(), Y.current) {
276
284
  let t = Math.abs(e.clientX - Y.current.x), n = Math.abs(e.clientY - Y.current.y);
277
285
  if (t > 5 || n > 5) {
@@ -284,20 +292,20 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
284
292
  C,
285
293
  w,
286
294
  u.id
287
- ]), qe = f((e) => {
295
+ ]), Je = f((e) => {
288
296
  (e.key === "Enter" || e.key === " ") && (e.preventDefault(), e.stopPropagation(), C && w(u.id));
289
297
  }, [
290
298
  C,
291
299
  w,
292
300
  u.id
293
- ]), Je = p(() => u.type === "custom" && le(u.config), [u.type, u.config]), Ye = p(() => u.type === "custom" && ce(u.config), [u.type, u.config]), X = q && !Ye, Xe = !M && !N && !W && !Je, Z = p(() => u.renderer, [u]), Q = p(() => Z && Z !== "BIGCONSOLE", [Z]), Ze = p(() => ({
301
+ ]), Ye = p(() => u.type === "custom" && le(u.config), [u.type, u.config]), Xe = p(() => u.type === "custom" && ce(u.config), [u.type, u.config]), X = q && !Xe, Ze = !M && !N && !W && !Ye, Z = p(() => u.renderer, [u]), Q = p(() => Z && Z !== "BIGCONSOLE", [Z]), Qe = p(() => ({
294
302
  widgetId: u.id,
295
303
  data: W || {}
296
304
  }), [u.id, W]), $ = f((e, t) => {
297
305
  if (!x) return;
298
306
  let n = b?.find((t) => t.name === e.name);
299
307
  x(n || e, t);
300
- }, [x, b]), Qe = f(() => {
308
+ }, [x, b]), $e = f(() => {
301
309
  let e = {
302
310
  widget: u,
303
311
  data: (() => {
@@ -385,7 +393,7 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
385
393
  }
386
394
  switch (u.type?.toLowerCase() || "") {
387
395
  case "metric_card": return /* @__PURE__ */ g(me, { ...e });
388
- case "kpi_card_comparison": return /* @__PURE__ */ g(Te, { ...e });
396
+ case "kpi_card_comparison": return /* @__PURE__ */ g(Ee, { ...e });
389
397
  case "chart":
390
398
  case "funnel_chart": return /* @__PURE__ */ g(he, { ...e });
391
399
  case "table": return /* @__PURE__ */ g(ge, { ...e });
@@ -394,14 +402,15 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
394
402
  case "progress": return /* @__PURE__ */ g(ye, { ...e });
395
403
  case "list": return /* @__PURE__ */ g(be, { ...e });
396
404
  case "heatmap": return /* @__PURE__ */ g(xe, { ...e });
397
- case "calendar": return /* @__PURE__ */ g(Se, { ...e });
398
- case "timeline": return /* @__PURE__ */ g(we, { ...e });
399
- case "kanban": return /* @__PURE__ */ g(Ce, { ...e });
400
- case "form": return /* @__PURE__ */ g(Ae, { ...e });
401
- case "text": return /* @__PURE__ */ g(Ee, { ...e });
402
- case "iframe": return /* @__PURE__ */ g(Oe, { ...e });
403
- case "map": return /* @__PURE__ */ g(De, { ...e });
404
- case "custom": return /* @__PURE__ */ g(ke, { ...e });
405
+ case "retention": return /* @__PURE__ */ g(Se, { ...e });
406
+ case "calendar": return /* @__PURE__ */ g(Ce, { ...e });
407
+ case "timeline": return /* @__PURE__ */ g(Te, { ...e });
408
+ case "kanban": return /* @__PURE__ */ g(we, { ...e });
409
+ case "form": return /* @__PURE__ */ g(je, { ...e });
410
+ case "text": return /* @__PURE__ */ g(De, { ...e });
411
+ case "iframe": return /* @__PURE__ */ g(ke, { ...e });
412
+ case "map": return /* @__PURE__ */ g(Oe, { ...e });
413
+ case "custom": return /* @__PURE__ */ g(Ae, { ...e });
405
414
  default: return d || /* @__PURE__ */ g(c, { widgetType: u.type });
406
415
  }
407
416
  }, [
@@ -430,9 +439,9 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
430
439
  ${C ? "cursor-pointer" : ""}
431
440
  ${v}
432
441
  `,
433
- onMouseDown: Ge,
434
- onClick: Ke,
435
- onKeyDown: qe,
442
+ onMouseDown: Ke,
443
+ onClick: qe,
444
+ onKeyDown: Je,
436
445
  tabIndex: C ? 0 : -1,
437
446
  role: C ? "button" : void 0,
438
447
  "aria-selected": T,
@@ -442,19 +451,19 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
442
451
  children: [
443
452
  /* @__PURE__ */ g(ae, {
444
453
  widget: u,
445
- definition: Le,
454
+ definition: Re,
446
455
  isSelected: T,
447
456
  isEditMode: C,
448
457
  isLoading: M,
449
- timeUntilRefresh: u.refreshInterval && !ze ? ee(Re) : void 0,
458
+ timeUntilRefresh: u.refreshInterval && !Be ? ee(ze) : void 0,
450
459
  hasDrilldown: q,
451
460
  onRefresh: y,
452
- onExportCSV: B ? Ue : void 0,
453
- onExportPNG: We,
461
+ onExportCSV: B ? We : void 0,
462
+ onExportPNG: Ge,
454
463
  onDrilldown: q ? () => J() : void 0,
455
- onToggleComments: He,
464
+ onToggleComments: Ue,
456
465
  commentsOpen: L,
457
- commentCount: z ? Ve : void 0
466
+ commentCount: z ? He : void 0
458
467
  }),
459
468
  /* @__PURE__ */ g("div", {
460
469
  className: `
@@ -470,7 +479,7 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
470
479
  error: N,
471
480
  onRetry: y
472
481
  });
473
- if (Xe && !d) return /* @__PURE__ */ g(c, {
482
+ if (Ze && !d) return /* @__PURE__ */ g(c, {
474
483
  widgetType: u.type,
475
484
  hasDataSource: !!u.parserId || !!u.dataSinkId
476
485
  });
@@ -482,7 +491,7 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
482
491
  resetKey: e,
483
492
  children: d ?? /* @__PURE__ */ g(l, {
484
493
  fallback: /* @__PURE__ */ g(s, {}),
485
- children: Qe()
494
+ children: $e()
486
495
  })
487
496
  });
488
497
  })()
@@ -493,7 +502,7 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
493
502
  style: { flexShrink: 0 },
494
503
  children: /* @__PURE__ */ g(de, {
495
504
  actions: b,
496
- context: Ze,
505
+ context: Qe,
497
506
  onAction: x,
498
507
  disabled: C,
499
508
  layout: "horizontal",
@@ -518,7 +527,7 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
518
527
  }),
519
528
  L && /* @__PURE__ */ g(l, {
520
529
  fallback: null,
521
- children: /* @__PURE__ */ g(je, {
530
+ children: /* @__PURE__ */ g(Me, {
522
531
  widgetId: u.id,
523
532
  onClose: () => R(!1)
524
533
  })