strapi-plugin-bulk-updater 1.3.11 → 1.4.3

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.
@@ -2,8 +2,8 @@ import { jsx, jsxs, 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
4
  import { Box, Flex, Typography, Button, SingleSelect, SingleSelectOption, Badge, Checkbox, Alert, Table, Thead, Tr, Th, Tbody, Td, Loader, TextInput, ComboboxOption, Field, Combobox } from "@strapi/design-system";
5
- import { ArrowClockwise, Download, Upload, Check, Eye, Play, Cog } from "@strapi/icons";
6
- import { V as ValidationRulesTab } from "./ValidationRulesTab-VeRr-vxa.mjs";
5
+ import { ArrowClockwise, Download, Upload, Check, Cog, Eye, Play } from "@strapi/icons";
6
+ import { i as isAbortError, V as ValidationRulesTab } from "./ValidationRulesTab-BtOCWK8E.mjs";
7
7
  function parseCsvRows(csvText) {
8
8
  if (!csvText) return [];
9
9
  let text = csvText;
@@ -91,6 +91,51 @@ function parseCsv(csvText) {
91
91
  }
92
92
  return records;
93
93
  }
94
+ const LIFECYCLE_STATUS_WORDS = /* @__PURE__ */ new Set([
95
+ "pending review",
96
+ "pending_review",
97
+ "pending approval",
98
+ "pending_approval",
99
+ "approved",
100
+ "rejected",
101
+ "draft",
102
+ "published",
103
+ "modified",
104
+ "supported",
105
+ "ignored"
106
+ ]);
107
+ function isValidDocId(val) {
108
+ if (!val || typeof val !== "string") return false;
109
+ const trimmed = val.trim();
110
+ if (!trimmed) return false;
111
+ if (LIFECYCLE_STATUS_WORDS.has(trimmed.toLowerCase())) return false;
112
+ if (/\s/.test(trimmed)) return false;
113
+ return /^[a-zA-Z0-9_-]+$/.test(trimmed);
114
+ }
115
+ function extractDocId(row) {
116
+ if (!row || typeof row !== "object") return "";
117
+ const candidates = [
118
+ row.documentId,
119
+ row.document_id,
120
+ row["Document ID"],
121
+ row["Document Id"],
122
+ row["document_id"],
123
+ row.docId,
124
+ row["docId"],
125
+ row.id,
126
+ row.ID,
127
+ row.Id
128
+ ];
129
+ for (const c of candidates) {
130
+ if (c !== void 0 && c !== null) {
131
+ const str = String(c).trim();
132
+ if (isValidDocId(str)) {
133
+ return str;
134
+ }
135
+ }
136
+ }
137
+ return "";
138
+ }
94
139
  function CsvManagerTab() {
95
140
  const { get, post } = useFetchClient();
96
141
  const { toggleNotification } = useNotification();
@@ -131,6 +176,7 @@ function CsvManagerTab() {
131
176
  }
132
177
  }
133
178
  } catch (err) {
179
+ if (isAbortError(err)) return;
134
180
  toggleNotification({
135
181
  type: "danger",
136
182
  message: err.message || "Failed loading collections for CSV Manager"
@@ -151,6 +197,7 @@ function CsvManagerTab() {
151
197
  message: "CSV Template downloaded successfully"
152
198
  });
153
199
  } catch (err) {
200
+ if (isAbortError(err)) return;
154
201
  toggleNotification({
155
202
  type: "danger",
156
203
  message: err.message || "Failed downloading CSV template"
@@ -169,6 +216,7 @@ function CsvManagerTab() {
169
216
  message: "Collection exported to CSV successfully"
170
217
  });
171
218
  } catch (err) {
219
+ if (isAbortError(err)) return;
172
220
  toggleNotification({
173
221
  type: "danger",
174
222
  message: err.message || "Failed exporting collection to CSV"
@@ -187,6 +235,7 @@ function CsvManagerTab() {
187
235
  message: "Rule violations exported to CSV successfully"
188
236
  });
189
237
  } catch (err) {
238
+ if (isAbortError(err)) return;
190
239
  toggleNotification({
191
240
  type: "danger",
192
241
  message: err.message || "Failed exporting violations to CSV"
@@ -256,6 +305,7 @@ function CsvManagerTab() {
256
305
  throw new Error(res.data?.error || "Import failed");
257
306
  }
258
307
  } catch (err) {
308
+ if (isAbortError(err)) return;
259
309
  toggleNotification({
260
310
  type: "danger",
261
311
  message: err.message || "Error processing CSV import"
@@ -409,7 +459,7 @@ function CsvManagerTab() {
409
459
  ),
410
460
  parsedPreview.length > 0 && (() => {
411
461
  const missingDocIdCount = parsedPreview.filter(
412
- (row) => !(row.documentId || row.id || "").trim()
462
+ (row) => !extractDocId(row)
413
463
  ).length;
414
464
  const headers = Object.keys(parsedPreview[0]);
415
465
  return /* @__PURE__ */ jsxs(Box, { marginTop: 4, background: "neutral0", padding: 4, hasRadius: true, children: [
@@ -454,7 +504,7 @@ function CsvManagerTab() {
454
504
  headers.map((h) => /* @__PURE__ */ jsx(Th, { style: { minWidth: 160 }, children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: h }) }, h))
455
505
  ] }) }),
456
506
  /* @__PURE__ */ jsx(Tbody, { children: parsedPreview.map((row, rIdx) => {
457
- const hasDocId = !!(row.documentId || row.id || "").trim();
507
+ const hasDocId = !!extractDocId(row);
458
508
  return /* @__PURE__ */ jsxs(Tr, { children: [
459
509
  /* @__PURE__ */ jsx(Td, { children: hasDocId ? /* @__PURE__ */ jsx(Badge, { backgroundColor: "primary100", textColor: "primary700", children: "🔄 Match / Update" }) : /* @__PURE__ */ jsx(Badge, { backgroundColor: "warning100", textColor: "warning700", children: "➕ New Entry" }) }),
460
510
  headers.map((h) => /* @__PURE__ */ jsx(Td, { style: { verticalAlign: "top", maxWidth: 300 }, children: (h === "documentId" || h === "id") && !row[h]?.trim() ? /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "warning700", fontWeight: "bold", children: "(Auto-generate ID)" }) : /* @__PURE__ */ jsx(
@@ -540,12 +590,53 @@ function CsvManagerTab() {
540
590
  importResult.stats.errors.length,
541
591
  "):"
542
592
  ] }),
543
- /* @__PURE__ */ jsx("ul", { style: { margin: "4px 0 0 16px", padding: 0 }, children: importResult.stats.errors.slice(0, 5).map((err, idx) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "danger600", children: [
593
+ /* @__PURE__ */ jsx("ul", { style: { margin: "4px 0 0 16px", padding: 0 }, children: importResult.stats.errors.slice(0, 10).map((err, idx) => /* @__PURE__ */ jsx("li", { style: { marginBottom: "2px" }, children: /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "danger600", children: [
544
594
  "Row ",
545
595
  err.row,
546
596
  ": ",
547
597
  err.error
548
- ] }) }, idx)) })
598
+ ] }) }, idx)) }),
599
+ importResult.stats.errors.length > 10 && /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", style: { display: "block", marginTop: 4, fontStyle: "italic" }, children: [
600
+ "...and ",
601
+ importResult.stats.errors.length - 10,
602
+ " more error",
603
+ importResult.stats.errors.length - 10 > 1 ? "s" : ""
604
+ ] })
605
+ ] }),
606
+ importResult.stats.diffs && importResult.stats.diffs.length > 0 && /* @__PURE__ */ jsxs(Box, { marginTop: 3, padding: 3, background: "neutral0", hasRadius: true, style: { border: "1px solid #dcdce4" }, children: [
607
+ /* @__PURE__ */ jsxs(Typography, { variant: "sigma", textColor: "neutral800", fontWeight: "bold", display: "block", marginBottom: 2, children: [
608
+ "CHANGES APPLIED (",
609
+ importResult.stats.diffs.length,
610
+ "):"
611
+ ] }),
612
+ /* @__PURE__ */ jsx(Box, { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsxs(Table, { colCount: 4, rowCount: importResult.stats.diffs.length + 1, children: [
613
+ /* @__PURE__ */ jsx(Thead, { children: /* @__PURE__ */ jsxs(Tr, { children: [
614
+ /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: "Entry / Document" }) }),
615
+ /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: "Attribute" }) }),
616
+ /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: "Previous Value" }) }),
617
+ /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: "Applied Value" }) })
618
+ ] }) }),
619
+ /* @__PURE__ */ jsx(Tbody, { children: importResult.stats.diffs.slice(0, 10).map((d, idx) => {
620
+ const oldDisplay = d.oldValue !== null && d.oldValue !== void 0 ? typeof d.oldValue === "object" ? JSON.stringify(d.oldValue) : String(d.oldValue) : "(empty)";
621
+ const newDisplay = d.newValue !== null && d.newValue !== void 0 ? typeof d.newValue === "object" ? JSON.stringify(d.newValue) : String(d.newValue) : "(empty)";
622
+ return /* @__PURE__ */ jsxs(Tr, { children: [
623
+ /* @__PURE__ */ jsxs(Td, { children: [
624
+ /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", children: d.label || d.documentId }),
625
+ d.documentId && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", display: "block", children: d.documentId })
626
+ ] }),
627
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Badge, { backgroundColor: "secondary100", textColor: "secondary700", children: d.attribute || "field" }) }),
628
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { textColor: "danger600", children: oldDisplay }) }),
629
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "semiBold", children: newDisplay }) })
630
+ ] }, idx);
631
+ }) })
632
+ ] }) }),
633
+ importResult.stats.diffs.length > 10 && /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", style: { display: "block", marginTop: 6, fontStyle: "italic" }, children: [
634
+ "...and ",
635
+ importResult.stats.diffs.length - 10,
636
+ " more change",
637
+ importResult.stats.diffs.length - 10 > 1 ? "s" : "",
638
+ " recorded in Audit Trail & Version History."
639
+ ] })
549
640
  ] })
550
641
  ]
551
642
  }
@@ -1508,9 +1599,72 @@ const BulkUpdatePreviewModal = ({
1508
1599
  }
1509
1600
  );
1510
1601
  };
