@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.
- package/dist/bigconsole/BigConsoleRoutes.js +93 -93
- package/dist/bigconsole/assistant/assistantApi.js +215 -0
- package/dist/bigconsole/assistant/assistantApi.js.map +1 -0
- package/dist/bigconsole/assistant/createSandboxAssistantTransport.js +119 -0
- package/dist/bigconsole/assistant/createSandboxAssistantTransport.js.map +1 -0
- package/dist/bigconsole/assistant/index.js +2 -0
- package/dist/bigconsole/assistant/pageContext.js +51 -0
- package/dist/bigconsole/assistant/pageContext.js.map +1 -0
- package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js +48 -48
- package/dist/bigconsole/components/dashboard/DashboardToolbar.js +52 -52
- package/dist/bigconsole/components/dashboard/DrilldownBreadcrumb.js.map +1 -1
- package/dist/bigconsole/components/dashboard/ExportDashboardDialog.js +33 -33
- package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js +179 -179
- package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js.map +1 -1
- package/dist/bigconsole/components/dashboard/WidgetPalette.js +38 -38
- package/dist/bigconsole/components/datasink/DataSinkTableViewer.js +32 -32
- package/dist/bigconsole/components/datasink/ExportDataSinkDialog.js +31 -31
- package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js +98 -98
- package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js.map +1 -1
- package/dist/bigconsole/components/parser/ExportParserDialog.js +31 -31
- package/dist/bigconsole/components/parser/ImportParserDialog.js +162 -162
- package/dist/bigconsole/components/parser/ImportParserDialog.js.map +1 -1
- package/dist/bigconsole/components/widgets/ActionConfigDialog.js +79 -79
- package/dist/bigconsole/components/widgets/ActionConfigDialog.js.map +1 -1
- package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js.map +1 -1
- package/dist/bigconsole/components/widgets/PropertiesPanel.js +307 -307
- package/dist/bigconsole/components/widgets/PropertiesPanel.js.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetConfigDialog.js +222 -222
- package/dist/bigconsole/components/widgets/WidgetConfigDialog.js.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetTypeSelector.js +23 -23
- package/dist/bigconsole/index.js +3 -0
- package/dist/bigconsole/pages/DashboardBuilderPage.js +74 -74
- package/dist/bigconsole/pages/DashboardBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/DashboardViewPage.js +168 -189
- package/dist/bigconsole/pages/DashboardViewPage.js.map +1 -1
- package/dist/bigconsole/pages/DashboardsPage.js +266 -310
- package/dist/bigconsole/pages/DashboardsPage.js.map +1 -1
- package/dist/bigconsole/pages/DataParsersPage.js +148 -194
- package/dist/bigconsole/pages/DataParsersPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkBuilderPage.js +252 -246
- package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkViewPage.js +256 -231
- package/dist/bigconsole/pages/DataSinkViewPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinksPage.js +173 -219
- package/dist/bigconsole/pages/DataSinksPage.js.map +1 -1
- package/dist/bigconsole/pages/HomePage.js +125 -141
- package/dist/bigconsole/pages/HomePage.js.map +1 -1
- package/dist/bigconsole/pages/InsightsPage.js +159 -184
- package/dist/bigconsole/pages/InsightsPage.js.map +1 -1
- package/dist/bigconsole/pages/ParserBuilderPage.js +401 -393
- package/dist/bigconsole/pages/ParserBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/ParserViewPage.js +220 -201
- package/dist/bigconsole/pages/ParserViewPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelineBuilderPage.js +212 -206
- package/dist/bigconsole/pages/PipelineBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelineViewPage.js +204 -181
- package/dist/bigconsole/pages/PipelineViewPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelinesPage.js +107 -150
- package/dist/bigconsole/pages/PipelinesPage.js.map +1 -1
- package/dist/bigconsole/pages/SettingsPage.js +184 -171
- package/dist/bigconsole/pages/SettingsPage.js.map +1 -1
- package/dist/bigconsole/pages/WidgetDemoPage.js +69 -81
- package/dist/bigconsole/pages/WidgetDemoPage.js.map +1 -1
- package/dist/bigconsole/pages/WorkflowViewPage.js +230 -216
- package/dist/bigconsole/pages/WorkflowViewPage.js.map +1 -1
- package/dist/bigconsole/pages/WorkflowsPage.js +106 -149
- package/dist/bigconsole/pages/WorkflowsPage.js.map +1 -1
- package/dist/generated/wspace-operations.js +87 -36
- package/dist/generated/wspace-operations.js.map +1 -1
- package/dist/index.js +3 -1
- 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
|
|
15
|
-
import
|
|
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
|
|
18
|
-
import { useParams as
|
|
19
|
-
import { ArrowLeft as
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
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 =
|
|
39
|
-
let { dashboardId:
|
|
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] =
|
|
44
|
-
|
|
45
|
-
if (!
|
|
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(
|
|
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(
|
|
62
|
+
}), e.pages.length > 0 && !A && j(e.pages[0].id), e.name && x(p, e.name)) : b("/dashboards");
|
|
63
63
|
}), () => {
|
|
64
|
-
|
|
64
|
+
p && ne(p);
|
|
65
65
|
};
|
|
66
66
|
}, [
|
|
67
|
-
|
|
67
|
+
p,
|
|
68
68
|
b,
|
|
69
69
|
G,
|
|
70
70
|
M,
|
|
71
71
|
A
|
|
72
72
|
]);
|
|
73
|
-
let ae =
|
|
74
|
-
if (!X || !
|
|
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:
|
|
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
|
-
|
|
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 =
|
|
119
|
-
if (!
|
|
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:
|
|
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
|
-
|
|
138
|
+
p,
|
|
139
139
|
K,
|
|
140
140
|
I,
|
|
141
141
|
J,
|
|
142
142
|
Y,
|
|
143
143
|
T
|
|
144
|
-
]), se =
|
|
144
|
+
]), se = m(() => {
|
|
145
145
|
b("/dashboards");
|
|
146
|
-
}, [b]), $ =
|
|
147
|
-
if (
|
|
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:
|
|
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
|
-
|
|
189
|
+
p,
|
|
190
190
|
K,
|
|
191
191
|
L,
|
|
192
192
|
B,
|
|
193
193
|
N
|
|
194
|
-
]), ce =
|
|
194
|
+
]), ce = m(() => {
|
|
195
195
|
k(!0);
|
|
196
|
-
}, []), le =
|
|
196
|
+
}, []), le = m(() => {
|
|
197
197
|
k(!1);
|
|
198
|
-
}, []), ue =
|
|
198
|
+
}, []), ue = m((e) => {
|
|
199
199
|
j(e);
|
|
200
|
-
}, []), de =
|
|
201
|
-
if (!K || !
|
|
200
|
+
}, []), de = m(async () => {
|
|
201
|
+
if (!K || !p) return;
|
|
202
202
|
let e = await V({
|
|
203
|
-
dashboardId:
|
|
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
|
-
|
|
217
|
+
p,
|
|
218
218
|
G,
|
|
219
219
|
V
|
|
220
|
-
]), fe =
|
|
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 =
|
|
236
|
-
if (!K || !
|
|
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:
|
|
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
|
-
|
|
254
|
+
p,
|
|
255
255
|
G,
|
|
256
256
|
V
|
|
257
|
-
]), me =
|
|
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 =
|
|
274
|
-
!K || !
|
|
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(
|
|
280
|
+
}), await W(p, e.map((e) => e.id)));
|
|
281
281
|
}, [
|
|
282
282
|
K,
|
|
283
|
-
|
|
283
|
+
p,
|
|
284
284
|
G,
|
|
285
285
|
W
|
|
286
286
|
]);
|
|
287
|
-
return P || !K ? /* @__PURE__ */
|
|
287
|
+
return P || !K ? /* @__PURE__ */ v("div", {
|
|
288
288
|
className: "flex items-center justify-center h-full",
|
|
289
|
-
children: /* @__PURE__ */
|
|
290
|
-
}) : F ? /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
299
|
+
/* @__PURE__ */ v("p", {
|
|
300
300
|
className: "text-sm text-text-secondary mt-1",
|
|
301
301
|
children: F.message
|
|
302
302
|
}),
|
|
303
|
-
/* @__PURE__ */
|
|
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__ */
|
|
311
|
+
}) : /* @__PURE__ */ y("div", {
|
|
312
312
|
className: "flex flex-col h-full",
|
|
313
|
-
children: [/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
322
|
-
}), /* @__PURE__ */
|
|
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__ */
|
|
326
|
+
}), /* @__PURE__ */ y("div", {
|
|
327
327
|
className: "flex flex-1 min-h-0 relative",
|
|
328
328
|
children: [
|
|
329
|
-
/* @__PURE__ */
|
|
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__ */
|
|
338
|
+
children: E && /* @__PURE__ */ y("div", {
|
|
339
339
|
className: "h-full flex flex-col",
|
|
340
|
-
children: [/* @__PURE__ */
|
|
340
|
+
children: [/* @__PURE__ */ y("div", {
|
|
341
341
|
className: "flex items-center justify-between p-3 border-b border-border-default",
|
|
342
|
-
children: [/* @__PURE__ */
|
|
342
|
+
children: [/* @__PURE__ */ v("h3", {
|
|
343
343
|
className: "text-sm font-semibold text-text-primary",
|
|
344
344
|
children: "Widgets"
|
|
345
|
-
}), /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
362
|
+
}), /* @__PURE__ */ v("div", {
|
|
363
363
|
className: "flex-1 overflow-auto",
|
|
364
|
-
children: /* @__PURE__ */
|
|
364
|
+
children: /* @__PURE__ */ v(l, {
|
|
365
365
|
onSelect: oe,
|
|
366
366
|
definitions: T
|
|
367
367
|
})
|
|
368
368
|
})]
|
|
369
369
|
})
|
|
370
370
|
}),
|
|
371
|
-
!E && /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
389
|
+
/* @__PURE__ */ v("div", {
|
|
390
390
|
className: "flex-1 relative",
|
|
391
|
-
children: /* @__PURE__ */
|
|
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__ */
|
|
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"}
|