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