strapi-plugin-bulk-updater 1.4.9 → 1.5.0

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.
@@ -1,7 +1,7 @@
1
1
  import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
2
  import React__default, { useState, useEffect, useMemo, useRef } from "react";
3
3
  import { useFetchClient, useNotification } from "@strapi/strapi/admin";
4
- import { Box, Flex, Typography, Button, SingleSelect, SingleSelectOption, Badge, Checkbox, Alert, Table, Thead, Tr, Th, Tbody, Td, TextInput, Loader, ComboboxOption, Field, Combobox } from "@strapi/design-system";
4
+ import { Box, Flex, Typography, Button, Combobox, ComboboxOption, SingleSelect, SingleSelectOption, Badge, Checkbox, Alert, Table, Thead, Tr, Th, Tbody, Td, TextInput, Loader, Field } from "@strapi/design-system";
5
5
  import { ArrowClockwise, Download, Upload, ChevronLeft, ChevronRight, Eye, Check, Cog, Play } from "@strapi/icons";
6
6
  import { i as isAbortError, V as ValidationRulesTab } from "./ValidationRulesTab-BtOCWK8E.mjs";
7
7
  function parseCsvRows(csvText) {
@@ -162,8 +162,8 @@ function CsvManagerTab() {
162
162
  const [showConfirmModal, setShowConfirmModal] = useState(false);
163
163
  const [makerNotesInput, setMakerNotesInput] = useState("");
164
164
  const [submittingBatch, setSubmittingBatch] = useState(false);
165
- const [publishStrategy, setPublishStrategy] = useState("safe");
166
- const [unreviewedConsent, setUnreviewedConsent] = useState(false);
165
+ const [publishStrategy, setPublishStrategy] = useState("all");
166
+ const [unreviewedConsent, setUnreviewedConsent] = useState(true);
167
167
  useEffect(() => {
168
168
  fetchInitialData();
169
169
  }, []);
@@ -480,23 +480,36 @@ function CsvManagerTab() {
480
480
  /* @__PURE__ */ jsxs(Box, { style: { flex: 1 }, children: [
481
481
  /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", marginBottom: 2, children: "Target Collection Type" }),
482
482
  /* @__PURE__ */ jsx(
483
- SingleSelect,
483
+ Combobox,
484
484
  {
485
- value: selectedUid,
486
- onChange: (val) => {
487
- setSelectedUid(val);
485
+ value: selectedUid || void 0,
486
+ autocomplete: { type: "list", filter: "contains" },
487
+ placeholder: "Search & select a collection...",
488
+ disabled: loadingCollections,
489
+ clearLabel: "Clear collection selection",
490
+ onClear: () => {
491
+ setSelectedUid("");
488
492
  setImportResult(null);
489
493
  setImportProgress(null);
490
494
  },
491
- disabled: loadingCollections,
492
- placeholder: "Select a collection...",
493
- children: collections.map((col) => /* @__PURE__ */ jsxs(SingleSelectOption, { value: col.uid, children: [
495
+ onFocus: (e) => {
496
+ e.target.select();
497
+ },
498
+ onChange: (val) => {
499
+ if (val && typeof val === "string") {
500
+ setSelectedUid(val);
501
+ setImportResult(null);
502
+ setImportProgress(null);
503
+ }
504
+ },
505
+ children: collections.map((col) => /* @__PURE__ */ jsxs(ComboboxOption, { value: col.uid, textValue: `${col.displayName} (${col.uid})`, children: [
494
506
  col.displayName,
495
507
  " (",
496
508
  col.totalEntries ?? 0,
497
509
  " records)"
498
510
  ] }, col.uid))
499
- }
511
+ },
512
+ `csv-col-${selectedUid}`
500
513
  )
501
514
  ] }),
502
515
  /* @__PURE__ */ jsx(
@@ -591,7 +604,13 @@ function CsvManagerTab() {
591
604
  Checkbox,
592
605
  {
593
606
  checked: publishOnImport,
594
- onValueChange: (val) => setPublishOnImport(val),
607
+ onValueChange: (val) => {
608
+ setPublishOnImport(val);
609
+ if (val) {
610
+ setPublishStrategy("all");
611
+ setUnreviewedConsent(true);
612
+ }
613
+ },
595
614
  children: "Auto-publish on import"
596
615
  }
597
616
  )
@@ -854,8 +873,13 @@ function CsvManagerTab() {
854
873
  size: "L",
855
874
  startIcon: /* @__PURE__ */ jsx(Check, {}),
856
875
  onClick: () => {
857
- setPublishStrategy("safe");
858
- setUnreviewedConsent(false);
876
+ if (publishOnImport) {
877
+ setPublishStrategy("all");
878
+ setUnreviewedConsent(true);
879
+ } else {
880
+ setPublishStrategy("safe");
881
+ setUnreviewedConsent(false);
882
+ }
859
883
  setShowConfirmModal(true);
860
884
  },
861
885
  loading: importing || submittingBatch,
@@ -1178,7 +1202,7 @@ function CsvManagerTab() {
1178
1202
  ] })
1179
1203
  }
1180
1204
  ),
1181
- publishOnImport && (preflightReport?.lifecycleStats?.unreviewedCount ?? 0) > 0 && /* @__PURE__ */ jsxs(
1205
+ publishOnImport && /* @__PURE__ */ jsxs(
1182
1206
  Box,
1183
1207
  {
1184
1208
  padding: 4,
@@ -1187,7 +1211,7 @@ function CsvManagerTab() {
1187
1211
  marginBottom: 4,
1188
1212
  style: { border: "1px solid #d9d8ff" },
1189
1213
  children: [
1190
- /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", marginBottom: 3, display: "block", children: "PUBLISHING STRATEGY & GOVERNANCE CONSENT" }),
1214
+ /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", marginBottom: 3, display: "block", children: "PUBLISHING STRATEGY & GOVERNANCE" }),
1191
1215
  /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 3, children: [
1192
1216
  /* @__PURE__ */ jsx(
1193
1217
  Box,
@@ -1195,40 +1219,32 @@ function CsvManagerTab() {
1195
1219
  padding: 3,
1196
1220
  hasRadius: true,
1197
1221
  style: {
1198
- border: publishStrategy === "safe" ? "2px solid #4945ff" : "1px solid #eaeaef",
1199
- backgroundColor: publishStrategy === "safe" ? "#f0f0ff" : "#ffffff",
1222
+ border: publishStrategy === "all" ? "2px solid #4945ff" : "1px solid #eaeaef",
1223
+ backgroundColor: publishStrategy === "all" ? "#f0f0ff" : "#ffffff",
1200
1224
  cursor: "pointer"
1201
1225
  },
1202
1226
  onClick: () => {
1203
- setPublishStrategy("safe");
1204
- setUnreviewedConsent(false);
1227
+ setPublishStrategy("all");
1228
+ setUnreviewedConsent(true);
1205
1229
  },
1206
1230
  children: /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "flex-start", children: [
1207
1231
  /* @__PURE__ */ jsx(
1208
1232
  "input",
1209
1233
  {
1210
1234
  type: "radio",
1211
- id: "csv-strategy-safe",
1235
+ id: "csv-strategy-all",
1212
1236
  name: "csvPublishStrategy",
1213
- checked: publishStrategy === "safe",
1237
+ checked: publishStrategy === "all",
1214
1238
  onChange: () => {
1215
- setPublishStrategy("safe");
1216
- setUnreviewedConsent(false);
1239
+ setPublishStrategy("all");
1240
+ setUnreviewedConsent(true);
1217
1241
  },
1218
1242
  style: { marginTop: 3 }
1219
1243
  }
1220
1244
  ),
1221
1245
  /* @__PURE__ */ jsxs(Box, { children: [
1222
- /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", display: "block", children: "🛡️ Safe Publishing (Recommended)" }),
1223
- /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", children: [
1224
- "Only publish records that are already approved & live (",
1225
- preflightReport?.lifecycleStats?.published ?? 0,
1226
- " record",
1227
- (preflightReport?.lifecycleStats?.published ?? 0) === 1 ? "" : "s",
1228
- "). The ",
1229
- preflightReport?.lifecycleStats?.unreviewedCount ?? 0,
1230
- " unreviewed or draft record(s) will receive the CSV update in Draft mode without publishing unreviewed draft revisions to visitors."
1231
- ] })
1246
+ /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", textColor: "primary700", display: "block", children: "🚀 Publish All Imported Records Live (Immediate)" }),
1247
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Publish all affected records live to production immediately upon import execution." })
1232
1248
  ] })
1233
1249
  ] })
1234
1250
  }
@@ -1239,56 +1255,32 @@ function CsvManagerTab() {
1239
1255
  padding: 3,
1240
1256
  hasRadius: true,
1241
1257
  style: {
1242
- border: publishStrategy === "all" ? "2px solid #d02b20" : "1px solid #eaeaef",
1243
- backgroundColor: publishStrategy === "all" ? "#fff5f5" : "#ffffff",
1258
+ border: publishStrategy === "safe" ? "2px solid #4945ff" : "1px solid #eaeaef",
1259
+ backgroundColor: publishStrategy === "safe" ? "#f0f0ff" : "#ffffff",
1244
1260
  cursor: "pointer"
1245
1261
  },
1246
- onClick: () => setPublishStrategy("all"),
1262
+ onClick: () => {
1263
+ setPublishStrategy("safe");
1264
+ setUnreviewedConsent(false);
1265
+ },
1247
1266
  children: /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "flex-start", children: [
1248
1267
  /* @__PURE__ */ jsx(
1249
1268
  "input",
1250
1269
  {
1251
1270
  type: "radio",
1252
- id: "csv-strategy-all",
1271
+ id: "csv-strategy-safe",
1253
1272
  name: "csvPublishStrategy",
1254
- checked: publishStrategy === "all",
1255
- onChange: () => setPublishStrategy("all"),
1273
+ checked: publishStrategy === "safe",
1274
+ onChange: () => {
1275
+ setPublishStrategy("safe");
1276
+ setUnreviewedConsent(false);
1277
+ },
1256
1278
  style: { marginTop: 3 }
1257
1279
  }
1258
1280
  ),
1259
1281
  /* @__PURE__ */ jsxs(Box, { children: [
1260
- /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", textColor: "danger700", display: "block", children: "⚠️ Publish All Imported Records (Includes Unreviewed Drafts)" }),
1261
- /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", children: [
1262
- "Publish all affected records live to production immediately, pushing all pending unreviewed draft edits in the ",
1263
- preflightReport?.lifecycleStats?.unreviewedCount ?? 0,
1264
- " draft/modified record(s) live."
1265
- ] })
1266
- ] })
1267
- ] })
1268
- }
1269
- ),
1270
- publishStrategy === "all" && /* @__PURE__ */ jsx(
1271
- Box,
1272
- {
1273
- padding: 3,
1274
- background: "danger100",
1275
- hasRadius: true,
1276
- style: { border: "1px solid #f5c0b8" },
1277
- children: /* @__PURE__ */ jsxs(Flex, { gap: 3, alignItems: "flex-start", children: [
1278
- /* @__PURE__ */ jsx(
1279
- Checkbox,
1280
- {
1281
- checked: unreviewedConsent,
1282
- onValueChange: (checked) => setUnreviewedConsent(Boolean(checked))
1283
- }
1284
- ),
1285
- /* @__PURE__ */ jsxs(Box, { style: { cursor: "pointer" }, onClick: () => setUnreviewedConsent(!unreviewedConsent), children: [
1286
- /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", textColor: "danger700", display: "block", children: "Mandatory Risk Consent Required" }),
1287
- /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "danger700", children: [
1288
- "I understand and explicitly consent that ",
1289
- preflightReport?.lifecycleStats?.unreviewedCount ?? 0,
1290
- " record(s) with unreviewed draft revisions or saved draft states will be published live to production visitors."
1291
- ] })
1282
+ /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", display: "block", children: "🛡️ Safe Publishing (Only Publish Pre-Approved Live Records)" }),
1283
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Only publish records that are already approved & live. Any unreviewed or draft records will receive the CSV update in Draft mode without publishing to visitors." })
1292
1284
  ] })
1293
1285
  ] })
1294
1286
  }
