strapi-plugin-bulk-updater 1.2.11 → 1.2.13

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.
@@ -3,7 +3,7 @@ import React__default, { useState, useEffect, useMemo, useRef } from "react";
3
3
  import { useFetchClient, useNotification } from "@strapi/strapi/admin";
4
4
  import { Box, Flex, Typography, Button, SingleSelect, SingleSelectOption, Checkbox, Badge, Alert, Table, Thead, Tr, Th, Tbody, Td, Loader, TextInput, ComboboxOption, Field, Combobox } from "@strapi/design-system";
5
5
  import { ArrowClockwise, Download, Upload, Check, Eye, Play } from "@strapi/icons";
6
- import { V as ValidationRulesTab } from "./ValidationRulesTab-BGcqM9cN.mjs";
6
+ import { V as ValidationRulesTab } from "./ValidationRulesTab-Dt53h-Ke.mjs";
7
7
  function CsvManagerTab() {
8
8
  const { get, post } = useFetchClient();
9
9
  const { toggleNotification } = useNotification();
@@ -114,7 +114,8 @@ function CsvManagerTab() {
114
114
  });
115
115
  return;
116
116
  }
117
- const blob = new Blob([content], { type: "text/csv;charset=utf-8;" });
117
+ const safeContent = content.startsWith("\uFEFF") ? content : "\uFEFF" + content;
118
+ const blob = new Blob([safeContent], { type: "text/csv;charset=utf-8;" });
118
119
  const url = URL.createObjectURL(blob);
119
120
  const link = document.createElement("a");
120
121
  link.href = url;
@@ -503,7 +504,9 @@ function formatVal(v) {
503
504
  return String(v);
504
505
  }
505
506
  function downloadFile(content, filename, mimeType = "text/csv;charset=utf-8;") {
506
- const blob = new Blob([content], { type: mimeType });
507
+ const isCsv = mimeType.includes("csv") || filename.endsWith(".csv");
508
+ const safeContent = isCsv && !content.startsWith("\uFEFF") ? "\uFEFF" + content : content;
509
+ const blob = new Blob([safeContent], { type: mimeType });
507
510
  const url = URL.createObjectURL(blob);
508
511
  const a = document.createElement("a");
509
512
  a.href = url;
@@ -625,7 +628,7 @@ function ProcessingDashboardModal({
625
628
  ].join(",")
626
629
  )
627
630
  ];
628
- downloadFile(csvRows.join("\n"), `bulk_update_report_${targetId}.csv`);
631
+ downloadFile(csvRows.join("\r\n") + "\r\n", `bulk_update_report_${targetId}.csv`);
629
632
  toggleNotification({
630
633
  type: "success",
631
634
  message: "Execution report downloaded successfully"
@@ -1120,7 +1123,8 @@ const BulkUpdatePreviewModal = ({
1120
1123
  loading,
1121
1124
  previewData,
1122
1125
  attribute,
1123
- targetValueDisplay
1126
+ targetValueDisplay,
1127
+ publishOnApproval = true
1124
1128
  }) => {
1125
1129
  const [filterTab, setFilterTab] = useState("all");
1126
1130
  const [searchQuery, setSearchQuery] = useState("");
@@ -1193,9 +1197,17 @@ const BulkUpdatePreviewModal = ({
1193
1197
  ] }),
1194
1198
  /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Inspect exact before & after values across target records before applying changes to the database." })
1195
1199
  ] }),
1196
- /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
1200
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
1197
1201
  /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "New Value:" }),
1198
- /* @__PURE__ */ jsx(Badge, { backgroundColor: "success100", textColor: "success700", children: targetValueDisplay || "(empty)" })
1202
+ /* @__PURE__ */ jsx(Badge, { backgroundColor: "success100", textColor: "success700", children: targetValueDisplay || "(empty)" }),
1203
+ /* @__PURE__ */ jsx(
1204
+ Badge,
1205
+ {
1206
+ backgroundColor: publishOnApproval !== false ? "success100" : "warning100",
1207
+ textColor: publishOnApproval !== false ? "success700" : "warning700",
1208
+ children: publishOnApproval !== false ? "✓ LIVE PUBLISH" : "DRAFT ONLY"
1209
+ }
1210
+ )
1199
1211
  ] })
