@burdenoff/microfe-bigconsole 2026.624.2 → 2026.625.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.
Files changed (71) hide show
  1. package/dist/bigconsole/BigConsoleRoutes.js +93 -93
  2. package/dist/bigconsole/assistant/assistantApi.js +215 -0
  3. package/dist/bigconsole/assistant/assistantApi.js.map +1 -0
  4. package/dist/bigconsole/assistant/createSandboxAssistantTransport.js +119 -0
  5. package/dist/bigconsole/assistant/createSandboxAssistantTransport.js.map +1 -0
  6. package/dist/bigconsole/assistant/index.js +2 -0
  7. package/dist/bigconsole/assistant/pageContext.js +51 -0
  8. package/dist/bigconsole/assistant/pageContext.js.map +1 -0
  9. package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js +48 -48
  10. package/dist/bigconsole/components/dashboard/DashboardToolbar.js +52 -52
  11. package/dist/bigconsole/components/dashboard/DrilldownBreadcrumb.js.map +1 -1
  12. package/dist/bigconsole/components/dashboard/ExportDashboardDialog.js +33 -33
  13. package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js +179 -179
  14. package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js.map +1 -1
  15. package/dist/bigconsole/components/dashboard/WidgetPalette.js +38 -38
  16. package/dist/bigconsole/components/datasink/DataSinkTableViewer.js +32 -32
  17. package/dist/bigconsole/components/datasink/ExportDataSinkDialog.js +31 -31
  18. package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js +98 -98
  19. package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js.map +1 -1
  20. package/dist/bigconsole/components/parser/ExportParserDialog.js +31 -31
  21. package/dist/bigconsole/components/parser/ImportParserDialog.js +162 -162
  22. package/dist/bigconsole/components/parser/ImportParserDialog.js.map +1 -1
  23. package/dist/bigconsole/components/widgets/ActionConfigDialog.js +79 -79
  24. package/dist/bigconsole/components/widgets/ActionConfigDialog.js.map +1 -1
  25. package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js.map +1 -1
  26. package/dist/bigconsole/components/widgets/PropertiesPanel.js +307 -307
  27. package/dist/bigconsole/components/widgets/PropertiesPanel.js.map +1 -1
  28. package/dist/bigconsole/components/widgets/WidgetConfigDialog.js +222 -222
  29. package/dist/bigconsole/components/widgets/WidgetConfigDialog.js.map +1 -1
  30. package/dist/bigconsole/components/widgets/WidgetTypeSelector.js +23 -23
  31. package/dist/bigconsole/index.js +3 -0
  32. package/dist/bigconsole/pages/DashboardBuilderPage.js +74 -74
  33. package/dist/bigconsole/pages/DashboardBuilderPage.js.map +1 -1
  34. package/dist/bigconsole/pages/DashboardViewPage.js +168 -189
  35. package/dist/bigconsole/pages/DashboardViewPage.js.map +1 -1
  36. package/dist/bigconsole/pages/DashboardsPage.js +266 -310
  37. package/dist/bigconsole/pages/DashboardsPage.js.map +1 -1
  38. package/dist/bigconsole/pages/DataParsersPage.js +148 -194
  39. package/dist/bigconsole/pages/DataParsersPage.js.map +1 -1
  40. package/dist/bigconsole/pages/DataSinkBuilderPage.js +252 -246
  41. package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
  42. package/dist/bigconsole/pages/DataSinkViewPage.js +256 -231
  43. package/dist/bigconsole/pages/DataSinkViewPage.js.map +1 -1
  44. package/dist/bigconsole/pages/DataSinksPage.js +173 -219
  45. package/dist/bigconsole/pages/DataSinksPage.js.map +1 -1
  46. package/dist/bigconsole/pages/HomePage.js +125 -141
  47. package/dist/bigconsole/pages/HomePage.js.map +1 -1
  48. package/dist/bigconsole/pages/InsightsPage.js +159 -184
  49. package/dist/bigconsole/pages/InsightsPage.js.map +1 -1
  50. package/dist/bigconsole/pages/ParserBuilderPage.js +401 -393
  51. package/dist/bigconsole/pages/ParserBuilderPage.js.map +1 -1
  52. package/dist/bigconsole/pages/ParserViewPage.js +220 -201
  53. package/dist/bigconsole/pages/ParserViewPage.js.map +1 -1
  54. package/dist/bigconsole/pages/PipelineBuilderPage.js +212 -206
  55. package/dist/bigconsole/pages/PipelineBuilderPage.js.map +1 -1
  56. package/dist/bigconsole/pages/PipelineViewPage.js +204 -181
  57. package/dist/bigconsole/pages/PipelineViewPage.js.map +1 -1
  58. package/dist/bigconsole/pages/PipelinesPage.js +107 -150
  59. package/dist/bigconsole/pages/PipelinesPage.js.map +1 -1
  60. package/dist/bigconsole/pages/SettingsPage.js +184 -171
  61. package/dist/bigconsole/pages/SettingsPage.js.map +1 -1
  62. package/dist/bigconsole/pages/WidgetDemoPage.js +69 -81
  63. package/dist/bigconsole/pages/WidgetDemoPage.js.map +1 -1
  64. package/dist/bigconsole/pages/WorkflowViewPage.js +230 -216
  65. package/dist/bigconsole/pages/WorkflowViewPage.js.map +1 -1
  66. package/dist/bigconsole/pages/WorkflowsPage.js +106 -149
  67. package/dist/bigconsole/pages/WorkflowsPage.js.map +1 -1
  68. package/dist/generated/wspace-operations.js +87 -36
  69. package/dist/generated/wspace-operations.js.map +1 -1
  70. package/dist/index.js +3 -1
  71. package/package.json +6 -2
@@ -11,14 +11,14 @@ import c from "../hooks/usePageOperations.js";
11
11
  import "../hooks/index.js";
12
12
  import l from "../components/widgets/WidgetTypeSelector.js";
13
13
  import { findNextAvailablePosition as u } from "../utils/widgetPositioning.js";
14
- import ee from "../components/dashboard/DashboardCanvas.js";
15
- import d from "../components/dashboard/ExportDashboardDialog.js";
14
+ import d from "../components/dashboard/DashboardCanvas.js";
15
+ import f from "../components/dashboard/ExportDashboardDialog.js";
16
16
  import "../components/dashboard/index.js";
17
- import { memo as f, useCallback as p, useEffect as m, useState as h } from "react";
18
- import { useParams as g } from "react-router-dom";
19
- import { ArrowLeft as te } from "lucide-react";
20
- import { jsx as _, jsxs as v } from "react/jsx-runtime";
21
- import { Button as y } from "@burdenoff/fe-libs/ui";
17
+ import { memo as p, useCallback as m, useEffect as h, useState as g } from "react";
18
+ import { useParams as _ } from "react-router-dom";
19
+ import { ArrowLeft as ee } from "lucide-react";
20
+ import { Button as te } from "@burdenoff/fe-libs/ui";
21
+ import { jsx as v, jsxs as y } from "react/jsx-runtime";
22
22
  //#region src/bigconsole/pages/DashboardBuilderPage.tsx