@@ -2356,6 +2348,511 @@ const BulkUpdatePreviewModal = ({
2356
2348
  }
2357
2349
  );
2358
2350
  };
2351
+ const CheckerReviewModal = ({
2352
+ isOpen,
2353
+ onClose,
2354
+ batch,
2355
+ onApprove,
2356
+ onReject,
2357
+ approving,
2358
+ rejecting
2359
+ }) => {
2360
+ const { get } = useFetchClient();
2361
+ const { toggleNotification } = useNotification();
2362
+ const [loading, setLoading] = useState(false);
2363
+ const [error, setError] = useState(null);
2364
+ const [diffs, setDiffs] = useState([]);
2365
+ const [summary, setSummary] = useState({
2366
+ total: 0,
2367
+ willUpdate: 0,
2368
+ willCreate: 0,
2369
+ unchanged: 0,
2370
+ skipped: 0
2371
+ });
2372
+ const [filterTab, setFilterTab] = useState("all");
2373
+ const [searchQuery, setSearchQuery] = useState("");
2374
+ const [isExporting, setIsExporting] = useState(false);
2375
+ const [showRejectInput, setShowRejectInput] = useState(false);
2376
+ const [rejectionReason, setRejectionReason] = useState("");
2377
+ const fetchBatchDiffs = async () => {
2378
+ if (!batch || !batch.id) return;
2379
+ try {
2380
+ setLoading(true);
2381
+ setError(null);
2382
+ const res = await get(`/bulk-updater/batches/${batch.id}/diffs`);
2383
+ if (res.data && res.data.success) {
2384
+ setDiffs(res.data.diffs || []);
2385
+ setSummary({
2386
+ total: res.data.summary?.total ?? res.data.diffs?.length ?? 0,
2387
+ willUpdate: res.data.summary?.willUpdate ?? 0,
2388
+ willCreate: res.data.summary?.willCreate ?? 0,
2389
+ unchanged: res.data.summary?.unchanged ?? 0,
2390
+ skipped: res.data.summary?.skipped ?? 0
2391
+ });
2392
+ } else {
2393
+ setError(res.data?.error || "Failed to inspect pending batch changes.");
2394
+ }
2395
+ } catch (err) {
2396
+ setError(err.message || "An error occurred while fetching batch diffs.");
2397
+ } finally {
2398
+ setLoading(false);
2399
+ }
2400
+ };
2401
+ useEffect(() => {
2402
+ if (isOpen && batch) {
2403
+ setShowRejectInput(false);
2404
+ setRejectionReason("");
2405
+ setFilterTab("all");
2406
+ setSearchQuery("");
2407
+ fetchBatchDiffs();
2408
+ }
2409
+ }, [isOpen, batch?.id]);
2410
+ const handleExportCsv = async () => {
2411
+ if (!batch || !batch.id) return;
2412
+ try {
2413
+ setIsExporting(true);
2414
+ const res = await get(`/bulk-updater/batches/${batch.id}/diffs/export`);
2415
+ if (res.data && res.data.success && res.data.csvContent) {
2416
+ const safeContent = res.data.csvContent.startsWith("\uFEFF") ? res.data.csvContent : "\uFEFF" + res.data.csvContent;
2417
+ const blob = new Blob([safeContent], { type: "text/csv;charset=utf-8;" });
2418
+ const url = URL.createObjectURL(blob);
2419
+ const link = document.createElement("a");
2420
+ link.href = url;
2421
+ link.setAttribute("download", res.data.filename || `batch_${batch.id}_review.csv`);
2422
+ document.body.appendChild(link);
2423
+ link.click();
2424
+ document.body.removeChild(link);
2425
+ URL.revokeObjectURL(url);
2426
+ toggleNotification({
2427
+ type: "success",
2428
+ message: `Exported ${res.data.count || diffs.length} batch changes to audit CSV.`
2429
+ });
2430
+ } else {
2431
+ toggleNotification({
2432
+ type: "danger",
2433
+ message: "Failed to generate review CSV export."
2434
+ });
2435
+ }
2436
+ } catch (err) {
2437
+ toggleNotification({
2438
+ type: "danger",
2439
+ message: err.message || "Error downloading review CSV."
2440
+ });
2441
+ } finally {
2442
+ setIsExporting(false);
2443
+ }
2444
+ };
2445
+ const filteredDiffs = useMemo(() => {
2446
+ let items = diffs;
2447
+ if (filterTab === "changes") {
2448
+ items = items.filter((d) => d.hasChange || d.status === "will_create");
2449
+ } else if (filterTab === "will_update") {
2450
+ items = items.filter((d) => d.status === "will_update");
2451
+ } else if (filterTab === "will_create") {
2452
+ items = items.filter((d) => d.status === "will_create");
2453
+ } else if (filterTab === "unchanged") {
2454
+ items = items.filter((d) => d.status === "unchanged");
2455
+ } else if (filterTab === "will_skip") {
2456
+ items = items.filter((d) => d.status === "will_skip");
2457
+ }
2458
+ if (searchQuery.trim()) {
2459
+ const q = searchQuery.toLowerCase().trim();
2460
+ items = items.filter(
2461
+ (d) => d.label?.toLowerCase().includes(q) || d.documentId?.toLowerCase().includes(q) || d.collectionName?.toLowerCase().includes(q) || d.attribute?.toLowerCase().includes(q) || String(d.oldDisplay || "").toLowerCase().includes(q) || String(d.newDisplay || "").toLowerCase().includes(q)
2462
+ );
2463
+ }
2464
+ return items;
2465
+ }, [diffs, filterTab, searchQuery]);
2466
+ if (!isOpen || !batch) return null;
2467
+ const totalChanges = (summary.willUpdate || 0) + (summary.willCreate || 0);
2468
+ return /* @__PURE__ */ jsx(
2469
+ "div",
2470
+ {
2471
+ style: {
2472
+ position: "fixed",
2473
+ inset: 0,
2474
+ backgroundColor: "rgba(20, 20, 30, 0.75)",
2475
+ backdropFilter: "blur(4px)",
2476
+ display: "flex",
2477
+ alignItems: "center",
2478
+ justifyContent: "center",
2479
+ zIndex: 9999,
2480
+ padding: 16,
2481
+ boxSizing: "border-box"
2482
+ },
2483
+ onClick: onClose,
2484
+ children: /* @__PURE__ */ jsxs(
2485
+ Box,
2486
+ {
2487
+ background: "neutral0",
2488
+ hasRadius: true,
2489
+ shadow: "popupShadow",
2490
+ style: {
2491
+ maxWidth: 1160,
2492
+ width: "96%",
2493
+ maxHeight: "calc(100vh - 40px)",
2494
+ display: "flex",
2495
+ flexDirection: "column",
2496
+ overflow: "hidden",
2497
+ position: "relative",
2498
+ boxShadow: "0 24px 50px rgba(0, 0, 0, 0.4), 0 0 1px rgba(0, 0, 0, 0.25)"
2499
+ },
2500
+ onClick: (e) => e.stopPropagation(),
2501
+ children: [
2502
+ /* @__PURE__ */ jsx(
2503
+ Box,
2504
+ {
2505
+ padding: 5,
2506
+ background: "neutral100",
2507
+ style: {
2508
+ borderBottom: "1px solid rgba(120, 120, 150, 0.2)",
2509
+ flexShrink: 0
2510
+ },
2511
+ children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "flex-start", wrap: "wrap", gap: 3, children: [
2512
+ /* @__PURE__ */ jsxs(Box, { children: [
2513
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", marginBottom: 1, children: [
2514
+ /* @__PURE__ */ jsx(Typography, { variant: "delta", fontWeight: "bold", children: "Checker Approval: Bulk Change Inspection" }),
2515
+ /* @__PURE__ */ jsx(Badge, { backgroundColor: "primary100", textColor: "primary700", children: batch.id }),
2516
+ (batch.payload?.action === "csv_import" || batch.id?.startsWith("csv_")) && /* @__PURE__ */ jsx(Badge, { backgroundColor: "secondary100", textColor: "secondary700", children: "📊 CSV IMPORT" }),
2517
+ batch.payload?.action === "publish" && /* @__PURE__ */ jsx(Badge, { backgroundColor: "success100", textColor: "success700", children: "🚀 BULK PUBLISH" })
2518
+ ] }),
2519
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", children: [
2520
+ "Submitted by ",
2521
+ /* @__PURE__ */ jsx("strong", { children: batch.createdBy?.email || "admin" }),
2522
+ " on ",
2523
+ new Date(batch.createdAt).toLocaleString()
2524
+ ] }),
2525
+ batch.makerNotes && /* @__PURE__ */ jsx(Box, { marginTop: 2, padding: 2, background: "neutral150", hasRadius: true, style: { borderLeft: "3px solid #4945ff" }, children: /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral700", children: [
2526
+ /* @__PURE__ */ jsx("strong", { children: "Maker Notes:" }),
2527
+ " ",
2528
+ batch.makerNotes
2529
+ ] }) })
2530
+ ] }),
2531
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
2532
+ /* @__PURE__ */ jsx(
2533
+ Button,
2534
+ {
2535
+ variant: "tertiary",
2536
+ size: "S",
2537
+ startIcon: /* @__PURE__ */ jsx(Download, {}),
2538
+ onClick: handleExportCsv,
2539
+ loading: isExporting,
2540
+ children: "Export Audit CSV"
2541
+ }
2542
+ ),
2543
+ /* @__PURE__ */ jsx(
2544
+ Button,
2545
+ {
2546
+ variant: "tertiary",
2547
+ size: "S",
2548
+ startIcon: /* @__PURE__ */ jsx(ArrowClockwise, {}),
2549
+ onClick: fetchBatchDiffs,
2550
+ loading,
2551
+ children: "Refresh"
2552
+ }
2553
+ )
2554
+ ] })
2555
+ ] })
2556
+ }
2557
+ ),
2558
+ /* @__PURE__ */ jsxs(
2559
+ Box,
2560
+ {
2561
+ padding: 5,
2562
+ style: {
2563
+ flex: "1 1 auto",
2564
+ minHeight: 0,
2565
+ overflowY: "auto",
2566
+ WebkitOverflowScrolling: "touch"
2567
+ },
2568
+ children: [
2569
+ loading ? /* @__PURE__ */ jsx(Box, { padding: 8, style: { textAlign: "center" }, children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "center", gap: 3, children: [
2570
+ /* @__PURE__ */ jsx(Loader, { children: "Inspecting target records from database..." }),
2571
+ /* @__PURE__ */ jsx(Typography, { variant: "delta", fontWeight: "semiBold", children: "Generating Itemized Diffs..." }),
2572
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Comparing proposed values against current database records." })
2573
+ ] }) }) : error ? /* @__PURE__ */ jsxs(Box, { padding: 6, style: { textAlign: "center" }, children: [
2574
+ /* @__PURE__ */ jsx(Typography, { variant: "delta", textColor: "danger700", fontWeight: "bold", children: "Failed to load change diffs" }),
2575
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral700", display: "block", marginTop: 1, children: error })
2576
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2577
+ /* @__PURE__ */ jsxs(Flex, { gap: 3, marginBottom: 4, wrap: "wrap", children: [
2578
+ /* @__PURE__ */ jsxs(
2579
+ Box,
2580
+ {
2581
+ padding: 3,
2582
+ background: "neutral100",
2583
+ hasRadius: true,
2584
+ style: { flex: 1, minWidth: 130, border: "1px solid rgba(120, 120, 150, 0.15)" },
2585
+ children: [
2586
+ /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", display: "block", children: "TOTAL TARGETS" }),
2587
+ /* @__PURE__ */ jsx(Typography, { variant: "beta", fontWeight: "bold", textColor: "neutral800", children: summary.total })
2588
+ ]
2589
+ }
2590
+ ),
2591
+ /* @__PURE__ */ jsxs(
2592
+ Box,
2593
+ {
2594
+ padding: 3,
2595
+ background: "warning100",
2596
+ hasRadius: true,
2597
+ style: { flex: 1, minWidth: 130, border: "1px solid #ffd591" },
2598
+ children: [
2599
+ /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "warning700", display: "block", children: "WILL UPDATE" }),
2600
+ /* @__PURE__ */ jsx(Typography, { variant: "beta", fontWeight: "bold", textColor: "warning700", children: summary.willUpdate })
2601
+ ]
2602
+ }
2603
+ ),
2604
+ (summary.willCreate ?? 0) > 0 && /* @__PURE__ */ jsxs(
2605
+ Box,
2606
+ {
2607
+ padding: 3,
2608
+ background: "success100",
2609
+ hasRadius: true,
2610
+ style: { flex: 1, minWidth: 130, border: "1px solid #b7eb8f" },
2611
+ children: [
2612
+ /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "success700", display: "block", children: "WILL CREATE (NEW)" }),
2613
+ /* @__PURE__ */ jsx(Typography, { variant: "beta", fontWeight: "bold", textColor: "success700", children: summary.willCreate })
2614
+ ]
2615
+ }
2616
+ ),
2617
+ /* @__PURE__ */ jsxs(
2618
+ Box,
2619
+ {
2620
+ padding: 3,
2621
+ background: "neutral100",
2622
+ hasRadius: true,
2623
+ style: { flex: 1, minWidth: 130, border: "1px solid rgba(120, 120, 150, 0.15)" },
2624
+ children: [
2625
+ /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", display: "block", children: "UNCHANGED" }),
2626
+ /* @__PURE__ */ jsx(Typography, { variant: "beta", fontWeight: "bold", textColor: "neutral600", children: summary.unchanged })
2627
+ ]
2628
+ }
2629
+ ),
2630
+ summary.skipped > 0 && /* @__PURE__ */ jsxs(
2631
+ Box,
2632
+ {
2633
+ padding: 3,
2634
+ background: "danger100",
2635
+ hasRadius: true,
2636
+ style: { flex: 1, minWidth: 130, border: "1px solid #ffa39e" },
2637
+ children: [
2638
+ /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "danger700", display: "block", children: "SKIPPED / ERRORS" }),
2639
+ /* @__PURE__ */ jsx(Typography, { variant: "beta", fontWeight: "bold", textColor: "danger700", children: summary.skipped })
2640
+ ]
2641
+ }
2642
+ )
2643
+ ] }),
2644
+ /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 3, wrap: "wrap", gap: 3, children: [
2645
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, wrap: "wrap", children: [
2646
+ /* @__PURE__ */ jsxs(
2647
+ Button,
2648
+ {
2649
+ variant: filterTab === "all" ? "default" : "tertiary",
2650
+ size: "S",
2651
+ onClick: () => setFilterTab("all"),
2652
+ children: [
2653
+ "All Items (",
2654
+ diffs.length,
2655
+ ")"
2656
+ ]
2657
+ }
2658
+ ),
2659
+ /* @__PURE__ */ jsxs(
2660
+ Button,
2661
+ {
2662
+ variant: filterTab === "changes" ? "default" : "tertiary",
2663
+ size: "S",
2664
+ onClick: () => setFilterTab("changes"),
2665
+ children: [
2666
+ "Changes Only (",
2667
+ totalChanges,
2668
+ ")"
2669
+ ]
2670
+ }
2671
+ ),
2672
+ /* @__PURE__ */ jsxs(
2673
+ Button,
2674
+ {
2675
+ variant: filterTab === "will_update" ? "default" : "tertiary",
2676
+ size: "S",
2677
+ onClick: () => setFilterTab("will_update"),
2678
+ children: [
2679
+ "Updates (",
2680
+ summary.willUpdate,
2681
+ ")"
2682
+ ]
2683
+ }
2684
+ ),
2685
+ (summary.willCreate ?? 0) > 0 && /* @__PURE__ */ jsxs(
2686
+ Button,
2687
+ {
2688
+ variant: filterTab === "will_create" ? "default" : "tertiary",
2689
+ size: "S",
2690
+ onClick: () => setFilterTab("will_create"),
2691
+ children: [
2692
+ "Creates (",
2693
+ summary.willCreate,
2694
+ ")"
2695
+ ]
2696
+ }
2697
+ ),
2698
+ /* @__PURE__ */ jsxs(
2699
+ Button,
2700
+ {
2701
+ variant: filterTab === "unchanged" ? "default" : "tertiary",
2702
+ size: "S",
2703
+ onClick: () => setFilterTab("unchanged"),
2704
+ children: [
2705
+ "Unchanged (",
2706
+ summary.unchanged,
2707
+ ")"
2708
+ ]
2709
+ }
2710
+ ),
2711
+ summary.skipped > 0 && /* @__PURE__ */ jsxs(
2712
+ Button,
2713
+ {
2714
+ variant: filterTab === "will_skip" ? "default" : "tertiary",
2715
+ size: "S",
2716
+ onClick: () => setFilterTab("will_skip"),
2717
+ children: [
2718
+ "Skipped (",
2719
+ summary.skipped,
2720
+ ")"
2721
+ ]
2722
+ }
2723
+ )
2724
+ ] }),
2725
+ /* @__PURE__ */ jsx(Box, { style: { width: 260 }, children: /* @__PURE__ */ jsx(
2726
+ TextInput,
2727
+ {
2728
+ placeholder: "Search records or values...",
2729
+ size: "S",
2730
+ value: searchQuery,
2731
+ onChange: (e) => setSearchQuery(e.target.value)
2732
+ }
2733
+ ) })
2734
+ ] }),
2735
+ /* @__PURE__ */ jsx(
2736
+ Box,
2737
+ {
2738
+ hasRadius: true,
2739
+ style: {
2740
+ border: "1px solid #eaeaef",
2741
+ maxHeight: 380,
2742
+ overflowY: "auto",
2743
+ overflowX: "auto"
2744
+ },
2745
+ children: /* @__PURE__ */ jsxs(Table, { colCount: 6, rowCount: filteredDiffs.length + 1, style: { width: "100%", minWidth: 880 }, children: [
2746
+ /* @__PURE__ */ jsx(Thead, { children: /* @__PURE__ */ jsxs(Tr, { children: [
2747
+ /* @__PURE__ */ jsx(Th, { style: { width: 140 }, children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", children: "COLLECTION" }) }),
2748
+ /* @__PURE__ */ jsx(Th, { style: { minWidth: 180 }, children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", children: "RECORD IDENTIFIER" }) }),
2749
+ /* @__PURE__ */ jsx(Th, { style: { minWidth: 140 }, children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", children: "ATTRIBUTE" }) }),
2750
+ /* @__PURE__ */ jsx(Th, { style: { minWidth: 180 }, children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", children: "CURRENT VALUE (BEFORE)" }) }),
2751
+ /* @__PURE__ */ jsx(Th, { style: { minWidth: 180 }, children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", children: "PROPOSED VALUE (AFTER)" }) }),
2752
+ /* @__PURE__ */ jsx(Th, { style: { width: 130, textAlign: "right" }, children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", children: "IMPACT" }) })
2753
+ ] }) }),
2754
+ /* @__PURE__ */ jsx(Tbody, { children: filteredDiffs.length === 0 ? /* @__PURE__ */ jsx(Tr, { children: /* @__PURE__ */ jsx(Td, { colSpan: 6, style: { textAlign: "center", padding: "24px" }, children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", children: "No records match the current filter or search criteria." }) }) }) : filteredDiffs.map((diff, idx) => /* @__PURE__ */ jsxs(Tr, { children: [
2755
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Badge, { backgroundColor: "neutral150", textColor: "neutral700", children: diff.collectionName }) }),
2756
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsxs(Box, { children: [
2757
+ /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", display: "block", children: diff.label }),
2758
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: /* @__PURE__ */ jsx("code", { children: diff.documentId }) })
2759
+ ] }) }),
2760
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "semiBold", children: diff.attribute }) }),
2761
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(
2762
+ Typography,
2763
+ {
2764
+ variant: "omega",
2765
+ style: {
2766
+ color: diff.hasChange ? "#9254de" : "#272635",
2767
+ textDecoration: diff.hasChange ? "line-through" : "none",
2768
+ wordBreak: "break-all"
2769
+ },
2770
+ children: diff.oldDisplay || "(empty)"
2771
+ }
2772
+ ) }),
2773
+ /* @__PURE__ */ jsx(Td, { children: diff.status === "will_create" ? /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "bold", textColor: "success700", style: { wordBreak: "break-all" }, children: diff.newDisplay || "(new value)" }) : diff.status === "will_skip" ? /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "warning700", children: "— Skipped —" }) : diff.hasChange ? /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "bold", textColor: "success700", style: { wordBreak: "break-all" }, children: diff.newDisplay || "(empty)" }) : /* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral600", children: diff.newDisplay || "(matching)" }) }),
2774
+ /* @__PURE__ */ jsxs(Td, { style: { textAlign: "right" }, children: [
2775
+ diff.status === "will_create" && /* @__PURE__ */ jsx(Badge, { backgroundColor: "success100", textColor: "success700", children: "+ Will Create" }),
2776
+ diff.status === "will_update" && /* @__PURE__ */ jsx(Badge, { backgroundColor: "warning100", textColor: "warning700", children: "✎ Will Update" }),
2777
+ diff.status === "unchanged" && /* @__PURE__ */ jsx(Badge, { backgroundColor: "neutral150", textColor: "neutral600", children: "= Unchanged" }),
2778
+ diff.status === "will_skip" && /* @__PURE__ */ jsx(Badge, { backgroundColor: "danger100", textColor: "danger700", children: "⚠ Will Skip" })
2779
+ ] })
2780
+ ] }, `${diff.uid}-${diff.documentId}-${diff.attribute}-${idx}`)) })
2781
+ ] })
2782
+ }
2783
+ )
2784
+ ] }),
2785
+ showRejectInput && /* @__PURE__ */ jsxs(Box, { marginTop: 4, padding: 4, background: "danger100", hasRadius: true, style: { border: "1px solid #ffa39e" }, children: [
2786
+ /* @__PURE__ */ jsx(Typography, { variant: "delta", fontWeight: "bold", textColor: "danger700", marginBottom: 2, children: "Reject Batch" }),
2787
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "danger700", marginBottom: 2, display: "block", children: "Please provide a rejection note explaining why this batch was declined. The Maker will see this message." }),
2788
+ /* @__PURE__ */ jsx(
2789
+ TextInput,
2790
+ {
2791
+ placeholder: "Reason for rejection (e.g., incorrect localized prices in CSV rows 4-8)...",
2792
+ value: rejectionReason,
2793
+ onChange: (e) => setRejectionReason(e.target.value),
2794
+ style: { marginBottom: 12 }
2795
+ }
2796
+ ),
2797
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, justifyContent: "flex-end", children: [
2798
+ /* @__PURE__ */ jsx(Button, { variant: "tertiary", size: "S", onClick: () => setShowRejectInput(false), children: "Cancel" }),
2799
+ /* @__PURE__ */ jsx(
2800
+ Button,
2801
+ {
2802
+ variant: "danger",
2803
+ size: "S",
2804
+ loading: rejecting,
2805
+ onClick: () => onReject(batch.id, rejectionReason || "Declined by Checker"),
2806
+ children: "Confirm Rejection"
2807
+ }
2808
+ )
2809
+ ] })
2810
+ ] })
2811
+ ]
2812
+ }
2813
+ ),
2814
+ /* @__PURE__ */ jsx(
2815
+ Box,
2816
+ {
2817
+ padding: 4,
2818
+ background: "neutral100",
2819
+ style: {
2820
+ borderTop: "1px solid rgba(120, 120, 150, 0.2)",
2821
+ flexShrink: 0
2822
+ },
2823
+ children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", wrap: "wrap", gap: 3, children: [
2824
+ /* @__PURE__ */ jsx(Button, { variant: "tertiary", onClick: onClose, disabled: approving || rejecting, children: "Close Preview" }),
2825
+ /* @__PURE__ */ jsxs(Flex, { gap: 3, children: [
2826
+ !showRejectInput && /* @__PURE__ */ jsx(
2827
+ Button,
2828
+ {
2829
+ variant: "danger-light",
2830
+ onClick: () => setShowRejectInput(true),
2831
+ disabled: approving || rejecting,
2832
+ children: "Reject Batch"
2833
+ }
2834
+ ),
2835
+ /* @__PURE__ */ jsx(
2836
+ Button,
2837
+ {
2838
+ variant: "success",
2839
+ startIcon: /* @__PURE__ */ jsx(Check, {}),
2840
+ onClick: () => onApprove(batch.id),
2841
+ loading: approving,
2842
+ disabled: rejecting,
2843
+ children: "Approve & Execute Batch"
2844
+ }
2845
+ )
2846
+ ] })
2847
+ ] })
2848
+ }
2849
+ )
2850
+ ]
2851
+ }
2852
+ )
2853
+ }
2854
+ );
2855
+ };
2359
2856
  function parseDynamicZonePath(path) {
2360
2857
  if (!path) return { cleanPath: "", rootKey: "", subPath: "" };
2361
2858
  const bracketMatch = path.match(/^([^.[]+)\[([^\]]+)\]\.(.+)$/);
@@ -3056,6 +3553,8 @@ const BulkUpdater = () => {
3056
3553
  const [pendingBatchesLoading, setPendingBatchesLoading] = useState(false);
3057
3554
  const [approvingBatchId, setApprovingBatchId] = useState(null);
3058
3555
  const [rejectingBatchId, setRejectingBatchId] = useState(null);
3556
+ const [inspectingPendingBatch, setInspectingPendingBatch] = useState(null);
3557
+ const [exportingPendingBatchId, setExportingPendingBatchId] = useState(null);
3059
3558
  const [makerNotesInput, setMakerNotesInput] = useState("");
3060
3559
  const [publishOnApproval, setPublishOnApproval] = useState(true);
3061
3560
  const [publishStrategy, setPublishStrategy] = useState("safe");
@@ -3751,7 +4250,7 @@ const BulkUpdater = () => {
3751
4250
  return val.some((item) => typeof item === "object" ? testEntityObject(item) : testString(item));
3752
4251
  }
3753
4252
  if (typeof val === "object" && val !== null) {
3754
- if (testEntityObject(val)) return true;
4253
+ return testEntityObject(val);
3755
4254
  }
3756
4255
  return testString(displayStr);
3757
4256
  };
@@ -4344,6 +4843,7 @@ const BulkUpdater = () => {
4344
4843
  type: "success",
4345
4844
  message: res.data.message || `Batch ${batchId} approved and executed successfully!`
4346
4845
  });
