@burdenoff/microfe-bigconsole 2026.805.2 → 2026.805.3
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/components/builder/inspector/DataBindingSection.js +109 -113
- package/dist/bigconsole/components/builder/inspector/DataBindingSection.js.map +1 -1
- package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js +115 -113
- package/dist/bigconsole/components/dashboard/CreateDashboardDialog.js.map +1 -1
- package/dist/bigconsole/components/dashboard/DashboardCanvas.js +71 -62
- package/dist/bigconsole/components/dashboard/DashboardCanvas.js.map +1 -1
- package/dist/bigconsole/components/dashboard/DashboardToolbar.js +90 -89
- package/dist/bigconsole/components/dashboard/DashboardToolbar.js.map +1 -1
- package/dist/bigconsole/components/dashboard/DrilldownBreadcrumb.js +56 -54
- package/dist/bigconsole/components/dashboard/DrilldownBreadcrumb.js.map +1 -1
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterChip.js +126 -125
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterChip.js.map +1 -1
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.js +151 -150
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.js.map +1 -1
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterPresetSelector.js +77 -76
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterPresetSelector.js.map +1 -1
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.js +97 -96
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.js.map +1 -1
- package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js +172 -191
- package/dist/bigconsole/components/dashboard/ImportDashboardDialog.js.map +1 -1
- package/dist/bigconsole/components/dashboard/PublishToStoreDialog.js +75 -83
- package/dist/bigconsole/components/dashboard/PublishToStoreDialog.js.map +1 -1
- package/dist/bigconsole/components/dashboard/SavedViewsDropdown/SavedViewsDropdown.js +151 -154
- package/dist/bigconsole/components/dashboard/SavedViewsDropdown/SavedViewsDropdown.js.map +1 -1
- package/dist/bigconsole/components/dashboard/ShareDialog/EmbedTab.js +181 -190
- package/dist/bigconsole/components/dashboard/ShareDialog/EmbedTab.js.map +1 -1
- package/dist/bigconsole/components/dashboard/TemplatePicker/TemplatePicker.js +1 -0
- package/dist/bigconsole/components/dashboard/WidgetPalette.js +110 -108
- package/dist/bigconsole/components/dashboard/WidgetPalette.js.map +1 -1
- package/dist/bigconsole/components/datasink/CacheTTLSelector.js +102 -103
- package/dist/bigconsole/components/datasink/CacheTTLSelector.js.map +1 -1
- package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js +36 -41
- package/dist/bigconsole/components/datasink/DataSinkDeleteDialog.js.map +1 -1
- package/dist/bigconsole/components/datasink/DataSinkRefreshDialog.js +38 -37
- package/dist/bigconsole/components/datasink/DataSinkRefreshDialog.js.map +1 -1
- package/dist/bigconsole/components/datasink/ImportDataGuideDialog.js +113 -117
- package/dist/bigconsole/components/datasink/ImportDataGuideDialog.js.map +1 -1
- package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js +182 -197
- package/dist/bigconsole/components/datasink/ImportDataSinkDialog.js.map +1 -1
- package/dist/bigconsole/components/datasink/RefreshTypeSelector.js +166 -168
- package/dist/bigconsole/components/datasink/RefreshTypeSelector.js.map +1 -1
- package/dist/bigconsole/components/parser/DataSinkSelector.js +87 -86
- package/dist/bigconsole/components/parser/DataSinkSelector.js.map +1 -1
- package/dist/bigconsole/components/parser/ImportParserDialog.js +196 -211
- package/dist/bigconsole/components/parser/ImportParserDialog.js.map +1 -1
- package/dist/bigconsole/components/parser/ParserSelector.js +130 -128
- package/dist/bigconsole/components/parser/ParserSelector.js.map +1 -1
- package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js +66 -63
- package/dist/bigconsole/components/preview/AiPreviewMiniPanel.js.map +1 -1
- package/dist/bigconsole/components/preview/AiPreviewPanel.js +95 -91
- package/dist/bigconsole/components/preview/AiPreviewPanel.js.map +1 -1
- package/dist/bigconsole/components/widgets/ActionConfigDialog.js +222 -215
- package/dist/bigconsole/components/widgets/ActionConfigDialog.js.map +1 -1
- package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js +149 -145
- package/dist/bigconsole/components/widgets/DrilldownConfigPanel.js.map +1 -1
- package/dist/bigconsole/components/widgets/PropertiesPanel.js +504 -470
- package/dist/bigconsole/components/widgets/PropertiesPanel.js.map +1 -1
- package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js +44 -47
- package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/chart/ChartConfig.js +143 -142
- package/dist/bigconsole/components/widgets/chart/ChartConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/comments/WidgetComments.js +101 -88
- package/dist/bigconsole/components/widgets/comments/WidgetComments.js.map +1 -1
- package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js +135 -134
- package/dist/bigconsole/components/widgets/event-logs/EventLogViewer.js.map +1 -1
- package/dist/bigconsole/components/widgets/form/FormWidget.js +167 -159
- package/dist/bigconsole/components/widgets/form/FormWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js +69 -68
- package/dist/bigconsole/components/widgets/gauge/GaugeConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js +64 -72
- package/dist/bigconsole/components/widgets/heatmap/HeatmapConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js +60 -59
- package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/list/ListConfig.js +57 -56
- package/dist/bigconsole/components/widgets/list/ListConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js +70 -69
- package/dist/bigconsole/components/widgets/metric-card/MetricCardConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js +35 -34
- package/dist/bigconsole/components/widgets/metric-card/SparklineChart.js.map +1 -1
- package/dist/bigconsole/components/widgets/metric-card/TrendIndicator.js +20 -19
- package/dist/bigconsole/components/widgets/metric-card/TrendIndicator.js.map +1 -1
- package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js +178 -177
- package/dist/bigconsole/components/widgets/pivot-table/PivotTableWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/progress/ProgressConfig.js +76 -75
- package/dist/bigconsole/components/widgets/progress/ProgressConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/table/TableConfig.js +183 -168
- package/dist/bigconsole/components/widgets/table/TableConfig.js.map +1 -1
- package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js +187 -180
- package/dist/bigconsole/components/widgets/webhook-config/WebhookConfigPanel.js.map +1 -1
- package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js +40 -38
- package/dist/bigconsole/customWidget/CustomWidgetBuilderSheet.js.map +1 -1
- package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js +150 -148
- package/dist/bigconsole/customWidget/CustomWidgetProposalPanel.js.map +1 -1
- package/dist/bigconsole/pages/DashboardBuilderPage.js +181 -176
- package/dist/bigconsole/pages/DashboardBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/DashboardViewPage.js +196 -192
- package/dist/bigconsole/pages/DashboardViewPage.js.map +1 -1
- package/dist/bigconsole/pages/DashboardsPage.js +223 -219
- package/dist/bigconsole/pages/DashboardsPage.js.map +1 -1
- package/dist/bigconsole/pages/DataParsersPage.js +167 -170
- package/dist/bigconsole/pages/DataParsersPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkBuilderPage.js +204 -189
- package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkViewPage.js +175 -169
- package/dist/bigconsole/pages/DataSinkViewPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSourcesPage.js +8 -7
- package/dist/bigconsole/pages/DataSourcesPage.js.map +1 -1
- package/dist/bigconsole/pages/InsightsPage.js +238 -208
- package/dist/bigconsole/pages/InsightsPage.js.map +1 -1
- package/dist/bigconsole/pages/ParserBuilderPage.js +464 -412
- package/dist/bigconsole/pages/ParserBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/ParserViewPage.js +92 -90
- package/dist/bigconsole/pages/ParserViewPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelineBuilderPage.js +221 -194
- package/dist/bigconsole/pages/PipelineBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelineViewPage.js +181 -184
- package/dist/bigconsole/pages/PipelineViewPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelinesPage.js +128 -127
- package/dist/bigconsole/pages/PipelinesPage.js.map +1 -1
- package/dist/bigconsole/pages/SettingsPage.js +177 -172
- package/dist/bigconsole/pages/SettingsPage.js.map +1 -1
- package/dist/bigconsole/pages/WidgetDemoPage.js +121 -83
- package/dist/bigconsole/pages/WidgetDemoPage.js.map +1 -1
- package/dist/bigconsole/pages/WorkflowViewPage.js +199 -193
- package/dist/bigconsole/pages/WorkflowViewPage.js.map +1 -1
- package/dist/bigconsole/pages/WorkflowsPage.js +129 -128
- package/dist/bigconsole/pages/WorkflowsPage.js.map +1 -1
- package/dist/bigconsole/renderers/adapters/AdaptiveCardRenderer.js +111 -109
- package/dist/bigconsole/renderers/adapters/AdaptiveCardRenderer.js.map +1 -1
- package/dist/bigconsole/renderers/adapters/BlockKitRenderer.js +127 -126
- package/dist/bigconsole/renderers/adapters/BlockKitRenderer.js.map +1 -1
- package/dist/bigconsole/renderers/adapters/CustomRenderer.js +103 -103
- package/dist/bigconsole/renderers/adapters/CustomRenderer.js.map +1 -1
- package/package.json +2 -1
|
@@ -1,215 +1,211 @@
|
|
|
1
1
|
import { parseCsv as e } from "../../utils/csv.js";
|
|
2
2
|
import { memo as t, useCallback as n, useEffect as r, useRef as i, useState as a } from "react";
|
|
3
3
|
import { AlertTriangle as o, ArrowRight as s, FileUp as c, Loader2 as l, Upload as u, Workflow as d } from "lucide-react";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { useI18n as f } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
5
|
+
import { Button as p, Dialog as m, DialogContent as h, DialogDescription as g, DialogFooter as _, DialogHeader as v, DialogTitle as y } from "@burdenoff/fe-libs/ui";
|
|
6
|
+
import { Fragment as b, jsx as x, jsxs as S } from "react/jsx-runtime";
|
|
6
7
|
//#region src/bigconsole/components/datasink/ImportDataGuideDialog.tsx
|
|
7
|
-
var
|
|
8
|
-
let
|
|
9
|
-
|
|
8
|
+
var C = 6, w = 1e7, T = 5e4, E = t(function({ isOpen: t, dataSinkName: E, hasExistingData: D, onClose: O, onGoToWorkflows: k, onImportCsv: A }) {
|
|
9
|
+
let { t: j } = f(), M = i(null), N = i(0), [P, F] = a(null), [I, L] = a(null), [R, z] = a(null), [B, V] = a(null), [H, U] = a(!1), W = n(() => {
|
|
10
|
+
N.current += 1, F(null), L(null), z(null), V(null), U(!1);
|
|
10
11
|
}, []);
|
|
11
12
|
r(() => {
|
|
12
|
-
t ||
|
|
13
|
-
}, [t,
|
|
14
|
-
let
|
|
13
|
+
t || W();
|
|
14
|
+
}, [t, W]);
|
|
15
|
+
let G = n(async (t) => {
|
|
15
16
|
let n = t.target.files?.[0];
|
|
16
17
|
if (t.target.value = "", !n) return;
|
|
17
|
-
let r =
|
|
18
|
-
if (
|
|
19
|
-
|
|
18
|
+
let r = N.current += 1;
|
|
19
|
+
if (L(null), z(null), V(null), F(n.name), n.size > w) {
|
|
20
|
+
z(j("bigconsole.dataSinks.importGuide.csvTooLarge", "This CSV is larger than 10 MB. Import large datasets with a workflow instead."));
|
|
20
21
|
return;
|
|
21
22
|
}
|
|
22
23
|
try {
|
|
23
24
|
let t = await n.text();
|
|
24
|
-
if (r !==
|
|
25
|
+
if (r !== N.current) return;
|
|
25
26
|
let i = e(t);
|
|
26
|
-
if (i.rows.length >
|
|
27
|
-
|
|
27
|
+
if (i.rows.length > T) {
|
|
28
|
+
z(j("bigconsole.dataSinks.importGuide.csvTooManyRows", "This CSV has {{rows}} rows (limit {{limit}}). Import large datasets with a workflow instead.", {
|
|
29
|
+
rows: i.rows.length.toLocaleString(),
|
|
30
|
+
limit: T.toLocaleString()
|
|
31
|
+
}));
|
|
28
32
|
return;
|
|
29
33
|
}
|
|
30
|
-
|
|
34
|
+
L(i);
|
|
31
35
|
} catch (e) {
|
|
32
|
-
if (r !==
|
|
33
|
-
|
|
36
|
+
if (r !== N.current) return;
|
|
37
|
+
L(null), z(e instanceof Error ? e.message : j("bigconsole.dataSinks.importGuide.parseFailed", "Failed to parse the CSV file."));
|
|
34
38
|
}
|
|
35
|
-
}, []),
|
|
36
|
-
if (!(!
|
|
37
|
-
|
|
39
|
+
}, [j]), K = n(async () => {
|
|
40
|
+
if (!(!I || !A)) {
|
|
41
|
+
U(!0), V(null);
|
|
38
42
|
try {
|
|
39
|
-
await
|
|
43
|
+
await A(I.rows) ? O() : V(j("bigconsole.dataSinks.importGuide.importFailed", "Import failed. Please try again."));
|
|
40
44
|
} catch (e) {
|
|
41
|
-
|
|
45
|
+
V(e instanceof Error ? e.message : j("bigconsole.dataSinks.importGuide.importFailed", "Import failed. Please try again."));
|
|
42
46
|
} finally {
|
|
43
|
-
|
|
47
|
+
U(!1);
|
|
44
48
|
}
|
|
45
49
|
}
|
|
46
50
|
}, [
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
I,
|
|
52
|
+
A,
|
|
53
|
+
O,
|
|
54
|
+
j
|
|
55
|
+
]), q = n(() => M.current?.click(), []), J = I?.columns.slice(0, C) ?? [], Y = I ? I.columns.length - J.length : 0;
|
|
56
|
+
return /* @__PURE__ */ x(m, {
|
|
52
57
|
open: t,
|
|
53
|
-
onOpenChange: (e) => !e && !
|
|
54
|
-
children: /* @__PURE__ */
|
|
58
|
+
onOpenChange: (e) => !e && !H && O(),
|
|
59
|
+
children: /* @__PURE__ */ S(h, {
|
|
55
60
|
className: "sm:max-w-lg",
|
|
56
61
|
children: [
|
|
57
|
-
/* @__PURE__ */
|
|
62
|
+
/* @__PURE__ */ S(v, { children: [/* @__PURE__ */ S("div", {
|
|
58
63
|
className: "flex items-center gap-3",
|
|
59
|
-
children: [/* @__PURE__ */
|
|
64
|
+
children: [/* @__PURE__ */ x("div", {
|
|
60
65
|
className: "flex size-10 items-center justify-center rounded-lg bg-action-primary-bg/10",
|
|
61
|
-
children: /* @__PURE__ */
|
|
62
|
-
}), /* @__PURE__ */
|
|
63
|
-
}), /* @__PURE__ */
|
|
64
|
-
/* @__PURE__ */
|
|
66
|
+
children: /* @__PURE__ */ x(u, { className: "size-5 text-action-primary-bg" })
|
|
67
|
+
}), /* @__PURE__ */ x(y, { children: j("bigconsole.dataSinks.importGuide.title", "Import data") })]
|
|
68
|
+
}), /* @__PURE__ */ x(g, { children: E ? j("bigconsole.dataSinks.importGuide.descriptionNamed", "Add data to “{{name}}”", { name: E }) : j("bigconsole.dataSinks.importGuide.description", "Add data to this data sink") })] }),
|
|
69
|
+
/* @__PURE__ */ S("div", {
|
|
65
70
|
className: "py-2 space-y-5",
|
|
66
71
|
children: [
|
|
67
|
-
/* @__PURE__ */
|
|
72
|
+
/* @__PURE__ */ S("section", {
|
|
68
73
|
className: "space-y-3",
|
|
69
|
-
children: [/* @__PURE__ */
|
|
74
|
+
children: [/* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("h3", {
|
|
70
75
|
className: "text-sm font-semibold text-text-primary",
|
|
71
|
-
children: "Build a workflow"
|
|
72
|
-
}), /* @__PURE__ */
|
|
76
|
+
children: j("bigconsole.dataSinks.importGuide.buildWorkflowHeading", "Build a workflow")
|
|
77
|
+
}), /* @__PURE__ */ x("p", {
|
|
73
78
|
className: "text-sm text-text-secondary leading-relaxed",
|
|
74
|
-
children: "The recommended way to keep this data sink up to date — build a repeatable, scheduled pipeline that fetches from your source (an API, database, or app) and writes into this data sink on every run."
|
|
75
|
-
})] }), /* @__PURE__ */
|
|
79
|
+
children: j("bigconsole.dataSinks.importGuide.buildWorkflowBody", "The recommended way to keep this data sink up to date — build a repeatable, scheduled pipeline that fetches from your source (an API, database, or app) and writes into this data sink on every run.")
|
|
80
|
+
})] }), /* @__PURE__ */ S(p, {
|
|
76
81
|
variant: "default",
|
|
77
|
-
onClick:
|
|
78
|
-
disabled:
|
|
82
|
+
onClick: k,
|
|
83
|
+
disabled: H,
|
|
79
84
|
className: "w-full",
|
|
80
85
|
children: [
|
|
81
|
-
/* @__PURE__ */
|
|
82
|
-
"Go to Workflows",
|
|
83
|
-
/* @__PURE__ */
|
|
86
|
+
/* @__PURE__ */ x(d, { className: "size-4" }),
|
|
87
|
+
j("bigconsole.dataSinks.importGuide.goToWorkflows", "Go to Workflows"),
|
|
88
|
+
/* @__PURE__ */ x(s, { className: "size-4" })
|
|
84
89
|
]
|
|
85
90
|
})]
|
|
86
91
|
}),
|
|
87
|
-
|
|
92
|
+
A && /* @__PURE__ */ S("div", {
|
|
88
93
|
className: "flex items-center gap-3",
|
|
89
94
|
children: [
|
|
90
|
-
/* @__PURE__ */
|
|
91
|
-
/* @__PURE__ */
|
|
95
|
+
/* @__PURE__ */ x("span", { className: "h-px flex-1 bg-border-subtle" }),
|
|
96
|
+
/* @__PURE__ */ x("span", {
|
|
92
97
|
className: "text-xs font-medium uppercase tracking-wide text-text-tertiary",
|
|
93
|
-
children: "Or"
|
|
98
|
+
children: j("bigconsole.dataSinks.importGuide.or", "Or")
|
|
94
99
|
}),
|
|
95
|
-
/* @__PURE__ */
|
|
100
|
+
/* @__PURE__ */ x("span", { className: "h-px flex-1 bg-border-subtle" })
|
|
96
101
|
]
|
|
97
102
|
}),
|
|
98
|
-
|
|
103
|
+
A && /* @__PURE__ */ S("section", {
|
|
99
104
|
className: "space-y-3",
|
|
100
105
|
children: [
|
|
101
|
-
/* @__PURE__ */
|
|
106
|
+
/* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("h3", {
|
|
102
107
|
className: "text-sm font-semibold text-text-primary",
|
|
103
|
-
children: "Upload a CSV file"
|
|
104
|
-
}), /* @__PURE__ */
|
|
108
|
+
children: j("bigconsole.dataSinks.importGuide.uploadCsvHeading", "Upload a CSV file")
|
|
109
|
+
}), /* @__PURE__ */ x("p", {
|
|
105
110
|
className: "text-sm text-text-secondary leading-relaxed",
|
|
106
|
-
children: "For a quick, one-off import, upload a spreadsheet export and it becomes available to your dashboards right away."
|
|
111
|
+
children: j("bigconsole.dataSinks.importGuide.uploadCsvBody", "For a quick, one-off import, upload a spreadsheet export and it becomes available to your dashboards right away.")
|
|
107
112
|
})] }),
|
|
108
|
-
|
|
113
|
+
D && /* @__PURE__ */ S("div", {
|
|
109
114
|
className: "flex items-start gap-2 rounded-lg border border-status-warning-border bg-status-warning-bg px-3 py-2",
|
|
110
|
-
children: [/* @__PURE__ */
|
|
115
|
+
children: [/* @__PURE__ */ x(o, { className: "size-4 shrink-0 text-status-warning-text mt-0.5" }), /* @__PURE__ */ x("p", {
|
|
111
116
|
className: "text-sm text-status-warning-text",
|
|
112
|
-
children: "This data sink already has data — importing a CSV will replace it."
|
|
117
|
+
children: j("bigconsole.dataSinks.importGuide.hasExistingDataWarning", "This data sink already has data — importing a CSV will replace it.")
|
|
113
118
|
})]
|
|
114
119
|
}),
|
|
115
|
-
/* @__PURE__ */
|
|
116
|
-
ref:
|
|
120
|
+
/* @__PURE__ */ x("input", {
|
|
121
|
+
ref: M,
|
|
117
122
|
type: "file",
|
|
118
123
|
accept: ".csv,text/csv",
|
|
119
124
|
className: "hidden",
|
|
120
|
-
onChange:
|
|
121
|
-
"aria-label": "Choose a CSV file to import"
|
|
125
|
+
onChange: G,
|
|
126
|
+
"aria-label": j("bigconsole.dataSinks.importGuide.fileInputAriaLabel", "Choose a CSV file to import")
|
|
122
127
|
}),
|
|
123
|
-
!
|
|
128
|
+
!I && /* @__PURE__ */ S("button", {
|
|
124
129
|
type: "button",
|
|
125
|
-
onClick:
|
|
130
|
+
onClick: q,
|
|
126
131
|
className: "flex w-full flex-col items-center justify-center gap-2 rounded-lg border border-dashed border-border-default bg-bg-sunken px-4 py-6 text-center transition-colors hover:border-action-primary-bg hover:bg-action-primary-bg/5",
|
|
127
132
|
children: [
|
|
128
|
-
/* @__PURE__ */
|
|
129
|
-
/* @__PURE__ */
|
|
133
|
+
/* @__PURE__ */ x(c, { className: "size-6 text-text-tertiary" }),
|
|
134
|
+
/* @__PURE__ */ x("span", {
|
|
130
135
|
className: "text-sm font-medium text-text-primary",
|
|
131
|
-
children:
|
|
136
|
+
children: P ? j("bigconsole.dataSinks.importGuide.chooseDifferentCsv", "Choose a different CSV file") : j("bigconsole.dataSinks.importGuide.chooseCsv", "Choose a CSV file")
|
|
132
137
|
}),
|
|
133
|
-
/* @__PURE__ */
|
|
138
|
+
/* @__PURE__ */ x("span", {
|
|
134
139
|
className: "text-xs text-text-tertiary",
|
|
135
|
-
children: "The first row is used as column names."
|
|
140
|
+
children: j("bigconsole.dataSinks.importGuide.firstRowHint", "The first row is used as column names.")
|
|
136
141
|
})
|
|
137
142
|
]
|
|
138
143
|
}),
|
|
139
|
-
|
|
144
|
+
R && /* @__PURE__ */ x("div", {
|
|
140
145
|
className: "rounded-lg border border-status-error-border bg-status-error-bg px-3 py-2",
|
|
141
|
-
children: /* @__PURE__ */
|
|
146
|
+
children: /* @__PURE__ */ x("p", {
|
|
142
147
|
className: "text-sm text-status-error-text",
|
|
143
|
-
children:
|
|
148
|
+
children: R
|
|
144
149
|
})
|
|
145
150
|
}),
|
|
146
|
-
|
|
151
|
+
I && /* @__PURE__ */ S("div", {
|
|
147
152
|
className: "space-y-3 rounded-lg border border-border-default bg-bg-sunken p-4",
|
|
148
153
|
children: [
|
|
149
|
-
/* @__PURE__ */
|
|
154
|
+
/* @__PURE__ */ S("div", {
|
|
150
155
|
className: "flex items-center justify-between gap-3",
|
|
151
|
-
children: [/* @__PURE__ */
|
|
156
|
+
children: [/* @__PURE__ */ x("span", {
|
|
152
157
|
className: "truncate text-sm font-medium text-text-primary",
|
|
153
|
-
title:
|
|
154
|
-
children:
|
|
155
|
-
}), /* @__PURE__ */
|
|
158
|
+
title: P ?? void 0,
|
|
159
|
+
children: P
|
|
160
|
+
}), /* @__PURE__ */ x("button", {
|
|
156
161
|
type: "button",
|
|
157
|
-
onClick:
|
|
158
|
-
disabled:
|
|
162
|
+
onClick: q,
|
|
163
|
+
disabled: H,
|
|
159
164
|
className: "shrink-0 text-xs font-medium text-action-primary-bg hover:underline disabled:cursor-not-allowed disabled:opacity-50 disabled:no-underline",
|
|
160
|
-
children: "Change file"
|
|
165
|
+
children: j("bigconsole.dataSinks.importGuide.changeFile", "Change file")
|
|
161
166
|
})]
|
|
162
167
|
}),
|
|
163
|
-
/* @__PURE__ */
|
|
168
|
+
/* @__PURE__ */ S("p", {
|
|
164
169
|
className: "text-sm text-text-secondary",
|
|
165
170
|
children: [
|
|
166
|
-
"Ready to import
|
|
167
|
-
|
|
171
|
+
j("bigconsole.dataSinks.importGuide.readyToImportPrefix", "Ready to import"),
|
|
172
|
+
" ",
|
|
173
|
+
/* @__PURE__ */ x("strong", {
|
|
168
174
|
className: "text-text-primary",
|
|
169
|
-
children:
|
|
175
|
+
children: I.rows.length
|
|
170
176
|
}),
|
|
171
177
|
" ",
|
|
172
|
-
|
|
173
|
-
" ×",
|
|
178
|
+
I.rows.length === 1 ? j("bigconsole.dataSinks.importGuide.rowSingular", "row") : j("bigconsole.dataSinks.importGuide.rowPlural", "rows"),
|
|
174
179
|
" ",
|
|
175
|
-
|
|
180
|
+
"× ",
|
|
181
|
+
/* @__PURE__ */ x("strong", {
|
|
176
182
|
className: "text-text-primary",
|
|
177
|
-
children:
|
|
183
|
+
children: I.columns.length
|
|
178
184
|
}),
|
|
179
185
|
" ",
|
|
180
|
-
|
|
186
|
+
I.columns.length === 1 ? j("bigconsole.dataSinks.importGuide.columnSingular", "column") : j("bigconsole.dataSinks.importGuide.columnPlural", "columns"),
|
|
181
187
|
"."
|
|
182
188
|
]
|
|
183
189
|
}),
|
|
184
|
-
/* @__PURE__ */
|
|
190
|
+
/* @__PURE__ */ S("div", {
|
|
185
191
|
className: "flex flex-wrap gap-1.5",
|
|
186
|
-
children: [
|
|
192
|
+
children: [J.map((e) => /* @__PURE__ */ x("span", {
|
|
187
193
|
className: "rounded-full bg-bg-surface px-2 py-0.5 text-xs text-text-secondary border border-border-subtle",
|
|
188
194
|
children: e
|
|
189
|
-
}, e)),
|
|
195
|
+
}, e)), Y > 0 && /* @__PURE__ */ x("span", {
|
|
190
196
|
className: "rounded-full px-2 py-0.5 text-xs text-text-tertiary",
|
|
191
|
-
children:
|
|
192
|
-
"+",
|
|
193
|
-
q,
|
|
194
|
-
" more"
|
|
195
|
-
]
|
|
197
|
+
children: j("bigconsole.dataSinks.importGuide.moreColumns", "+{{count}} more", { count: Y })
|
|
196
198
|
})]
|
|
197
199
|
}),
|
|
198
|
-
|
|
200
|
+
B && /* @__PURE__ */ x("p", {
|
|
199
201
|
className: "text-sm text-status-error-text",
|
|
200
|
-
children:
|
|
202
|
+
children: B
|
|
201
203
|
}),
|
|
202
|
-
/* @__PURE__ */
|
|
203
|
-
onClick:
|
|
204
|
-
disabled:
|
|
204
|
+
/* @__PURE__ */ x(p, {
|
|
205
|
+
onClick: K,
|
|
206
|
+
disabled: H,
|
|
205
207
|
className: "w-full",
|
|
206
|
-
children:
|
|
207
|
-
/* @__PURE__ */ b(u, { className: "size-4" }),
|
|
208
|
-
"Import ",
|
|
209
|
-
P.rows.length,
|
|
210
|
-
" ",
|
|
211
|
-
P.rows.length === 1 ? "row" : "rows"
|
|
212
|
-
] })
|
|
208
|
+
children: H ? /* @__PURE__ */ S(b, { children: [/* @__PURE__ */ x(l, { className: "size-4 animate-spin" }), j("bigconsole.dataSinks.importGuide.importing", "Importing…")] }) : /* @__PURE__ */ S(b, { children: [/* @__PURE__ */ x(u, { className: "size-4" }), I.rows.length === 1 ? j("bigconsole.dataSinks.importGuide.importRowSingular", "Import {{count}} row", { count: I.rows.length }) : j("bigconsole.dataSinks.importGuide.importRowPlural", "Import {{count}} rows", { count: I.rows.length })] })
|
|
213
209
|
})
|
|
214
210
|
]
|
|
215
211
|
})
|
|
@@ -217,17 +213,17 @@ var S = 6, C = 1e7, w = 5e4, T = t(function({ isOpen: t, dataSinkName: T, hasExi
|
|
|
217
213
|
})
|
|
218
214
|
]
|
|
219
215
|
}),
|
|
220
|
-
/* @__PURE__ */
|
|
216
|
+
/* @__PURE__ */ x(_, { children: /* @__PURE__ */ x(p, {
|
|
221
217
|
variant: "outline",
|
|
222
|
-
onClick:
|
|
223
|
-
disabled:
|
|
224
|
-
children: "Cancel"
|
|
218
|
+
onClick: O,
|
|
219
|
+
disabled: H,
|
|
220
|
+
children: j("bigconsole.dataSinks.importGuide.cancel", "Cancel")
|
|
225
221
|
}) })
|
|
226
222
|
]
|
|
227
223
|
})
|
|
228
224
|
});
|
|
229
225
|
});
|
|
230
226
|
//#endregion
|
|
231
|
-
export {
|
|
227
|
+
export { E as default };
|
|
232
228
|
|
|
233
229
|
//# sourceMappingURL=ImportDataGuideDialog.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImportDataGuideDialog.js","names":[],"sources":["../../../../src/bigconsole/components/datasink/ImportDataGuideDialog.tsx"],"sourcesContent":["/**\n * Import data into a DataSink. Offers two methods:\n * 1. Build a workflow — a repeatable, scheduled pipeline (the primary path).\n * 2. Upload a CSV file directly (parsed client-side, written to the sink) —\n * the quickest path for one-off or small datasets.\n *\n * Named to avoid confusion with ImportDataSinkDialog, which imports a DataSink\n * *config* from JSON.\n */\n\nimport { type ChangeEvent, type FC, memo, useCallback, useEffect, useRef, useState } from 'react';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Button,\n} from '@burdenoff/fe-libs/ui';\nimport { Upload, Workflow, ArrowRight, FileUp, Loader2, AlertTriangle } from 'lucide-react';\n\nimport { parseCsv, type ParsedCsv } from '../../utils';\n\nexport interface ImportDataGuideDialogProps {\n /** Whether dialog is open */\n isOpen: boolean;\n /** DataSink name for context */\n dataSinkName?: string;\n /** Whether the sink already holds data — a CSV import would replace it. */\n hasExistingData?: boolean;\n /** Callback when dialog is closed */\n onClose: () => void;\n /** Callback when the user chooses to go to the Workflows page */\n onGoToWorkflows: () => void;\n /**\n * When provided, enables the direct CSV upload method. Receives the parsed\n * rows and should persist them to the DataSink. Resolves true on success\n * (the dialog then closes) or false on a handled failure.\n */\n onImportCsv?: (rows: Record<string, unknown>[]) => Promise<boolean>;\n}\n\nconst MAX_PREVIEW_COLUMNS = 6;\n\n/** Guard against reading a huge file fully into memory (~3-4x its size). */\nconst MAX_CSV_BYTES = 10_000_000; // 10 MB\n\n/** Cap rows so a single updateDataSink payload stays a sane size. */\nconst MAX_CSV_ROWS = 50_000;\n\nexport const ImportDataGuideDialog: FC<ImportDataGuideDialogProps> = memo(function ImportDataGuideDialog({\n isOpen,\n dataSinkName,\n hasExistingData,\n onClose,\n onGoToWorkflows,\n onImportCsv,\n}) {\n const fileInputRef = useRef<HTMLInputElement>(null);\n // Monotonic token for the in-flight file read; bumped on every new selection\n // or reset so a slow read that resolves late can detect it was superseded.\n const readSeqRef = useRef(0);\n const [fileName, setFileName] = useState<string | null>(null);\n const [parsed, setParsed] = useState<ParsedCsv | null>(null);\n const [parseError, setParseError] = useState<string | null>(null);\n const [importError, setImportError] = useState<string | null>(null);\n const [isImporting, setIsImporting] = useState(false);\n\n const resetUploadState = useCallback(() => {\n readSeqRef.current += 1; // invalidate any in-flight file read\n setFileName(null);\n setParsed(null);\n setParseError(null);\n setImportError(null);\n setIsImporting(false);\n }, []);\n\n // Clear any prior selection whenever the dialog is (re)opened or closed.\n useEffect(() => {\n if (!isOpen) resetUploadState();\n }, [isOpen, resetUploadState]);\n\n const handleFileChange = useCallback(async (event: ChangeEvent<HTMLInputElement>) => {\n const file = event.target.files?.[0];\n // Reset the input so selecting the same file again re-triggers onChange.\n event.target.value = '';\n if (!file) return;\n\n const seq = (readSeqRef.current += 1);\n setParsed(null);\n setParseError(null);\n setImportError(null);\n setFileName(file.name);\n\n if (file.size > MAX_CSV_BYTES) {\n setParseError('This CSV is larger than 10 MB. Import large datasets with a workflow instead.');\n return;\n }\n\n try {\n const text = await file.text();\n if (seq !== readSeqRef.current) return; // superseded by a newer selection/close\n const result = parseCsv(text);\n if (result.rows.length > MAX_CSV_ROWS) {\n setParseError(\n `This CSV has ${result.rows.length.toLocaleString()} rows (limit ${MAX_CSV_ROWS.toLocaleString()}). Import large datasets with a workflow instead.`\n );\n return;\n }\n setParsed(result);\n } catch (err) {\n if (seq !== readSeqRef.current) return;\n setParsed(null);\n setParseError(err instanceof Error ? err.message : 'Failed to parse the CSV file.');\n }\n }, []);\n\n const handleConfirmImport = useCallback(async () => {\n if (!parsed || !onImportCsv) return;\n setIsImporting(true);\n setImportError(null);\n try {\n const ok = await onImportCsv(parsed.rows);\n if (ok) {\n onClose();\n } else {\n setImportError('Import failed. Please try again.');\n }\n } catch (err) {\n setImportError(err instanceof Error ? err.message : 'Import failed. Please try again.');\n } finally {\n setIsImporting(false);\n }\n }, [parsed, onImportCsv, onClose]);\n\n const openFilePicker = useCallback(() => fileInputRef.current?.click(), []);\n\n const previewColumns = parsed?.columns.slice(0, MAX_PREVIEW_COLUMNS) ?? [];\n const extraColumns = parsed ? parsed.columns.length - previewColumns.length : 0;\n\n return (\n <Dialog open={isOpen} onOpenChange={(open) => !open && !isImporting && onClose()}>\n <DialogContent className=\"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-lg bg-action-primary-bg/10\">\n <Upload className=\"size-5 text-action-primary-bg\" />\n </div>\n <DialogTitle>Import data</DialogTitle>\n </div>\n <DialogDescription>\n {dataSinkName ? `Add data to “${dataSinkName}”` : 'Add data to this data sink'}\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"py-2 space-y-5\">\n <section className=\"space-y-3\">\n <div>\n <h3 className=\"text-sm font-semibold text-text-primary\">Build a workflow</h3>\n <p className=\"text-sm text-text-secondary leading-relaxed\">\n The recommended way to keep this data sink up to date — build a repeatable, scheduled pipeline that\n fetches from your source (an API, database, or app) and writes into this data sink on every run.\n </p>\n </div>\n <Button variant=\"default\" onClick={onGoToWorkflows} disabled={isImporting} className=\"w-full\">\n <Workflow className=\"size-4\" />\n Go to Workflows\n <ArrowRight className=\"size-4\" />\n </Button>\n </section>\n\n {onImportCsv && (\n <div className=\"flex items-center gap-3\">\n <span className=\"h-px flex-1 bg-border-subtle\" />\n <span className=\"text-xs font-medium uppercase tracking-wide text-text-tertiary\">Or</span>\n <span className=\"h-px flex-1 bg-border-subtle\" />\n </div>\n )}\n\n {onImportCsv && (\n <section className=\"space-y-3\">\n <div>\n <h3 className=\"text-sm font-semibold text-text-primary\">Upload a CSV file</h3>\n <p className=\"text-sm text-text-secondary leading-relaxed\">\n For a quick, one-off import, upload a spreadsheet export and it becomes available to your dashboards\n right away.\n </p>\n </div>\n\n {hasExistingData && (\n <div className=\"flex items-start gap-2 rounded-lg border border-status-warning-border bg-status-warning-bg px-3 py-2\">\n <AlertTriangle className=\"size-4 shrink-0 text-status-warning-text mt-0.5\" />\n <p className=\"text-sm text-status-warning-text\">\n This data sink already has data — importing a CSV will replace it.\n </p>\n </div>\n )}\n\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\".csv,text/csv\"\n className=\"hidden\"\n onChange={handleFileChange}\n aria-label=\"Choose a CSV file to import\"\n />\n\n {!parsed && (\n <button\n type=\"button\"\n onClick={openFilePicker}\n className=\"flex w-full flex-col items-center justify-center gap-2 rounded-lg border border-dashed border-border-default bg-bg-sunken px-4 py-6 text-center transition-colors hover:border-action-primary-bg hover:bg-action-primary-bg/5\"\n >\n <FileUp className=\"size-6 text-text-tertiary\" />\n <span className=\"text-sm font-medium text-text-primary\">\n {fileName ? 'Choose a different CSV file' : 'Choose a CSV file'}\n </span>\n <span className=\"text-xs text-text-tertiary\">The first row is used as column names.</span>\n </button>\n )}\n\n {parseError && (\n <div className=\"rounded-lg border border-status-error-border bg-status-error-bg px-3 py-2\">\n <p className=\"text-sm text-status-error-text\">{parseError}</p>\n </div>\n )}\n\n {parsed && (\n <div className=\"space-y-3 rounded-lg border border-border-default bg-bg-sunken p-4\">\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"truncate text-sm font-medium text-text-primary\" title={fileName ?? undefined}>\n {fileName}\n </span>\n <button\n type=\"button\"\n onClick={openFilePicker}\n disabled={isImporting}\n className=\"shrink-0 text-xs font-medium text-action-primary-bg hover:underline disabled:cursor-not-allowed disabled:opacity-50 disabled:no-underline\"\n >\n Change file\n </button>\n </div>\n <p className=\"text-sm text-text-secondary\">\n Ready to import <strong className=\"text-text-primary\">{parsed.rows.length}</strong>{' '}\n {parsed.rows.length === 1 ? 'row' : 'rows'} ×{' '}\n <strong className=\"text-text-primary\">{parsed.columns.length}</strong>{' '}\n {parsed.columns.length === 1 ? 'column' : 'columns'}.\n </p>\n <div className=\"flex flex-wrap gap-1.5\">\n {previewColumns.map((col) => (\n <span\n key={col}\n className=\"rounded-full bg-bg-surface px-2 py-0.5 text-xs text-text-secondary border border-border-subtle\"\n >\n {col}\n </span>\n ))}\n {extraColumns > 0 && (\n <span className=\"rounded-full px-2 py-0.5 text-xs text-text-tertiary\">+{extraColumns} more</span>\n )}\n </div>\n\n {importError && <p className=\"text-sm text-status-error-text\">{importError}</p>}\n\n <Button onClick={handleConfirmImport} disabled={isImporting} className=\"w-full\">\n {isImporting ? (\n <>\n <Loader2 className=\"size-4 animate-spin\" />\n Importing…\n </>\n ) : (\n <>\n <Upload className=\"size-4\" />\n Import {parsed.rows.length} {parsed.rows.length === 1 ? 'row' : 'rows'}\n </>\n )}\n </Button>\n </div>\n )}\n </section>\n )}\n </div>\n\n <DialogFooter>\n <Button variant=\"outline\" onClick={onClose} disabled={isImporting}>\n Cancel\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n});\n\nexport default ImportDataGuideDialog;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ImportDataGuideDialog.js","names":[],"sources":["../../../../src/bigconsole/components/datasink/ImportDataGuideDialog.tsx"],"sourcesContent":["/**\n * Import data into a DataSink. Offers two methods:\n * 1. Build a workflow — a repeatable, scheduled pipeline (the primary path).\n * 2. Upload a CSV file directly (parsed client-side, written to the sink) —\n * the quickest path for one-off or small datasets.\n *\n * Named to avoid confusion with ImportDataSinkDialog, which imports a DataSink\n * *config* from JSON.\n */\n\nimport { type ChangeEvent, type FC, memo, useCallback, useEffect, useRef, useState } from 'react';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Button,\n} from '@burdenoff/fe-libs/ui';\nimport { Upload, Workflow, ArrowRight, FileUp, Loader2, AlertTriangle } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\nimport { parseCsv, type ParsedCsv } from '../../utils';\n\nexport interface ImportDataGuideDialogProps {\n /** Whether dialog is open */\n isOpen: boolean;\n /** DataSink name for context */\n dataSinkName?: string;\n /** Whether the sink already holds data — a CSV import would replace it. */\n hasExistingData?: boolean;\n /** Callback when dialog is closed */\n onClose: () => void;\n /** Callback when the user chooses to go to the Workflows page */\n onGoToWorkflows: () => void;\n /**\n * When provided, enables the direct CSV upload method. Receives the parsed\n * rows and should persist them to the DataSink. Resolves true on success\n * (the dialog then closes) or false on a handled failure.\n */\n onImportCsv?: (rows: Record<string, unknown>[]) => Promise<boolean>;\n}\n\nconst MAX_PREVIEW_COLUMNS = 6;\n\n/** Guard against reading a huge file fully into memory (~3-4x its size). */\nconst MAX_CSV_BYTES = 10_000_000; // 10 MB\n\n/** Cap rows so a single updateDataSink payload stays a sane size. */\nconst MAX_CSV_ROWS = 50_000;\n\nexport const ImportDataGuideDialog: FC<ImportDataGuideDialogProps> = memo(function ImportDataGuideDialog({\n isOpen,\n dataSinkName,\n hasExistingData,\n onClose,\n onGoToWorkflows,\n onImportCsv,\n}) {\n const { t } = useI18n();\n const fileInputRef = useRef<HTMLInputElement>(null);\n // Monotonic token for the in-flight file read; bumped on every new selection\n // or reset so a slow read that resolves late can detect it was superseded.\n const readSeqRef = useRef(0);\n const [fileName, setFileName] = useState<string | null>(null);\n const [parsed, setParsed] = useState<ParsedCsv | null>(null);\n const [parseError, setParseError] = useState<string | null>(null);\n const [importError, setImportError] = useState<string | null>(null);\n const [isImporting, setIsImporting] = useState(false);\n\n const resetUploadState = useCallback(() => {\n readSeqRef.current += 1; // invalidate any in-flight file read\n setFileName(null);\n setParsed(null);\n setParseError(null);\n setImportError(null);\n setIsImporting(false);\n }, []);\n\n // Clear any prior selection whenever the dialog is (re)opened or closed.\n useEffect(() => {\n if (!isOpen) resetUploadState();\n }, [isOpen, resetUploadState]);\n\n const handleFileChange = useCallback(\n async (event: ChangeEvent<HTMLInputElement>) => {\n const file = event.target.files?.[0];\n // Reset the input so selecting the same file again re-triggers onChange.\n event.target.value = '';\n if (!file) return;\n\n const seq = (readSeqRef.current += 1);\n setParsed(null);\n setParseError(null);\n setImportError(null);\n setFileName(file.name);\n\n if (file.size > MAX_CSV_BYTES) {\n setParseError(\n t(\n 'bigconsole.dataSinks.importGuide.csvTooLarge',\n 'This CSV is larger than 10 MB. Import large datasets with a workflow instead.'\n )\n );\n return;\n }\n\n try {\n const text = await file.text();\n if (seq !== readSeqRef.current) return; // superseded by a newer selection/close\n const result = parseCsv(text);\n if (result.rows.length > MAX_CSV_ROWS) {\n setParseError(\n t(\n 'bigconsole.dataSinks.importGuide.csvTooManyRows',\n 'This CSV has {{rows}} rows (limit {{limit}}). Import large datasets with a workflow instead.',\n { rows: result.rows.length.toLocaleString(), limit: MAX_CSV_ROWS.toLocaleString() }\n )\n );\n return;\n }\n setParsed(result);\n } catch (err) {\n if (seq !== readSeqRef.current) return;\n setParsed(null);\n setParseError(\n err instanceof Error\n ? err.message\n : t('bigconsole.dataSinks.importGuide.parseFailed', 'Failed to parse the CSV file.')\n );\n }\n },\n [t]\n );\n\n const handleConfirmImport = useCallback(async () => {\n if (!parsed || !onImportCsv) return;\n setIsImporting(true);\n setImportError(null);\n try {\n const ok = await onImportCsv(parsed.rows);\n if (ok) {\n onClose();\n } else {\n setImportError(t('bigconsole.dataSinks.importGuide.importFailed', 'Import failed. Please try again.'));\n }\n } catch (err) {\n setImportError(\n err instanceof Error\n ? err.message\n : t('bigconsole.dataSinks.importGuide.importFailed', 'Import failed. Please try again.')\n );\n } finally {\n setIsImporting(false);\n }\n }, [parsed, onImportCsv, onClose, t]);\n\n const openFilePicker = useCallback(() => fileInputRef.current?.click(), []);\n\n const previewColumns = parsed?.columns.slice(0, MAX_PREVIEW_COLUMNS) ?? [];\n const extraColumns = parsed ? parsed.columns.length - previewColumns.length : 0;\n\n return (\n <Dialog open={isOpen} onOpenChange={(open) => !open && !isImporting && onClose()}>\n <DialogContent className=\"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-lg bg-action-primary-bg/10\">\n <Upload className=\"size-5 text-action-primary-bg\" />\n </div>\n <DialogTitle>{t('bigconsole.dataSinks.importGuide.title', 'Import data')}</DialogTitle>\n </div>\n <DialogDescription>\n {dataSinkName\n ? t('bigconsole.dataSinks.importGuide.descriptionNamed', 'Add data to “{{name}}”', {\n name: dataSinkName,\n })\n : t('bigconsole.dataSinks.importGuide.description', 'Add data to this data sink')}\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"py-2 space-y-5\">\n <section className=\"space-y-3\">\n <div>\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {t('bigconsole.dataSinks.importGuide.buildWorkflowHeading', 'Build a workflow')}\n </h3>\n <p className=\"text-sm text-text-secondary leading-relaxed\">\n {t(\n 'bigconsole.dataSinks.importGuide.buildWorkflowBody',\n 'The recommended way to keep this data sink up to date — build a repeatable, scheduled pipeline that fetches from your source (an API, database, or app) and writes into this data sink on every run.'\n )}\n </p>\n </div>\n <Button variant=\"default\" onClick={onGoToWorkflows} disabled={isImporting} className=\"w-full\">\n <Workflow className=\"size-4\" />\n {t('bigconsole.dataSinks.importGuide.goToWorkflows', 'Go to Workflows')}\n <ArrowRight className=\"size-4\" />\n </Button>\n </section>\n\n {onImportCsv && (\n <div className=\"flex items-center gap-3\">\n <span className=\"h-px flex-1 bg-border-subtle\" />\n <span className=\"text-xs font-medium uppercase tracking-wide text-text-tertiary\">\n {t('bigconsole.dataSinks.importGuide.or', 'Or')}\n </span>\n <span className=\"h-px flex-1 bg-border-subtle\" />\n </div>\n )}\n\n {onImportCsv && (\n <section className=\"space-y-3\">\n <div>\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {t('bigconsole.dataSinks.importGuide.uploadCsvHeading', 'Upload a CSV file')}\n </h3>\n <p className=\"text-sm text-text-secondary leading-relaxed\">\n {t(\n 'bigconsole.dataSinks.importGuide.uploadCsvBody',\n 'For a quick, one-off import, upload a spreadsheet export and it becomes available to your dashboards right away.'\n )}\n </p>\n </div>\n\n {hasExistingData && (\n <div className=\"flex items-start gap-2 rounded-lg border border-status-warning-border bg-status-warning-bg px-3 py-2\">\n <AlertTriangle className=\"size-4 shrink-0 text-status-warning-text mt-0.5\" />\n <p className=\"text-sm text-status-warning-text\">\n {t(\n 'bigconsole.dataSinks.importGuide.hasExistingDataWarning',\n 'This data sink already has data — importing a CSV will replace it.'\n )}\n </p>\n </div>\n )}\n\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\".csv,text/csv\"\n className=\"hidden\"\n onChange={handleFileChange}\n aria-label={t('bigconsole.dataSinks.importGuide.fileInputAriaLabel', 'Choose a CSV file to import')}\n />\n\n {!parsed && (\n <button\n type=\"button\"\n onClick={openFilePicker}\n className=\"flex w-full flex-col items-center justify-center gap-2 rounded-lg border border-dashed border-border-default bg-bg-sunken px-4 py-6 text-center transition-colors hover:border-action-primary-bg hover:bg-action-primary-bg/5\"\n >\n <FileUp className=\"size-6 text-text-tertiary\" />\n <span className=\"text-sm font-medium text-text-primary\">\n {fileName\n ? t('bigconsole.dataSinks.importGuide.chooseDifferentCsv', 'Choose a different CSV file')\n : t('bigconsole.dataSinks.importGuide.chooseCsv', 'Choose a CSV file')}\n </span>\n <span className=\"text-xs text-text-tertiary\">\n {t('bigconsole.dataSinks.importGuide.firstRowHint', 'The first row is used as column names.')}\n </span>\n </button>\n )}\n\n {parseError && (\n <div className=\"rounded-lg border border-status-error-border bg-status-error-bg px-3 py-2\">\n <p className=\"text-sm text-status-error-text\">{parseError}</p>\n </div>\n )}\n\n {parsed && (\n <div className=\"space-y-3 rounded-lg border border-border-default bg-bg-sunken p-4\">\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"truncate text-sm font-medium text-text-primary\" title={fileName ?? undefined}>\n {fileName}\n </span>\n <button\n type=\"button\"\n onClick={openFilePicker}\n disabled={isImporting}\n className=\"shrink-0 text-xs font-medium text-action-primary-bg hover:underline disabled:cursor-not-allowed disabled:opacity-50 disabled:no-underline\"\n >\n {t('bigconsole.dataSinks.importGuide.changeFile', 'Change file')}\n </button>\n </div>\n <p className=\"text-sm text-text-secondary\">\n {t('bigconsole.dataSinks.importGuide.readyToImportPrefix', 'Ready to import')}{' '}\n <strong className=\"text-text-primary\">{parsed.rows.length}</strong>{' '}\n {parsed.rows.length === 1\n ? t('bigconsole.dataSinks.importGuide.rowSingular', 'row')\n : t('bigconsole.dataSinks.importGuide.rowPlural', 'rows')}{' '}\n × <strong className=\"text-text-primary\">{parsed.columns.length}</strong>{' '}\n {parsed.columns.length === 1\n ? t('bigconsole.dataSinks.importGuide.columnSingular', 'column')\n : t('bigconsole.dataSinks.importGuide.columnPlural', 'columns')}\n .\n </p>\n <div className=\"flex flex-wrap gap-1.5\">\n {previewColumns.map((col) => (\n <span\n key={col}\n className=\"rounded-full bg-bg-surface px-2 py-0.5 text-xs text-text-secondary border border-border-subtle\"\n >\n {col}\n </span>\n ))}\n {extraColumns > 0 && (\n <span className=\"rounded-full px-2 py-0.5 text-xs text-text-tertiary\">\n {t('bigconsole.dataSinks.importGuide.moreColumns', '+{{count}} more', { count: extraColumns })}\n </span>\n )}\n </div>\n\n {importError && <p className=\"text-sm text-status-error-text\">{importError}</p>}\n\n <Button onClick={handleConfirmImport} disabled={isImporting} className=\"w-full\">\n {isImporting ? (\n <>\n <Loader2 className=\"size-4 animate-spin\" />\n {t('bigconsole.dataSinks.importGuide.importing', 'Importing…')}\n </>\n ) : (\n <>\n <Upload className=\"size-4\" />\n {parsed.rows.length === 1\n ? t('bigconsole.dataSinks.importGuide.importRowSingular', 'Import {{count}} row', {\n count: parsed.rows.length,\n })\n : t('bigconsole.dataSinks.importGuide.importRowPlural', 'Import {{count}} rows', {\n count: parsed.rows.length,\n })}\n </>\n )}\n </Button>\n </div>\n )}\n </section>\n )}\n </div>\n\n <DialogFooter>\n <Button variant=\"outline\" onClick={onClose} disabled={isImporting}>\n {t('bigconsole.dataSinks.importGuide.cancel', 'Cancel')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n});\n\nexport default ImportDataGuideDialog;\n"],"mappings":"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"}
|