strapi-plugin-bulk-updater 1.2.11 → 1.2.12

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.
@@ -1120,7 +1120,8 @@ const BulkUpdatePreviewModal = ({
1120
1120
  loading,
1121
1121
  previewData,
1122
1122
  attribute,
1123
- targetValueDisplay
1123
+ targetValueDisplay,
1124
+ publishOnApproval = true
1124
1125
  }) => {
1125
1126
  const [filterTab, setFilterTab] = useState("all");
1126
1127
  const [searchQuery, setSearchQuery] = useState("");
@@ -1193,9 +1194,17 @@ const BulkUpdatePreviewModal = ({
1193
1194
  ] }),
1194
1195
  /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Inspect exact before & after values across target records before applying changes to the database." })
1195
1196
  ] }),
1196
- /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
1197
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
1197
1198
  /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "New Value:" }),
1198
- /* @__PURE__ */ jsx(Badge, { backgroundColor: "success100", textColor: "success700", children: targetValueDisplay || "(empty)" })
1199
+ /* @__PURE__ */ jsx(Badge, { backgroundColor: "success100", textColor: "success700", children: targetValueDisplay || "(empty)" }),
1200
+ /* @__PURE__ */ jsx(
1201
+ Badge,
1202
+ {
1203
+ backgroundColor: publishOnApproval !== false ? "success100" : "warning100",
1204
+ textColor: publishOnApproval !== false ? "success700" : "warning700",
1205
+ children: publishOnApproval !== false ? "✓ LIVE PUBLISH" : "DRAFT ONLY"
1206
+ }
1207
+ )
1199
1208
  ] })
1200
1209
  ] })
1201
1210
  }