1602
+ function parseDynamicZonePath(path) {
1603
+ if (!path) return { cleanPath: "", rootKey: "", subPath: "" };
1604
+ const bracketMatch = path.match(/^([^.[]+)\[([^\]]+)\]\.(.+)$/);
1605
+ if (bracketMatch) {
1606
+ const rootKey = bracketMatch[1];
1607
+ const selector = bracketMatch[2];
1608
+ const subPath = bracketMatch[3];
1609
+ const cleanPath = `${rootKey}.${subPath}`;
1610
+ if (/^\d+$/.test(selector)) {
1611
+ return { cleanPath, rootKey, subPath, targetIndex: parseInt(selector, 10) };
1612
+ }
1613
+ return { cleanPath, rootKey, subPath, targetComponentUid: selector };
1614
+ }
1615
+ const parts = path.split(".");
1616
+ return {
1617
+ cleanPath: path,
1618
+ rootKey: parts[0] || "",
1619
+ subPath: parts.slice(1).join(".")
1620
+ };
1621
+ }
1622
+ function formatComponentName(compUid) {
1623
+ if (!compUid) return "Component";
1624
+ const name = compUid.includes(".") ? compUid.split(".")[1] : compUid;
1625
+ return name.split(/[-_]/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
1626
+ }
1627
+ function getAllNestedValues(obj, path) {
1628
+ if (!obj || !path) return [];
1629
+ const parsed = parseDynamicZonePath(path);
1630
+ const parts = parsed.cleanPath.split(".");
1631
+ const [head, ...tail] = parts;
1632
+ const rootTarget = obj[head];
1633
+ if (Array.isArray(rootTarget)) {
1634
+ const results = [];
1635
+ rootTarget.forEach((item, idx) => {
1636
+ if (!item || typeof item !== "object") return;
1637
+ if (parsed.targetIndex !== void 0 && idx !== parsed.targetIndex) return;
1638
+ if (parsed.targetComponentUid && item.__component !== parsed.targetComponentUid) return;
1639
+ const subVal = tail.length > 0 ? getNestedValue(item, tail.join(".")) : item;
1640
+ if (subVal !== void 0) {
1641
+ results.push({
1642
+ index: idx,
1643
+ componentUid: item.__component,
1644
+ componentName: formatComponentName(item.__component),
1645
+ value: subVal,
1646
+ path: `${head}[#${idx}${item.__component ? ` ${formatComponentName(item.__component)}` : ""}].${tail.join(".")}`
1647
+ });
1648
+ }
1649
+ });
1650
+ return results;
1651
+ }
1652
+ const singleVal = getNestedValue(obj, parsed.cleanPath);
1653
+ if (singleVal !== void 0) {
1654
+ return [
1655
+ {
1656
+ index: 0,
1657
+ value: singleVal,
1658
+ path: parsed.cleanPath
1659
+ }
1660
+ ];
1661
+ }
1662
+ return [];
1663
+ }
1511
1664
  function getNestedValue(obj, path) {
1512
1665
  if (!obj || !path) return void 0;
1513
- const parts = path.split(".");
1666
+ const parsed = parseDynamicZonePath(path);
1667
+ const parts = parsed.cleanPath.split(".");
1514
1668
  function extract(current, remainingParts) {
1515
1669
  if (current === void 0 || current === null) return void 0;
1516
1670
  if (remainingParts.length === 0) return current;
@@ -1519,7 +1673,10 @@ function getNestedValue(obj, path) {
1519
1673
  if (/^\d+$/.test(head)) {
1520
1674
  return extract(current[parseInt(head, 10)], tail);
1521
1675
  }
1522
- for (const item of current) {
1676
+ for (let idx = 0; idx < current.length; idx++) {
1677
+ const item = current[idx];
1678
+ if (parsed.targetIndex !== void 0 && idx !== parsed.targetIndex) continue;
1679
+ if (parsed.targetComponentUid && item?.__component !== parsed.targetComponentUid) continue;
1523
1680
  const found = extract(item?.[head], tail);
1524
1681
  if (found !== void 0 && found !== null) return found;
1525
1682
  }
@@ -1549,7 +1706,18 @@ function getAvailableColumnsForCollection(col, selectedAttribute, searchAttribut
1549
1706
  if (attr === "name" || attr === "title" || attr === selectedAttribute || searchAttribute && attr === searchAttribute) {
1550
1707
  return;
1551
1708
  }
1552
- const formattedLabel = attr.includes(".") ? attr.split(".").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" > ") : attr.charAt(0).toUpperCase() + attr.slice(1);
1709
+ let formattedLabel = attr;
1710
+ const bracketMatch = attr.match(/^([^.[]+)\[([^\]]+)\]\.(.+)$/);
1711
+ if (bracketMatch) {
1712
+ const root = bracketMatch[1].charAt(0).toUpperCase() + bracketMatch[1].slice(1);
1713
+ const comp = formatComponentName(bracketMatch[2]);
1714
+ const sub = bracketMatch[3].split(".").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" > ");
1715
+ formattedLabel = `${root} [${comp}] > ${sub}`;
1716
+ } else if (attr.includes(".")) {
1717
+ formattedLabel = attr.split(".").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" > ");
1718
+ } else {
1719
+ formattedLabel = attr.charAt(0).toUpperCase() + attr.slice(1);
1720
+ }
1553
1721
  cols.push({
1554
1722
  key: `attr_${attr}`,
1555
1723
  label: formattedLabel,
@@ -1558,7 +1726,16 @@ function getAvailableColumnsForCollection(col, selectedAttribute, searchAttribut
1558
1726
  });
1559
1727
  });
1560
1728
  if (searchAttribute && searchAttribute !== selectedAttribute) {
1561
- const formattedSearchLabel = searchAttribute.includes(".") ? searchAttribute.split(".").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" > ") : searchAttribute;
1729
+ let formattedSearchLabel = searchAttribute;
1730
+ const bracketMatch = searchAttribute.match(/^([^.[]+)\[([^\]]+)\]\.(.+)$/);
1731
+ if (bracketMatch) {
1732
+ const root = bracketMatch[1].charAt(0).toUpperCase() + bracketMatch[1].slice(1);
1733
+ const comp = formatComponentName(bracketMatch[2]);
1734
+ const sub = bracketMatch[3].split(".").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" > ");
1735
+ formattedSearchLabel = `${root} [${comp}] > ${sub}`;
1736
+ } else if (searchAttribute.includes(".")) {
1737
+ formattedSearchLabel = searchAttribute.split(".").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" > ");
1738
+ }
1562
1739
  cols.push({
1563
1740
  key: "search_attr",
1564
1741
  label: `Search: "${formattedSearchLabel}"`,
@@ -1566,13 +1743,25 @@ function getAvailableColumnsForCollection(col, selectedAttribute, searchAttribut
1566
1743
  defaultVisible: true
1567
1744
  });
1568
1745
  }
