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