1200
1212
  ] })
1201
1213
  }
@@ -1634,6 +1646,10 @@ const BulkUpdater = () => {
1634
1646
  const [showPreviewModal, setShowPreviewModal] = useState(false);
1635
1647
  const [previewLoading, setPreviewLoading] = useState(false);
1636
1648
  const [previewData, setPreviewData] = useState(null);
1649
+ const [showPublishConfirmModal, setShowPublishConfirmModal] = useState(false);
1650
+ const [publishing, setPublishing] = useState(false);
1651
+ const [publishMakerNotesInput, setPublishMakerNotesInput] = useState("");
1652
+ const [bulkExporting, setBulkExporting] = useState(false);
1637
1653
  const MODELS_CACHE_KEY = "strapi_bulk_updater_models_cache";
1638
1654
  const LAST_ATTR_KEY = "strapi_bulk_updater_last_attr";
1639
1655
  const getInitialAttribute = () => {
@@ -2419,6 +2435,199 @@ const BulkUpdater = () => {
2419
2435
  setMakerNotesInput("");
2420
2436
  }
2421
2437
  };
2438
+ const handleBulkExportSelected = async () => {
2439
+ const targets = [];
2440
+ Object.keys(selectedEntries).forEach((key) => {
2441
+ if (selectedEntries[key]) {
2442
+ const parts = key.split(KEY_SEP);
2443
+ if (parts.length === 2) {
2444
+ targets.push({ uid: parts[0], documentId: parts[1] });
2445
+ }
2446
+ }
2447
+ });
2448
+ if (targets.length === 0) {
2449
+ toggleNotification({
2450
+ type: "warning",
2451
+ message: "Please select at least one entry to export"
2452
+ });
2453
+ return;
2454
+ }
2455
+ try {
2456
+ setBulkExporting(true);
2457
+ const res = await post("/bulk-updater/csv/export-bulk", { selectedEntries: targets });
2458
+ const csvStr = res.data?.csvContent || (typeof res.data === "string" ? res.data : "");
2459
+ if (!csvStr) {
2460
+ toggleNotification({
2461
+ type: "warning",
2462
+ message: "No CSV content returned for selected entries"
2463
+ });
2464
+ return;
2465
+ }
2466
+ const safeContent = csvStr.startsWith("\uFEFF") ? csvStr : "\uFEFF" + csvStr;
2467
+ const blob = new Blob([safeContent], { type: "text/csv;charset=utf-8;" });
2468
+ const url = URL.createObjectURL(blob);
2469
+ const link = document.createElement("a");
2470
+ link.href = url;
2471
+ link.setAttribute("download", res.data?.filename || `bulk_export_selected_${targets.length}.csv`);
2472
+ document.body.appendChild(link);
2473
+ link.click();
2474
+ document.body.removeChild(link);
2475
+ URL.revokeObjectURL(url);
2476
+ toggleNotification({
2477
+ type: "success",
2478
+ message: `Successfully exported ${res.data?.count || targets.length} selected records to Excel CSV`
2479
+ });
2480
+ } catch (e) {
2481
+ toggleNotification({
2482
+ type: "danger",
2483
+ message: e.message || "Failed exporting selected records to CSV"
2484
+ });
2485
+ } finally {
2486
+ setBulkExporting(false);
2487
+ }
2488
+ };
2489
+ const handleOpenPublishModal = () => {
2490
+ const totalSelected = Object.values(selectedEntries).filter(Boolean).length;
2491
+ if (totalSelected === 0) {
2492
+ toggleNotification({
2493
+ type: "warning",
2494
+ message: "Please select at least one collection type or entry to publish"
2495
+ });
2496
+ return;
2497
+ }
2498
+ setShowPublishConfirmModal(true);
2499
+ };
2500
+ const executeBatchPublish = async (executionMode, forceImmediate = false) => {
2501
+ const targets = [];
2502
+ Object.keys(selectedEntries).forEach((key) => {
2503
+ if (selectedEntries[key]) {
2504
+ const parts = key.split(KEY_SEP);
2505
+ if (parts.length === 2) {
2506
+ targets.push({ uid: parts[0], documentId: parts[1] });
2507
+ }
2508
+ }
2509
+ });
2510
+ try {
2511
+ setPublishing(true);
2512
+ setShowPublishConfirmModal(false);
2513
+ setShowProcessingDashboard(true);
2514
+ setIsSubmittingBatch(true);
2515
+ setLastResults(null);
2516
+ const tempBatchId = `batch_pub_${Date.now()}`;
2517
+ setDashboardBatchId(tempBatchId);
2518
+ setDashboardJob({
2519
+ id: tempBatchId,
2520
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2521
+ status: "processing",
2522
+ executionMode,
2523
+ attribute: "(publish)",
2524
+ value: "published",
2525
+ totalTargets: targets.length,
2526
+ processedCount: 0,
2527
+ updatedCount: 0,
2528
+ skippedCount: 0,
2529
+ failedCount: 0,
2530
+ isLive: true,
2531
+ publishOnApproval: true,
2532
+ results: []
2533
+ });
2534
+ const payload = {
2535
+ selectedEntries: targets,
2536
+ executionMode,
2537
+ makerNotes: publishMakerNotesInput,
2538
+ forceImmediate
2539
+ };
2540
+ const res = await post("/bulk-updater/batch-publish", payload);
2541
+ setIsSubmittingBatch(false);
2542
+ if (res.data && res.data.success) {
2543
+ setSelectedEntries({});
2544
+ const finalBatchId = res.data.batchId;
2545
+ setDashboardBatchId(finalBatchId);
2546
+ if (res.data.pending) {
2547
+ setDashboardJob({
2548
+ id: finalBatchId,
2549
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2550
+ status: res.data.status || "pending_approval",
2551
+ executionMode,
2552
+ scheduledFor: res.data.scheduledFor,
2553
+ attribute: "(publish)",
2554
+ value: "published",
2555
+ totalTargets: targets.length,
2556
+ processedCount: 0,
2557
+ updatedCount: 0,
2558
+ skippedCount: 0,
2559
+ failedCount: 0,
2560
+ isLive: true,
2561
+ publishOnApproval: true,
2562
+ makerNotes: publishMakerNotesInput,
2563
+ policyMessage: res.data.message,
2564
+ results: []
2565
+ });
2566
+ toggleNotification({
2567
+ type: "success",
2568
+ message: res.data.message || "Publish batch submitted successfully."
2569
+ });
2570
+ await fetchPendingBatches();
2571
+ } else {
2572
+ setLastResults(res.data.results || []);
2573
+ setUpdateSummary({
2574
+ updatedCount: res.data.publishedCount || 0,
2575
+ skippedCount: res.data.skippedCount || 0,
2576
+ batchId: res.data.batchId
2577
+ });
2578
+ setDashboardJob({
2579
+ id: finalBatchId,
2580
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2581
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
2582
+ status: res.data.status || "successful",
2583
+ executionMode: "immediate",
2584
+ attribute: "(publish)",
2585
+ value: "published",
2586
+ totalTargets: res.data.totalTargets || targets.length,
2587
+ processedCount: res.data.results?.length || targets.length,
2588
+ updatedCount: res.data.publishedCount || 0,
2589
+ skippedCount: res.data.skippedCount || 0,
2590
+ failedCount: res.data.failedCount || 0,
2591
+ isLive: true,
2592
+ publishOnApproval: true,
2593
+ results: res.data.results || []
2594
+ });
2595
+ toggleNotification({
2596
+ type: "success",
2597
+ message: `Bulk publish complete! Batch ID: ${res.data.batchId}. Published: ${res.data.publishedCount}, Skipped: ${res.data.skippedCount}`
2598
+ });
2599
+ await fetchModels();
2600
+ await fetchAuditHistory();
2601
+ }
2602
+ } else {
2603
+ setIsSubmittingBatch(false);
2604
+ setDashboardJob((prev) => ({
2605
+ ...prev,
2606
+ status: "failed",
2607
+ error: res.data?.error || "Batch publish encountered an error"
2608
+ }));
2609
+ toggleNotification({
2610
+ type: "danger",
2611
+ message: res.data?.error || "Batch publish encountered an error"
2612
+ });
2613
+ }
2614
+ } catch (err) {
2615
+ setIsSubmittingBatch(false);
2616
+ const errMsg = err.response?.data?.error || err.message || "Batch publish failed";
2617
+ setDashboardJob((prev) => ({
2618
+ ...prev,
2619
+ status: "failed",
2620
+ error: errMsg
2621
+ }));
2622
+ toggleNotification({
2623
+ type: "danger",
2624
+ message: errMsg
2625
+ });
2626
+ } finally {
2627
+ setPublishing(false);
2628
+ setPublishMakerNotesInput("");
2629
+ }
2630
+ };
2422
2631
  const handleApproveBatch = async (batchId) => {
2423
2632
  try {
2424
2633
  setApprovingBatchId(batchId);
@@ -2903,9 +3112,64 @@ const BulkUpdater = () => {
2903
3112
  ")"
2904
3113
  ]
2905
3114
  }
3115
+ ),
3116
+ /* @__PURE__ */ jsxs(
3117
+ Button,
3118
+ {
3119
+ startIcon: /* @__PURE__ */ jsx(Check, {}),
3120
+ variant: "success-light",
3121
+ size: "L",
3122
+ onClick: handleOpenPublishModal,
3123
+ loading: publishing,
3124
+ disabled: loading || totalSelectedCount === 0,
3125
+ title: "Directly publish selected draft records across collections",
3126
+ children: [
3127
+ "Publish Selected (",
3128
+ totalSelectedCount,
3129
+ ")"
3130
+ ]
3131
+ }
3132
+ ),
3133
+ /* @__PURE__ */ jsxs(
3134
+ Button,
3135
+ {
3136
+ startIcon: /* @__PURE__ */ jsx(Download, {}),
3137
+ variant: "tertiary",
3138
+ size: "L",
3139
+ onClick: handleBulkExportSelected,
3140
+ loading: bulkExporting,
3141
+ disabled: loading || totalSelectedCount === 0,
3142
+ title: "Export selected entries to Excel-compatible CSV with full nested component support",
3143
+ children: [
3144
+ "Export Selected (",
3145
+ totalSelectedCount,
3146
+ ")"
3147
+ ]
3148
+ }
2906
3149
  )
2907
3150
  ] })
