@burdenoff/microfe-bigconsole 2026.924.3 → 2026.925.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/BigConsoleRoot.js +94 -84
- package/dist/bigconsole/BigConsoleRoot.js.map +1 -1
- package/dist/bigconsole/assistant/previewController.js +6 -6
- package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js +73 -61
- package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js.map +1 -1
- package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js +4 -4
- package/dist/bigconsole/components/preview/AiPreviewPanel.js +5 -5
- package/dist/bigconsole/hooks/useDataSinkOperations.js +92 -89
- package/dist/bigconsole/hooks/useDataSinkOperations.js.map +1 -1
- package/dist/bigconsole/hooks/useImportDataSink.js +96 -91
- package/dist/bigconsole/hooks/useImportDataSink.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkBuilderPage.js +79 -77
- package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
- package/dist/bigconsole/providers/BigConsoleQuotaProvider.js +36 -35
- package/dist/bigconsole/providers/BigConsoleQuotaProvider.js.map +1 -1
- package/dist/bigconsole/utils/quota.js +51 -23
- package/dist/bigconsole/utils/quota.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { reportBigConsoleQuotaError as e } from "../../utils/quota.js";
|
|
2
|
+
import { Section as t, SectionStack as n } from "../common/Section.js";
|
|
2
3
|
import "../common/index.js";
|
|
3
|
-
import
|
|
4
|
-
import
|
|
4
|
+
import r from "../../hooks/useBigConsoleAnalytics.js";
|
|
5
|
+
import i from "../../hooks/useImportDataSink.js";
|
|
5
6
|
import "../../hooks/index.js";
|
|
6
|
-
import { memo as
|
|
7
|
-
import { ArrowLeft as
|
|
8
|
-
import { Badge as
|
|
7
|
+
import { memo as a, useCallback as o, useEffect as s, useRef as c, useState as l } from "react";
|
|
8
|
+
import { ArrowLeft as u, Check as d, FileJson as ee, Info as f, RefreshCw as te, Upload as p, XCircle as m } from "lucide-react";
|
|
9
|
+
import { Badge as h, Button as g, Dialog as _, DialogContent as ne, DialogDescription as re, DialogFooter as v, DialogHeader as y, DialogTitle as b, Input as x, Label as S, Spinner as ie } from "@burdenoff/fe-libs/ui";
|
|
9
10
|
import { Fragment as C, jsx as w, jsxs as T } from "react/jsx-runtime";
|
|
10
11
|
import { useI18n as E } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
11
12
|
//#region src/bigconsole/components/datasink/ImportDataSinkDialog.tsx
|
|
@@ -26,12 +27,12 @@ var D = [
|
|
|
26
27
|
function O(e) {
|
|
27
28
|
return e === "select" ? 0 : e === "complete" ? 2 : 1;
|
|
28
29
|
}
|
|
29
|
-
var k =
|
|
30
|
-
let { t: j } = E(), [M, N] =
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}, [
|
|
34
|
-
let
|
|
30
|
+
var k = a(function({ isOpen: a, onClose: k, onSuccess: A }) {
|
|
31
|
+
let { t: j } = E(), [M, N] = l("select"), [, P] = l(null), [F, I] = l(null), [L, R] = l(""), [z, B] = l(""), V = c(null), { loading: H, error: U, validationResult: W, importResult: G, validateImport: K, importDataSink: q, extractDataSinkId: J, clearState: Y } = i(), X = r();
|
|
32
|
+
s(() => {
|
|
33
|
+
a && (N("select"), P(null), I(null), R(""), B(""), Y());
|
|
34
|
+
}, [a, Y]);
|
|
35
|
+
let ae = o(async (e) => {
|
|
35
36
|
let t = e.target.files?.[0];
|
|
36
37
|
if (!t) return;
|
|
37
38
|
if (!t.name.endsWith(".json")) {
|
|
@@ -48,47 +49,58 @@ var k = r(function({ isOpen: r, onClose: k, onSuccess: A }) {
|
|
|
48
49
|
}, n.onerror = () => {
|
|
49
50
|
alert(j("bigconsole.dataSinks.import.readFileError", "Failed to read file"));
|
|
50
51
|
}, n.readAsText(t);
|
|
51
|
-
}, [K, j]),
|
|
52
|
+
}, [K, j]), oe = o((e) => {
|
|
52
53
|
e.preventDefault();
|
|
53
54
|
let t = e.dataTransfer.files?.[0];
|
|
54
55
|
if (t) {
|
|
55
56
|
let e = new DataTransfer();
|
|
56
57
|
e.items.add(t), V.current && (V.current.files = e.files, V.current.dispatchEvent(new Event("change", { bubbles: !0 })));
|
|
57
58
|
}
|
|
58
|
-
}, []),
|
|
59
|
+
}, []), se = o(async () => {
|
|
59
60
|
if (!F) return;
|
|
60
61
|
N("importing");
|
|
61
|
-
let
|
|
62
|
+
let t = {
|
|
62
63
|
name: L.trim() || void 0,
|
|
63
64
|
key: z.trim() || void 0
|
|
64
65
|
};
|
|
65
66
|
X("bigconsole.data_sink.import_clicked", { source: "import" });
|
|
66
|
-
let
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
let n;
|
|
68
|
+
try {
|
|
69
|
+
n = await q(F, t);
|
|
70
|
+
} catch (t) {
|
|
71
|
+
if (e(t)) {
|
|
72
|
+
k();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
N("preview");
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
n?.success && n.dataSink ? (N("complete"), X("bigconsole.data_sink.imported", {
|
|
79
|
+
dataSinkId: n.dataSink.id,
|
|
69
80
|
source: "import",
|
|
70
|
-
originalUpdated:
|
|
71
|
-
}), A?.(
|
|
81
|
+
originalUpdated: n.originalUpdated ?? !1
|
|
82
|
+
}), A?.(n.dataSink.id, n.dataSink.name, n.originalUpdated ?? !1)) : N("preview");
|
|
72
83
|
}, [
|
|
73
84
|
X,
|
|
74
85
|
F,
|
|
75
86
|
q,
|
|
76
87
|
z,
|
|
77
88
|
L,
|
|
89
|
+
k,
|
|
78
90
|
A
|
|
79
91
|
]), Z = !H && M !== "importing", Q = F ? J(F) : null, $ = O(M);
|
|
80
|
-
return /* @__PURE__ */ w(
|
|
81
|
-
open:
|
|
92
|
+
return /* @__PURE__ */ w(_, {
|
|
93
|
+
open: a,
|
|
82
94
|
onOpenChange: (e) => !e && Z && k(),
|
|
83
|
-
children: /* @__PURE__ */ T(
|
|
95
|
+
children: /* @__PURE__ */ T(ne, {
|
|
84
96
|
className: "flex max-h-[85vh] flex-col sm:max-w-lg",
|
|
85
97
|
children: [
|
|
86
|
-
/* @__PURE__ */ T(
|
|
98
|
+
/* @__PURE__ */ T(y, { children: [/* @__PURE__ */ T("div", {
|
|
87
99
|
className: "flex items-center gap-3",
|
|
88
100
|
children: [/* @__PURE__ */ w("div", {
|
|
89
101
|
className: "flex size-10 items-center justify-center rounded-card bg-bg-accentSubtle",
|
|
90
|
-
children: /* @__PURE__ */ w(
|
|
91
|
-
}), /* @__PURE__ */ w(
|
|
102
|
+
children: /* @__PURE__ */ w(p, { className: "size-5 text-text-link" })
|
|
103
|
+
}), /* @__PURE__ */ w(b, { children: j("bigconsole.dataSinks.import.title", "Import DataSink") })]
|
|
92
104
|
}), /* @__PURE__ */ w(re, { children: j("bigconsole.dataSinks.import.description", "Upload a DataSink export file to restore it into this workspace.") })] }),
|
|
93
105
|
/* @__PURE__ */ w("ol", {
|
|
94
106
|
className: "flex flex-wrap items-center gap-x-icon-gap gap-y-1 text-xs",
|
|
@@ -112,18 +124,18 @@ var k = r(function({ isOpen: r, onClose: k, onSuccess: A }) {
|
|
|
112
124
|
}),
|
|
113
125
|
/* @__PURE__ */ w("div", {
|
|
114
126
|
className: "min-w-0 flex-1 overflow-y-auto py-4",
|
|
115
|
-
children: /* @__PURE__ */ T(
|
|
116
|
-
M === "select" && /* @__PURE__ */ w(
|
|
127
|
+
children: /* @__PURE__ */ T(n, { children: [
|
|
128
|
+
M === "select" && /* @__PURE__ */ w(t, {
|
|
117
129
|
title: "Choose an export file",
|
|
118
130
|
description: j("bigconsole.dataSinks.import.supportedFilesHint", "Only .json files exported from BigConsole are supported"),
|
|
119
131
|
headingLevel: 3,
|
|
120
132
|
bodyClassName: "mt-form-gap",
|
|
121
133
|
children: /* @__PURE__ */ T("div", {
|
|
122
134
|
onDragOver: (e) => e.preventDefault(),
|
|
123
|
-
onDrop:
|
|
135
|
+
onDrop: oe,
|
|
124
136
|
className: "rounded-card border-2 border-dashed border-[var(--color-border-default)] p-8 text-center hover:border-[var(--color-action-primary-bg)] motion-safe:transition-colors",
|
|
125
137
|
children: [
|
|
126
|
-
/* @__PURE__ */ w(
|
|
138
|
+
/* @__PURE__ */ w(ee, { className: "mx-auto mb-4 size-12 text-text-secondary" }),
|
|
127
139
|
/* @__PURE__ */ w("p", {
|
|
128
140
|
className: "mb-2 text-sm",
|
|
129
141
|
children: j("bigconsole.dataSinks.import.dropzoneText", "Drag and drop a DataSink export file here")
|
|
@@ -136,10 +148,10 @@ var k = r(function({ isOpen: r, onClose: k, onSuccess: A }) {
|
|
|
136
148
|
ref: V,
|
|
137
149
|
type: "file",
|
|
138
150
|
accept: ".json",
|
|
139
|
-
onChange:
|
|
151
|
+
onChange: ae,
|
|
140
152
|
className: "hidden"
|
|
141
153
|
}),
|
|
142
|
-
/* @__PURE__ */ w(
|
|
154
|
+
/* @__PURE__ */ w(g, {
|
|
143
155
|
onClick: () => V.current?.click(),
|
|
144
156
|
disabled: H,
|
|
145
157
|
children: j("bigconsole.dataSinks.import.browseFiles", "Browse Files")
|
|
@@ -148,7 +160,7 @@ var k = r(function({ isOpen: r, onClose: k, onSuccess: A }) {
|
|
|
148
160
|
})
|
|
149
161
|
}),
|
|
150
162
|
(M === "preview" || M === "importing") && W && /* @__PURE__ */ T(C, { children: [
|
|
151
|
-
W.dataSinkInfo && /* @__PURE__ */ T(
|
|
163
|
+
W.dataSinkInfo && /* @__PURE__ */ T(t, {
|
|
152
164
|
emphasis: "muted",
|
|
153
165
|
padding: "compact",
|
|
154
166
|
headingLevel: 3,
|
|
@@ -181,7 +193,7 @@ var k = r(function({ isOpen: r, onClose: k, onSuccess: A }) {
|
|
|
181
193
|
children: [/* @__PURE__ */ w("span", {
|
|
182
194
|
className: "text-sm text-text-secondary",
|
|
183
195
|
children: j("bigconsole.dataSinks.import.statusLabel", "Status")
|
|
184
|
-
}), /* @__PURE__ */ w(
|
|
196
|
+
}), /* @__PURE__ */ w(h, {
|
|
185
197
|
variant: "secondary",
|
|
186
198
|
children: W.dataSinkInfo.status
|
|
187
199
|
})]
|
|
@@ -191,7 +203,7 @@ var k = r(function({ isOpen: r, onClose: k, onSuccess: A }) {
|
|
|
191
203
|
children: [/* @__PURE__ */ w("span", {
|
|
192
204
|
className: "text-sm text-text-secondary",
|
|
193
205
|
children: j("bigconsole.dataSinks.import.setupStateLabel", "Setup State")
|
|
194
|
-
}), /* @__PURE__ */ w(
|
|
206
|
+
}), /* @__PURE__ */ w(h, {
|
|
195
207
|
variant: "outline",
|
|
196
208
|
children: W.dataSinkInfo.setupState
|
|
197
209
|
})]
|
|
@@ -218,12 +230,12 @@ var k = r(function({ isOpen: r, onClose: k, onSuccess: A }) {
|
|
|
218
230
|
})
|
|
219
231
|
]
|
|
220
232
|
}),
|
|
221
|
-
W.errors.length > 0 && /* @__PURE__ */ w(
|
|
233
|
+
W.errors.length > 0 && /* @__PURE__ */ w(t, {
|
|
222
234
|
tone: "danger",
|
|
223
235
|
padding: "compact",
|
|
224
236
|
headingLevel: 3,
|
|
225
237
|
title: j("bigconsole.dataSinks.import.errorsHeading", "Errors ({{count}})", { count: W.errors.length }),
|
|
226
|
-
icon: /* @__PURE__ */ w(
|
|
238
|
+
icon: /* @__PURE__ */ w(m, { className: "size-4" }),
|
|
227
239
|
children: /* @__PURE__ */ w("ul", {
|
|
228
240
|
className: "space-y-1 text-xs text-status-error-text",
|
|
229
241
|
children: W.errors.map((e, t) => /* @__PURE__ */ T("li", { children: [
|
|
@@ -240,18 +252,18 @@ var k = r(function({ isOpen: r, onClose: k, onSuccess: A }) {
|
|
|
240
252
|
] }, t))
|
|
241
253
|
})
|
|
242
254
|
}),
|
|
243
|
-
W.isValid && /* @__PURE__ */ T(
|
|
255
|
+
W.isValid && /* @__PURE__ */ T(t, {
|
|
244
256
|
title: j("bigconsole.dataSinks.import.optionsHeading", "Import Options"),
|
|
245
257
|
description: "Rename the sink or give it a different key before importing.",
|
|
246
258
|
headingLevel: 3,
|
|
247
259
|
bodyClassName: "space-y-form-gap",
|
|
248
260
|
children: [
|
|
249
|
-
/* @__PURE__ */ w(
|
|
261
|
+
/* @__PURE__ */ w(t, {
|
|
250
262
|
tone: "info",
|
|
251
263
|
emphasis: "muted",
|
|
252
264
|
padding: "compact",
|
|
253
265
|
headingLevel: 4,
|
|
254
|
-
icon: /* @__PURE__ */ w(
|
|
266
|
+
icon: /* @__PURE__ */ w(f, { className: "size-4" }),
|
|
255
267
|
title: Q ? j("bigconsole.dataSinks.import.checkExistingHeading", "Import will check for existing DataSink") : j("bigconsole.dataSinks.import.newWillBeCreatedHeading", "A new DataSink will be created"),
|
|
256
268
|
children: /* @__PURE__ */ w("div", {
|
|
257
269
|
className: "text-xs text-[var(--color-status-info-text)]",
|
|
@@ -278,10 +290,10 @@ var k = r(function({ isOpen: r, onClose: k, onSuccess: A }) {
|
|
|
278
290
|
}),
|
|
279
291
|
/* @__PURE__ */ T("div", {
|
|
280
292
|
className: "space-y-2",
|
|
281
|
-
children: [/* @__PURE__ */ w(
|
|
293
|
+
children: [/* @__PURE__ */ w(S, {
|
|
282
294
|
htmlFor: "import-name",
|
|
283
295
|
children: j("bigconsole.dataSinks.import.nameFieldLabel", "DataSink Name")
|
|
284
|
-
}), /* @__PURE__ */ w(
|
|
296
|
+
}), /* @__PURE__ */ w(x, {
|
|
285
297
|
id: "import-name",
|
|
286
298
|
type: "text",
|
|
287
299
|
value: L,
|
|
@@ -293,11 +305,11 @@ var k = r(function({ isOpen: r, onClose: k, onSuccess: A }) {
|
|
|
293
305
|
/* @__PURE__ */ T("div", {
|
|
294
306
|
className: "space-y-2",
|
|
295
307
|
children: [
|
|
296
|
-
/* @__PURE__ */ w(
|
|
308
|
+
/* @__PURE__ */ w(S, {
|
|
297
309
|
htmlFor: "import-key",
|
|
298
310
|
children: j("bigconsole.dataSinks.import.keyFieldLabel", "DataSink Key")
|
|
299
311
|
}),
|
|
300
|
-
/* @__PURE__ */ w(
|
|
312
|
+
/* @__PURE__ */ w(x, {
|
|
301
313
|
id: "import-key",
|
|
302
314
|
type: "text",
|
|
303
315
|
value: z,
|
|
@@ -315,38 +327,38 @@ var k = r(function({ isOpen: r, onClose: k, onSuccess: A }) {
|
|
|
315
327
|
})
|
|
316
328
|
] }),
|
|
317
329
|
M === "complete" && G?.success && /* @__PURE__ */ T(C, { children: [
|
|
318
|
-
G.alreadyExists && /* @__PURE__ */ w(
|
|
330
|
+
G.alreadyExists && /* @__PURE__ */ w(t, {
|
|
319
331
|
tone: "info",
|
|
320
332
|
headingLevel: 3,
|
|
321
333
|
title: j("bigconsole.dataSinks.import.alreadyExistsTitle", "DataSink Already Exists"),
|
|
322
|
-
icon: /* @__PURE__ */ w(
|
|
334
|
+
icon: /* @__PURE__ */ w(f, { className: "h-icon-sm w-icon-sm" }),
|
|
323
335
|
children: /* @__PURE__ */ w("p", {
|
|
324
336
|
className: "text-sm text-text-secondary",
|
|
325
337
|
children: j("bigconsole.dataSinks.import.alreadyExistsBody", "DataSink \"{{name}}\" already exists with the same data. No changes were made.", { name: G.dataSink?.name || G.dataSink?.key || "" })
|
|
326
338
|
})
|
|
327
339
|
}),
|
|
328
|
-
G.originalUpdated && !G.alreadyExists && /* @__PURE__ */ w(
|
|
340
|
+
G.originalUpdated && !G.alreadyExists && /* @__PURE__ */ w(t, {
|
|
329
341
|
tone: "success",
|
|
330
342
|
headingLevel: 3,
|
|
331
343
|
title: j("bigconsole.dataSinks.import.updatedTitle", "DataSink Updated!"),
|
|
332
|
-
icon: /* @__PURE__ */ w(
|
|
344
|
+
icon: /* @__PURE__ */ w(te, { className: "h-icon-sm w-icon-sm" }),
|
|
333
345
|
children: /* @__PURE__ */ w("p", {
|
|
334
346
|
className: "text-sm text-text-secondary",
|
|
335
347
|
children: j("bigconsole.dataSinks.import.updatedBody", "DataSink \"{{name}}\" has been updated with the imported data.", { name: G.dataSink?.name || G.dataSink?.key || "" })
|
|
336
348
|
})
|
|
337
349
|
}),
|
|
338
|
-
!G.originalUpdated && !G.alreadyExists && /* @__PURE__ */ w(
|
|
350
|
+
!G.originalUpdated && !G.alreadyExists && /* @__PURE__ */ w(t, {
|
|
339
351
|
tone: "success",
|
|
340
352
|
headingLevel: 3,
|
|
341
353
|
title: j("bigconsole.dataSinks.import.successTitle", "Import Successful!"),
|
|
342
|
-
icon: /* @__PURE__ */ w(
|
|
354
|
+
icon: /* @__PURE__ */ w(d, { className: "h-icon-sm w-icon-sm" }),
|
|
343
355
|
children: /* @__PURE__ */ w("p", {
|
|
344
356
|
className: "text-sm text-text-secondary",
|
|
345
357
|
children: j("bigconsole.dataSinks.import.successBody", "DataSink \"{{name}}\" has been created.", { name: G.dataSink?.name || G.dataSink?.key || "" })
|
|
346
358
|
})
|
|
347
359
|
})
|
|
348
360
|
] }),
|
|
349
|
-
U && /* @__PURE__ */ w(
|
|
361
|
+
U && /* @__PURE__ */ w(t, {
|
|
350
362
|
tone: "danger",
|
|
351
363
|
padding: "compact",
|
|
352
364
|
headingLevel: 3,
|
|
@@ -356,7 +368,7 @@ var k = r(function({ isOpen: r, onClose: k, onSuccess: A }) {
|
|
|
356
368
|
children: U.message
|
|
357
369
|
})
|
|
358
370
|
}),
|
|
359
|
-
G && !G.success && G.errorMessage && /* @__PURE__ */ w(
|
|
371
|
+
G && !G.success && G.errorMessage && /* @__PURE__ */ w(t, {
|
|
360
372
|
tone: "danger",
|
|
361
373
|
padding: "compact",
|
|
362
374
|
headingLevel: 3,
|
|
@@ -368,37 +380,37 @@ var k = r(function({ isOpen: r, onClose: k, onSuccess: A }) {
|
|
|
368
380
|
})
|
|
369
381
|
] })
|
|
370
382
|
}),
|
|
371
|
-
/* @__PURE__ */ T(
|
|
383
|
+
/* @__PURE__ */ T(v, {
|
|
372
384
|
className: "flex flex-col-reverse gap-control-gap sm:flex-row sm:justify-between",
|
|
373
|
-
children: [M === "preview" ? /* @__PURE__ */ T(
|
|
385
|
+
children: [M === "preview" ? /* @__PURE__ */ T(g, {
|
|
374
386
|
variant: "ghost",
|
|
375
387
|
onClick: () => {
|
|
376
388
|
N("select"), P(null), I(null), Y();
|
|
377
389
|
},
|
|
378
390
|
disabled: H,
|
|
379
|
-
children: [/* @__PURE__ */ w(
|
|
391
|
+
children: [/* @__PURE__ */ w(u, { className: "size-4" }), j("bigconsole.dataSinks.import.back", "Back")]
|
|
380
392
|
}) : /* @__PURE__ */ w("span", {
|
|
381
393
|
"aria-hidden": "true",
|
|
382
394
|
className: "hidden sm:block"
|
|
383
395
|
}), /* @__PURE__ */ T("div", {
|
|
384
396
|
className: "flex flex-wrap items-center gap-2",
|
|
385
397
|
children: [
|
|
386
|
-
M !== "complete" && /* @__PURE__ */ w(
|
|
398
|
+
M !== "complete" && /* @__PURE__ */ w(g, {
|
|
387
399
|
variant: "outline",
|
|
388
400
|
onClick: k,
|
|
389
401
|
disabled: !Z,
|
|
390
402
|
children: j("bigconsole.dataSinks.import.cancel", "Cancel")
|
|
391
403
|
}),
|
|
392
|
-
M === "preview" && W?.isValid && /* @__PURE__ */ T(
|
|
393
|
-
onClick:
|
|
404
|
+
M === "preview" && W?.isValid && /* @__PURE__ */ T(g, {
|
|
405
|
+
onClick: se,
|
|
394
406
|
disabled: H,
|
|
395
|
-
children: [/* @__PURE__ */ w(
|
|
407
|
+
children: [/* @__PURE__ */ w(p, { className: "size-4" }), j("bigconsole.dataSinks.import.importButton", "Import DataSink")]
|
|
396
408
|
}),
|
|
397
409
|
M === "importing" && /* @__PURE__ */ T("div", {
|
|
398
410
|
className: "flex items-center gap-2 text-sm text-text-secondary",
|
|
399
|
-
children: [/* @__PURE__ */ w(
|
|
411
|
+
children: [/* @__PURE__ */ w(ie, { className: "size-4" }), j("bigconsole.dataSinks.import.importing", "Importing...")]
|
|
400
412
|
}),
|
|
401
|
-
M === "complete" && /* @__PURE__ */ w(
|
|
413
|
+
M === "complete" && /* @__PURE__ */ w(g, {
|
|
402
414
|
onClick: k,
|
|
403
415
|
children: j("bigconsole.dataSinks.import.done", "Done")
|
|
404
416
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImportDataSinkDialog.js","names":[],"sources":["../../../../src/bigconsole/components/datasink/ImportDataSinkDialog.tsx"],"sourcesContent":["/**\n * ImportDataSinkDialog Component\n *\n * Modal dialog for importing a DataSink from JSON file.\n * Supports both creating new DataSinks and updating existing ones.\n */\n\nimport { type FC, memo, useState, useCallback, useEffect, useRef } from 'react';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@burdenoff/fe-libs/ui';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Input } from '@burdenoff/fe-libs/ui';\nimport { Label } from '@burdenoff/fe-libs/ui';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport { Badge } from '@burdenoff/fe-libs/ui';\nimport { Upload, FileJson, Check, XCircle, ArrowLeft, RefreshCw, Info } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useImportDataSink, type ImportDataSinkOptions } from '../../hooks';\nimport { useBigConsoleAnalytics } from '../../hooks/useBigConsoleAnalytics';\nimport { Section, SectionStack } from '../common';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ImportDataSinkDialogProps {\n isOpen: boolean;\n onClose: () => void;\n onSuccess?: (dataSinkId: string, dataSinkName: string | null, originalUpdated: boolean) => void;\n}\n\ntype ImportStep = 'select' | 'preview' | 'importing' | 'complete';\n\n/**\n * Wizard steps. The dialog previously moved between three screens with no\n * indicator at all, so a user could not tell where they were.\n */\nconst WIZARD_STEPS: { id: ImportStep; label: string }[] = [\n { id: 'select', label: 'Choose file' },\n { id: 'preview', label: 'Review' },\n { id: 'complete', label: 'Done' },\n];\n\n/** Index of the wizard step currently on screen ('importing' still shows Review). */\nfunction wizardIndex(step: ImportStep): number {\n if (step === 'select') return 0;\n if (step === 'complete') return 2;\n return 1;\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const ImportDataSinkDialog: FC<ImportDataSinkDialogProps> = memo(function ImportDataSinkDialog({\n isOpen,\n onClose,\n onSuccess,\n}) {\n const { t } = useI18n();\n const [step, setStep] = useState<ImportStep>('select');\n const [, setSelectedFile] = useState<File | null>(null);\n const [fileContent, setFileContent] = useState<string | null>(null);\n const [nameOverride, setNameOverride] = useState('');\n const [keyOverride, setKeyOverride] = useState('');\n\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const {\n loading,\n error,\n validationResult,\n importResult,\n validateImport,\n importDataSink,\n extractDataSinkId,\n clearState,\n } = useImportDataSink();\n const emitBigConsoleEvent = useBigConsoleAnalytics();\n\n // Reset state when dialog opens\n useEffect(() => {\n if (isOpen) {\n setStep('select');\n setSelectedFile(null);\n setFileContent(null);\n setNameOverride('');\n setKeyOverride('');\n clearState();\n }\n }, [isOpen, clearState]);\n\n // Handle file selection\n const handleFileSelect = useCallback(\n async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n\n if (!file.name.endsWith('.json')) {\n alert(t('bigconsole.dataSinks.import.selectJsonFile', 'Please select a JSON file'));\n return;\n }\n\n setSelectedFile(file);\n\n const reader = new FileReader();\n reader.onload = async (event) => {\n const content = event.target?.result as string;\n setFileContent(content);\n\n const result = validateImport(content);\n if (result.isValid && result.dataSinkInfo) {\n setStep('preview');\n setNameOverride(result.dataSinkInfo.name || '');\n setKeyOverride(result.dataSinkInfo.key || '');\n } else {\n setStep('preview');\n }\n };\n reader.onerror = () => {\n alert(t('bigconsole.dataSinks.import.readFileError', 'Failed to read file'));\n };\n reader.readAsText(file);\n },\n [validateImport, t]\n );\n\n // Handle file drop\n const handleDrop = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n const file = e.dataTransfer.files?.[0];\n if (file) {\n const dt = new DataTransfer();\n dt.items.add(file);\n if (fileInputRef.current) {\n fileInputRef.current.files = dt.files;\n fileInputRef.current.dispatchEvent(new Event('change', { bubbles: true }));\n }\n }\n }, []);\n\n // Handle import\n const handleImport = useCallback(async () => {\n if (!fileContent) return;\n\n setStep('importing');\n\n const options: ImportDataSinkOptions = {\n name: nameOverride.trim() || undefined,\n key: keyOverride.trim() || undefined,\n };\n\n emitBigConsoleEvent('bigconsole.data_sink.import_clicked', { source: 'import' });\n\n const result = await importDataSink(fileContent, options);\n\n if (result?.success && result.dataSink) {\n setStep('complete');\n emitBigConsoleEvent('bigconsole.data_sink.imported', {\n dataSinkId: result.dataSink.id,\n source: 'import',\n originalUpdated: result.originalUpdated ?? false,\n });\n onSuccess?.(result.dataSink.id, result.dataSink.name, result.originalUpdated ?? false);\n } else {\n setStep('preview');\n }\n }, [emitBigConsoleEvent, fileContent, importDataSink, keyOverride, nameOverride, onSuccess]);\n\n const canClose = !loading && step !== 'importing';\n const dataSinkId = fileContent ? extractDataSinkId(fileContent) : null;\n const currentStepIndex = wizardIndex(step);\n\n return (\n <Dialog open={isOpen} onOpenChange={(open) => !open && canClose && onClose()}>\n <DialogContent className=\"flex max-h-[85vh] flex-col sm:max-w-lg\">\n <DialogHeader>\n <div className=\"flex items-center gap-3\">\n <div className=\"flex size-10 items-center justify-center rounded-card bg-bg-accentSubtle\">\n <Upload className=\"size-5 text-text-link\" />\n </div>\n <DialogTitle>{t('bigconsole.dataSinks.import.title', 'Import DataSink')}</DialogTitle>\n </div>\n <DialogDescription>\n {t(\n 'bigconsole.dataSinks.import.description',\n 'Upload a DataSink export file to restore it into this workspace.'\n )}\n </DialogDescription>\n </DialogHeader>\n\n {/* Step indicator — structural strip so the wizard reads as a sequence. */}\n <ol className=\"flex flex-wrap items-center gap-x-icon-gap gap-y-1 text-xs\" aria-label=\"Import progress\">\n {WIZARD_STEPS.map((wizardStep, index) => (\n <li\n key={wizardStep.id}\n aria-current={index === currentStepIndex ? 'step' : undefined}\n className={`flex items-center gap-icon-gap ${\n index === currentStepIndex ? 'font-semibold text-text-primary' : 'text-text-muted'\n }`}\n >\n <span\n className={`inline-flex size-5 items-center justify-center rounded-pill text-[10px] ${\n index <= currentStepIndex ? 'bg-action-primary-bg text-action-primary-text' : 'bg-bg-sunken'\n }`}\n >\n {index + 1}\n </span>\n {wizardStep.label}\n {index < WIZARD_STEPS.length - 1 && (\n <span aria-hidden=\"true\" className=\"text-text-muted\">\n ›\n </span>\n )}\n </li>\n ))}\n </ol>\n\n <div className=\"min-w-0 flex-1 overflow-y-auto py-4\">\n <SectionStack>\n {/* Step 1: File Selection */}\n {step === 'select' && (\n <Section\n title=\"Choose an export file\"\n description={t(\n 'bigconsole.dataSinks.import.supportedFilesHint',\n 'Only .json files exported from BigConsole are supported'\n )}\n headingLevel={3}\n bodyClassName=\"mt-form-gap\"\n >\n <div\n onDragOver={(e) => e.preventDefault()}\n onDrop={handleDrop}\n className=\"rounded-card border-2 border-dashed border-[var(--color-border-default)] p-8 text-center hover:border-[var(--color-action-primary-bg)] motion-safe:transition-colors\"\n >\n <FileJson className=\"mx-auto mb-4 size-12 text-text-secondary\" />\n <p className=\"mb-2 text-sm\">\n {t('bigconsole.dataSinks.import.dropzoneText', 'Drag and drop a DataSink export file here')}\n </p>\n <p className=\"mb-4 text-xs text-text-secondary\">{t('bigconsole.dataSinks.import.or', 'or')}</p>\n <input ref={fileInputRef} type=\"file\" accept=\".json\" onChange={handleFileSelect} className=\"hidden\" />\n <Button onClick={() => fileInputRef.current?.click()} disabled={loading}>\n {t('bigconsole.dataSinks.import.browseFiles', 'Browse Files')}\n </Button>\n </div>\n </Section>\n )}\n\n {/* Step 2: Preview & Options */}\n {(step === 'preview' || step === 'importing') && validationResult && (\n <>\n {/* What is in the file — supporting detail. */}\n {validationResult.dataSinkInfo && (\n <Section\n emphasis=\"muted\"\n padding=\"compact\"\n headingLevel={3}\n title=\"File contents\"\n description=\"What this export file describes.\"\n bodyClassName=\"space-y-2\"\n >\n <div className=\"flex items-center justify-between gap-icon-gap\">\n <span className=\"text-sm text-text-secondary\">\n {t('bigconsole.dataSinks.import.nameLabel', 'Name')}\n </span>\n <span className=\"min-w-0 truncate text-sm font-medium\">\n {validationResult.dataSinkInfo.name || t('bigconsole.dataSinks.import.unnamed', 'Unnamed')}\n </span>\n </div>\n <div className=\"flex items-center justify-between gap-icon-gap\">\n <span className=\"text-sm text-text-secondary\">\n {t('bigconsole.dataSinks.import.keyLabel', 'Key')}\n </span>\n <span className=\"min-w-0 truncate font-mono text-xs\">{validationResult.dataSinkInfo.key}</span>\n </div>\n <div className=\"flex items-center justify-between gap-icon-gap\">\n <span className=\"text-sm text-text-secondary\">\n {t('bigconsole.dataSinks.import.statusLabel', 'Status')}\n </span>\n <Badge variant=\"secondary\">{validationResult.dataSinkInfo.status}</Badge>\n </div>\n <div className=\"flex items-center justify-between gap-icon-gap\">\n <span className=\"text-sm text-text-secondary\">\n {t('bigconsole.dataSinks.import.setupStateLabel', 'Setup State')}\n </span>\n <Badge variant=\"outline\">{validationResult.dataSinkInfo.setupState}</Badge>\n </div>\n {validationResult.dataSinkInfo.exportedFrom && (\n <div className=\"flex items-center justify-between gap-icon-gap\">\n <span className=\"text-sm text-text-secondary\">\n {t('bigconsole.dataSinks.import.sourceIdLabel', 'Source ID')}\n </span>\n <span className=\"min-w-0 max-w-[180px] truncate font-mono text-xs text-text-secondary\">\n {validationResult.dataSinkInfo.exportedFrom}\n </span>\n </div>\n )}\n <div className=\"flex items-center justify-between gap-icon-gap\">\n <span className=\"text-sm text-text-secondary\">\n {t('bigconsole.dataSinks.import.schemaVersionLabel', 'Schema Version')}\n </span>\n <span className=\"text-xs text-text-secondary\">{validationResult.dataSinkInfo.schemaVersion}</span>\n </div>\n </Section>\n )}\n\n {/* Validation Errors */}\n {validationResult.errors.length > 0 && (\n <Section\n tone=\"danger\"\n padding=\"compact\"\n headingLevel={3}\n title={t('bigconsole.dataSinks.import.errorsHeading', 'Errors ({{count}})', {\n count: validationResult.errors.length,\n })}\n icon={<XCircle className=\"size-4\" />}\n >\n <ul className=\"space-y-1 text-xs text-status-error-text\">\n {validationResult.errors.map((err, idx) => (\n <li key={idx}>\n <span className=\"font-mono\">[{err.code}]</span> {err.message}\n </li>\n ))}\n </ul>\n </Section>\n )}\n\n {/* Import Options */}\n {validationResult.isValid && (\n <Section\n title={t('bigconsole.dataSinks.import.optionsHeading', 'Import Options')}\n description=\"Rename the sink or give it a different key before importing.\"\n headingLevel={3}\n bodyClassName=\"space-y-form-gap\"\n >\n <Section\n tone=\"info\"\n emphasis=\"muted\"\n padding=\"compact\"\n headingLevel={4}\n icon={<Info className=\"size-4\" />}\n title={\n dataSinkId\n ? t(\n 'bigconsole.dataSinks.import.checkExistingHeading',\n 'Import will check for existing DataSink'\n )\n : t('bigconsole.dataSinks.import.newWillBeCreatedHeading', 'A new DataSink will be created')\n }\n >\n <div className=\"text-xs text-[var(--color-status-info-text)]\">\n {dataSinkId ? (\n <>\n <p>\n {t('bigconsole.dataSinks.import.ifOriginalExistsPrefix', 'If the original DataSink (ID:')}{' '}\n <code className=\"rounded-input bg-bg-surface px-1 font-mono\">\n {dataSinkId.slice(0, 8)}...\n </code>\n {t('bigconsole.dataSinks.import.ifOriginalExistsSuffix', ') exists:')}\n </p>\n <ul className=\"mt-1 list-inside list-disc space-y-0.5\">\n <li>\n {t(\n 'bigconsole.dataSinks.import.withChangesUpdate',\n 'With changes → Update the existing DataSink'\n )}\n </li>\n <li>\n {t(\n 'bigconsole.dataSinks.import.noChangesMessage',\n 'No changes → Show \"already exists\" message'\n )}\n </li>\n </ul>\n <p className=\"mt-1\">\n {t(\n 'bigconsole.dataSinks.import.ifNotExistsCreate',\n \"If original doesn't exist → Create a new DataSink\"\n )}\n </p>\n </>\n ) : (\n <p>\n {t(\n 'bigconsole.dataSinks.import.newWillBeCreatedBody',\n 'Import as a new DataSink with the specified configuration.'\n )}\n </p>\n )}\n </div>\n </Section>\n\n <div className=\"space-y-2\">\n <Label htmlFor=\"import-name\">\n {t('bigconsole.dataSinks.import.nameFieldLabel', 'DataSink Name')}\n </Label>\n <Input\n id=\"import-name\"\n type=\"text\"\n value={nameOverride}\n onChange={(e) => setNameOverride(e.target.value)}\n placeholder={\n validationResult.dataSinkInfo?.name ||\n t('bigconsole.dataSinks.import.namePlaceholder', 'DataSink name')\n }\n disabled={step === 'importing'}\n />\n </div>\n\n <div className=\"space-y-2\">\n <Label htmlFor=\"import-key\">\n {t('bigconsole.dataSinks.import.keyFieldLabel', 'DataSink Key')}\n </Label>\n <Input\n id=\"import-key\"\n type=\"text\"\n value={keyOverride}\n onChange={(e) => setKeyOverride(e.target.value)}\n placeholder={\n validationResult.dataSinkInfo?.key ||\n t('bigconsole.dataSinks.import.keyPlaceholder', 'datasink-key')\n }\n disabled={step === 'importing'}\n />\n <p className=\"text-xs text-text-secondary\">\n {t(\n 'bigconsole.dataSinks.import.keyHelp',\n 'Use a unique key to avoid conflicts with existing DataSinks.'\n )}\n </p>\n </div>\n </Section>\n )}\n </>\n )}\n\n {/* Step 3: Complete */}\n {step === 'complete' && importResult?.success && (\n <>\n {/* Already Exists - No Changes */}\n {importResult.alreadyExists && (\n <Section\n tone=\"info\"\n headingLevel={3}\n title={t('bigconsole.dataSinks.import.alreadyExistsTitle', 'DataSink Already Exists')}\n icon={<Info className=\"h-icon-sm w-icon-sm\" />}\n >\n <p className=\"text-sm text-text-secondary\">\n {t(\n 'bigconsole.dataSinks.import.alreadyExistsBody',\n 'DataSink \"{{name}}\" already exists with the same data. No changes were made.',\n { name: importResult.dataSink?.name || importResult.dataSink?.key || '' }\n )}\n </p>\n </Section>\n )}\n\n {/* Updated Existing */}\n {importResult.originalUpdated && !importResult.alreadyExists && (\n <Section\n tone=\"success\"\n headingLevel={3}\n title={t('bigconsole.dataSinks.import.updatedTitle', 'DataSink Updated!')}\n icon={<RefreshCw className=\"h-icon-sm w-icon-sm\" />}\n >\n <p className=\"text-sm text-text-secondary\">\n {t(\n 'bigconsole.dataSinks.import.updatedBody',\n 'DataSink \"{{name}}\" has been updated with the imported data.',\n { name: importResult.dataSink?.name || importResult.dataSink?.key || '' }\n )}\n </p>\n </Section>\n )}\n\n {/* Created New */}\n {!importResult.originalUpdated && !importResult.alreadyExists && (\n <Section\n tone=\"success\"\n headingLevel={3}\n title={t('bigconsole.dataSinks.import.successTitle', 'Import Successful!')}\n icon={<Check className=\"h-icon-sm w-icon-sm\" />}\n >\n <p className=\"text-sm text-text-secondary\">\n {t('bigconsole.dataSinks.import.successBody', 'DataSink \"{{name}}\" has been created.', {\n name: importResult.dataSink?.name || importResult.dataSink?.key || '',\n })}\n </p>\n </Section>\n )}\n </>\n )}\n\n {/* Error */}\n {error && (\n <Section tone=\"danger\" padding=\"compact\" headingLevel={3} title=\"Import failed\">\n <p className=\"text-sm text-status-error-text\">{error.message}</p>\n </Section>\n )}\n\n {importResult && !importResult.success && importResult.errorMessage && (\n <Section tone=\"danger\" padding=\"compact\" headingLevel={3} title=\"Import failed\">\n <p className=\"text-sm text-status-error-text\">{importResult.errorMessage}</p>\n </Section>\n )}\n </SectionStack>\n </div>\n\n <DialogFooter className=\"flex flex-col-reverse gap-control-gap sm:flex-row sm:justify-between\">\n {step === 'preview' ? (\n <Button\n variant=\"ghost\"\n onClick={() => {\n setStep('select');\n setSelectedFile(null);\n setFileContent(null);\n clearState();\n }}\n disabled={loading}\n >\n <ArrowLeft className=\"size-4\" />\n {t('bigconsole.dataSinks.import.back', 'Back')}\n </Button>\n ) : (\n <span aria-hidden=\"true\" className=\"hidden sm:block\" />\n )}\n\n <div className=\"flex flex-wrap items-center gap-2\">\n {step !== 'complete' && (\n <Button variant=\"outline\" onClick={onClose} disabled={!canClose}>\n {t('bigconsole.dataSinks.import.cancel', 'Cancel')}\n </Button>\n )}\n\n {step === 'preview' && validationResult?.isValid && (\n <Button onClick={handleImport} disabled={loading}>\n <Upload className=\"size-4\" />\n {t('bigconsole.dataSinks.import.importButton', 'Import DataSink')}\n </Button>\n )}\n\n {step === 'importing' && (\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Spinner className=\"size-4\" />\n {t('bigconsole.dataSinks.import.importing', 'Importing...')}\n </div>\n )}\n\n {step === 'complete' && <Button onClick={onClose}>{t('bigconsole.dataSinks.import.done', 'Done')}</Button>}\n </div>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n});\n\nexport default ImportDataSinkDialog;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ImportDataSinkDialog.js","names":[],"sources":["../../../../src/bigconsole/components/datasink/ImportDataSinkDialog.tsx"],"sourcesContent":["/**\n * ImportDataSinkDialog Component\n *\n * Modal dialog for importing a DataSink from JSON file.\n * Supports both creating new DataSinks and updating existing ones.\n */\n\nimport { type FC, memo, useState, useCallback, useEffect, useRef } from 'react';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@burdenoff/fe-libs/ui';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Input } from '@burdenoff/fe-libs/ui';\nimport { Label } from '@burdenoff/fe-libs/ui';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport { Badge } from '@burdenoff/fe-libs/ui';\nimport { Upload, FileJson, Check, XCircle, ArrowLeft, RefreshCw, Info } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useImportDataSink, type ImportDataSinkOptions } from '../../hooks';\nimport { useBigConsoleAnalytics } from '../../hooks/useBigConsoleAnalytics';\nimport { Section, SectionStack } from '../common';\nimport { reportBigConsoleQuotaError } from '../../utils/quota';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ImportDataSinkDialogProps {\n isOpen: boolean;\n onClose: () => void;\n onSuccess?: (dataSinkId: string, dataSinkName: string | null, originalUpdated: boolean) => void;\n}\n\ntype ImportStep = 'select' | 'preview' | 'importing' | 'complete';\n\n/**\n * Wizard steps. The dialog previously moved between three screens with no\n * indicator at all, so a user could not tell where they were.\n */\nconst WIZARD_STEPS: { id: ImportStep; label: string }[] = [\n { id: 'select', label: 'Choose file' },\n { id: 'preview', label: 'Review' },\n { id: 'complete', label: 'Done' },\n];\n\n/** Index of the wizard step currently on screen ('importing' still shows Review). */\nfunction wizardIndex(step: ImportStep): number {\n if (step === 'select') return 0;\n if (step === 'complete') return 2;\n return 1;\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const ImportDataSinkDialog: FC<ImportDataSinkDialogProps> = memo(function ImportDataSinkDialog({\n isOpen,\n onClose,\n onSuccess,\n}) {\n const { t } = useI18n();\n const [step, setStep] = useState<ImportStep>('select');\n const [, setSelectedFile] = useState<File | null>(null);\n const [fileContent, setFileContent] = useState<string | null>(null);\n const [nameOverride, setNameOverride] = useState('');\n const [keyOverride, setKeyOverride] = useState('');\n\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const {\n loading,\n error,\n validationResult,\n importResult,\n validateImport,\n importDataSink,\n extractDataSinkId,\n clearState,\n } = useImportDataSink();\n const emitBigConsoleEvent = useBigConsoleAnalytics();\n\n // Reset state when dialog opens\n useEffect(() => {\n if (isOpen) {\n setStep('select');\n setSelectedFile(null);\n setFileContent(null);\n setNameOverride('');\n setKeyOverride('');\n clearState();\n }\n }, [isOpen, clearState]);\n\n // Handle file selection\n const handleFileSelect = useCallback(\n async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n\n if (!file.name.endsWith('.json')) {\n alert(t('bigconsole.dataSinks.import.selectJsonFile', 'Please select a JSON file'));\n return;\n }\n\n setSelectedFile(file);\n\n const reader = new FileReader();\n reader.onload = async (event) => {\n const content = event.target?.result as string;\n setFileContent(content);\n\n const result = validateImport(content);\n if (result.isValid && result.dataSinkInfo) {\n setStep('preview');\n setNameOverride(result.dataSinkInfo.name || '');\n setKeyOverride(result.dataSinkInfo.key || '');\n } else {\n setStep('preview');\n }\n };\n reader.onerror = () => {\n alert(t('bigconsole.dataSinks.import.readFileError', 'Failed to read file'));\n };\n reader.readAsText(file);\n },\n [validateImport, t]\n );\n\n // Handle file drop\n const handleDrop = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n const file = e.dataTransfer.files?.[0];\n if (file) {\n const dt = new DataTransfer();\n dt.items.add(file);\n if (fileInputRef.current) {\n fileInputRef.current.files = dt.files;\n fileInputRef.current.dispatchEvent(new Event('change', { bubbles: true }));\n }\n }\n }, []);\n\n // Handle import\n const handleImport = useCallback(async () => {\n if (!fileContent) return;\n\n setStep('importing');\n\n const options: ImportDataSinkOptions = {\n name: nameOverride.trim() || undefined,\n key: keyOverride.trim() || undefined,\n };\n\n emitBigConsoleEvent('bigconsole.data_sink.import_clicked', { source: 'import' });\n\n let result: Awaited<ReturnType<typeof importDataSink>>;\n try {\n result = await importDataSink(fileContent, options);\n } catch (err) {\n // Quota refusals (e.g. \"Set up billing\" for an org without a billing\n // account, BOFF-7913) are shown by the shared quota dialog.\n if (reportBigConsoleQuotaError(err)) {\n onClose();\n return;\n }\n setStep('preview');\n return;\n }\n\n if (result?.success && result.dataSink) {\n setStep('complete');\n emitBigConsoleEvent('bigconsole.data_sink.imported', {\n dataSinkId: result.dataSink.id,\n source: 'import',\n originalUpdated: result.originalUpdated ?? false,\n });\n onSuccess?.(result.dataSink.id, result.dataSink.name, result.originalUpdated ?? false);\n } else {\n setStep('preview');\n }\n }, [emitBigConsoleEvent, fileContent, importDataSink, keyOverride, nameOverride, onClose, onSuccess]);\n\n const canClose = !loading && step !== 'importing';\n const dataSinkId = fileContent ? extractDataSinkId(fileContent) : null;\n const currentStepIndex = wizardIndex(step);\n\n return (\n <Dialog open={isOpen} onOpenChange={(open) => !open && canClose && onClose()}>\n <DialogContent className=\"flex max-h-[85vh] flex-col sm:max-w-lg\">\n <DialogHeader>\n <div className=\"flex items-center gap-3\">\n <div className=\"flex size-10 items-center justify-center rounded-card bg-bg-accentSubtle\">\n <Upload className=\"size-5 text-text-link\" />\n </div>\n <DialogTitle>{t('bigconsole.dataSinks.import.title', 'Import DataSink')}</DialogTitle>\n </div>\n <DialogDescription>\n {t(\n 'bigconsole.dataSinks.import.description',\n 'Upload a DataSink export file to restore it into this workspace.'\n )}\n </DialogDescription>\n </DialogHeader>\n\n {/* Step indicator — structural strip so the wizard reads as a sequence. */}\n <ol className=\"flex flex-wrap items-center gap-x-icon-gap gap-y-1 text-xs\" aria-label=\"Import progress\">\n {WIZARD_STEPS.map((wizardStep, index) => (\n <li\n key={wizardStep.id}\n aria-current={index === currentStepIndex ? 'step' : undefined}\n className={`flex items-center gap-icon-gap ${\n index === currentStepIndex ? 'font-semibold text-text-primary' : 'text-text-muted'\n }`}\n >\n <span\n className={`inline-flex size-5 items-center justify-center rounded-pill text-[10px] ${\n index <= currentStepIndex ? 'bg-action-primary-bg text-action-primary-text' : 'bg-bg-sunken'\n }`}\n >\n {index + 1}\n </span>\n {wizardStep.label}\n {index < WIZARD_STEPS.length - 1 && (\n <span aria-hidden=\"true\" className=\"text-text-muted\">\n ›\n </span>\n )}\n </li>\n ))}\n </ol>\n\n <div className=\"min-w-0 flex-1 overflow-y-auto py-4\">\n <SectionStack>\n {/* Step 1: File Selection */}\n {step === 'select' && (\n <Section\n title=\"Choose an export file\"\n description={t(\n 'bigconsole.dataSinks.import.supportedFilesHint',\n 'Only .json files exported from BigConsole are supported'\n )}\n headingLevel={3}\n bodyClassName=\"mt-form-gap\"\n >\n <div\n onDragOver={(e) => e.preventDefault()}\n onDrop={handleDrop}\n className=\"rounded-card border-2 border-dashed border-[var(--color-border-default)] p-8 text-center hover:border-[var(--color-action-primary-bg)] motion-safe:transition-colors\"\n >\n <FileJson className=\"mx-auto mb-4 size-12 text-text-secondary\" />\n <p className=\"mb-2 text-sm\">\n {t('bigconsole.dataSinks.import.dropzoneText', 'Drag and drop a DataSink export file here')}\n </p>\n <p className=\"mb-4 text-xs text-text-secondary\">{t('bigconsole.dataSinks.import.or', 'or')}</p>\n <input ref={fileInputRef} type=\"file\" accept=\".json\" onChange={handleFileSelect} className=\"hidden\" />\n <Button onClick={() => fileInputRef.current?.click()} disabled={loading}>\n {t('bigconsole.dataSinks.import.browseFiles', 'Browse Files')}\n </Button>\n </div>\n </Section>\n )}\n\n {/* Step 2: Preview & Options */}\n {(step === 'preview' || step === 'importing') && validationResult && (\n <>\n {/* What is in the file — supporting detail. */}\n {validationResult.dataSinkInfo && (\n <Section\n emphasis=\"muted\"\n padding=\"compact\"\n headingLevel={3}\n title=\"File contents\"\n description=\"What this export file describes.\"\n bodyClassName=\"space-y-2\"\n >\n <div className=\"flex items-center justify-between gap-icon-gap\">\n <span className=\"text-sm text-text-secondary\">\n {t('bigconsole.dataSinks.import.nameLabel', 'Name')}\n </span>\n <span className=\"min-w-0 truncate text-sm font-medium\">\n {validationResult.dataSinkInfo.name || t('bigconsole.dataSinks.import.unnamed', 'Unnamed')}\n </span>\n </div>\n <div className=\"flex items-center justify-between gap-icon-gap\">\n <span className=\"text-sm text-text-secondary\">\n {t('bigconsole.dataSinks.import.keyLabel', 'Key')}\n </span>\n <span className=\"min-w-0 truncate font-mono text-xs\">{validationResult.dataSinkInfo.key}</span>\n </div>\n <div className=\"flex items-center justify-between gap-icon-gap\">\n <span className=\"text-sm text-text-secondary\">\n {t('bigconsole.dataSinks.import.statusLabel', 'Status')}\n </span>\n <Badge variant=\"secondary\">{validationResult.dataSinkInfo.status}</Badge>\n </div>\n <div className=\"flex items-center justify-between gap-icon-gap\">\n <span className=\"text-sm text-text-secondary\">\n {t('bigconsole.dataSinks.import.setupStateLabel', 'Setup State')}\n </span>\n <Badge variant=\"outline\">{validationResult.dataSinkInfo.setupState}</Badge>\n </div>\n {validationResult.dataSinkInfo.exportedFrom && (\n <div className=\"flex items-center justify-between gap-icon-gap\">\n <span className=\"text-sm text-text-secondary\">\n {t('bigconsole.dataSinks.import.sourceIdLabel', 'Source ID')}\n </span>\n <span className=\"min-w-0 max-w-[180px] truncate font-mono text-xs text-text-secondary\">\n {validationResult.dataSinkInfo.exportedFrom}\n </span>\n </div>\n )}\n <div className=\"flex items-center justify-between gap-icon-gap\">\n <span className=\"text-sm text-text-secondary\">\n {t('bigconsole.dataSinks.import.schemaVersionLabel', 'Schema Version')}\n </span>\n <span className=\"text-xs text-text-secondary\">{validationResult.dataSinkInfo.schemaVersion}</span>\n </div>\n </Section>\n )}\n\n {/* Validation Errors */}\n {validationResult.errors.length > 0 && (\n <Section\n tone=\"danger\"\n padding=\"compact\"\n headingLevel={3}\n title={t('bigconsole.dataSinks.import.errorsHeading', 'Errors ({{count}})', {\n count: validationResult.errors.length,\n })}\n icon={<XCircle className=\"size-4\" />}\n >\n <ul className=\"space-y-1 text-xs text-status-error-text\">\n {validationResult.errors.map((err, idx) => (\n <li key={idx}>\n <span className=\"font-mono\">[{err.code}]</span> {err.message}\n </li>\n ))}\n </ul>\n </Section>\n )}\n\n {/* Import Options */}\n {validationResult.isValid && (\n <Section\n title={t('bigconsole.dataSinks.import.optionsHeading', 'Import Options')}\n description=\"Rename the sink or give it a different key before importing.\"\n headingLevel={3}\n bodyClassName=\"space-y-form-gap\"\n >\n <Section\n tone=\"info\"\n emphasis=\"muted\"\n padding=\"compact\"\n headingLevel={4}\n icon={<Info className=\"size-4\" />}\n title={\n dataSinkId\n ? t(\n 'bigconsole.dataSinks.import.checkExistingHeading',\n 'Import will check for existing DataSink'\n )\n : t('bigconsole.dataSinks.import.newWillBeCreatedHeading', 'A new DataSink will be created')\n }\n >\n <div className=\"text-xs text-[var(--color-status-info-text)]\">\n {dataSinkId ? (\n <>\n <p>\n {t('bigconsole.dataSinks.import.ifOriginalExistsPrefix', 'If the original DataSink (ID:')}{' '}\n <code className=\"rounded-input bg-bg-surface px-1 font-mono\">\n {dataSinkId.slice(0, 8)}...\n </code>\n {t('bigconsole.dataSinks.import.ifOriginalExistsSuffix', ') exists:')}\n </p>\n <ul className=\"mt-1 list-inside list-disc space-y-0.5\">\n <li>\n {t(\n 'bigconsole.dataSinks.import.withChangesUpdate',\n 'With changes → Update the existing DataSink'\n )}\n </li>\n <li>\n {t(\n 'bigconsole.dataSinks.import.noChangesMessage',\n 'No changes → Show \"already exists\" message'\n )}\n </li>\n </ul>\n <p className=\"mt-1\">\n {t(\n 'bigconsole.dataSinks.import.ifNotExistsCreate',\n \"If original doesn't exist → Create a new DataSink\"\n )}\n </p>\n </>\n ) : (\n <p>\n {t(\n 'bigconsole.dataSinks.import.newWillBeCreatedBody',\n 'Import as a new DataSink with the specified configuration.'\n )}\n </p>\n )}\n </div>\n </Section>\n\n <div className=\"space-y-2\">\n <Label htmlFor=\"import-name\">\n {t('bigconsole.dataSinks.import.nameFieldLabel', 'DataSink Name')}\n </Label>\n <Input\n id=\"import-name\"\n type=\"text\"\n value={nameOverride}\n onChange={(e) => setNameOverride(e.target.value)}\n placeholder={\n validationResult.dataSinkInfo?.name ||\n t('bigconsole.dataSinks.import.namePlaceholder', 'DataSink name')\n }\n disabled={step === 'importing'}\n />\n </div>\n\n <div className=\"space-y-2\">\n <Label htmlFor=\"import-key\">\n {t('bigconsole.dataSinks.import.keyFieldLabel', 'DataSink Key')}\n </Label>\n <Input\n id=\"import-key\"\n type=\"text\"\n value={keyOverride}\n onChange={(e) => setKeyOverride(e.target.value)}\n placeholder={\n validationResult.dataSinkInfo?.key ||\n t('bigconsole.dataSinks.import.keyPlaceholder', 'datasink-key')\n }\n disabled={step === 'importing'}\n />\n <p className=\"text-xs text-text-secondary\">\n {t(\n 'bigconsole.dataSinks.import.keyHelp',\n 'Use a unique key to avoid conflicts with existing DataSinks.'\n )}\n </p>\n </div>\n </Section>\n )}\n </>\n )}\n\n {/* Step 3: Complete */}\n {step === 'complete' && importResult?.success && (\n <>\n {/* Already Exists - No Changes */}\n {importResult.alreadyExists && (\n <Section\n tone=\"info\"\n headingLevel={3}\n title={t('bigconsole.dataSinks.import.alreadyExistsTitle', 'DataSink Already Exists')}\n icon={<Info className=\"h-icon-sm w-icon-sm\" />}\n >\n <p className=\"text-sm text-text-secondary\">\n {t(\n 'bigconsole.dataSinks.import.alreadyExistsBody',\n 'DataSink \"{{name}}\" already exists with the same data. No changes were made.',\n { name: importResult.dataSink?.name || importResult.dataSink?.key || '' }\n )}\n </p>\n </Section>\n )}\n\n {/* Updated Existing */}\n {importResult.originalUpdated && !importResult.alreadyExists && (\n <Section\n tone=\"success\"\n headingLevel={3}\n title={t('bigconsole.dataSinks.import.updatedTitle', 'DataSink Updated!')}\n icon={<RefreshCw className=\"h-icon-sm w-icon-sm\" />}\n >\n <p className=\"text-sm text-text-secondary\">\n {t(\n 'bigconsole.dataSinks.import.updatedBody',\n 'DataSink \"{{name}}\" has been updated with the imported data.',\n { name: importResult.dataSink?.name || importResult.dataSink?.key || '' }\n )}\n </p>\n </Section>\n )}\n\n {/* Created New */}\n {!importResult.originalUpdated && !importResult.alreadyExists && (\n <Section\n tone=\"success\"\n headingLevel={3}\n title={t('bigconsole.dataSinks.import.successTitle', 'Import Successful!')}\n icon={<Check className=\"h-icon-sm w-icon-sm\" />}\n >\n <p className=\"text-sm text-text-secondary\">\n {t('bigconsole.dataSinks.import.successBody', 'DataSink \"{{name}}\" has been created.', {\n name: importResult.dataSink?.name || importResult.dataSink?.key || '',\n })}\n </p>\n </Section>\n )}\n </>\n )}\n\n {/* Error */}\n {error && (\n <Section tone=\"danger\" padding=\"compact\" headingLevel={3} title=\"Import failed\">\n <p className=\"text-sm text-status-error-text\">{error.message}</p>\n </Section>\n )}\n\n {importResult && !importResult.success && importResult.errorMessage && (\n <Section tone=\"danger\" padding=\"compact\" headingLevel={3} title=\"Import failed\">\n <p className=\"text-sm text-status-error-text\">{importResult.errorMessage}</p>\n </Section>\n )}\n </SectionStack>\n </div>\n\n <DialogFooter className=\"flex flex-col-reverse gap-control-gap sm:flex-row sm:justify-between\">\n {step === 'preview' ? (\n <Button\n variant=\"ghost\"\n onClick={() => {\n setStep('select');\n setSelectedFile(null);\n setFileContent(null);\n clearState();\n }}\n disabled={loading}\n >\n <ArrowLeft className=\"size-4\" />\n {t('bigconsole.dataSinks.import.back', 'Back')}\n </Button>\n ) : (\n <span aria-hidden=\"true\" className=\"hidden sm:block\" />\n )}\n\n <div className=\"flex flex-wrap items-center gap-2\">\n {step !== 'complete' && (\n <Button variant=\"outline\" onClick={onClose} disabled={!canClose}>\n {t('bigconsole.dataSinks.import.cancel', 'Cancel')}\n </Button>\n )}\n\n {step === 'preview' && validationResult?.isValid && (\n <Button onClick={handleImport} disabled={loading}>\n <Upload className=\"size-4\" />\n {t('bigconsole.dataSinks.import.importButton', 'Import DataSink')}\n </Button>\n )}\n\n {step === 'importing' && (\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Spinner className=\"size-4\" />\n {t('bigconsole.dataSinks.import.importing', 'Importing...')}\n </div>\n )}\n\n {step === 'complete' && <Button onClick={onClose}>{t('bigconsole.dataSinks.import.done', 'Done')}</Button>}\n </div>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n});\n\nexport default ImportDataSinkDialog;\n"],"mappings":"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"}
|
|
@@ -6,11 +6,11 @@ import { DOCK_CLEARANCE as i, PreviewMeta as a, STEP_LABEL as o, formatAgo as s,
|
|
|
6
6
|
import { ArrowUpRight as l, Braces as u, Database as d, LayoutDashboard as f, Loader2 as p, Sparkles as m, X as h } from "lucide-react";
|
|
7
7
|
import { Button as g } from "@burdenoff/fe-libs/ui";
|
|
8
8
|
import { jsx as _, jsxs as v } from "react/jsx-runtime";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { useI18n as y } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
10
|
+
import { AssistantEntityPreview as b } from "@burdenoff/fe-libs/shared/assistant";
|
|
11
11
|
//#region src/bigconsole/components/preview/AiPreviewMiniPanel.tsx
|
|
12
12
|
function x({ onNavigate: x }) {
|
|
13
|
-
let { t: S } =
|
|
13
|
+
let { t: S } = y(), C = e(), w = n((e) => e.isRunning), T = n((e) => e.previewOpen), E = n((e) => e.hasRun), D = n((e) => e.richMounted), O = n((e) => e.steps), k = n((e) => e.entityIds), A = n((e) => e.caption), j = n((e) => e.error), M = n((e) => e.updatedAt), N = n((e) => e.openPreview), P = n((e) => e.closePreview), F = (e) => {
|
|
14
14
|
x ? x(e) : typeof window < "u" && window.location.assign(e);
|
|
15
15
|
};
|
|
16
16
|
if (!E || D || C) return null;
|
|
@@ -71,7 +71,7 @@ function x({ onNavigate: x }) {
|
|
|
71
71
|
children: [/* @__PURE__ */ _("h2", {
|
|
72
72
|
className: "sr-only",
|
|
73
73
|
children: S("bigconsole.widget.aiPreviewMini.title", "AI Preview")
|
|
74
|
-
}), /* @__PURE__ */ _(
|
|
74
|
+
}), /* @__PURE__ */ _(b, {
|
|
75
75
|
title: S("bigconsole.widget.aiPreviewMini.title", "AI Preview"),
|
|
76
76
|
steps: L,
|
|
77
77
|
caption: w ? A || S("bigconsole.widget.aiPreviewMini.working", "Working…") : S("bigconsole.widget.aiPreviewMini.done", "Done"),
|
|
@@ -10,8 +10,8 @@ import { useEffect as m, useRef as h, useState as g } from "react";
|
|
|
10
10
|
import { ArrowUpRight as _, Loader2 as v, Sparkles as y, X as b } from "lucide-react";
|
|
11
11
|
import { Button as x } from "@burdenoff/fe-libs/ui";
|
|
12
12
|
import { jsx as S, jsxs as C } from "react/jsx-runtime";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
13
|
+
import { useI18n as w } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
14
|
+
import { AssistantEntityPreview as T } from "@burdenoff/fe-libs/shared/assistant";
|
|
15
15
|
//#region src/bigconsole/components/preview/AiPreviewPanel.tsx
|
|
16
16
|
function E({ children: e }) {
|
|
17
17
|
return /* @__PURE__ */ S("div", {
|
|
@@ -21,7 +21,7 @@ function E({ children: e }) {
|
|
|
21
21
|
});
|
|
22
22
|
}
|
|
23
23
|
function D({ onOpen: e }) {
|
|
24
|
-
let { t } =
|
|
24
|
+
let { t } = w();
|
|
25
25
|
return /* @__PURE__ */ C(x, {
|
|
26
26
|
size: "sm",
|
|
27
27
|
variant: "outline",
|
|
@@ -31,7 +31,7 @@ function D({ onOpen: e }) {
|
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
33
|
function O() {
|
|
34
|
-
let { t: _ } =
|
|
34
|
+
let { t: _ } = w(), O = t(), k = e(), A = r((e) => e.isRunning), j = r((e) => e.previewOpen), M = r((e) => e.hasRun), N = r((e) => e.steps), P = r((e) => e.entityIds), F = r((e) => e.caption), I = r((e) => e.error), L = r((e) => e.updatedAt), R = r((e) => e.openPreview), z = r((e) => e.closePreview), B = r((e) => e.setRichMounted);
|
|
35
35
|
m(() => (B(!0), () => {
|
|
36
36
|
B(!1);
|
|
37
37
|
}), [B]);
|
|
@@ -131,7 +131,7 @@ function O() {
|
|
|
131
131
|
children: [/* @__PURE__ */ S("h2", {
|
|
132
132
|
className: "sr-only",
|
|
133
133
|
children: _("bigconsole.widget.aiPreview.title", "AI Preview")
|
|
134
|
-
}), /* @__PURE__ */ S(
|
|
134
|
+
}), /* @__PURE__ */ S(T, {
|
|
135
135
|
title: _("bigconsole.widget.aiPreview.title", "AI Preview"),
|
|
136
136
|
runKey: String(V),
|
|
137
137
|
steps: G,
|