1569
- const targetLabel = searchAttribute && searchAttribute !== selectedAttribute ? `Update Target: "${selectedAttribute}"` : `Current "${selectedAttribute}"`;
1570
- cols.push({
1571
- key: "target_attr",
1572
- label: targetLabel,
1573
- sortable: !col.isSingleType && col.attributes.includes(selectedAttribute),
1574
- defaultVisible: true
1575
- });
1746
+ if (selectedAttribute && selectedAttribute.trim()) {
1747
+ let formattedTargetLabel = selectedAttribute;
1748
+ const bracketMatch = selectedAttribute.match(/^([^.[]+)\[([^\]]+)\]\.(.+)$/);
1749
+ if (bracketMatch) {
1750
+ const root = bracketMatch[1].charAt(0).toUpperCase() + bracketMatch[1].slice(1);
1751
+ const comp = formatComponentName(bracketMatch[2]);
1752
+ const sub = bracketMatch[3].split(".").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" > ");
1753
+ formattedTargetLabel = `${root} [${comp}] > ${sub}`;
1754
+ } else if (selectedAttribute.includes(".")) {
1755
+ formattedTargetLabel = selectedAttribute.split(".").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" > ");
1756
+ }
1757
+ const targetLabel = searchAttribute && searchAttribute !== selectedAttribute ? `Update Target: "${formattedTargetLabel}"` : `Current "${formattedTargetLabel}"`;
1758
+ cols.push({
1759
+ key: "target_attr",
1760
+ label: targetLabel,
1761
+ sortable: !col.isSingleType && col.attributes.includes(selectedAttribute),
1762
+ defaultVisible: true
1763
+ });
1764
+ }
1576
1765
  cols.push({
1577
1766
  key: "status",
1578
1767
  label: "Status",
@@ -1629,7 +1818,68 @@ function formatDisplayValue(val) {
1629
1818
  }
1630
1819
  return String(val);
1631
1820
  }
1632
- function renderCellContent(colDef, entry, col, selectedAttribute, searchAttribute, isMatch, hasAttr, isSelected, onToggleSelect) {
1821
+ function getEntryLifecycleStatus(entry, col, pendingBatches = []) {
1822
+ const isPendingApproval = pendingBatches.some((b) => {
1823
+ if (b.status !== "pending_approval") return false;
1824
+ const targets = b.payload?.selectedEntries || [];
1825
+ return targets.some((t) => t.documentId === entry.documentId || String(t.documentId) === String(entry.id));
1826
+ });
1827
+ if (isPendingApproval) {
1828
+ return {
1829
+ status: "pending_review",
1830
+ label: "Pending Review",
1831
+ badgeColor: "warning100",
1832
+ textColor: "warning700"
1833
+ };
1834
+ }
1835
+ if (entry.status === "modified") {
1836
+ return {
1837
+ status: "modified",
1838
+ label: "Modified",
1839
+ badgeColor: "primary100",
1840
+ textColor: "primary700"
1841
+ };
1842
+ }
1843
+ if (entry.status === "draft") {
1844
+ return {
1845
+ status: "draft",
1846
+ label: "Draft",
1847
+ badgeColor: "neutral150",
1848
+ textColor: "neutral700"
1849
+ };
1850
+ }
1851
+ if (entry.status === "published") {
1852
+ return {
1853
+ status: "published",
1854
+ label: "Published",
1855
+ badgeColor: "success100",
1856
+ textColor: "success700"
1857
+ };
1858
+ }
1859
+ if (col && col.draftAndPublish === false) {
1860
+ return {
1861
+ status: "published",
1862
+ label: "Published",
1863
+ badgeColor: "success100",
1864
+ textColor: "success700"
1865
+ };
1866
+ }
1867
+ if (entry.publishedAt) {
1868
+ return {
1869
+ status: "published",
1870
+ label: "Published",
1871
+ badgeColor: "success100",
1872
+ textColor: "success700"
1873
+ };
1874
+ }
1875
+ return {
1876
+ status: "draft",
1877
+ label: "Draft",
1878
+ badgeColor: "neutral150",
1879
+ textColor: "neutral700"
1880
+ };
1881
+ }
1882
+ function renderCellContent(colDef, entry, col, selectedAttribute, searchAttribute, isMatch, hasAttr, isSelected, onToggleSelect, pendingBatches = [], isDzExpanded = false, onToggleExpandDz, filterQuery = "") {
1633
1883
  switch (colDef.key) {
1634
1884
  case "select":
1635
1885
  return /* @__PURE__ */ jsx(
@@ -1641,58 +1891,170 @@ function renderCellContent(colDef, entry, col, selectedAttribute, searchAttribut
1641
1891
  );
1642
1892
  case "identifier": {
1643
1893
  const mainText = entry.name || entry.title || `Entry #${entry.id || entry.documentId}`;
1894
+ const dzField = Object.keys(entry).find(
1895
+ (k) => Array.isArray(entry[k]) && entry[k].length > 0 && entry[k].some((item) => item && item.__component)
1896
+ );
1897
+ const dzItemsCount = dzField ? entry[dzField].length : 0;
1644
1898
  return /* @__PURE__ */ jsxs(Box, { children: [
1645
1899
  /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", children: mainText }),
1646
- entry.email && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", display: "block", children: entry.email })
1900
+ entry.email && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", display: "block", children: entry.email }),
1901
+ dzItemsCount > 0 && /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(
1902
+ Button,
1903
+ {
1904
+ variant: "ghost",
1905
+ size: "S",
1906
+ onClick: onToggleExpandDz,
1907
+ style: {
1908
+ padding: "2px 6px",
1909
+ height: "auto",
1910
+ fontSize: "0.72rem",
1911
+ color: isDzExpanded ? "#4945ff" : "#666687",
1912
+ backgroundColor: isDzExpanded ? "rgba(73, 69, 255, 0.08)" : "rgba(0, 0, 0, 0.04)",
1913
+ borderRadius: 4
1914
+ },
1915
+ children: isDzExpanded ? `▲ Hide ${dzField} (${dzItemsCount} blocks)` : `▼ View ${dzField} (${dzItemsCount} blocks)`
1916
+ }
1917
+ ) })
1647
1918
  ] });
1648
1919
  }
1649
1920
  case "search_attr": {
1650
- const val = getNestedValue(entry, searchAttribute);
1651
- const displayStr = formatDisplayValue(val);
1652
- const isUnset = displayStr === "(empty / not set)" || displayStr === "(empty / unlinked)";
1653
- return /* @__PURE__ */ jsx(
1654
- Typography,
1655
- {
1656
- textColor: isUnset ? "neutral500" : "primary700",
1657
- fontWeight: "semiBold",
1658
- style: {
1659
- fontStyle: isUnset ? "italic" : "normal",
1660
- display: "inline-block",
1661
- maxWidth: 260,
1662
- overflow: "hidden",
1663
- textOverflow: "ellipsis",
1664
- whiteSpace: "nowrap"
1921
+ const matches = getAllNestedValues(entry, searchAttribute);
1922
+ if (matches.length === 0) {
1923
+ return /* @__PURE__ */ jsx(Typography, { textColor: "neutral500", style: { fontStyle: "italic" }, children: "(empty / not set)" });
1924
+ }
1925
+ if (matches.length === 1 && !matches[0].componentUid) {
1926
+ const displayStr = formatDisplayValue(matches[0].value);
1927
+ const isUnset = displayStr === "(empty / not set)" || displayStr === "(empty / unlinked)";
1928
+ return /* @__PURE__ */ jsx(
1929
+ Typography,
1930
+ {
1931
+ textColor: isUnset ? "neutral500" : "primary700",
1932
+ fontWeight: "semiBold",
1933
+ style: {
1934
+ fontStyle: isUnset ? "italic" : "normal",
1935
+ display: "inline-block",
1936
+ maxWidth: 260,
1937
+ overflow: "hidden",
1938
+ textOverflow: "ellipsis",
1939
+ whiteSpace: "nowrap"
1940
+ },
1941
+ children: displayStr
1942
+ }
1943
+ );
1944
+ }
1945
+ const qLower = (filterQuery || "").trim().toLowerCase();
1946
+ return /* @__PURE__ */ jsx(Flex, { direction: "column", gap: 1, alignItems: "flex-start", style: { maxWidth: 320 }, children: matches.map((m) => {
1947
+ const displayStr = formatDisplayValue(m.value);
1948
+ const isMatchItem = qLower && displayStr.toLowerCase().includes(qLower);
1949
+ return /* @__PURE__ */ jsxs(
1950
+ Flex,
1951
+ {
1952
+ gap: 1,
1953
+ alignItems: "center",
1954
+ style: {
1955
+ backgroundColor: isMatchItem ? "rgba(46, 213, 115, 0.15)" : "rgba(0, 0, 0, 0.03)",
1956
+ padding: "2px 6px",
1957
+ borderRadius: 4,
1958
+ border: isMatchItem ? "1px solid #2ed573" : "1px solid transparent"
1959
+ },
1960
+ children: [
1961
+ /* @__PURE__ */ jsxs(Badge, { size: "S", backgroundColor: isMatchItem ? "success100" : "primary100", textColor: isMatchItem ? "success700" : "primary700", children: [
1962
+ "#",
1963
+ m.index,
1964
+ " ",
1965
+ m.componentName
1966
+ ] }),
1967
+ /* @__PURE__ */ jsx(
1968
+ Typography,
1969
+ {
1970
+ variant: "pi",
1971
+ fontWeight: isMatchItem ? "bold" : "normal",
1972
+ textColor: isMatchItem ? "success700" : "neutral800",
1973
+ style: {
1974
+ maxWidth: 200,
1975
+ overflow: "hidden",
1976
+ textOverflow: "ellipsis",
1977
+ whiteSpace: "nowrap"
1978
+ },
1979
+ children: displayStr
1980
+ }
1981
+ )
1982
+ ]
1665
1983
  },
1666
- children: displayStr
1667
- }
1668
- );
1984
+ m.index
1985
+ );
1986
+ }) });
1669
1987
  }
1670
1988
  case "target_attr": {
1671
- const val = getNestedValue(entry, selectedAttribute);
1672
- const displayStr = formatDisplayValue(val);
1673
- const isUnset = displayStr === "(empty / not set)" || displayStr === "(empty / unlinked)";
1674
- return /* @__PURE__ */ jsx(
1675
- Typography,
1676
- {
1677
- textColor: isUnset ? "neutral500" : "neutral800",
1678
- style: {
1679
- fontStyle: isUnset ? "italic" : "normal",
1680
- display: "inline-block",
1681
- maxWidth: 260,
1682
- overflow: "hidden",
1683
- textOverflow: "ellipsis",
1684
- whiteSpace: "nowrap"
1989
+ const matches = getAllNestedValues(entry, selectedAttribute);
1990
+ if (matches.length === 0) {
1991
+ return /* @__PURE__ */ jsx(Typography, { textColor: "neutral500", style: { fontStyle: "italic" }, children: "(empty / not set)" });
1992
+ }
1993
+ if (matches.length === 1 && !matches[0].componentUid) {
1994
+ const displayStr = formatDisplayValue(matches[0].value);
1995
+ const isUnset = displayStr === "(empty / not set)" || displayStr === "(empty / unlinked)";
1996
+ return /* @__PURE__ */ jsx(
1997
+ Typography,
1998
+ {
1999
+ textColor: isUnset ? "neutral500" : "neutral800",
2000
+ style: {
2001
+ fontStyle: isUnset ? "italic" : "normal",
2002
+ display: "inline-block",
2003
+ maxWidth: 260,
2004
+ overflow: "hidden",
2005
+ textOverflow: "ellipsis",
2006
+ whiteSpace: "nowrap"
2007
+ },
2008
+ children: displayStr
2009
+ }
2010
+ );
2011
+ }
2012
+ return /* @__PURE__ */ jsx(Flex, { direction: "column", gap: 1, alignItems: "flex-start", style: { maxWidth: 320 }, children: matches.map((m) => {
2013
+ const displayStr = formatDisplayValue(m.value);
2014
+ return /* @__PURE__ */ jsxs(
2015
+ Flex,
2016
+ {
2017
+ gap: 1,
2018
+ alignItems: "center",
2019
+ style: {
2020
+ backgroundColor: "rgba(0, 0, 0, 0.03)",
2021
+ padding: "2px 6px",
2022
+ borderRadius: 4
2023
+ },
2024
+ children: [
2025
+ /* @__PURE__ */ jsxs(Badge, { size: "S", backgroundColor: "neutral200", textColor: "neutral800", children: [
2026
+ "#",
2027
+ m.index,
2028
+ " ",
2029
+ m.componentName
2030
+ ] }),
2031
+ /* @__PURE__ */ jsx(
2032
+ Typography,
2033
+ {
2034
+ variant: "pi",
2035
+ textColor: "neutral800",
2036
+ style: {
2037
+ maxWidth: 200,
2038
+ overflow: "hidden",
2039
+ textOverflow: "ellipsis",
2040
+ whiteSpace: "nowrap"
2041
+ },
2042
+ children: displayStr
2043
+ }
2044
+ )
2045
+ ]
1685
2046
  },
1686
- children: displayStr
1687
- }
1688
- );
2047
+ m.index
2048
+ );
2049
+ }) });
1689
2050
  }
1690
2051
  case "status": {
1691
- if (!hasAttr) {
2052
+ if (selectedAttribute && !hasAttr) {
1692
2053
  return /* @__PURE__ */ jsx(Badge, { backgroundColor: "neutral200", textColor: "neutral600", children: "Ignored" });
1693
2054
  }
2055
+ const lifecycle = getEntryLifecycleStatus(entry, col, pendingBatches);
1694
2056
  return /* @__PURE__ */ jsxs(Flex, { gap: 1, alignItems: "center", children: [
1695
- /* @__PURE__ */ jsx(Badge, { backgroundColor: "success100", textColor: "success700", children: "Supported" }),
2057
+ /* @__PURE__ */ jsx(Badge, { backgroundColor: lifecycle.badgeColor, textColor: lifecycle.textColor, children: lifecycle.label }),
1696
2058
  isMatch && /* @__PURE__ */ jsx(Badge, { backgroundColor: "secondary100", textColor: "secondary700", children: "Matches Filter" })
1697
2059
  ] });
1698
2060
  }
@@ -1776,11 +2138,13 @@ const BulkUpdater = () => {
1776
2138
  if (stored) return stored;
1777
2139
  } catch {
1778
2140
  }
1779
- return "metaDescription";
2141
+ return "";
1780
2142
  };
1781
2143
  const [selectedAttribute, setSelectedAttribute] = useState(getInitialAttribute);
1782
2144
  const [attributeValue, setAttributeValue] = useState("");
1783
2145
  const [selectedEntries, setSelectedEntries] = useState({});
2146
+ const [expandedDzEntries, setExpandedDzEntries] = useState({});
2147
+ const [selectedDzBlocks, setSelectedDzBlocks] = useState({});
1784
2148
  const [relationsMeta, setRelationsMeta] = useState({});
1785
2149
  const [relationOptions, setRelationOptions] = useState([]);
1786
2150
  const [relationOptionsLoading, setRelationOptionsLoading] = useState(false);
@@ -1828,7 +2192,8 @@ const BulkUpdater = () => {
1828
2192
  const [filterOperator, setFilterOperator] = useState("none");
1829
2193
  const [filterQuery, setFilterQuery] = useState("");
1830
2194
  const [entrySearch, setEntrySearch] = useState("");
1831
- const isFilterActive = Boolean(searchAttribute && searchAttribute !== selectedAttribute) || filterOperator !== "none" && (["empty", "not_empty"].includes(filterOperator) || Boolean(filterQuery.trim())) || Boolean(entrySearch.trim()) || Boolean(useRegex && regexPattern.trim());
2195
+ const [statusFilter, setStatusFilter] = useState("all");
2196
+ const isFilterActive = Boolean(searchAttribute && searchAttribute !== selectedAttribute) || filterOperator !== "none" && (["empty", "not_empty"].includes(filterOperator) || Boolean(filterQuery.trim())) || Boolean(entrySearch.trim()) || Boolean(statusFilter !== "all") || Boolean(useRegex && regexPattern.trim());
1832
2197
  const [lastResults, setLastResults] = useState(null);
1833
2198
  const [updateSummary, setUpdateSummary] = useState(null);
1834
2199
  const [collectionPages, setCollectionPages] = useState({});
@@ -1934,7 +2299,7 @@ const BulkUpdater = () => {
1934
2299
  storedAttr = localStorage.getItem(LAST_ATTR_KEY);
1935
2300
  } catch {
1936
2301
  }
1937
- const resolvedAttr = storedAttr && activeAttrs.includes(storedAttr) ? storedAttr : selectedAttribute && activeAttrs.includes(selectedAttribute) ? selectedAttribute : activeAttrs[0] || "";
2302
+ const resolvedAttr = storedAttr && activeAttrs.includes(storedAttr) ? storedAttr : selectedAttribute && activeAttrs.includes(selectedAttribute) ? selectedAttribute : "";
1938
2303
  setSelectedAttribute(resolvedAttr);
1939
2304
  if (resolvedAttr && data.relationsMeta && data.relationsMeta[resolvedAttr]) {
1940
2305
  fetchRelationOptions(data.relationsMeta[resolvedAttr].targetUid);
@@ -1965,8 +2330,7 @@ const BulkUpdater = () => {
1965
2330
  }
1966
2331
  }
1967
2332
  } catch (err) {
1968
- const isAborted = err?.name === "AbortError" || err?.name === "CanceledError" || err?.code === "ERR_CANCELED" || err?.message?.includes("aborted") || err?.message?.includes("canceled");
1969
- if (!isAborted) {
2333
+ if (!isAbortError(err)) {
1970
2334
  toggleNotification({
1971
2335
  type: "danger",
1972
2336
  message: err?.message || "Failed to load collections data"
@@ -2043,8 +2407,7 @@ const BulkUpdater = () => {
2043
2407
  }
2044
2408
  }
2045
2409
  } catch (err) {
2046
- const isAborted = err?.name === "AbortError" || err?.name === "CanceledError" || err?.code === "ERR_CANCELED" || err?.message?.includes("aborted") || err?.message?.includes("canceled");
2047
- if (!isAborted) {
2410
+ if (!isAbortError(err)) {
2048
2411
  toggleNotification({
2049
2412
  type: "danger",
2050
2413
  message: `Failed to load entries for ${colUid}: ${err?.message || "Network error"}`
@@ -2073,8 +2436,7 @@ const BulkUpdater = () => {
2073
2436
  }
2074
2437
  }
2075
2438
  } catch (err) {
2076
- const isAborted = err?.name === "AbortError" || err?.name === "CanceledError" || err?.code === "ERR_CANCELED" || err?.message?.includes("aborted") || err?.message?.includes("canceled");
2077
- if (!isAborted) {
2439
+ if (!isAbortError(err)) {
2078
2440
  toggleNotification({
2079
2441
  type: "danger",
2080
2442
  message: err?.message || "Failed to fetch audit history."
@@ -2156,18 +2518,14 @@ const BulkUpdater = () => {
2156
2518
  const targetCol = collections.find((c) => c.uid === newUid);
2157
2519
  const colAttrs = targetCol?.attributes || [];
2158
2520
  setAttributes(colAttrs);
2159
- if (!colAttrs.includes(selectedAttribute)) {
2160
- const newAttr = colAttrs[0] || "";
2161
- setSelectedAttribute(newAttr);
2521
+ if (selectedAttribute && !colAttrs.includes(selectedAttribute)) {
2522
+ setSelectedAttribute("");
2162
2523
  try {
2163
- localStorage.setItem(LAST_ATTR_KEY, newAttr);
2524
+ localStorage.removeItem(LAST_ATTR_KEY);
2164
2525
  } catch {
2165
2526
  }
2166
- if (newAttr && relationsMeta[newAttr]) {
2167
- fetchRelationOptions(relationsMeta[newAttr].targetUid);
2168
- } else {
2169
- setSelectedRelationDocId("");
2170
- }
2527
+ setSelectedRelationDocId("");
2528
+ setAttributeValue("");
2171
2529
  }
2172
2530
  loadCollectionPage(newUid, 1, void 0, void 0, void 0, filterOperator, filterQuery, entrySearch, true, "");
2173
2531
  };
@@ -2182,10 +2540,6 @@ const BulkUpdater = () => {
2182
2540
  }
2183
2541
  } catch {
2184
2542
  }
2185
- setSelectedEntries({});
2186
- setFilterOperator("none");
2187
- setFilterQuery("");
2188
- setEntrySearch("");
2189
2543
  setSelectedRelationDocId("");
2190
2544
  setAttributeValue("");
2191
2545
  if (newAttr && relationsMeta[newAttr]) {
@@ -2193,9 +2547,6 @@ const BulkUpdater = () => {
2193
2547
  } else {
2194
2548
  setRelationOptions([]);
2195
2549
  }
2196
- if (newAttr && selectedCollectionUid) {
2197
- loadCollectionPage(selectedCollectionUid, 1);
2198
- }
2199
2550
  }
2200
2551
  };
2201
2552
  const filteredCollections = useMemo(() => {
@@ -2211,10 +2562,10 @@ const BulkUpdater = () => {
2211
2562
  return availableColAttributes.filter((attr) => getAttrDepth(attr) <= componentDepth);
2212
2563
  }, [availableColAttributes, componentDepth, attributesMeta]);
2213
2564
  const filteredAttributes = useMemo(() => {
2214
- if (!attributeSearch.trim()) {
2565
+ const q = attributeSearch.toLowerCase().trim();
2566
+ if (!q || q === (selectedAttribute || "").toLowerCase().trim()) {
2215
2567
  return depthFilteredAttributes;
2216
2568
  }
2217
- const q = attributeSearch.toLowerCase().trim();
2218
2569
  const cleanQ = q.replace(/[^a-z0-9]/g, "");
2219
2570
  return depthFilteredAttributes.filter((attr) => {
2220
2571
  const lower = attr.toLowerCase();
@@ -2223,12 +2574,12 @@ const BulkUpdater = () => {
2223
2574
  const relTarget = (rel?.targetDisplayName || "").toLowerCase();
2224
2575
  return lower.includes(q) || cleanLower.includes(cleanQ) || relTarget.includes(q);
2225
2576
  });
2226
- }, [depthFilteredAttributes, attributeSearch, relationsMeta]);
2577
+ }, [depthFilteredAttributes, attributeSearch, selectedAttribute, relationsMeta]);
2227
2578
  const filteredSearchAttributes = useMemo(() => {
2228
- if (!searchAttributeSearch.trim()) {
2579
+ const q = searchAttributeSearch.toLowerCase().trim();
2580
+ if (!q || q === (searchAttribute || "").toLowerCase().trim()) {
2229
2581
  return depthFilteredAttributes;
2230
2582
  }
2231
- const q = searchAttributeSearch.toLowerCase().trim();
2232
2583
  const cleanQ = q.replace(/[^a-z0-9]/g, "");
2233
2584
  return depthFilteredAttributes.filter((attr) => {
2234
2585
  const lower = attr.toLowerCase();
@@ -2237,7 +2588,7 @@ const BulkUpdater = () => {
2237
2588
  const relTarget = (rel?.targetDisplayName || "").toLowerCase();
2238
2589
  return lower.includes(q) || cleanLower.includes(cleanQ) || relTarget.includes(q);
2239
2590
  });
2240
- }, [depthFilteredAttributes, searchAttributeSearch, relationsMeta]);
2591
+ }, [depthFilteredAttributes, searchAttributeSearch, searchAttribute, relationsMeta]);
2241
2592
  const memoizedComboboxOptions = useMemo(() => {
2242
2593
  if (filteredAttributes.length === 0) {
2243
2594
  return /* @__PURE__ */ jsx(ComboboxOption, { value: "__none__", disabled: true, textValue: "No matching attributes found", children: /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", children: [
@@ -2336,61 +2687,100 @@ const BulkUpdater = () => {
2336
2687
  };
2337
2688
  const toggleEntry = (uid, documentId) => {
2338
2689
  const key = `${uid}${KEY_SEP}${documentId}`;
2690
+ const nextVal = !selectedEntries[key];
2339
2691
  setSelectedEntries((prev) => ({
2340
2692
  ...prev,
2341
- [key]: !prev[key]
2693
+ [key]: nextVal
2342
2694
  }));
2695
+ if (!nextVal) {
2696
+ setSelectedDzBlocks((prev) => {
2697
+ const copy = { ...prev };
2698
+ delete copy[key];
2699
+ return copy;
2700
+ });
2701
+ }
2702
+ };
2703
+ const toggleDzBlock = (uid, documentId, blockIndex, allApplicableIndexes) => {
2704
+ const key = `${uid}${KEY_SEP}${documentId}`;
2705
+ setSelectedDzBlocks((prev) => {
2706
+ const currentSelected = prev[key] !== void 0 ? prev[key] : [...allApplicableIndexes];
2707
+ let nextSelected;
2708
+ if (currentSelected.includes(blockIndex)) {
2709
+ nextSelected = currentSelected.filter((idx) => idx !== blockIndex);
2710
+ } else {
2711
+ nextSelected = [...currentSelected, blockIndex];
2712
+ }
2713
+ if (nextSelected.length > 0) {
2714
+ setSelectedEntries((e) => ({ ...e, [key]: true }));
2715
+ } else {
2716
+ setSelectedEntries((e) => ({ ...e, [key]: false }));
2717
+ }
2718
+ return {
2719
+ ...prev,
2720
+ [key]: nextSelected
2721
+ };
2722
+ });
2343
2723
  };
2344
2724
  const entryMatchesFilter = (entry, attr) => {
2725
+ const matches = getAllNestedValues(entry, attr);
2345
2726
  if (useRegex && regexPattern.trim()) {
2346
2727
  try {
2347
2728
  const regex = new RegExp(regexPattern, "i");
2348
- const targetSearchVal = formatDisplayValue(getNestedValue(entry, attr));
2349
- if (!regex.test(targetSearchVal)) {
2729
+ const anyRegexMatch = matches.some((m) => regex.test(formatDisplayValue(m.value)));
2730
+ if (!anyRegexMatch) {
2350
2731
  return false;
2351
2732
  }
2352
2733
  } catch {
2353
2734
  }
2354
2735
  }
2355
2736
  if (filterOperator === "none") return true;
2356
- const val = getNestedValue(entry, attr);
2357
- const displayStr = formatDisplayValue(val);
2358
- 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)";
2359
- switch (filterOperator) {
2360
- case "empty":
2361
- return isValEmpty;
2362
- case "not_empty":
2363
- return !isValEmpty;
2364
- case "equals":
2365
- return !isValEmpty && displayStr.trim().toLowerCase() === filterQuery.trim().toLowerCase();
2366
- case "contains":
2367
- return !isValEmpty && displayStr.toLowerCase().includes(filterQuery.trim().toLowerCase());
2368
- case "starts_with":
2369
- return !isValEmpty && displayStr.trim().toLowerCase().startsWith(filterQuery.trim().toLowerCase());
2370
- default:
2371
- return true;
2737
+ if (matches.length === 0) {
2738
+ return filterOperator === "empty";
2739
+ }
2740
+ const checkMatch = (val) => {
2741
+ const displayStr = formatDisplayValue(val);
2742
+ 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)";
2743
+ switch (filterOperator) {
2744
+ case "empty":
2745
+ return isValEmpty;
2746
+ case "not_empty":
2747
+ return !isValEmpty;
2748
+ case "equals":
2749
+ return !isValEmpty && displayStr.trim().toLowerCase() === filterQuery.trim().toLowerCase();
2750
+ case "contains":
2751
+ return !isValEmpty && displayStr.toLowerCase().includes(filterQuery.trim().toLowerCase());
2752
+ case "starts_with":
2753
+ return !isValEmpty && displayStr.trim().toLowerCase().startsWith(filterQuery.trim().toLowerCase());
2754
+ default:
2755
+ return true;
2756
+ }
2757
+ };
2758
+ if (filterOperator === "empty") {
2759
+ return matches.every((m) => checkMatch(m.value));
2372
2760
  }
2761
+ return matches.some((m) => checkMatch(m.value));
2373
2762
  };
2374
2763
  const getVisibleEntries = (col) => {
2375
2764
  const pageState = collectionPages[col.uid];
2376
- return pageState ? pageState.entries : col.entries || [];
2765
+ const raw = pageState ? pageState.entries : col.entries || [];
2766
+ if (statusFilter === "all") return raw;
2767
+ return raw.filter((entry) => {
2768
+ const lifecycle = getEntryLifecycleStatus(entry, col, pendingBatches);
2769
+ return lifecycle.status === statusFilter;
2770
+ });
2377
2771
  };
2378
2772
  const matchingEntriesCount = React__default.useMemo(() => {
2379
2773
  if (!isFilterActive) return 0;
2380
2774
  let count = 0;
2381
2775
  filteredCollections.forEach((col) => {
2382
- const pageState = collectionPages[col.uid];
2383
- if (pageState) {
2384
- count += pageState.total;
2385
- }
2776
+ count += getVisibleEntries(col).length;
2386
2777
  });
2387
2778
  return count;
2388
- }, [filteredCollections, collectionPages, isFilterActive]);
2779
+ }, [filteredCollections, collectionPages, isFilterActive, statusFilter, pendingBatches]);
2389
2780
  const selectAllMatching = () => {
2390
2781
  const updated = { ...selectedEntries };
2391
2782
  filteredCollections.forEach((col) => {
2392
- const pageState = collectionPages[col.uid];
2393
- const entries = pageState ? pageState.entries : col.entries || [];
2783
+ const entries = getVisibleEntries(col);
2394
2784
  entries.forEach((e) => {
2395
2785
  updated[`${col.uid}${KEY_SEP}${e.documentId}`] = true;
2396
2786
  });
@@ -2400,8 +2790,7 @@ const BulkUpdater = () => {
2400
2790
  const deselectAllMatching = () => {
2401
2791
  const updated = { ...selectedEntries };
2402
2792
  filteredCollections.forEach((col) => {
2403
- const pageState = collectionPages[col.uid];
2404
- const entries = pageState ? pageState.entries : col.entries || [];
2793
+ const entries = getVisibleEntries(col);
2405
2794
  entries.forEach((e) => {
2406
2795
  delete updated[`${col.uid}${KEY_SEP}${e.documentId}`];
2407
2796
  });
@@ -2414,6 +2803,7 @@ const BulkUpdater = () => {
2414
2803
  setFilterOperator("none");
2415
2804
  setFilterQuery("");
2416
2805
  setEntrySearch("");
2806
+ setStatusFilter("all");
2417
2807
  setRegexPattern("");
2418
2808
  setSelectedEntries({});
2419
2809
  collections.forEach((col) => {
@@ -2534,10 +2924,12 @@ const BulkUpdater = () => {
2534
2924
  throw new Error(res.data?.error || "Failed to generate preview");
2535
2925
  }
2536
2926
  } catch (err) {
2537
- toggleNotification({
2538
- type: "danger",
2539
- message: err.message || "Failed to fetch preview diffs"
2540
- });
2927
+ if (!isAbortError(err)) {
2928
+ toggleNotification({
2929
+ type: "danger",
2930
+ message: err.message || "Failed to fetch preview diffs"
2931
+ });
2932
+ }
2541
2933
  setShowPreviewModal(false);
2542
2934
  } finally {
2543
2935
  setPreviewLoading(false);
@@ -2549,7 +2941,11 @@ const BulkUpdater = () => {
2549
2941
  if (selectedEntries[key]) {
2550
2942
  const parts = key.split(KEY_SEP);
2551
2943
  if (parts.length === 2) {
2552
- targets.push({ uid: parts[0], documentId: parts[1] });
2944
+ const targetObj = { uid: parts[0], documentId: parts[1] };
2945
+ if (selectedDzBlocks[key] && selectedDzBlocks[key].length > 0) {
2946
+ targetObj.dynamicZoneIndexes = selectedDzBlocks[key];
2947
+ }
2948
+ targets.push(targetObj);
2553
2949
  }
2554
2950
  }
2555
2951
  });
@@ -2592,6 +2988,7 @@ const BulkUpdater = () => {
2592
2988
  setIsSubmittingBatch(false);
2593
2989
  if (res.data && res.data.success) {
2594
2990
  setSelectedEntries({});
2991
+ setSelectedDzBlocks({});
2595
2992
  const finalBatchId = res.data.batchId;
2596
2993
  setDashboardBatchId(finalBatchId);
2597
2994
  if (res.data.pending) {
@@ -3270,282 +3667,46 @@ const BulkUpdater = () => {
3270
3667
  marginBottom: 6,
3271
3668
  style: { width: "100%", maxWidth: "100%", minWidth: 0, boxSizing: "border-box" },
3272
3669
  children: [
3273
- /* @__PURE__ */ jsx(Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 4, wrap: "wrap", gap: 3, children: /* @__PURE__ */ jsxs(Box, { children: [
3274
- /* @__PURE__ */ jsx(Typography, { variant: "delta", tag: "h2", fontWeight: "semiBold", children: "1. Configure Attribute Update" }),
3275
- /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Select the target attribute to update and configure the replacement value." })
3276
- ] }) }),
3277
- /* @__PURE__ */ jsxs(Flex, { gap: 3, alignItems: "flex-end", wrap: "wrap", children: [
3278
- /* @__PURE__ */ jsx(Box, { style: { width: 280, minWidth: 230 }, children: /* @__PURE__ */ jsxs(Field.Root, { children: [
3279
- /* @__PURE__ */ jsx(Field.Label, { children: "Attribute to Update" }),
3280
- /* @__PURE__ */ jsx(
3281
- Combobox,
3282
- {
3283
- autocomplete: "none",
3284
- placeholder: "Search attribute by name or relation...",
3285
- value: selectedAttribute || void 0,
3286
- clearLabel: "Clear attribute selection",
3287
- onClear: () => {
3288
- handleAttributeChange("");
3289
- setAttributeSearch("");
3290
- },
3291
- onInputChange: (e) => {
3292
- setAttributeSearch(e.target.value);
3293
- },
3294
- onOpenChange: (isOpen) => {
3295
- if (!isOpen) {
3296
- setAttributeSearch("");
3297
- }
3298
- },
3299
- loading: loading && attributes.length === 0,
3300
- loadingMessage: "Discovering schema attributes...",
3301
- onChange: (val) => {
3302
- if (val && typeof val === "string" && val !== "__none__") {
3303
- handleAttributeChange(val);
3304
- setAttributeSearch("");
3305
- }
3306
- },
3307
- children: memoizedComboboxOptions
3308
- },
3309
- `update-attr-${selectedCollectionUid}-${selectedAttribute}`
3310
- )
3311
- ] }) }),
3312
- /* @__PURE__ */ jsx(Box, { style: { flex: 1, minWidth: 340 }, children: relationsMeta[selectedAttribute] ? /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 1, style: { width: "100%" }, children: [
3313
- /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
3314
- /* @__PURE__ */ jsxs(Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral700", children: [
3315
- "Target ",
3316
- relationsMeta[selectedAttribute].targetDisplayName,
3317
- " Relation:"
3318
- ] }),
3319
- /* @__PURE__ */ jsxs(Badge, { backgroundColor: "secondary100", textColor: "secondary700", children: [
3320
- relationsMeta[selectedAttribute].relationType,
3321
- " → ",
3322
- relationsMeta[selectedAttribute].targetDisplayName
3323
- ] }),
3324
- relationsMeta[selectedAttribute].isMulti && /* @__PURE__ */ jsx(Badge, { backgroundColor: "primary100", textColor: "primary700", children: "Multi-Relation" })
3325
- ] }),
3326
- /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", style: { width: "100%" }, children: [
3327
- /* @__PURE__ */ jsx(Box, { style: { flex: 1, minWidth: 200 }, children: /* @__PURE__ */ jsxs(Field.Root, { children: [
3328
- /* @__PURE__ */ jsx(Field.Label, { children: `Choose ${relationsMeta[selectedAttribute].targetDisplayName}` }),
3329
- /* @__PURE__ */ jsxs(
3330
- Combobox,
3331
- {
3332
- autocomplete: { type: "list", filter: "contains" },
3333
- placeholder: relationOptionsLoading ? "Loading entities..." : `Search & pick ${relationsMeta[selectedAttribute].targetDisplayName}...`,
3334
- value: selectedRelationDocId,
3335
- onChange: (val) => {
3336
- const docId = val ? String(val) : "";
3337
- setSelectedRelationDocId(docId);
3338
- if (docId === "__clear__") {
3339
- setAttributeValue(JSON.stringify({ mode: "clear", label: "(clear relation)" }));
3340
- } else {
3341
- const opt = relationOptions.find((o) => o.documentId === docId);
3342
- setAttributeValue(JSON.stringify({ mode: relationMode, documentIds: [docId], label: opt?.label || docId }));
3343
- }
3344
- },
3345
- children: [
3346
- /* @__PURE__ */ jsx(ComboboxOption, { value: "__clear__", textValue: "Clear / Unlink Relation", children: "-- Clear / Unlink Relation --" }),
3347
- relationOptions.map((opt) => /* @__PURE__ */ jsx(ComboboxOption, { value: opt.documentId, textValue: opt.label, children: opt.label }, opt.documentId))
3348
- ]
3349
- }
3350
- )
3351
- ] }) }),
3352
- relationsMeta[selectedAttribute].isMulti && /* @__PURE__ */ jsx(Box, { style: { width: 170 }, children: /* @__PURE__ */ jsxs(
3353
- SingleSelect,
3354
- {
3355
- label: "Action Mode",
3356
- value: relationMode,
3357
- onChange: (val) => {
3358
- const m = String(val);
3359
- setRelationMode(m);
3360
- if (selectedRelationDocId) {
3361
- if (selectedRelationDocId === "__clear__" || m === "clear") {
3362
- setAttributeValue(JSON.stringify({ mode: "clear", label: "(clear relation)" }));
3363
- } else {
3364
- const opt = relationOptions.find((o) => o.documentId === selectedRelationDocId);
3365
- setAttributeValue(JSON.stringify({ mode: m, documentIds: [selectedRelationDocId], label: opt?.label || selectedRelationDocId }));
3366
- }
3367
- }
3368
- },
3369
- children: [
3370
- /* @__PURE__ */ jsx(SingleSelectOption, { value: "set", children: "Set / Overwrite" }),
3371
- /* @__PURE__ */ jsx(SingleSelectOption, { value: "connect", children: "Add / Connect" }),
3372
- /* @__PURE__ */ jsx(SingleSelectOption, { value: "disconnect", children: "Remove / Disconnect" }),
3373
- /* @__PURE__ */ jsx(SingleSelectOption, { value: "clear", children: "Clear All" })
3374
- ]
3375
- }
3376
- ) })
3377
- ] })
3378
- ] }) : /* @__PURE__ */ jsx(
3379
- TextInput,
3380
- {
3381
- label: useRegex ? "Replacement Value" : "New Attribute Value",
3382
- name: "attributeValue",
3383
- placeholder: useRegex ? "Replace matched pattern with..." : "Enter the value to apply...",
3384
- value: attributeValue,
3385
- onChange: (e) => setAttributeValue(e.target.value)
3386
- }
3387
- ) }),
3388
- /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
3389
- /* @__PURE__ */ jsxs(
3390
- Button,
3391
- {
3392
- startIcon: /* @__PURE__ */ jsx(Eye, {}),
3393
- variant: "secondary",
3394
- size: "L",
3395
- onClick: handleOpenPreviewModal,
3396
- loading: previewLoading,
3397
- disabled: loading || totalSelectedCount === 0 || !selectedAttribute,
3398
- children: [
3399
- "Preview Changes (",
3400
- totalSelectedCount,
3401
- ")"
3402
- ]
3403
- }
3404
- ),
3405
- /* @__PURE__ */ jsxs(
3406
- Button,
3407
- {
3408
- startIcon: /* @__PURE__ */ jsx(Play, {}),
3409
- variant: "default",
3410
- size: "L",
3411
- onClick: handleOpenConfirmModal,
3412
- loading: updating,
3413
- disabled: loading || totalSelectedCount === 0 || !selectedAttribute,
3414
- children: [
3415
- "Update Selected (",
3416
- totalSelectedCount,
3417
- ")"
3418
- ]
3419
- }
3420
- ),
3421
- /* @__PURE__ */ jsxs(
3422
- Button,
3423
- {
3424
- startIcon: /* @__PURE__ */ jsx(Check, {}),
3425
- variant: "success-light",
3426
- size: "L",
3427
- onClick: handleOpenPublishModal,
3428
- loading: publishing,
3429
- disabled: loading || totalSelectedCount === 0,
3430
- title: "Directly publish selected draft records across collections",
3431
- children: [
3432
- "Publish Selected (",
3433
- totalSelectedCount,
3434
- ")"
3435
- ]
3436
- }
3437
- ),
3438
- /* @__PURE__ */ jsxs(
3439
- Button,
3440
- {
3441
- startIcon: /* @__PURE__ */ jsx(Download, {}),
3442
- variant: "tertiary",
3443
- size: "L",
3444
- onClick: handleBulkExportSelected,
3445
- loading: bulkExporting,
3446
- disabled: loading || totalSelectedCount === 0,
3447
- title: "Export selected entries to Excel-compatible CSV with full nested component support",
3448
- children: [
3449
- "Export Selected (",
3450
- totalSelectedCount,
3451
- ")"
3452
- ]
3453
- }
3454
- )
3455
- ] })
3456
- ] }),
3457
- /* @__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: [
3458
- /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
3459
- /* @__PURE__ */ jsx(
3460
- Checkbox,
3461
- {
3462
- checked: publishOnApproval,
3463
- onCheckedChange: (checked) => setPublishOnApproval(Boolean(checked)),
3464
- children: /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: "Auto-Publish after Update" })
3465
- }
3466
- ),
3467
- /* @__PURE__ */ jsx(
3468
- Badge,
3469
- {
3470
- backgroundColor: publishOnApproval ? "success100" : "warning100",
3471
- textColor: publishOnApproval ? "success700" : "warning700",
3472
- children: publishOnApproval ? "✓ LIVE PUBLISH" : "DRAFT ONLY"
3473
- }
3474
- )
3475
- ] }),
3476
- /* @__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." })
3477
- ] }) }),
3478
- selectedCol && selectedAttribute && /* @__PURE__ */ jsx(Box, { marginTop: 4, padding: 3, background: "neutral100", hasRadius: true, style: { border: "1px solid #eaeaef" }, children: /* @__PURE__ */ jsx(Flex, { justifyContent: "space-between", alignItems: "center", wrap: "wrap", gap: 3, children: /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
3479
- /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", children: "Target Selection:" }),
3480
- /* @__PURE__ */ jsxs(Badge, { backgroundColor: "primary100", textColor: "primary700", children: [
3481
- "Collection: ",
3482
- selectedCol.displayName
3483
- ] }),
3484
- /* @__PURE__ */ jsxs(Badge, { backgroundColor: "secondary100", textColor: "secondary700", children: [
3485
- "Attribute: ",
3486
- selectedAttribute,
3487
- " ",
3488
- attributesMeta[selectedAttribute]?.type ? `(${attributesMeta[selectedAttribute].type})` : ""
3489
- ] }),
3490
- attributesMeta[selectedAttribute]?.depth ? /* @__PURE__ */ jsxs(Badge, { backgroundColor: "neutral200", textColor: "neutral700", children: [
3491
- "Nesting Level: L",
3492
- attributesMeta[selectedAttribute].depth
3493
- ] }) : null,
3494
- selectedCol.draftAndPublish ? /* @__PURE__ */ jsx(Badge, { backgroundColor: "success100", textColor: "success700", children: "Draft & Publish Enabled" }) : /* @__PURE__ */ jsx(Badge, { backgroundColor: "warning100", textColor: "warning700", children: "Direct Publish Only" })
3495
- ] }) }) })
3496
- ]
3497
- }
3498
- ),
3499
- /* @__PURE__ */ jsxs(
3500
- Box,
3501
- {
3502
- padding: 6,
3503
- background: "neutral0",
3504
- shadow: "filterShadow",
3505
- hasRadius: true,
3506
- marginBottom: 6,
3507
- style: { width: "100%", maxWidth: "100%", minWidth: 0, boxSizing: "border-box" },
3508
- children: [
3509
- /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 4, wrap: "wrap", gap: 3, children: [
3510
- /* @__PURE__ */ jsxs(Box, { children: [
3511
- /* @__PURE__ */ jsx(Typography, { variant: "delta", tag: "h2", fontWeight: "semiBold", children: "2. Select Targets" }),
3512
- /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", children: [
3513
- "Search and select entries to apply the update to within ",
3514
- selectedCol ? selectedCol.displayName : "the selected collection",
3515
- "."
3516
- ] })
3517
- ] }),
3518
- /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3519
- /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "S", onClick: selectAll, children: "Select All" }),
3520
- /* @__PURE__ */ jsx(Button, { variant: "tertiary", size: "S", onClick: deselectAll, children: "Deselect All" })
3521
- ] })
3522
- ] }),
3523
- /* @__PURE__ */ jsx(
3524
- Box,
3525
- {
3526
- padding: 4,
3527
- background: "neutral100",
3528
- hasRadius: true,
3529
- marginBottom: 5,
3530
- style: { width: "100%", maxWidth: "100%", boxSizing: "border-box" },
3531
- children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 3, children: [
3532
- /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", wrap: "wrap", gap: 2, children: [
3533
- /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
3534
- /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "bold", children: "Search & Filter Targets:" }),
3535
- isFilterActive && /* @__PURE__ */ jsxs(Badge, { backgroundColor: "primary100", textColor: "primary700", children: [
3536
- matchingEntriesCount,
3537
- " matching ",
3538
- matchingEntriesCount === 1 ? "entry" : "entries",
3539
- " found in database"
3540
- ] }),
3541
- searchAttribute && searchAttribute !== selectedAttribute && /* @__PURE__ */ jsxs(Badge, { backgroundColor: "secondary100", textColor: "secondary700", children: [
3542
- "Searching by: ",
3543
- searchAttribute,
3544
- " → Target to update: ",
3545
- selectedAttribute
3546
- ] })
3547
- ] }),
3548
- isFilterActive && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "S", onClick: clearFilter, children: "Clear Search & Filter" })
3670
+ /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 4, wrap: "wrap", gap: 3, children: [
3671
+ /* @__PURE__ */ jsxs(Box, { children: [
3672
+ /* @__PURE__ */ jsx(Typography, { variant: "delta", tag: "h2", fontWeight: "semiBold", children: "1. Search & Filter Targets" }),
3673
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", children: [
3674
+ "Search, filter, and select entries within ",
3675
+ selectedCol ? selectedCol.displayName : "the selected collection",
3676
+ " before updating."
3677
+ ] })
3678
+ ] }),
3679
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3680
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "S", onClick: selectAll, children: "Select All" }),
3681
+ /* @__PURE__ */ jsx(Button, { variant: "tertiary", size: "S", onClick: deselectAll, children: "Deselect All" })
3682
+ ] })
3683
+ ] }),
3684
+ /* @__PURE__ */ jsx(
3685
+ Box,
3686
+ {
3687
+ padding: 4,
3688
+ background: "neutral100",
3689
+ hasRadius: true,
3690
+ marginBottom: 5,
3691
+ style: { width: "100%", maxWidth: "100%", boxSizing: "border-box" },
3692
+ children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 3, children: [
3693
+ /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", wrap: "wrap", gap: 2, children: [
3694
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
3695
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "bold", children: "Search & Filter Targets:" }),
3696
+ isFilterActive && /* @__PURE__ */ jsxs(Badge, { backgroundColor: "primary100", textColor: "primary700", children: [
3697
+ matchingEntriesCount,
3698
+ " matching ",
3699
+ matchingEntriesCount === 1 ? "entry" : "entries",
3700
+ " found in database"
3701
+ ] }),
3702
+ searchAttribute && searchAttribute !== selectedAttribute && /* @__PURE__ */ jsxs(Badge, { backgroundColor: "secondary100", textColor: "secondary700", children: [
3703
+ "Searching by: ",
3704
+ searchAttribute,
3705
+ " → Target to update: ",
3706
+ selectedAttribute
3707
+ ] })
3708
+ ] }),
3709
+ isFilterActive && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "S", onClick: clearFilter, children: "Clear Search & Filter" })
3549
3710
  ] }),