2908
3151
  ] }),
3152
+ /* @__PURE__ */ jsx(Box, { marginTop: 4, padding: 4, background: "neutral100", hasRadius: true, style: { border: "1px solid #eaeaef" }, children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", wrap: "wrap", gap: 3, children: [
3153
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
3154
+ /* @__PURE__ */ jsx(
3155
+ Checkbox,
3156
+ {
3157
+ checked: publishOnApproval,
3158
+ onCheckedChange: (checked) => setPublishOnApproval(Boolean(checked)),
3159
+ children: /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: "Auto-Publish after Update" })
3160
+ }
3161
+ ),
3162
+ /* @__PURE__ */ jsx(
3163
+ Badge,
3164
+ {
3165
+ backgroundColor: publishOnApproval ? "success100" : "warning100",
3166
+ textColor: publishOnApproval ? "success700" : "warning700",
3167
+ children: publishOnApproval ? "✓ LIVE PUBLISH" : "DRAFT ONLY"
3168
+ }
3169
+ )
3170
+ ] }),
3171
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: publishOnApproval ? "When enabled, entries will be published live immediately upon batch execution for draft-enabled content types." : "When disabled, entries will be saved as draft versions without publishing to live visitors." })
3172
+ ] }) }),
2909
3173
  /* @__PURE__ */ jsx(Box, { marginTop: 4, padding: 4, background: "neutral100", hasRadius: true, children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", wrap: "wrap", gap: 3, children: [
2910
3174
  /* @__PURE__ */ jsx(Flex, { gap: 2, alignItems: "center", children: /* @__PURE__ */ jsx(
2911
3175
  Checkbox,
@@ -3383,6 +3647,10 @@ const BulkUpdater = () => {
3383
3647
  if (entrySearch && entrySearch.trim()) {
3384
3648
  params.set("search", entrySearch.trim());
3385
3649
  }
3650
+ const colSelectedDocIds = col.entries.filter((e) => selectedEntries[`${col.uid}${KEY_SEP}${e.documentId}`]).map((e) => e.documentId);
3651
+ if (colSelectedDocIds.length > 0) {
3652
+ params.set("documentIds", colSelectedDocIds.join(","));
3653
+ }
3386
3654
  const res = await get(`/bulk-updater/csv/export/${col.uid}?${params.toString()}`);
3387
3655
  const csvStr = res.data?.csvContent || (typeof res.data === "string" ? res.data : "");
3388
3656
  if (!csvStr) {
@@ -3392,7 +3660,8 @@ const BulkUpdater = () => {
3392
3660
  });
3393
3661
  return;
3394
3662
  }
3395
- const blob = new Blob([csvStr], { type: "text/csv;charset=utf-8;" });
3663
+ const safeContent = csvStr.startsWith("\uFEFF") ? csvStr : "\uFEFF" + csvStr;
3664
+ const blob = new Blob([safeContent], { type: "text/csv;charset=utf-8;" });
3396
3665
  const url = URL.createObjectURL(blob);
3397
3666
  const link = document.createElement("a");
3398
3667
  link.href = url;
@@ -3403,7 +3672,7 @@ const BulkUpdater = () => {
3403
3672
  URL.revokeObjectURL(url);
3404
3673
  toggleNotification({
3405
3674
  type: "success",
3406
- message: `Exported ${col.displayName} entries to CSV`
3675
+ message: `Exported ${res.data?.count ?? (colSelectedDocIds.length || col.entries.length)} ${col.displayName} entries to Excel CSV`
3407
3676
  });
3408
3677
  } catch (e) {
3409
3678
  toggleNotification({
@@ -4233,6 +4502,210 @@ const BulkUpdater = () => {
4233
4502
  )
4234
4503
  }
4235
4504
  ),
4505
+ showPublishConfirmModal && /* @__PURE__ */ jsx(
4506
+ "div",
4507
+ {
4508
+ style: {
4509
+ position: "fixed",
4510
+ top: 0,
4511
+ left: 0,
4512
+ right: 0,
4513
+ bottom: 0,
4514
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
4515
+ display: "flex",
4516
+ alignItems: "center",
4517
+ justifyContent: "center",
4518
+ zIndex: 100
4519
+ },
4520
+ onClick: () => setShowPublishConfirmModal(false),
4521
+ children: /* @__PURE__ */ jsxs(
4522
+ Box,
4523
+ {
4524
+ background: "neutral0",
4525
+ hasRadius: true,
4526
+ style: {
4527
+ width: "90%",
4528
+ maxWidth: 620,
4529
+ maxHeight: "90vh",
4530
+ display: "flex",
4531
+ flexDirection: "column",
4532
+ boxShadow: "0 10px 40px rgba(0, 0, 0, 0.25)",
4533
+ overflow: "hidden"
4534
+ },
4535
+ onClick: (e) => e.stopPropagation(),
4536
+ children: [
4537
+ /* @__PURE__ */ jsx(
4538
+ Box,
4539
+ {
4540
+ padding: 5,
4541
+ background: "neutral100",
4542
+ style: {
4543
+ borderBottom: "1px solid rgba(120, 120, 150, 0.2)",
4544
+ flexShrink: 0
4545
+ },
4546
+ children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [
4547
+ /* @__PURE__ */ jsxs(Box, { children: [
4548
+ /* @__PURE__ */ jsx(Typography, { variant: "beta", fontWeight: "bold", children: "Confirm Bulk Publish" }),
4549
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Publish selected draft records live to visitors across content types" }) })
4550
+ ] }),
4551
+ /* @__PURE__ */ jsxs(Badge, { backgroundColor: "success100", textColor: "success700", children: [
4552
+ totalSelectedCount,
4553
+ " Selected"
4554
+ ] })
4555
+ ] })
4556
+ }
4557
+ ),
4558
+ /* @__PURE__ */ jsxs(
4559
+ Box,
4560
+ {
4561
+ padding: 5,
4562
+ style: {
4563
+ overflowY: "auto",
4564
+ flexGrow: 1,
4565
+ display: "flex",
4566
+ flexDirection: "column",
4567
+ gap: 16
4568
+ },
4569
+ children: [
4570
+ /* @__PURE__ */ jsxs(Box, { padding: 4, background: "neutral100", hasRadius: true, style: { border: "1px solid #eaeaef" }, children: [
4571
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "bold", children: "Collection Breakdown:" }),
4572
+ /* @__PURE__ */ jsx(Box, { marginTop: 2, children: collections.filter(
4573
+ (col) => col.entries.some((entry) => selectedEntries[`${col.uid}${KEY_SEP}${entry.documentId}`])
4574
+ ).map((col) => {
4575
+ const count = col.entries.filter(
4576
+ (entry) => selectedEntries[`${col.uid}${KEY_SEP}${entry.documentId}`]
4577
+ ).length;
4578
+ const hasDraftAndPublish = col.draftAndPublish !== false;
4579
+ return /* @__PURE__ */ jsxs(
4580
+ Flex,
4581
+ {
4582
+ justifyContent: "space-between",
4583
+ alignItems: "center",
4584
+ paddingTop: 2,
4585
+ paddingBottom: 2,
4586
+ style: { borderBottom: "1px dashed #eaeaef" },
4587
+ children: [
4588
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", children: [
4589
+ /* @__PURE__ */ jsx("strong", { children: col.displayName }),
4590
+ " (",
4591
+ col.uid,
4592
+ ")"
4593
+ ] }),
4594
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
4595
+ /* @__PURE__ */ jsxs(Badge, { backgroundColor: "neutral150", textColor: "neutral700", children: [
4596
+ count,
4597
+ " ",
4598
+ count === 1 ? "entry" : "entries"
4599
+ ] }),
4600
+ hasDraftAndPublish ? /* @__PURE__ */ jsx(Badge, { backgroundColor: "success100", textColor: "success700", children: "✓ Draft & Publish Enabled" }) : /* @__PURE__ */ jsx(Badge, { backgroundColor: "warning100", textColor: "warning700", children: "⚠️ Skipped (Drafts Disabled)" })
4601
+ ] })
4602
+ ]
4603
+ },
4604
+ col.uid
4605
+ );
4606
+ }) })
4607
+ ] }),
4608
+ executionWindow?.isBusinessHours && /* @__PURE__ */ jsxs(
4609
+ Box,
4610
+ {
4611
+ padding: 4,
4612
+ background: "warning100",
4613
+ hasRadius: true,
4614
+ style: { border: "1px solid #f5c0b8" },
4615
+ children: [
4616
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", textColor: "warning700", children: "⚠️ Business Hours Active:" }),
4617
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "warning700", style: { display: "block", marginTop: 4 }, children: [
4618
+ "It is currently business peak hours (",
4619
+ executionWindow.currentTime,
4620
+ "). To prevent API latency spikes, publish requests should be queued for off-peak hours (",
4621
+ executionWindow.offPeakStartTime,
4622
+ ") or submitted for governance review."
4623
+ ] })
4624
+ ]
4625
+ }
4626
+ ),
4627
+ /* @__PURE__ */ jsxs(Box, { children: [
4628
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", children: "Governance Notes / Reason (Optional):" }),
4629
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(
4630
+ TextInput,
4631
+ {
4632
+ name: "publishMakerNotes",
4633
+ placeholder: "e.g. Publishing Q3 catalog release updates",
4634
+ value: publishMakerNotesInput,
4635
+ onChange: (e) => setPublishMakerNotesInput(e.target.value)
4636
+ }
4637
+ ) })
4638
+ ] })
4639
+ ]
4640
+ }
4641
+ ),
4642
+ /* @__PURE__ */ jsx(
4643
+ Box,
4644
+ {
4645
+ padding: 4,
4646
+ background: "neutral100",
4647
+ style: {
4648
+ borderTop: "1px solid rgba(120, 120, 150, 0.2)",
4649
+ flexShrink: 0,
4650
+ boxShadow: "0 -4px 16px rgba(0, 0, 0, 0.08)"
4651
+ },
4652
+ children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", gap: 3, style: { width: "100%" }, children: [
4653
+ /* @__PURE__ */ jsx(Button, { variant: "tertiary", size: "M", onClick: () => setShowPublishConfirmModal(false), children: "Cancel" }),
4654
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, wrap: "wrap", justifyContent: "flex-end", alignItems: "center", children: [
4655
+ /* @__PURE__ */ jsx(
4656
+ Button,
4657
+ {
4658
+ variant: executionWindow?.isBusinessHours ? "default" : "secondary",
4659
+ size: "M",
4660
+ onClick: () => executeBatchPublish("maker_checker"),
4661
+ loading: publishing,
4662
+ children: "Submit for Checker Approval"
4663
+ }
4664
+ ),
4665
+ executionWindow?.isBusinessHours ? /* @__PURE__ */ jsxs(Fragment, { children: [
4666
+ /* @__PURE__ */ jsxs(
4667
+ Button,
4668
+ {
4669
+ variant: "secondary",
4670
+ size: "M",
4671
+ onClick: () => executeBatchPublish("queue_offpeak"),
4672
+ loading: publishing,
4673
+ children: [
4674
+ "Queue for Off-Peak (",
4675
+ executionWindow?.offPeakStartTime || "18:00",
4676
+ ")"
4677
+ ]
4678
+ }
4679
+ ),
4680
+ /* @__PURE__ */ jsx(
4681
+ Button,
4682
+ {
4683
+ variant: "danger-light",
4684
+ size: "S",
4685
+ onClick: () => executeBatchPublish("immediate", true),
4686
+ loading: publishing,
4687
+ children: "Force Publish Now"
4688
+ }
4689
+ )
4690
+ ] }) : /* @__PURE__ */ jsx(
4691
+ Button,
4692
+ {
4693
+ variant: "default",
4694
+ size: "M",
4695
+ onClick: () => executeBatchPublish("immediate"),
4696
+ loading: publishing,
4697
+ children: "Confirm & Publish Now"
4698
+ }
4699
+ )
4700
+ ] })
4701
+ ] })
4702
+ }
4703
+ )
4704
+ ]
4705
+ }
4706
+ )
4707
+ }
4708
+ ),
4236
4709
  /* @__PURE__ */ jsx(
4237
4710
  BulkUpdatePreviewModal,
4238
4711
  {
@@ -4245,6 +4718,7 @@ const BulkUpdater = () => {
4245
4718
  loading: previewLoading,
4246
4719
  previewData,
4247
4720
  attribute: selectedAttribute,
4721
+ publishOnApproval,
4248
4722
  targetValueDisplay: relationsMeta[selectedAttribute] ? selectedRelationDocId === "__clear__" ? "Clear / Unlink Relation" : relationOptions.find((o) => o.documentId === selectedRelationDocId)?.label || selectedRelationDocId || "(none)" : useRegex ? `Replace /${regexPattern}/g with "${attributeValue}"` : attributeValue
4249
4723
  }
4250
4724
  ),
@@ -4268,4 +4742,4 @@ export {
4268
4742
  getAvailableColumnsForCollection,
4269
4743
  getNestedValue
4270
4744
  };
4271
- //# sourceMappingURL=BulkUpdater-B_COVQmo.mjs.map
4745
+ //# sourceMappingURL=BulkUpdater-Cfig2f7d.mjs.map