@burdenoff/microfe-bigconsole 2026.1004.4 → 2026.1004.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.
@@ -1 +1 @@
1
- {"version":3,"file":"DrilldownDashboardRenderer.d.ts","sourceRoot":"","sources":["../../../src/bigconsole/components/DrilldownDashboardRenderer.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,EAAE,EAA6B,MAAM,OAAO,CAAC;AAa3D,MAAM,WAAW,+BAA+B;IAC9C,oCAAoC;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AA8ED,eAAO,MAAM,0BAA0B,EAAE,EAAE,CAAC,+BAA+B,CAgQ1E,CAAC;AAmBF,eAAe,0BAA0B,CAAC"}
1
+ {"version":3,"file":"DrilldownDashboardRenderer.d.ts","sourceRoot":"","sources":["../../../src/bigconsole/components/DrilldownDashboardRenderer.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,EAAE,EAA6B,MAAM,OAAO,CAAC;AAc3D,MAAM,WAAW,+BAA+B;IAC9C,oCAAoC;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AA8ED,eAAO,MAAM,0BAA0B,EAAE,EAAE,CAAC,+BAA+B,CAgQ1E,CAAC;AAmBF,eAAe,0BAA0B,CAAC"}
@@ -4,11 +4,12 @@ import "./common/index.js";
4
4
  import { mapFromFederationWidgetType as i } from "../utils/widgetTypeMapping.js";
5
5
  import { MODAL_TARGET_PAGE_PARAM as a } from "../hooks/useDrilldown.js";
6
6
  import o from "./widgets/WidgetWrapper.js";
7
- import { memo as s, useEffect as c, useState as l } from "react";
8
- import { useApolloClient as u } from "@apollo/client/react";
9
- import { jsx as d, jsxs as f } from "react/jsx-runtime";
7
+ import { getVisibleDrilldownParams as s } from "../utils/drilldownParams.js";
8
+ import { memo as c, useEffect as l, useState as u } from "react";
9
+ import { useApolloClient as d } from "@apollo/client/react";
10
+ import { jsx as f, jsxs as p } from "react/jsx-runtime";
10
11
  //#region src/bigconsole/components/DrilldownDashboardRenderer.tsx
11
- function p(e, t) {
12
+ function m(e, t) {
12
13
  let n = t * 4, r = {
13
14
  x: 0,
14
15
  y: n,
@@ -48,7 +49,7 @@ function p(e, t) {
48
49
  updatedAt: e.updatedAt || (/* @__PURE__ */ new Date()).toISOString()
49
50
  };
50
51
  }
51
- function m(e, t) {
52
+ function h(e, t) {
52
53
  let n = {
53
54
  x: 0,
54
55
  y: t * 4,
@@ -64,20 +65,20 @@ function m(e, t) {
64
65
  positionHeight: 4
65
66
  };
66
67
  }
67
- var h = s(function({ dashboardId: i, params: o, live: s = !1, refreshRevision: h = 0 }) {
68
- let _ = u(), [v, y] = l(!0), [b, x] = l(null), [S, C] = l(null), [w, T] = l([]);
69
- if (c(() => {
68
+ var g = c(function({ dashboardId: i, params: o, live: c = !1, refreshRevision: g = 0 }) {
69
+ let v = d(), [y, b] = u(!0), [x, S] = u(null), [C, w] = u(null), [T, E] = u([]);
70
+ if (l(() => {
70
71
  if (!i) {
71
- y(!1);
72
+ b(!1);
72
73
  return;
73
74
  }
74
75
  let n = !1, r = !1;
75
- y(!0);
76
+ b(!0);
76
77
  async function a() {
77
78
  if (!r) {
78
- r = !0, x(null);
79
+ r = !0, S(null);
79
80
  try {
80
- let r = await _.query({
81
+ let r = await v.query({
81
82
  query: e,
82
83
  variables: { id: i },
83
84
  fetchPolicy: "network-only"
@@ -85,35 +86,35 @@ var h = s(function({ dashboardId: i, params: o, live: s = !1, refreshRevision: h
85
86
  if (n) return;
86
87
  let a = r.data?.getDashboard;
87
88
  if (!a) {
88
- x("Dashboard not found"), y(!1);
89
+ S("Dashboard not found"), b(!1);
89
90
  return;
90
91
  }
91
92
  let o = a.pages?.edges?.map((e) => ({
92
93
  id: e.node.id,
93
94
  name: e.node.name || "Page 1"
94
95
  })) || [];
95
- C({
96
+ w({
96
97
  id: a.id,
97
98
  name: a.name,
98
99
  description: a.description,
99
100
  pages: o
100
101
  });
101
- let s = await _.query({
102
+ let s = await v.query({
102
103
  query: t,
103
104
  variables: { dashboardId: i },
104
105
  fetchPolicy: "network-only"
105
106
  });
106
107
  if (n) return;
107
- T((s.data?.listWidgetsByDashboard || []).map((e, t) => p(e, t)));
108
+ E((s.data?.listWidgetsByDashboard || []).map((e, t) => m(e, t)));
108
109
  } catch (e) {
109
- n || x(e instanceof Error ? e.message : "Failed to load dashboard");
110
+ n || S(e instanceof Error ? e.message : "Failed to load dashboard");
110
111
  } finally {
111
- r = !1, n || y(!1);
112
+ r = !1, n || b(!1);
112
113
  }
113
114
  }
114
115
  }
115
116
  a();
116
- let o = s ? window.setInterval(() => {
117
+ let o = c ? window.setInterval(() => {
117
118
  document.visibilityState === "visible" && a();
118
119
  }, 4e3) : void 0;
119
120
  return () => {
@@ -121,35 +122,35 @@ var h = s(function({ dashboardId: i, params: o, live: s = !1, refreshRevision: h
121
122
  };
122
123
  }, [
123
124
  i,
124
- _,
125
- s,
126
- h
127
- ]), v) return /* @__PURE__ */ d("div", {
125
+ v,
126
+ c,
127
+ g
128
+ ]), y) return /* @__PURE__ */ f("div", {
128
129
  className: "flex items-center justify-center h-full",
129
- children: /* @__PURE__ */ f("div", {
130
+ children: /* @__PURE__ */ p("div", {
130
131
  className: "flex flex-col items-center gap-3",
131
- children: [/* @__PURE__ */ d("div", { className: "w-8 h-8 border-2 border-action-primary-bg border-t-transparent rounded-full animate-spin" }), /* @__PURE__ */ d("p", {
132
+ children: [/* @__PURE__ */ f("div", { className: "w-8 h-8 border-2 border-action-primary-bg border-t-transparent rounded-full animate-spin" }), /* @__PURE__ */ f("p", {
132
133
  className: "text-sm text-text-secondary",
133
134
  children: "Loading dashboard..."
134
135
  })]
135
136
  })
136
137
  });
137
- if (b) return /* @__PURE__ */ d("div", {
138
+ if (x) return /* @__PURE__ */ f("div", {
138
139
  className: "flex h-full items-center justify-center",
139
140
  role: "alert",
140
- children: /* @__PURE__ */ d(n, {
141
+ children: /* @__PURE__ */ f(n, {
141
142
  headingLevel: 3,
142
143
  tone: "danger",
143
144
  className: "w-full max-w-md",
144
145
  "data-testid": "drilldown-error",
145
146
  title: "Could not load this dashboard",
146
- description: b,
147
- icon: /* @__PURE__ */ d("svg", {
147
+ description: x,
148
+ icon: /* @__PURE__ */ f("svg", {
148
149
  className: "h-icon-md w-icon-md",
149
150
  fill: "none",
150
151
  stroke: "currentColor",
151
152
  viewBox: "0 0 24 24",
152
- children: /* @__PURE__ */ d("path", {
153
+ children: /* @__PURE__ */ f("path", {
153
154
  strokeLinecap: "round",
154
155
  strokeLinejoin: "round",
155
156
  strokeWidth: 1.5,
@@ -158,69 +159,69 @@ var h = s(function({ dashboardId: i, params: o, live: s = !1, refreshRevision: h
158
159
  })
159
160
  })
160
161
  });
161
- if (!S || w.length === 0) return /* @__PURE__ */ d("div", {
162
+ if (!C || T.length === 0) return /* @__PURE__ */ f("div", {
162
163
  className: "flex items-center justify-center h-full",
163
- children: /* @__PURE__ */ f("div", {
164
+ children: /* @__PURE__ */ p("div", {
164
165
  className: "flex flex-col items-center gap-3 text-center",
165
- children: [/* @__PURE__ */ d("svg", {
166
+ children: [/* @__PURE__ */ f("svg", {
166
167
  className: "w-12 h-12 text-text-muted",
167
168
  fill: "none",
168
169
  stroke: "currentColor",
169
170
  viewBox: "0 0 24 24",
170
- children: /* @__PURE__ */ d("path", {
171
+ children: /* @__PURE__ */ f("path", {
171
172
  strokeLinecap: "round",
172
173
  strokeLinejoin: "round",
173
174
  strokeWidth: 1.5,
174
175
  d: "M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z"
175
176
  })
176
- }), /* @__PURE__ */ d("p", {
177
+ }), /* @__PURE__ */ f("p", {
177
178
  className: "text-sm text-text-secondary",
178
- children: S ? "This dashboard has no widgets" : "Dashboard not found"
179
+ children: C ? "This dashboard has no widgets" : "Dashboard not found"
179
180
  })]
180
181
  })
181
182
  });
182
- let E = Object.entries(o).filter(([e]) => !e.startsWith("__")), D = o[a], O = S.pages.find((e) => e.id === D) ?? S.pages[0] ?? null, k = (O ? w.filter((e) => !e.pageId || e.pageId === O.id) : w).map((e, t) => m(e, t));
183
- return /* @__PURE__ */ f(r, {
183
+ let D = s(o), O = o[a], k = C.pages.find((e) => e.id === O) ?? C.pages[0] ?? null, A = (k ? T.filter((e) => !e.pageId || e.pageId === k.id) : T).map((e, t) => h(e, t));
184
+ return /* @__PURE__ */ p(r, {
184
185
  className: "w-full",
185
186
  children: [
186
- /* @__PURE__ */ d(n, {
187
+ /* @__PURE__ */ f(n, {
187
188
  emphasis: "bare",
188
189
  padding: "none",
189
190
  headingLevel: 3,
190
- title: S.name,
191
- description: S.pages.length > 1 && O ? /* @__PURE__ */ d("span", {
191
+ title: C.name,
192
+ description: C.pages.length > 1 && k ? /* @__PURE__ */ f("span", {
192
193
  "data-testid": "drilldown-dashboard-page",
193
- children: O.name
194
- }) : S.description,
194
+ children: k.name
195
+ }) : C.description,
195
196
  "data-testid": "drilldown-dashboard-header"
196
197
  }),
197
- E.length > 0 && /* @__PURE__ */ d(n, {
198
+ D.length > 0 && /* @__PURE__ */ f(n, {
198
199
  emphasis: "muted",
199
200
  padding: "compact",
200
201
  headingLevel: 3,
201
202
  title: "Filtered by",
202
203
  "data-testid": "drilldown-params",
203
204
  bodyClassName: "flex flex-wrap gap-control-gap",
204
- children: E.map(([e, t]) => /* @__PURE__ */ f("span", {
205
+ children: D.map(([e, t]) => /* @__PURE__ */ p("span", {
205
206
  className: "inline-flex items-center rounded-pill bg-bg-surface px-2 py-1 text-xs text-text-secondary",
206
- children: [/* @__PURE__ */ f("span", {
207
+ children: [/* @__PURE__ */ p("span", {
207
208
  className: "font-medium text-text-primary",
208
209
  children: [e, ":"]
209
- }), /* @__PURE__ */ d("span", {
210
+ }), /* @__PURE__ */ f("span", {
210
211
  className: "ml-1",
211
212
  children: typeof t == "object" && t ? JSON.stringify(t) : String(t)
212
213
  })]
213
214
  }, e))
214
215
  }),
215
- /* @__PURE__ */ f("div", {
216
+ /* @__PURE__ */ p("div", {
216
217
  className: "flex flex-col gap-form-gap",
217
- children: [k.length === 0 && /* @__PURE__ */ d("p", {
218
+ children: [A.length === 0 && /* @__PURE__ */ f("p", {
218
219
  className: "text-sm text-text-secondary",
219
220
  "data-testid": "drilldown-page-empty",
220
221
  children: "This page has no widgets"
221
- }), k.map((e) => {
222
+ }), A.map((e) => {
222
223
  let t = e.config?._internalWidgetType, n = e.type;
223
- return /* @__PURE__ */ d("div", {
224
+ return /* @__PURE__ */ f("div", {
224
225
  className: "min-w-0 overflow-hidden rounded-card border border-[var(--color-border-subtle)] bg-bg-surface",
225
226
  style: n === "LINE_CHART" || n === "chart" || t === "chart" || t === "funnel_chart" ? { height: "clamp(220px, 45vh, 350px)" } : n === "TABLE" || n === "table" || t === "table" || t === "list" || t === "pivot_table" ? {
226
227
  minHeight: "min(250px, 40vh)",
@@ -229,7 +230,7 @@ var h = s(function({ dashboardId: i, params: o, live: s = !1, refreshRevision: h
229
230
  minHeight: "min(120px, 25vh)",
230
231
  maxHeight: "min(300px, 50vh)"
231
232
  },
232
- children: /* @__PURE__ */ d(g, {
233
+ children: /* @__PURE__ */ f(_, {
233
234
  widget: e,
234
235
  filterValues: o
235
236
  })
@@ -238,10 +239,10 @@ var h = s(function({ dashboardId: i, params: o, live: s = !1, refreshRevision: h
238
239
  })
239
240
  ]
240
241
  });
241
- }), g = s(function({ widget: e, filterValues: t }) {
242
- return /* @__PURE__ */ d("div", {
242
+ }), _ = c(function({ widget: e, filterValues: t }) {
243
+ return /* @__PURE__ */ f("div", {
243
244
  className: "h-full [&_[data-widget-id]]:border-transparent [&_[data-widget-id]:hover]:border-transparent",
244
- children: /* @__PURE__ */ d(o, {
245
+ children: /* @__PURE__ */ f(o, {
245
246
  widget: e,
246
247
  isLoading: !1,
247
248
  error: null,
@@ -250,6 +251,6 @@ var h = s(function({ dashboardId: i, params: o, live: s = !1, refreshRevision: h
250
251
  });
251
252
  });
252
253
  //#endregion
253
- export { h as default };
254
+ export { g as default };
254
255
 
255
256
  //# sourceMappingURL=DrilldownDashboardRenderer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DrilldownDashboardRenderer.js","names":[],"sources":["../../../src/bigconsole/components/DrilldownDashboardRenderer.tsx"],"sourcesContent":["/**\n * DrilldownDashboardRenderer Component\n *\n * Renders a dashboard inside the DrilldownModal.\n * Fetches dashboard data and displays the target page's widgets (the page named\n * by the drilldown, else the first page) with passed parameters (BOFF-7625).\n */\n\nimport { type FC, memo, useEffect, useState } from 'react';\nimport { useApolloClient } from '@apollo/client/react';\nimport type { Widget } from '../types';\nimport { WidgetWrapper } from './widgets/WidgetWrapper';\nimport { Section, SectionStack } from './common';\nimport { ListWidgetsByDashboardDocument, GetDashboardDocument } from '../../generated/wspace-operations';\nimport { mapFromFederationWidgetType } from '../utils/widgetTypeMapping';\nimport { MODAL_TARGET_PAGE_PARAM } from '../hooks/useDrilldown';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface DrilldownDashboardRendererProps {\n /** Target dashboard ID to render */\n dashboardId: string;\n live?: boolean;\n refreshRevision?: number;\n /** Parameters passed from drilldown (can be used for filtering) */\n params: Record<string, unknown>;\n}\n\ninterface DashboardData {\n id: string;\n name: string;\n description?: string;\n pages: Array<{\n id: string;\n name: string;\n }>;\n}\n\n// ============================================================================\n// Helper: Normalize widget from GraphQL\n// ============================================================================\n\nfunction normalizeWidget(raw: Record<string, unknown>, index: number): Widget {\n // For drilldown modal, stack widgets vertically with compact sizing\n const posX = 0;\n const posY = index * 4; // Stack vertically, 4 row units per widget\n const posW = 12; // Full width\n const posH = 4; // Better height for widget content\n\n const position = { x: posX, y: posY, width: posW, height: posH };\n\n // Get the config object\n const config = (raw.config as Record<string, unknown>) || {};\n\n // Map widget type correctly: check _internalWidgetType first, then map from federation type\n // This is critical — federation types like 'KPI' must be mapped to internal types like 'metric_card'\n const internalType = config._internalWidgetType as string | undefined;\n const widgetType = internalType || mapFromFederationWidgetType((raw.type as string) || 'KPI');\n\n return {\n id: (raw.id as string) ?? '',\n pageId: (raw.pageId as string) || '',\n dashboardId: raw.dashboardId as string | undefined,\n type: widgetType,\n title: (raw.title as string) || 'Untitled Widget',\n renderer: raw.renderer || 'BIGCONSOLE',\n template: raw.template || null,\n dataSinkId: raw.dataSinkId || null,\n datasetId: raw.datasetId || null,\n parserId: raw.parserId || null,\n parserRules: raw.parserRules || null,\n config: config,\n position: position,\n positionX: posX,\n positionY: posY,\n positionWidth: posW,\n positionHeight: posH,\n positionResponsive: raw.positionResponsive as Widget['positionResponsive'],\n rowOrder: (raw.rowOrder as number | null) ?? null,\n refreshInterval: raw.refreshInterval,\n lastRefreshedAt: raw.lastRefreshedAt,\n cacheTTL: (raw.cacheTTL as number | null) ?? null,\n drilldown: raw.drilldown as Widget['drilldown'],\n actions: (raw.actions as Widget['actions']) || [],\n translations: (raw.translations as Widget['translations']) || [],\n metadata: raw.metadata as Record<string, unknown> | undefined,\n context: raw.context,\n // Include widget data from backend (critical for showing real data in modal)\n data: raw.data || null,\n createdAt: (raw.createdAt as string) || new Date().toISOString(),\n updatedAt: (raw.updatedAt as string) || new Date().toISOString(),\n } as Widget;\n}\n\n/** Place a widget at a given slot of the modal's single-column stack. */\nfunction normalizeStacking(widget: Widget, index: number): Widget {\n const position = { x: 0, y: index * 4, width: 12, height: 4 };\n return { ...widget, position, positionX: 0, positionY: position.y, positionWidth: 12, positionHeight: 4 };\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const DrilldownDashboardRenderer: FC<DrilldownDashboardRendererProps> = memo(\n function DrilldownDashboardRenderer({ dashboardId, params, live = false, refreshRevision = 0 }) {\n const apolloClient = useApolloClient();\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [dashboard, setDashboard] = useState<DashboardData | null>(null);\n const [widgets, setWidgets] = useState<Widget[]>([]);\n\n // Fetch dashboard and widgets — only when dashboardId is provided\n useEffect(() => {\n if (!dashboardId) {\n setLoading(false);\n return;\n }\n\n let cancelled = false;\n let fetching = false;\n setLoading(true);\n async function fetchData() {\n if (fetching) return;\n fetching = true;\n setError(null);\n\n try {\n // Fetch dashboard info\n interface DashboardQueryResult {\n getDashboard: {\n id: string;\n name: string;\n description?: string;\n pages?: {\n edges?: Array<{ node: { id: string; name?: string } }>;\n };\n } | null;\n }\n\n const dashboardResult = await apolloClient.query<DashboardQueryResult>({\n query: GetDashboardDocument,\n variables: { id: dashboardId },\n fetchPolicy: 'network-only',\n });\n\n if (cancelled) return;\n const dashboardData = dashboardResult.data?.getDashboard;\n if (!dashboardData) {\n setError('Dashboard not found');\n setLoading(false);\n return;\n }\n\n // Normalize dashboard\n const pages =\n dashboardData.pages?.edges?.map((edge) => ({\n id: edge.node.id,\n name: edge.node.name || 'Page 1',\n })) || [];\n\n setDashboard({\n id: dashboardData.id,\n name: dashboardData.name,\n description: dashboardData.description,\n pages,\n });\n\n // Fetch widgets for the dashboard\n const widgetsResult = await apolloClient.query<{ listWidgetsByDashboard: Record<string, unknown>[] }>({\n query: ListWidgetsByDashboardDocument,\n variables: { dashboardId },\n fetchPolicy: 'network-only',\n });\n\n if (cancelled) return;\n const widgetsList = widgetsResult.data?.listWidgetsByDashboard || [];\n setWidgets(widgetsList.map((w, i) => normalizeWidget(w, i)));\n } catch (err) {\n if (!cancelled) setError(err instanceof Error ? err.message : 'Failed to load dashboard');\n } finally {\n fetching = false;\n if (!cancelled) setLoading(false);\n }\n }\n\n void fetchData();\n const interval = live\n ? window.setInterval(() => {\n if (document.visibilityState === 'visible') void fetchData();\n }, 4000)\n : undefined;\n return () => {\n cancelled = true;\n if (interval !== undefined) window.clearInterval(interval);\n };\n }, [dashboardId, apolloClient, live, refreshRevision]);\n\n // Loading state\n if (loading) {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <div className=\"flex flex-col items-center gap-3\">\n <div className=\"w-8 h-8 border-2 border-action-primary-bg border-t-transparent rounded-full animate-spin\" />\n <p className=\"text-sm text-text-secondary\">Loading dashboard...</p>\n </div>\n </div>\n );\n }\n\n // Error state\n if (error) {\n return (\n <div className=\"flex h-full items-center justify-center\" role=\"alert\">\n <Section\n headingLevel={3}\n tone=\"danger\"\n className=\"w-full max-w-md\"\n data-testid=\"drilldown-error\"\n title=\"Could not load this dashboard\"\n description={error}\n icon={\n <svg className=\"h-icon-md w-icon-md\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n }\n />\n </div>\n );\n }\n\n // Empty state\n if (!dashboard || widgets.length === 0) {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <div className=\"flex flex-col items-center gap-3 text-center\">\n <svg className=\"w-12 h-12 text-text-muted\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z\"\n />\n </svg>\n <p className=\"text-sm text-text-secondary\">\n {dashboard ? 'This dashboard has no widgets' : 'Dashboard not found'}\n </p>\n </div>\n </div>\n );\n }\n\n const visibleParams = Object.entries(params).filter(([key]) => !key.startsWith('__'));\n\n // Show one page: the drilldown's target page when it still exists, else the\n // first page. Widgets without a page id (older payloads) are always shown.\n const requestedPageId = params[MODAL_TARGET_PAGE_PARAM];\n const activePage = dashboard.pages.find((page) => page.id === requestedPageId) ?? dashboard.pages[0] ?? null;\n const pageWidgets = activePage\n ? widgets.filter((widget) => !widget.pageId || widget.pageId === activePage.id)\n : widgets;\n // Re-flow the page's widgets top to bottom (the stacking was computed over\n // the whole dashboard).\n const stackedWidgets = pageWidgets.map((widget, index) => normalizeStacking(widget, index));\n\n return (\n <SectionStack className=\"w-full\">\n {/* Which board you drilled into — identity, not content. */}\n <Section\n emphasis=\"bare\"\n padding=\"none\"\n headingLevel={3}\n title={dashboard.name}\n description={\n dashboard.pages.length > 1 && activePage ? (\n <span data-testid=\"drilldown-dashboard-page\">{activePage.name}</span>\n ) : (\n dashboard.description\n )\n }\n data-testid=\"drilldown-dashboard-header\"\n />\n\n {/* The filter context you arrived with: supporting detail, recessed. */}\n {visibleParams.length > 0 && (\n <Section\n emphasis=\"muted\"\n padding=\"compact\"\n headingLevel={3}\n title=\"Filtered by\"\n data-testid=\"drilldown-params\"\n bodyClassName=\"flex flex-wrap gap-control-gap\"\n >\n {visibleParams.map(([key, value]) => (\n <span\n key={key}\n className=\"inline-flex items-center rounded-pill bg-bg-surface px-2 py-1 text-xs text-text-secondary\"\n >\n <span className=\"font-medium text-text-primary\">{key}:</span>\n <span className=\"ml-1\">\n {typeof value === 'object' && value !== null ? JSON.stringify(value) : String(value)}\n </span>\n </span>\n ))}\n </Section>\n )}\n\n {/* Widgets List - simple vertical layout for modal */}\n <div className=\"flex flex-col gap-form-gap\">\n {stackedWidgets.length === 0 && (\n <p className=\"text-sm text-text-secondary\" data-testid=\"drilldown-page-empty\">\n This page has no widgets\n </p>\n )}\n {stackedWidgets.map((widget) => {\n // Chart widgets (LINE_CHART / chart) need explicit pixel height because\n // Recharts ResponsiveContainer height=\"100%\" requires a parent with\n // a definite height — minHeight alone doesn't work.\n const internalType = (widget.config as Record<string, unknown>)?._internalWidgetType as string | undefined;\n const widgetType = widget.type as string;\n const isChartWidget =\n widgetType === 'LINE_CHART' ||\n widgetType === 'chart' ||\n internalType === 'chart' ||\n internalType === 'funnel_chart';\n const isTableWidget =\n widgetType === 'TABLE' ||\n widgetType === 'table' ||\n internalType === 'table' ||\n internalType === 'list' ||\n internalType === 'pivot_table';\n\n // Charts need an explicit height (Recharts' ResponsiveContainer needs a\n // definite parent). Clamping against the viewport keeps a 350px chart\n // plus a 500px table from filling a phone screen twice over.\n const heightStyle = isChartWidget\n ? { height: 'clamp(220px, 45vh, 350px)' }\n : isTableWidget\n ? { minHeight: 'min(250px, 40vh)', maxHeight: 'min(500px, 65vh)' }\n : { minHeight: 'min(120px, 25vh)', maxHeight: 'min(300px, 50vh)' };\n\n return (\n <div\n key={widget.id}\n className=\"min-w-0 overflow-hidden rounded-card border border-[var(--color-border-subtle)] bg-bg-surface\"\n style={heightStyle}\n >\n <WidgetInModal widget={widget} filterValues={params} />\n </div>\n );\n })}\n </div>\n </SectionStack>\n );\n }\n);\n\n// ============================================================================\n// Widget In Modal Component\n// ============================================================================\n\ninterface WidgetInModalProps {\n widget: Widget;\n filterValues?: Record<string, unknown>;\n}\n\nconst WidgetInModal: FC<WidgetInModalProps> = memo(function WidgetInModal({ widget, filterValues }) {\n return (\n <div className=\"h-full [&_[data-widget-id]]:border-transparent [&_[data-widget-id]:hover]:border-transparent\">\n <WidgetWrapper widget={widget} isLoading={false} error={null} filterValues={filterValues} />\n </div>\n );\n});\n\nexport default DrilldownDashboardRenderer;\n"],"mappings":"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"}
1
+ {"version":3,"file":"DrilldownDashboardRenderer.js","names":[],"sources":["../../../src/bigconsole/components/DrilldownDashboardRenderer.tsx"],"sourcesContent":["/**\n * DrilldownDashboardRenderer Component\n *\n * Renders a dashboard inside the DrilldownModal.\n * Fetches dashboard data and displays the target page's widgets (the page named\n * by the drilldown, else the first page) with passed parameters (BOFF-7625).\n */\n\nimport { type FC, memo, useEffect, useState } from 'react';\nimport { useApolloClient } from '@apollo/client/react';\nimport type { Widget } from '../types';\nimport { WidgetWrapper } from './widgets/WidgetWrapper';\nimport { Section, SectionStack } from './common';\nimport { ListWidgetsByDashboardDocument, GetDashboardDocument } from '../../generated/wspace-operations';\nimport { mapFromFederationWidgetType } from '../utils/widgetTypeMapping';\nimport { MODAL_TARGET_PAGE_PARAM } from '../hooks/useDrilldown';\nimport { getVisibleDrilldownParams } from '../utils/drilldownParams';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface DrilldownDashboardRendererProps {\n /** Target dashboard ID to render */\n dashboardId: string;\n live?: boolean;\n refreshRevision?: number;\n /** Parameters passed from drilldown (can be used for filtering) */\n params: Record<string, unknown>;\n}\n\ninterface DashboardData {\n id: string;\n name: string;\n description?: string;\n pages: Array<{\n id: string;\n name: string;\n }>;\n}\n\n// ============================================================================\n// Helper: Normalize widget from GraphQL\n// ============================================================================\n\nfunction normalizeWidget(raw: Record<string, unknown>, index: number): Widget {\n // For drilldown modal, stack widgets vertically with compact sizing\n const posX = 0;\n const posY = index * 4; // Stack vertically, 4 row units per widget\n const posW = 12; // Full width\n const posH = 4; // Better height for widget content\n\n const position = { x: posX, y: posY, width: posW, height: posH };\n\n // Get the config object\n const config = (raw.config as Record<string, unknown>) || {};\n\n // Map widget type correctly: check _internalWidgetType first, then map from federation type\n // This is critical — federation types like 'KPI' must be mapped to internal types like 'metric_card'\n const internalType = config._internalWidgetType as string | undefined;\n const widgetType = internalType || mapFromFederationWidgetType((raw.type as string) || 'KPI');\n\n return {\n id: (raw.id as string) ?? '',\n pageId: (raw.pageId as string) || '',\n dashboardId: raw.dashboardId as string | undefined,\n type: widgetType,\n title: (raw.title as string) || 'Untitled Widget',\n renderer: raw.renderer || 'BIGCONSOLE',\n template: raw.template || null,\n dataSinkId: raw.dataSinkId || null,\n datasetId: raw.datasetId || null,\n parserId: raw.parserId || null,\n parserRules: raw.parserRules || null,\n config: config,\n position: position,\n positionX: posX,\n positionY: posY,\n positionWidth: posW,\n positionHeight: posH,\n positionResponsive: raw.positionResponsive as Widget['positionResponsive'],\n rowOrder: (raw.rowOrder as number | null) ?? null,\n refreshInterval: raw.refreshInterval,\n lastRefreshedAt: raw.lastRefreshedAt,\n cacheTTL: (raw.cacheTTL as number | null) ?? null,\n drilldown: raw.drilldown as Widget['drilldown'],\n actions: (raw.actions as Widget['actions']) || [],\n translations: (raw.translations as Widget['translations']) || [],\n metadata: raw.metadata as Record<string, unknown> | undefined,\n context: raw.context,\n // Include widget data from backend (critical for showing real data in modal)\n data: raw.data || null,\n createdAt: (raw.createdAt as string) || new Date().toISOString(),\n updatedAt: (raw.updatedAt as string) || new Date().toISOString(),\n } as Widget;\n}\n\n/** Place a widget at a given slot of the modal's single-column stack. */\nfunction normalizeStacking(widget: Widget, index: number): Widget {\n const position = { x: 0, y: index * 4, width: 12, height: 4 };\n return { ...widget, position, positionX: 0, positionY: position.y, positionWidth: 12, positionHeight: 4 };\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const DrilldownDashboardRenderer: FC<DrilldownDashboardRendererProps> = memo(\n function DrilldownDashboardRenderer({ dashboardId, params, live = false, refreshRevision = 0 }) {\n const apolloClient = useApolloClient();\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [dashboard, setDashboard] = useState<DashboardData | null>(null);\n const [widgets, setWidgets] = useState<Widget[]>([]);\n\n // Fetch dashboard and widgets — only when dashboardId is provided\n useEffect(() => {\n if (!dashboardId) {\n setLoading(false);\n return;\n }\n\n let cancelled = false;\n let fetching = false;\n setLoading(true);\n async function fetchData() {\n if (fetching) return;\n fetching = true;\n setError(null);\n\n try {\n // Fetch dashboard info\n interface DashboardQueryResult {\n getDashboard: {\n id: string;\n name: string;\n description?: string;\n pages?: {\n edges?: Array<{ node: { id: string; name?: string } }>;\n };\n } | null;\n }\n\n const dashboardResult = await apolloClient.query<DashboardQueryResult>({\n query: GetDashboardDocument,\n variables: { id: dashboardId },\n fetchPolicy: 'network-only',\n });\n\n if (cancelled) return;\n const dashboardData = dashboardResult.data?.getDashboard;\n if (!dashboardData) {\n setError('Dashboard not found');\n setLoading(false);\n return;\n }\n\n // Normalize dashboard\n const pages =\n dashboardData.pages?.edges?.map((edge) => ({\n id: edge.node.id,\n name: edge.node.name || 'Page 1',\n })) || [];\n\n setDashboard({\n id: dashboardData.id,\n name: dashboardData.name,\n description: dashboardData.description,\n pages,\n });\n\n // Fetch widgets for the dashboard\n const widgetsResult = await apolloClient.query<{ listWidgetsByDashboard: Record<string, unknown>[] }>({\n query: ListWidgetsByDashboardDocument,\n variables: { dashboardId },\n fetchPolicy: 'network-only',\n });\n\n if (cancelled) return;\n const widgetsList = widgetsResult.data?.listWidgetsByDashboard || [];\n setWidgets(widgetsList.map((w, i) => normalizeWidget(w, i)));\n } catch (err) {\n if (!cancelled) setError(err instanceof Error ? err.message : 'Failed to load dashboard');\n } finally {\n fetching = false;\n if (!cancelled) setLoading(false);\n }\n }\n\n void fetchData();\n const interval = live\n ? window.setInterval(() => {\n if (document.visibilityState === 'visible') void fetchData();\n }, 4000)\n : undefined;\n return () => {\n cancelled = true;\n if (interval !== undefined) window.clearInterval(interval);\n };\n }, [dashboardId, apolloClient, live, refreshRevision]);\n\n // Loading state\n if (loading) {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <div className=\"flex flex-col items-center gap-3\">\n <div className=\"w-8 h-8 border-2 border-action-primary-bg border-t-transparent rounded-full animate-spin\" />\n <p className=\"text-sm text-text-secondary\">Loading dashboard...</p>\n </div>\n </div>\n );\n }\n\n // Error state\n if (error) {\n return (\n <div className=\"flex h-full items-center justify-center\" role=\"alert\">\n <Section\n headingLevel={3}\n tone=\"danger\"\n className=\"w-full max-w-md\"\n data-testid=\"drilldown-error\"\n title=\"Could not load this dashboard\"\n description={error}\n icon={\n <svg className=\"h-icon-md w-icon-md\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n }\n />\n </div>\n );\n }\n\n // Empty state\n if (!dashboard || widgets.length === 0) {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <div className=\"flex flex-col items-center gap-3 text-center\">\n <svg className=\"w-12 h-12 text-text-muted\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z\"\n />\n </svg>\n <p className=\"text-sm text-text-secondary\">\n {dashboard ? 'This dashboard has no widgets' : 'Dashboard not found'}\n </p>\n </div>\n </div>\n );\n }\n\n const visibleParams = getVisibleDrilldownParams(params);\n\n // Show one page: the drilldown's target page when it still exists, else the\n // first page. Widgets without a page id (older payloads) are always shown.\n const requestedPageId = params[MODAL_TARGET_PAGE_PARAM];\n const activePage = dashboard.pages.find((page) => page.id === requestedPageId) ?? dashboard.pages[0] ?? null;\n const pageWidgets = activePage\n ? widgets.filter((widget) => !widget.pageId || widget.pageId === activePage.id)\n : widgets;\n // Re-flow the page's widgets top to bottom (the stacking was computed over\n // the whole dashboard).\n const stackedWidgets = pageWidgets.map((widget, index) => normalizeStacking(widget, index));\n\n return (\n <SectionStack className=\"w-full\">\n {/* Which board you drilled into — identity, not content. */}\n <Section\n emphasis=\"bare\"\n padding=\"none\"\n headingLevel={3}\n title={dashboard.name}\n description={\n dashboard.pages.length > 1 && activePage ? (\n <span data-testid=\"drilldown-dashboard-page\">{activePage.name}</span>\n ) : (\n dashboard.description\n )\n }\n data-testid=\"drilldown-dashboard-header\"\n />\n\n {/* The filter context you arrived with: supporting detail, recessed. */}\n {visibleParams.length > 0 && (\n <Section\n emphasis=\"muted\"\n padding=\"compact\"\n headingLevel={3}\n title=\"Filtered by\"\n data-testid=\"drilldown-params\"\n bodyClassName=\"flex flex-wrap gap-control-gap\"\n >\n {visibleParams.map(([key, value]) => (\n <span\n key={key}\n className=\"inline-flex items-center rounded-pill bg-bg-surface px-2 py-1 text-xs text-text-secondary\"\n >\n <span className=\"font-medium text-text-primary\">{key}:</span>\n <span className=\"ml-1\">\n {typeof value === 'object' && value !== null ? JSON.stringify(value) : String(value)}\n </span>\n </span>\n ))}\n </Section>\n )}\n\n {/* Widgets List - simple vertical layout for modal */}\n <div className=\"flex flex-col gap-form-gap\">\n {stackedWidgets.length === 0 && (\n <p className=\"text-sm text-text-secondary\" data-testid=\"drilldown-page-empty\">\n This page has no widgets\n </p>\n )}\n {stackedWidgets.map((widget) => {\n // Chart widgets (LINE_CHART / chart) need explicit pixel height because\n // Recharts ResponsiveContainer height=\"100%\" requires a parent with\n // a definite height — minHeight alone doesn't work.\n const internalType = (widget.config as Record<string, unknown>)?._internalWidgetType as string | undefined;\n const widgetType = widget.type as string;\n const isChartWidget =\n widgetType === 'LINE_CHART' ||\n widgetType === 'chart' ||\n internalType === 'chart' ||\n internalType === 'funnel_chart';\n const isTableWidget =\n widgetType === 'TABLE' ||\n widgetType === 'table' ||\n internalType === 'table' ||\n internalType === 'list' ||\n internalType === 'pivot_table';\n\n // Charts need an explicit height (Recharts' ResponsiveContainer needs a\n // definite parent). Clamping against the viewport keeps a 350px chart\n // plus a 500px table from filling a phone screen twice over.\n const heightStyle = isChartWidget\n ? { height: 'clamp(220px, 45vh, 350px)' }\n : isTableWidget\n ? { minHeight: 'min(250px, 40vh)', maxHeight: 'min(500px, 65vh)' }\n : { minHeight: 'min(120px, 25vh)', maxHeight: 'min(300px, 50vh)' };\n\n return (\n <div\n key={widget.id}\n className=\"min-w-0 overflow-hidden rounded-card border border-[var(--color-border-subtle)] bg-bg-surface\"\n style={heightStyle}\n >\n <WidgetInModal widget={widget} filterValues={params} />\n </div>\n );\n })}\n </div>\n </SectionStack>\n );\n }\n);\n\n// ============================================================================\n// Widget In Modal Component\n// ============================================================================\n\ninterface WidgetInModalProps {\n widget: Widget;\n filterValues?: Record<string, unknown>;\n}\n\nconst WidgetInModal: FC<WidgetInModalProps> = memo(function WidgetInModal({ widget, filterValues }) {\n return (\n <div className=\"h-full [&_[data-widget-id]]:border-transparent [&_[data-widget-id]:hover]:border-transparent\">\n <WidgetWrapper widget={widget} isLoading={false} error={null} filterValues={filterValues} />\n </div>\n );\n});\n\nexport default DrilldownDashboardRenderer;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"DrilldownModal.d.ts","sourceRoot":"","sources":["../../../src/bigconsole/components/DrilldownModal.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,EAAE,EAA6B,MAAM,OAAO,CAAC;AAc3D,MAAM,WAAW,mBAAmB;IAClC,gDAAgD;IAChD,eAAe,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,KAAK,CAAC,SAAS,CAAC;IAC5F,+BAA+B;IAC/B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAMD,eAAO,MAAM,cAAc,EAAE,EAAE,CAAC,mBAAmB,CAsHjD,CAAC;AAYH,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"DrilldownModal.d.ts","sourceRoot":"","sources":["../../../src/bigconsole/components/DrilldownModal.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,EAAE,EAA6B,MAAM,OAAO,CAAC;AAe3D,MAAM,WAAW,mBAAmB;IAClC,gDAAgD;IAChD,eAAe,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,KAAK,CAAC,SAAS,CAAC;IAC5F,+BAA+B;IAC/B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAMD,eAAO,MAAM,cAAc,EAAE,EAAE,CAAC,mBAAmB,CAoHjD,CAAC;AAYH,eAAe,cAAc,CAAC"}
@@ -1,54 +1,55 @@
1
1
  import e from "../store/drilldownStore.js";
2
2
  import { SECTION_FOCUS_RING as t } from "./common/sectionStyles.js";
3
3
  import "./common/index.js";
4
- import { memo as n, useCallback as r, useRef as i } from "react";
5
- import { ResponsiveDialog as a, ResponsiveDialogContent as o, ResponsiveDialogDescription as s, ResponsiveDialogTitle as c } from "@burdenoff/fe-libs/ui";
6
- import { jsx as l, jsxs as u } from "react/jsx-runtime";
4
+ import { getVisibleDrilldownParams as n } from "../utils/drilldownParams.js";
5
+ import { memo as r, useCallback as i, useRef as a } from "react";
6
+ import { ResponsiveDialog as o, ResponsiveDialogContent as s, ResponsiveDialogDescription as c, ResponsiveDialogTitle as l } from "@burdenoff/fe-libs/ui";
7
+ import { jsx as u, jsxs as d } from "react/jsx-runtime";
7
8
  //#region src/bigconsole/components/DrilldownModal.tsx
8
- var d = n(function({ renderDashboard: n, onClose: d }) {
9
- let p = i(null), m = e((e) => e.isOpen), h = e((e) => e.dashboardId), g = e((e) => e.params), _ = e((e) => e.history), v = e((e) => e.closeModal), y = e((e) => e.popDrilldown), b = r(() => {
10
- v(), d?.();
11
- }, [v, d]), x = r(() => {
12
- y();
13
- }, [y]);
14
- return !m || !h ? null : /* @__PURE__ */ l(a, {
15
- open: m,
9
+ var f = r(function({ renderDashboard: r, onClose: f }) {
10
+ let m = a(null), h = e((e) => e.isOpen), g = e((e) => e.dashboardId), _ = e((e) => e.params), v = e((e) => e.history), y = e((e) => e.closeModal), b = e((e) => e.popDrilldown), x = i(() => {
11
+ y(), f?.();
12
+ }, [y, f]), S = i(() => {
13
+ b();
14
+ }, [b]);
15
+ return !h || !g ? null : /* @__PURE__ */ u(o, {
16
+ open: h,
16
17
  onOpenChange: (e) => {
17
- e || b();
18
+ e || x();
18
19
  },
19
- children: /* @__PURE__ */ u(o, {
20
+ children: /* @__PURE__ */ d(s, {
20
21
  showCloseButton: !1,
21
22
  onOpenAutoFocus: () => {
22
23
  let e = document.activeElement;
23
- e instanceof HTMLElement && e !== document.body && !e.closest("[role=\"dialog\"]") && (p.current = e);
24
+ e instanceof HTMLElement && e !== document.body && !e.closest("[role=\"dialog\"]") && (m.current = e);
24
25
  },
25
26
  onCloseAutoFocus: (e) => {
26
- e.preventDefault(), p.current?.isConnected && p.current.focus();
27
+ e.preventDefault(), m.current?.isConnected && m.current.focus();
27
28
  },
28
29
  className: "flex w-full md:w-[calc(100%-2rem)] max-w-5xl flex-col gap-0 overflow-hidden rounded-card bg-bg-surface p-0 sm:max-w-5xl",
29
30
  style: { maxHeight: "calc(100dvh - 2rem)" },
30
31
  children: [
31
- /* @__PURE__ */ l(s, {
32
+ /* @__PURE__ */ u(c, {
32
33
  className: "sr-only",
33
34
  children: "Explore the linked dashboard and return to the previous drilldown level."
34
35
  }),
35
- /* @__PURE__ */ u("div", {
36
+ /* @__PURE__ */ d("div", {
36
37
  className: "flex flex-shrink-0 flex-wrap items-center justify-between gap-control-gap border-b border-[var(--color-border-subtle)] px-4 py-3",
37
- children: [/* @__PURE__ */ u("div", {
38
+ children: [/* @__PURE__ */ d("div", {
38
39
  className: "flex min-w-0 items-center gap-3",
39
40
  children: [
40
- _.length > 0 && /* @__PURE__ */ l("button", {
41
+ v.length > 0 && /* @__PURE__ */ u("button", {
41
42
  type: "button",
42
- onClick: x,
43
+ onClick: S,
43
44
  className: "flex h-control-md w-[var(--size-controlHeight-md)] shrink-0 items-center justify-center rounded-button motion-safe:transition-colors hover:bg-bg-sunken focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-bg-surface",
44
45
  title: "Go back",
45
46
  "aria-label": "Go back",
46
- children: /* @__PURE__ */ l("svg", {
47
+ children: /* @__PURE__ */ u("svg", {
47
48
  className: "w-5 h-5 text-text-secondary",
48
49
  fill: "none",
49
50
  stroke: "currentColor",
50
51
  viewBox: "0 0 24 24",
51
- children: /* @__PURE__ */ l("path", {
52
+ children: /* @__PURE__ */ u("path", {
52
53
  strokeLinecap: "round",
53
54
  strokeLinejoin: "round",
54
55
  strokeWidth: 2,
@@ -56,33 +57,33 @@ var d = n(function({ renderDashboard: n, onClose: d }) {
56
57
  })
57
58
  })
58
59
  }),
59
- /* @__PURE__ */ l(c, {
60
+ /* @__PURE__ */ u(l, {
60
61
  className: "truncate text-sm font-semibold text-text-primary",
61
62
  children: "Drilldown View"
62
63
  }),
63
- _.length > 0 && /* @__PURE__ */ u("span", {
64
+ v.length > 0 && /* @__PURE__ */ d("span", {
64
65
  className: "text-xs text-text-muted",
65
66
  children: [
66
67
  "(",
67
- _.length + 1,
68
+ v.length + 1,
68
69
  " level",
69
- _.length > 0 ? "s" : "",
70
+ v.length > 0 ? "s" : "",
70
71
  " deep)"
71
72
  ]
72
73
  })
73
74
  ]
74
- }), /* @__PURE__ */ l("button", {
75
+ }), /* @__PURE__ */ u("button", {
75
76
  type: "button",
76
- onClick: b,
77
+ onClick: x,
77
78
  className: `flex h-control-md w-[var(--size-controlHeight-md)] shrink-0 items-center justify-center rounded-button motion-safe:transition-colors hover:bg-bg-sunken ${t}`,
78
79
  title: "Close (Esc)",
79
80
  "aria-label": "Close drilldown",
80
- children: /* @__PURE__ */ l("svg", {
81
+ children: /* @__PURE__ */ u("svg", {
81
82
  className: "w-5 h-5 text-text-secondary",
82
83
  fill: "none",
83
84
  stroke: "currentColor",
84
85
  viewBox: "0 0 24 24",
85
- children: /* @__PURE__ */ l("path", {
86
+ children: /* @__PURE__ */ u("path", {
86
87
  strokeLinecap: "round",
87
88
  strokeLinejoin: "round",
88
89
  strokeWidth: 2,
@@ -91,32 +92,32 @@ var d = n(function({ renderDashboard: n, onClose: d }) {
91
92
  })
92
93
  })]
93
94
  }),
94
- /* @__PURE__ */ l("div", {
95
+ /* @__PURE__ */ u("div", {
95
96
  className: "min-h-0 flex-1 overflow-y-auto bg-bg-sunken p-4",
96
- children: n ? n(h, g) : /* @__PURE__ */ l(f, {})
97
+ children: r ? r(g, _) : /* @__PURE__ */ u(p, {})
97
98
  }),
98
- /* @__PURE__ */ l("div", {
99
+ /* @__PURE__ */ u("div", {
99
100
  className: "flex-shrink-0 border-t border-[var(--color-border-subtle)] px-4 py-2",
100
- children: /* @__PURE__ */ u("div", {
101
+ children: /* @__PURE__ */ d("div", {
101
102
  className: "flex flex-wrap items-center justify-between gap-x-4 gap-y-1 text-xs text-text-muted",
102
- children: [/* @__PURE__ */ u("span", { children: [
103
+ children: [/* @__PURE__ */ d("span", { children: [
103
104
  "Parameters:",
104
105
  " ",
105
- Object.keys(g).filter((e) => !e.startsWith("__")).length > 0 ? Object.keys(g).filter((e) => !e.startsWith("__")).join(", ") : "None"
106
- ] }), /* @__PURE__ */ l("span", { children: "Press Esc to close" })]
106
+ n(_).map(([e]) => e).join(", ") || "None"
107
+ ] }), /* @__PURE__ */ u("span", { children: "Press Esc to close" })]
107
108
  })
108
109
  })
109
110
  ]
110
111
  })
111
112
  });
112
113
  });
113
- function f() {
114
- return /* @__PURE__ */ l("div", {
114
+ function p() {
115
+ return /* @__PURE__ */ u("div", {
115
116
  className: "flex items-center justify-center h-full text-sm text-text-secondary",
116
117
  children: "Unable to load drilldown content. Please try again."
117
118
  });
118
119
  }
119
120
  //#endregion
120
- export { d as default };
121
+ export { f as default };
121
122
 
122
123
  //# sourceMappingURL=DrilldownModal.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DrilldownModal.js","names":[],"sources":["../../../src/bigconsole/components/DrilldownModal.tsx"],"sourcesContent":["/**\n * DrilldownModal Component\n *\n * Modal overlay for displaying drilldown dashboards.\n * Supports nested drilldowns with back navigation.\n */\n\nimport { type FC, useCallback, useRef, memo } from 'react';\nimport { useDrilldownStore } from '../store/drilldownStore';\nimport { SECTION_FOCUS_RING } from './common';\nimport {\n ResponsiveDialog as Dialog,\n ResponsiveDialogContent as DialogContent,\n ResponsiveDialogTitle as DialogTitle,\n ResponsiveDialogDescription as DialogDescription,\n} from '@burdenoff/fe-libs/ui';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface DrilldownModalProps {\n /** Custom content renderer for the dashboard */\n renderDashboard?: (dashboardId: string, params: Record<string, unknown>) => React.ReactNode;\n /** Called when modal closes */\n onClose?: () => void;\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const DrilldownModal: FC<DrilldownModalProps> = memo(function DrilldownModal({ renderDashboard, onClose }) {\n const returnFocus = useRef<HTMLElement | null>(null);\n const isOpen = useDrilldownStore((state) => state.isOpen);\n const dashboardId = useDrilldownStore((state) => state.dashboardId);\n const params = useDrilldownStore((state) => state.params);\n const history = useDrilldownStore((state) => state.history);\n const closeModal = useDrilldownStore((state) => state.closeModal);\n const popDrilldown = useDrilldownStore((state) => state.popDrilldown);\n\n // Define handlers before effects that use them\n const handleClose = useCallback(() => {\n closeModal();\n onClose?.();\n }, [closeModal, onClose]);\n\n const handleBack = useCallback(() => {\n popDrilldown();\n }, [popDrilldown]);\n\n if (!isOpen || !dashboardId) {\n return null;\n }\n\n return (\n <Dialog\n open={isOpen}\n onOpenChange={(open) => {\n if (!open) handleClose();\n }}\n >\n <DialogContent\n showCloseButton={false}\n onOpenAutoFocus={() => {\n const activeElement = document.activeElement;\n if (\n activeElement instanceof HTMLElement &&\n activeElement !== document.body &&\n !activeElement.closest('[role=\"dialog\"]')\n ) {\n returnFocus.current = activeElement;\n }\n }}\n onCloseAutoFocus={(event) => {\n event.preventDefault();\n if (returnFocus.current?.isConnected) returnFocus.current.focus();\n }}\n className=\"flex w-full md:w-[calc(100%-2rem)] max-w-5xl flex-col gap-0 overflow-hidden rounded-card bg-bg-surface p-0 sm:max-w-5xl\"\n style={{ maxHeight: 'calc(100dvh - 2rem)' }}\n >\n <DialogDescription className=\"sr-only\">\n Explore the linked dashboard and return to the previous drilldown level.\n </DialogDescription>\n {/* Header — bare chrome: identity + close, no surface of its own */}\n <div className=\"flex flex-shrink-0 flex-wrap items-center justify-between gap-control-gap border-b border-[var(--color-border-subtle)] px-4 py-3\">\n <div className=\"flex min-w-0 items-center gap-3\">\n {/* Back button */}\n {history.length > 0 && (\n <button\n type=\"button\"\n onClick={handleBack}\n className={`flex h-control-md w-[var(--size-controlHeight-md)] shrink-0 items-center justify-center rounded-button motion-safe:transition-colors hover:bg-bg-sunken ${SECTION_FOCUS_RING}`}\n title=\"Go back\"\n aria-label=\"Go back\"\n >\n <svg className=\"w-5 h-5 text-text-secondary\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M15 19l-7-7 7-7\" />\n </svg>\n </button>\n )}\n\n {/* Title */}\n <DialogTitle className=\"truncate text-sm font-semibold text-text-primary\">Drilldown View</DialogTitle>\n\n {/* Breadcrumb indicator */}\n {history.length > 0 && (\n <span className=\"text-xs text-text-muted\">\n ({history.length + 1} level{history.length > 0 ? 's' : ''} deep)\n </span>\n )}\n </div>\n\n {/* Close button */}\n <button\n type=\"button\"\n onClick={handleClose}\n className={`flex h-control-md w-[var(--size-controlHeight-md)] shrink-0 items-center justify-center rounded-button motion-safe:transition-colors hover:bg-bg-sunken ${SECTION_FOCUS_RING}`}\n title=\"Close (Esc)\"\n aria-label=\"Close drilldown\"\n >\n <svg className=\"w-5 h-5 text-text-secondary\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n {/* Dashboard Content — the point of the overlay, so it gets the surface\n weight and the chrome around it stays flat. */}\n <div className=\"min-h-0 flex-1 overflow-y-auto bg-bg-sunken p-4\">\n {renderDashboard ? renderDashboard(dashboardId, params) : <DrilldownFallback />}\n </div>\n\n {/* Footer — supporting detail only */}\n <div className=\"flex-shrink-0 border-t border-[var(--color-border-subtle)] px-4 py-2\">\n <div className=\"flex flex-wrap items-center justify-between gap-x-4 gap-y-1 text-xs text-text-muted\">\n <span>\n Parameters:{' '}\n {Object.keys(params).filter((k) => !k.startsWith('__')).length > 0\n ? Object.keys(params)\n .filter((k) => !k.startsWith('__'))\n .join(', ')\n : 'None'}\n </span>\n <span>Press Esc to close</span>\n </div>\n </div>\n </DialogContent>\n </Dialog>\n );\n});\n\n// Fallback when no renderDashboard prop is provided (should not happen in normal usage\n// since BigConsoleRoot always passes DrilldownDashboardRenderer).\nfunction DrilldownFallback() {\n return (\n <div className=\"flex items-center justify-center h-full text-sm text-text-secondary\">\n Unable to load drilldown content. Please try again.\n </div>\n );\n}\n\nexport default DrilldownModal;\n"],"mappings":";;;;;;;AAgCA,IAAa,IAA0C,EAAK,SAAwB,EAAE,oBAAiB,cAAW;CAChH,IAAM,IAAc,EAA2B,KAAK,EAC9C,IAAS,GAAmB,MAAU,EAAM,OAAO,EACnD,IAAc,GAAmB,MAAU,EAAM,YAAY,EAC7D,IAAS,GAAmB,MAAU,EAAM,OAAO,EACnD,IAAU,GAAmB,MAAU,EAAM,QAAQ,EACrD,IAAa,GAAmB,MAAU,EAAM,WAAW,EAC3D,IAAe,GAAmB,MAAU,EAAM,aAAa,EAG/D,IAAc,QAAkB;AAEpC,EADA,GAAY,EACZ,KAAW;IACV,CAAC,GAAY,EAAQ,CAAC,EAEnB,IAAa,QAAkB;AACnC,KAAc;IACb,CAAC,EAAa,CAAC;AAMlB,QAJI,CAAC,KAAU,CAAC,IACP,OAIP,kBAAC,GAAD;EACE,MAAM;EACN,eAAe,MAAS;AACtB,GAAK,KAAM,GAAa;;YAG1B,kBAAC,GAAD;GACE,iBAAiB;GACjB,uBAAuB;IACrB,IAAM,IAAgB,SAAS;AAC/B,IACE,aAAyB,eACzB,MAAkB,SAAS,QAC3B,CAAC,EAAc,QAAQ,oBAAkB,KAEzC,EAAY,UAAU;;GAG1B,mBAAmB,MAAU;AAE3B,IADA,EAAM,gBAAgB,EAClB,EAAY,SAAS,eAAa,EAAY,QAAQ,OAAO;;GAEnE,WAAU;GACV,OAAO,EAAE,WAAW,uBAAuB;aAjB7C;IAmBE,kBAAC,GAAD;KAAmB,WAAU;eAAU;KAEnB,CAAA;IAEpB,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OAEG,EAAQ,SAAS,KAChB,kBAAC,UAAD;QACE,MAAK;QACL,SAAS;QACT,WAAW;QACX,OAAM;QACN,cAAW;kBAEX,kBAAC,OAAD;SAAK,WAAU;SAA8B,MAAK;SAAO,QAAO;SAAe,SAAQ;mBACrF,kBAAC,QAAD;UAAM,eAAc;UAAQ,gBAAe;UAAQ,aAAa;UAAG,GAAE;UAAoB,CAAA;SACrF,CAAA;QACC,CAAA;OAIX,kBAAC,GAAD;QAAa,WAAU;kBAAmD;QAA4B,CAAA;OAGrG,EAAQ,SAAS,KAChB,kBAAC,QAAD;QAAM,WAAU;kBAAhB;SAA0C;SACtC,EAAQ,SAAS;SAAE;SAAO,EAAQ,SAAS,IAAI,MAAM;SAAG;SACrD;;OAEL;SAGN,kBAAC,UAAD;MACE,MAAK;MACL,SAAS;MACT,WAAW,2JAA2J;MACtK,OAAM;MACN,cAAW;gBAEX,kBAAC,OAAD;OAAK,WAAU;OAA8B,MAAK;OAAO,QAAO;OAAe,SAAQ;iBACrF,kBAAC,QAAD;QAAM,eAAc;QAAQ,gBAAe;QAAQ,aAAa;QAAG,GAAE;QAAyB,CAAA;OAC1F,CAAA;MACC,CAAA,CACL;;IAIN,kBAAC,OAAD;KAAK,WAAU;eACZ,IAAkB,EAAgB,GAAa,EAAO,GAAG,kBAAC,GAAD,EAAqB,CAAA;KAC3E,CAAA;IAGN,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,QAAD,EAAA,UAAA;OAAM;OACQ;OACX,OAAO,KAAK,EAAO,CAAC,QAAQ,MAAM,CAAC,EAAE,WAAW,KAAK,CAAC,CAAC,SAAS,IAC7D,OAAO,KAAK,EAAO,CAChB,QAAQ,MAAM,CAAC,EAAE,WAAW,KAAK,CAAC,CAClC,KAAK,KAAK,GACb;OACC,EAAA,CAAA,EACP,kBAAC,QAAD,EAAA,UAAM,sBAAyB,CAAA,CAC3B;;KACF,CAAA;IACQ;;EACT,CAAA;EAEX;AAIF,SAAS,IAAoB;AAC3B,QACE,kBAAC,OAAD;EAAK,WAAU;YAAsE;EAE/E,CAAA"}
1
+ {"version":3,"file":"DrilldownModal.js","names":[],"sources":["../../../src/bigconsole/components/DrilldownModal.tsx"],"sourcesContent":["/**\n * DrilldownModal Component\n *\n * Modal overlay for displaying drilldown dashboards.\n * Supports nested drilldowns with back navigation.\n */\n\nimport { type FC, useCallback, useRef, memo } from 'react';\nimport { useDrilldownStore } from '../store/drilldownStore';\nimport { SECTION_FOCUS_RING } from './common';\nimport { getVisibleDrilldownParams } from '../utils/drilldownParams';\nimport {\n ResponsiveDialog as Dialog,\n ResponsiveDialogContent as DialogContent,\n ResponsiveDialogTitle as DialogTitle,\n ResponsiveDialogDescription as DialogDescription,\n} from '@burdenoff/fe-libs/ui';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface DrilldownModalProps {\n /** Custom content renderer for the dashboard */\n renderDashboard?: (dashboardId: string, params: Record<string, unknown>) => React.ReactNode;\n /** Called when modal closes */\n onClose?: () => void;\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const DrilldownModal: FC<DrilldownModalProps> = memo(function DrilldownModal({ renderDashboard, onClose }) {\n const returnFocus = useRef<HTMLElement | null>(null);\n const isOpen = useDrilldownStore((state) => state.isOpen);\n const dashboardId = useDrilldownStore((state) => state.dashboardId);\n const params = useDrilldownStore((state) => state.params);\n const history = useDrilldownStore((state) => state.history);\n const closeModal = useDrilldownStore((state) => state.closeModal);\n const popDrilldown = useDrilldownStore((state) => state.popDrilldown);\n\n // Define handlers before effects that use them\n const handleClose = useCallback(() => {\n closeModal();\n onClose?.();\n }, [closeModal, onClose]);\n\n const handleBack = useCallback(() => {\n popDrilldown();\n }, [popDrilldown]);\n\n if (!isOpen || !dashboardId) {\n return null;\n }\n\n return (\n <Dialog\n open={isOpen}\n onOpenChange={(open) => {\n if (!open) handleClose();\n }}\n >\n <DialogContent\n showCloseButton={false}\n onOpenAutoFocus={() => {\n const activeElement = document.activeElement;\n if (\n activeElement instanceof HTMLElement &&\n activeElement !== document.body &&\n !activeElement.closest('[role=\"dialog\"]')\n ) {\n returnFocus.current = activeElement;\n }\n }}\n onCloseAutoFocus={(event) => {\n event.preventDefault();\n if (returnFocus.current?.isConnected) returnFocus.current.focus();\n }}\n className=\"flex w-full md:w-[calc(100%-2rem)] max-w-5xl flex-col gap-0 overflow-hidden rounded-card bg-bg-surface p-0 sm:max-w-5xl\"\n style={{ maxHeight: 'calc(100dvh - 2rem)' }}\n >\n <DialogDescription className=\"sr-only\">\n Explore the linked dashboard and return to the previous drilldown level.\n </DialogDescription>\n {/* Header — bare chrome: identity + close, no surface of its own */}\n <div className=\"flex flex-shrink-0 flex-wrap items-center justify-between gap-control-gap border-b border-[var(--color-border-subtle)] px-4 py-3\">\n <div className=\"flex min-w-0 items-center gap-3\">\n {/* Back button */}\n {history.length > 0 && (\n <button\n type=\"button\"\n onClick={handleBack}\n className={`flex h-control-md w-[var(--size-controlHeight-md)] shrink-0 items-center justify-center rounded-button motion-safe:transition-colors hover:bg-bg-sunken ${SECTION_FOCUS_RING}`}\n title=\"Go back\"\n aria-label=\"Go back\"\n >\n <svg className=\"w-5 h-5 text-text-secondary\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M15 19l-7-7 7-7\" />\n </svg>\n </button>\n )}\n\n {/* Title */}\n <DialogTitle className=\"truncate text-sm font-semibold text-text-primary\">Drilldown View</DialogTitle>\n\n {/* Breadcrumb indicator */}\n {history.length > 0 && (\n <span className=\"text-xs text-text-muted\">\n ({history.length + 1} level{history.length > 0 ? 's' : ''} deep)\n </span>\n )}\n </div>\n\n {/* Close button */}\n <button\n type=\"button\"\n onClick={handleClose}\n className={`flex h-control-md w-[var(--size-controlHeight-md)] shrink-0 items-center justify-center rounded-button motion-safe:transition-colors hover:bg-bg-sunken ${SECTION_FOCUS_RING}`}\n title=\"Close (Esc)\"\n aria-label=\"Close drilldown\"\n >\n <svg className=\"w-5 h-5 text-text-secondary\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n {/* Dashboard Content — the point of the overlay, so it gets the surface\n weight and the chrome around it stays flat. */}\n <div className=\"min-h-0 flex-1 overflow-y-auto bg-bg-sunken p-4\">\n {renderDashboard ? renderDashboard(dashboardId, params) : <DrilldownFallback />}\n </div>\n\n {/* Footer — supporting detail only */}\n <div className=\"flex-shrink-0 border-t border-[var(--color-border-subtle)] px-4 py-2\">\n <div className=\"flex flex-wrap items-center justify-between gap-x-4 gap-y-1 text-xs text-text-muted\">\n <span>\n Parameters:{' '}\n {getVisibleDrilldownParams(params)\n .map(([key]) => key)\n .join(', ') || 'None'}\n </span>\n <span>Press Esc to close</span>\n </div>\n </div>\n </DialogContent>\n </Dialog>\n );\n});\n\n// Fallback when no renderDashboard prop is provided (should not happen in normal usage\n// since BigConsoleRoot always passes DrilldownDashboardRenderer).\nfunction DrilldownFallback() {\n return (\n <div className=\"flex items-center justify-center h-full text-sm text-text-secondary\">\n Unable to load drilldown content. Please try again.\n </div>\n );\n}\n\nexport default DrilldownModal;\n"],"mappings":";;;;;;;;AAiCA,IAAa,IAA0C,EAAK,SAAwB,EAAE,oBAAiB,cAAW;CAChH,IAAM,IAAc,EAA2B,KAAK,EAC9C,IAAS,GAAmB,MAAU,EAAM,OAAO,EACnD,IAAc,GAAmB,MAAU,EAAM,YAAY,EAC7D,IAAS,GAAmB,MAAU,EAAM,OAAO,EACnD,IAAU,GAAmB,MAAU,EAAM,QAAQ,EACrD,IAAa,GAAmB,MAAU,EAAM,WAAW,EAC3D,IAAe,GAAmB,MAAU,EAAM,aAAa,EAG/D,IAAc,QAAkB;AAEpC,EADA,GAAY,EACZ,KAAW;IACV,CAAC,GAAY,EAAQ,CAAC,EAEnB,IAAa,QAAkB;AACnC,KAAc;IACb,CAAC,EAAa,CAAC;AAMlB,QAJI,CAAC,KAAU,CAAC,IACP,OAIP,kBAAC,GAAD;EACE,MAAM;EACN,eAAe,MAAS;AACtB,GAAK,KAAM,GAAa;;YAG1B,kBAAC,GAAD;GACE,iBAAiB;GACjB,uBAAuB;IACrB,IAAM,IAAgB,SAAS;AAC/B,IACE,aAAyB,eACzB,MAAkB,SAAS,QAC3B,CAAC,EAAc,QAAQ,oBAAkB,KAEzC,EAAY,UAAU;;GAG1B,mBAAmB,MAAU;AAE3B,IADA,EAAM,gBAAgB,EAClB,EAAY,SAAS,eAAa,EAAY,QAAQ,OAAO;;GAEnE,WAAU;GACV,OAAO,EAAE,WAAW,uBAAuB;aAjB7C;IAmBE,kBAAC,GAAD;KAAmB,WAAU;eAAU;KAEnB,CAAA;IAEpB,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OAEG,EAAQ,SAAS,KAChB,kBAAC,UAAD;QACE,MAAK;QACL,SAAS;QACT,WAAW;QACX,OAAM;QACN,cAAW;kBAEX,kBAAC,OAAD;SAAK,WAAU;SAA8B,MAAK;SAAO,QAAO;SAAe,SAAQ;mBACrF,kBAAC,QAAD;UAAM,eAAc;UAAQ,gBAAe;UAAQ,aAAa;UAAG,GAAE;UAAoB,CAAA;SACrF,CAAA;QACC,CAAA;OAIX,kBAAC,GAAD;QAAa,WAAU;kBAAmD;QAA4B,CAAA;OAGrG,EAAQ,SAAS,KAChB,kBAAC,QAAD;QAAM,WAAU;kBAAhB;SAA0C;SACtC,EAAQ,SAAS;SAAE;SAAO,EAAQ,SAAS,IAAI,MAAM;SAAG;SACrD;;OAEL;SAGN,kBAAC,UAAD;MACE,MAAK;MACL,SAAS;MACT,WAAW,2JAA2J;MACtK,OAAM;MACN,cAAW;gBAEX,kBAAC,OAAD;OAAK,WAAU;OAA8B,MAAK;OAAO,QAAO;OAAe,SAAQ;iBACrF,kBAAC,QAAD;QAAM,eAAc;QAAQ,gBAAe;QAAQ,aAAa;QAAG,GAAE;QAAyB,CAAA;OAC1F,CAAA;MACC,CAAA,CACL;;IAIN,kBAAC,OAAD;KAAK,WAAU;eACZ,IAAkB,EAAgB,GAAa,EAAO,GAAG,kBAAC,GAAD,EAAqB,CAAA;KAC3E,CAAA;IAGN,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,QAAD,EAAA,UAAA;OAAM;OACQ;OACX,EAA0B,EAAO,CAC/B,KAAK,CAAC,OAAS,EAAI,CACnB,KAAK,KAAK,IAAI;OACZ,EAAA,CAAA,EACP,kBAAC,QAAD,EAAA,UAAM,sBAAyB,CAAA,CAC3B;;KACF,CAAA;IACQ;;EACT,CAAA;EAEX;AAIF,SAAS,IAAoB;AAC3B,QACE,kBAAC,OAAD;EAAK,WAAU;YAAsE;EAE/E,CAAA"}
@@ -0,0 +1,3 @@
1
+ /** Display only meaningful context; the original drilldown parameters remain unchanged. */
2
+ export declare function getVisibleDrilldownParams(params: Record<string, unknown>): Array<[string, unknown]>;
3
+ //# sourceMappingURL=drilldownParams.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drilldownParams.d.ts","sourceRoot":"","sources":["../../../src/bigconsole/utils/drilldownParams.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAOnG"}
@@ -0,0 +1,8 @@
1
+ //#region src/bigconsole/utils/drilldownParams.ts
2
+ function e(e) {
3
+ return Object.entries(e).filter(([e, t]) => e.startsWith("__") || t == null ? !1 : typeof t == "string" ? t.trim().length > 0 : Array.isArray(t) ? t.length > 0 : !0);
4
+ }
5
+ //#endregion
6
+ export { e as getVisibleDrilldownParams };
7
+
8
+ //# sourceMappingURL=drilldownParams.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drilldownParams.js","names":[],"sources":["../../../src/bigconsole/utils/drilldownParams.ts"],"sourcesContent":["/** Display only meaningful context; the original drilldown parameters remain unchanged. */\nexport function getVisibleDrilldownParams(params: Record<string, unknown>): Array<[string, unknown]> {\n return Object.entries(params).filter(([key, value]) => {\n if (key.startsWith('__') || value === null || value === undefined) return false;\n if (typeof value === 'string') return value.trim().length > 0;\n if (Array.isArray(value)) return value.length > 0;\n return true;\n });\n}\n"],"mappings":";AACA,SAAgB,EAA0B,GAA2D;AACnG,QAAO,OAAO,QAAQ,EAAO,CAAC,QAAQ,CAAC,GAAK,OACtC,EAAI,WAAW,KAAK,IAAI,KAAU,OAAoC,KACtE,OAAO,KAAU,WAAiB,EAAM,MAAM,CAAC,SAAS,IACxD,MAAM,QAAQ,EAAM,GAAS,EAAM,SAAS,IACzC,GACP"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-bigconsole",
3
- "version": "2026.1004.4",
3
+ "version": "2026.1004.5",
4
4
  "description": "BigConsole - AI-powered analytics and dashboard platform",
5
5
  "type": "module",
6
6
  "files": [
@@ -13,6 +13,7 @@
13
13
  "types": "./dist/index.d.ts",
14
14
  "import": "./dist/index.js"
15
15
  },
16
+ "./styles.css": "./dist/microfe-bigconsole.css",
16
17
  "./assistant": {
17
18
  "types": "./dist/bigconsole/assistant/index.d.ts",
18
19
  "import": "./dist/bigconsole/assistant/index.js"