@burdenoff/microfe-bigconsole 2026.619.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) => {
@@ -254,7 +254,7 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
254
254
  A,
255
255
  V
256
256
  ]), W = p(() => U ?? null, [U]), { executeDrilldown: G, canDrilldown: K } = ie({ onDrilldown: (e, t) => {
257
- Pe?.(e);
257
+ Fe?.(e);
258
258
  } }), q = p(() => K(u), [u, K]), J = f((e) => {
259
259
  if (!u.drilldown?.enabled) return;
260
260
  let t = {
@@ -274,12 +274,12 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
274
274
  W,
275
275
  D,
276
276
  G
277
- ]), Y = m(null), Ge = f((e) => {
277
+ ]), Y = m(null), Ke = f((e) => {
278
278
  Y.current = {
279
279
  x: e.clientX,
280
280
  y: e.clientY
281
281
  };
282
- }, []), Ke = f((e) => {
282
+ }, []), qe = f((e) => {
283
283
  if (e.stopPropagation(), Y.current) {
284
284
  let t = Math.abs(e.clientX - Y.current.x), n = Math.abs(e.clientY - Y.current.y);
285
285
  if (t > 5 || n > 5) {
@@ -292,20 +292,20 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
292
292
  C,
293
293
  w,
294
294
  u.id
295
- ]), qe = f((e) => {
295
+ ]), Je = f((e) => {
296
296
  (e.key === "Enter" || e.key === " ") && (e.preventDefault(), e.stopPropagation(), C && w(u.id));
297
297
  }, [
298
298
  C,
299
299
  w,
300
300
  u.id
301
- ]), 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(() => ({
302
302
  widgetId: u.id,
303
303
  data: W || {}
304
304
  }), [u.id, W]), $ = f((e, t) => {
305
305
  if (!x) return;
306
306
  let n = b?.find((t) => t.name === e.name);
307
307
  x(n || e, t);
308
- }, [x, b]), Qe = f(() => {
308
+ }, [x, b]), $e = f(() => {
309
309
  let e = {
310
310
  widget: u,
311
311
  data: (() => {
@@ -393,7 +393,7 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
393
393
  }
394
394
  switch (u.type?.toLowerCase() || "") {
395
395
  case "metric_card": return /* @__PURE__ */ g(me, { ...e });
396
- case "kpi_card_comparison": return /* @__PURE__ */ g(Te, { ...e });
396
+ case "kpi_card_comparison": return /* @__PURE__ */ g(Ee, { ...e });
397
397
  case "chart":
398
398
  case "funnel_chart": return /* @__PURE__ */ g(he, { ...e });
399
399
  case "table": return /* @__PURE__ */ g(ge, { ...e });
@@ -402,14 +402,15 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
402
402
  case "progress": return /* @__PURE__ */ g(ye, { ...e });
403
403
  case "list": return /* @__PURE__ */ g(be, { ...e });
404
404
  case "heatmap": return /* @__PURE__ */ g(xe, { ...e });
405
- case "calendar": return /* @__PURE__ */ g(Se, { ...e });
406
- case "timeline": return /* @__PURE__ */ g(we, { ...e });
407
- case "kanban": return /* @__PURE__ */ g(Ce, { ...e });
408
- case "form": return /* @__PURE__ */ g(Ae, { ...e });
409
- case "text": return /* @__PURE__ */ g(Ee, { ...e });
410
- case "iframe": return /* @__PURE__ */ g(Oe, { ...e });
411
- case "map": return /* @__PURE__ */ g(De, { ...e });
412
- 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 });
413
414
  default: return d || /* @__PURE__ */ g(c, { widgetType: u.type });
414
415
  }
415
416
  }, [
@@ -438,9 +439,9 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
438
439
  ${C ? "cursor-pointer" : ""}
439
440
  ${v}
440
441
  `,
441
- onMouseDown: Ge,
442
- onClick: Ke,
443
- onKeyDown: qe,
442
+ onMouseDown: Ke,
443
+ onClick: qe,
444
+ onKeyDown: Je,
444
445
  tabIndex: C ? 0 : -1,
445
446
  role: C ? "button" : void 0,
446
447
  "aria-selected": T,
@@ -450,19 +451,19 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
450
451
  children: [
451
452
  /* @__PURE__ */ g(ae, {
452
453
  widget: u,
453
- definition: Le,
454
+ definition: Re,
454
455
  isSelected: T,
455
456
  isEditMode: C,
456
457
  isLoading: M,
457
- timeUntilRefresh: u.refreshInterval && !ze ? ee(Re) : void 0,
458
+ timeUntilRefresh: u.refreshInterval && !Be ? ee(ze) : void 0,
458
459
  hasDrilldown: q,
459
460
  onRefresh: y,
460
- onExportCSV: B ? Ue : void 0,
461
- onExportPNG: We,
461
+ onExportCSV: B ? We : void 0,
462
+ onExportPNG: Ge,
462
463
  onDrilldown: q ? () => J() : void 0,
463
- onToggleComments: He,
464
+ onToggleComments: Ue,
464
465
  commentsOpen: L,
465
- commentCount: z ? Ve : void 0
466
+ commentCount: z ? He : void 0
466
467
  }),
467
468
  /* @__PURE__ */ g("div", {
468
469
  className: `
@@ -478,7 +479,7 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
478
479
  error: N,
479
480
  onRetry: y
480
481
  });
481
- if (Xe && !d) return /* @__PURE__ */ g(c, {
482
+ if (Ze && !d) return /* @__PURE__ */ g(c, {
482
483
  widgetType: u.type,
483
484
  hasDataSource: !!u.parserId || !!u.dataSinkId
484
485
  });
@@ -490,7 +491,7 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
490
491
  resetKey: e,
491
492
  children: d ?? /* @__PURE__ */ g(l, {
492
493
  fallback: /* @__PURE__ */ g(s, {}),
493
- children: Qe()
494
+ children: $e()
494
495
  })
495
496
  });
496
497
  })()
@@ -501,7 +502,7 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
501
502
  style: { flexShrink: 0 },
502
503
  children: /* @__PURE__ */ g(de, {
503
504
  actions: b,
504
- context: Ze,
505
+ context: Qe,
505
506
  onAction: x,
506
507
  disabled: C,
507
508
  layout: "horizontal",
@@ -526,7 +527,7 @@ var v = d(function({ widget: u, children: d, data: _, className: v = "", isLoadi
526
527
  }),
527
528
  L && /* @__PURE__ */ g(l, {
528
529
  fallback: null,
529
- children: /* @__PURE__ */ g(je, {
530
+ children: /* @__PURE__ */ g(Me, {
530
531
  widgetId: u.id,
531
532
  onClose: () => R(!1)
532
533
  })