3550
3711
  /* @__PURE__ */ jsxs(Flex, { gap: 3, alignItems: "flex-end", wrap: "wrap", children: [
3551
3712
  /* @__PURE__ */ jsx(Box, { style: { width: 280, minWidth: 230 }, children: /* @__PURE__ */ jsxs(Field.Root, { children: [
@@ -3577,7 +3738,7 @@ const BulkUpdater = () => {
3577
3738
  },
3578
3739
  children: memoizedSearchComboboxOptions
3579
3740
  },
3580
- `search-attr-${selectedCollectionUid}-${searchAttribute}`
3741
+ `search-attr-${selectedCollectionUid}`
3581
3742
  )
3582
3743
  ] }) }),
3583
3744
  /* @__PURE__ */ jsx(Box, { style: { width: 200, minWidth: 170 }, children: /* @__PURE__ */ jsxs(
@@ -3614,6 +3775,21 @@ const BulkUpdater = () => {
3614
3775
  onChange: (e) => setEntrySearch(e.target.value)
3615
3776
  }
3616
3777
  ) }),
3778
+ /* @__PURE__ */ jsx(Box, { style: { width: 190, minWidth: 160 }, children: /* @__PURE__ */ jsxs(
3779
+ SingleSelect,
3780
+ {
3781
+ label: "Lifecycle Status",
3782
+ value: statusFilter,
3783
+ onChange: (val) => setStatusFilter(String(val)),
3784
+ children: [
3785
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "all", children: "All Statuses" }),
3786
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "pending_review", children: "Pending Review (Due)" }),
3787
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "draft", children: "Draft" }),
3788
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "published", children: "Published" }),
3789
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "modified", children: "Modified" })
3790
+ ]
3791
+ }
3792
+ ) }),
3617
3793
  isFilterActive && /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