@@ -1634,6 +1643,9 @@ const BulkUpdater = () => {
1634
1643
  const [showPreviewModal, setShowPreviewModal] = useState(false);
1635
1644
  const [previewLoading, setPreviewLoading] = useState(false);
1636
1645
  const [previewData, setPreviewData] = useState(null);
1646
+ const [showPublishConfirmModal, setShowPublishConfirmModal] = useState(false);
1647
+ const [publishing, setPublishing] = useState(false);
1648
+ const [publishMakerNotesInput, setPublishMakerNotesInput] = useState("");
1637
1649
  const MODELS_CACHE_KEY = "strapi_bulk_updater_models_cache";
1638
1650
  const LAST_ATTR_KEY = "strapi_bulk_updater_last_attr";
1639
1651
  const getInitialAttribute = () => {
@@ -2419,6 +2431,148 @@ const BulkUpdater = () => {
2419
2431
  setMakerNotesInput("");
2420
2432
  }
2421
2433
  };
2434
+ const handleOpenPublishModal = () => {
2435
+ const totalSelected = Object.values(selectedEntries).filter(Boolean).length;
2436
+ if (totalSelected === 0) {
2437
+ toggleNotification({
2438
+ type: "warning",
2439
+ message: "Please select at least one collection type or entry to publish"
2440
+ });
2441
+ return;
2442
+ }
2443
+ setShowPublishConfirmModal(true);
2444
+ };
2445
+ const executeBatchPublish = async (executionMode, forceImmediate = false) => {
2446
+ const targets = [];
2447
+ Object.keys(selectedEntries).forEach((key) => {
2448
+ if (selectedEntries[key]) {
2449
+ const parts = key.split(KEY_SEP);
2450
+ if (parts.length === 2) {
2451
+ targets.push({ uid: parts[0], documentId: parts[1] });
2452
+ }
2453
+ }
2454
+ });
2455
+ try {
2456
+ setPublishing(true);
2457
+ setShowPublishConfirmModal(false);
2458
+ setShowProcessingDashboard(true);
2459
+ setIsSubmittingBatch(true);
2460
+ setLastResults(null);
2461
+ const tempBatchId = `batch_pub_${Date.now()}`;
2462
+ setDashboardBatchId(tempBatchId);
2463
+ setDashboardJob({
2464
+ id: tempBatchId,
2465
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2466
+ status: "processing",
2467
+ executionMode,
2468
+ attribute: "(publish)",
2469
+ value: "published",
2470
+ totalTargets: targets.length,
2471
+ processedCount: 0,
2472
+ updatedCount: 0,
2473
+ skippedCount: 0,
2474
+ failedCount: 0,
2475
+ isLive: true,
2476
+ publishOnApproval: true,
2477
+ results: []
2478
+ });
2479
+ const payload = {
2480
+ selectedEntries: targets,
2481
+ executionMode,
2482
+ makerNotes: publishMakerNotesInput,
2483
+ forceImmediate
2484
+ };
2485
+ const res = await post("/bulk-updater/batch-publish", payload);
2486
+ setIsSubmittingBatch(false);
2487
+ if (res.data && res.data.success) {
2488
+ setSelectedEntries({});
2489
+ const finalBatchId = res.data.batchId;
2490
+ setDashboardBatchId(finalBatchId);
2491
+ if (res.data.pending) {
2492
+ setDashboardJob({
2493
+ id: finalBatchId,
2494
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2495
+ status: res.data.status || "pending_approval",
2496
+ executionMode,
2497
+ scheduledFor: res.data.scheduledFor,
2498
+ attribute: "(publish)",
2499
+ value: "published",
2500
+ totalTargets: targets.length,
2501
+ processedCount: 0,
2502
+ updatedCount: 0,
2503
+ skippedCount: 0,
2504
+ failedCount: 0,
2505
+ isLive: true,
2506
+ publishOnApproval: true,
2507
+ makerNotes: publishMakerNotesInput,
2508
+ policyMessage: res.data.message,
2509
+ results: []
2510
+ });
2511
+ toggleNotification({
2512
+ type: "success",
2513
+ message: res.data.message || "Publish batch submitted successfully."
2514
+ });
2515
+ await fetchPendingBatches();
2516
+ } else {
2517
+ setLastResults(res.data.results || []);
2518
+ setUpdateSummary({
2519
+ updatedCount: res.data.publishedCount || 0,
2520
+ skippedCount: res.data.skippedCount || 0,
2521
+ batchId: res.data.batchId
2522
+ });
2523
+ setDashboardJob({
2524
+ id: finalBatchId,
2525
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2526
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
2527
+ status: res.data.status || "successful",
2528
+ executionMode: "immediate",
2529
+ attribute: "(publish)",
2530
+ value: "published",
2531
+ totalTargets: res.data.totalTargets || targets.length,
2532
+ processedCount: res.data.results?.length || targets.length,
2533
+ updatedCount: res.data.publishedCount || 0,
2534
+ skippedCount: res.data.skippedCount || 0,
2535
+ failedCount: res.data.failedCount || 0,
2536
+ isLive: true,
2537
+ publishOnApproval: true,
2538
+ results: res.data.results || []
2539
+ });
2540
+ toggleNotification({
2541
+ type: "success",
2542
+ message: `Bulk publish complete! Batch ID: ${res.data.batchId}. Published: ${res.data.publishedCount}, Skipped: ${res.data.skippedCount}`
2543
+ });
2544
+ await fetchModels();
2545
+ await fetchAuditHistory();
2546
+ }
2547
+ } else {
2548
+ setIsSubmittingBatch(false);
2549
+ setDashboardJob((prev) => ({
2550
+ ...prev,
2551
+ status: "failed",
2552
+ error: res.data?.error || "Batch publish encountered an error"
2553
+ }));
2554
+ toggleNotification({
2555
+ type: "danger",
2556
+ message: res.data?.error || "Batch publish encountered an error"
2557
+ });
2558
+ }
2559
+ } catch (err) {
2560
+ setIsSubmittingBatch(false);
2561
+ const errMsg = err.response?.data?.error || err.message || "Batch publish failed";
2562
+ setDashboardJob((prev) => ({
2563
+ ...prev,
2564
+ status: "failed",
2565
+ error: errMsg
2566
+ }));
2567
+ toggleNotification({
2568
+ type: "danger",
2569
+ message: errMsg
2570
+ });
2571
+ } finally {
2572
+ setPublishing(false);
2573
+ setPublishMakerNotesInput("");
2574
+ }
2575
+ };
2422
2576
  const handleApproveBatch = async (batchId) => {
2423
2577
  try {
2424
2578
  setApprovingBatchId(batchId);
@@ -2903,9 +3057,47 @@ const BulkUpdater = () => {
2903
3057
  ")"
2904
3058
  ]
2905
3059
  }
3060
+ ),
3061
+ /* @__PURE__ */ jsxs(
3062
+ Button,
3063
+ {
3064
+ startIcon: /* @__PURE__ */ jsx(Check, {}),
3065
+ variant: "success-light",
3066
+ size: "L",
3067
+ onClick: handleOpenPublishModal,
3068
+ loading: publishing,
3069
+ disabled: loading || totalSelectedCount === 0,
3070
+ title: "Directly publish selected draft records across collections",
3071
+ children: [
3072
+ "Publish Selected (",
3073
+ totalSelectedCount,
3074
+ ")"
3075
+ ]
3076
+ }
2906
3077
  )
2907
3078
  ] })
