strapi-plugin-bulk-updater 1.4.3 → 1.4.6
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/_chunks/{BulkUpdater-CbQk_OQG.mjs → BulkUpdater-CMkPdA9_.mjs} +942 -328
- package/dist/_chunks/BulkUpdater-CMkPdA9_.mjs.map +1 -0
- package/dist/_chunks/{BulkUpdater-mSvmiLwc.js → BulkUpdater-DtBH2c0-.js} +939 -325
- package/dist/_chunks/BulkUpdater-DtBH2c0-.js.map +1 -0
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +1341 -629
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +1341 -629
- package/dist/server/index.mjs.map +1 -1
- package/package.json +3 -3
- package/dist/_chunks/BulkUpdater-CbQk_OQG.mjs.map +0 -1
- package/dist/_chunks/BulkUpdater-mSvmiLwc.js.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import React__default, { useState, useEffect, useMemo, useRef } from "react";
|
|
3
3
|
import { useFetchClient, useNotification } from "@strapi/strapi/admin";
|
|
4
|
-
import { Box, Flex, Typography, Button, SingleSelect, SingleSelectOption, Badge, Checkbox, Alert, Table, Thead, Tr, Th, Tbody, Td,
|
|
5
|
-
import { ArrowClockwise, Download, Upload,
|
|
4
|
+
import { Box, Flex, Typography, Button, SingleSelect, SingleSelectOption, Badge, Checkbox, Alert, Table, Thead, Tr, Th, Tbody, Td, TextInput, Loader, ComboboxOption, Field, Combobox } from "@strapi/design-system";
|
|
5
|
+
import { ArrowClockwise, Download, Upload, ChevronLeft, ChevronRight, Eye, Check, Cog, Play } from "@strapi/icons";
|
|
6
6
|
import { i as isAbortError, V as ValidationRulesTab } from "./ValidationRulesTab-BtOCWK8E.mjs";
|
|
7
7
|
function parseCsvRows(csvText) {
|
|
8
8
|
if (!csvText) return [];
|
|
@@ -142,7 +142,7 @@ function CsvManagerTab() {
|
|
|
142
142
|
const [collections, setCollections] = useState([]);
|
|
143
143
|
const [loadingCollections, setLoadingCollections] = useState(true);
|
|
144
144
|
const [selectedUid, setSelectedUid] = useState("");
|
|
145
|
-
const [exportLimit, setExportLimit] = useState(
|
|
145
|
+
const [exportLimit, setExportLimit] = useState(0);
|
|
146
146
|
const [exportOnlyViolations, setExportOnlyViolations] = useState(false);
|
|
147
147
|
const [rules, setRules] = useState([]);
|
|
148
148
|
const [selectedRuleId, setSelectedRuleId] = useState("");
|
|
@@ -150,9 +150,18 @@ function CsvManagerTab() {
|
|
|
150
150
|
const [publishOnImport, setPublishOnImport] = useState(true);
|
|
151
151
|
const [csvRawText, setCsvRawText] = useState("");
|
|
152
152
|
const [fileName, setFileName] = useState("");
|
|
153
|
-
const [
|
|
153
|
+
const [allParsedRecords, setAllParsedRecords] = useState([]);
|
|
154
|
+
const [previewPage, setPreviewPage] = useState(1);
|
|
155
|
+
const [previewPageSize, setPreviewPageSize] = useState(10);
|
|
154
156
|
const [importing, setImporting] = useState(false);
|
|
157
|
+
const [importProgress, setImportProgress] = useState(null);
|
|
155
158
|
const [importResult, setImportResult] = useState(null);
|
|
159
|
+
const [executionWindow, setExecutionWindow] = useState(null);
|
|
160
|
+
const [preflightLoading, setPreflightLoading] = useState(false);
|
|
161
|
+
const [preflightReport, setPreflightReport] = useState(null);
|
|
162
|
+
const [showConfirmModal, setShowConfirmModal] = useState(false);
|
|
163
|
+
const [makerNotesInput, setMakerNotesInput] = useState("");
|
|
164
|
+
const [submittingBatch, setSubmittingBatch] = useState(false);
|
|
156
165
|
useEffect(() => {
|
|
157
166
|
fetchInitialData();
|
|
158
167
|
}, []);
|
|
@@ -163,6 +172,9 @@ function CsvManagerTab() {
|
|
|
163
172
|
get("/bulk-updater/models"),
|
|
164
173
|
get("/bulk-updater/validation-rules")
|
|
165
174
|
]);
|
|
175
|
+
if (modelsRes.data?.executionWindow) {
|
|
176
|
+
setExecutionWindow(modelsRes.data.executionWindow);
|
|
177
|
+
}
|
|
166
178
|
if (modelsRes.data?.collections) {
|
|
167
179
|
setCollections(modelsRes.data.collections);
|
|
168
180
|
if (modelsRes.data.collections.length > 0) {
|
|
@@ -213,7 +225,7 @@ function CsvManagerTab() {
|
|
|
213
225
|
downloadCsvFile(csvStr, filename);
|
|
214
226
|
toggleNotification({
|
|
215
227
|
type: "success",
|
|
216
|
-
message:
|
|
228
|
+
message: `Collection exported successfully (${res.data?.count ?? 0} records)`
|
|
217
229
|
});
|
|
218
230
|
} catch (err) {
|
|
219
231
|
if (isAbortError(err)) return;
|
|
@@ -266,34 +278,93 @@ function CsvManagerTab() {
|
|
|
266
278
|
if (!file) return;
|
|
267
279
|
setFileName(file.name);
|
|
268
280
|
setImportResult(null);
|
|
281
|
+
setImportProgress(null);
|
|
269
282
|
const reader = new FileReader();
|
|
270
283
|
reader.onload = (event) => {
|
|
271
284
|
const text = event.target?.result;
|
|
272
285
|
setCsvRawText(text);
|
|
273
286
|
try {
|
|
274
287
|
const records = parseCsv(text);
|
|
275
|
-
|
|
288
|
+
setAllParsedRecords(records);
|
|
289
|
+
setPreviewPage(1);
|
|
276
290
|
} catch (err) {
|
|
277
|
-
|
|
291
|
+
setAllParsedRecords([]);
|
|
278
292
|
}
|
|
279
293
|
};
|
|
280
294
|
reader.readAsText(file);
|
|
281
295
|
};
|
|
282
296
|
const handleExecuteImport = async () => {
|
|
283
|
-
if (!selectedUid ||
|
|
297
|
+
if (!selectedUid || allParsedRecords.length === 0) return;
|
|
298
|
+
const totalRows = allParsedRecords.length;
|
|
299
|
+
const CHUNK_SIZE = 100;
|
|
300
|
+
const totalChunks = Math.ceil(totalRows / CHUNK_SIZE);
|
|
301
|
+
const batchId = `csv_batch_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;
|
|
284
302
|
try {
|
|
285
303
|
setImporting(true);
|
|
286
304
|
setImportResult(null);
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
305
|
+
let liveCreated = 0;
|
|
306
|
+
let liveUpdated = 0;
|
|
307
|
+
let liveSkipped = 0;
|
|
308
|
+
let liveErrors = 0;
|
|
309
|
+
let finalResultData = null;
|
|
310
|
+
setImportProgress({
|
|
311
|
+
currentChunk: 0,
|
|
312
|
+
totalChunks,
|
|
313
|
+
percent: 0,
|
|
314
|
+
processedRows: 0,
|
|
315
|
+
totalRows,
|
|
316
|
+
liveCreated: 0,
|
|
317
|
+
liveUpdated: 0,
|
|
318
|
+
liveSkipped: 0,
|
|
319
|
+
liveErrors: 0
|
|
292
320
|
});
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
const
|
|
296
|
-
|
|
321
|
+
for (let chunkIdx = 0; chunkIdx < totalChunks; chunkIdx++) {
|
|
322
|
+
const startIdx = chunkIdx * CHUNK_SIZE;
|
|
323
|
+
const endIdx = Math.min(startIdx + CHUNK_SIZE, totalRows);
|
|
324
|
+
const chunkRows = allParsedRecords.slice(startIdx, endIdx);
|
|
325
|
+
const isFirst = chunkIdx === 0;
|
|
326
|
+
const isLast = chunkIdx === totalChunks - 1;
|
|
327
|
+
const startRowNumber = startIdx + 2;
|
|
328
|
+
const res = await post("/bulk-updater/csv/import-chunk", {
|
|
329
|
+
uid: selectedUid,
|
|
330
|
+
rows: chunkRows,
|
|
331
|
+
batchId,
|
|
332
|
+
isFirstChunk: isFirst,
|
|
333
|
+
isLastChunk: isLast,
|
|
334
|
+
startRowNumber,
|
|
335
|
+
mode: importMode,
|
|
336
|
+
publish: publishOnImport
|
|
337
|
+
});
|
|
338
|
+
if (!res.data || !res.data.success) {
|
|
339
|
+
throw new Error(res.data?.error || `Chunk ${chunkIdx + 1} failed to process`);
|
|
340
|
+
}
|
|
341
|
+
const chunkStats = res.data.chunkStats;
|
|
342
|
+
if (chunkStats) {
|
|
343
|
+
liveCreated += chunkStats.created || 0;
|
|
344
|
+
liveUpdated += chunkStats.updated || 0;
|
|
345
|
+
liveSkipped += chunkStats.skipped || 0;
|
|
346
|
+
liveErrors += chunkStats.errors?.length || 0;
|
|
347
|
+
}
|
|
348
|
+
const currentProgressPercent = Math.round((chunkIdx + 1) / totalChunks * 100);
|
|
349
|
+
setImportProgress({
|
|
350
|
+
currentChunk: chunkIdx + 1,
|
|
351
|
+
totalChunks,
|
|
352
|
+
percent: currentProgressPercent,
|
|
353
|
+
processedRows: endIdx,
|
|
354
|
+
totalRows,
|
|
355
|
+
liveCreated,
|
|
356
|
+
liveUpdated,
|
|
357
|
+
liveSkipped,
|
|
358
|
+
liveErrors
|
|
359
|
+
});
|
|
360
|
+
if (isLast) {
|
|
361
|
+
finalResultData = res.data;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
if (finalResultData && finalResultData.stats) {
|
|
365
|
+
setImportResult(finalResultData);
|
|
366
|
+
const stats = finalResultData.stats;
|
|
367
|
+
let notifMsg = `CSV Import complete: ${stats.created} created, ${stats.updated} updated across ${stats.total} records.`;
|
|
297
368
|
if (stats.newWithoutDocId && stats.newWithoutDocId > 0) {
|
|
298
369
|
notifMsg += ` (${stats.newWithoutDocId} new entries created due to omitted documentId)`;
|
|
299
370
|
}
|
|
@@ -301,348 +372,864 @@ function CsvManagerTab() {
|
|
|
301
372
|
type: "success",
|
|
302
373
|
message: notifMsg
|
|
303
374
|
});
|
|
304
|
-
} else {
|
|
305
|
-
throw new Error(res.data?.error || "Import failed");
|
|
306
375
|
}
|
|
307
376
|
} catch (err) {
|
|
308
377
|
if (isAbortError(err)) return;
|
|
309
378
|
toggleNotification({
|
|
310
379
|
type: "danger",
|
|
311
|
-
message: err.message || "Error processing CSV import"
|
|
380
|
+
message: err.message || "Error processing CSV import batch"
|
|
312
381
|
});
|
|
313
382
|
} finally {
|
|
314
383
|
setImporting(false);
|
|
315
384
|
}
|
|
316
385
|
};
|
|
386
|
+
const handleRunPreflight = async () => {
|
|
387
|
+
if (!selectedUid || allParsedRecords.length === 0) return;
|
|
388
|
+
try {
|
|
389
|
+
setPreflightLoading(true);
|
|
390
|
+
const res = await post("/bulk-updater/csv/validate-preflight", {
|
|
391
|
+
uid: selectedUid,
|
|
392
|
+
rows: allParsedRecords,
|
|
393
|
+
mode: importMode
|
|
394
|
+
});
|
|
395
|
+
if (res.data && res.data.success) {
|
|
396
|
+
setPreflightReport(res.data);
|
|
397
|
+
if (res.data.hasErrors) {
|
|
398
|
+
toggleNotification({
|
|
399
|
+
type: "warning",
|
|
400
|
+
message: `Pre-flight validation: ${res.data.totalErrorCount} error(s) and ${res.data.totalWarningCount} warning(s) detected.`
|
|
401
|
+
});
|
|
402
|
+
} else if (res.data.hasWarnings) {
|
|
403
|
+
toggleNotification({
|
|
404
|
+
type: "warning",
|
|
405
|
+
message: `Pre-flight validation passed with ${res.data.totalWarningCount} warning(s).`
|
|
406
|
+
});
|
|
407
|
+
} else {
|
|
408
|
+
toggleNotification({
|
|
409
|
+
type: "success",
|
|
410
|
+
message: `Pre-flight validation passed! All ${res.data.validRows} rows are ready for import.`
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
} catch (err) {
|
|
415
|
+
if (isAbortError(err)) return;
|
|
416
|
+
toggleNotification({
|
|
417
|
+
type: "danger",
|
|
418
|
+
message: err.message || "Failed running pre-flight validation"
|
|
419
|
+
});
|
|
420
|
+
} finally {
|
|
421
|
+
setPreflightLoading(false);
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
const submitBatchWithMode = async (executionMode, forceImmediate = false) => {
|
|
425
|
+
if (!selectedUid || allParsedRecords.length === 0) return;
|
|
426
|
+
if (executionMode === "immediate") {
|
|
427
|
+
setShowConfirmModal(false);
|
|
428
|
+
await handleExecuteImport();
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
try {
|
|
432
|
+
setSubmittingBatch(true);
|
|
433
|
+
const res = await post("/bulk-updater/csv/submit-batch", {
|
|
434
|
+
uid: selectedUid,
|
|
435
|
+
rows: allParsedRecords,
|
|
436
|
+
executionMode,
|
|
437
|
+
makerNotes: makerNotesInput,
|
|
438
|
+
forceImmediate,
|
|
439
|
+
mode: importMode,
|
|
440
|
+
publish: publishOnImport
|
|
441
|
+
});
|
|
442
|
+
setShowConfirmModal(false);
|
|
443
|
+
if (res.data && res.data.pending) {
|
|
444
|
+
setMakerNotesInput("");
|
|
445
|
+
toggleNotification({
|
|
446
|
+
type: "success",
|
|
447
|
+
message: res.data.message || "CSV batch submitted for Checker authorization."
|
|
448
|
+
});
|
|
449
|
+
} else if (res.data && res.data.executeNow) {
|
|
450
|
+
await handleExecuteImport();
|
|
451
|
+
}
|
|
452
|
+
} catch (err) {
|
|
453
|
+
if (isAbortError(err)) return;
|
|
454
|
+
toggleNotification({
|
|
455
|
+
type: "danger",
|
|
456
|
+
message: err.message || "Failed submitting CSV batch"
|
|
457
|
+
});
|
|
458
|
+
} finally {
|
|
459
|
+
setSubmittingBatch(false);
|
|
460
|
+
}
|
|
461
|
+
};
|
|
317
462
|
const selectedCol = collections.find((c) => c.uid === selectedUid);
|
|
318
|
-
return /* @__PURE__ */
|
|
319
|
-
/* @__PURE__ */ jsxs(Flex, {
|
|
320
|
-
/* @__PURE__ */ jsxs(
|
|
321
|
-
/* @__PURE__ */
|
|
322
|
-
|
|
463
|
+
return /* @__PURE__ */ jsxs(Box, { padding: 6, background: "neutral0", hasRadius: true, shadow: "filterShadow", children: [
|
|
464
|
+
/* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 6, children: [
|
|
465
|
+
/* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [
|
|
466
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
467
|
+
/* @__PURE__ */ jsx(Typography, { variant: "beta", tag: "h2", fontWeight: "bold", children: "CSV Export & Import Center" }),
|
|
468
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Export all records (including 10,000+ datasets), filtered subsets, or rule violations into CSV. Correct or add records in spreadsheets and re-upload with high-performance chunked batch processing." })
|
|
469
|
+
] }),
|
|
470
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", startIcon: /* @__PURE__ */ jsx(ArrowClockwise, {}), onClick: fetchInitialData, children: "Refresh" })
|
|
323
471
|
] }),
|
|
324
|
-
/* @__PURE__ */ jsx(
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
472
|
+
/* @__PURE__ */ jsx(Box, { padding: 4, background: "neutral100", hasRadius: true, children: /* @__PURE__ */ jsxs(Flex, { gap: 4, alignItems: "flex-end", children: [
|
|
473
|
+
/* @__PURE__ */ jsxs(Box, { style: { flex: 1 }, children: [
|
|
474
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", marginBottom: 2, children: "Target Collection Type" }),
|
|
475
|
+
/* @__PURE__ */ jsx(
|
|
476
|
+
SingleSelect,
|
|
477
|
+
{
|
|
478
|
+
value: selectedUid,
|
|
479
|
+
onChange: (val) => {
|
|
480
|
+
setSelectedUid(val);
|
|
481
|
+
setImportResult(null);
|
|
482
|
+
setImportProgress(null);
|
|
483
|
+
},
|
|
484
|
+
disabled: loadingCollections,
|
|
485
|
+
placeholder: "Select a collection...",
|
|
486
|
+
children: collections.map((col) => /* @__PURE__ */ jsxs(SingleSelectOption, { value: col.uid, children: [
|
|
487
|
+
col.displayName,
|
|
488
|
+
" (",
|
|
489
|
+
col.totalEntries ?? 0,
|
|
490
|
+
" records)"
|
|
491
|
+
] }, col.uid))
|
|
492
|
+
}
|
|
493
|
+
)
|
|
494
|
+
] }),
|
|
329
495
|
/* @__PURE__ */ jsx(
|
|
330
|
-
SingleSelect,
|
|
331
|
-
{
|
|
332
|
-
value: selectedUid,
|
|
333
|
-
onChange: (val) => {
|
|
334
|
-
setSelectedUid(val);
|
|
335
|
-
setImportResult(null);
|
|
336
|
-
},
|
|
337
|
-
disabled: loadingCollections,
|
|
338
|
-
placeholder: "Select a collection...",
|
|
339
|
-
children: collections.map((col) => /* @__PURE__ */ jsxs(SingleSelectOption, { value: col.uid, children: [
|
|
340
|
-
col.displayName,
|
|
341
|
-
" (",
|
|
342
|
-
col.totalEntries ?? 0,
|
|
343
|
-
" records)"
|
|
344
|
-
] }, col.uid))
|
|
345
|
-
}
|
|
346
|
-
)
|
|
347
|
-
] }),
|
|
348
|
-
/* @__PURE__ */ jsx(
|
|
349
|
-
Button,
|
|
350
|
-
{
|
|
351
|
-
variant: "tertiary",
|
|
352
|
-
startIcon: /* @__PURE__ */ jsx(Download, {}),
|
|
353
|
-
onClick: handleDownloadTemplate,
|
|
354
|
-
disabled: !selectedUid,
|
|
355
|
-
children: "Download Sample CSV Template"
|
|
356
|
-
}
|
|
357
|
-
)
|
|
358
|
-
] }) }),
|
|
359
|
-
/* @__PURE__ */ jsxs(Box, { padding: 5, background: "neutral100", hasRadius: true, children: [
|
|
360
|
-
/* @__PURE__ */ jsx(Typography, { variant: "delta", tag: "h3", fontWeight: "bold", marginBottom: 2, children: "1. Export Data to CSV" }),
|
|
361
|
-
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", marginBottom: 4, children: "Extract entire collections or pinpoint records violating validation quotas." }),
|
|
362
|
-
/* @__PURE__ */ jsxs(Flex, { gap: 4, wrap: "wrap", alignItems: "center", marginTop: 3, children: [
|
|
363
|
-
/* @__PURE__ */ jsxs(
|
|
364
496
|
Button,
|
|
365
497
|
{
|
|
366
|
-
variant: "
|
|
498
|
+
variant: "tertiary",
|
|
367
499
|
startIcon: /* @__PURE__ */ jsx(Download, {}),
|
|
368
|
-
onClick:
|
|
500
|
+
onClick: handleDownloadTemplate,
|
|
369
501
|
disabled: !selectedUid,
|
|
370
|
-
children:
|
|
371
|
-
"Export All ",
|
|
372
|
-
selectedCol?.displayName || "Collection",
|
|
373
|
-
" Records (.csv)"
|
|
374
|
-
]
|
|
502
|
+
children: "Download Sample CSV Template"
|
|
375
503
|
}
|
|
376
|
-
)
|
|
377
|
-
|
|
378
|
-
|
|
504
|
+
)
|
|
505
|
+
] }) }),
|
|
506
|
+
/* @__PURE__ */ jsxs(Box, { padding: 5, background: "neutral100", hasRadius: true, children: [
|
|
507
|
+
/* @__PURE__ */ jsx(Typography, { variant: "delta", tag: "h3", fontWeight: "bold", marginBottom: 2, children: "1. Export Data to CSV" }),
|
|
508
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", marginBottom: 4, children: "Extract entire collections without artificial limits (streams 10,000+ records in paged chunks) or pinpoint records violating validation quotas." }),
|
|
509
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 4, wrap: "wrap", alignItems: "center", marginTop: 3, children: [
|
|
510
|
+
/* @__PURE__ */ jsx(Box, { style: { width: 220 }, children: /* @__PURE__ */ jsxs(
|
|
379
511
|
SingleSelect,
|
|
380
512
|
{
|
|
381
|
-
value:
|
|
382
|
-
onChange: (val) =>
|
|
383
|
-
placeholder: "
|
|
384
|
-
children:
|
|
385
|
-
"
|
|
386
|
-
|
|
387
|
-
|
|
513
|
+
value: String(exportLimit),
|
|
514
|
+
onChange: (val) => setExportLimit(Number(val)),
|
|
515
|
+
placeholder: "Export Limit",
|
|
516
|
+
children: [
|
|
517
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "0", children: "All Records (No Limit)" }),
|
|
518
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "10000", children: "Up to 10,000 Records" }),
|
|
519
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "5000", children: "Up to 5,000 Records" }),
|
|
520
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "1000", children: "Up to 1,000 Records" })
|
|
521
|
+
]
|
|
388
522
|
}
|
|
389
|
-
),
|
|
390
|
-
/* @__PURE__ */
|
|
523
|
+
) }),
|
|
524
|
+
/* @__PURE__ */ jsxs(
|
|
391
525
|
Button,
|
|
392
526
|
{
|
|
393
|
-
variant: "
|
|
527
|
+
variant: "default",
|
|
394
528
|
startIcon: /* @__PURE__ */ jsx(Download, {}),
|
|
395
|
-
onClick:
|
|
396
|
-
disabled: !
|
|
397
|
-
children:
|
|
529
|
+
onClick: handleExportCollection,
|
|
530
|
+
disabled: !selectedUid,
|
|
531
|
+
children: [
|
|
532
|
+
"Export ",
|
|
533
|
+
exportLimit === 0 ? "All" : `${exportLimit}`,
|
|
534
|
+
" ",
|
|
535
|
+
selectedCol?.displayName || "Collection",
|
|
536
|
+
" Records (.csv)"
|
|
537
|
+
]
|
|
398
538
|
}
|
|
399
|
-
)
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
539
|
+
),
|
|
540
|
+
rules.length > 0 && /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", style: { marginLeft: "auto" }, children: [
|
|
541
|
+
/* @__PURE__ */ jsx(
|
|
542
|
+
SingleSelect,
|
|
543
|
+
{
|
|
544
|
+
value: selectedRuleId,
|
|
545
|
+
onChange: (val) => setSelectedRuleId(val),
|
|
546
|
+
placeholder: "Select Quota Rule...",
|
|
547
|
+
children: rules.map((r) => /* @__PURE__ */ jsxs(SingleSelectOption, { value: r.id, children: [
|
|
548
|
+
"Rule: ",
|
|
549
|
+
r.name
|
|
550
|
+
] }, r.id))
|
|
551
|
+
}
|
|
552
|
+
),
|
|
553
|
+
/* @__PURE__ */ jsx(
|
|
554
|
+
Button,
|
|
555
|
+
{
|
|
556
|
+
variant: "danger-light",
|
|
557
|
+
startIcon: /* @__PURE__ */ jsx(Download, {}),
|
|
558
|
+
onClick: handleExportViolations,
|
|
559
|
+
disabled: !selectedRuleId,
|
|
560
|
+
children: "Export Violators CSV"
|
|
561
|
+
}
|
|
562
|
+
)
|
|
416
563
|
] })
|
|
417
|
-
] }),
|
|
418
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
419
|
-
/* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", marginBottom: 1, display: "block", children: "Publish Options" }),
|
|
420
|
-
/* @__PURE__ */ jsx(
|
|
421
|
-
Checkbox,
|
|
422
|
-
{
|
|
423
|
-
checked: publishOnImport,
|
|
424
|
-
onValueChange: (val) => setPublishOnImport(val),
|
|
425
|
-
children: "Auto-publish on import"
|
|
426
|
-
}
|
|
427
|
-
)
|
|
428
564
|
] })
|
|
429
565
|
] }),
|
|
430
|
-
/* @__PURE__ */ jsxs(
|
|
431
|
-
|
|
432
|
-
{
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
566
|
+
/* @__PURE__ */ jsxs(Box, { padding: 5, background: "neutral100", hasRadius: true, children: [
|
|
567
|
+
/* @__PURE__ */ jsx(Typography, { variant: "delta", tag: "h3", fontWeight: "bold", marginBottom: 2, children: "2. Import & Batch Override CSV" }),
|
|
568
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", marginBottom: 4, children: "Upload an updated CSV file (supports 10,000+ records via chunked streaming) to bulk update existing records or insert new records." }),
|
|
569
|
+
/* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 4, wrap: "wrap", gap: 4, children: [
|
|
570
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
571
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", marginBottom: 1, display: "block", children: "Operation Mode" }),
|
|
572
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
|
|
573
|
+
/* @__PURE__ */ jsx(Badge, { backgroundColor: "primary100", textColor: "primary700", children: "⚡ Smart Auto-Detect" }),
|
|
574
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", children: [
|
|
575
|
+
"Automatically updates matching records by ",
|
|
576
|
+
/* @__PURE__ */ jsx("code", { children: "documentId" }),
|
|
577
|
+
" and creates new entries when ID is omitted."
|
|
578
|
+
] })
|
|
579
|
+
] })
|
|
580
|
+
] }),
|
|
581
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
582
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", marginBottom: 1, display: "block", children: "Publish Options" }),
|
|
442
583
|
/* @__PURE__ */ jsx(
|
|
443
|
-
|
|
584
|
+
Checkbox,
|
|
444
585
|
{
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
style: { display: "none" },
|
|
449
|
-
onChange: handleFileUpload
|
|
586
|
+
checked: publishOnImport,
|
|
587
|
+
onValueChange: (val) => setPublishOnImport(val),
|
|
588
|
+
children: "Auto-publish on import"
|
|
450
589
|
}
|
|
451
|
-
)
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
590
|
+
)
|
|
591
|
+
] })
|
|
592
|
+
] }),
|
|
593
|
+
/* @__PURE__ */ jsxs(
|
|
594
|
+
Box,
|
|
595
|
+
{
|
|
596
|
+
padding: 6,
|
|
597
|
+
background: "neutral0",
|
|
598
|
+
hasRadius: true,
|
|
599
|
+
style: {
|
|
600
|
+
border: "2px dashed #dcdce4",
|
|
601
|
+
textAlign: "center",
|
|
602
|
+
cursor: "pointer"
|
|
603
|
+
},
|
|
604
|
+
children: [
|
|
605
|
+
/* @__PURE__ */ jsx(
|
|
606
|
+
"input",
|
|
607
|
+
{
|
|
608
|
+
type: "file",
|
|
609
|
+
accept: ".csv",
|
|
610
|
+
id: "csv-file-input",
|
|
611
|
+
style: { display: "none" },
|
|
612
|
+
onChange: handleFileUpload
|
|
613
|
+
}
|
|
614
|
+
),
|
|
615
|
+
/* @__PURE__ */ jsxs("label", { htmlFor: "csv-file-input", style: { cursor: "pointer", display: "block" }, children: [
|
|
616
|
+
/* @__PURE__ */ jsx(Upload, { style: { width: 32, height: 32, margin: "0 auto 8px", color: "#4945ff" } }),
|
|
617
|
+
/* @__PURE__ */ jsx(Typography, { variant: "delta", fontWeight: "bold", display: "block", children: fileName ? `Selected: ${fileName}` : "Click here or drag a .csv file to upload" }),
|
|
618
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: "UTF-8 encoded CSV matching collection schema headers" })
|
|
619
|
+
] })
|
|
620
|
+
]
|
|
621
|
+
}
|
|
622
|
+
),
|
|
623
|
+
allParsedRecords.length > 0 && (() => {
|
|
624
|
+
const totalRows = allParsedRecords.length;
|
|
625
|
+
const missingDocIdCount = allParsedRecords.filter((row) => !extractDocId(row)).length;
|
|
626
|
+
const updateCount = totalRows - missingDocIdCount;
|
|
627
|
+
const headers = Object.keys(allParsedRecords[0]);
|
|
628
|
+
const totalPages = Math.ceil(totalRows / previewPageSize) || 1;
|
|
629
|
+
const safePage = Math.min(Math.max(1, previewPage), totalPages);
|
|
630
|
+
const startIndex = (safePage - 1) * previewPageSize;
|
|
631
|
+
const endIndex = Math.min(startIndex + previewPageSize, totalRows);
|
|
632
|
+
const displayedRows = allParsedRecords.slice(startIndex, endIndex);
|
|
633
|
+
return /* @__PURE__ */ jsxs(Box, { marginTop: 4, background: "neutral0", padding: 4, hasRadius: true, children: [
|
|
634
|
+
/* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 3, wrap: "wrap", gap: 2, children: [
|
|
635
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
636
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "sigma", textColor: "neutral700", children: [
|
|
637
|
+
"FILE PREVIEW — ",
|
|
638
|
+
totalRows.toLocaleString(),
|
|
639
|
+
" RECORDS DETECTED IN CSV"
|
|
640
|
+
] }),
|
|
641
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral500", display: "block", children: [
|
|
642
|
+
totalRows.toLocaleString(),
|
|
643
|
+
" total row",
|
|
644
|
+
totalRows > 1 ? "s" : "",
|
|
645
|
+
" •",
|
|
646
|
+
" ",
|
|
647
|
+
updateCount > 0 ? `${updateCount.toLocaleString()} updates` : "",
|
|
648
|
+
updateCount > 0 && missingDocIdCount > 0 ? ", " : "",
|
|
649
|
+
missingDocIdCount > 0 ? `${missingDocIdCount.toLocaleString()} new entries (missing documentId)` : ""
|
|
650
|
+
] })
|
|
472
651
|
] }),
|
|
473
|
-
/* @__PURE__ */ jsxs(
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
missingDocIdCount > 0
|
|
652
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
|
653
|
+
/* @__PURE__ */ jsxs(Badge, { backgroundColor: "primary100", textColor: "primary700", children: [
|
|
654
|
+
"🔄 ",
|
|
655
|
+
updateCount.toLocaleString(),
|
|
656
|
+
" Updates"
|
|
657
|
+
] }),
|
|
658
|
+
missingDocIdCount > 0 && /* @__PURE__ */ jsxs(Badge, { backgroundColor: "warning100", textColor: "warning700", children: [
|
|
659
|
+
"➕ ",
|
|
660
|
+
missingDocIdCount.toLocaleString(),
|
|
661
|
+
" New (No ID)"
|
|
662
|
+
] })
|
|
480
663
|
] })
|
|
481
664
|
] }),
|
|
482
|
-
/* @__PURE__ */ jsx(
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
665
|
+
preflightReport && /* @__PURE__ */ jsx(
|
|
666
|
+
Box,
|
|
667
|
+
{
|
|
668
|
+
marginBottom: 3,
|
|
669
|
+
padding: 4,
|
|
670
|
+
background: preflightReport.hasErrors ? "danger100" : preflightReport.hasWarnings ? "warning100" : "success100",
|
|
671
|
+
hasRadius: true,
|
|
672
|
+
style: { border: `1px solid ${preflightReport.hasErrors ? "#d9534f" : preflightReport.hasWarnings ? "#f0ad4e" : "#5cb85c"}` },
|
|
673
|
+
children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
|
|
674
|
+
/* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", wrap: "wrap", gap: 2, children: [
|
|
675
|
+
/* @__PURE__ */ jsx(Typography, { fontWeight: "bold", textColor: preflightReport.hasErrors ? "danger700" : preflightReport.hasWarnings ? "warning700" : "success700", children: preflightReport.hasErrors ? `⚠️ Pre-Flight Check: ${preflightReport.totalErrorCount} error(s) detected` : preflightReport.hasWarnings ? `⚡ Pre-Flight Check: ${preflightReport.validRows} valid rows with ${preflightReport.totalWarningCount} warning(s)` : `✅ Pre-Flight Check Passed: All ${preflightReport.validRows} rows are ready for import` }),
|
|
676
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
|
677
|
+
/* @__PURE__ */ jsxs(Badge, { backgroundColor: "success100", textColor: "success700", children: [
|
|
678
|
+
"✓ ",
|
|
679
|
+
preflightReport.validRows,
|
|
680
|
+
" Valid Rows"
|
|
681
|
+
] }),
|
|
682
|
+
/* @__PURE__ */ jsxs(Badge, { backgroundColor: "primary100", textColor: "primary700", children: [
|
|
683
|
+
"🔄 ",
|
|
684
|
+
preflightReport.estimatedUpdates,
|
|
685
|
+
" Updates"
|
|
686
|
+
] }),
|
|
687
|
+
/* @__PURE__ */ jsxs(Badge, { backgroundColor: "warning100", textColor: "warning700", children: [
|
|
688
|
+
"➕ ",
|
|
689
|
+
preflightReport.estimatedCreates,
|
|
690
|
+
" New"
|
|
691
|
+
] })
|
|
692
|
+
] })
|
|
693
|
+
] }),
|
|
694
|
+
preflightReport.hasErrors && /* @__PURE__ */ jsxs(Box, { marginTop: 2, background: "neutral0", padding: 3, hasRadius: true, style: { maxHeight: 160, overflowY: "auto" }, children: [
|
|
695
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "pi", fontWeight: "bold", textColor: "danger700", display: "block", marginBottom: 1, children: [
|
|
696
|
+
"Validation Errors (",
|
|
697
|
+
preflightReport.totalErrorCount,
|
|
698
|
+
"):"
|
|
699
|
+
] }),
|
|
700
|
+
preflightReport.errors.map((e, idx) => /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "danger700", display: "block", children: [
|
|
701
|
+
"• Row ",
|
|
702
|
+
e.row,
|
|
703
|
+
": ",
|
|
704
|
+
e.error
|
|
705
|
+
] }, idx))
|
|
706
|
+
] }),
|
|
707
|
+
preflightReport.hasWarnings && /* @__PURE__ */ jsxs(Box, { marginTop: 2, background: "neutral0", padding: 3, hasRadius: true, style: { maxHeight: 140, overflowY: "auto" }, children: [
|
|
708
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "pi", fontWeight: "bold", textColor: "warning700", display: "block", marginBottom: 1, children: [
|
|
709
|
+
"Warnings (",
|
|
710
|
+
preflightReport.totalWarningCount,
|
|
711
|
+
"):"
|
|
712
|
+
] }),
|
|
713
|
+
preflightReport.warnings.map((w, idx) => /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "warning700", display: "block", children: [
|
|
714
|
+
"• Row ",
|
|
715
|
+
w.row,
|
|
716
|
+
": ",
|
|
717
|
+
w.warning
|
|
718
|
+
] }, idx))
|
|
719
|
+
] })
|
|
720
|
+
] })
|
|
721
|
+
}
|
|
722
|
+
),
|
|
723
|
+
missingDocIdCount > 0 && /* @__PURE__ */ jsx(Box, { marginBottom: 3, children: /* @__PURE__ */ jsx(Alert, { variant: "default", title: "Smart Auto-Detect Active", children: /* @__PURE__ */ jsxs(Typography, { variant: "omega", children: [
|
|
724
|
+
missingDocIdCount.toLocaleString(),
|
|
725
|
+
" row",
|
|
726
|
+
missingDocIdCount > 1 ? "s have" : " has",
|
|
727
|
+
" no ",
|
|
728
|
+
/* @__PURE__ */ jsx("code", { children: "documentId" }),
|
|
729
|
+
".",
|
|
730
|
+
" ",
|
|
731
|
+
"Because no documentId is provided, the engine will automatically treat them as new entries and generate new database IDs for them."
|
|
732
|
+
] }) }) }),
|
|
733
|
+
/* @__PURE__ */ jsx(Box, { style: { overflowX: "auto", maxWidth: "100%", border: "1px solid #e0e0e0", borderRadius: 4 }, children: /* @__PURE__ */ jsxs(Table, { colCount: headers.length + 1, rowCount: displayedRows.length + 1, children: [
|
|
734
|
+
/* @__PURE__ */ jsx(Thead, { children: /* @__PURE__ */ jsxs(Tr, { children: [
|
|
735
|
+
/* @__PURE__ */ jsx(Th, { style: { width: 150, minWidth: 150 }, children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: "Detected Action" }) }),
|
|
736
|
+
headers.map((h) => /* @__PURE__ */ jsx(Th, { style: { minWidth: 160 }, children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: h }) }, h))
|
|
737
|
+
] }) }),
|
|
738
|
+
/* @__PURE__ */ jsx(Tbody, { children: displayedRows.map((row, rIdx) => {
|
|
739
|
+
const hasDocId = !!extractDocId(row);
|
|
740
|
+
const actualRowIndex = startIndex + rIdx + 1;
|
|
741
|
+
return /* @__PURE__ */ jsxs(Tr, { children: [
|
|
742
|
+
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 1, children: [
|
|
743
|
+
hasDocId ? /* @__PURE__ */ jsx(Badge, { backgroundColor: "primary100", textColor: "primary700", children: "🔄 Update" }) : /* @__PURE__ */ jsx(Badge, { backgroundColor: "warning100", textColor: "warning700", children: "➕ New Entry" }),
|
|
744
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral500", children: [
|
|
745
|
+
"Row #",
|
|
746
|
+
actualRowIndex
|
|
747
|
+
] })
|
|
748
|
+
] }) }),
|
|
749
|
+
headers.map((h) => /* @__PURE__ */ jsx(Td, { style: { verticalAlign: "top", maxWidth: 300 }, children: (h === "documentId" || h === "id") && !row[h]?.trim() ? /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "warning700", fontWeight: "bold", children: "(Auto-generate ID)" }) : /* @__PURE__ */ jsx(
|
|
750
|
+
Typography,
|
|
751
|
+
{
|
|
752
|
+
variant: "omega",
|
|
753
|
+
style: {
|
|
754
|
+
display: "-webkit-box",
|
|
755
|
+
WebkitLineClamp: 3,
|
|
756
|
+
WebkitBoxOrient: "vertical",
|
|
757
|
+
overflow: "hidden",
|
|
758
|
+
textOverflow: "ellipsis",
|
|
759
|
+
whiteSpace: "pre-wrap",
|
|
760
|
+
wordBreak: "break-word",
|
|
761
|
+
maxHeight: 65
|
|
762
|
+
},
|
|
763
|
+
title: row[h] || "",
|
|
764
|
+
children: row[h] || "-"
|
|
765
|
+
}
|
|
766
|
+
) }, h))
|
|
767
|
+
] }, rIdx);
|
|
768
|
+
}) })
|
|
505
769
|
] }) }),
|
|
506
|
-
/* @__PURE__ */
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
/* @__PURE__ */ jsx(
|
|
510
|
-
|
|
511
|
-
Typography,
|
|
770
|
+
/* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", marginTop: 3, wrap: "wrap", gap: 3, children: [
|
|
771
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
|
|
772
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Rows per page:" }),
|
|
773
|
+
/* @__PURE__ */ jsx(Box, { style: { width: 80 }, children: /* @__PURE__ */ jsxs(
|
|
774
|
+
SingleSelect,
|
|
512
775
|
{
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
WebkitBoxOrient: "vertical",
|
|
518
|
-
overflow: "hidden",
|
|
519
|
-
textOverflow: "ellipsis",
|
|
520
|
-
whiteSpace: "pre-wrap",
|
|
521
|
-
wordBreak: "break-word",
|
|
522
|
-
maxHeight: 65
|
|
776
|
+
value: String(previewPageSize),
|
|
777
|
+
onChange: (val) => {
|
|
778
|
+
setPreviewPageSize(Number(val));
|
|
779
|
+
setPreviewPage(1);
|
|
523
780
|
},
|
|
524
|
-
|
|
525
|
-
|
|
781
|
+
children: [
|
|
782
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "10", children: "10" }),
|
|
783
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "25", children: "25" }),
|
|
784
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "50", children: "50" }),
|
|
785
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "100", children: "100" })
|
|
786
|
+
]
|
|
526
787
|
}
|
|
527
|
-
) },
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
788
|
+
) }),
|
|
789
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", children: [
|
|
790
|
+
"Showing ",
|
|
791
|
+
startIndex + 1,
|
|
792
|
+
"–",
|
|
793
|
+
endIndex,
|
|
794
|
+
" of ",
|
|
795
|
+
totalRows.toLocaleString(),
|
|
796
|
+
" rows"
|
|
797
|
+
] })
|
|
798
|
+
] }),
|
|
799
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
|
|
800
|
+
/* @__PURE__ */ jsx(
|
|
801
|
+
Button,
|
|
802
|
+
{
|
|
803
|
+
variant: "tertiary",
|
|
804
|
+
size: "S",
|
|
805
|
+
startIcon: /* @__PURE__ */ jsx(ChevronLeft, {}),
|
|
806
|
+
disabled: safePage <= 1 || importing,
|
|
807
|
+
onClick: () => setPreviewPage((p) => Math.max(1, p - 1)),
|
|
808
|
+
children: "Prev"
|
|
809
|
+
}
|
|
810
|
+
),
|
|
811
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral700", children: [
|
|
812
|
+
"Page ",
|
|
813
|
+
safePage,
|
|
814
|
+
" of ",
|
|
815
|
+
totalPages
|
|
816
|
+
] }),
|
|
817
|
+
/* @__PURE__ */ jsx(
|
|
818
|
+
Button,
|
|
819
|
+
{
|
|
820
|
+
variant: "tertiary",
|
|
821
|
+
size: "S",
|
|
822
|
+
endIcon: /* @__PURE__ */ jsx(ChevronRight, {}),
|
|
823
|
+
disabled: safePage >= totalPages || importing,
|
|
824
|
+
onClick: () => setPreviewPage((p) => Math.min(totalPages, p + 1)),
|
|
825
|
+
children: "Next"
|
|
826
|
+
}
|
|
827
|
+
)
|
|
828
|
+
] })
|
|
829
|
+
] }),
|
|
830
|
+
/* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", marginTop: 4, wrap: "wrap", gap: 3, children: [
|
|
831
|
+
/* @__PURE__ */ jsx(
|
|
832
|
+
Button,
|
|
833
|
+
{
|
|
834
|
+
variant: "secondary",
|
|
835
|
+
size: "L",
|
|
836
|
+
startIcon: /* @__PURE__ */ jsx(Eye, {}),
|
|
837
|
+
onClick: handleRunPreflight,
|
|
838
|
+
loading: preflightLoading,
|
|
839
|
+
disabled: importing,
|
|
840
|
+
children: "Run Pre-Flight Dry Run"
|
|
841
|
+
}
|
|
842
|
+
),
|
|
843
|
+
/* @__PURE__ */ jsxs(
|
|
844
|
+
Button,
|
|
845
|
+
{
|
|
846
|
+
variant: "default",
|
|
847
|
+
size: "L",
|
|
848
|
+
startIcon: /* @__PURE__ */ jsx(Check, {}),
|
|
849
|
+
onClick: () => setShowConfirmModal(true),
|
|
850
|
+
loading: importing || submittingBatch,
|
|
851
|
+
children: [
|
|
852
|
+
"Review & Import (",
|
|
853
|
+
totalRows.toLocaleString(),
|
|
854
|
+
" Records)..."
|
|
855
|
+
]
|
|
856
|
+
}
|
|
857
|
+
)
|
|
858
|
+
] })
|
|
859
|
+
] });
|
|
860
|
+
})(),
|
|
861
|
+
importProgress && /* @__PURE__ */ jsxs(Box, { marginTop: 4, padding: 4, background: "neutral0", hasRadius: true, style: { border: "1px solid #4945ff" }, children: [
|
|
862
|
+
/* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 2, children: [
|
|
863
|
+
/* @__PURE__ */ jsx(Typography, { variant: "delta", fontWeight: "bold", textColor: "primary700", children: importing ? `Processing Batch Chunk ${importProgress.currentChunk} of ${importProgress.totalChunks} (${importProgress.percent}%)` : "Batch Import Complete" }),
|
|
864
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral700", children: [
|
|
865
|
+
importProgress.processedRows.toLocaleString(),
|
|
866
|
+
" / ",
|
|
867
|
+
importProgress.totalRows.toLocaleString(),
|
|
868
|
+
" rows processed"
|
|
869
|
+
] })
|
|
870
|
+
] }),
|
|
871
|
+
/* @__PURE__ */ jsx(Box, { style: { width: "100%", height: 10, background: "#e0e0e0", borderRadius: 5, overflow: "hidden", marginBottom: 12 }, children: /* @__PURE__ */ jsx(
|
|
872
|
+
Box,
|
|
533
873
|
{
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
874
|
+
style: {
|
|
875
|
+
width: `${importProgress.percent}%`,
|
|
876
|
+
height: "100%",
|
|
877
|
+
background: importProgress.percent === 100 ? "#2f6846" : "#4945ff",
|
|
878
|
+
transition: "width 0.2s ease-in-out"
|
|
879
|
+
}
|
|
540
880
|
}
|
|
541
|
-
) })
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
{
|
|
547
|
-
variant: importResult.stats.errors.length > 0 ? "warning" : "success",
|
|
548
|
-
title: "CSV Import Results",
|
|
549
|
-
children: [
|
|
550
|
-
/* @__PURE__ */ jsxs(Typography, { variant: "omega", display: "block", marginBottom: 1, children: [
|
|
551
|
-
"Successfully processed: ",
|
|
552
|
-
/* @__PURE__ */ jsxs("strong", { children: [
|
|
553
|
-
importResult.stats.created,
|
|
554
|
-
" created"
|
|
555
|
-
] }),
|
|
556
|
-
importResult.stats.newWithoutDocId > 0 && /* @__PURE__ */ jsxs("span", { children: [
|
|
557
|
-
" (",
|
|
558
|
-
importResult.stats.newWithoutDocId,
|
|
559
|
-
" created as new entries because documentId was omitted)"
|
|
560
|
-
] }),
|
|
561
|
-
", ",
|
|
562
|
-
/* @__PURE__ */ jsxs("strong", { children: [
|
|
563
|
-
importResult.stats.updated,
|
|
564
|
-
" updated"
|
|
565
|
-
] }),
|
|
566
|
-
",",
|
|
567
|
-
" ",
|
|
568
|
-
/* @__PURE__ */ jsxs("strong", { children: [
|
|
569
|
-
importResult.stats.skipped,
|
|
570
|
-
" skipped"
|
|
571
|
-
] }),
|
|
572
|
-
" out of ",
|
|
573
|
-
importResult.stats.total,
|
|
574
|
-
" total rows."
|
|
881
|
+
) }),
|
|
882
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 3, wrap: "wrap", alignItems: "center", children: [
|
|
883
|
+
/* @__PURE__ */ jsxs(Badge, { backgroundColor: "success100", textColor: "success700", children: [
|
|
884
|
+
"Created: ",
|
|
885
|
+
importProgress.liveCreated.toLocaleString()
|
|
575
886
|
] }),
|
|
576
|
-
|
|
577
|
-
"
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
"
|
|
582
|
-
|
|
583
|
-
" had no ",
|
|
584
|
-
/* @__PURE__ */ jsx("code", { children: "documentId" }),
|
|
585
|
-
" specified in the CSV. The engine generated brand-new database entries with assigned document IDs. If you export this collection now, you will see their generated document IDs."
|
|
586
|
-
] }) }),
|
|
587
|
-
importResult.stats.errors.length > 0 && /* @__PURE__ */ jsxs(Box, { marginTop: 2, children: [
|
|
588
|
-
/* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "danger700", fontWeight: "bold", children: [
|
|
589
|
-
"Errors encountered (",
|
|
590
|
-
importResult.stats.errors.length,
|
|
591
|
-
"):"
|
|
592
|
-
] }),
|
|
593
|
-
/* @__PURE__ */ jsx("ul", { style: { margin: "4px 0 0 16px", padding: 0 }, children: importResult.stats.errors.slice(0, 10).map((err, idx) => /* @__PURE__ */ jsx("li", { style: { marginBottom: "2px" }, children: /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "danger600", children: [
|
|
594
|
-
"Row ",
|
|
595
|
-
err.row,
|
|
596
|
-
": ",
|
|
597
|
-
err.error
|
|
598
|
-
] }) }, idx)) }),
|
|
599
|
-
importResult.stats.errors.length > 10 && /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", style: { display: "block", marginTop: 4, fontStyle: "italic" }, children: [
|
|
600
|
-
"...and ",
|
|
601
|
-
importResult.stats.errors.length - 10,
|
|
602
|
-
" more error",
|
|
603
|
-
importResult.stats.errors.length - 10 > 1 ? "s" : ""
|
|
604
|
-
] })
|
|
887
|
+
/* @__PURE__ */ jsxs(Badge, { backgroundColor: "primary100", textColor: "primary700", children: [
|
|
888
|
+
"Updated: ",
|
|
889
|
+
importProgress.liveUpdated.toLocaleString()
|
|
890
|
+
] }),
|
|
891
|
+
/* @__PURE__ */ jsxs(Badge, { backgroundColor: "neutral150", textColor: "neutral700", children: [
|
|
892
|
+
"Skipped: ",
|
|
893
|
+
importProgress.liveSkipped.toLocaleString()
|
|
605
894
|
] }),
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
895
|
+
importProgress.liveErrors > 0 && /* @__PURE__ */ jsxs(Badge, { backgroundColor: "danger100", textColor: "danger700", children: [
|
|
896
|
+
"Errors: ",
|
|
897
|
+
importProgress.liveErrors.toLocaleString()
|
|
898
|
+
] })
|
|
899
|
+
] })
|
|
900
|
+
] }),
|
|
901
|
+
importResult && /* @__PURE__ */ jsx(Box, { marginTop: 4, children: /* @__PURE__ */ jsxs(
|
|
902
|
+
Alert,
|
|
903
|
+
{
|
|
904
|
+
variant: importResult.stats.errors.length > 0 ? "warning" : "success",
|
|
905
|
+
title: "CSV Import Results",
|
|
906
|
+
children: [
|
|
907
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "omega", display: "block", marginBottom: 1, children: [
|
|
908
|
+
"Successfully processed: ",
|
|
909
|
+
/* @__PURE__ */ jsxs("strong", { children: [
|
|
910
|
+
importResult.stats.created.toLocaleString(),
|
|
911
|
+
" created"
|
|
912
|
+
] }),
|
|
913
|
+
importResult.stats.newWithoutDocId > 0 && /* @__PURE__ */ jsxs("span", { children: [
|
|
914
|
+
" (",
|
|
915
|
+
importResult.stats.newWithoutDocId.toLocaleString(),
|
|
916
|
+
" created as new entries because documentId was omitted)"
|
|
917
|
+
] }),
|
|
918
|
+
", ",
|
|
919
|
+
/* @__PURE__ */ jsxs("strong", { children: [
|
|
920
|
+
importResult.stats.updated.toLocaleString(),
|
|
921
|
+
" updated"
|
|
922
|
+
] }),
|
|
923
|
+
",",
|
|
924
|
+
" ",
|
|
925
|
+
/* @__PURE__ */ jsxs("strong", { children: [
|
|
926
|
+
importResult.stats.skipped.toLocaleString(),
|
|
927
|
+
" skipped"
|
|
928
|
+
] }),
|
|
929
|
+
" out of ",
|
|
930
|
+
importResult.stats.total.toLocaleString(),
|
|
931
|
+
" total rows."
|
|
611
932
|
] }),
|
|
612
|
-
/* @__PURE__ */ jsx(Box, {
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
return /* @__PURE__ */ jsxs(Tr, { children: [
|
|
623
|
-
/* @__PURE__ */ jsxs(Td, { children: [
|
|
624
|
-
/* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", children: d.label || d.documentId }),
|
|
625
|
-
d.documentId && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", display: "block", children: d.documentId })
|
|
626
|
-
] }),
|
|
627
|
-
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Badge, { backgroundColor: "secondary100", textColor: "secondary700", children: d.attribute || "field" }) }),
|
|
628
|
-
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { textColor: "danger600", children: oldDisplay }) }),
|
|
629
|
-
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "semiBold", children: newDisplay }) })
|
|
630
|
-
] }, idx);
|
|
631
|
-
}) })
|
|
933
|
+
importResult.stats.newWithoutDocId > 0 && /* @__PURE__ */ jsx(Box, { marginTop: 2, padding: 2, background: "neutral100", hasRadius: true, children: /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral700", children: [
|
|
934
|
+
"ℹ️ ",
|
|
935
|
+
/* @__PURE__ */ jsx("strong", { children: "Note on new entries:" }),
|
|
936
|
+
" ",
|
|
937
|
+
importResult.stats.newWithoutDocId,
|
|
938
|
+
" row",
|
|
939
|
+
importResult.stats.newWithoutDocId > 1 ? "s" : "",
|
|
940
|
+
" had no ",
|
|
941
|
+
/* @__PURE__ */ jsx("code", { children: "documentId" }),
|
|
942
|
+
" specified in the CSV. The engine generated brand-new database entries with assigned document IDs. If you export this collection now, you will see their generated document IDs."
|
|
632
943
|
] }) }),
|
|
633
|
-
importResult.stats.
|
|
634
|
-
"
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
944
|
+
importResult.stats.errors.length > 0 && /* @__PURE__ */ jsxs(Box, { marginTop: 2, children: [
|
|
945
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "danger700", fontWeight: "bold", children: [
|
|
946
|
+
"Errors encountered (",
|
|
947
|
+
importResult.stats.errors.length,
|
|
948
|
+
"):"
|
|
949
|
+
] }),
|
|
950
|
+
/* @__PURE__ */ jsx("ul", { style: { margin: "4px 0 0 16px", padding: 0 }, children: importResult.stats.errors.slice(0, 10).map((err, idx) => /* @__PURE__ */ jsx("li", { style: { marginBottom: "2px" }, children: /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "danger600", children: [
|
|
951
|
+
"Row ",
|
|
952
|
+
err.row,
|
|
953
|
+
": ",
|
|
954
|
+
err.error
|
|
955
|
+
] }) }, idx)) }),
|
|
956
|
+
importResult.stats.errors.length > 10 && /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", style: { display: "block", marginTop: 4, fontStyle: "italic" }, children: [
|
|
957
|
+
"...and ",
|
|
958
|
+
importResult.stats.errors.length - 10,
|
|
959
|
+
" more error",
|
|
960
|
+
importResult.stats.errors.length - 10 > 1 ? "s" : ""
|
|
961
|
+
] })
|
|
962
|
+
] }),
|
|
963
|
+
importResult.stats.diffs && importResult.stats.diffs.length > 0 && /* @__PURE__ */ jsxs(Box, { marginTop: 3, padding: 3, background: "neutral0", hasRadius: true, style: { border: "1px solid #dcdce4" }, children: [
|
|
964
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "sigma", textColor: "neutral800", fontWeight: "bold", display: "block", marginBottom: 2, children: [
|
|
965
|
+
"CHANGES APPLIED (",
|
|
966
|
+
importResult.stats.diffs.length.toLocaleString(),
|
|
967
|
+
"):"
|
|
968
|
+
] }),
|
|
969
|
+
/* @__PURE__ */ jsx(Box, { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsxs(Table, { colCount: 4, rowCount: importResult.stats.diffs.length + 1, children: [
|
|
970
|
+
/* @__PURE__ */ jsx(Thead, { children: /* @__PURE__ */ jsxs(Tr, { children: [
|
|
971
|
+
/* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: "Entry / Document" }) }),
|
|
972
|
+
/* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: "Attribute" }) }),
|
|
973
|
+
/* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: "Previous Value" }) }),
|
|
974
|
+
/* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: "Applied Value" }) })
|
|
975
|
+
] }) }),
|
|
976
|
+
/* @__PURE__ */ jsx(Tbody, { children: importResult.stats.diffs.slice(0, 10).map((d, idx) => {
|
|
977
|
+
const oldDisplay = d.oldValue !== null && d.oldValue !== void 0 ? typeof d.oldValue === "object" ? JSON.stringify(d.oldValue) : String(d.oldValue) : "(empty)";
|
|
978
|
+
const newDisplay = d.newValue !== null && d.newValue !== void 0 ? typeof d.newValue === "object" ? JSON.stringify(d.newValue) : String(d.newValue) : "(empty)";
|
|
979
|
+
return /* @__PURE__ */ jsxs(Tr, { children: [
|
|
980
|
+
/* @__PURE__ */ jsxs(Td, { children: [
|
|
981
|
+
/* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", children: d.label || d.documentId }),
|
|
982
|
+
d.documentId && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", display: "block", children: d.documentId })
|
|
983
|
+
] }),
|
|
984
|
+
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Badge, { backgroundColor: "secondary100", textColor: "secondary700", children: d.attribute || "field" }) }),
|
|
985
|
+
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { textColor: "danger600", children: oldDisplay }) }),
|
|
986
|
+
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "semiBold", children: newDisplay }) })
|
|
987
|
+
] }, idx);
|
|
988
|
+
}) })
|
|
989
|
+
] }) }),
|
|
990
|
+
importResult.stats.diffs.length > 10 && /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", style: { display: "block", marginTop: 6, fontStyle: "italic" }, children: [
|
|
991
|
+
"...and ",
|
|
992
|
+
importResult.stats.diffs.length - 10,
|
|
993
|
+
" more change",
|
|
994
|
+
importResult.stats.diffs.length - 10 > 1 ? "s" : "",
|
|
995
|
+
" recorded in Audit Trail & Version History."
|
|
996
|
+
] })
|
|
639
997
|
] })
|
|
640
|
-
]
|
|
641
|
-
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
] })
|
|
645
|
-
|
|
998
|
+
]
|
|
999
|
+
}
|
|
1000
|
+
) })
|
|
1001
|
+
] })
|
|
1002
|
+
] }),
|
|
1003
|
+
showConfirmModal && /* @__PURE__ */ jsx(
|
|
1004
|
+
"div",
|
|
1005
|
+
{
|
|
1006
|
+
style: {
|
|
1007
|
+
position: "fixed",
|
|
1008
|
+
inset: 0,
|
|
1009
|
+
backgroundColor: "rgba(20, 20, 30, 0.65)",
|
|
1010
|
+
backdropFilter: "blur(2px)",
|
|
1011
|
+
display: "flex",
|
|
1012
|
+
alignItems: "center",
|
|
1013
|
+
justifyContent: "center",
|
|
1014
|
+
zIndex: 9999,
|
|
1015
|
+
padding: 16,
|
|
1016
|
+
boxSizing: "border-box",
|
|
1017
|
+
overflowY: "auto"
|
|
1018
|
+
},
|
|
1019
|
+
onClick: () => setShowConfirmModal(false),
|
|
1020
|
+
children: /* @__PURE__ */ jsxs(
|
|
1021
|
+
Box,
|
|
1022
|
+
{
|
|
1023
|
+
background: "neutral0",
|
|
1024
|
+
hasRadius: true,
|
|
1025
|
+
shadow: "popupShadow",
|
|
1026
|
+
style: {
|
|
1027
|
+
maxWidth: 680,
|
|
1028
|
+
width: "100%",
|
|
1029
|
+
maxHeight: "calc(100vh - 48px)",
|
|
1030
|
+
display: "flex",
|
|
1031
|
+
flexDirection: "column",
|
|
1032
|
+
overflow: "hidden",
|
|
1033
|
+
position: "relative",
|
|
1034
|
+
boxShadow: "0 24px 48px rgba(0, 0, 0, 0.32), 0 0 1px rgba(0, 0, 0, 0.2)"
|
|
1035
|
+
},
|
|
1036
|
+
onClick: (e) => e.stopPropagation(),
|
|
1037
|
+
children: [
|
|
1038
|
+
/* @__PURE__ */ jsx(
|
|
1039
|
+
Box,
|
|
1040
|
+
{
|
|
1041
|
+
padding: 5,
|
|
1042
|
+
background: "neutral100",
|
|
1043
|
+
style: {
|
|
1044
|
+
borderBottom: "1px solid rgba(120, 120, 150, 0.2)",
|
|
1045
|
+
flexShrink: 0
|
|
1046
|
+
},
|
|
1047
|
+
children: /* @__PURE__ */ jsx(Flex, { justifyContent: "space-between", alignItems: "center", children: /* @__PURE__ */ jsxs(Box, { children: [
|
|
1048
|
+
/* @__PURE__ */ jsx(Typography, { variant: "delta", fontWeight: "bold", children: "Confirm CSV Bulk Import" }),
|
|
1049
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", display: "block", children: "Review import target, record actions, publishing mode, and execution window policies before proceeding." })
|
|
1050
|
+
] }) })
|
|
1051
|
+
}
|
|
1052
|
+
),
|
|
1053
|
+
/* @__PURE__ */ jsxs(
|
|
1054
|
+
Box,
|
|
1055
|
+
{
|
|
1056
|
+
padding: 5,
|
|
1057
|
+
style: {
|
|
1058
|
+
flex: "1 1 auto",
|
|
1059
|
+
minHeight: 0,
|
|
1060
|
+
overflowY: "auto",
|
|
1061
|
+
WebkitOverflowScrolling: "touch"
|
|
1062
|
+
},
|
|
1063
|
+
children: [
|
|
1064
|
+
/* @__PURE__ */ jsxs(Box, { padding: 4, background: "neutral100", hasRadius: true, marginBottom: 4, children: [
|
|
1065
|
+
/* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", marginBottom: 2, display: "block", children: "IMPORT DETAILS" }),
|
|
1066
|
+
/* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
|
|
1067
|
+
/* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [
|
|
1068
|
+
/* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", children: "Target Collection:" }),
|
|
1069
|
+
/* @__PURE__ */ jsx(Badge, { backgroundColor: "primary100", textColor: "primary700", children: selectedCol?.displayName || selectedUid })
|
|
1070
|
+
] }),
|
|
1071
|
+
/* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [
|
|
1072
|
+
/* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", children: "Total Detected Records:" }),
|
|
1073
|
+
/* @__PURE__ */ jsxs(Typography, { fontWeight: "bold", textColor: "primary600", children: [
|
|
1074
|
+
allParsedRecords.length.toLocaleString(),
|
|
1075
|
+
" records"
|
|
1076
|
+
] })
|
|
1077
|
+
] }),
|
|
1078
|
+
/* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [
|
|
1079
|
+
/* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", children: "Action Breakdown:" }),
|
|
1080
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
|
1081
|
+
/* @__PURE__ */ jsxs(Badge, { backgroundColor: "primary100", textColor: "primary700", children: [
|
|
1082
|
+
"🔄 ",
|
|
1083
|
+
allParsedRecords.filter((r) => !!extractDocId(r)).length.toLocaleString(),
|
|
1084
|
+
" Updates"
|
|
1085
|
+
] }),
|
|
1086
|
+
/* @__PURE__ */ jsxs(Badge, { backgroundColor: "warning100", textColor: "warning700", children: [
|
|
1087
|
+
"➕ ",
|
|
1088
|
+
allParsedRecords.filter((r) => !extractDocId(r)).length.toLocaleString(),
|
|
1089
|
+
" New (No ID)"
|
|
1090
|
+
] })
|
|
1091
|
+
] })
|
|
1092
|
+
] }),
|
|
1093
|
+
/* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [
|
|
1094
|
+
/* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", children: "Import Mode:" }),
|
|
1095
|
+
/* @__PURE__ */ jsx(Badge, { backgroundColor: "neutral200", textColor: "neutral800", children: importMode === "update" ? "Update Only (Exact Document IDs)" : importMode === "create_or_override" ? "Create or Override" : "Smart Auto-Detect" })
|
|
1096
|
+
] }),
|
|
1097
|
+
/* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [
|
|
1098
|
+
/* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", children: "Publishing Mode:" }),
|
|
1099
|
+
/* @__PURE__ */ jsx(
|
|
1100
|
+
Badge,
|
|
1101
|
+
{
|
|
1102
|
+
backgroundColor: publishOnImport ? "success100" : "warning100",
|
|
1103
|
+
textColor: publishOnImport ? "success700" : "warning700",
|
|
1104
|
+
children: publishOnImport ? "Publish Immediately" : "Keep as Draft"
|
|
1105
|
+
}
|
|
1106
|
+
)
|
|
1107
|
+
] }),
|
|
1108
|
+
preflightReport && /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", marginTop: 2, paddingTop: 2, style: { borderTop: "1px solid #eaeaef" }, children: [
|
|
1109
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Pre-Flight Status:" }),
|
|
1110
|
+
/* @__PURE__ */ jsx(
|
|
1111
|
+
Typography,
|
|
1112
|
+
{
|
|
1113
|
+
variant: "pi",
|
|
1114
|
+
fontWeight: "bold",
|
|
1115
|
+
textColor: preflightReport.hasErrors ? "danger700" : preflightReport.hasWarnings ? "warning700" : "success700",
|
|
1116
|
+
children: preflightReport.hasErrors ? `⚠️ ${preflightReport.totalErrorCount} errors found` : preflightReport.hasWarnings ? `⚡ Passed with ${preflightReport.totalWarningCount} warnings` : "✅ 100% Passed"
|
|
1117
|
+
}
|
|
1118
|
+
)
|
|
1119
|
+
] })
|
|
1120
|
+
] })
|
|
1121
|
+
] }),
|
|
1122
|
+
/* @__PURE__ */ jsx(Box, { padding: 4, hasRadius: true, marginBottom: 4, background: executionWindow?.isBusinessHours ? "warning100" : "success100", children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 1, children: [
|
|
1123
|
+
/* @__PURE__ */ jsx(Flex, { gap: 2, alignItems: "center", children: /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", textColor: executionWindow?.isBusinessHours ? "warning700" : "success700", children: executionWindow?.isBusinessHours ? "⏰ Peak Business Hours Restriction Active" : "✅ Server Off-Peak Window Active" }) }),
|
|
1124
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: executionWindow?.isBusinessHours ? "warning700" : "success700", children: executionWindow?.policyMessage || (executionWindow?.isBusinessHours ? "Server policy restricts bulk operations during peak business hours (09:00 - 18:00). Direct execution is paused to preserve API throughput." : "Currently outside peak business hours. Direct execution is permitted.") })
|
|
1125
|
+
] }) }),
|
|
1126
|
+
/* @__PURE__ */ jsx(
|
|
1127
|
+
Box,
|
|
1128
|
+
{
|
|
1129
|
+
padding: 4,
|
|
1130
|
+
background: "neutral100",
|
|
1131
|
+
hasRadius: true,
|
|
1132
|
+
marginBottom: 4,
|
|
1133
|
+
style: { border: "1px solid rgba(120, 120, 150, 0.15)" },
|
|
1134
|
+
children: /* @__PURE__ */ jsxs(Flex, { gap: 3, alignItems: "flex-start", children: [
|
|
1135
|
+
/* @__PURE__ */ jsx(
|
|
1136
|
+
Checkbox,
|
|
1137
|
+
{
|
|
1138
|
+
checked: publishOnImport,
|
|
1139
|
+
onValueChange: (val) => setPublishOnImport(Boolean(val))
|
|
1140
|
+
}
|
|
1141
|
+
),
|
|
1142
|
+
/* @__PURE__ */ jsxs(Box, { style: { cursor: "pointer" }, onClick: () => setPublishOnImport(!publishOnImport), children: [
|
|
1143
|
+
/* @__PURE__ */ jsx(Typography, { fontWeight: "bold", display: "block", children: "Publish immediately upon checker approval / execution" }),
|
|
1144
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "When checked (default), content types with Draft & Publish enabled will have their updated documents published immediately upon execution. When unchecked, changes remain in Draft for further editorial review." })
|
|
1145
|
+
] })
|
|
1146
|
+
] })
|
|
1147
|
+
}
|
|
1148
|
+
),
|
|
1149
|
+
/* @__PURE__ */ jsx(Box, { marginBottom: 2, children: /* @__PURE__ */ jsx(
|
|
1150
|
+
TextInput,
|
|
1151
|
+
{
|
|
1152
|
+
label: "Change Request / Release Notes (Optional)",
|
|
1153
|
+
name: "makerNotes",
|
|
1154
|
+
placeholder: "e.g. REL-5040: Bulk updating catalog attributes via CSV",
|
|
1155
|
+
value: makerNotesInput,
|
|
1156
|
+
onChange: (e) => setMakerNotesInput(e.target.value)
|
|
1157
|
+
}
|
|
1158
|
+
) })
|
|
1159
|
+
]
|
|
1160
|
+
}
|
|
1161
|
+
),
|
|
1162
|
+
/* @__PURE__ */ jsx(
|
|
1163
|
+
Box,
|
|
1164
|
+
{
|
|
1165
|
+
padding: 4,
|
|
1166
|
+
background: "neutral100",
|
|
1167
|
+
style: {
|
|
1168
|
+
borderTop: "1px solid rgba(120, 120, 150, 0.2)",
|
|
1169
|
+
flexShrink: 0,
|
|
1170
|
+
position: "sticky",
|
|
1171
|
+
bottom: 0,
|
|
1172
|
+
zIndex: 20,
|
|
1173
|
+
boxShadow: "0 -4px 16px rgba(0, 0, 0, 0.08)"
|
|
1174
|
+
},
|
|
1175
|
+
children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", gap: 3, style: { width: "100%" }, children: [
|
|
1176
|
+
/* @__PURE__ */ jsx(Button, { variant: "tertiary", size: "M", onClick: () => setShowConfirmModal(false), children: "Cancel" }),
|
|
1177
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, wrap: "wrap", justifyContent: "flex-end", alignItems: "center", children: [
|
|
1178
|
+
/* @__PURE__ */ jsx(
|
|
1179
|
+
Button,
|
|
1180
|
+
{
|
|
1181
|
+
variant: executionWindow?.isBusinessHours ? "default" : "secondary",
|
|
1182
|
+
size: "M",
|
|
1183
|
+
onClick: () => submitBatchWithMode("maker_checker"),
|
|
1184
|
+
loading: submittingBatch,
|
|
1185
|
+
children: "Submit for Checker Approval"
|
|
1186
|
+
}
|
|
1187
|
+
),
|
|
1188
|
+
executionWindow?.isBusinessHours ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1189
|
+
/* @__PURE__ */ jsxs(
|
|
1190
|
+
Button,
|
|
1191
|
+
{
|
|
1192
|
+
variant: "secondary",
|
|
1193
|
+
size: "M",
|
|
1194
|
+
onClick: () => submitBatchWithMode("queue_offpeak"),
|
|
1195
|
+
loading: submittingBatch,
|
|
1196
|
+
children: [
|
|
1197
|
+
"Queue for Off-Peak (",
|
|
1198
|
+
executionWindow?.offPeakStartTime || "18:00",
|
|
1199
|
+
")"
|
|
1200
|
+
]
|
|
1201
|
+
}
|
|
1202
|
+
),
|
|
1203
|
+
/* @__PURE__ */ jsx(
|
|
1204
|
+
Button,
|
|
1205
|
+
{
|
|
1206
|
+
variant: "danger-light",
|
|
1207
|
+
size: "S",
|
|
1208
|
+
onClick: () => submitBatchWithMode("immediate", true),
|
|
1209
|
+
loading: importing,
|
|
1210
|
+
children: "Force Run Now"
|
|
1211
|
+
}
|
|
1212
|
+
)
|
|
1213
|
+
] }) : /* @__PURE__ */ jsx(
|
|
1214
|
+
Button,
|
|
1215
|
+
{
|
|
1216
|
+
variant: "default",
|
|
1217
|
+
size: "M",
|
|
1218
|
+
onClick: () => submitBatchWithMode("immediate"),
|
|
1219
|
+
loading: importing,
|
|
1220
|
+
children: "Confirm & Execute Now"
|
|
1221
|
+
}
|
|
1222
|
+
)
|
|
1223
|
+
] })
|
|
1224
|
+
] })
|
|
1225
|
+
}
|
|
1226
|
+
)
|
|
1227
|
+
]
|
|
1228
|
+
}
|
|
1229
|
+
)
|
|
1230
|
+
}
|
|
1231
|
+
)
|
|
1232
|
+
] });
|
|
646
1233
|
}
|
|
647
1234
|
function formatVal(v) {
|
|
648
1235
|
if (v === null || v === void 0) return "(empty)";
|
|
@@ -1624,7 +2211,7 @@ function formatComponentName(compUid) {
|
|
|
1624
2211
|
const name = compUid.includes(".") ? compUid.split(".")[1] : compUid;
|
|
1625
2212
|
return name.split(/[-_]/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
1626
2213
|
}
|
|
1627
|
-
function getAllNestedValues(obj, path) {
|
|
2214
|
+
function getAllNestedValues(obj, path, availableAttributes) {
|
|
1628
2215
|
if (!obj || !path) return [];
|
|
1629
2216
|
const parsed = parseDynamicZonePath(path);
|
|
1630
2217
|
const parts = parsed.cleanPath.split(".");
|
|
@@ -1636,14 +2223,17 @@ function getAllNestedValues(obj, path) {
|
|
|
1636
2223
|
if (!item || typeof item !== "object") return;
|
|
1637
2224
|
if (parsed.targetIndex !== void 0 && idx !== parsed.targetIndex) return;
|
|
1638
2225
|
if (parsed.targetComponentUid && item.__component !== parsed.targetComponentUid) return;
|
|
1639
|
-
const
|
|
1640
|
-
|
|
2226
|
+
const subPath = tail.join(".");
|
|
2227
|
+
const scopedPath = item.__component ? `${head}[${item.__component}].${subPath}` : "";
|
|
2228
|
+
const isSupported = availableAttributes ? availableAttributes.includes(scopedPath) : false;
|
|
2229
|
+
const subVal = tail.length > 0 ? getNestedValue(item, subPath) : item;
|
|
2230
|
+
if (subVal !== void 0 || isSupported) {
|
|
1641
2231
|
results.push({
|
|
1642
2232
|
index: idx,
|
|
1643
2233
|
componentUid: item.__component,
|
|
1644
2234
|
componentName: formatComponentName(item.__component),
|
|
1645
|
-
value: subVal,
|
|
1646
|
-
path: `${head}[#${idx}${item.__component ? ` ${formatComponentName(item.__component)}` : ""}].${
|
|
2235
|
+
value: subVal !== void 0 ? subVal : null,
|
|
2236
|
+
path: `${head}[#${idx}${item.__component ? ` ${formatComponentName(item.__component)}` : ""}].${subPath}`
|
|
1647
2237
|
});
|
|
1648
2238
|
}
|
|
1649
2239
|
});
|
|
@@ -1918,7 +2508,7 @@ function renderCellContent(colDef, entry, col, selectedAttribute, searchAttribut
|
|
|
1918
2508
|
] });
|
|
1919
2509
|
}
|
|
1920
2510
|
case "search_attr": {
|
|
1921
|
-
const matches = getAllNestedValues(entry, searchAttribute);
|
|
2511
|
+
const matches = getAllNestedValues(entry, searchAttribute, col?.attributes);
|
|
1922
2512
|
if (matches.length === 0) {
|
|
1923
2513
|
return /* @__PURE__ */ jsx(Typography, { textColor: "neutral500", style: { fontStyle: "italic" }, children: "(empty / not set)" });
|
|
1924
2514
|
}
|
|
@@ -1986,7 +2576,7 @@ function renderCellContent(colDef, entry, col, selectedAttribute, searchAttribut
|
|
|
1986
2576
|
}) });
|
|
1987
2577
|
}
|
|
1988
2578
|
case "target_attr": {
|
|
1989
|
-
const matches = getAllNestedValues(entry, selectedAttribute);
|
|
2579
|
+
const matches = getAllNestedValues(entry, selectedAttribute, col?.attributes);
|
|
1990
2580
|
if (matches.length === 0) {
|
|
1991
2581
|
return /* @__PURE__ */ jsx(Typography, { textColor: "neutral500", style: { fontStyle: "italic" }, children: "(empty / not set)" });
|
|
1992
2582
|
}
|
|
@@ -2896,7 +3486,11 @@ const BulkUpdater = () => {
|
|
|
2896
3486
|
if (selectedEntries[key]) {
|
|
2897
3487
|
const parts = key.split(KEY_SEP);
|
|
2898
3488
|
if (parts.length === 2) {
|
|
2899
|
-
|
|
3489
|
+
const targetObj = { uid: parts[0], documentId: parts[1] };
|
|
3490
|
+
if (selectedDzBlocks[key] && selectedDzBlocks[key].length > 0) {
|
|
3491
|
+
targetObj.dynamicZoneIndexes = selectedDzBlocks[key];
|
|
3492
|
+
}
|
|
3493
|
+
targets.push(targetObj);
|
|
2900
3494
|
}
|
|
2901
3495
|
}
|
|
2902
3496
|
});
|
|
@@ -3046,6 +3640,20 @@ const BulkUpdater = () => {
|
|
|
3046
3640
|
});
|
|
3047
3641
|
await fetchModels();
|
|
3048
3642
|
await fetchAuditHistory();
|
|
3643
|
+
if (selectedCollectionUid) {
|
|
3644
|
+
loadCollectionPage(
|
|
3645
|
+
selectedCollectionUid,
|
|
3646
|
+
collectionPages[selectedCollectionUid]?.page || 1,
|
|
3647
|
+
void 0,
|
|
3648
|
+
void 0,
|
|
3649
|
+
void 0,
|
|
3650
|
+
filterOperator,
|
|
3651
|
+
filterQuery,
|
|
3652
|
+
entrySearch,
|
|
3653
|
+
false,
|
|
3654
|
+
searchAttribute
|
|
3655
|
+
);
|
|
3656
|
+
}
|
|
3049
3657
|
}
|
|
3050
3658
|
} else {
|
|
3051
3659
|
setIsSubmittingBatch(false);
|
|
@@ -4212,10 +4820,13 @@ const BulkUpdater = () => {
|
|
|
4212
4820
|
isDzExpanded && dzFields.map((dzKey) => {
|
|
4213
4821
|
const blocks = entry[dzKey] || [];
|
|
4214
4822
|
const targetParsed = parseDynamicZonePath(selectedAttribute);
|
|
4215
|
-
const
|
|
4823
|
+
const isBlockApplicable = (blockItem) => {
|
|
4216
4824
|
if (!targetParsed.subPath) return true;
|
|
4217
|
-
|
|
4218
|
-
|
|
4825
|
+
const scopedPath = `${dzKey}[${blockItem?.__component}].${targetParsed.subPath}`;
|
|
4826
|
+
const componentSupports = (col?.attributes || attributes || []).includes(scopedPath);
|
|
4827
|
+
return componentSupports || getNestedValue(blockItem, targetParsed.subPath) !== void 0;
|
|
4828
|
+
};
|
|
4829
|
+
const allApplicableIndexes = blocks.map((_, i) => i).filter((i) => isBlockApplicable(blocks[i]));
|
|
4219
4830
|
return /* @__PURE__ */ jsx(Tr, { children: /* @__PURE__ */ jsx(Td, { colSpan: activeColumns.length, style: { padding: "12px 16px", backgroundColor: "rgba(73, 69, 255, 0.02)", borderBottom: "2px solid rgba(73, 69, 255, 0.15)" }, children: /* @__PURE__ */ jsxs(
|
|
4220
4831
|
Box,
|
|
4221
4832
|
{
|
|
@@ -4252,8 +4863,10 @@ const BulkUpdater = () => {
|
|
|
4252
4863
|
/* @__PURE__ */ jsx(Tbody, { children: blocks.map((block, bIdx) => {
|
|
4253
4864
|
const compUid = block.__component;
|
|
4254
4865
|
const compLabel = formatComponentName(compUid);
|
|
4866
|
+
const scopedPath = `${dzKey}[${compUid}].${targetParsed.subPath}`;
|
|
4867
|
+
const componentSupports = (col?.attributes || attributes || []).includes(scopedPath);
|
|
4255
4868
|
const blockVal = targetParsed.subPath ? getNestedValue(block, targetParsed.subPath) : void 0;
|
|
4256
|
-
const hasTargetAttr = blockVal !== void 0;
|
|
4869
|
+
const hasTargetAttr = componentSupports || blockVal !== void 0;
|
|
4257
4870
|
const isBlockChecked = hasTargetAttr && isSelected && (selectedDzBlocks[key] !== void 0 ? selectedDzBlocks[key].includes(bIdx) : true);
|
|
4258
4871
|
return /* @__PURE__ */ jsxs(
|
|
4259
4872
|
Tr,
|
|
@@ -4770,6 +5383,7 @@ const BulkUpdater = () => {
|
|
|
4770
5383
|
'"'
|
|
4771
5384
|
] }),
|
|
4772
5385
|
/* @__PURE__ */ jsxs(Flex, { gap: 1, alignItems: "center", marginTop: 1, children: [
|
|
5386
|
+
(batch.payload?.action === "csv_import" || batch.id?.startsWith("csv_")) && /* @__PURE__ */ jsx(Badge, { backgroundColor: "secondary100", textColor: "secondary700", children: "📊 CSV IMPORT" }),
|
|
4773
5387
|
/* @__PURE__ */ jsx(
|
|
4774
5388
|
Badge,
|
|
4775
5389
|
{
|
|
@@ -5521,4 +6135,4 @@ export {
|
|
|
5521
6135
|
getNestedValue,
|
|
5522
6136
|
parseDynamicZonePath
|
|
5523
6137
|
};
|
|
5524
|
-
//# sourceMappingURL=BulkUpdater-
|
|
6138
|
+
//# sourceMappingURL=BulkUpdater-CMkPdA9_.mjs.map
|