3618
3794
  /* @__PURE__ */ jsx(
3619
3795
  Button,
@@ -4000,27 +4176,123 @@ const BulkUpdater = () => {
4000
4176
  const key = `${col.uid}${KEY_SEP}${entry.documentId}`;
4001
4177
  const isSelected = Boolean(selectedEntries[key]);
4002
4178
  const isMatch = isFilterActive;
4003
- return /* @__PURE__ */ jsx(
4004
- Tr,
4005
- {
4006
- style: {
4007
- backgroundColor: isSelected ? "rgba(73, 69, 255, 0.14)" : isMatch ? "rgba(46, 213, 115, 0.08)" : void 0,
4008
- boxShadow: isSelected ? "inset 3px 0 0 0 #4945ff" : isMatch ? "inset 3px 0 0 0 #2ed573" : void 0
4009
- },
4010
- children: activeColumns.map((colDef) => /* @__PURE__ */ jsx(Td, { children: renderCellContent(
4011
- colDef,
4012
- entry,
4013
- col,
4014
- selectedAttribute,
4015
- searchAttribute,
4016
- isMatch,
4017
- hasAttr,
4018
- isSelected,
4019
- () => toggleEntry(col.uid, entry.documentId)
4020
- ) }, colDef.key))
4021
- },
4022
- key
4179
+ const isDzExpanded = Boolean(expandedDzEntries[key]);
4180
+ const onToggleExpandDz = () => setExpandedDzEntries((prev) => ({
4181
+ ...prev,
4182
+ [key]: !prev[key]
4183
+ }));
4184
+ const dzFields = Object.keys(entry).filter(
4185
+ (k) => Array.isArray(entry[k]) && entry[k].length > 0 && entry[k].some((item) => item && item.__component)
4023
4186
  );
4187
+ return /* @__PURE__ */ jsxs(React__default.Fragment, { children: [
4188
+ /* @__PURE__ */ jsx(
4189
+ Tr,
4190
+ {
4191
+ style: {
4192
+ backgroundColor: isSelected ? "rgba(73, 69, 255, 0.14)" : isMatch ? "rgba(46, 213, 115, 0.08)" : void 0,
4193
+ boxShadow: isSelected ? "inset 3px 0 0 0 #4945ff" : isMatch ? "inset 3px 0 0 0 #2ed573" : void 0
4194
+ },
4195
+ children: activeColumns.map((colDef) => /* @__PURE__ */ jsx(Td, { children: renderCellContent(
4196
+ colDef,
4197
+ entry,
4198
+ col,
4199
+ selectedAttribute,
4200
+ searchAttribute,
4201
+ isMatch,
4202
+ hasAttr,
4203
+ isSelected,
4204
+ () => toggleEntry(col.uid, entry.documentId),
4205
+ pendingBatches,
4206
+ isDzExpanded,
4207
+ onToggleExpandDz,
4208
+ filterQuery
4209
+ ) }, colDef.key))
4210
+ }
4211
+ ),
4212
+ isDzExpanded && dzFields.map((dzKey) => {
4213
+ const blocks = entry[dzKey] || [];
4214
+ const targetParsed = parseDynamicZonePath(selectedAttribute);
4215
+ const allApplicableIndexes = blocks.map((_, i) => i).filter((i) => {
4216
+ if (!targetParsed.subPath) return true;
4217
+ return getNestedValue(blocks[i], targetParsed.subPath) !== void 0;
4218
+ });
4219
+ return /* @__PURE__ */ jsx(Tr, { children: /* @__PURE__ */ jsx(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__ */ jsxs(
4220
+ Box,
4221
+ {
4222
+ padding: 3,
4223
+ background: "neutral0",
4224
+ hasRadius: true,
4225
+ style: { border: "1px solid rgba(73, 69, 255, 0.25)", boxShadow: "0 2px 8px rgba(0,0,0,0.05)" },
4226
+ children: [
4227
+ /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 2, children: [
4228
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
4229
+ /* @__PURE__ */ jsxs(Typography, { variant: "sigma", textColor: "primary700", children: [
4230
+ 'DYNAMIC ZONE: "',
4231
+ dzKey,
4232
+ '" (',
4233
+ blocks.length,
4234
+ " blocks)"
4235
+ ] }),
4236
+ /* @__PURE__ */ jsx(Badge, { backgroundColor: "primary100", textColor: "primary700", children: "Selective Block Targeting" })
4237
+ ] }),
4238
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: "Selectively choose which blocks to update for this entry" })
4239
+ ] }),
4240
+ /* @__PURE__ */ jsxs(Table, { colCount: 5, rowCount: blocks.length + 1, style: { width: "100%", background: "#fff" }, children: [
4241
+ /* @__PURE__ */ jsx(Thead, { children: /* @__PURE__ */ jsxs(Tr, { children: [
4242
+ /* @__PURE__ */ jsx(Th, { style: { width: 64 }, children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: "Update?" }) }),
4243
+ /* @__PURE__ */ jsx(Th, { style: { width: 60 }, children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: "Pos" }) }),
4244
+ /* @__PURE__ */ jsx(Th, { style: { width: 220 }, children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: "Component" }) }),
4245
+ /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsxs(Typography, { variant: "sigma", children: [
4246
+ "Target Field Value (",
4247
+ selectedAttribute || "selected",
4248
+ ")"
4249
+ ] }) }),
4250
+ /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: "Block Summary" }) })
4251
+ ] }) }),
4252
+ /* @__PURE__ */ jsx(Tbody, { children: blocks.map((block, bIdx) => {
4253
+ const compUid = block.__component;
4254
+ const compLabel = formatComponentName(compUid);
4255
+ const blockVal = targetParsed.subPath ? getNestedValue(block, targetParsed.subPath) : void 0;
4256
+ const hasTargetAttr = blockVal !== void 0;
4257
+ const isBlockChecked = hasTargetAttr && isSelected && (selectedDzBlocks[key] !== void 0 ? selectedDzBlocks[key].includes(bIdx) : true);
4258
+ return /* @__PURE__ */ jsxs(
4259
+ Tr,
4260
+ {
4261
+ style: {
4262
+ backgroundColor: isBlockChecked ? "rgba(73, 69, 255, 0.08)" : void 0
4263
+ },
4264
+ children: [
4265
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(
4266
+ Checkbox,
4267
+ {
4268
+ checked: isBlockChecked,
4269
+ disabled: !hasTargetAttr,
4270
+ onCheckedChange: () => {
4271
+ toggleDzBlock(col.uid, entry.documentId, bIdx, allApplicableIndexes);
4272
+ }
4273
+ }
4274
+ ) }),
4275
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsxs(Typography, { variant: "pi", fontWeight: "bold", children: [
4276
+ "#",
4277
+ bIdx
4278
+ ] }) }),
4279
+ /* @__PURE__ */ jsxs(Td, { children: [
4280
+ /* @__PURE__ */ jsx(Badge, { backgroundColor: "neutral150", textColor: "neutral800", children: compLabel }),
4281
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", display: "block", style: { fontSize: "0.68rem", marginTop: 2 }, children: compUid })
4282
+ ] }),
4283
+ /* @__PURE__ */ jsx(Td, { children: hasTargetAttr ? /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "semiBold", textColor: "primary700", children: formatDisplayValue(blockVal) }) : /* @__PURE__ */ jsx(Badge, { backgroundColor: "neutral100", textColor: "neutral500", children: "Does not contain attribute" }) }),
4284
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(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(", ") || "-" }) })
4285
+ ]
4286
+ },
4287
+ bIdx
4288
+ );
4289
+ }) })
4290
+ ] })
4291
+ ]
4292
+ }
4293
+ ) }) }, `${key}-dz-${dzKey}`);
4294
+ })
4295
+ ] }, key);
4024
4296
  }) })
