@burdenoff/microfe-bigconsole 2026.707.3 → 2026.708.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.
@@ -1,42 +1,135 @@
1
1
  import { memo as e, useCallback as t, useEffect as n, useMemo as r, useState as i } from "react";
2
2
  import { jsx as a, jsxs as o } from "react/jsx-runtime";
3
3
  //#region src/bigconsole/components/widgets/table/TableConfig.tsx
4
- var s = e(function({ config: e, onChange: s }) {
5
- let [c, l] = i(r(() => (e.columns || []).map((e) => typeof e == "string" ? {
4
+ var s = [
5
+ {
6
+ value: "gt",
7
+ label: "> greater than"
8
+ },
9
+ {
10
+ value: "gte",
11
+ label: "≥ at least"
12
+ },
13
+ {
14
+ value: "lt",
15
+ label: "< less than"
16
+ },
17
+ {
18
+ value: "lte",
19
+ label: "≤ at most"
20
+ },
21
+ {
22
+ value: "eq",
23
+ label: "= equals"
24
+ },
25
+ {
26
+ value: "neq",
27
+ label: "≠ not equal"
28
+ },
29
+ {
30
+ value: "between",
31
+ label: "between"
32
+ },
33
+ {
34
+ value: "outside",
35
+ label: "outside"
36
+ },
37
+ {
38
+ value: "contains",
39
+ label: "contains"
40
+ }
41
+ ], c = [
42
+ {
43
+ value: "danger",
44
+ label: "Red — danger"
45
+ },
46
+ {
47
+ value: "warning",
48
+ label: "Amber — warning"
49
+ },
50
+ {
51
+ value: "success",
52
+ label: "Green — good"
53
+ },
54
+ {
55
+ value: "info",
56
+ label: "Blue — info"
57
+ },
58
+ {
59
+ value: "neutral",
60
+ label: "Neutral"
61
+ }
62
+ ], l = "px-2 py-1 text-xs text-text-primary bg-bg-surface border border-border-default rounded-md focus:outline-none focus:ring-2 focus:ring-action-primary-bg", u = e(function({ config: e, onChange: u }) {
63
+ let [d, f] = i(r(() => (e.columns || []).map((e) => typeof e == "string" ? {
6
64
  field: e,
7
65
  header: e.charAt(0).toUpperCase() + e.slice(1).replace(/_/g, " ")
8
66
  } : e), []));
9
67
  n(() => {
10
- JSON.stringify(e.columns) !== JSON.stringify(c) && c.length > 0 && s({
68
+ JSON.stringify(e.columns) !== JSON.stringify(d) && d.length > 0 && u({
11
69
  ...e,
12
- columns: c
70
+ columns: d
13
71
  });
14
- }, [c]), n(() => {
15
- l((e.columns || []).map((e) => typeof e == "string" ? {
72
+ }, [d]), n(() => {
73
+ f((e.columns || []).map((e) => typeof e == "string" ? {
16
74
  field: e,
17
75
  header: e.charAt(0).toUpperCase() + e.slice(1).replace(/_/g, " ")
18
76
  } : e));
19
77
  }, [e.columns]);
20
- let u = t((t, n) => {
21
- s({
78
+ let p = t((t, n) => {
79
+ u({
22
80
  ...e,
23
81
  [t]: n
24
82
  });
25
- }, [e, s]), d = t((e, t, n) => {
26
- l((r) => {
83
+ }, [e, u]), m = t((e, t, n) => {
84
+ f((r) => {
27
85
  let i = [...r];
28
86
  return i[e] = {
29
87
  ...i[e],
30
88
  [t]: n
31
89
  }, i;
32
90
  });
33
- }, []), f = t(() => {
34
- l((e) => [...e, {
91
+ }, []), h = t((e, t) => {
92
+ f((n) => {
93
+ let r = [...n];
94
+ return r[e] = {
95
+ ...r[e],
96
+ conditionalRules: t
97
+ }, r;
98
+ });
99
+ }, []), g = t((e) => {
100
+ let t = d[e]?.conditionalRules ?? [], n = {
101
+ operator: "gt",
102
+ value: 0,
103
+ style: {
104
+ bgColor: "danger",
105
+ textColor: "danger",
106
+ bold: !0
107
+ }
108
+ };
109
+ h(e, [...t, n]);
110
+ }, [d, h]), _ = t((e, t, n) => {
111
+ h(e, (d[e]?.conditionalRules ?? []).map((e, r) => r === t ? {
112
+ ...e,
113
+ ...n
114
+ } : e));
115
+ }, [d, h]), v = t((e, t, n) => {
116
+ h(e, (d[e]?.conditionalRules ?? []).map((e, r) => r === t ? {
117
+ ...e,
118
+ style: {
119
+ ...e.style,
120
+ bgColor: n,
121
+ textColor: n
122
+ }
123
+ } : e));
124
+ }, [d, h]), y = t((e, t) => {
125
+ h(e, (d[e]?.conditionalRules ?? []).filter((e, n) => n !== t));
126
+ }, [d, h]), b = t(() => {
127
+ f((e) => [...e, {
35
128
  field: "",
36
129
  header: ""
37
130
  }]);
38
- }, []), p = t((e) => {
39
- l((t) => t.filter((t, n) => n !== e));
131
+ }, []), x = t((e) => {
132
+ f((t) => t.filter((t, n) => n !== e));
40
133
  }, []);
41
134
  return /* @__PURE__ */ o("div", {
42
135
  className: "space-y-4",
@@ -46,7 +139,7 @@ var s = e(function({ config: e, onChange: s }) {
46
139
  children: "Page Size"
47
140
  }), /* @__PURE__ */ o("select", {
48
141
  value: e.pageSize || 10,
49
- onChange: (e) => u("pageSize", Number(e.target.value)),
142
+ onChange: (e) => p("pageSize", Number(e.target.value)),
50
143
  className: "\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n ",
51
144
  children: [
52
145
  /* @__PURE__ */ a("option", {
@@ -74,13 +167,13 @@ var s = e(function({ config: e, onChange: s }) {
74
167
  children: "Columns"
75
168
  }), /* @__PURE__ */ a("button", {
76
169
  type: "button",
77
- onClick: f,
170
+ onClick: b,
78
171
  className: "\n text-sm text-action-primary-bg\n hover:text-action-primary-bgHover\n ",
79
172
  children: "+ Add Column"
80
173
  })]
81
174
  }), /* @__PURE__ */ o("div", {
82
175
  className: "space-y-3",
83
- children: [c.map((e, t) => /* @__PURE__ */ o("div", {
176
+ children: [d.map((e, t) => /* @__PURE__ */ o("div", {
84
177
  className: "\n p-3\n bg-bg-sunken\n rounded-md\n space-y-2\n ",
85
178
  children: [
86
179
  /* @__PURE__ */ o("div", {
@@ -90,7 +183,7 @@ var s = e(function({ config: e, onChange: s }) {
90
183
  children: ["Column ", t + 1]
91
184
  }), /* @__PURE__ */ a("button", {
92
185
  type: "button",
93
- onClick: () => p(t),
186
+ onClick: () => x(t),
94
187
  className: "text-state-error hover:text-state-error/80",
95
188
  children: /* @__PURE__ */ a("svg", {
96
189
  className: "w-4 h-4",
@@ -111,13 +204,13 @@ var s = e(function({ config: e, onChange: s }) {
111
204
  children: [/* @__PURE__ */ a("input", {
112
205
  type: "text",
113
206
  value: e.field || "",
114
- onChange: (e) => d(t, "field", e.target.value),
207
+ onChange: (e) => m(t, "field", e.target.value),
115
208
  placeholder: "Field name",
116
209
  className: "\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n "
117
210
  }), /* @__PURE__ */ a("input", {
118
211
  type: "text",
119
212
  value: e.header || "",
120
- onChange: (e) => d(t, "header", e.target.value),
213
+ onChange: (e) => m(t, "header", e.target.value),
121
214
  placeholder: "Header label",
122
215
  className: "\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n "
123
216
  })]
@@ -126,7 +219,7 @@ var s = e(function({ config: e, onChange: s }) {
126
219
  className: "grid grid-cols-2 gap-2",
127
220
  children: [/* @__PURE__ */ o("select", {
128
221
  value: e.format || "text",
129
- onChange: (e) => d(t, "format", e.target.value),
222
+ onChange: (e) => m(t, "format", e.target.value),
130
223
  className: "\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n ",
131
224
  children: [
132
225
  /* @__PURE__ */ a("option", {
@@ -156,7 +249,7 @@ var s = e(function({ config: e, onChange: s }) {
156
249
  ]
157
250
  }), /* @__PURE__ */ o("select", {
158
251
  value: e.align || "left",
159
- onChange: (e) => d(t, "align", e.target.value),
252
+ onChange: (e) => m(t, "align", e.target.value),
160
253
  className: "\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n ",
161
254
  children: [
162
255
  /* @__PURE__ */ a("option", {
@@ -173,9 +266,107 @@ var s = e(function({ config: e, onChange: s }) {
173
266
  })
174
267
  ]
175
268
  })]
269
+ }),
270
+ /* @__PURE__ */ o("div", {
271
+ className: "pt-2 border-t border-border-default/60",
272
+ children: [
273
+ /* @__PURE__ */ o("div", {
274
+ className: "flex items-center justify-between mb-1",
275
+ children: [/* @__PURE__ */ a("span", {
276
+ className: "text-xs font-medium text-text-secondary",
277
+ children: "Conditional formatting"
278
+ }), /* @__PURE__ */ a("button", {
279
+ type: "button",
280
+ onClick: () => g(t),
281
+ className: "text-xs text-action-primary-bg hover:text-action-primary-bgHover",
282
+ children: "+ Add rule"
283
+ })]
284
+ }),
285
+ (e.conditionalRules?.length ?? 0) === 0 && /* @__PURE__ */ a("p", {
286
+ className: "text-xs text-text-secondary",
287
+ children: "No rules — cell shows its plain value."
288
+ }),
289
+ /* @__PURE__ */ a("div", {
290
+ className: "space-y-2",
291
+ children: (e.conditionalRules ?? []).map((e, n) => {
292
+ let r = e.operator === "between" || e.operator === "outside", i = e.style?.bgColor ?? e.style?.textColor ?? "danger";
293
+ return /* @__PURE__ */ o("div", {
294
+ className: "p-2 bg-bg-surface rounded-md border border-border-default space-y-2",
295
+ children: [/* @__PURE__ */ o("div", {
296
+ className: "flex items-center gap-2",
297
+ children: [
298
+ /* @__PURE__ */ a("select", {
299
+ value: e.operator,
300
+ onChange: (e) => _(t, n, { operator: e.target.value }),
301
+ className: `${l} flex-1`,
302
+ children: s.map((e) => /* @__PURE__ */ a("option", {
303
+ value: e.value,
304
+ children: e.label
305
+ }, e.value))
306
+ }),
307
+ /* @__PURE__ */ a("input", {
308
+ type: "text",
309
+ value: e.value ?? "",
310
+ onChange: (e) => _(t, n, { value: e.target.value }),
311
+ placeholder: "value",
312
+ className: `${l} w-20`
313
+ }),
314
+ r && /* @__PURE__ */ a("input", {
315
+ type: "text",
316
+ value: e.value2 ?? "",
317
+ onChange: (e) => _(t, n, { value2: e.target.value }),
318
+ placeholder: "and",
319
+ className: `${l} w-20`
320
+ }),
321
+ /* @__PURE__ */ a("button", {
322
+ type: "button",
323
+ onClick: () => y(t, n),
324
+ className: "text-state-error hover:text-state-error/80",
325
+ "aria-label": "Remove rule",
326
+ children: /* @__PURE__ */ a("svg", {
327
+ className: "w-3.5 h-3.5",
328
+ fill: "none",
329
+ stroke: "currentColor",
330
+ viewBox: "0 0 24 24",
331
+ children: /* @__PURE__ */ a("path", {
332
+ strokeLinecap: "round",
333
+ strokeLinejoin: "round",
334
+ strokeWidth: 2,
335
+ d: "M6 18L18 6M6 6l12 12"
336
+ })
337
+ })
338
+ })
339
+ ]
340
+ }), /* @__PURE__ */ o("div", {
341
+ className: "flex items-center gap-2",
342
+ children: [/* @__PURE__ */ a("select", {
343
+ value: i,
344
+ onChange: (e) => v(t, n, e.target.value),
345
+ className: `${l} flex-1`,
346
+ children: c.map((e) => /* @__PURE__ */ a("option", {
347
+ value: e.value,
348
+ children: e.label
349
+ }, e.value))
350
+ }), /* @__PURE__ */ o("label", {
351
+ className: "flex items-center gap-1 text-xs text-text-primary",
352
+ children: [/* @__PURE__ */ a("input", {
353
+ type: "checkbox",
354
+ checked: e.style?.bold === !0,
355
+ onChange: (r) => _(t, n, { style: {
356
+ ...e.style,
357
+ bold: r.target.checked
358
+ } }),
359
+ className: "w-3.5 h-3.5 text-action-primary-bg bg-bg-surface border-border-default rounded focus:ring-action-primary-bg"
360
+ }), "Bold"]
361
+ })]
362
+ })]
363
+ }, n);
364
+ })
365
+ })
366
+ ]
176
367
  })
177
368
  ]
178
- }, t)), c.length === 0 && /* @__PURE__ */ a("p", {
369
+ }, t)), d.length === 0 && /* @__PURE__ */ a("p", {
179
370
  className: "text-sm text-text-secondary text-center py-4",
180
371
  children: "No columns configured. Columns will be auto-generated from data."
181
372
  })]
@@ -188,7 +379,7 @@ var s = e(function({ config: e, onChange: s }) {
188
379
  children: [/* @__PURE__ */ a("input", {
189
380
  type: "checkbox",
190
381
  checked: e.showSearch !== !1,
191
- onChange: (e) => u("showSearch", e.target.checked),
382
+ onChange: (e) => p("showSearch", e.target.checked),
192
383
  className: "\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n "
193
384
  }), /* @__PURE__ */ a("span", {
194
385
  className: "text-sm text-text-primary",
@@ -200,7 +391,7 @@ var s = e(function({ config: e, onChange: s }) {
200
391
  children: [/* @__PURE__ */ a("input", {
201
392
  type: "checkbox",
202
393
  checked: e.showPagination !== !1,
203
- onChange: (e) => u("showPagination", e.target.checked),
394
+ onChange: (e) => p("showPagination", e.target.checked),
204
395
  className: "\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n "
205
396
  }), /* @__PURE__ */ a("span", {
206
397
  className: "text-sm text-text-primary",
@@ -212,7 +403,7 @@ var s = e(function({ config: e, onChange: s }) {
212
403
  children: [/* @__PURE__ */ a("input", {
213
404
  type: "checkbox",
214
405
  checked: e.showExport !== !1,
215
- onChange: (e) => u("showExport", e.target.checked),
406
+ onChange: (e) => p("showExport", e.target.checked),
216
407
  className: "\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n "
217
408
  }), /* @__PURE__ */ a("span", {
218
409
  className: "text-sm text-text-primary",
@@ -224,7 +415,7 @@ var s = e(function({ config: e, onChange: s }) {
224
415
  children: [/* @__PURE__ */ a("input", {
225
416
  type: "checkbox",
226
417
  checked: e.stickyHeader === !0,
227
- onChange: (e) => u("stickyHeader", e.target.checked),
418
+ onChange: (e) => p("stickyHeader", e.target.checked),
228
419
  className: "\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n "
229
420
  }), /* @__PURE__ */ a("span", {
230
421
  className: "text-sm text-text-primary",
@@ -236,7 +427,7 @@ var s = e(function({ config: e, onChange: s }) {
236
427
  children: [/* @__PURE__ */ a("input", {
237
428
  type: "checkbox",
238
429
  checked: e.stripedRows === !0,
239
- onChange: (e) => u("stripedRows", e.target.checked),
430
+ onChange: (e) => p("stripedRows", e.target.checked),
240
431
  className: "\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n "
241
432
  }), /* @__PURE__ */ a("span", {
242
433
  className: "text-sm text-text-primary",
@@ -249,6 +440,6 @@ var s = e(function({ config: e, onChange: s }) {
249
440
  });
250
441
  });
251
442
  //#endregion
252
- export { s as default };
443
+ export { u as default };
253
444
 
254
445
  //# sourceMappingURL=TableConfig.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TableConfig.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/table/TableConfig.tsx"],"sourcesContent":["/**\n * TableConfig Component\n *\n * Configuration panel for Table widgets.\n */\n\nimport { type FC, memo, useCallback, useMemo, useEffect, useState } from 'react';\nimport type { TableConfig as ConfigType, TableColumnConfig } from '../../../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TableConfigProps {\n /** Current configuration */\n config: ConfigType;\n /** Callback when config changes */\n onChange: (config: ConfigType) => void;\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const TableConfig: FC<TableConfigProps> = memo(function TableConfig({ config, onChange }) {\n // Normalize columns - convert string[] to TableColumnConfig[]\n const initialColumns = useMemo(() => {\n return ((config.columns || []) as (string | TableColumnConfig)[]).map((col) => {\n if (typeof col === 'string') {\n return {\n field: col,\n header: col.charAt(0).toUpperCase() + col.slice(1).replace(/_/g, ' '),\n };\n }\n return col as TableColumnConfig;\n });\n }, []); // Only run once on mount\n\n // Local state for columns to make them editable\n const [columns, setColumns] = useState<TableColumnConfig[]>(initialColumns);\n\n // Sync with parent when columns change\n useEffect(() => {\n // Only update if columns actually changed (deep compare)\n const currentStr = JSON.stringify(config.columns);\n const newStr = JSON.stringify(columns);\n if (currentStr !== newStr && columns.length > 0) {\n onChange({ ...config, columns });\n }\n }, [columns]);\n\n // Reset columns when config changes from outside\n useEffect(() => {\n const normalized = ((config.columns || []) as (string | TableColumnConfig)[]).map((col) => {\n if (typeof col === 'string') {\n return {\n field: col,\n header: col.charAt(0).toUpperCase() + col.slice(1).replace(/_/g, ' '),\n };\n }\n return col as TableColumnConfig;\n });\n setColumns(normalized);\n }, [config.columns]);\n\n const handleChange = useCallback(\n <K extends keyof ConfigType>(key: K, value: ConfigType[K]) => {\n onChange({ ...config, [key]: value });\n },\n [config, onChange]\n );\n\n const handleColumnChange = useCallback((index: number, field: keyof TableColumnConfig, value: string) => {\n setColumns((prev) => {\n const newColumns = [...prev];\n newColumns[index] = { ...newColumns[index], [field]: value };\n return newColumns;\n });\n }, []);\n\n const addColumn = useCallback(() => {\n setColumns((prev) => [...prev, { field: '', header: '' }]);\n }, []);\n\n const removeColumn = useCallback((index: number) => {\n setColumns((prev) => prev.filter((_, i) => i !== index));\n }, []);\n\n return (\n <div className=\"space-y-4\">\n {/* Page Size */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">Page Size</label>\n <select\n value={config.pageSize || 10}\n onChange={(e) => handleChange('pageSize', Number(e.target.value))}\n className=\"\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value={10}>10 rows</option>\n <option value={25}>25 rows</option>\n <option value={50}>50 rows</option>\n <option value={100}>100 rows</option>\n </select>\n </div>\n\n {/* Columns Configuration */}\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <label className=\"text-sm font-medium text-text-primary\">Columns</label>\n <button\n type=\"button\"\n onClick={addColumn}\n className=\"\n text-sm text-action-primary-bg\n hover:text-action-primary-bgHover\n \"\n >\n + Add Column\n </button>\n </div>\n\n <div className=\"space-y-3\">\n {columns.map((col, index) => (\n <div\n key={index}\n className=\"\n p-3\n bg-bg-sunken\n rounded-md\n space-y-2\n \"\n >\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-text-secondary\">Column {index + 1}</span>\n <button\n type=\"button\"\n onClick={() => removeColumn(index)}\n className=\"text-state-error hover:text-state-error/80\"\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\n <div className=\"grid grid-cols-2 gap-2\">\n <input\n type=\"text\"\n value={col.field || ''}\n onChange={(e) => handleColumnChange(index, 'field', e.target.value)}\n placeholder=\"Field name\"\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n <input\n type=\"text\"\n value={col.header || ''}\n onChange={(e) => handleColumnChange(index, 'header', e.target.value)}\n placeholder=\"Header label\"\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-2\">\n <select\n value={col.format || 'text'}\n onChange={(e) => handleColumnChange(index, 'format', e.target.value)}\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value=\"text\">Text</option>\n <option value=\"number\">Number</option>\n <option value=\"currency\">Currency</option>\n <option value=\"percentage\">Percentage</option>\n <option value=\"date\">Date</option>\n <option value=\"badge\">Badge</option>\n </select>\n <select\n value={col.align || 'left'}\n onChange={(e) => handleColumnChange(index, 'align', e.target.value)}\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value=\"left\">Left</option>\n <option value=\"center\">Center</option>\n <option value=\"right\">Right</option>\n </select>\n </div>\n </div>\n ))}\n\n {columns.length === 0 && (\n <p className=\"text-sm text-text-secondary text-center py-4\">\n No columns configured. Columns will be auto-generated from data.\n </p>\n )}\n </div>\n </div>\n\n {/* Toggle Options */}\n <div className=\"space-y-3\">\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showSearch !== false}\n onChange={(e) => handleChange('showSearch', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Show search box</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showPagination !== false}\n onChange={(e) => handleChange('showPagination', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Show pagination</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showExport !== false}\n onChange={(e) => handleChange('showExport', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Show export button</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.stickyHeader === true}\n onChange={(e) => handleChange('stickyHeader', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Sticky header</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.stripedRows === true}\n onChange={(e) => handleChange('stripedRows', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Striped rows</span>\n </label>\n </div>\n </div>\n );\n});\n\nexport default TableConfig;\n"],"mappings":";;;AAwBA,IAAa,IAAoC,EAAK,SAAqB,EAAE,WAAQ,eAAY;CAe/F,IAAM,CAAC,GAAS,KAAc,EAbP,SACZ,EAAO,WAAW,EAAE,EAAqC,KAAK,MACjE,OAAO,KAAQ,WACV;EACL,OAAO;EACP,QAAQ,EAAI,OAAO,EAAE,CAAC,aAAa,GAAG,EAAI,MAAM,EAAE,CAAC,QAAQ,MAAM,IAAI;EACtE,GAEI,EACP,EACD,EAAE,CAAC,CAGqE;AAa3E,CAVA,QAAgB;AAId,EAFmB,KAAK,UAAU,EAAO,QAAQ,KAClC,KAAK,UAAU,EAAQ,IACT,EAAQ,SAAS,KAC5C,EAAS;GAAE,GAAG;GAAQ;GAAS,CAAC;IAEjC,CAAC,EAAQ,CAAC,EAGb,QAAgB;AAUd,KATqB,EAAO,WAAW,EAAE,EAAqC,KAAK,MAC7E,OAAO,KAAQ,WACV;GACL,OAAO;GACP,QAAQ,EAAI,OAAO,EAAE,CAAC,aAAa,GAAG,EAAI,MAAM,EAAE,CAAC,QAAQ,MAAM,IAAI;GACtE,GAEI,EACP,CACoB;IACrB,CAAC,EAAO,QAAQ,CAAC;CAEpB,IAAM,IAAe,GACU,GAAQ,MAAyB;AAC5D,IAAS;GAAE,GAAG;IAAS,IAAM;GAAO,CAAC;IAEvC,CAAC,GAAQ,EAAS,CACnB,EAEK,IAAqB,GAAa,GAAe,GAAgC,MAAkB;AACvG,KAAY,MAAS;GACnB,IAAM,IAAa,CAAC,GAAG,EAAK;AAE5B,UADA,EAAW,KAAS;IAAE,GAAG,EAAW;KAAS,IAAQ;IAAO,EACrD;IACP;IACD,EAAE,CAAC,EAEA,IAAY,QAAkB;AAClC,KAAY,MAAS,CAAC,GAAG,GAAM;GAAE,OAAO;GAAI,QAAQ;GAAI,CAAC,CAAC;IACzD,EAAE,CAAC,EAEA,IAAe,GAAa,MAAkB;AAClD,KAAY,MAAS,EAAK,QAAQ,GAAG,MAAM,MAAM,EAAM,CAAC;IACvD,EAAE,CAAC;AAEN,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GAEE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;IAAO,WAAU;cAAmD;IAAiB,CAAA,EACrF,kBAAC,UAAD;IACE,OAAO,EAAO,YAAY;IAC1B,WAAW,MAAM,EAAa,YAAY,OAAO,EAAE,OAAO,MAAM,CAAC;IACjE,WAAU;cAHZ;KAYE,kBAAC,UAAD;MAAQ,OAAO;gBAAI;MAAgB,CAAA;KACnC,kBAAC,UAAD;MAAQ,OAAO;gBAAI;MAAgB,CAAA;KACnC,kBAAC,UAAD;MAAQ,OAAO;gBAAI;MAAgB,CAAA;KACnC,kBAAC,UAAD;MAAQ,OAAO;gBAAK;MAAiB,CAAA;KAC9B;MACL,EAAA,CAAA;GAGN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,SAAD;KAAO,WAAU;eAAwC;KAAe,CAAA,EACxE,kBAAC,UAAD;KACE,MAAK;KACL,SAAS;KACT,WAAU;eAIX;KAEQ,CAAA,CACL;OAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,EAAQ,KAAK,GAAK,MACjB,kBAAC,OAAD;KAEE,WAAU;eAFZ;MASE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD;QAAM,WAAU;kBAAhB,CAA8C,WAAQ,IAAQ,EAAS;WACvE,kBAAC,UAAD;QACE,MAAK;QACL,eAAe,EAAa,EAAM;QAClC,WAAU;kBAEV,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;;MAEN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,SAAD;QACE,MAAK;QACL,OAAO,EAAI,SAAS;QACpB,WAAW,MAAM,EAAmB,GAAO,SAAS,EAAE,OAAO,MAAM;QACnE,aAAY;QACZ,WAAU;QAQV,CAAA,EACF,kBAAC,SAAD;QACE,MAAK;QACL,OAAO,EAAI,UAAU;QACrB,WAAW,MAAM,EAAmB,GAAO,UAAU,EAAE,OAAO,MAAM;QACpE,aAAY;QACZ,WAAU;QAQV,CAAA,CACE;;MAEN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,UAAD;QACE,OAAO,EAAI,UAAU;QACrB,WAAW,MAAM,EAAmB,GAAO,UAAU,EAAE,OAAO,MAAM;QACpE,WAAU;kBAHZ;SAYE,kBAAC,UAAD;UAAQ,OAAM;oBAAO;UAAa,CAAA;SAClC,kBAAC,UAAD;UAAQ,OAAM;oBAAS;UAAe,CAAA;SACtC,kBAAC,UAAD;UAAQ,OAAM;oBAAW;UAAiB,CAAA;SAC1C,kBAAC,UAAD;UAAQ,OAAM;oBAAa;UAAmB,CAAA;SAC9C,kBAAC,UAAD;UAAQ,OAAM;oBAAO;UAAa,CAAA;SAClC,kBAAC,UAAD;UAAQ,OAAM;oBAAQ;UAAc,CAAA;SAC7B;WACT,kBAAC,UAAD;QACE,OAAO,EAAI,SAAS;QACpB,WAAW,MAAM,EAAmB,GAAO,SAAS,EAAE,OAAO,MAAM;QACnE,WAAU;kBAHZ;SAYE,kBAAC,UAAD;UAAQ,OAAM;oBAAO;UAAa,CAAA;SAClC,kBAAC,UAAD;UAAQ,OAAM;oBAAS;UAAe,CAAA;SACtC,kBAAC,UAAD;UAAQ,OAAM;oBAAQ;UAAc,CAAA;SAC7B;UACL;;MACF;OAzFC,EAyFD,CACN,EAED,EAAQ,WAAW,KAClB,kBAAC,KAAD;KAAG,WAAU;eAA+C;KAExD,CAAA,CAEF;MACF,EAAA,CAAA;GAGN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,SAAD;MAAO,WAAU;gBAAjB,CACE,kBAAC,SAAD;OACE,MAAK;OACL,SAAS,EAAO,eAAe;OAC/B,WAAW,MAAM,EAAa,cAAc,EAAE,OAAO,QAAQ;OAC7D,WAAU;OAQV,CAAA,EACF,kBAAC,QAAD;OAAM,WAAU;iBAA4B;OAAsB,CAAA,CAC5D;;KAER,kBAAC,SAAD;MAAO,WAAU;gBAAjB,CACE,kBAAC,SAAD;OACE,MAAK;OACL,SAAS,EAAO,mBAAmB;OACnC,WAAW,MAAM,EAAa,kBAAkB,EAAE,OAAO,QAAQ;OACjE,WAAU;OAQV,CAAA,EACF,kBAAC,QAAD;OAAM,WAAU;iBAA4B;OAAsB,CAAA,CAC5D;;KAER,kBAAC,SAAD;MAAO,WAAU;gBAAjB,CACE,kBAAC,SAAD;OACE,MAAK;OACL,SAAS,EAAO,eAAe;OAC/B,WAAW,MAAM,EAAa,cAAc,EAAE,OAAO,QAAQ;OAC7D,WAAU;OAQV,CAAA,EACF,kBAAC,QAAD;OAAM,WAAU;iBAA4B;OAAyB,CAAA,CAC/D;;KAER,kBAAC,SAAD;MAAO,WAAU;gBAAjB,CACE,kBAAC,SAAD;OACE,MAAK;OACL,SAAS,EAAO,iBAAiB;OACjC,WAAW,MAAM,EAAa,gBAAgB,EAAE,OAAO,QAAQ;OAC/D,WAAU;OAQV,CAAA,EACF,kBAAC,QAAD;OAAM,WAAU;iBAA4B;OAAoB,CAAA,CAC1D;;KAER,kBAAC,SAAD;MAAO,WAAU;gBAAjB,CACE,kBAAC,SAAD;OACE,MAAK;OACL,SAAS,EAAO,gBAAgB;OAChC,WAAW,MAAM,EAAa,eAAe,EAAE,OAAO,QAAQ;OAC9D,WAAU;OAQV,CAAA,EACF,kBAAC,QAAD;OAAM,WAAU;iBAA4B;OAAmB,CAAA,CACzD;;KACJ;;GACF;;EAER"}
1
+ {"version":3,"file":"TableConfig.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/table/TableConfig.tsx"],"sourcesContent":["/**\n * TableConfig Component\n *\n * Configuration panel for Table widgets.\n */\n\nimport { type FC, memo, useCallback, useMemo, useEffect, useState } from 'react';\nimport type { TableConfig as ConfigType, TableColumnConfig } from '../../../types';\nimport type { ConditionalRule, ConditionalOperator, SemanticIntent } from '../utils/conditionalFormat';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface TableConfigProps {\n /** Current configuration */\n config: ConfigType;\n /** Callback when config changes */\n onChange: (config: ConfigType) => void;\n}\n\n// Operators offered in the conditional-formatting editor. Kept to the common,\n// self-explanatory set; the engine supports more (see conditionalFormat.ts).\nconst CF_OPERATORS: { value: ConditionalOperator; label: string }[] = [\n { value: 'gt', label: '> greater than' },\n { value: 'gte', label: '≥ at least' },\n { value: 'lt', label: '< less than' },\n { value: 'lte', label: '≤ at most' },\n { value: 'eq', label: '= equals' },\n { value: 'neq', label: '≠ not equal' },\n { value: 'between', label: 'between' },\n { value: 'outside', label: 'outside' },\n { value: 'contains', label: 'contains' },\n];\n\n// Semantic color intents — theme-safe (never raw hex). Resolved to status tokens.\nconst CF_INTENTS: { value: SemanticIntent; label: string }[] = [\n { value: 'danger', label: 'Red — danger' },\n { value: 'warning', label: 'Amber — warning' },\n { value: 'success', label: 'Green — good' },\n { value: 'info', label: 'Blue — info' },\n { value: 'neutral', label: 'Neutral' },\n];\n\nconst CF_FIELD_CLASS =\n 'px-2 py-1 text-xs text-text-primary bg-bg-surface border border-border-default rounded-md focus:outline-none focus:ring-2 focus:ring-action-primary-bg';\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const TableConfig: FC<TableConfigProps> = memo(function TableConfig({ config, onChange }) {\n // Normalize columns - convert string[] to TableColumnConfig[]\n const initialColumns = useMemo(() => {\n return ((config.columns || []) as (string | TableColumnConfig)[]).map((col) => {\n if (typeof col === 'string') {\n return {\n field: col,\n header: col.charAt(0).toUpperCase() + col.slice(1).replace(/_/g, ' '),\n };\n }\n return col as TableColumnConfig;\n });\n }, []); // Only run once on mount\n\n // Local state for columns to make them editable\n const [columns, setColumns] = useState<TableColumnConfig[]>(initialColumns);\n\n // Sync with parent when columns change\n useEffect(() => {\n // Only update if columns actually changed (deep compare)\n const currentStr = JSON.stringify(config.columns);\n const newStr = JSON.stringify(columns);\n if (currentStr !== newStr && columns.length > 0) {\n onChange({ ...config, columns });\n }\n }, [columns]);\n\n // Reset columns when config changes from outside\n useEffect(() => {\n const normalized = ((config.columns || []) as (string | TableColumnConfig)[]).map((col) => {\n if (typeof col === 'string') {\n return {\n field: col,\n header: col.charAt(0).toUpperCase() + col.slice(1).replace(/_/g, ' '),\n };\n }\n return col as TableColumnConfig;\n });\n setColumns(normalized);\n }, [config.columns]);\n\n const handleChange = useCallback(\n <K extends keyof ConfigType>(key: K, value: ConfigType[K]) => {\n onChange({ ...config, [key]: value });\n },\n [config, onChange]\n );\n\n const handleColumnChange = useCallback((index: number, field: keyof TableColumnConfig, value: string) => {\n setColumns((prev) => {\n const newColumns = [...prev];\n newColumns[index] = { ...newColumns[index], [field]: value };\n return newColumns;\n });\n }, []);\n\n // Conditional-formatting rule edits for a column. The rules array is stored on\n // `column.conditionalRules` and consumed at render time by TableCell.\n const handleColumnRules = useCallback((index: number, rules: ConditionalRule[]) => {\n setColumns((prev) => {\n const newColumns = [...prev];\n newColumns[index] = { ...newColumns[index], conditionalRules: rules };\n return newColumns;\n });\n }, []);\n\n const addRule = useCallback(\n (index: number) => {\n const existing = columns[index]?.conditionalRules ?? [];\n const next: ConditionalRule = {\n operator: 'gt',\n value: 0,\n style: { bgColor: 'danger', textColor: 'danger', bold: true },\n };\n handleColumnRules(index, [...existing, next]);\n },\n [columns, handleColumnRules]\n );\n\n const updateRule = useCallback(\n (colIndex: number, ruleIndex: number, patch: Partial<ConditionalRule>) => {\n const existing = columns[colIndex]?.conditionalRules ?? [];\n const next = existing.map((r, i) => (i === ruleIndex ? { ...r, ...patch } : r));\n handleColumnRules(colIndex, next);\n },\n [columns, handleColumnRules]\n );\n\n const updateRuleStyle = useCallback(\n (colIndex: number, ruleIndex: number, intent: SemanticIntent) => {\n const existing = columns[colIndex]?.conditionalRules ?? [];\n const next = existing.map((r, i) =>\n i === ruleIndex ? { ...r, style: { ...r.style, bgColor: intent, textColor: intent } } : r\n );\n handleColumnRules(colIndex, next);\n },\n [columns, handleColumnRules]\n );\n\n const removeRule = useCallback(\n (colIndex: number, ruleIndex: number) => {\n const existing = columns[colIndex]?.conditionalRules ?? [];\n handleColumnRules(\n colIndex,\n existing.filter((_, i) => i !== ruleIndex)\n );\n },\n [columns, handleColumnRules]\n );\n\n const addColumn = useCallback(() => {\n setColumns((prev) => [...prev, { field: '', header: '' }]);\n }, []);\n\n const removeColumn = useCallback((index: number) => {\n setColumns((prev) => prev.filter((_, i) => i !== index));\n }, []);\n\n return (\n <div className=\"space-y-4\">\n {/* Page Size */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">Page Size</label>\n <select\n value={config.pageSize || 10}\n onChange={(e) => handleChange('pageSize', Number(e.target.value))}\n className=\"\n w-full px-3 py-2\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value={10}>10 rows</option>\n <option value={25}>25 rows</option>\n <option value={50}>50 rows</option>\n <option value={100}>100 rows</option>\n </select>\n </div>\n\n {/* Columns Configuration */}\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <label className=\"text-sm font-medium text-text-primary\">Columns</label>\n <button\n type=\"button\"\n onClick={addColumn}\n className=\"\n text-sm text-action-primary-bg\n hover:text-action-primary-bgHover\n \"\n >\n + Add Column\n </button>\n </div>\n\n <div className=\"space-y-3\">\n {columns.map((col, index) => (\n <div\n key={index}\n className=\"\n p-3\n bg-bg-sunken\n rounded-md\n space-y-2\n \"\n >\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs text-text-secondary\">Column {index + 1}</span>\n <button\n type=\"button\"\n onClick={() => removeColumn(index)}\n className=\"text-state-error hover:text-state-error/80\"\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\n <div className=\"grid grid-cols-2 gap-2\">\n <input\n type=\"text\"\n value={col.field || ''}\n onChange={(e) => handleColumnChange(index, 'field', e.target.value)}\n placeholder=\"Field name\"\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n <input\n type=\"text\"\n value={col.header || ''}\n onChange={(e) => handleColumnChange(index, 'header', e.target.value)}\n placeholder=\"Header label\"\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n />\n </div>\n\n <div className=\"grid grid-cols-2 gap-2\">\n <select\n value={col.format || 'text'}\n onChange={(e) => handleColumnChange(index, 'format', e.target.value)}\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value=\"text\">Text</option>\n <option value=\"number\">Number</option>\n <option value=\"currency\">Currency</option>\n <option value=\"percentage\">Percentage</option>\n <option value=\"date\">Date</option>\n <option value=\"badge\">Badge</option>\n </select>\n <select\n value={col.align || 'left'}\n onChange={(e) => handleColumnChange(index, 'align', e.target.value)}\n className=\"\n px-2 py-1\n text-sm text-text-primary\n bg-bg-surface\n border border-border-default\n rounded-md\n focus:outline-none focus:ring-2 focus:ring-action-primary-bg\n \"\n >\n <option value=\"left\">Left</option>\n <option value=\"center\">Center</option>\n <option value=\"right\">Right</option>\n </select>\n </div>\n\n {/* Conditional formatting rules */}\n <div className=\"pt-2 border-t border-border-default/60\">\n <div className=\"flex items-center justify-between mb-1\">\n <span className=\"text-xs font-medium text-text-secondary\">Conditional formatting</span>\n <button\n type=\"button\"\n onClick={() => addRule(index)}\n className=\"text-xs text-action-primary-bg hover:text-action-primary-bgHover\"\n >\n + Add rule\n </button>\n </div>\n\n {(col.conditionalRules?.length ?? 0) === 0 && (\n <p className=\"text-xs text-text-secondary\">No rules — cell shows its plain value.</p>\n )}\n\n <div className=\"space-y-2\">\n {(col.conditionalRules ?? []).map((rule, ruleIndex) => {\n const needsSecond = rule.operator === 'between' || rule.operator === 'outside';\n const currentIntent: SemanticIntent = rule.style?.bgColor ?? rule.style?.textColor ?? 'danger';\n return (\n <div\n key={ruleIndex}\n className=\"p-2 bg-bg-surface rounded-md border border-border-default space-y-2\"\n >\n <div className=\"flex items-center gap-2\">\n <select\n value={rule.operator}\n onChange={(e) =>\n updateRule(index, ruleIndex, { operator: e.target.value as ConditionalOperator })\n }\n className={`${CF_FIELD_CLASS} flex-1`}\n >\n {CF_OPERATORS.map((op) => (\n <option key={op.value} value={op.value}>\n {op.label}\n </option>\n ))}\n </select>\n <input\n type=\"text\"\n value={rule.value ?? ''}\n onChange={(e) => updateRule(index, ruleIndex, { value: e.target.value })}\n placeholder=\"value\"\n className={`${CF_FIELD_CLASS} w-20`}\n />\n {needsSecond && (\n <input\n type=\"text\"\n value={rule.value2 ?? ''}\n onChange={(e) => updateRule(index, ruleIndex, { value2: e.target.value })}\n placeholder=\"and\"\n className={`${CF_FIELD_CLASS} w-20`}\n />\n )}\n <button\n type=\"button\"\n onClick={() => removeRule(index, ruleIndex)}\n className=\"text-state-error hover:text-state-error/80\"\n aria-label=\"Remove rule\"\n >\n <svg className=\"w-3.5 h-3.5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n <div className=\"flex items-center gap-2\">\n <select\n value={currentIntent}\n onChange={(e) => updateRuleStyle(index, ruleIndex, e.target.value as SemanticIntent)}\n className={`${CF_FIELD_CLASS} flex-1`}\n >\n {CF_INTENTS.map((it) => (\n <option key={it.value} value={it.value}>\n {it.label}\n </option>\n ))}\n </select>\n <label className=\"flex items-center gap-1 text-xs text-text-primary\">\n <input\n type=\"checkbox\"\n checked={rule.style?.bold === true}\n onChange={(e) =>\n updateRule(index, ruleIndex, { style: { ...rule.style, bold: e.target.checked } })\n }\n className=\"w-3.5 h-3.5 text-action-primary-bg bg-bg-surface border-border-default rounded focus:ring-action-primary-bg\"\n />\n Bold\n </label>\n </div>\n </div>\n );\n })}\n </div>\n </div>\n </div>\n ))}\n\n {columns.length === 0 && (\n <p className=\"text-sm text-text-secondary text-center py-4\">\n No columns configured. Columns will be auto-generated from data.\n </p>\n )}\n </div>\n </div>\n\n {/* Toggle Options */}\n <div className=\"space-y-3\">\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showSearch !== false}\n onChange={(e) => handleChange('showSearch', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Show search box</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showPagination !== false}\n onChange={(e) => handleChange('showPagination', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Show pagination</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.showExport !== false}\n onChange={(e) => handleChange('showExport', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Show export button</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.stickyHeader === true}\n onChange={(e) => handleChange('stickyHeader', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Sticky header</span>\n </label>\n\n <label className=\"flex items-center gap-3\">\n <input\n type=\"checkbox\"\n checked={config.stripedRows === true}\n onChange={(e) => handleChange('stripedRows', e.target.checked)}\n className=\"\n w-4 h-4\n text-action-primary-bg\n bg-bg-surface\n border-border-default\n rounded\n focus:ring-action-primary-bg\n \"\n />\n <span className=\"text-sm text-text-primary\">Striped rows</span>\n </label>\n </div>\n </div>\n );\n});\n\nexport default TableConfig;\n"],"mappings":"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"}
@@ -24,6 +24,7 @@ function s(e, t = {}) {
24
24
  description: e.description,
25
25
  key: e.key,
26
26
  config: e.config,
27
+ data: e.data,
27
28
  ttl: e.ttl,
28
29
  isActive: e.isActive,
29
30
  fieldMaskingEnabled: e.fieldMaskingEnabled,
@@ -1 +1 @@
1
- {"version":3,"file":"useExportDataSink.js","names":[],"sources":["../../../src/bigconsole/hooks/useExportDataSink.ts"],"sourcesContent":["/**\n * useExportDataSink Hook\n *\n * Provides DataSink export functionality with file download.\n * Exports DataSink configuration as JSON for backup/transfer.\n */\n\nimport { useCallback, useState } from 'react';\nimport { useApolloClient } from '@apollo/client/react';\nimport { GetDataSinkDocument } from '../../generated/wspace-operations';\nimport type { DataSink } from '../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ExportDataSinkOptions {\n /** Pretty print JSON output (default: true) */\n prettyPrint?: boolean;\n /** Include linked workflow info (default: false, for portability) */\n includeWorkflowLinks?: boolean;\n}\n\nexport interface UseExportDataSinkResult {\n /** Loading state */\n loading: boolean;\n /** Error state */\n error: Error | null;\n /** Export DataSink to JSON string */\n exportDataSink: (dataSinkId: string, options?: ExportDataSinkOptions) => Promise<string | null>;\n /** Export and download DataSink as JSON file */\n downloadDataSink: (dataSinkId: string, dataSinkName?: string, options?: ExportDataSinkOptions) => Promise<boolean>;\n /** Clear error */\n clearError: () => void;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst EXPORT_SCHEMA_VERSION = '1.0.0';\n\n// ============================================================================\n// Helper: Download JSON file\n// ============================================================================\n\nfunction downloadJsonFile(content: string, filename: string): void {\n const blob = new Blob([content], { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n}\n\nfunction sanitizeFilename(name: string): string {\n return name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .substring(0, 50);\n}\n\n// ============================================================================\n// Helper: Create export structure\n// ============================================================================\n\ninterface DataSinkExportStructure {\n schemaVersion: string;\n exportedAt: string;\n exportedFrom: {\n dataSinkId: string;\n workspaceId?: string;\n };\n dataSink: {\n id: string;\n name: string | null;\n description: string | null;\n key: string;\n config: Record<string, unknown> | null;\n ttl: number;\n isActive: boolean;\n fieldMaskingEnabled: boolean;\n fieldMaskingRules: Record<string, unknown> | null;\n status: string;\n setupState: string;\n refresh: DataSink['refresh'];\n exports: DataSink['exports'];\n alerts: DataSink['alerts'];\n quota: DataSink['quota'];\n metadata: Record<string, unknown> | null;\n };\n}\n\nfunction createExportStructure(dataSink: DataSink, options: ExportDataSinkOptions = {}): DataSinkExportStructure {\n return {\n schemaVersion: EXPORT_SCHEMA_VERSION,\n exportedAt: new Date().toISOString(),\n exportedFrom: {\n dataSinkId: dataSink.id,\n workspaceId: dataSink.workspaceId,\n },\n dataSink: {\n id: dataSink.id,\n name: dataSink.name,\n description: dataSink.description,\n key: dataSink.key,\n config: dataSink.config,\n ttl: dataSink.ttl,\n isActive: dataSink.isActive,\n fieldMaskingEnabled: dataSink.fieldMaskingEnabled,\n fieldMaskingRules: dataSink.fieldMaskingRules,\n status: dataSink.status,\n setupState: dataSink.setupState,\n refresh: dataSink.refresh,\n exports: dataSink.exports,\n alerts: dataSink.alerts,\n quota: dataSink.quota,\n metadata: dataSink.metadata,\n },\n };\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\nexport function useExportDataSink(): UseExportDataSinkResult {\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const apolloClient = useApolloClient();\n\n // Export DataSink to JSON string\n const exportDataSink = useCallback(\n async (dataSinkId: string, options: ExportDataSinkOptions = {}): Promise<string | null> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await apolloClient.query<{ getDataSink?: DataSink }>({\n query: GetDataSinkDocument,\n variables: { id: dataSinkId },\n fetchPolicy: 'network-only',\n });\n\n const dataSink = result.data?.getDataSink;\n\n if (!dataSink) {\n throw new Error('DataSink not found');\n }\n\n const exportData = createExportStructure(dataSink, options);\n const prettyPrint = options.prettyPrint ?? true;\n const jsonContent = prettyPrint ? JSON.stringify(exportData, null, 2) : JSON.stringify(exportData);\n\n return jsonContent;\n } catch (err) {\n const exportError = err instanceof Error ? err : new Error('Failed to export DataSink');\n setError(exportError);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [apolloClient]\n );\n\n // Export and download DataSink as JSON file\n const downloadDataSink = useCallback(\n async (dataSinkId: string, dataSinkName?: string, options: ExportDataSinkOptions = {}): Promise<boolean> => {\n try {\n const content = await exportDataSink(dataSinkId, options);\n\n if (!content) {\n return false;\n }\n\n // Extract name from content if not provided\n let filename = dataSinkName;\n try {\n const parsed = JSON.parse(content);\n filename = filename || parsed.dataSink?.name || parsed.dataSink?.key || 'datasink';\n } catch {\n filename = filename || 'datasink';\n }\n\n const sanitizedName = sanitizeFilename(filename || 'datasink');\n const timestamp = new Date().toISOString().split('T')[0];\n const fullFilename = `${sanitizedName}-datasink-export-${timestamp}.json`;\n\n downloadJsonFile(content, fullFilename);\n\n return true;\n } catch (err) {\n const downloadError = err instanceof Error ? err : new Error('Failed to download DataSink');\n setError(downloadError);\n return false;\n }\n },\n [exportDataSink]\n );\n\n // Clear error\n const clearError = useCallback(() => {\n setError(null);\n }, []);\n\n return {\n loading,\n error,\n exportDataSink,\n downloadDataSink,\n clearError,\n };\n}\n\nexport default useExportDataSink;\n"],"mappings":";;;;AAwCA,IAAM,IAAwB;AAM9B,SAAS,EAAiB,GAAiB,GAAwB;CACjE,IAAM,IAAO,IAAI,KAAK,CAAC,EAAQ,EAAE,EAAE,MAAM,oBAAoB,CAAC,EACxD,IAAM,IAAI,gBAAgB,EAAK,EAC/B,IAAO,SAAS,cAAc,IAAI;AAMxC,CALA,EAAK,OAAO,GACZ,EAAK,WAAW,GAChB,SAAS,KAAK,YAAY,EAAK,EAC/B,EAAK,OAAO,EACZ,SAAS,KAAK,YAAY,EAAK,EAC/B,IAAI,gBAAgB,EAAI;;AAG1B,SAAS,EAAiB,GAAsB;AAC9C,QAAO,EACJ,aAAa,CACb,QAAQ,eAAe,IAAI,CAC3B,QAAQ,YAAY,GAAG,CACvB,UAAU,GAAG,GAAG;;AAkCrB,SAAS,EAAsB,GAAoB,IAAiC,EAAE,EAA2B;AAC/G,QAAO;EACL,eAAe;EACf,6BAAY,IAAI,MAAM,EAAC,aAAa;EACpC,cAAc;GACZ,YAAY,EAAS;GACrB,aAAa,EAAS;GACvB;EACD,UAAU;GACR,IAAI,EAAS;GACb,MAAM,EAAS;GACf,aAAa,EAAS;GACtB,KAAK,EAAS;GACd,QAAQ,EAAS;GACjB,KAAK,EAAS;GACd,UAAU,EAAS;GACnB,qBAAqB,EAAS;GAC9B,mBAAmB,EAAS;GAC5B,QAAQ,EAAS;GACjB,YAAY,EAAS;GACrB,SAAS,EAAS;GAClB,SAAS,EAAS;GAClB,QAAQ,EAAS;GACjB,OAAO,EAAS;GAChB,UAAU,EAAS;GACpB;EACF;;AAOH,SAAgB,IAA6C;CAC3D,IAAM,CAAC,GAAS,KAAc,EAAS,GAAM,EACvC,CAAC,GAAO,KAAY,EAAuB,KAAK,EAEhD,IAAe,GAAiB,EAGhC,IAAiB,EACrB,OAAO,GAAoB,IAAiC,EAAE,KAA6B;AACzF,MAAI;AAEF,GADA,EAAW,GAAK,EAChB,EAAS,KAAK;GAQd,IAAM,KANS,MAAM,EAAa,MAAkC;IAClE,OAAO;IACP,WAAW,EAAE,IAAI,GAAY;IAC7B,aAAa;IACd,CAAC,EAEsB,MAAM;AAE9B,OAAI,CAAC,EACH,OAAU,MAAM,qBAAqB;GAGvC,IAAM,IAAa,EAAsB,GAAU,EAAQ;AAI3D,UAHoB,EAAQ,eAAe,KACT,KAAK,UAAU,GAAY,MAAM,EAAE,GAAG,KAAK,UAAU,EAAW;WAG3F,GAAK;AAGZ,UADA,EADoB,aAAe,QAAQ,IAAM,gBAAI,MAAM,4BAA4B,CAClE,EACd;YACC;AACR,KAAW,GAAM;;IAGrB,CAAC,EAAa,CACf;AA0CD,QAAO;EACL;EACA;EACA;EACA,kBA3CuB,EACvB,OAAO,GAAoB,GAAuB,IAAiC,EAAE,KAAuB;AAC1G,OAAI;IACF,IAAM,IAAU,MAAM,EAAe,GAAY,EAAQ;AAEzD,QAAI,CAAC,EACH,QAAO;IAIT,IAAI,IAAW;AACf,QAAI;KACF,IAAM,IAAS,KAAK,MAAM,EAAQ;AAClC,SAAW,KAAY,EAAO,UAAU,QAAQ,EAAO,UAAU,OAAO;YAClE;AACN,WAAuB;;AASzB,WAFA,EAAiB,GAFI,GAFC,EAAiB,KAAY,WAAW,CAExB,oCADpB,IAAI,MAAM,EAAC,aAAa,CAAC,MAAM,IAAI,CAAC,GACa,OAE5B,EAEhC;YACA,GAAK;AAGZ,WADA,EADsB,aAAe,QAAQ,IAAM,gBAAI,MAAM,8BAA8B,CACpE,EAChB;;KAGX,CAAC,EAAe,CACjB;EAYC,YATiB,QAAkB;AACnC,KAAS,KAAK;KACb,EAAE,CAAC;EAQL"}
1
+ {"version":3,"file":"useExportDataSink.js","names":[],"sources":["../../../src/bigconsole/hooks/useExportDataSink.ts"],"sourcesContent":["/**\n * useExportDataSink Hook\n *\n * Provides DataSink export functionality with file download.\n * Exports DataSink configuration as JSON for backup/transfer.\n */\n\nimport { useCallback, useState } from 'react';\nimport { useApolloClient } from '@apollo/client/react';\nimport { GetDataSinkDocument } from '../../generated/wspace-operations';\nimport type { DataSink } from '../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ExportDataSinkOptions {\n /** Pretty print JSON output (default: true) */\n prettyPrint?: boolean;\n /** Include linked workflow info (default: false, for portability) */\n includeWorkflowLinks?: boolean;\n}\n\nexport interface UseExportDataSinkResult {\n /** Loading state */\n loading: boolean;\n /** Error state */\n error: Error | null;\n /** Export DataSink to JSON string */\n exportDataSink: (dataSinkId: string, options?: ExportDataSinkOptions) => Promise<string | null>;\n /** Export and download DataSink as JSON file */\n downloadDataSink: (dataSinkId: string, dataSinkName?: string, options?: ExportDataSinkOptions) => Promise<boolean>;\n /** Clear error */\n clearError: () => void;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst EXPORT_SCHEMA_VERSION = '1.0.0';\n\n// ============================================================================\n// Helper: Download JSON file\n// ============================================================================\n\nfunction downloadJsonFile(content: string, filename: string): void {\n const blob = new Blob([content], { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n}\n\nfunction sanitizeFilename(name: string): string {\n return name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .substring(0, 50);\n}\n\n// ============================================================================\n// Helper: Create export structure\n// ============================================================================\n\ninterface DataSinkExportStructure {\n schemaVersion: string;\n exportedAt: string;\n exportedFrom: {\n dataSinkId: string;\n workspaceId?: string;\n };\n dataSink: {\n id: string;\n name: string | null;\n description: string | null;\n key: string;\n config: Record<string, unknown> | null;\n data: Record<string, unknown>;\n ttl: number;\n isActive: boolean;\n fieldMaskingEnabled: boolean;\n fieldMaskingRules: Record<string, unknown> | null;\n status: string;\n setupState: string;\n refresh: DataSink['refresh'];\n exports: DataSink['exports'];\n alerts: DataSink['alerts'];\n quota: DataSink['quota'];\n metadata: Record<string, unknown> | null;\n };\n}\n\nfunction createExportStructure(dataSink: DataSink, options: ExportDataSinkOptions = {}): DataSinkExportStructure {\n return {\n schemaVersion: EXPORT_SCHEMA_VERSION,\n exportedAt: new Date().toISOString(),\n exportedFrom: {\n dataSinkId: dataSink.id,\n workspaceId: dataSink.workspaceId,\n },\n dataSink: {\n id: dataSink.id,\n name: dataSink.name,\n description: dataSink.description,\n key: dataSink.key,\n config: dataSink.config,\n data: dataSink.data,\n ttl: dataSink.ttl,\n isActive: dataSink.isActive,\n fieldMaskingEnabled: dataSink.fieldMaskingEnabled,\n fieldMaskingRules: dataSink.fieldMaskingRules,\n status: dataSink.status,\n setupState: dataSink.setupState,\n refresh: dataSink.refresh,\n exports: dataSink.exports,\n alerts: dataSink.alerts,\n quota: dataSink.quota,\n metadata: dataSink.metadata,\n },\n };\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\nexport function useExportDataSink(): UseExportDataSinkResult {\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const apolloClient = useApolloClient();\n\n // Export DataSink to JSON string\n const exportDataSink = useCallback(\n async (dataSinkId: string, options: ExportDataSinkOptions = {}): Promise<string | null> => {\n try {\n setLoading(true);\n setError(null);\n\n const result = await apolloClient.query<{ getDataSink?: DataSink }>({\n query: GetDataSinkDocument,\n variables: { id: dataSinkId },\n fetchPolicy: 'network-only',\n });\n\n const dataSink = result.data?.getDataSink;\n\n if (!dataSink) {\n throw new Error('DataSink not found');\n }\n\n const exportData = createExportStructure(dataSink, options);\n const prettyPrint = options.prettyPrint ?? true;\n const jsonContent = prettyPrint ? JSON.stringify(exportData, null, 2) : JSON.stringify(exportData);\n\n return jsonContent;\n } catch (err) {\n const exportError = err instanceof Error ? err : new Error('Failed to export DataSink');\n setError(exportError);\n return null;\n } finally {\n setLoading(false);\n }\n },\n [apolloClient]\n );\n\n // Export and download DataSink as JSON file\n const downloadDataSink = useCallback(\n async (dataSinkId: string, dataSinkName?: string, options: ExportDataSinkOptions = {}): Promise<boolean> => {\n try {\n const content = await exportDataSink(dataSinkId, options);\n\n if (!content) {\n return false;\n }\n\n // Extract name from content if not provided\n let filename = dataSinkName;\n try {\n const parsed = JSON.parse(content);\n filename = filename || parsed.dataSink?.name || parsed.dataSink?.key || 'datasink';\n } catch {\n filename = filename || 'datasink';\n }\n\n const sanitizedName = sanitizeFilename(filename || 'datasink');\n const timestamp = new Date().toISOString().split('T')[0];\n const fullFilename = `${sanitizedName}-datasink-export-${timestamp}.json`;\n\n downloadJsonFile(content, fullFilename);\n\n return true;\n } catch (err) {\n const downloadError = err instanceof Error ? err : new Error('Failed to download DataSink');\n setError(downloadError);\n return false;\n }\n },\n [exportDataSink]\n );\n\n // Clear error\n const clearError = useCallback(() => {\n setError(null);\n }, []);\n\n return {\n loading,\n error,\n exportDataSink,\n downloadDataSink,\n clearError,\n };\n}\n\nexport default useExportDataSink;\n"],"mappings":";;;;AAwCA,IAAM,IAAwB;AAM9B,SAAS,EAAiB,GAAiB,GAAwB;CACjE,IAAM,IAAO,IAAI,KAAK,CAAC,EAAQ,EAAE,EAAE,MAAM,oBAAoB,CAAC,EACxD,IAAM,IAAI,gBAAgB,EAAK,EAC/B,IAAO,SAAS,cAAc,IAAI;AAMxC,CALA,EAAK,OAAO,GACZ,EAAK,WAAW,GAChB,SAAS,KAAK,YAAY,EAAK,EAC/B,EAAK,OAAO,EACZ,SAAS,KAAK,YAAY,EAAK,EAC/B,IAAI,gBAAgB,EAAI;;AAG1B,SAAS,EAAiB,GAAsB;AAC9C,QAAO,EACJ,aAAa,CACb,QAAQ,eAAe,IAAI,CAC3B,QAAQ,YAAY,GAAG,CACvB,UAAU,GAAG,GAAG;;AAmCrB,SAAS,EAAsB,GAAoB,IAAiC,EAAE,EAA2B;AAC/G,QAAO;EACL,eAAe;EACf,6BAAY,IAAI,MAAM,EAAC,aAAa;EACpC,cAAc;GACZ,YAAY,EAAS;GACrB,aAAa,EAAS;GACvB;EACD,UAAU;GACR,IAAI,EAAS;GACb,MAAM,EAAS;GACf,aAAa,EAAS;GACtB,KAAK,EAAS;GACd,QAAQ,EAAS;GACjB,MAAM,EAAS;GACf,KAAK,EAAS;GACd,UAAU,EAAS;GACnB,qBAAqB,EAAS;GAC9B,mBAAmB,EAAS;GAC5B,QAAQ,EAAS;GACjB,YAAY,EAAS;GACrB,SAAS,EAAS;GAClB,SAAS,EAAS;GAClB,QAAQ,EAAS;GACjB,OAAO,EAAS;GAChB,UAAU,EAAS;GACpB;EACF;;AAOH,SAAgB,IAA6C;CAC3D,IAAM,CAAC,GAAS,KAAc,EAAS,GAAM,EACvC,CAAC,GAAO,KAAY,EAAuB,KAAK,EAEhD,IAAe,GAAiB,EAGhC,IAAiB,EACrB,OAAO,GAAoB,IAAiC,EAAE,KAA6B;AACzF,MAAI;AAEF,GADA,EAAW,GAAK,EAChB,EAAS,KAAK;GAQd,IAAM,KANS,MAAM,EAAa,MAAkC;IAClE,OAAO;IACP,WAAW,EAAE,IAAI,GAAY;IAC7B,aAAa;IACd,CAAC,EAEsB,MAAM;AAE9B,OAAI,CAAC,EACH,OAAU,MAAM,qBAAqB;GAGvC,IAAM,IAAa,EAAsB,GAAU,EAAQ;AAI3D,UAHoB,EAAQ,eAAe,KACT,KAAK,UAAU,GAAY,MAAM,EAAE,GAAG,KAAK,UAAU,EAAW;WAG3F,GAAK;AAGZ,UADA,EADoB,aAAe,QAAQ,IAAM,gBAAI,MAAM,4BAA4B,CAClE,EACd;YACC;AACR,KAAW,GAAM;;IAGrB,CAAC,EAAa,CACf;AA0CD,QAAO;EACL;EACA;EACA;EACA,kBA3CuB,EACvB,OAAO,GAAoB,GAAuB,IAAiC,EAAE,KAAuB;AAC1G,OAAI;IACF,IAAM,IAAU,MAAM,EAAe,GAAY,EAAQ;AAEzD,QAAI,CAAC,EACH,QAAO;IAIT,IAAI,IAAW;AACf,QAAI;KACF,IAAM,IAAS,KAAK,MAAM,EAAQ;AAClC,SAAW,KAAY,EAAO,UAAU,QAAQ,EAAO,UAAU,OAAO;YAClE;AACN,WAAuB;;AASzB,WAFA,EAAiB,GAFI,GAFC,EAAiB,KAAY,WAAW,CAExB,oCADpB,IAAI,MAAM,EAAC,aAAa,CAAC,MAAM,IAAI,CAAC,GACa,OAE5B,EAEhC;YACA,GAAK;AAGZ,WADA,EADsB,aAAe,QAAQ,IAAM,gBAAI,MAAM,8BAA8B,CACpE,EAChB;;KAGX,CAAC,EAAe,CACjB;EAYC,YATiB,QAAkB;AACnC,KAAS,KAAK;KACb,EAAE,CAAC;EAQL"}