23
23
  function b() {
24
24
  try {
@@ -35,18 +35,18 @@ function ne(e) {
35
35
  let t = b();
36
36
  t?.unregister && t.unregister(e);
37
37
  }
38
- var S = f(function() {
39
- let { dashboardId: f } = g(), b = r(), { workspaceId: S, apiGatewayUrl: C, authToken: w } = n(), { definitions: T } = a({
38
+ var S = p(function() {
39
+ let { dashboardId: p } = _(), b = r(), { workspaceId: S, apiGatewayUrl: C, authToken: w } = n(), { definitions: T } = a({
40
40
  workspaceId: S,
41
41
  apiGatewayUrl: C,
42
42
  authToken: w
43
- }), [E, D] = h(!1), [re, O] = h(!1), [ie, k] = h(!1), [A, j] = h(null), { fetchDashboard: M, updateDashboard: N, loading: P, error: F } = s(), { createWidget: I, updateWidget: L, deleteWidget: R, duplicateWidget: z, batchUpdatePositions: B } = o(void 0, f), { createPage: V, updatePage: H, deletePage: U, reorderPages: W } = c(), G = t((e) => e.setCurrentDashboard), K = t((e) => e.currentDashboard), q = t((e) => e.setViewMode), J = e((e) => e.selectWidget), Y = e((e) => e.widgets), X = e((e) => e.clipboardWidgetId), Z = e((e) => e.clipboardAction), Q = e((e) => e.clearClipboard);
44
- m(() => (q("edit"), () => q("view")), [q]), m(() => {
45
- if (!f) {
43
+ }), [E, D] = g(!1), [re, O] = g(!1), [ie, k] = g(!1), [A, j] = g(null), { fetchDashboard: M, updateDashboard: N, loading: P, error: F } = s(), { createWidget: I, updateWidget: L, deleteWidget: R, duplicateWidget: z, batchUpdatePositions: B } = o(void 0, p), { createPage: V, updatePage: H, deletePage: U, reorderPages: W } = c(), G = t((e) => e.setCurrentDashboard), K = t((e) => e.currentDashboard), q = t((e) => e.setViewMode), J = e((e) => e.selectWidget), Y = e((e) => e.widgets), X = e((e) => e.clipboardWidgetId), Z = e((e) => e.clipboardAction), Q = e((e) => e.clearClipboard);
44
+ h(() => (q("edit"), () => q("view")), [q]), h(() => {
45
+ if (!p) {
46
46
  b("/dashboards");
47
47
  return;
48
48
  }
49
- return M(f).then((e) => {
49
+ return M(p).then((e) => {
50
50
  e ? (G({
51
51
  id: e.id,
52
52
  title: e.name,
@@ -59,19 +59,19 @@ var S = f(function() {
59
59
  })),
60
60
  createdAt: e.createdAt,
61
61
  updatedAt: e.updatedAt
62
- }), e.pages.length > 0 && !A && j(e.pages[0].id), e.name && x(f, e.name)) : b("/dashboards");
62
+ }), e.pages.length > 0 && !A && j(e.pages[0].id), e.name && x(p, e.name)) : b("/dashboards");
63
63
  }), () => {
64
- f && ne(f);
64
+ p && ne(p);
65
65
  };
66
66
  }, [
67
- f,
67
+ p,
68
68
  b,
69
69
  G,
70
70
  M,
71
71
  A
72
72
  ]);
73
- let ae = p(async () => {
74
- if (!X || !f || !K?.pages?.[0]?.id) return;
73
+ let ae = m(async () => {
74
+ if (!X || !p || !K?.pages?.[0]?.id) return;
75
75
  let e = Y.get(X);
76
76
  if (!e) {
77
77
  Q();
@@ -91,7 +91,7 @@ var S = f(function() {
91
91
  } catch {}
92
92
  c ||= await I({
93
93
  pageId: t,
94
- dashboardId: f,
94
+ dashboardId: p,
95
95
  type: e.type,
96
96
  title: s,
97
97
  description: e.description,
@@ -107,7 +107,7 @@ var S = f(function() {
107
107
  }, [
108
108
  X,
109
109
  Z,
110
- f,
110
+ p,
111
111
  K,
112
112
  Y,
113
113
  z,
@@ -115,14 +115,14 @@ var S = f(function() {
115
115
  R,
116
116
  J,
117
117
  Q
118
- ]), oe = p(async (e) => {
119
- if (!f || !K?.pages?.[0]?.id) return;
118
+ ]), oe = m(async (e) => {
119
+ if (!p || !K?.pages?.[0]?.id) return;
120
120
  let t = K.pages[0].id, n = e.replace(/_/g, " ").toLowerCase().replace(/^\w/, (e) => e.toUpperCase()), r = Array.from(Y.values()), a = T.find((t) => t.type === e) ?? i(e), o = {
121
121
  width: a?.defaultSize?.width ?? 4,
122
122
  height: a?.defaultSize?.height ?? 4
123
123
  }, { x: s, y: c } = u(r, o, { cols: 12 }), l = await I({
124
124
  pageId: t,
125
- dashboardId: f,
125
+ dashboardId: p,
126
126
  type: e,
127
127
  title: n,
128
128
  config: {},
@@ -135,16 +135,16 @@ var S = f(function() {
135
135
  });
136
136
  l && (J(l.id), D(!1));
137
137
  }, [
138
- f,
138
+ p,
139
139
  K,
140
140
  I,
141
141
  J,
142
142
  Y,
143
143
  T
144
- ]), se = p(() => {
144
+ ]), se = m(() => {
145
145
  b("/dashboards");
146
- }, [b]), $ = p(async () => {
147
- if (f) {
146
+ }, [b]), $ = m(async () => {
147
+ if (p) {
148
148
  O(!0);
149
149
  try {
150
150
  let t = e.getState(), n = Array.from(t.widgets.values()), r = t.dirtyWidgetIds, i = n.filter((e) => r.has(e.id));
@@ -177,7 +177,7 @@ var S = f(function() {
177
177
  height: e.positionHeight ?? 4
178
178
  }
179
179
  }))), K && await N({
180
- id: f,
180
+ id: p,
181
181
  name: K.title,
182
182
  description: K.description
183
183
  });
@@ -186,21 +186,21 @@ var S = f(function() {
186
186
  }
187
187
  }
188
188
  }, [
189
- f,
189
+ p,
190
190
  K,
191
191
  L,
192
192
  B,
193
193
  N
194
- ]), ce = p(() => {
194
+ ]), ce = m(() => {
195
195
  k(!0);
196
- }, []), le = p(() => {
196
+ }, []), le = m(() => {
197
197
  k(!1);
198
- }, []), ue = p((e) => {
198
+ }, []), ue = m((e) => {
199
199
  j(e);
200
- }, []), de = p(async () => {
201
- if (!K || !f) return;
200
+ }, []), de = m(async () => {
201
+ if (!K || !p) return;
202
202
  let e = await V({
203
- dashboardId: f,
203
+ dashboardId: p,
204
204
  name: `Page ${K.pages.length + 1}`
205
205
  });
206
206
  e && (G({
@@ -214,10 +214,10 @@ var S = f(function() {
214
214
  }), j(e.id));
215
215
  }, [
216
216
  K,
217
- f,
217
+ p,
218
218
  G,
219
219
  V
220
- ]), fe = p(async (e, t) => {
220
+ ]), fe = m(async (e, t) => {
221
221
  K && await H({
222
222
  id: e,
223
223
  name: t
@@ -232,12 +232,12 @@ var S = f(function() {
232
232
  K,
233
233
  G,
234
234
  H
235
- ]), pe = p(async (e) => {
236
- if (!K || !f) return;
235
+ ]), pe = m(async (e) => {
236
+ if (!K || !p) return;
237
237
  let t = K.pages.find((t) => t.id === e);
238
238
  if (!t) return;
239
239
  let n = await V({
240
- dashboardId: f,
240
+ dashboardId: p,
241
241
  name: `${t.title} (Copy)`
242
242
  });
243
243
  n && (G({
@@ -251,10 +251,10 @@ var S = f(function() {
251
251
  }), j(n.id));
252
252
  }, [
253
253
  K,
254
- f,
254
+ p,
255
255
  G,
256
256
  V
257
- ]), me = p(async (e) => {
257
+ ]), me = m(async (e) => {
258
258
  if (!(!K || K.pages.length <= 1) && await U(e)) {
259
259
  let t = K.pages.filter((t) => t.id !== e).map((e, t) => ({
260
260
  ...e,
@@ -270,37 +270,37 @@ var S = f(function() {
270
270
  G,
271
271
  A,
272
272
  U
273
- ]), he = p(async (e) => {
274
- !K || !f || (G({
273
+ ]), he = m(async (e) => {
274
+ !K || !p || (G({
275
275
  ...K,
276
276
  pages: e.map((e, t) => ({
277
277
  ...e,
278
278
  index: t
279
279
  }))
280
- }), await W(f, e.map((e) => e.id)));
280
+ }), await W(p, e.map((e) => e.id)));
281
281
  }, [
282
282
  K,
283
- f,
283
+ p,
284
284
  G,
285
285
  W
286
286
  ]);
287
- return P || !K ? /* @__PURE__ */ _("div", {
287
+ return P || !K ? /* @__PURE__ */ v("div", {
288
288
  className: "flex items-center justify-center h-full",
289
- children: /* @__PURE__ */ _("div", { className: "animate-spin w-8 h-8 border-4 border-action-primary-bg border-t-transparent rounded-full" })
290
- }) : F ? /* @__PURE__ */ _("div", {
289
+ children: /* @__PURE__ */ v("div", { className: "animate-spin w-8 h-8 border-4 border-action-primary-bg border-t-transparent rounded-full" })
290
+ }) : F ? /* @__PURE__ */ v("div", {
291
291
  className: "flex flex-col items-center justify-center h-full p-6",
292
- children: /* @__PURE__ */ v("div", {
292
+ children: /* @__PURE__ */ y("div", {
293
293
  className: "bg-status-error-bg border border-status-error-border rounded-lg p-4 max-w-md",
294
294
  children: [
295
- /* @__PURE__ */ _("h3", {
295
+ /* @__PURE__ */ v("h3", {
296
296
  className: "text-sm font-medium text-status-error-text",
297
297
  children: "Failed to load dashboard"
298
298
  }),
299
- /* @__PURE__ */ _("p", {
299
+ /* @__PURE__ */ v("p", {
300
300
  className: "text-sm text-text-secondary mt-1",
301
301
  children: F.message
302
302
  }),
303
- /* @__PURE__ */ _("button", {
303
+ /* @__PURE__ */ v("button", {
304
304
  type: "button",
305
305
  onClick: () => b("/dashboards"),
306
306
  className: "mt-3 px-3 py-1.5 text-sm font-medium text-action-primary-fg bg-action-primary-bg hover:bg-action-primary-bgHover rounded-md",
@@ -308,25 +308,25 @@ var S = f(function() {
308
308
  })
309
309
  ]
310
310
  })
311
- }) : /* @__PURE__ */ v("div", {
311
+ }) : /* @__PURE__ */ y("div", {
312
312
  className: "flex flex-col h-full",
313
- children: [/* @__PURE__ */ v("div", {
313
+ children: [/* @__PURE__ */ y("div", {
314
314
  className: "flex items-center gap-3 px-3 py-2 border-b border-border-default bg-bg-surface flex-shrink-0",
315
- children: [/* @__PURE__ */ v(y, {
315
+ children: [/* @__PURE__ */ y(te, {
316
316
  onClick: se,
317
317
  variant: "ghost",
318
318
  size: "sm",
319
319
  title: "Back to Dashboards",
320
320
  "aria-label": "Back to Dashboards",
321
- children: [/* @__PURE__ */ _(te, { className: "w-4 h-4 mr-2" }), "Back"]
322
- }), /* @__PURE__ */ _("h2", {
321
+ children: [/* @__PURE__ */ v(ee, { className: "w-4 h-4 mr-2" }), "Back"]
322
+ }), /* @__PURE__ */ v("h2", {
323
323
  className: "text-sm font-semibold text-text-primary truncate",
324
324
  children: K.title
325
325
  })]
326
- }), /* @__PURE__ */ v("div", {
326
+ }), /* @__PURE__ */ y("div", {
327
327
  className: "flex flex-1 min-h-0 relative",
328
328
  children: [
329
- /* @__PURE__ */ _("div", {
329
+ /* @__PURE__ */ v("div", {
330
330
  className: `
331
331
  ${E ? "w-72" : "w-0"}
332
332
  flex-shrink-0
@@ -335,23 +335,23 @@ var S = f(function() {
335
335
  transition-all duration-300
336
336
  overflow-hidden
337
337
  `,
338
- children: E && /* @__PURE__ */ v("div", {
338
+ children: E && /* @__PURE__ */ y("div", {
339
339
  className: "h-full flex flex-col",
340
- children: [/* @__PURE__ */ v("div", {
340
+ children: [/* @__PURE__ */ y("div", {
341
341
  className: "flex items-center justify-between p-3 border-b border-border-default",
342
- children: [/* @__PURE__ */ _("h3", {
342
+ children: [/* @__PURE__ */ v("h3", {
343
343
  className: "text-sm font-semibold text-text-primary",
344
344
  children: "Widgets"
345
- }), /* @__PURE__ */ _("button", {
345
+ }), /* @__PURE__ */ v("button", {
346
346
  type: "button",
347
347
  onClick: () => D(!1),
348
348
  className: "\n p-1 rounded-md\n text-text-secondary\n hover:text-text-primary\n hover:bg-bg-sunken\n ",
349
- children: /* @__PURE__ */ _("svg", {
349
+ children: /* @__PURE__ */ v("svg", {
350
350
  className: "w-4 h-4",
351
351
  fill: "none",
352
352
  stroke: "currentColor",
353
353
  viewBox: "0 0 24 24",
354
- children: /* @__PURE__ */ _("path", {
354
+ children: /* @__PURE__ */ v("path", {
355
355
  strokeLinecap: "round",
356
356
  strokeLinejoin: "round",
357
357
  strokeWidth: 2,
@@ -359,26 +359,26 @@ var S = f(function() {
359
359
  })
360
360
  })
361
361
  })]
362
- }), /* @__PURE__ */ _("div", {
362
+ }), /* @__PURE__ */ v("div", {
363
363
  className: "flex-1 overflow-auto",
364
- children: /* @__PURE__ */ _(l, {
364
+ children: /* @__PURE__ */ v(l, {
365
365
  onSelect: oe,
366
366
  definitions: T
367
367
  })
368
368
  })]
369
369
  })
370
370
  }),
371
- !E && /* @__PURE__ */ _("button", {
371
+ !E && /* @__PURE__ */ v("button", {
372
372
  type: "button",
373
373
  onClick: () => D(!0),
374
374
  className: "\n absolute left-0 top-1/2 -translate-y-1/2 z-20\n w-8 h-24\n bg-bg-surface\n border border-l-0 border-border-default\n rounded-r-lg\n flex items-center justify-center\n text-text-secondary\n hover:text-text-primary\n hover:bg-bg-sunken\n transition-colors\n ",
375
375
  title: "Open widget panel",
376
- children: /* @__PURE__ */ _("svg", {
376
+ children: /* @__PURE__ */ v("svg", {
377
377
  className: "w-4 h-4",
378
378
  fill: "none",
379
379
  stroke: "currentColor",
380
380
  viewBox: "0 0 24 24",
381
- children: /* @__PURE__ */ _("path", {
381
+ children: /* @__PURE__ */ v("path", {
382
382
  strokeLinecap: "round",
383
383
  strokeLinejoin: "round",
384
384
  strokeWidth: 2,
@@ -386,9 +386,9 @@ var S = f(function() {
386
386
  })
387
387
  })
388
388
  }),
389
- /* @__PURE__ */ _("div", {
389
+ /* @__PURE__ */ v("div", {
390
390
  className: "flex-1 relative",
391
- children: /* @__PURE__ */ _(ee, {
391
+ children: /* @__PURE__ */ v(d, {
392
392
  dashboardId: K.id,
393
393
  pageId: A || K.pages?.[0]?.id,
394
394
  title: K.title,
@@ -411,7 +411,7 @@ var S = f(function() {
411
411
  showPageTabs: !0
412
412
  })
413
413
  }),
414
- /* @__PURE__ */ _(d, {
414
+ /* @__PURE__ */ v(f, {
415
415
  isOpen: ie,
416
416
  dashboardId: K.id,
417
417
  dashboardName: K.title,
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardBuilderPage.js","names":[],"sources":["../../../src/bigconsole/pages/DashboardBuilderPage.tsx"],"sourcesContent":["/**\n * DashboardBuilderPage\n *\n * Full dashboard builder experience with side panels.\n */\n\nimport { type FC, memo, useState, useEffect, useCallback } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft } from 'lucide-react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { useBigConsoleNavigate, useBigConsole } from '../context';\nimport { DashboardCanvas, ExportDashboardDialog } from '../components/dashboard';\nimport { WidgetTypeSelector } from '../components/widgets/WidgetTypeSelector';\nimport { useDashboardStore, useWidgetStore } from '../store';\nimport { useDashboardOperations, useWidgetOperations, usePageOperations, useWidgetCatalog } from '../hooks';\nimport type { WidgetType, Dashboard, DashboardPage } from '../types';\nimport { findNextAvailablePosition } from '../utils/widgetPositioning';\nimport { getWidgetDefinition } from '../components/widgets/WidgetRegistry';\n\n// Breadcrumb name registration helpers (get from shell at call time to avoid timing issues)\nfunction getBreadcrumbRegistry() {\n try {\n return (\n window as unknown as {\n __breadcrumbRegistry?: { register: (id: string, name: string) => void; unregister: (id: string) => void };\n }\n ).__breadcrumbRegistry;\n } catch {\n return undefined;\n }\n}\n\nfunction registerBreadcrumbName(id: string, name: string) {\n const registry = getBreadcrumbRegistry();\n if (registry?.register) {\n registry.register(id, name);\n }\n}\n\nfunction unregisterBreadcrumbName(id: string) {\n const registry = getBreadcrumbRegistry();\n if (registry?.unregister) {\n registry.unregister(id);\n }\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const DashboardBuilderPage: FC = memo(function DashboardBuilderPage() {\n const { dashboardId } = useParams<{ dashboardId: string }>();\n const navigate = useBigConsoleNavigate();\n const { workspaceId, apiGatewayUrl, authToken } = useBigConsole();\n // Built-in widget catalog from the backend (getWidgetTypes); falls back to the\n // bundled registry while loading or if the supergraph hasn't adopted it yet.\n const { definitions: widgetCatalog } = useWidgetCatalog({ workspaceId, apiGatewayUrl, authToken });\n const [isWidgetPanelOpen, setIsWidgetPanelOpen] = useState(false);\n const [isSaving, setIsSaving] = useState(false);\n const [isExportDialogOpen, setIsExportDialogOpen] = useState(false);\n const [activePageId, setActivePageId] = useState<string | null>(null);\n\n // Dashboard operations from GraphQL\n const {\n fetchDashboard,\n updateDashboard,\n loading: dashboardLoading,\n error: dashboardError,\n } = useDashboardOperations();\n\n // Widget operations from GraphQL\n const {\n createWidget: createWidgetMutation,\n updateWidget: updateWidgetMutation,\n deleteWidget: deleteWidgetMutation,\n duplicateWidget: duplicateWidgetMutation,\n batchUpdatePositions,\n } = useWidgetOperations(undefined, dashboardId);\n\n // Page operations from GraphQL\n const {\n createPage: createPageMutation,\n updatePage: updatePageMutation,\n deletePage: deletePageMutation,\n reorderPages: reorderPagesMutation,\n } = usePageOperations();\n\n // Store actions\n const setCurrentDashboard = useDashboardStore((state) => state.setCurrentDashboard);\n const currentDashboard = useDashboardStore((state) => state.currentDashboard);\n const setViewMode = useDashboardStore((state) => state.setViewMode);\n const selectWidget = useWidgetStore((state) => state.selectWidget);\n const widgets = useWidgetStore((state) => state.widgets);\n const clipboardWidgetId = useWidgetStore((state) => state.clipboardWidgetId);\n const clipboardAction = useWidgetStore((state) => state.clipboardAction);\n const clearClipboard = useWidgetStore((state) => state.clearClipboard);\n\n // Set edit mode on mount\n useEffect(() => {\n setViewMode('edit');\n return () => setViewMode('view');\n }, [setViewMode]);\n\n // Load dashboard data from API\n useEffect(() => {\n if (!dashboardId) {\n navigate('/dashboards');\n return;\n }\n\n // Fetch dashboard from API\n fetchDashboard(dashboardId).then((dashboard) => {\n if (dashboard) {\n setCurrentDashboard({\n id: dashboard.id,\n title: dashboard.name,\n description: dashboard.description || '',\n pages: dashboard.pages.map((page, index) => ({\n id: page.id,\n title: page.name || '',\n index,\n layoutConfig: page.layoutConfig || {},\n })) as any,\n createdAt: dashboard.createdAt,\n updatedAt: dashboard.updatedAt,\n } as unknown as Dashboard);\n // Set active page to first page\n if (dashboard.pages.length > 0 && !activePageId) {\n setActivePageId(dashboard.pages[0].id);\n }\n\n // Register dashboard name for breadcrumb display\n if (dashboard.name) {\n registerBreadcrumbName(dashboardId, dashboard.name);\n }\n } else {\n // Dashboard not found, redirect\n navigate('/dashboards');\n }\n });\n\n // Cleanup: unregister breadcrumb name on unmount\n return () => {\n if (dashboardId) {\n unregisterBreadcrumbName(dashboardId);\n }\n };\n }, [dashboardId, navigate, setCurrentDashboard, fetchDashboard, activePageId]);\n\n // Handle paste widget from clipboard\n const handlePaste = useCallback(async () => {\n if (!clipboardWidgetId || !dashboardId || !currentDashboard?.pages?.[0]?.id) {\n return;\n }\n\n const sourceWidget = widgets.get(clipboardWidgetId);\n if (!sourceWidget) {\n clearClipboard();\n return;\n }\n\n const pageId = currentDashboard.pages[0].id;\n\n // Use smart placement algorithm - horizontal first, then next row\n const widgetsArray = Array.from(widgets.values());\n const widgetSize = {\n width: sourceWidget.positionWidth ?? 4,\n height: sourceWidget.positionHeight ?? 4,\n };\n\n const { x, y } = findNextAvailablePosition(widgetsArray, widgetSize, { cols: 12 });\n\n const newPosition = {\n x,\n y,\n width: widgetSize.width,\n height: widgetSize.height,\n };\n\n const newTitle = clipboardAction === 'copy' ? `${sourceWidget.title} (Copy)` : sourceWidget.title;\n\n let newWidget = null;\n\n // Try duplicateWidget API first\n try {\n newWidget = await duplicateWidgetMutation(clipboardWidgetId, newPosition, newTitle);\n } catch (err) {}\n\n // Fallback: Create new widget with source widget's data\n if (!newWidget) {\n newWidget = await createWidgetMutation({\n pageId,\n dashboardId,\n type: sourceWidget.type,\n title: newTitle,\n description: sourceWidget.description,\n // v2.0: Use dataSinkId and parserId instead of dataSourceId/dataPath\n dataSinkId: sourceWidget.dataSinkId ?? undefined,\n datasetId: sourceWidget.datasetId ?? undefined,\n parserId: sourceWidget.parserId ?? undefined,\n parserRules: sourceWidget.parserRules ?? undefined,\n config: sourceWidget.config || {},\n position: newPosition,\n refreshInterval: sourceWidget.refreshInterval ?? undefined,\n metadata: sourceWidget.metadata,\n });\n }\n\n if (newWidget) {\n selectWidget(newWidget.id);\n\n // If cut action, delete the original widget from backend\n if (clipboardAction === 'cut') {\n await deleteWidgetMutation(clipboardWidgetId);\n }\n }\n\n clearClipboard();\n }, [\n clipboardWidgetId,\n clipboardAction,\n dashboardId,\n currentDashboard,\n widgets,\n duplicateWidgetMutation,\n createWidgetMutation,\n deleteWidgetMutation,\n selectWidget,\n clearClipboard,\n ]);\n\n // Handle quick add widget from panel\n const handleQuickAddWidget = useCallback(\n async (type: WidgetType) => {\n if (!dashboardId || !currentDashboard?.pages?.[0]?.id) return;\n\n const pageId = currentDashboard.pages[0].id;\n const title = type\n .replace(/_/g, ' ')\n .toLowerCase()\n .replace(/^\\w/, (c) => c.toUpperCase());\n\n // Use smart placement algorithm - horizontal first, then next row.\n // Prefer the backend-sourced catalog entry; fall back to the static registry.\n const widgetsArray = Array.from(widgets.values());\n const definition = widgetCatalog.find((d) => d.type === type) ?? getWidgetDefinition(type);\n const widgetSize = {\n width: definition?.defaultSize?.width ?? 4,\n height: definition?.defaultSize?.height ?? 4,\n };\n\n const { x, y } = findNextAvailablePosition(widgetsArray, widgetSize, { cols: 12 });\n\n // Create widget via API\n const newWidget = await createWidgetMutation({\n pageId,\n dashboardId,\n type,\n title,\n config: {},\n position: {\n x,\n y,\n width: widgetSize.width,\n height: widgetSize.height,\n },\n });\n\n if (newWidget) {\n selectWidget(newWidget.id);\n setIsWidgetPanelOpen(false);\n }\n },\n [dashboardId, currentDashboard, createWidgetMutation, selectWidget, widgets, widgetCatalog]\n );\n\n // Navigate back to the dashboards list\n const handleBack = useCallback(() => {\n navigate('/dashboards');\n }, [navigate]);\n\n // Handle save - save dirty widgets and batch update positions\n const handleSave = useCallback(async () => {\n if (!dashboardId) return;\n\n setIsSaving(true);\n try {\n // Get the LATEST state directly from store (avoid stale closure)\n const storeState = useWidgetStore.getState();\n const currentWidgets = Array.from(storeState.widgets.values());\n const currentDirtyIds = storeState.dirtyWidgetIds;\n\n // Debug: Log dirty widget IDs\n\n // 1. Save dirty widgets (property changes like title, config, etc.)\n const dirtyWidgets = currentWidgets.filter((w) => currentDirtyIds.has(w.id));\n\n if (dirtyWidgets.length > 0) {\n // Save each dirty widget\n const updatePromises = dirtyWidgets.map(async (widget) => {\n const updateInput = {\n id: widget.id,\n title: widget.title,\n config: widget.config,\n refreshInterval: widget.refreshInterval ?? undefined,\n // v2.0: Use dataSinkId and parserId instead of dataSourceId/dataPath\n dataSinkId: widget.dataSinkId ?? undefined,\n datasetId: widget.datasetId ?? undefined,\n parserId: widget.parserId ?? undefined,\n parserRules: widget.parserRules ?? undefined,\n };\n\n try {\n const result = await updateWidgetMutation(updateInput);\n return result;\n } catch (err) {\n throw err;\n }\n });\n\n const results = await Promise.all(updatePromises);\n\n // Clear dirty flags after successful save\n storeState.clearAllDirty();\n } else {\n }\n\n // 2. Batch update widget positions\n if (currentWidgets.length > 0) {\n const positionUpdates = currentWidgets.map((widget) => ({\n id: widget.id,\n position: widget.position || {\n x: widget.positionX ?? 0,\n y: widget.positionY ?? 0,\n width: widget.positionWidth ?? 4,\n height: widget.positionHeight ?? 4,\n },\n }));\n\n await batchUpdatePositions(positionUpdates);\n }\n\n // 3. Update dashboard metadata if needed\n if (currentDashboard) {\n await updateDashboard({\n id: dashboardId,\n name: currentDashboard.title,\n description: currentDashboard.description,\n });\n }\n } catch (error) {\n } finally {\n setIsSaving(false);\n }\n }, [dashboardId, currentDashboard, updateWidgetMutation, batchUpdatePositions, updateDashboard]);\n\n // Handle export\n const handleExport = useCallback(() => {\n setIsExportDialogOpen(true);\n }, []);\n\n const handleExportClose = useCallback(() => {\n setIsExportDialogOpen(false);\n }, []);\n\n // ============================================================================\n // Page Management Callbacks\n // ============================================================================\n\n // Handle page selection\n const handlePageChange = useCallback((pageId: string) => {\n setActivePageId(pageId);\n }, []);\n\n // Handle adding a new page\n const handlePageAdd = useCallback(async () => {\n if (!currentDashboard || !dashboardId) return;\n\n const newPageCount = currentDashboard.pages.length + 1;\n const newPageName = `Page ${newPageCount}`;\n\n // Call GraphQL mutation to create page\n // Note: 'order' is not available for create - backend auto-assigns order\n const newPage = await createPageMutation({\n dashboardId,\n name: newPageName,\n });\n\n if (newPage) {\n // Update local state with the created page\n setCurrentDashboard({\n ...currentDashboard,\n pages: [\n ...currentDashboard.pages,\n {\n id: newPage.id,\n title: newPage.name,\n index: newPage.order,\n layoutConfig: newPage.layoutConfig || {},\n },\n ],\n });\n\n // Switch to the new page\n setActivePageId(newPage.id);\n }\n }, [currentDashboard, dashboardId, setCurrentDashboard, createPageMutation]);\n\n // Handle renaming a page\n const handlePageRename = useCallback(\n async (pageId: string, newName: string) => {\n if (!currentDashboard) return;\n\n // Call GraphQL mutation to update page\n const updatedPage = await updatePageMutation({\n id: pageId,\n name: newName,\n });\n\n if (updatedPage) {\n setCurrentDashboard({\n ...currentDashboard,\n pages: currentDashboard.pages.map((page) => (page.id === pageId ? { ...page, title: newName } : page)),\n });\n }\n },\n [currentDashboard, setCurrentDashboard, updatePageMutation]\n );\n\n // Handle duplicating a page\n const handlePageDuplicate = useCallback(\n async (pageId: string) => {\n if (!currentDashboard || !dashboardId) return;\n\n const sourcePage = currentDashboard.pages.find((p) => p.id === pageId);\n if (!sourcePage) return;\n\n // Call GraphQL mutation to create a copy of the page\n // Note: 'order' is not available for create - backend auto-assigns order\n // Note: 'layout' should be PageLayout enum ('GRID', 'FLEX', 'FREEFORM'), not layoutConfig object\n const newPage = await createPageMutation({\n dashboardId,\n name: `${sourcePage.title} (Copy)`,\n });\n\n if (newPage) {\n setCurrentDashboard({\n ...currentDashboard,\n pages: [\n ...currentDashboard.pages,\n {\n id: newPage.id,\n title: newPage.name,\n index: newPage.order,\n layoutConfig: newPage.layoutConfig || {},\n },\n ],\n });\n\n setActivePageId(newPage.id);\n }\n },\n [currentDashboard, dashboardId, setCurrentDashboard, createPageMutation]\n );\n\n // Handle deleting a page\n const handlePageDelete = useCallback(\n async (pageId: string) => {\n if (!currentDashboard || currentDashboard.pages.length <= 1) return;\n\n // Call GraphQL mutation to delete page\n const success = await deletePageMutation(pageId);\n\n if (success) {\n const updatedPages = currentDashboard.pages.filter((p) => p.id !== pageId).map((p, index) => ({ ...p, index }));\n\n setCurrentDashboard({\n ...currentDashboard,\n pages: updatedPages,\n });\n\n // Switch to first page if current page was deleted\n if (activePageId === pageId) {\n setActivePageId(updatedPages[0]?.id || null);\n }\n }\n },\n [currentDashboard, setCurrentDashboard, activePageId, deletePageMutation]\n );\n\n // Handle reordering pages\n const handlePagesReorder = useCallback(\n async (reorderedPages: DashboardPage[]) => {\n if (!currentDashboard || !dashboardId) return;\n\n // Update local state optimistically\n setCurrentDashboard({\n ...currentDashboard,\n pages: reorderedPages.map((page, index) => ({\n ...page,\n index,\n })),\n });\n\n // Call GraphQL mutation to persist the reorder\n const pageIds = reorderedPages.map((p) => p.id);\n await reorderPagesMutation(dashboardId, pageIds);\n },\n [currentDashboard, dashboardId, setCurrentDashboard, reorderPagesMutation]\n );\n\n // Show loading state\n if (dashboardLoading || !currentDashboard) {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <div className=\"animate-spin w-8 h-8 border-4 border-action-primary-bg border-t-transparent rounded-full\" />\n </div>\n );\n }\n\n // Show error state\n if (dashboardError) {\n return (\n <div className=\"flex flex-col items-center justify-center h-full p-6\">\n <div className=\"bg-status-error-bg border border-status-error-border rounded-lg p-4 max-w-md\">\n <h3 className=\"text-sm font-medium text-status-error-text\">Failed to load dashboard</h3>\n <p className=\"text-sm text-text-secondary mt-1\">{dashboardError.message}</p>\n <button\n type=\"button\"\n onClick={() => navigate('/dashboards')}\n className=\"mt-3 px-3 py-1.5 text-sm font-medium text-action-primary-fg bg-action-primary-bg hover:bg-action-primary-bgHover rounded-md\"\n >\n Back to Dashboards\n </button>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col h-full\">\n {/* Header / Toolbar */}\n <div className=\"flex items-center gap-3 px-3 py-2 border-b border-border-default bg-bg-surface flex-shrink-0\">\n <Button\n onClick={handleBack}\n variant=\"ghost\"\n size=\"sm\"\n title=\"Back to Dashboards\"\n aria-label=\"Back to Dashboards\"\n >\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n Back\n </Button>\n <h2 className=\"text-sm font-semibold text-text-primary truncate\">{currentDashboard.title}</h2>\n </div>\n\n {/* Builder Body */}\n <div className=\"flex flex-1 min-h-0 relative\">\n {/* Widget Panel (Left) */}\n <div\n className={`\n ${isWidgetPanelOpen ? 'w-72' : 'w-0'}\n flex-shrink-0\n bg-bg-surface\n border-r border-border-default\n transition-all duration-300\n overflow-hidden\n `}\n >\n {isWidgetPanelOpen && (\n <div className=\"h-full flex flex-col\">\n <div className=\"flex items-center justify-between p-3 border-b border-border-default\">\n <h3 className=\"text-sm font-semibold text-text-primary\">Widgets</h3>\n <button\n type=\"button\"\n onClick={() => setIsWidgetPanelOpen(false)}\n className=\"\n p-1 rounded-md\n text-text-secondary\n hover:text-text-primary\n hover:bg-bg-sunken\n \"\n >\n <svg className=\"w-4 h-4\" 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 <div className=\"flex-1 overflow-auto\">\n <WidgetTypeSelector onSelect={handleQuickAddWidget} definitions={widgetCatalog} />\n </div>\n </div>\n )}\n </div>\n\n {/* Toggle Widget Panel Button */}\n {!isWidgetPanelOpen && (\n <button\n type=\"button\"\n onClick={() => setIsWidgetPanelOpen(true)}\n className=\"\n absolute left-0 top-1/2 -translate-y-1/2 z-20\n w-8 h-24\n bg-bg-surface\n border border-l-0 border-border-default\n rounded-r-lg\n flex items-center justify-center\n text-text-secondary\n hover:text-text-primary\n hover:bg-bg-sunken\n transition-colors\n \"\n title=\"Open widget panel\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n )}\n\n {/* Main Canvas */}\n <div className=\"flex-1 relative\">\n <DashboardCanvas\n dashboardId={currentDashboard.id}\n pageId={activePageId || currentDashboard.pages?.[0]?.id}\n title={currentDashboard.title}\n onPaste={handlePaste}\n onSave={handleSave}\n isSaving={isSaving}\n onExport={handleExport}\n // Page tabs props\n pages={currentDashboard.pages.map((page) => ({\n id: page.id,\n name: page.title || `Page ${(page.index ?? 0) + 1}`,\n order: page.index ?? 0,\n }))}\n activePageId={activePageId || currentDashboard.pages?.[0]?.id}\n onPageChange={handlePageChange}\n onPageAdd={handlePageAdd}\n onPageRename={handlePageRename}\n onPageDuplicate={handlePageDuplicate}\n onPageDelete={handlePageDelete}\n onPagesReorder={handlePagesReorder}\n showPageTabs={true}\n />\n </div>\n\n {/* Export Dashboard Dialog */}\n <ExportDashboardDialog\n isOpen={isExportDialogOpen}\n dashboardId={currentDashboard.id}\n dashboardName={currentDashboard.title}\n onClose={handleExportClose}\n />\n </div>\n </div>\n );\n});\n\nexport default DashboardBuilderPage;\n"],"mappings":"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"}
1
+ {"version":3,"file":"DashboardBuilderPage.js","names":[],"sources":["../../../src/bigconsole/pages/DashboardBuilderPage.tsx"],"sourcesContent":["/**\n * DashboardBuilderPage\n *\n * Full dashboard builder experience with side panels.\n */\n\nimport { type FC, memo, useState, useEffect, useCallback } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft } from 'lucide-react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { useBigConsoleNavigate, useBigConsole } from '../context';\nimport { DashboardCanvas, ExportDashboardDialog } from '../components/dashboard';\nimport { WidgetTypeSelector } from '../components/widgets/WidgetTypeSelector';\nimport { useDashboardStore, useWidgetStore } from '../store';\nimport { useDashboardOperations, useWidgetOperations, usePageOperations, useWidgetCatalog } from '../hooks';\nimport type { WidgetType, Dashboard, DashboardPage } from '../types';\nimport { findNextAvailablePosition } from '../utils/widgetPositioning';\nimport { getWidgetDefinition } from '../components/widgets/WidgetRegistry';\n\n// Breadcrumb name registration helpers (get from shell at call time to avoid timing issues)\nfunction getBreadcrumbRegistry() {\n try {\n return (\n window as unknown as {\n __breadcrumbRegistry?: { register: (id: string, name: string) => void; unregister: (id: string) => void };\n }\n ).__breadcrumbRegistry;\n } catch {\n return undefined;\n }\n}\n\nfunction registerBreadcrumbName(id: string, name: string) {\n const registry = getBreadcrumbRegistry();\n if (registry?.register) {\n registry.register(id, name);\n }\n}\n\nfunction unregisterBreadcrumbName(id: string) {\n const registry = getBreadcrumbRegistry();\n if (registry?.unregister) {\n registry.unregister(id);\n }\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const DashboardBuilderPage: FC = memo(function DashboardBuilderPage() {\n const { dashboardId } = useParams<{ dashboardId: string }>();\n const navigate = useBigConsoleNavigate();\n const { workspaceId, apiGatewayUrl, authToken } = useBigConsole();\n // Built-in widget catalog from the backend (getWidgetTypes); falls back to the\n // bundled registry while loading or if the supergraph hasn't adopted it yet.\n const { definitions: widgetCatalog } = useWidgetCatalog({ workspaceId, apiGatewayUrl, authToken });\n const [isWidgetPanelOpen, setIsWidgetPanelOpen] = useState(false);\n const [isSaving, setIsSaving] = useState(false);\n const [isExportDialogOpen, setIsExportDialogOpen] = useState(false);\n const [activePageId, setActivePageId] = useState<string | null>(null);\n\n // Dashboard operations from GraphQL\n const {\n fetchDashboard,\n updateDashboard,\n loading: dashboardLoading,\n error: dashboardError,\n } = useDashboardOperations();\n\n // Widget operations from GraphQL\n const {\n createWidget: createWidgetMutation,\n updateWidget: updateWidgetMutation,\n deleteWidget: deleteWidgetMutation,\n duplicateWidget: duplicateWidgetMutation,\n batchUpdatePositions,\n } = useWidgetOperations(undefined, dashboardId);\n\n // Page operations from GraphQL\n const {\n createPage: createPageMutation,\n updatePage: updatePageMutation,\n deletePage: deletePageMutation,\n reorderPages: reorderPagesMutation,\n } = usePageOperations();\n\n // Store actions\n const setCurrentDashboard = useDashboardStore((state) => state.setCurrentDashboard);\n const currentDashboard = useDashboardStore((state) => state.currentDashboard);\n const setViewMode = useDashboardStore((state) => state.setViewMode);\n const selectWidget = useWidgetStore((state) => state.selectWidget);\n const widgets = useWidgetStore((state) => state.widgets);\n const clipboardWidgetId = useWidgetStore((state) => state.clipboardWidgetId);\n const clipboardAction = useWidgetStore((state) => state.clipboardAction);\n const clearClipboard = useWidgetStore((state) => state.clearClipboard);\n\n // Set edit mode on mount\n useEffect(() => {\n setViewMode('edit');\n return () => setViewMode('view');\n }, [setViewMode]);\n\n // Load dashboard data from API\n useEffect(() => {\n if (!dashboardId) {\n navigate('/dashboards');\n return;\n }\n\n // Fetch dashboard from API\n fetchDashboard(dashboardId).then((dashboard) => {\n if (dashboard) {\n setCurrentDashboard({\n id: dashboard.id,\n title: dashboard.name,\n description: dashboard.description || '',\n pages: dashboard.pages.map((page, index) => ({\n id: page.id,\n title: page.name || '',\n index,\n layoutConfig: page.layoutConfig || {},\n })) as any,\n createdAt: dashboard.createdAt,\n updatedAt: dashboard.updatedAt,\n } as unknown as Dashboard);\n // Set active page to first page\n if (dashboard.pages.length > 0 && !activePageId) {\n setActivePageId(dashboard.pages[0].id);\n }\n\n // Register dashboard name for breadcrumb display\n if (dashboard.name) {\n registerBreadcrumbName(dashboardId, dashboard.name);\n }\n } else {\n // Dashboard not found, redirect\n navigate('/dashboards');\n }\n });\n\n // Cleanup: unregister breadcrumb name on unmount\n return () => {\n if (dashboardId) {\n unregisterBreadcrumbName(dashboardId);\n }\n };\n }, [dashboardId, navigate, setCurrentDashboard, fetchDashboard, activePageId]);\n\n // Handle paste widget from clipboard\n const handlePaste = useCallback(async () => {\n if (!clipboardWidgetId || !dashboardId || !currentDashboard?.pages?.[0]?.id) {\n return;\n }\n\n const sourceWidget = widgets.get(clipboardWidgetId);\n if (!sourceWidget) {\n clearClipboard();\n return;\n }\n\n const pageId = currentDashboard.pages[0].id;\n\n // Use smart placement algorithm - horizontal first, then next row\n const widgetsArray = Array.from(widgets.values());\n const widgetSize = {\n width: sourceWidget.positionWidth ?? 4,\n height: sourceWidget.positionHeight ?? 4,\n };\n\n const { x, y } = findNextAvailablePosition(widgetsArray, widgetSize, { cols: 12 });\n\n const newPosition = {\n x,\n y,\n width: widgetSize.width,\n height: widgetSize.height,\n };\n\n const newTitle = clipboardAction === 'copy' ? `${sourceWidget.title} (Copy)` : sourceWidget.title;\n\n let newWidget = null;\n\n // Try duplicateWidget API first\n try {\n newWidget = await duplicateWidgetMutation(clipboardWidgetId, newPosition, newTitle);\n } catch (err) {}\n\n // Fallback: Create new widget with source widget's data\n if (!newWidget) {\n newWidget = await createWidgetMutation({\n pageId,\n dashboardId,\n type: sourceWidget.type,\n title: newTitle,\n description: sourceWidget.description,\n // v2.0: Use dataSinkId and parserId instead of dataSourceId/dataPath\n dataSinkId: sourceWidget.dataSinkId ?? undefined,\n datasetId: sourceWidget.datasetId ?? undefined,\n parserId: sourceWidget.parserId ?? undefined,\n parserRules: sourceWidget.parserRules ?? undefined,\n config: sourceWidget.config || {},\n position: newPosition,\n refreshInterval: sourceWidget.refreshInterval ?? undefined,\n metadata: sourceWidget.metadata,\n });\n }\n\n if (newWidget) {\n selectWidget(newWidget.id);\n\n // If cut action, delete the original widget from backend\n if (clipboardAction === 'cut') {\n await deleteWidgetMutation(clipboardWidgetId);\n }\n }\n\n clearClipboard();\n }, [\n clipboardWidgetId,\n clipboardAction,\n dashboardId,\n currentDashboard,\n widgets,\n duplicateWidgetMutation,\n createWidgetMutation,\n deleteWidgetMutation,\n selectWidget,\n clearClipboard,\n ]);\n\n // Handle quick add widget from panel\n const handleQuickAddWidget = useCallback(\n async (type: WidgetType) => {\n if (!dashboardId || !currentDashboard?.pages?.[0]?.id) return;\n\n const pageId = currentDashboard.pages[0].id;\n const title = type\n .replace(/_/g, ' ')\n .toLowerCase()\n .replace(/^\\w/, (c) => c.toUpperCase());\n\n // Use smart placement algorithm - horizontal first, then next row.\n // Prefer the backend-sourced catalog entry; fall back to the static registry.\n const widgetsArray = Array.from(widgets.values());\n const definition = widgetCatalog.find((d) => d.type === type) ?? getWidgetDefinition(type);\n const widgetSize = {\n width: definition?.defaultSize?.width ?? 4,\n height: definition?.defaultSize?.height ?? 4,\n };\n\n const { x, y } = findNextAvailablePosition(widgetsArray, widgetSize, { cols: 12 });\n\n // Create widget via API\n const newWidget = await createWidgetMutation({\n pageId,\n dashboardId,\n type,\n title,\n config: {},\n position: {\n x,\n y,\n width: widgetSize.width,\n height: widgetSize.height,\n },\n });\n\n if (newWidget) {\n selectWidget(newWidget.id);\n setIsWidgetPanelOpen(false);\n }\n },\n [dashboardId, currentDashboard, createWidgetMutation, selectWidget, widgets, widgetCatalog]\n );\n\n // Navigate back to the dashboards list\n const handleBack = useCallback(() => {\n navigate('/dashboards');\n }, [navigate]);\n\n // Handle save - save dirty widgets and batch update positions\n const handleSave = useCallback(async () => {\n if (!dashboardId) return;\n\n setIsSaving(true);\n try {\n // Get the LATEST state directly from store (avoid stale closure)\n const storeState = useWidgetStore.getState();\n const currentWidgets = Array.from(storeState.widgets.values());\n const currentDirtyIds = storeState.dirtyWidgetIds;\n\n // Debug: Log dirty widget IDs\n\n // 1. Save dirty widgets (property changes like title, config, etc.)\n const dirtyWidgets = currentWidgets.filter((w) => currentDirtyIds.has(w.id));\n\n if (dirtyWidgets.length > 0) {\n // Save each dirty widget\n const updatePromises = dirtyWidgets.map(async (widget) => {\n const updateInput = {\n id: widget.id,\n title: widget.title,\n config: widget.config,\n refreshInterval: widget.refreshInterval ?? undefined,\n // v2.0: Use dataSinkId and parserId instead of dataSourceId/dataPath\n dataSinkId: widget.dataSinkId ?? undefined,\n datasetId: widget.datasetId ?? undefined,\n parserId: widget.parserId ?? undefined,\n parserRules: widget.parserRules ?? undefined,\n };\n\n try {\n const result = await updateWidgetMutation(updateInput);\n return result;\n } catch (err) {\n throw err;\n }\n });\n\n const results = await Promise.all(updatePromises);\n\n // Clear dirty flags after successful save\n storeState.clearAllDirty();\n } else {\n }\n\n // 2. Batch update widget positions\n if (currentWidgets.length > 0) {\n const positionUpdates = currentWidgets.map((widget) => ({\n id: widget.id,\n position: widget.position || {\n x: widget.positionX ?? 0,\n y: widget.positionY ?? 0,\n width: widget.positionWidth ?? 4,\n height: widget.positionHeight ?? 4,\n },\n }));\n\n await batchUpdatePositions(positionUpdates);\n }\n\n // 3. Update dashboard metadata if needed\n if (currentDashboard) {\n await updateDashboard({\n id: dashboardId,\n name: currentDashboard.title,\n description: currentDashboard.description,\n });\n }\n } catch (error) {\n } finally {\n setIsSaving(false);\n }\n }, [dashboardId, currentDashboard, updateWidgetMutation, batchUpdatePositions, updateDashboard]);\n\n // Handle export\n const handleExport = useCallback(() => {\n setIsExportDialogOpen(true);\n }, []);\n\n const handleExportClose = useCallback(() => {\n setIsExportDialogOpen(false);\n }, []);\n\n // ============================================================================\n // Page Management Callbacks\n // ============================================================================\n\n // Handle page selection\n const handlePageChange = useCallback((pageId: string) => {\n setActivePageId(pageId);\n }, []);\n\n // Handle adding a new page\n const handlePageAdd = useCallback(async () => {\n if (!currentDashboard || !dashboardId) return;\n\n const newPageCount = currentDashboard.pages.length + 1;\n const newPageName = `Page ${newPageCount}`;\n\n // Call GraphQL mutation to create page\n // Note: 'order' is not available for create - backend auto-assigns order\n const newPage = await createPageMutation({\n dashboardId,\n name: newPageName,\n });\n\n if (newPage) {\n // Update local state with the created page\n setCurrentDashboard({\n ...currentDashboard,\n pages: [\n ...currentDashboard.pages,\n {\n id: newPage.id,\n title: newPage.name,\n index: newPage.order,\n layoutConfig: newPage.layoutConfig || {},\n },\n ],\n });\n\n // Switch to the new page\n setActivePageId(newPage.id);\n }\n }, [currentDashboard, dashboardId, setCurrentDashboard, createPageMutation]);\n\n // Handle renaming a page\n const handlePageRename = useCallback(\n async (pageId: string, newName: string) => {\n if (!currentDashboard) return;\n\n // Call GraphQL mutation to update page\n const updatedPage = await updatePageMutation({\n id: pageId,\n name: newName,\n });\n\n if (updatedPage) {\n setCurrentDashboard({\n ...currentDashboard,\n pages: currentDashboard.pages.map((page) => (page.id === pageId ? { ...page, title: newName } : page)),\n });\n }\n },\n [currentDashboard, setCurrentDashboard, updatePageMutation]\n );\n\n // Handle duplicating a page\n const handlePageDuplicate = useCallback(\n async (pageId: string) => {\n if (!currentDashboard || !dashboardId) return;\n\n const sourcePage = currentDashboard.pages.find((p) => p.id === pageId);\n if (!sourcePage) return;\n\n // Call GraphQL mutation to create a copy of the page\n // Note: 'order' is not available for create - backend auto-assigns order\n // Note: 'layout' should be PageLayout enum ('GRID', 'FLEX', 'FREEFORM'), not layoutConfig object\n const newPage = await createPageMutation({\n dashboardId,\n name: `${sourcePage.title} (Copy)`,\n });\n\n if (newPage) {\n setCurrentDashboard({\n ...currentDashboard,\n pages: [\n ...currentDashboard.pages,\n {\n id: newPage.id,\n title: newPage.name,\n index: newPage.order,\n layoutConfig: newPage.layoutConfig || {},\n },\n ],\n });\n\n setActivePageId(newPage.id);\n }\n },\n [currentDashboard, dashboardId, setCurrentDashboard, createPageMutation]\n );\n\n // Handle deleting a page\n const handlePageDelete = useCallback(\n async (pageId: string) => {\n if (!currentDashboard || currentDashboard.pages.length <= 1) return;\n\n // Call GraphQL mutation to delete page\n const success = await deletePageMutation(pageId);\n\n if (success) {\n const updatedPages = currentDashboard.pages.filter((p) => p.id !== pageId).map((p, index) => ({ ...p, index }));\n\n setCurrentDashboard({\n ...currentDashboard,\n pages: updatedPages,\n });\n\n // Switch to first page if current page was deleted\n if (activePageId === pageId) {\n setActivePageId(updatedPages[0]?.id || null);\n }\n }\n },\n [currentDashboard, setCurrentDashboard, activePageId, deletePageMutation]\n );\n\n // Handle reordering pages\n const handlePagesReorder = useCallback(\n async (reorderedPages: DashboardPage[]) => {\n if (!currentDashboard || !dashboardId) return;\n\n // Update local state optimistically\n setCurrentDashboard({\n ...currentDashboard,\n pages: reorderedPages.map((page, index) => ({\n ...page,\n index,\n })),\n });\n\n // Call GraphQL mutation to persist the reorder\n const pageIds = reorderedPages.map((p) => p.id);\n await reorderPagesMutation(dashboardId, pageIds);\n },\n [currentDashboard, dashboardId, setCurrentDashboard, reorderPagesMutation]\n );\n\n // Show loading state\n if (dashboardLoading || !currentDashboard) {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <div className=\"animate-spin w-8 h-8 border-4 border-action-primary-bg border-t-transparent rounded-full\" />\n </div>\n );\n }\n\n // Show error state\n if (dashboardError) {\n return (\n <div className=\"flex flex-col items-center justify-center h-full p-6\">\n <div className=\"bg-status-error-bg border border-status-error-border rounded-lg p-4 max-w-md\">\n <h3 className=\"text-sm font-medium text-status-error-text\">Failed to load dashboard</h3>\n <p className=\"text-sm text-text-secondary mt-1\">{dashboardError.message}</p>\n <button\n type=\"button\"\n onClick={() => navigate('/dashboards')}\n className=\"mt-3 px-3 py-1.5 text-sm font-medium text-action-primary-fg bg-action-primary-bg hover:bg-action-primary-bgHover rounded-md\"\n >\n Back to Dashboards\n </button>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col h-full\">\n {/* Header / Toolbar */}\n <div className=\"flex items-center gap-3 px-3 py-2 border-b border-border-default bg-bg-surface flex-shrink-0\">\n <Button\n onClick={handleBack}\n variant=\"ghost\"\n size=\"sm\"\n title=\"Back to Dashboards\"\n aria-label=\"Back to Dashboards\"\n >\n <ArrowLeft className=\"w-4 h-4 mr-2\" />\n Back\n </Button>\n <h2 className=\"text-sm font-semibold text-text-primary truncate\">{currentDashboard.title}</h2>\n </div>\n\n {/* Builder Body */}\n <div className=\"flex flex-1 min-h-0 relative\">\n {/* Widget Panel (Left) */}\n <div\n className={`\n ${isWidgetPanelOpen ? 'w-72' : 'w-0'}\n flex-shrink-0\n bg-bg-surface\n border-r border-border-default\n transition-all duration-300\n overflow-hidden\n `}\n >\n {isWidgetPanelOpen && (\n <div className=\"h-full flex flex-col\">\n <div className=\"flex items-center justify-between p-3 border-b border-border-default\">\n <h3 className=\"text-sm font-semibold text-text-primary\">Widgets</h3>\n <button\n type=\"button\"\n onClick={() => setIsWidgetPanelOpen(false)}\n className=\"\n p-1 rounded-md\n text-text-secondary\n hover:text-text-primary\n hover:bg-bg-sunken\n \"\n >\n <svg className=\"w-4 h-4\" 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 <div className=\"flex-1 overflow-auto\">\n <WidgetTypeSelector onSelect={handleQuickAddWidget} definitions={widgetCatalog} />\n </div>\n </div>\n )}\n </div>\n\n {/* Toggle Widget Panel Button */}\n {!isWidgetPanelOpen && (\n <button\n type=\"button\"\n onClick={() => setIsWidgetPanelOpen(true)}\n className=\"\n absolute left-0 top-1/2 -translate-y-1/2 z-20\n w-8 h-24\n bg-bg-surface\n border border-l-0 border-border-default\n rounded-r-lg\n flex items-center justify-center\n text-text-secondary\n hover:text-text-primary\n hover:bg-bg-sunken\n transition-colors\n \"\n title=\"Open widget panel\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n )}\n\n {/* Main Canvas */}\n <div className=\"flex-1 relative\">\n <DashboardCanvas\n dashboardId={currentDashboard.id}\n pageId={activePageId || currentDashboard.pages?.[0]?.id}\n title={currentDashboard.title}\n onPaste={handlePaste}\n onSave={handleSave}\n isSaving={isSaving}\n onExport={handleExport}\n // Page tabs props\n pages={currentDashboard.pages.map((page) => ({\n id: page.id,\n name: page.title || `Page ${(page.index ?? 0) + 1}`,\n order: page.index ?? 0,\n }))}\n activePageId={activePageId || currentDashboard.pages?.[0]?.id}\n onPageChange={handlePageChange}\n onPageAdd={handlePageAdd}\n onPageRename={handlePageRename}\n onPageDuplicate={handlePageDuplicate}\n onPageDelete={handlePageDelete}\n onPagesReorder={handlePagesReorder}\n showPageTabs={true}\n />\n </div>\n\n {/* Export Dashboard Dialog */}\n <ExportDashboardDialog\n isOpen={isExportDialogOpen}\n dashboardId={currentDashboard.id}\n dashboardName={currentDashboard.title}\n onClose={handleExportClose}\n />\n </div>\n </div>\n );\n});\n\nexport default DashboardBuilderPage;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAoBA,SAAS,IAAwB;AAC/B,KAAI;AACF,SACE,OAGA;SACI;AACN;;;AAIJ,SAAS,EAAuB,GAAY,GAAc;CACxD,IAAM,IAAW,GAAuB;AACxC,CAAI,GAAU,YACZ,EAAS,SAAS,GAAI,EAAK;;AAI/B,SAAS,GAAyB,GAAY;CAC5C,IAAM,IAAW,GAAuB;AACxC,CAAI,GAAU,cACZ,EAAS,WAAW,EAAG;;AAQ3B,IAAa,IAA2B,EAAK,WAAgC;CAC3E,IAAM,EAAE,mBAAgB,GAAoC,EACtD,IAAW,GAAuB,EAClC,EAAE,gBAAa,kBAAe,iBAAc,GAAe,EAG3D,EAAE,aAAa,MAAkB,EAAiB;EAAE;EAAa;EAAe;EAAW,CAAC,EAC5F,CAAC,GAAmB,KAAwB,EAAS,GAAM,EAC3D,CAAC,IAAU,KAAe,EAAS,GAAM,EACzC,CAAC,IAAoB,KAAyB,EAAS,GAAM,EAC7D,CAAC,GAAc,KAAmB,EAAwB,KAAK,EAG/D,EACJ,mBACA,oBACA,SAAS,GACT,OAAO,MACL,GAAwB,EAGtB,EACJ,cAAc,GACd,cAAc,GACd,cAAc,GACd,iBAAiB,GACjB,4BACE,EAAoB,KAAA,GAAW,EAAY,EAGzC,EACJ,YAAY,GACZ,YAAY,GACZ,YAAY,GACZ,cAAc,MACZ,GAAmB,EAGjB,IAAsB,GAAmB,MAAU,EAAM,oBAAoB,EAC7E,IAAmB,GAAmB,MAAU,EAAM,iBAAiB,EACvE,IAAc,GAAmB,MAAU,EAAM,YAAY,EAC7D,IAAe,GAAgB,MAAU,EAAM,aAAa,EAC5D,IAAU,GAAgB,MAAU,EAAM,QAAQ,EAClD,IAAoB,GAAgB,MAAU,EAAM,kBAAkB,EACtE,IAAkB,GAAgB,MAAU,EAAM,gBAAgB,EAClE,IAAiB,GAAgB,MAAU,EAAM,eAAe;AAStE,CANA,SACE,EAAY,OAAO,QACN,EAAY,OAAO,GAC/B,CAAC,EAAY,CAAC,EAGjB,QAAgB;AACd,MAAI,CAAC,GAAa;AAChB,KAAS,cAAc;AACvB;;AAmCF,SA/BA,EAAe,EAAY,CAAC,MAAM,MAAc;AAC9C,GAAI,KACF,EAAoB;IAClB,IAAI,EAAU;IACd,OAAO,EAAU;IACjB,aAAa,EAAU,eAAe;IACtC,OAAO,EAAU,MAAM,KAAK,GAAM,OAAW;KAC3C,IAAI,EAAK;KACT,OAAO,EAAK,QAAQ;KACpB;KACA,cAAc,EAAK,gBAAgB,EAAE;KACtC,EAAE;IACH,WAAW,EAAU;IACrB,WAAW,EAAU;IACtB,CAAyB,EAEtB,EAAU,MAAM,SAAS,KAAK,CAAC,KACjC,EAAgB,EAAU,MAAM,GAAG,GAAG,EAIpC,EAAU,QACZ,EAAuB,GAAa,EAAU,KAAK,IAIrD,EAAS,cAAc;IAEzB,QAGW;AACX,GAAI,KACF,GAAyB,EAAY;;IAGxC;EAAC;EAAa;EAAU;EAAqB;EAAgB;EAAa,CAAC;CAG9E,IAAM,KAAc,EAAY,YAAY;AAC1C,MAAI,CAAC,KAAqB,CAAC,KAAe,CAAC,GAAkB,QAAQ,IAAI,GACvE;EAGF,IAAM,IAAe,EAAQ,IAAI,EAAkB;AACnD,MAAI,CAAC,GAAc;AACjB,MAAgB;AAChB;;EAGF,IAAM,IAAS,EAAiB,MAAM,GAAG,IAGnC,IAAe,MAAM,KAAK,EAAQ,QAAQ,CAAC,EAC3C,IAAa;GACjB,OAAO,EAAa,iBAAiB;GACrC,QAAQ,EAAa,kBAAkB;GACxC,EAEK,EAAE,MAAG,SAAM,EAA0B,GAAc,GAAY,EAAE,MAAM,IAAI,CAAC,EAE5E,IAAc;GAClB;GACA;GACA,OAAO,EAAW;GAClB,QAAQ,EAAW;GACpB,EAEK,IAAW,MAAoB,SAAS,GAAG,EAAa,MAAM,WAAW,EAAa,OAExF,IAAY;AAGhB,MAAI;AACF,OAAY,MAAM,EAAwB,GAAmB,GAAa,EAAS;UACvE;AA+Bd,EA5BA,AACE,MAAY,MAAM,EAAqB;GACrC;GACA;GACA,MAAM,EAAa;GACnB,OAAO;GACP,aAAa,EAAa;GAE1B,YAAY,EAAa,cAAc,KAAA;GACvC,WAAW,EAAa,aAAa,KAAA;GACrC,UAAU,EAAa,YAAY,KAAA;GACnC,aAAa,EAAa,eAAe,KAAA;GACzC,QAAQ,EAAa,UAAU,EAAE;GACjC,UAAU;GACV,iBAAiB,EAAa,mBAAmB,KAAA;GACjD,UAAU,EAAa;GACxB,CAAC,EAGA,MACF,EAAa,EAAU,GAAG,EAGtB,MAAoB,SACtB,MAAM,EAAqB,EAAkB,GAIjD,GAAgB;IACf;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,EAGI,KAAuB,EAC3B,OAAO,MAAqB;AAC1B,MAAI,CAAC,KAAe,CAAC,GAAkB,QAAQ,IAAI,GAAI;EAEvD,IAAM,IAAS,EAAiB,MAAM,GAAG,IACnC,IAAQ,EACX,QAAQ,MAAM,IAAI,CAClB,aAAa,CACb,QAAQ,QAAQ,MAAM,EAAE,aAAa,CAAC,EAInC,IAAe,MAAM,KAAK,EAAQ,QAAQ,CAAC,EAC3C,IAAa,EAAc,MAAM,MAAM,EAAE,SAAS,EAAK,IAAI,EAAoB,EAAK,EACpF,IAAa;GACjB,OAAO,GAAY,aAAa,SAAS;GACzC,QAAQ,GAAY,aAAa,UAAU;GAC5C,EAEK,EAAE,MAAG,SAAM,EAA0B,GAAc,GAAY,EAAE,MAAM,IAAI,CAAC,EAG5E,IAAY,MAAM,EAAqB;GAC3C;GACA;GACA;GACA;GACA,QAAQ,EAAE;GACV,UAAU;IACR;IACA;IACA,OAAO,EAAW;IAClB,QAAQ,EAAW;IACpB;GACF,CAAC;AAEF,EAAI,MACF,EAAa,EAAU,GAAG,EAC1B,EAAqB,GAAM;IAG/B;EAAC;EAAa;EAAkB;EAAsB;EAAc;EAAS;EAAc,CAC5F,EAGK,KAAa,QAAkB;AACnC,IAAS,cAAc;IACtB,CAAC,EAAS,CAAC,EAGR,IAAa,EAAY,YAAY;AACpC,SAEL;KAAY,GAAK;AACjB,OAAI;IAEF,IAAM,IAAa,EAAe,UAAU,EACtC,IAAiB,MAAM,KAAK,EAAW,QAAQ,QAAQ,CAAC,EACxD,IAAkB,EAAW,gBAK7B,IAAe,EAAe,QAAQ,MAAM,EAAgB,IAAI,EAAE,GAAG,CAAC;AAE5E,QAAI,EAAa,SAAS,GAAG;KAE3B,IAAM,IAAiB,EAAa,IAAI,OAAO,MAAW;MACxD,IAAM,IAAc;OAClB,IAAI,EAAO;OACX,OAAO,EAAO;OACd,QAAQ,EAAO;OACf,iBAAiB,EAAO,mBAAmB,KAAA;OAE3C,YAAY,EAAO,cAAc,KAAA;OACjC,WAAW,EAAO,aAAa,KAAA;OAC/B,UAAU,EAAO,YAAY,KAAA;OAC7B,aAAa,EAAO,eAAe,KAAA;OACpC;AAED,UAAI;AAEF,cADe,MAAM,EAAqB,EAAY;eAE/C,GAAK;AACZ,aAAM;;OAER;AAKF,KAHgB,MAAM,QAAQ,IAAI,EAAe,EAGjD,EAAW,eAAe;;AAoB5B,IAfI,EAAe,SAAS,KAW1B,MAAM,EAVkB,EAAe,KAAK,OAAY;KACtD,IAAI,EAAO;KACX,UAAU,EAAO,YAAY;MAC3B,GAAG,EAAO,aAAa;MACvB,GAAG,EAAO,aAAa;MACvB,OAAO,EAAO,iBAAiB;MAC/B,QAAQ,EAAO,kBAAkB;MAClC;KACF,EAAE,CAEwC,EAIzC,KACF,MAAM,EAAgB;KACpB,IAAI;KACJ,MAAM,EAAiB;KACvB,aAAa,EAAiB;KAC/B,CAAC;WAEU,WACN;AACR,MAAY,GAAM;;;IAEnB;EAAC;EAAa;EAAkB;EAAsB;EAAsB;EAAgB,CAAC,EAG1F,KAAe,QAAkB;AACrC,IAAsB,GAAK;IAC1B,EAAE,CAAC,EAEA,KAAoB,QAAkB;AAC1C,IAAsB,GAAM;IAC3B,EAAE,CAAC,EAOA,KAAmB,GAAa,MAAmB;AACvD,IAAgB,EAAO;IACtB,EAAE,CAAC,EAGA,KAAgB,EAAY,YAAY;AAC5C,MAAI,CAAC,KAAoB,CAAC,EAAa;EAOvC,IAAM,IAAU,MAAM,EAAmB;GACvC;GACA,MANkB,QADC,EAAiB,MAAM,SAAS;GAQpD,CAAC;AAEF,EAAI,MAEF,EAAoB;GAClB,GAAG;GACH,OAAO,CACL,GAAG,EAAiB,OACpB;IACE,IAAI,EAAQ;IACZ,OAAO,EAAQ;IACf,OAAO,EAAQ;IACf,cAAc,EAAQ,gBAAgB,EAAE;IACzC,CACF;GACF,CAAC,EAGF,EAAgB,EAAQ,GAAG;IAE5B;EAAC;EAAkB;EAAa;EAAqB;EAAmB,CAAC,EAGtE,KAAmB,EACvB,OAAO,GAAgB,MAAoB;AACpC,OAGe,MAAM,EAAmB;GAC3C,IAAI;GACJ,MAAM;GACP,CAAC,IAGA,EAAoB;GAClB,GAAG;GACH,OAAO,EAAiB,MAAM,KAAK,MAAU,EAAK,OAAO,IAAS;IAAE,GAAG;IAAM,OAAO;IAAS,GAAG,EAAM;GACvG,CAAC;IAGN;EAAC;EAAkB;EAAqB;EAAmB,CAC5D,EAGK,KAAsB,EAC1B,OAAO,MAAmB;AACxB,MAAI,CAAC,KAAoB,CAAC,EAAa;EAEvC,IAAM,IAAa,EAAiB,MAAM,MAAM,MAAM,EAAE,OAAO,EAAO;AACtE,MAAI,CAAC,EAAY;EAKjB,IAAM,IAAU,MAAM,EAAmB;GACvC;GACA,MAAM,GAAG,EAAW,MAAM;GAC3B,CAAC;AAEF,EAAI,MACF,EAAoB;GAClB,GAAG;GACH,OAAO,CACL,GAAG,EAAiB,OACpB;IACE,IAAI,EAAQ;IACZ,OAAO,EAAQ;IACf,OAAO,EAAQ;IACf,cAAc,EAAQ,gBAAgB,EAAE;IACzC,CACF;GACF,CAAC,EAEF,EAAgB,EAAQ,GAAG;IAG/B;EAAC;EAAkB;EAAa;EAAqB;EAAmB,CACzE,EAGK,KAAmB,EACvB,OAAO,MAAmB;AACpB,SAAC,KAAoB,EAAiB,MAAM,UAAU,MAG1C,MAAM,EAAmB,EAAO,EAEnC;GACX,IAAM,IAAe,EAAiB,MAAM,QAAQ,MAAM,EAAE,OAAO,EAAO,CAAC,KAAK,GAAG,OAAW;IAAE,GAAG;IAAG;IAAO,EAAE;AAQ/G,GANA,EAAoB;IAClB,GAAG;IACH,OAAO;IACR,CAAC,EAGE,MAAiB,KACnB,EAAgB,EAAa,IAAI,MAAM,KAAK;;IAIlD;EAAC;EAAkB;EAAqB;EAAc;EAAmB,CAC1E,EAGK,KAAqB,EACzB,OAAO,MAAoC;AACrC,GAAC,KAAoB,CAAC,MAG1B,EAAoB;GAClB,GAAG;GACH,OAAO,EAAe,KAAK,GAAM,OAAW;IAC1C,GAAG;IACH;IACD,EAAE;GACJ,CAAC,EAIF,MAAM,EAAqB,GADX,EAAe,KAAK,MAAM,EAAE,GAAG,CACC;IAElD;EAAC;EAAkB;EAAa;EAAqB;EAAqB,CAC3E;AA8BD,QA3BI,KAAoB,CAAC,IAErB,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD,EAAK,WAAU,4FAA6F,CAAA;EACxG,CAAA,GAKN,IAEA,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,MAAD;KAAI,WAAU;eAA6C;KAA6B,CAAA;IACxF,kBAAC,KAAD;KAAG,WAAU;eAAoC,EAAe;KAAY,CAAA;IAC5E,kBAAC,UAAD;KACE,MAAK;KACL,eAAe,EAAS,cAAc;KACtC,WAAU;eACX;KAEQ,CAAA;IACL;;EACF,CAAA,GAKR,kBAAC,OAAD;EAAK,WAAU;YAAf,CAEE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,IAAD;IACE,SAAS;IACT,SAAQ;IACR,MAAK;IACL,OAAM;IACN,cAAW;cALb,CAOE,kBAAC,IAAD,EAAW,WAAU,gBAAiB,CAAA,EAAA,OAE/B;OACT,kBAAC,MAAD;IAAI,WAAU;cAAoD,EAAiB;IAAW,CAAA,CAC1F;MAGN,kBAAC,OAAD;GAAK,WAAU;aAAf;IAEE,kBAAC,OAAD;KACE,WAAW;YACT,IAAoB,SAAS,MAAM;;;;;;;eAQpC,KACC,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,MAAD;QAAI,WAAU;kBAA0C;QAAY,CAAA,EACpE,kBAAC,UAAD;QACE,MAAK;QACL,eAAe,EAAqB,GAAM;QAC1C,WAAU;kBAOV,kBAAC,OAAD;SAAK,WAAU;SAAU,MAAK;SAAO,QAAO;SAAe,SAAQ;mBACjE,kBAAC,QAAD;UAAM,eAAc;UAAQ,gBAAe;UAAQ,aAAa;UAAG,GAAE;UAAyB,CAAA;SAC1F,CAAA;QACC,CAAA,CACL;UACN,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,GAAD;QAAoB,UAAU;QAAsB,aAAa;QAAiB,CAAA;OAC9E,CAAA,CACF;;KAEJ,CAAA;IAGL,CAAC,KACA,kBAAC,UAAD;KACE,MAAK;KACL,eAAe,EAAqB,GAAK;KACzC,WAAU;KAYV,OAAM;eAEN,kBAAC,OAAD;MAAK,WAAU;MAAU,MAAK;MAAO,QAAO;MAAe,SAAQ;gBACjE,kBAAC,QAAD;OAAM,eAAc;OAAQ,gBAAe;OAAQ,aAAa;OAAG,GAAE;OAAiB,CAAA;MAClF,CAAA;KACC,CAAA;IAIX,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD;MACE,aAAa,EAAiB;MAC9B,QAAQ,KAAgB,EAAiB,QAAQ,IAAI;MACrD,OAAO,EAAiB;MACxB,SAAS;MACT,QAAQ;MACE;MACV,UAAU;MAEV,OAAO,EAAiB,MAAM,KAAK,OAAU;OAC3C,IAAI,EAAK;OACT,MAAM,EAAK,SAAS,SAAS,EAAK,SAAS,KAAK;OAChD,OAAO,EAAK,SAAS;OACtB,EAAE;MACH,cAAc,KAAgB,EAAiB,QAAQ,IAAI;MAC3D,cAAc;MACd,WAAW;MACX,cAAc;MACd,iBAAiB;MACjB,cAAc;MACd,gBAAgB;MAChB,cAAc;MACd,CAAA;KACE,CAAA;IAGN,kBAAC,GAAD;KACE,QAAQ;KACR,aAAa,EAAiB;KAC9B,eAAe,EAAiB;KAChC,SAAS;KACT,CAAA;IACE;KACF;;EAER"}