4025
4297
  ] }) }),
4026
4298
  !col.isSingleType && /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", marginTop: 4, wrap: "wrap", gap: 3, children: [
@@ -4107,6 +4379,242 @@ const BulkUpdater = () => {
4107
4379
  ]
4108
4380
  }
4109
4381
  ),
4382
+ /* @__PURE__ */ jsxs(
4383
+ Box,
4384
+ {
4385
+ padding: 6,
4386
+ background: "neutral0",
4387
+ shadow: "filterShadow",
4388
+ hasRadius: true,
4389
+ marginBottom: 6,
4390
+ style: { width: "100%", maxWidth: "100%", minWidth: 0, boxSizing: "border-box" },
4391
+ children: [
4392
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 4, wrap: "wrap", gap: 3, children: /* @__PURE__ */ jsxs(Box, { children: [
4393
+ /* @__PURE__ */ jsx(Typography, { variant: "delta", tag: "h2", fontWeight: "semiBold", children: "2. Configure Attribute Update" }),
4394
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Select the target attribute to update and configure the replacement value for your selected entries." })
4395
+ ] }) }),
4396
+ /* @__PURE__ */ jsxs(Flex, { gap: 3, alignItems: "flex-end", wrap: "wrap", children: [
4397
+ /* @__PURE__ */ jsx(Box, { style: { width: 280, minWidth: 230 }, children: /* @__PURE__ */ jsxs(Field.Root, { children: [
4398
+ /* @__PURE__ */ jsx(Field.Label, { children: "Attribute to Update" }),
4399
+ /* @__PURE__ */ jsx(
4400
+ Combobox,
4401
+ {
4402
+ autocomplete: "none",
4403
+ placeholder: "Search attribute by name or relation...",
4404
+ value: selectedAttribute || void 0,
4405
+ clearLabel: "Clear attribute selection",
4406
+ onClear: () => {
4407
+ handleAttributeChange("");
4408
+ setAttributeSearch("");
4409
+ },
4410
+ onInputChange: (e) => {
4411
+ setAttributeSearch(e.target.value);
4412
+ },
4413
+ onOpenChange: (isOpen) => {
4414
+ if (!isOpen) {
4415
+ setAttributeSearch("");
4416
+ }
4417
+ },
4418
+ loading: loading && attributes.length === 0,
4419
+ loadingMessage: "Discovering schema attributes...",
4420
+ onChange: (val) => {
4421
+ if (val && typeof val === "string" && val !== "__none__") {
4422
+ handleAttributeChange(val);
4423
+ setAttributeSearch("");
4424
+ }
4425
+ },
4426
+ children: memoizedComboboxOptions
4427
+ },
4428
+ `update-attr-${selectedCollectionUid}`
4429
+ )
4430
+ ] }) }),
4431
+ /* @__PURE__ */ jsx(Box, { style: { flex: 1, minWidth: 340 }, children: relationsMeta[selectedAttribute] ? /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 1, style: { width: "100%" }, children: [
4432
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
4433
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral700", children: [
4434
+ "Target ",
4435
+ relationsMeta[selectedAttribute].targetDisplayName,
4436
+ " Relation:"
4437
+ ] }),
4438
+ /* @__PURE__ */ jsxs(Badge, { backgroundColor: "secondary100", textColor: "secondary700", children: [
4439
+ relationsMeta[selectedAttribute].relationType,
4440
+ " → ",
4441
+ relationsMeta[selectedAttribute].targetDisplayName
4442
+ ] }),
4443
+ relationsMeta[selectedAttribute].isMulti && /* @__PURE__ */ jsx(Badge, { backgroundColor: "primary100", textColor: "primary700", children: "Multi-Relation" })
4444
+ ] }),
4445
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", style: { width: "100%" }, children: [
4446
+ /* @__PURE__ */ jsx(Box, { style: { flex: 1, minWidth: 200 }, children: /* @__PURE__ */ jsxs(Field.Root, { children: [
4447
+ /* @__PURE__ */ jsx(Field.Label, { children: `Choose ${relationsMeta[selectedAttribute].targetDisplayName}` }),
4448
+ /* @__PURE__ */ jsxs(
4449
+ Combobox,
4450
+ {
4451
+ autocomplete: { type: "list", filter: "contains" },
4452
+ placeholder: relationOptionsLoading ? "Loading entities..." : `Search & pick ${relationsMeta[selectedAttribute].targetDisplayName}...`,
4453
+ value: selectedRelationDocId,
4454
+ onChange: (val) => {
4455
+ const docId = val ? String(val) : "";
4456
+ setSelectedRelationDocId(docId);
4457
+ if (docId === "__clear__") {
4458
+ setAttributeValue(JSON.stringify({ mode: "clear", label: "(clear relation)" }));
4459
+ } else {
4460
+ const opt = relationOptions.find((o) => o.documentId === docId);
4461
+ setAttributeValue(JSON.stringify({ mode: relationMode, documentIds: [docId], label: opt?.label || docId }));
4462
+ }
4463
+ },
4464
+ children: [
4465
+ /* @__PURE__ */ jsx(ComboboxOption, { value: "__clear__", textValue: "Clear / Unlink Relation", children: "-- Clear / Unlink Relation --" }),
4466
+ relationOptions.map((opt) => /* @__PURE__ */ jsx(ComboboxOption, { value: opt.documentId, textValue: opt.label, children: opt.label }, opt.documentId))
4467
+ ]
4468
+ }
4469
+ )
4470
+ ] }) }),
4471
+ relationsMeta[selectedAttribute].isMulti && /* @__PURE__ */ jsx(Box, { style: { width: 170 }, children: /* @__PURE__ */ jsxs(
4472
+ SingleSelect,
4473
+ {
4474
+ label: "Action Mode",
4475
+ value: relationMode,
4476
+ onChange: (val) => {
4477
+ const m = String(val);
4478
+ setRelationMode(m);
4479
+ if (selectedRelationDocId) {
4480
+ if (selectedRelationDocId === "__clear__" || m === "clear") {
4481
+ setAttributeValue(JSON.stringify({ mode: "clear", label: "(clear relation)" }));
4482
+ } else {
4483
+ const opt = relationOptions.find((o) => o.documentId === selectedRelationDocId);
4484
+ setAttributeValue(JSON.stringify({ mode: m, documentIds: [selectedRelationDocId], label: opt?.label || selectedRelationDocId }));
4485
+ }
4486
+ }
4487
+ },
4488
+ children: [
4489
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "set", children: "Set / Overwrite" }),
4490
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "connect", children: "Add / Connect" }),
4491
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "disconnect", children: "Remove / Disconnect" }),
4492
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "clear", children: "Clear All" })
4493
+ ]
4494
+ }
4495
+ ) })
4496
+ ] })
4497
+ ] }) : /* @__PURE__ */ jsx(
4498
+ TextInput,
4499
+ {
4500
+ label: useRegex ? "Replacement Value" : "New Attribute Value",
4501
+ name: "attributeValue",
4502
+ placeholder: useRegex ? "Replace matched pattern with..." : "Enter the value to apply...",
4503
+ value: attributeValue,
4504
+ onChange: (e) => setAttributeValue(e.target.value)
4505
+ }
4506
+ ) }),
4507
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
4508
+ /* @__PURE__ */ jsxs(
4509
+ Button,
4510
+ {
4511
+ startIcon: /* @__PURE__ */ jsx(Eye, {}),
4512
+ variant: "secondary",
4513
+ size: "L",
4514
+ onClick: handleOpenPreviewModal,
4515
+ loading: previewLoading,
4516
+ disabled: loading || totalSelectedCount === 0 || !selectedAttribute || !selectedAttribute.trim(),
4517
+ children: [
4518
+ "Preview Changes (",
4519
+ totalSelectedCount,
4520
+ ")"
4521
+ ]
4522
+ }
4523
+ ),
4524
+ /* @__PURE__ */ jsxs(
4525
+ Button,
4526
+ {
4527
+ startIcon: /* @__PURE__ */ jsx(Play, {}),
4528
+ variant: "default",
4529
+ size: "L",
4530
+ onClick: handleOpenConfirmModal,
4531
+ loading: updating,
4532
+ disabled: loading || totalSelectedCount === 0 || !selectedAttribute || !selectedAttribute.trim(),
4533
+ children: [
4534
+ "Update Selected (",
4535
+ totalSelectedCount,
4536
+ ")"
4537
+ ]
4538
+ }
4539
+ ),
4540
+ /* @__PURE__ */ jsxs(
4541
+ Button,
4542
+ {
4543
+ startIcon: /* @__PURE__ */ jsx(Check, {}),
4544
+ variant: "success-light",
4545
+ size: "L",
4546
+ onClick: handleOpenPublishModal,
4547
+ loading: publishing,
4548
+ disabled: loading || totalSelectedCount === 0,
4549
+ title: "Directly publish selected draft records across collections",
4550
+ children: [
4551
+ "Publish Selected (",
4552
+ totalSelectedCount,
4553
+ ")"
4554
+ ]
4555
+ }
4556
+ ),
4557
+ /* @__PURE__ */ jsxs(
4558
+ Button,
4559
+ {
4560
+ startIcon: /* @__PURE__ */ jsx(Download, {}),
4561
+ variant: "tertiary",
4562
+ size: "L",
4563
+ onClick: handleBulkExportSelected,
4564
+ loading: bulkExporting,
4565
+ disabled: loading || totalSelectedCount === 0,
4566
+ title: "Export selected entries to Excel-compatible CSV with full nested component support",
4567
+ children: [
4568
+ "Export Selected (",
4569
+ totalSelectedCount,
4570
+ ")"
4571
+ ]
4572
+ }
4573
+ )
4574
+ ] })
4575
+ ] }),
4576
+ /* @__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: [
4577
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
4578
+ /* @__PURE__ */ jsx(
4579
+ Checkbox,
4580
+ {
4581
+ checked: publishOnApproval,
4582
+ onCheckedChange: (checked) => setPublishOnApproval(Boolean(checked)),
4583
+ children: /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: "Auto-Publish after Update" })
4584
+ }
4585
+ ),
4586
+ /* @__PURE__ */ jsx(
4587
+ Badge,
4588
+ {
4589
+ backgroundColor: publishOnApproval ? "success100" : "warning100",
4590
+ textColor: publishOnApproval ? "success700" : "warning700",
4591
+ children: publishOnApproval ? "✓ LIVE PUBLISH" : "DRAFT ONLY"
4592
+ }
4593
+ )
4594
+ ] }),
4595
+ /* @__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." })
4596
+ ] }) }),
4597
+ selectedCol && selectedAttribute && /* @__PURE__ */ jsx(Box, { marginTop: 4, padding: 3, background: "neutral100", hasRadius: true, style: { border: "1px solid #eaeaef" }, children: /* @__PURE__ */ jsx(Flex, { justifyContent: "space-between", alignItems: "center", wrap: "wrap", gap: 3, children: /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
4598
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", children: "Target Selection:" }),
4599
+ /* @__PURE__ */ jsxs(Badge, { backgroundColor: "primary100", textColor: "primary700", children: [
4600
+ "Collection: ",
4601
+ selectedCol.displayName
4602
+ ] }),
4603
+ /* @__PURE__ */ jsxs(Badge, { backgroundColor: "secondary100", textColor: "secondary700", children: [
4604
+ "Attribute: ",
4605
+ selectedAttribute,
4606
+ " ",
4607
+ attributesMeta[selectedAttribute]?.type ? `(${attributesMeta[selectedAttribute].type})` : ""
4608
+ ] }),
4609
+ attributesMeta[selectedAttribute]?.depth ? /* @__PURE__ */ jsxs(Badge, { backgroundColor: "neutral200", textColor: "neutral700", children: [
4610
+ "Nesting Level: L",
4611
+ attributesMeta[selectedAttribute].depth
4612
+ ] }) : null,
4613
+ selectedCol.draftAndPublish ? /* @__PURE__ */ jsx(Badge, { backgroundColor: "success100", textColor: "success700", children: "Draft & Publish Enabled" }) : /* @__PURE__ */ jsx(Badge, { backgroundColor: "warning100", textColor: "warning700", children: "Direct Publish Only" })
4614
+ ] }) }) })
4615
+ ]
4616
+ }
4617
+ ),
4110
4618
  updateSummary && /* @__PURE__ */ jsxs(
4111
4619
  Box,
4112
4620
  {
@@ -4371,25 +4879,44 @@ const BulkUpdater = () => {
4371
4879
  /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", children: rec.userName }),
4372
4880
  /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", display: "block", style: { wordBreak: "break-all" }, children: rec.userEmail })
4373
4881
  ] }),