2908
3079
  ] }),
3080
+ /* @__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: [
3081
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
3082
+ /* @__PURE__ */ jsx(
3083
+ Checkbox,
3084
+ {
3085
+ checked: publishOnApproval,
3086
+ onCheckedChange: (checked) => setPublishOnApproval(Boolean(checked)),
3087
+ children: /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: "Auto-Publish after Update" })
3088
+ }
3089
+ ),
3090
+ /* @__PURE__ */ jsx(
3091
+ Badge,
3092
+ {
3093
+ backgroundColor: publishOnApproval ? "success100" : "warning100",
3094
+ textColor: publishOnApproval ? "success700" : "warning700",
3095
+ children: publishOnApproval ? "✓ LIVE PUBLISH" : "DRAFT ONLY"
3096
+ }
3097
+ )
3098
+ ] }),
3099
+ /* @__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." })
3100
+ ] }) }),
2909
3101
  /* @__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
3102
  /* @__PURE__ */ jsx(Flex, { gap: 2, alignItems: "center", children: /* @__PURE__ */ jsx(
2911
3103
  Checkbox,
@@ -4233,6 +4425,210 @@ const BulkUpdater = () => {
4233
4425
  )
4234
4426
  }
4235
4427
  ),
4428
+ showPublishConfirmModal && /* @__PURE__ */ jsx(
4429
+ "div",
4430
+ {
4431
+ style: {
4432
+ position: "fixed",
4433
+ top: 0,
4434
+ left: 0,
4435
+ right: 0,
4436
+ bottom: 0,
4437
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
4438
+ display: "flex",
4439
+ alignItems: "center",
4440
+ justifyContent: "center",
4441
+ zIndex: 100
4442
+ },
4443
+ onClick: () => setShowPublishConfirmModal(false),
4444
+ children: /* @__PURE__ */ jsxs(
4445
+ Box,
4446
+ {
4447
+ background: "neutral0",
4448
+ hasRadius: true,
4449
+ style: {
4450
+ width: "90%",
4451
+ maxWidth: 620,
4452
+ maxHeight: "90vh",
4453
+ display: "flex",
4454
+ flexDirection: "column",
4455
+ boxShadow: "0 10px 40px rgba(0, 0, 0, 0.25)",
4456
+ overflow: "hidden"
4457
+ },
4458
+ onClick: (e) => e.stopPropagation(),
4459
+ children: [
4460
+ /* @__PURE__ */ jsx(
4461
+ Box,
4462
+ {
4463
+ padding: 5,
4464
+ background: "neutral100",
4465
+ style: {
4466
+ borderBottom: "1px solid rgba(120, 120, 150, 0.2)",
4467
+ flexShrink: 0
4468
+ },
4469
+ children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [
4470
+ /* @__PURE__ */ jsxs(Box, { children: [
4471
+ /* @__PURE__ */ jsx(Typography, { variant: "beta", fontWeight: "bold", children: "Confirm Bulk Publish" }),
4472
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Publish selected draft records live to visitors across content types" }) })
4473
+ ] }),
4474
+ /* @__PURE__ */ jsxs(Badge, { backgroundColor: "success100", textColor: "success700", children: [
4475
+ totalSelectedCount,
4476
+ " Selected"
4477
+ ] })
4478
+ ] })
4479
+ }
4480
+ ),
4481
+ /* @__PURE__ */ jsxs(
4482
+ Box,
4483
+ {
4484
+ padding: 5,
4485
+ style: {
4486
+ overflowY: "auto",
4487
+ flexGrow: 1,
4488
+ display: "flex",
4489
+ flexDirection: "column",
4490
+ gap: 16
4491
+ },
4492
+ children: [
4493
+ /* @__PURE__ */ jsxs(Box, { padding: 4, background: "neutral100", hasRadius: true, style: { border: "1px solid #eaeaef" }, children: [
4494
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "bold", children: "Collection Breakdown:" }),
4495
+ /* @__PURE__ */ jsx(Box, { marginTop: 2, children: collections.filter(
4496
+ (col) => col.entries.some((entry) => selectedEntries[`${col.uid}${KEY_SEP}${entry.documentId}`])
4497
+ ).map((col) => {
4498
+ const count = col.entries.filter(
4499
+ (entry) => selectedEntries[`${col.uid}${KEY_SEP}${entry.documentId}`]
4500
+ ).length;
4501
+ const hasDraftAndPublish = col.draftAndPublish !== false;
4502
+ return /* @__PURE__ */ jsxs(
4503
+ Flex,
4504
+ {
4505
+ justifyContent: "space-between",
4506
+ alignItems: "center",
4507
+ paddingTop: 2,
4508
+ paddingBottom: 2,
4509
+ style: { borderBottom: "1px dashed #eaeaef" },
4510
+ children: [
4511
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", children: [
4512
+ /* @__PURE__ */ jsx("strong", { children: col.displayName }),
4513
+ " (",
4514
+ col.uid,
4515
+ ")"
4516
+ ] }),
4517
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
4518
+ /* @__PURE__ */ jsxs(Badge, { backgroundColor: "neutral150", textColor: "neutral700", children: [
4519
+ count,
4520
+ " ",
4521
+ count === 1 ? "entry" : "entries"
4522
+ ] }),
4523
+ hasDraftAndPublish ? /* @__PURE__ */ jsx(Badge, { backgroundColor: "success100", textColor: "success700", children: "✓ Draft & Publish Enabled" }) : /* @__PURE__ */ jsx(Badge, { backgroundColor: "warning100", textColor: "warning700", children: "⚠️ Skipped (Drafts Disabled)" })
4524
+ ] })
4525
+ ]
4526
+ },
4527
+ col.uid
4528
+ );
4529
+ }) })
4530
+ ] }),
4531
+ executionWindow?.isBusinessHours && /* @__PURE__ */ jsxs(
4532
+ Box,
4533
+ {
4534
+ padding: 4,
4535
+ background: "warning100",
4536
+ hasRadius: true,
4537
+ style: { border: "1px solid #f5c0b8" },
4538
+ children: [
4539
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", textColor: "warning700", children: "⚠️ Business Hours Active:" }),
4540
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "warning700", style: { display: "block", marginTop: 4 }, children: [
4541
+ "It is currently business peak hours (",
4542
+ executionWindow.currentTime,
4543
+ "). To prevent API latency spikes, publish requests should be queued for off-peak hours (",
4544
+ executionWindow.offPeakStartTime,
4545
+ ") or submitted for governance review."
4546
+ ] })
4547
+ ]
4548
+ }
4549
+ ),
4550
+ /* @__PURE__ */ jsxs(Box, { children: [
4551
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", children: "Governance Notes / Reason (Optional):" }),
4552
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(
4553
+ TextInput,
4554
+ {
4555
+ name: "publishMakerNotes",
4556
+ placeholder: "e.g. Publishing Q3 catalog release updates",
4557
+ value: publishMakerNotesInput,
4558
+ onChange: (e) => setPublishMakerNotesInput(e.target.value)
4559
+ }
4560
+ ) })
4561
+ ] })
4562
+ ]
4563
+ }
4564
+ ),
4565
+ /* @__PURE__ */ jsx(
4566
+ Box,
4567
+ {
4568
+ padding: 4,
4569
+ background: "neutral100",
4570
+ style: {
4571
+ borderTop: "1px solid rgba(120, 120, 150, 0.2)",
4572
+ flexShrink: 0,
4573
+ boxShadow: "0 -4px 16px rgba(0, 0, 0, 0.08)"
4574
+ },
4575
+ children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", gap: 3, style: { width: "100%" }, children: [
4576
+ /* @__PURE__ */ jsx(Button, { variant: "tertiary", size: "M", onClick: () => setShowPublishConfirmModal(false), children: "Cancel" }),
4577
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, wrap: "wrap", justifyContent: "flex-end", alignItems: "center", children: [
4578
+ /* @__PURE__ */ jsx(
4579
+ Button,
4580
+ {
4581
+ variant: executionWindow?.isBusinessHours ? "default" : "secondary",
4582
+ size: "M",
4583
+ onClick: () => executeBatchPublish("maker_checker"),
4584
+ loading: publishing,
4585
+ children: "Submit for Checker Approval"
4586
+ }
4587
+ ),
4588
+ executionWindow?.isBusinessHours ? /* @__PURE__ */ jsxs(Fragment, { children: [
4589
+ /* @__PURE__ */ jsxs(
4590
+ Button,
4591
+ {
4592
+ variant: "secondary",
4593
+ size: "M",
4594
+ onClick: () => executeBatchPublish("queue_offpeak"),
4595
+ loading: publishing,
4596
+ children: [
4597
+ "Queue for Off-Peak (",
4598
+ executionWindow?.offPeakStartTime || "18:00",
4599
+ ")"
4600
+ ]
4601
+ }
4602
+ ),
4603
+ /* @__PURE__ */ jsx(
4604
+ Button,
4605
+ {
4606
+ variant: "danger-light",
4607
+ size: "S",
4608
+ onClick: () => executeBatchPublish("immediate", true),
4609
+ loading: publishing,
4610
+ children: "Force Publish Now"
4611
+ }
4612
+ )
4613
+ ] }) : /* @__PURE__ */ jsx(
4614
+ Button,
4615
+ {
4616
+ variant: "default",
4617
+ size: "M",
4618
+ onClick: () => executeBatchPublish("immediate"),
4619
+ loading: publishing,
4620
+ children: "Confirm & Publish Now"
4621
+ }
4622
+ )
4623
+ ] })
4624
+ ] })
4625
+ }
4626
+ )
4627
+ ]
4628
+ }
4629
+ )
4630
+ }
4631
+ ),
4236
4632
  /* @__PURE__ */ jsx(
4237
4633
  BulkUpdatePreviewModal,
4238
4634
  {
@@ -4245,6 +4641,7 @@ const BulkUpdater = () => {
4245
4641
  loading: previewLoading,
4246
4642
  previewData,
4247
4643
  attribute: selectedAttribute,
4644
+ publishOnApproval,
4248
4645
  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
4646
  }
4250
4647
  ),
@@ -4268,4 +4665,4 @@ export {
4268
4665
  getAvailableColumnsForCollection,
4269
4666
  getNestedValue
4270
4667
  };
4271
- //# sourceMappingURL=BulkUpdater-B_COVQmo.mjs.map
4668
+ //# sourceMappingURL=BulkUpdater-DvCSr1vU.mjs.map