strapi-plugin-bulk-updater 1.4.2 → 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-D4v5fP-1.mjs → BulkUpdater-CMkPdA9_.mjs} +1365 -401
- package/dist/_chunks/BulkUpdater-CMkPdA9_.mjs.map +1 -0
- package/dist/_chunks/{BulkUpdater-L2FdlJfh.js → BulkUpdater-DtBH2c0-.js} +1361 -397
- 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 +1570 -643
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +1570 -643
- package/dist/server/index.mjs.map +1 -1
- package/package.json +3 -3
- package/dist/_chunks/BulkUpdater-D4v5fP-1.mjs.map +0 -1
- package/dist/_chunks/BulkUpdater-L2FdlJfh.js.map +0 -1
|
@@ -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(
|
|
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 [
|
|
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:
|
|
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
|
-
|
|
292
|
+
setAllParsedRecords(records);
|
|
293
|
+
setPreviewPage(1);
|
|
280
294
|
} catch (err) {
|
|
281
|
-
|
|
295
|
+
setAllParsedRecords([]);
|
|
282
296
|
}
|
|
283
297
|
};
|
|
284
298
|
reader.readAsText(file);
|
|
285
299
|
};
|
|
286
300
|
const handleExecuteImport = async () => {
|
|
287
|
-
if (!selectedUid ||
|
|
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
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
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
|
-
|
|
298
|
-
|
|
299
|
-
const
|
|
300
|
-
|
|
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.
|
|
323
|
-
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, {
|
|
324
|
-
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.
|
|
325
|
-
/* @__PURE__ */ jsxRuntime.
|
|
326
|
-
|
|
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.
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
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: "
|
|
502
|
+
variant: "tertiary",
|
|
371
503
|
startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Download, {}),
|
|
372
|
-
onClick:
|
|
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
|
-
|
|
382
|
-
|
|
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:
|
|
386
|
-
onChange: (val) =>
|
|
387
|
-
placeholder: "
|
|
388
|
-
children:
|
|
389
|
-
"
|
|
390
|
-
|
|
391
|
-
|
|
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.
|
|
527
|
+
) }),
|
|
528
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
395
529
|
designSystem.Button,
|
|
396
530
|
{
|
|
397
|
-
variant: "
|
|
531
|
+
variant: "default",
|
|
398
532
|
startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Download, {}),
|
|
399
|
-
onClick:
|
|
400
|
-
disabled: !
|
|
401
|
-
children:
|
|
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
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
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.
|
|
436
|
-
{
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
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
|
-
|
|
588
|
+
designSystem.Checkbox,
|
|
448
589
|
{
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
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
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
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.
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
missingDocIdCount > 0
|
|
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(
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
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.
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.
|
|
514
|
-
|
|
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
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
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
|
-
|
|
529
|
-
|
|
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
|
-
) },
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
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
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
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
|
-
|
|
549
|
-
|
|
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
|
-
|
|
581
|
-
"
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
"
|
|
586
|
-
|
|
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
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
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, {
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
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.
|
|
638
|
-
"
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
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)";
|
|
@@ -1603,9 +2190,75 @@ const BulkUpdatePreviewModal = ({
|
|
|
1603
2190
|
}
|
|
1604
2191
|
);
|
|
1605
2192
|
};
|
|
2193
|
+
function parseDynamicZonePath(path) {
|
|
2194
|
+
if (!path) return { cleanPath: "", rootKey: "", subPath: "" };
|
|
2195
|
+
const bracketMatch = path.match(/^([^.[]+)\[([^\]]+)\]\.(.+)$/);
|
|
2196
|
+
if (bracketMatch) {
|
|
2197
|
+
const rootKey = bracketMatch[1];
|
|
2198
|
+
const selector = bracketMatch[2];
|
|
2199
|
+
const subPath = bracketMatch[3];
|
|
2200
|
+
const cleanPath = `${rootKey}.${subPath}`;
|
|
2201
|
+
if (/^\d+$/.test(selector)) {
|
|
2202
|
+
return { cleanPath, rootKey, subPath, targetIndex: parseInt(selector, 10) };
|
|
2203
|
+
}
|
|
2204
|
+
return { cleanPath, rootKey, subPath, targetComponentUid: selector };
|
|
2205
|
+
}
|
|
2206
|
+
const parts = path.split(".");
|
|
2207
|
+
return {
|
|
2208
|
+
cleanPath: path,
|
|
2209
|
+
rootKey: parts[0] || "",
|
|
2210
|
+
subPath: parts.slice(1).join(".")
|
|
2211
|
+
};
|
|
2212
|
+
}
|
|
2213
|
+
function formatComponentName(compUid) {
|
|
2214
|
+
if (!compUid) return "Component";
|
|
2215
|
+
const name = compUid.includes(".") ? compUid.split(".")[1] : compUid;
|
|
2216
|
+
return name.split(/[-_]/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
2217
|
+
}
|
|
2218
|
+
function getAllNestedValues(obj, path, availableAttributes) {
|
|
2219
|
+
if (!obj || !path) return [];
|
|
2220
|
+
const parsed = parseDynamicZonePath(path);
|
|
2221
|
+
const parts = parsed.cleanPath.split(".");
|
|
2222
|
+
const [head, ...tail] = parts;
|
|
2223
|
+
const rootTarget = obj[head];
|
|
2224
|
+
if (Array.isArray(rootTarget)) {
|
|
2225
|
+
const results = [];
|
|
2226
|
+
rootTarget.forEach((item, idx) => {
|
|
2227
|
+
if (!item || typeof item !== "object") return;
|
|
2228
|
+
if (parsed.targetIndex !== void 0 && idx !== parsed.targetIndex) return;
|
|
2229
|
+
if (parsed.targetComponentUid && item.__component !== parsed.targetComponentUid) return;
|
|
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) {
|
|
2235
|
+
results.push({
|
|
2236
|
+
index: idx,
|
|
2237
|
+
componentUid: item.__component,
|
|
2238
|
+
componentName: formatComponentName(item.__component),
|
|
2239
|
+
value: subVal !== void 0 ? subVal : null,
|
|
2240
|
+
path: `${head}[#${idx}${item.__component ? ` ${formatComponentName(item.__component)}` : ""}].${subPath}`
|
|
2241
|
+
});
|
|
2242
|
+
}
|
|
2243
|
+
});
|
|
2244
|
+
return results;
|
|
2245
|
+
}
|
|
2246
|
+
const singleVal = getNestedValue(obj, parsed.cleanPath);
|
|
2247
|
+
if (singleVal !== void 0) {
|
|
2248
|
+
return [
|
|
2249
|
+
{
|
|
2250
|
+
index: 0,
|
|
2251
|
+
value: singleVal,
|
|
2252
|
+
path: parsed.cleanPath
|
|
2253
|
+
}
|
|
2254
|
+
];
|
|
2255
|
+
}
|
|
2256
|
+
return [];
|
|
2257
|
+
}
|
|
1606
2258
|
function getNestedValue(obj, path) {
|
|
1607
2259
|
if (!obj || !path) return void 0;
|
|
1608
|
-
const
|
|
2260
|
+
const parsed = parseDynamicZonePath(path);
|
|
2261
|
+
const parts = parsed.cleanPath.split(".");
|
|
1609
2262
|
function extract(current, remainingParts) {
|
|
1610
2263
|
if (current === void 0 || current === null) return void 0;
|
|
1611
2264
|
if (remainingParts.length === 0) return current;
|
|
@@ -1614,7 +2267,10 @@ function getNestedValue(obj, path) {
|
|
|
1614
2267
|
if (/^\d+$/.test(head)) {
|
|
1615
2268
|
return extract(current[parseInt(head, 10)], tail);
|
|
1616
2269
|
}
|
|
1617
|
-
for (
|
|
2270
|
+
for (let idx = 0; idx < current.length; idx++) {
|
|
2271
|
+
const item = current[idx];
|
|
2272
|
+
if (parsed.targetIndex !== void 0 && idx !== parsed.targetIndex) continue;
|
|
2273
|
+
if (parsed.targetComponentUid && item?.__component !== parsed.targetComponentUid) continue;
|
|
1618
2274
|
const found = extract(item?.[head], tail);
|
|
1619
2275
|
if (found !== void 0 && found !== null) return found;
|
|
1620
2276
|
}
|
|
@@ -1644,7 +2300,18 @@ function getAvailableColumnsForCollection(col, selectedAttribute, searchAttribut
|
|
|
1644
2300
|
if (attr === "name" || attr === "title" || attr === selectedAttribute || searchAttribute && attr === searchAttribute) {
|
|
1645
2301
|
return;
|
|
1646
2302
|
}
|
|
1647
|
-
|
|
2303
|
+
let formattedLabel = attr;
|
|
2304
|
+
const bracketMatch = attr.match(/^([^.[]+)\[([^\]]+)\]\.(.+)$/);
|
|
2305
|
+
if (bracketMatch) {
|
|
2306
|
+
const root = bracketMatch[1].charAt(0).toUpperCase() + bracketMatch[1].slice(1);
|
|
2307
|
+
const comp = formatComponentName(bracketMatch[2]);
|
|
2308
|
+
const sub = bracketMatch[3].split(".").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" > ");
|
|
2309
|
+
formattedLabel = `${root} [${comp}] > ${sub}`;
|
|
2310
|
+
} else if (attr.includes(".")) {
|
|
2311
|
+
formattedLabel = attr.split(".").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" > ");
|
|
2312
|
+
} else {
|
|
2313
|
+
formattedLabel = attr.charAt(0).toUpperCase() + attr.slice(1);
|
|
2314
|
+
}
|
|
1648
2315
|
cols.push({
|
|
1649
2316
|
key: `attr_${attr}`,
|
|
1650
2317
|
label: formattedLabel,
|
|
@@ -1653,7 +2320,16 @@ function getAvailableColumnsForCollection(col, selectedAttribute, searchAttribut
|
|
|
1653
2320
|
});
|
|
1654
2321
|
});
|
|
1655
2322
|
if (searchAttribute && searchAttribute !== selectedAttribute) {
|
|
1656
|
-
|
|
2323
|
+
let formattedSearchLabel = searchAttribute;
|
|
2324
|
+
const bracketMatch = searchAttribute.match(/^([^.[]+)\[([^\]]+)\]\.(.+)$/);
|
|
2325
|
+
if (bracketMatch) {
|
|
2326
|
+
const root = bracketMatch[1].charAt(0).toUpperCase() + bracketMatch[1].slice(1);
|
|
2327
|
+
const comp = formatComponentName(bracketMatch[2]);
|
|
2328
|
+
const sub = bracketMatch[3].split(".").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" > ");
|
|
2329
|
+
formattedSearchLabel = `${root} [${comp}] > ${sub}`;
|
|
2330
|
+
} else if (searchAttribute.includes(".")) {
|
|
2331
|
+
formattedSearchLabel = searchAttribute.split(".").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" > ");
|
|
2332
|
+
}
|
|
1657
2333
|
cols.push({
|
|
1658
2334
|
key: "search_attr",
|
|
1659
2335
|
label: `Search: "${formattedSearchLabel}"`,
|
|
@@ -1662,7 +2338,17 @@ function getAvailableColumnsForCollection(col, selectedAttribute, searchAttribut
|
|
|
1662
2338
|
});
|
|
1663
2339
|
}
|
|
1664
2340
|
if (selectedAttribute && selectedAttribute.trim()) {
|
|
1665
|
-
|
|
2341
|
+
let formattedTargetLabel = selectedAttribute;
|
|
2342
|
+
const bracketMatch = selectedAttribute.match(/^([^.[]+)\[([^\]]+)\]\.(.+)$/);
|
|
2343
|
+
if (bracketMatch) {
|
|
2344
|
+
const root = bracketMatch[1].charAt(0).toUpperCase() + bracketMatch[1].slice(1);
|
|
2345
|
+
const comp = formatComponentName(bracketMatch[2]);
|
|
2346
|
+
const sub = bracketMatch[3].split(".").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" > ");
|
|
2347
|
+
formattedTargetLabel = `${root} [${comp}] > ${sub}`;
|
|
2348
|
+
} else if (selectedAttribute.includes(".")) {
|
|
2349
|
+
formattedTargetLabel = selectedAttribute.split(".").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" > ");
|
|
2350
|
+
}
|
|
2351
|
+
const targetLabel = searchAttribute && searchAttribute !== selectedAttribute ? `Update Target: "${formattedTargetLabel}"` : `Current "${formattedTargetLabel}"`;
|
|
1666
2352
|
cols.push({
|
|
1667
2353
|
key: "target_attr",
|
|
1668
2354
|
label: targetLabel,
|
|
@@ -1787,7 +2473,7 @@ function getEntryLifecycleStatus(entry, col, pendingBatches = []) {
|
|
|
1787
2473
|
textColor: "neutral700"
|
|
1788
2474
|
};
|
|
1789
2475
|
}
|
|
1790
|
-
function renderCellContent(colDef, entry, col, selectedAttribute, searchAttribute, isMatch, hasAttr, isSelected, onToggleSelect, pendingBatches = []) {
|
|
2476
|
+
function renderCellContent(colDef, entry, col, selectedAttribute, searchAttribute, isMatch, hasAttr, isSelected, onToggleSelect, pendingBatches = [], isDzExpanded = false, onToggleExpandDz, filterQuery = "") {
|
|
1791
2477
|
switch (colDef.key) {
|
|
1792
2478
|
case "select":
|
|
1793
2479
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1799,51 +2485,162 @@ function renderCellContent(colDef, entry, col, selectedAttribute, searchAttribut
|
|
|
1799
2485
|
);
|
|
1800
2486
|
case "identifier": {
|
|
1801
2487
|
const mainText = entry.name || entry.title || `Entry #${entry.id || entry.documentId}`;
|
|
2488
|
+
const dzField = Object.keys(entry).find(
|
|
2489
|
+
(k) => Array.isArray(entry[k]) && entry[k].length > 0 && entry[k].some((item) => item && item.__component)
|
|
2490
|
+
);
|
|
2491
|
+
const dzItemsCount = dzField ? entry[dzField].length : 0;
|
|
1802
2492
|
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
|
|
1803
2493
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "semiBold", children: mainText }),
|
|
1804
|
-
entry.email && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral500", display: "block", children: entry.email })
|
|
2494
|
+
entry.email && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral500", display: "block", children: entry.email }),
|
|
2495
|
+
dzItemsCount > 0 && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2496
|
+
designSystem.Button,
|
|
2497
|
+
{
|
|
2498
|
+
variant: "ghost",
|
|
2499
|
+
size: "S",
|
|
2500
|
+
onClick: onToggleExpandDz,
|
|
2501
|
+
style: {
|
|
2502
|
+
padding: "2px 6px",
|
|
2503
|
+
height: "auto",
|
|
2504
|
+
fontSize: "0.72rem",
|
|
2505
|
+
color: isDzExpanded ? "#4945ff" : "#666687",
|
|
2506
|
+
backgroundColor: isDzExpanded ? "rgba(73, 69, 255, 0.08)" : "rgba(0, 0, 0, 0.04)",
|
|
2507
|
+
borderRadius: 4
|
|
2508
|
+
},
|
|
2509
|
+
children: isDzExpanded ? `▲ Hide ${dzField} (${dzItemsCount} blocks)` : `▼ View ${dzField} (${dzItemsCount} blocks)`
|
|
2510
|
+
}
|
|
2511
|
+
) })
|
|
1805
2512
|
] });
|
|
1806
2513
|
}
|
|
1807
2514
|
case "search_attr": {
|
|
1808
|
-
const
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
2515
|
+
const matches = getAllNestedValues(entry, searchAttribute, col?.attributes);
|
|
2516
|
+
if (matches.length === 0) {
|
|
2517
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral500", style: { fontStyle: "italic" }, children: "(empty / not set)" });
|
|
2518
|
+
}
|
|
2519
|
+
if (matches.length === 1 && !matches[0].componentUid) {
|
|
2520
|
+
const displayStr = formatDisplayValue(matches[0].value);
|
|
2521
|
+
const isUnset = displayStr === "(empty / not set)" || displayStr === "(empty / unlinked)";
|
|
2522
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2523
|
+
designSystem.Typography,
|
|
2524
|
+
{
|
|
2525
|
+
textColor: isUnset ? "neutral500" : "primary700",
|
|
2526
|
+
fontWeight: "semiBold",
|
|
2527
|
+
style: {
|
|
2528
|
+
fontStyle: isUnset ? "italic" : "normal",
|
|
2529
|
+
display: "inline-block",
|
|
2530
|
+
maxWidth: 260,
|
|
2531
|
+
overflow: "hidden",
|
|
2532
|
+
textOverflow: "ellipsis",
|
|
2533
|
+
whiteSpace: "nowrap"
|
|
2534
|
+
},
|
|
2535
|
+
children: displayStr
|
|
2536
|
+
}
|
|
2537
|
+
);
|
|
2538
|
+
}
|
|
2539
|
+
const qLower = (filterQuery || "").trim().toLowerCase();
|
|
2540
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", gap: 1, alignItems: "flex-start", style: { maxWidth: 320 }, children: matches.map((m) => {
|
|
2541
|
+
const displayStr = formatDisplayValue(m.value);
|
|
2542
|
+
const isMatchItem = qLower && displayStr.toLowerCase().includes(qLower);
|
|
2543
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2544
|
+
designSystem.Flex,
|
|
2545
|
+
{
|
|
2546
|
+
gap: 1,
|
|
2547
|
+
alignItems: "center",
|
|
2548
|
+
style: {
|
|
2549
|
+
backgroundColor: isMatchItem ? "rgba(46, 213, 115, 0.15)" : "rgba(0, 0, 0, 0.03)",
|
|
2550
|
+
padding: "2px 6px",
|
|
2551
|
+
borderRadius: 4,
|
|
2552
|
+
border: isMatchItem ? "1px solid #2ed573" : "1px solid transparent"
|
|
2553
|
+
},
|
|
2554
|
+
children: [
|
|
2555
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Badge, { size: "S", backgroundColor: isMatchItem ? "success100" : "primary100", textColor: isMatchItem ? "success700" : "primary700", children: [
|
|
2556
|
+
"#",
|
|
2557
|
+
m.index,
|
|
2558
|
+
" ",
|
|
2559
|
+
m.componentName
|
|
2560
|
+
] }),
|
|
2561
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2562
|
+
designSystem.Typography,
|
|
2563
|
+
{
|
|
2564
|
+
variant: "pi",
|
|
2565
|
+
fontWeight: isMatchItem ? "bold" : "normal",
|
|
2566
|
+
textColor: isMatchItem ? "success700" : "neutral800",
|
|
2567
|
+
style: {
|
|
2568
|
+
maxWidth: 200,
|
|
2569
|
+
overflow: "hidden",
|
|
2570
|
+
textOverflow: "ellipsis",
|
|
2571
|
+
whiteSpace: "nowrap"
|
|
2572
|
+
},
|
|
2573
|
+
children: displayStr
|
|
2574
|
+
}
|
|
2575
|
+
)
|
|
2576
|
+
]
|
|
1823
2577
|
},
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
);
|
|
2578
|
+
m.index
|
|
2579
|
+
);
|
|
2580
|
+
}) });
|
|
1827
2581
|
}
|
|
1828
2582
|
case "target_attr": {
|
|
1829
|
-
const
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
2583
|
+
const matches = getAllNestedValues(entry, selectedAttribute, col?.attributes);
|
|
2584
|
+
if (matches.length === 0) {
|
|
2585
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral500", style: { fontStyle: "italic" }, children: "(empty / not set)" });
|
|
2586
|
+
}
|
|
2587
|
+
if (matches.length === 1 && !matches[0].componentUid) {
|
|
2588
|
+
const displayStr = formatDisplayValue(matches[0].value);
|
|
2589
|
+
const isUnset = displayStr === "(empty / not set)" || displayStr === "(empty / unlinked)";
|
|
2590
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2591
|
+
designSystem.Typography,
|
|
2592
|
+
{
|
|
2593
|
+
textColor: isUnset ? "neutral500" : "neutral800",
|
|
2594
|
+
style: {
|
|
2595
|
+
fontStyle: isUnset ? "italic" : "normal",
|
|
2596
|
+
display: "inline-block",
|
|
2597
|
+
maxWidth: 260,
|
|
2598
|
+
overflow: "hidden",
|
|
2599
|
+
textOverflow: "ellipsis",
|
|
2600
|
+
whiteSpace: "nowrap"
|
|
2601
|
+
},
|
|
2602
|
+
children: displayStr
|
|
2603
|
+
}
|
|
2604
|
+
);
|
|
2605
|
+
}
|
|
2606
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", gap: 1, alignItems: "flex-start", style: { maxWidth: 320 }, children: matches.map((m) => {
|
|
2607
|
+
const displayStr = formatDisplayValue(m.value);
|
|
2608
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2609
|
+
designSystem.Flex,
|
|
2610
|
+
{
|
|
2611
|
+
gap: 1,
|
|
2612
|
+
alignItems: "center",
|
|
2613
|
+
style: {
|
|
2614
|
+
backgroundColor: "rgba(0, 0, 0, 0.03)",
|
|
2615
|
+
padding: "2px 6px",
|
|
2616
|
+
borderRadius: 4
|
|
2617
|
+
},
|
|
2618
|
+
children: [
|
|
2619
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Badge, { size: "S", backgroundColor: "neutral200", textColor: "neutral800", children: [
|
|
2620
|
+
"#",
|
|
2621
|
+
m.index,
|
|
2622
|
+
" ",
|
|
2623
|
+
m.componentName
|
|
2624
|
+
] }),
|
|
2625
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2626
|
+
designSystem.Typography,
|
|
2627
|
+
{
|
|
2628
|
+
variant: "pi",
|
|
2629
|
+
textColor: "neutral800",
|
|
2630
|
+
style: {
|
|
2631
|
+
maxWidth: 200,
|
|
2632
|
+
overflow: "hidden",
|
|
2633
|
+
textOverflow: "ellipsis",
|
|
2634
|
+
whiteSpace: "nowrap"
|
|
2635
|
+
},
|
|
2636
|
+
children: displayStr
|
|
2637
|
+
}
|
|
2638
|
+
)
|
|
2639
|
+
]
|
|
1843
2640
|
},
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
);
|
|
2641
|
+
m.index
|
|
2642
|
+
);
|
|
2643
|
+
}) });
|
|
1847
2644
|
}
|
|
1848
2645
|
case "status": {
|
|
1849
2646
|
if (selectedAttribute && !hasAttr) {
|
|
@@ -1940,6 +2737,8 @@ const BulkUpdater = () => {
|
|
|
1940
2737
|
const [selectedAttribute, setSelectedAttribute] = React.useState(getInitialAttribute);
|
|
1941
2738
|
const [attributeValue, setAttributeValue] = React.useState("");
|
|
1942
2739
|
const [selectedEntries, setSelectedEntries] = React.useState({});
|
|
2740
|
+
const [expandedDzEntries, setExpandedDzEntries] = React.useState({});
|
|
2741
|
+
const [selectedDzBlocks, setSelectedDzBlocks] = React.useState({});
|
|
1943
2742
|
const [relationsMeta, setRelationsMeta] = React.useState({});
|
|
1944
2743
|
const [relationOptions, setRelationOptions] = React.useState([]);
|
|
1945
2744
|
const [relationOptionsLoading, setRelationOptionsLoading] = React.useState(false);
|
|
@@ -2482,40 +3281,78 @@ const BulkUpdater = () => {
|
|
|
2482
3281
|
};
|
|
2483
3282
|
const toggleEntry = (uid, documentId) => {
|
|
2484
3283
|
const key = `${uid}${KEY_SEP}${documentId}`;
|
|
3284
|
+
const nextVal = !selectedEntries[key];
|
|
2485
3285
|
setSelectedEntries((prev) => ({
|
|
2486
3286
|
...prev,
|
|
2487
|
-
[key]:
|
|
3287
|
+
[key]: nextVal
|
|
2488
3288
|
}));
|
|
3289
|
+
if (!nextVal) {
|
|
3290
|
+
setSelectedDzBlocks((prev) => {
|
|
3291
|
+
const copy = { ...prev };
|
|
3292
|
+
delete copy[key];
|
|
3293
|
+
return copy;
|
|
3294
|
+
});
|
|
3295
|
+
}
|
|
3296
|
+
};
|
|
3297
|
+
const toggleDzBlock = (uid, documentId, blockIndex, allApplicableIndexes) => {
|
|
3298
|
+
const key = `${uid}${KEY_SEP}${documentId}`;
|
|
3299
|
+
setSelectedDzBlocks((prev) => {
|
|
3300
|
+
const currentSelected = prev[key] !== void 0 ? prev[key] : [...allApplicableIndexes];
|
|
3301
|
+
let nextSelected;
|
|
3302
|
+
if (currentSelected.includes(blockIndex)) {
|
|
3303
|
+
nextSelected = currentSelected.filter((idx) => idx !== blockIndex);
|
|
3304
|
+
} else {
|
|
3305
|
+
nextSelected = [...currentSelected, blockIndex];
|
|
3306
|
+
}
|
|
3307
|
+
if (nextSelected.length > 0) {
|
|
3308
|
+
setSelectedEntries((e) => ({ ...e, [key]: true }));
|
|
3309
|
+
} else {
|
|
3310
|
+
setSelectedEntries((e) => ({ ...e, [key]: false }));
|
|
3311
|
+
}
|
|
3312
|
+
return {
|
|
3313
|
+
...prev,
|
|
3314
|
+
[key]: nextSelected
|
|
3315
|
+
};
|
|
3316
|
+
});
|
|
2489
3317
|
};
|
|
2490
3318
|
const entryMatchesFilter = (entry, attr) => {
|
|
3319
|
+
const matches = getAllNestedValues(entry, attr);
|
|
2491
3320
|
if (useRegex && regexPattern.trim()) {
|
|
2492
3321
|
try {
|
|
2493
3322
|
const regex = new RegExp(regexPattern, "i");
|
|
2494
|
-
const
|
|
2495
|
-
if (!
|
|
3323
|
+
const anyRegexMatch = matches.some((m) => regex.test(formatDisplayValue(m.value)));
|
|
3324
|
+
if (!anyRegexMatch) {
|
|
2496
3325
|
return false;
|
|
2497
3326
|
}
|
|
2498
3327
|
} catch {
|
|
2499
3328
|
}
|
|
2500
3329
|
}
|
|
2501
3330
|
if (filterOperator === "none") return true;
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
const isValEmpty = val === void 0 || val === null || displayStr.trim() === "" || displayStr.trim().toLowerCase() === "(not set)" || displayStr.trim().toLowerCase() === "(empty / not set)" || displayStr.trim().toLowerCase() === "(empty / unlinked)";
|
|
2505
|
-
switch (filterOperator) {
|
|
2506
|
-
case "empty":
|
|
2507
|
-
return isValEmpty;
|
|
2508
|
-
case "not_empty":
|
|
2509
|
-
return !isValEmpty;
|
|
2510
|
-
case "equals":
|
|
2511
|
-
return !isValEmpty && displayStr.trim().toLowerCase() === filterQuery.trim().toLowerCase();
|
|
2512
|
-
case "contains":
|
|
2513
|
-
return !isValEmpty && displayStr.toLowerCase().includes(filterQuery.trim().toLowerCase());
|
|
2514
|
-
case "starts_with":
|
|
2515
|
-
return !isValEmpty && displayStr.trim().toLowerCase().startsWith(filterQuery.trim().toLowerCase());
|
|
2516
|
-
default:
|
|
2517
|
-
return true;
|
|
3331
|
+
if (matches.length === 0) {
|
|
3332
|
+
return filterOperator === "empty";
|
|
2518
3333
|
}
|
|
3334
|
+
const checkMatch = (val) => {
|
|
3335
|
+
const displayStr = formatDisplayValue(val);
|
|
3336
|
+
const isValEmpty = val === void 0 || val === null || displayStr.trim() === "" || displayStr.trim().toLowerCase() === "(not set)" || displayStr.trim().toLowerCase() === "(empty / not set)" || displayStr.trim().toLowerCase() === "(empty / unlinked)";
|
|
3337
|
+
switch (filterOperator) {
|
|
3338
|
+
case "empty":
|
|
3339
|
+
return isValEmpty;
|
|
3340
|
+
case "not_empty":
|
|
3341
|
+
return !isValEmpty;
|
|
3342
|
+
case "equals":
|
|
3343
|
+
return !isValEmpty && displayStr.trim().toLowerCase() === filterQuery.trim().toLowerCase();
|
|
3344
|
+
case "contains":
|
|
3345
|
+
return !isValEmpty && displayStr.toLowerCase().includes(filterQuery.trim().toLowerCase());
|
|
3346
|
+
case "starts_with":
|
|
3347
|
+
return !isValEmpty && displayStr.trim().toLowerCase().startsWith(filterQuery.trim().toLowerCase());
|
|
3348
|
+
default:
|
|
3349
|
+
return true;
|
|
3350
|
+
}
|
|
3351
|
+
};
|
|
3352
|
+
if (filterOperator === "empty") {
|
|
3353
|
+
return matches.every((m) => checkMatch(m.value));
|
|
3354
|
+
}
|
|
3355
|
+
return matches.some((m) => checkMatch(m.value));
|
|
2519
3356
|
};
|
|
2520
3357
|
const getVisibleEntries = (col) => {
|
|
2521
3358
|
const pageState = collectionPages[col.uid];
|
|
@@ -2653,7 +3490,11 @@ const BulkUpdater = () => {
|
|
|
2653
3490
|
if (selectedEntries[key]) {
|
|
2654
3491
|
const parts = key.split(KEY_SEP);
|
|
2655
3492
|
if (parts.length === 2) {
|
|
2656
|
-
|
|
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);
|
|
2657
3498
|
}
|
|
2658
3499
|
}
|
|
2659
3500
|
});
|
|
@@ -2698,7 +3539,11 @@ const BulkUpdater = () => {
|
|
|
2698
3539
|
if (selectedEntries[key]) {
|
|
2699
3540
|
const parts = key.split(KEY_SEP);
|
|
2700
3541
|
if (parts.length === 2) {
|
|
2701
|
-
|
|
3542
|
+
const targetObj = { uid: parts[0], documentId: parts[1] };
|
|
3543
|
+
if (selectedDzBlocks[key] && selectedDzBlocks[key].length > 0) {
|
|
3544
|
+
targetObj.dynamicZoneIndexes = selectedDzBlocks[key];
|
|
3545
|
+
}
|
|
3546
|
+
targets.push(targetObj);
|
|
2702
3547
|
}
|
|
2703
3548
|
}
|
|
2704
3549
|
});
|
|
@@ -2741,6 +3586,7 @@ const BulkUpdater = () => {
|
|
|
2741
3586
|
setIsSubmittingBatch(false);
|
|
2742
3587
|
if (res.data && res.data.success) {
|
|
2743
3588
|
setSelectedEntries({});
|
|
3589
|
+
setSelectedDzBlocks({});
|
|
2744
3590
|
const finalBatchId = res.data.batchId;
|
|
2745
3591
|
setDashboardBatchId(finalBatchId);
|
|
2746
3592
|
if (res.data.pending) {
|
|
@@ -2798,6 +3644,20 @@ const BulkUpdater = () => {
|
|
|
2798
3644
|
});
|
|
2799
3645
|
await fetchModels();
|
|
2800
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
|
+
}
|
|
2801
3661
|
}
|
|
2802
3662
|
} else {
|
|
2803
3663
|
setIsSubmittingBatch(false);
|
|
@@ -3928,28 +4788,128 @@ const BulkUpdater = () => {
|
|
|
3928
4788
|
const key = `${col.uid}${KEY_SEP}${entry.documentId}`;
|
|
3929
4789
|
const isSelected = Boolean(selectedEntries[key]);
|
|
3930
4790
|
const isMatch = isFilterActive;
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
children: activeColumns.map((colDef) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: renderCellContent(
|
|
3939
|
-
colDef,
|
|
3940
|
-
entry,
|
|
3941
|
-
col,
|
|
3942
|
-
selectedAttribute,
|
|
3943
|
-
searchAttribute,
|
|
3944
|
-
isMatch,
|
|
3945
|
-
hasAttr,
|
|
3946
|
-
isSelected,
|
|
3947
|
-
() => toggleEntry(col.uid, entry.documentId),
|
|
3948
|
-
pendingBatches
|
|
3949
|
-
) }, colDef.key))
|
|
3950
|
-
},
|
|
3951
|
-
key
|
|
4791
|
+
const isDzExpanded = Boolean(expandedDzEntries[key]);
|
|
4792
|
+
const onToggleExpandDz = () => setExpandedDzEntries((prev) => ({
|
|
4793
|
+
...prev,
|
|
4794
|
+
[key]: !prev[key]
|
|
4795
|
+
}));
|
|
4796
|
+
const dzFields = Object.keys(entry).filter(
|
|
4797
|
+
(k) => Array.isArray(entry[k]) && entry[k].length > 0 && entry[k].some((item) => item && item.__component)
|
|
3952
4798
|
);
|
|
4799
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(React__default.default.Fragment, { children: [
|
|
4800
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4801
|
+
designSystem.Tr,
|
|
4802
|
+
{
|
|
4803
|
+
style: {
|
|
4804
|
+
backgroundColor: isSelected ? "rgba(73, 69, 255, 0.14)" : isMatch ? "rgba(46, 213, 115, 0.08)" : void 0,
|
|
4805
|
+
boxShadow: isSelected ? "inset 3px 0 0 0 #4945ff" : isMatch ? "inset 3px 0 0 0 #2ed573" : void 0
|
|
4806
|
+
},
|
|
4807
|
+
children: activeColumns.map((colDef) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: renderCellContent(
|
|
4808
|
+
colDef,
|
|
4809
|
+
entry,
|
|
4810
|
+
col,
|
|
4811
|
+
selectedAttribute,
|
|
4812
|
+
searchAttribute,
|
|
4813
|
+
isMatch,
|
|
4814
|
+
hasAttr,
|
|
4815
|
+
isSelected,
|
|
4816
|
+
() => toggleEntry(col.uid, entry.documentId),
|
|
4817
|
+
pendingBatches,
|
|
4818
|
+
isDzExpanded,
|
|
4819
|
+
onToggleExpandDz,
|
|
4820
|
+
filterQuery
|
|
4821
|
+
) }, colDef.key))
|
|
4822
|
+
}
|
|
4823
|
+
),
|
|
4824
|
+
isDzExpanded && dzFields.map((dzKey) => {
|
|
4825
|
+
const blocks = entry[dzKey] || [];
|
|
4826
|
+
const targetParsed = parseDynamicZonePath(selectedAttribute);
|
|
4827
|
+
const isBlockApplicable = (blockItem) => {
|
|
4828
|
+
if (!targetParsed.subPath) return true;
|
|
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]));
|
|
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(
|
|
4835
|
+
designSystem.Box,
|
|
4836
|
+
{
|
|
4837
|
+
padding: 3,
|
|
4838
|
+
background: "neutral0",
|
|
4839
|
+
hasRadius: true,
|
|
4840
|
+
style: { border: "1px solid rgba(73, 69, 255, 0.25)", boxShadow: "0 2px 8px rgba(0,0,0,0.05)" },
|
|
4841
|
+
children: [
|
|
4842
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 2, children: [
|
|
4843
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", children: [
|
|
4844
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "sigma", textColor: "primary700", children: [
|
|
4845
|
+
'DYNAMIC ZONE: "',
|
|
4846
|
+
dzKey,
|
|
4847
|
+
'" (',
|
|
4848
|
+
blocks.length,
|
|
4849
|
+
" blocks)"
|
|
4850
|
+
] }),
|
|
4851
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: "primary100", textColor: "primary700", children: "Selective Block Targeting" })
|
|
4852
|
+
] }),
|
|
4853
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral500", children: "Selectively choose which blocks to update for this entry" })
|
|
4854
|
+
] }),
|
|
4855
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Table, { colCount: 5, rowCount: blocks.length + 1, style: { width: "100%", background: "#fff" }, children: [
|
|
4856
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Thead, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
|
|
4857
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { style: { width: 64 }, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Update?" }) }),
|
|
4858
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { style: { width: 60 }, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Pos" }) }),
|
|
4859
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { style: { width: 220 }, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Component" }) }),
|
|
4860
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "sigma", children: [
|
|
4861
|
+
"Target Field Value (",
|
|
4862
|
+
selectedAttribute || "selected",
|
|
4863
|
+
")"
|
|
4864
|
+
] }) }),
|
|
4865
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Block Summary" }) })
|
|
4866
|
+
] }) }),
|
|
4867
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Tbody, { children: blocks.map((block, bIdx) => {
|
|
4868
|
+
const compUid = block.__component;
|
|
4869
|
+
const compLabel = formatComponentName(compUid);
|
|
4870
|
+
const scopedPath = `${dzKey}[${compUid}].${targetParsed.subPath}`;
|
|
4871
|
+
const componentSupports = (col?.attributes || attributes || []).includes(scopedPath);
|
|
4872
|
+
const blockVal = targetParsed.subPath ? getNestedValue(block, targetParsed.subPath) : void 0;
|
|
4873
|
+
const hasTargetAttr = componentSupports || blockVal !== void 0;
|
|
4874
|
+
const isBlockChecked = hasTargetAttr && isSelected && (selectedDzBlocks[key] !== void 0 ? selectedDzBlocks[key].includes(bIdx) : true);
|
|
4875
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4876
|
+
designSystem.Tr,
|
|
4877
|
+
{
|
|
4878
|
+
style: {
|
|
4879
|
+
backgroundColor: isBlockChecked ? "rgba(73, 69, 255, 0.08)" : void 0
|
|
4880
|
+
},
|
|
4881
|
+
children: [
|
|
4882
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4883
|
+
designSystem.Checkbox,
|
|
4884
|
+
{
|
|
4885
|
+
checked: isBlockChecked,
|
|
4886
|
+
disabled: !hasTargetAttr,
|
|
4887
|
+
onCheckedChange: () => {
|
|
4888
|
+
toggleDzBlock(col.uid, entry.documentId, bIdx, allApplicableIndexes);
|
|
4889
|
+
}
|
|
4890
|
+
}
|
|
4891
|
+
) }),
|
|
4892
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "pi", fontWeight: "bold", children: [
|
|
4893
|
+
"#",
|
|
4894
|
+
bIdx
|
|
4895
|
+
] }) }),
|
|
4896
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Td, { children: [
|
|
4897
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: "neutral150", textColor: "neutral800", children: compLabel }),
|
|
4898
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral500", display: "block", style: { fontSize: "0.68rem", marginTop: 2 }, children: compUid })
|
|
4899
|
+
] }),
|
|
4900
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: hasTargetAttr ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "semiBold", textColor: "primary700", children: formatDisplayValue(blockVal) }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: "neutral100", textColor: "neutral500", children: "Does not contain attribute" }) }),
|
|
4901
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", style: { maxWidth: 300, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: block.title || block.name || block.heading || block.body || Object.keys(block).filter((k) => !k.startsWith("_") && k !== "id").slice(0, 3).map((k) => `${k}: ${formatDisplayValue(block[k])}`).join(", ") || "-" }) })
|
|
4902
|
+
]
|
|
4903
|
+
},
|
|
4904
|
+
bIdx
|
|
4905
|
+
);
|
|
4906
|
+
}) })
|
|
4907
|
+
] })
|
|
4908
|
+
]
|
|
4909
|
+
}
|
|
4910
|
+
) }) }, `${key}-dz-${dzKey}`);
|
|
4911
|
+
})
|
|
4912
|
+
] }, key);
|
|
3953
4913
|
}) })
|
|
3954
4914
|
] }) }),
|
|
3955
4915
|
!col.isSingleType && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", marginTop: 4, wrap: "wrap", gap: 3, children: [
|
|
@@ -4427,6 +5387,7 @@ const BulkUpdater = () => {
|
|
|
4427
5387
|
'"'
|
|
4428
5388
|
] }),
|
|
4429
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" }),
|
|
4430
5391
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4431
5392
|
designSystem.Badge,
|
|
4432
5393
|
{
|
|
@@ -5169,8 +6130,11 @@ const BulkUpdater = () => {
|
|
|
5169
6130
|
);
|
|
5170
6131
|
};
|
|
5171
6132
|
exports.default = BulkUpdater;
|
|
6133
|
+
exports.formatComponentName = formatComponentName;
|
|
5172
6134
|
exports.formatDisplayValue = formatDisplayValue;
|
|
6135
|
+
exports.getAllNestedValues = getAllNestedValues;
|
|
5173
6136
|
exports.getAvailableColumnsForCollection = getAvailableColumnsForCollection;
|
|
5174
6137
|
exports.getEntryLifecycleStatus = getEntryLifecycleStatus;
|
|
5175
6138
|
exports.getNestedValue = getNestedValue;
|
|
5176
|
-
|
|
6139
|
+
exports.parseDynamicZonePath = parseDynamicZonePath;
|
|
6140
|
+
//# sourceMappingURL=BulkUpdater-DtBH2c0-.js.map
|