4846
+ setInspectingPendingBatch(null);
4347
4847
  await fetchPendingBatches();
4348
4848
  await fetchAuditHistory();
4349
4849
  await fetchModels();
@@ -4362,8 +4862,8 @@ const BulkUpdater = () => {
4362
4862
  setApprovingBatchId(null);
4363
4863
  }
4364
4864
  };
4365
- const handleRejectBatch = async (batchId) => {
4366
- const reason = window.prompt("Enter reason for rejection:", "Does not meet release criteria") || "Rejected by Checker";
4865
+ const handleRejectBatch = async (batchId, customReason) => {
4866
+ const reason = customReason || window.prompt("Enter reason for rejection:", "Does not meet release criteria") || "Rejected by Checker";
4367
4867
  try {
4368
4868
  setRejectingBatchId(batchId);
4369
4869
  const res = await post(`/bulk-updater/batches/${batchId}/reject`, { reason });
@@ -4372,6 +4872,7 @@ const BulkUpdater = () => {
4372
4872
  type: "info",
4373
4873
  message: `Batch ${batchId} rejected: ${reason}`
4374
4874
  });
4875
+ setInspectingPendingBatch(null);
4375
4876
  await fetchPendingBatches();
4376
4877
  } else {
4377
4878
  toggleNotification({
@@ -4388,6 +4889,40 @@ const BulkUpdater = () => {
4388
4889
  setRejectingBatchId(null);
4389
4890
  }
4390
4891
  };
4892
+ const handleExportPendingBatch = async (batchId) => {
4893
+ try {
4894
+ setExportingPendingBatchId(batchId);
4895
+ const res = await get(`/bulk-updater/batches/${batchId}/diffs/export`);
4896
+ if (res.data && res.data.success && res.data.csvContent) {
4897
+ const safeContent = res.data.csvContent.startsWith("\uFEFF") ? res.data.csvContent : "\uFEFF" + res.data.csvContent;
4898
+ const blob = new Blob([safeContent], { type: "text/csv;charset=utf-8;" });
4899
+ const url = URL.createObjectURL(blob);
4900
+ const link = document.createElement("a");
4901
+ link.href = url;
4902
+ link.setAttribute("download", res.data.filename || `batch_${batchId}_review.csv`);
4903
+ document.body.appendChild(link);
4904
+ link.click();
4905
+ document.body.removeChild(link);
4906
+ URL.revokeObjectURL(url);
4907
+ toggleNotification({
4908
+ type: "success",
4909
+ message: `Exported ${res.data.count || ""} batch diffs to CSV.`
4910
+ });
4911
+ } else {
4912
+ toggleNotification({
4913
+ type: "danger",
4914
+ message: "Failed to export batch diffs to CSV."
4915
+ });
4916
+ }
4917
+ } catch (err) {
4918
+ toggleNotification({
4919
+ type: "danger",
4920
+ message: err.message || "Error exporting batch diffs."
4921
+ });
4922
+ } finally {
4923
+ setExportingPendingBatchId(null);
4924
+ }
4925
+ };
4391
4926
  const handleExecuteNow = async (batchId) => {
4392
4927
  try {
4393
4928
  setExecutingNowBatchId(batchId);
@@ -4681,9 +5216,14 @@ const BulkUpdater = () => {
4681
5216
  /* @__PURE__ */ jsx(
4682
5217
  Combobox,
4683
5218
  {
4684
- autocomplete: "none",
4685
- placeholder: "Select Collection Type...",
5219
+ autocomplete: { type: "list", filter: "contains" },
5220
+ placeholder: "Search Collection Type...",
4686
5221
  value: selectedCollectionUid || void 0,
5222
+ clearLabel: "Clear collection selection",
5223
+ onClear: () => handleCollectionChange(""),
5224
+ onFocus: (e) => {
5225
+ e.target.select();
5226
+ },
4687
5227
  onChange: (val) => {
4688
5228
  if (val && typeof val === "string") {
4689
5229
  handleCollectionChange(val);
@@ -4779,7 +5319,7 @@ const BulkUpdater = () => {
4779
5319
  /* @__PURE__ */ jsx(
4780
5320
  Combobox,
4781
5321
  {
4782
- autocomplete: "none",
5322
+ autocomplete: { type: "list", filter: "contains" },
4783
5323
  placeholder: searchAttribute || `Same as Update (${selectedAttribute || "None"})`,
4784
5324
  value: searchAttribute || "__default__",
4785
5325
  clearLabel: "Reset search attribute",
@@ -4787,6 +5327,9 @@ const BulkUpdater = () => {
4787
5327
  handleSearchAttributeChange("");
4788
5328
  setSearchAttributeSearch("");
4789
5329
  },
5330
+ onFocus: (e) => {
5331
+ e.target.select();
5332
+ },
4790
5333
  onInputChange: (e) => {
4791
5334
  setSearchAttributeSearch(e.target.value);
4792
5335
  },
@@ -5576,7 +6119,7 @@ const BulkUpdater = () => {
5576
6119
  /* @__PURE__ */ jsx(
5577
6120
  Combobox,
5578
6121
  {
5579
- autocomplete: "none",
6122
+ autocomplete: { type: "list", filter: "contains" },
5580
6123
  placeholder: "Search attribute by name or relation...",
5581
6124
  value: selectedAttribute || void 0,
5582
6125
  clearLabel: "Clear attribute selection",
@@ -5584,6 +6127,9 @@ const BulkUpdater = () => {
5584
6127
  handleAttributeChange("");
5585
6128
  setAttributeSearch("");
5586
6129
  },
6130
+ onFocus: (e) => {
6131
+ e.target.select();
6132
+ },
5587
6133
  onInputChange: (e) => {
5588
6134
  setAttributeSearch(e.target.value);
5589
6135
  },
@@ -6005,6 +6551,27 @@ const BulkUpdater = () => {
6005
6551
  ] })
6006
6552
  ] }) }),
6007
6553
  /* @__PURE__ */ jsx(Td, { style: { textAlign: "right" }, children: /* @__PURE__ */ jsxs(Flex, { gap: 2, justifyContent: "flex-end", children: [
6554
+ /* @__PURE__ */ jsx(
6555
+ Button,
6556
+ {
6557
+ size: "S",
6558
+ variant: "secondary",
6559
+ startIcon: /* @__PURE__ */ jsx(Eye, {}),
6560
+ onClick: () => setInspectingPendingBatch(batch),
6561
+ children: "Review Changes"
6562
+ }
6563
+ ),
6564
+ /* @__PURE__ */ jsx(
6565
+ Button,
6566
+ {
6567
+ size: "S",
6568
+ variant: "tertiary",
6569
+ startIcon: /* @__PURE__ */ jsx(Download, {}),
6570
+ onClick: () => handleExportPendingBatch(batch.id),
6571
+ loading: exportingPendingBatchId === batch.id,
6572
+ children: "Export CSV"
6573
+ }
6574
+ ),
6008
6575
  batch.status === "pending_approval" && /* @__PURE__ */ jsxs(Fragment, { children: [
6009
6576
  /* @__PURE__ */ jsx(
6010
6577
  Button,
@@ -6921,6 +7488,18 @@ const BulkUpdater = () => {
6921
7488
  initialJob: dashboardJob,
6922
7489
  isSubmitting: isSubmittingBatch
6923
7490
  }
7491
+ ),
7492
+ /* @__PURE__ */ jsx(
7493
+ CheckerReviewModal,
7494
+ {
7495
+ isOpen: Boolean(inspectingPendingBatch),
7496
+ onClose: () => setInspectingPendingBatch(null),
7497
+ batch: inspectingPendingBatch,
7498
+ onApprove: handleApproveBatch,
7499
+ onReject: handleRejectBatch,
7500
+ approving: Boolean(inspectingPendingBatch && approvingBatchId === inspectingPendingBatch.id),
7501
+ rejecting: Boolean(inspectingPendingBatch && rejectingBatchId === inspectingPendingBatch.id)
7502
+ }
6924
7503
  )
6925
7504
  ]
6926
7505
  }
@@ -6939,4 +7518,4 @@ export {
6939
7518
  getSortOptionsForCollection,
6940
7519
  parseDynamicZonePath
6941
7520
  };
6942
- //# sourceMappingURL=BulkUpdater-CHdA0546.mjs.map
7521
+ //# sourceMappingURL=BulkUpdater-By9Dd_YF.mjs.map