4374
- /* @__PURE__ */ jsx(Td, { style: { minWidth: 160 }, children: /* @__PURE__ */ jsxs(
4375
- Typography,
4376
- {
4377
- style: {
4378
- display: "inline-block",
4379
- maxWidth: "100%",
4380
- overflow: "hidden",
4381
- textOverflow: "ellipsis",
4382
- whiteSpace: "nowrap"
4383
- },
4384
- title: `${rec.attribute} → "${formatDisplayValue(rec.value)}"`,
4385
- children: [
4386
- /* @__PURE__ */ jsx("strong", { children: rec.attribute }),
4387
- " → “",
4388
- formatDisplayValue(rec.value),
4389
- "”"
4390
- ]
4882
+ /* @__PURE__ */ jsx(Td, { style: { minWidth: 200 }, children: (() => {
4883
+ const isCsv = rec.attribute === "CSV_IMPORT" || rec.attribute?.startsWith("CSV");
4884
+ let attrText = rec.attribute;
4885
+ let valText = formatDisplayValue(rec.value);
4886
+ if (rec.attribute === "CSV_IMPORT" && rec.diffs && rec.diffs.length > 0) {
4887
+ const colName = rec.diffs[0]?.collectionName || "Collection";
4888
+ const attrs = Array.from(new Set(rec.diffs.map((d) => d.attribute).filter(Boolean))).join(", ");
4889
+ attrText = `CSV [${colName}]: ${attrs || "fields"}`;
4890
+ if (rec.value.startsWith("Mode:") && rec.diffs.length === 1) {
4891
+ const d = rec.diffs[0];
4892
+ valText = `"${d.label || d.documentId}": ${d.attribute || "field"} → "${formatDisplayValue(d.newValue)}"`;
4893
+ } else if (rec.value.startsWith("Mode:")) {
4894
+ valText = `${rec.diffs.length} attribute${rec.diffs.length > 1 ? "s" : ""} updated in ${colName}`;
4895
+ }
4391
4896
  }
4392
- ) }),
4897
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
4898
+ isCsv && /* @__PURE__ */ jsx(Badge, { backgroundColor: "secondary100", textColor: "secondary700", children: "CSV IMPORT" }),
4899
+ /* @__PURE__ */ jsxs(
4900
+ Typography,
4901
+ {
4902
+ style: {
4903
+ display: "inline-block",
4904
+ maxWidth: "100%",
4905
+ overflow: "hidden",
4906
+ textOverflow: "ellipsis",
4907
+ whiteSpace: "nowrap"
4908
+ },
4909
+ title: `${attrText} → "${valText}"`,
4910
+ children: [
4911
+ /* @__PURE__ */ jsx("strong", { children: attrText.replace(/^CSV\s*\[?([^\]]+)\]?:\s*/, "$1: ") }),
4912
+ " → “",
4913
+ valText,
4914
+ "”"
4915
+ ]
4916
+ }
4917
+ )
4918
+ ] });
4919
+ })() }),
4393
4920
  /* @__PURE__ */ jsxs(Td, { style: { minWidth: 90, whiteSpace: "nowrap" }, children: [
4394
4921
  /* @__PURE__ */ jsxs(Badge, { backgroundColor: "success100", textColor: "success700", children: [
4395
4922
  rec.updatedCount,
@@ -4462,18 +4989,20 @@ const BulkUpdater = () => {
4462
4989
  rec.batchId,
4463
4990
  ":"
4464
4991
  ] }),
4465
- /* @__PURE__ */ jsxs(Table, { colCount: 4, rowCount: rec.diffs.length + 1, children: [
4992
+ /* @__PURE__ */ jsxs(Table, { colCount: 5, rowCount: rec.diffs.length + 1, children: [
4466
4993
  /* @__PURE__ */ jsx(Thead, { children: /* @__PURE__ */ jsxs(Tr, { children: [
4467
4994
  /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: "Collection" }) }),
4468
4995
  /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: "Document / Entry" }) }),
4996
+ /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: "Attribute" }) }),
4469
4997
  /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: "Previous Value" }) }),
4470
4998
  /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: "Applied Value" }) })
4471
4999
  ] }) }),
4472
5000
  /* @__PURE__ */ jsx(Tbody, { children: rec.diffs.map((d, dIdx) => /* @__PURE__ */ jsxs(Tr, { children: [
4473
5001
  /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", children: d.collectionName }) }),
4474
5002
  /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { children: d.label }) }),
5003
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Badge, { backgroundColor: "secondary100", textColor: "secondary700", children: d.attribute || "field" }) }),
4475
5004
  /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { textColor: "danger600", children: formatDisplayValue(d.oldValue) }) }),
4476
- /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { textColor: "success600", children: formatDisplayValue(d.newValue) }) })
5005
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "semiBold", children: formatDisplayValue(d.newValue) }) })
4477
5006
  ] }, dIdx)) })
4478
5007
  ] })
4479
5008
  ]
@@ -4984,8 +5513,12 @@ const BulkUpdater = () => {
4984
5513
  };
4985
5514
  export {
4986
5515
  BulkUpdater as default,
5516
+ formatComponentName,
4987
5517
  formatDisplayValue,
5518
+ getAllNestedValues,
4988
5519
  getAvailableColumnsForCollection,
4989
- getNestedValue
5520
+ getEntryLifecycleStatus,
5521
+ getNestedValue,
5522
+ parseDynamicZonePath
4990
5523
  };
4991
- //# sourceMappingURL=BulkUpdater-J21ZgJWx.mjs.map
5524
+ //# sourceMappingURL=BulkUpdater-CbQk_OQG.mjs.map