strapi-plugin-bulk-updater 1.2.12 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -4
- package/dist/_chunks/{BulkUpdater-CQ9zGdat.js → BulkUpdater-CRvwX326.js} +344 -39
- package/dist/_chunks/BulkUpdater-CRvwX326.js.map +1 -0
- package/dist/_chunks/{BulkUpdater-DvCSr1vU.mjs → BulkUpdater-DowSmA56.mjs} +344 -39
- package/dist/_chunks/BulkUpdater-DowSmA56.mjs.map +1 -0
- package/dist/_chunks/{SettingsPage-BRGTrW9H.js → SettingsPage-BAvuOb7V.js} +2 -2
- package/dist/_chunks/{SettingsPage-BRGTrW9H.js.map → SettingsPage-BAvuOb7V.js.map} +1 -1
- package/dist/_chunks/{SettingsPage-ieu-Out8.mjs → SettingsPage-BWo4l6Gd.mjs} +2 -2
- package/dist/_chunks/{SettingsPage-ieu-Out8.mjs.map → SettingsPage-BWo4l6Gd.mjs.map} +1 -1
- package/dist/_chunks/{ValidationRulesTab-BoqhoTjo.js → ValidationRulesTab-BLZWPGrZ.js} +3 -2
- package/dist/_chunks/{ValidationRulesTab-BoqhoTjo.js.map → ValidationRulesTab-BLZWPGrZ.js.map} +1 -1
- package/dist/_chunks/{ValidationRulesTab-BGcqM9cN.mjs → ValidationRulesTab-Dt53h-Ke.mjs} +3 -2
- package/dist/_chunks/{ValidationRulesTab-BGcqM9cN.mjs.map → ValidationRulesTab-Dt53h-Ke.mjs.map} +1 -1
- package/dist/admin/index.js +2 -2
- package/dist/admin/index.mjs +2 -2
- package/dist/server/index.js +480 -170
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +480 -170
- package/dist/server/index.mjs.map +1 -1
- package/package.json +3 -3
- package/dist/_chunks/BulkUpdater-CQ9zGdat.js.map +0 -1
- package/dist/_chunks/BulkUpdater-DvCSr1vU.mjs.map +0 -1
|
@@ -3,7 +3,7 @@ import React__default, { useState, useEffect, useMemo, useRef } from "react";
|
|
|
3
3
|
import { useFetchClient, useNotification } from "@strapi/strapi/admin";
|
|
4
4
|
import { Box, Flex, Typography, Button, SingleSelect, SingleSelectOption, Checkbox, Badge, Alert, Table, Thead, Tr, Th, Tbody, Td, Loader, TextInput, ComboboxOption, Field, Combobox } from "@strapi/design-system";
|
|
5
5
|
import { ArrowClockwise, Download, Upload, Check, Eye, Play } from "@strapi/icons";
|
|
6
|
-
import { V as ValidationRulesTab } from "./ValidationRulesTab-
|
|
6
|
+
import { V as ValidationRulesTab } from "./ValidationRulesTab-Dt53h-Ke.mjs";
|
|
7
7
|
function CsvManagerTab() {
|
|
8
8
|
const { get, post } = useFetchClient();
|
|
9
9
|
const { toggleNotification } = useNotification();
|
|
@@ -114,7 +114,8 @@ function CsvManagerTab() {
|
|
|
114
114
|
});
|
|
115
115
|
return;
|
|
116
116
|
}
|
|
117
|
-
const
|
|
117
|
+
const safeContent = content.startsWith("\uFEFF") ? content : "\uFEFF" + content;
|
|
118
|
+
const blob = new Blob([safeContent], { type: "text/csv;charset=utf-8;" });
|
|
118
119
|
const url = URL.createObjectURL(blob);
|
|
119
120
|
const link = document.createElement("a");
|
|
120
121
|
link.href = url;
|
|
@@ -503,7 +504,9 @@ function formatVal(v) {
|
|
|
503
504
|
return String(v);
|
|
504
505
|
}
|
|
505
506
|
function downloadFile(content, filename, mimeType = "text/csv;charset=utf-8;") {
|
|
506
|
-
const
|
|
507
|
+
const isCsv = mimeType.includes("csv") || filename.endsWith(".csv");
|
|
508
|
+
const safeContent = isCsv && !content.startsWith("\uFEFF") ? "\uFEFF" + content : content;
|
|
509
|
+
const blob = new Blob([safeContent], { type: mimeType });
|
|
507
510
|
const url = URL.createObjectURL(blob);
|
|
508
511
|
const a = document.createElement("a");
|
|
509
512
|
a.href = url;
|
|
@@ -625,7 +628,7 @@ function ProcessingDashboardModal({
|
|
|
625
628
|
].join(",")
|
|
626
629
|
)
|
|
627
630
|
];
|
|
628
|
-
downloadFile(csvRows.join("\n"), `bulk_update_report_${targetId}.csv`);
|
|
631
|
+
downloadFile(csvRows.join("\r\n") + "\r\n", `bulk_update_report_${targetId}.csv`);
|
|
629
632
|
toggleNotification({
|
|
630
633
|
type: "success",
|
|
631
634
|
message: "Execution report downloaded successfully"
|
|
@@ -1451,7 +1454,7 @@ function getNestedValue(obj, path) {
|
|
|
1451
1454
|
if (!path.includes(".")) return obj[path];
|
|
1452
1455
|
return path.split(".").reduce((acc, part) => acc && typeof acc === "object" ? acc[part] : void 0, obj);
|
|
1453
1456
|
}
|
|
1454
|
-
function getAvailableColumnsForCollection(col, selectedAttribute) {
|
|
1457
|
+
function getAvailableColumnsForCollection(col, selectedAttribute, searchAttribute) {
|
|
1455
1458
|
const cols = [
|
|
1456
1459
|
{
|
|
1457
1460
|
key: "select",
|
|
@@ -1468,7 +1471,7 @@ function getAvailableColumnsForCollection(col, selectedAttribute) {
|
|
|
1468
1471
|
];
|
|
1469
1472
|
const candidateAttrs = col.attributes || [];
|
|
1470
1473
|
candidateAttrs.forEach((attr) => {
|
|
1471
|
-
if (attr === "name" || attr === "title" || attr === selectedAttribute) {
|
|
1474
|
+
if (attr === "name" || attr === "title" || attr === selectedAttribute || searchAttribute && attr === searchAttribute) {
|
|
1472
1475
|
return;
|
|
1473
1476
|
}
|
|
1474
1477
|
const formattedLabel = attr.includes(".") ? attr.split(".").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" > ") : attr.charAt(0).toUpperCase() + attr.slice(1);
|
|
@@ -1479,9 +1482,19 @@ function getAvailableColumnsForCollection(col, selectedAttribute) {
|
|
|
1479
1482
|
defaultVisible: ["department", "email", "location"].includes(attr)
|
|
1480
1483
|
});
|
|
1481
1484
|
});
|
|
1485
|
+
if (searchAttribute && searchAttribute !== selectedAttribute) {
|
|
1486
|
+
const formattedSearchLabel = searchAttribute.includes(".") ? searchAttribute.split(".").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" > ") : searchAttribute;
|
|
1487
|
+
cols.push({
|
|
1488
|
+
key: "search_attr",
|
|
1489
|
+
label: `Search: "${formattedSearchLabel}"`,
|
|
1490
|
+
sortable: !col.isSingleType && col.attributes.includes(searchAttribute),
|
|
1491
|
+
defaultVisible: true
|
|
1492
|
+
});
|
|
1493
|
+
}
|
|
1494
|
+
const targetLabel = searchAttribute && searchAttribute !== selectedAttribute ? `Update Target: "${selectedAttribute}"` : `Current "${selectedAttribute}"`;
|
|
1482
1495
|
cols.push({
|
|
1483
1496
|
key: "target_attr",
|
|
1484
|
-
label:
|
|
1497
|
+
label: targetLabel,
|
|
1485
1498
|
sortable: !col.isSingleType && col.attributes.includes(selectedAttribute),
|
|
1486
1499
|
defaultVisible: true
|
|
1487
1500
|
});
|
|
@@ -1493,17 +1506,19 @@ function getAvailableColumnsForCollection(col, selectedAttribute) {
|
|
|
1493
1506
|
});
|
|
1494
1507
|
return cols;
|
|
1495
1508
|
}
|
|
1496
|
-
function renderHeaderCell(colDef, col, currentSort, selectedAttribute, onSort) {
|
|
1509
|
+
function renderHeaderCell(colDef, col, currentSort, selectedAttribute, searchAttribute, onSort) {
|
|
1497
1510
|
if (colDef.key === "select") {
|
|
1498
1511
|
return /* @__PURE__ */ jsx(Th, { style: { width: 48 }, children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: "Select" }) }, "select");
|
|
1499
1512
|
}
|
|
1500
|
-
const isCurrentSorted = colDef.key === "identifier" && (currentSort.field === "name" || currentSort.field === "title") || colDef.key === "target_attr" && currentSort.field === selectedAttribute || colDef.key.startsWith("attr_") && currentSort.field === colDef.key.replace("attr_", "");
|
|
1513
|
+
const isCurrentSorted = colDef.key === "identifier" && (currentSort.field === "name" || currentSort.field === "title") || colDef.key === "search_attr" && currentSort.field === searchAttribute || colDef.key === "target_attr" && currentSort.field === selectedAttribute || colDef.key.startsWith("attr_") && currentSort.field === colDef.key.replace("attr_", "");
|
|
1501
1514
|
const sortArrow = isCurrentSorted ? currentSort.order === "asc" ? "▲" : "▼" : "⇅";
|
|
1502
1515
|
const handleClick = () => {
|
|
1503
1516
|
if (!colDef.sortable) return;
|
|
1504
1517
|
if (colDef.key === "identifier") {
|
|
1505
1518
|
const field = col.attributes.includes("name") ? "name" : col.attributes.includes("title") ? "title" : "createdAt";
|
|
1506
1519
|
onSort(col.uid, field);
|
|
1520
|
+
} else if (colDef.key === "search_attr") {
|
|
1521
|
+
onSort(col.uid, searchAttribute);
|
|
1507
1522
|
} else if (colDef.key === "target_attr") {
|
|
1508
1523
|
onSort(col.uid, selectedAttribute);
|
|
1509
1524
|
} else if (colDef.key.startsWith("attr_")) {
|
|
@@ -1539,7 +1554,7 @@ function formatDisplayValue(val) {
|
|
|
1539
1554
|
}
|
|
1540
1555
|
return String(val);
|
|
1541
1556
|
}
|
|
1542
|
-
function renderCellContent(colDef, entry, col, selectedAttribute, isMatch, hasAttr, isSelected, onToggleSelect) {
|
|
1557
|
+
function renderCellContent(colDef, entry, col, selectedAttribute, searchAttribute, isMatch, hasAttr, isSelected, onToggleSelect) {
|
|
1543
1558
|
switch (colDef.key) {
|
|
1544
1559
|
case "select":
|
|
1545
1560
|
return /* @__PURE__ */ jsx(
|
|
@@ -1556,6 +1571,27 @@ function renderCellContent(colDef, entry, col, selectedAttribute, isMatch, hasAt
|
|
|
1556
1571
|
entry.email && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", display: "block", children: entry.email })
|
|
1557
1572
|
] });
|
|
1558
1573
|
}
|
|
1574
|
+
case "search_attr": {
|
|
1575
|
+
const val = getNestedValue(entry, searchAttribute);
|
|
1576
|
+
const displayStr = formatDisplayValue(val);
|
|
1577
|
+
const isUnset = displayStr === "(empty / not set)" || displayStr === "(empty / unlinked)";
|
|
1578
|
+
return /* @__PURE__ */ jsx(
|
|
1579
|
+
Typography,
|
|
1580
|
+
{
|
|
1581
|
+
textColor: isUnset ? "neutral500" : "primary700",
|
|
1582
|
+
fontWeight: "semiBold",
|
|
1583
|
+
style: {
|
|
1584
|
+
fontStyle: isUnset ? "italic" : "normal",
|
|
1585
|
+
display: "inline-block",
|
|
1586
|
+
maxWidth: 260,
|
|
1587
|
+
overflow: "hidden",
|
|
1588
|
+
textOverflow: "ellipsis",
|
|
1589
|
+
whiteSpace: "nowrap"
|
|
1590
|
+
},
|
|
1591
|
+
children: displayStr
|
|
1592
|
+
}
|
|
1593
|
+
);
|
|
1594
|
+
}
|
|
1559
1595
|
case "target_attr": {
|
|
1560
1596
|
const val = getNestedValue(entry, selectedAttribute);
|
|
1561
1597
|
const displayStr = formatDisplayValue(val);
|
|
@@ -1646,6 +1682,7 @@ const BulkUpdater = () => {
|
|
|
1646
1682
|
const [showPublishConfirmModal, setShowPublishConfirmModal] = useState(false);
|
|
1647
1683
|
const [publishing, setPublishing] = useState(false);
|
|
1648
1684
|
const [publishMakerNotesInput, setPublishMakerNotesInput] = useState("");
|
|
1685
|
+
const [bulkExporting, setBulkExporting] = useState(false);
|
|
1649
1686
|
const MODELS_CACHE_KEY = "strapi_bulk_updater_models_cache";
|
|
1650
1687
|
const LAST_ATTR_KEY = "strapi_bulk_updater_last_attr";
|
|
1651
1688
|
const getInitialAttribute = () => {
|
|
@@ -1679,10 +1716,34 @@ const BulkUpdater = () => {
|
|
|
1679
1716
|
};
|
|
1680
1717
|
const [useRegex, setUseRegex] = useState(false);
|
|
1681
1718
|
const [regexPattern, setRegexPattern] = useState("");
|
|
1719
|
+
const DEPTH_STORAGE_KEY = "strapi_bulk_updater_component_depth";
|
|
1720
|
+
const [componentDepth, setComponentDepth] = useState(() => {
|
|
1721
|
+
try {
|
|
1722
|
+
const stored = localStorage.getItem(DEPTH_STORAGE_KEY);
|
|
1723
|
+
if (stored) {
|
|
1724
|
+
const val = Number(stored);
|
|
1725
|
+
if (val >= 1 && val <= 5) return val;
|
|
1726
|
+
}
|
|
1727
|
+
} catch {
|
|
1728
|
+
}
|
|
1729
|
+
return 3;
|
|
1730
|
+
});
|
|
1731
|
+
const handleComponentDepthChange = (depth) => {
|
|
1732
|
+
const capped = Math.min(5, Math.max(1, depth));
|
|
1733
|
+
setComponentDepth(capped);
|
|
1734
|
+
try {
|
|
1735
|
+
localStorage.setItem(DEPTH_STORAGE_KEY, String(capped));
|
|
1736
|
+
} catch {
|
|
1737
|
+
}
|
|
1738
|
+
};
|
|
1739
|
+
const [searchAttribute, setSearchAttribute] = useState("");
|
|
1740
|
+
const [searchAttributeInput, setSearchAttributeInput] = useState("");
|
|
1741
|
+
const [attributesMeta, setAttributesMeta] = useState({});
|
|
1742
|
+
const effectiveSearchAttribute = searchAttribute || selectedAttribute;
|
|
1682
1743
|
const [filterOperator, setFilterOperator] = useState("none");
|
|
1683
1744
|
const [filterQuery, setFilterQuery] = useState("");
|
|
1684
1745
|
const [entrySearch, setEntrySearch] = useState("");
|
|
1685
|
-
const isFilterActive = filterOperator !== "none" && (["empty", "not_empty"].includes(filterOperator) || Boolean(filterQuery.trim())) || Boolean(entrySearch.trim());
|
|
1746
|
+
const isFilterActive = Boolean(searchAttribute && searchAttribute !== selectedAttribute) || filterOperator !== "none" && (["empty", "not_empty"].includes(filterOperator) || Boolean(filterQuery.trim())) || Boolean(entrySearch.trim());
|
|
1686
1747
|
const [lastResults, setLastResults] = useState(null);
|
|
1687
1748
|
const [updateSummary, setUpdateSummary] = useState(null);
|
|
1688
1749
|
const [collectionPages, setCollectionPages] = useState({});
|
|
@@ -1762,6 +1823,9 @@ const BulkUpdater = () => {
|
|
|
1762
1823
|
if (data.relationsMeta) {
|
|
1763
1824
|
setRelationsMeta(data.relationsMeta);
|
|
1764
1825
|
}
|
|
1826
|
+
if (data.attributesMeta) {
|
|
1827
|
+
setAttributesMeta(data.attributesMeta);
|
|
1828
|
+
}
|
|
1765
1829
|
let storedAttr = null;
|
|
1766
1830
|
try {
|
|
1767
1831
|
storedAttr = localStorage.getItem(LAST_ATTR_KEY);
|
|
@@ -1809,7 +1873,7 @@ const BulkUpdater = () => {
|
|
|
1809
1873
|
setLoading(false);
|
|
1810
1874
|
}
|
|
1811
1875
|
};
|
|
1812
|
-
const loadCollectionPage = async (colUid, targetPage, customPageSize, customSortField, customSortOrder, overrideFilterOp, overrideFilterQuery, overrideEntrySearch, autoSelectReturned = true) => {
|
|
1876
|
+
const loadCollectionPage = async (colUid, targetPage, customPageSize, customSortField, customSortOrder, overrideFilterOp, overrideFilterQuery, overrideEntrySearch, autoSelectReturned = true, overrideSearchAttr) => {
|
|
1813
1877
|
const currentPageState = collectionPages[colUid];
|
|
1814
1878
|
const size = customPageSize || currentPageState?.pageSize || defaultPageSize;
|
|
1815
1879
|
const currentSort = collectionSorts[colUid] || { field: "createdAt", order: "desc" };
|
|
@@ -1818,6 +1882,7 @@ const BulkUpdater = () => {
|
|
|
1818
1882
|
const op = overrideFilterOp !== void 0 ? overrideFilterOp : filterOperator;
|
|
1819
1883
|
const q = overrideFilterQuery !== void 0 ? overrideFilterQuery : filterQuery;
|
|
1820
1884
|
const s = overrideEntrySearch !== void 0 ? overrideEntrySearch : entrySearch;
|
|
1885
|
+
const searchAttr = overrideSearchAttr !== void 0 ? overrideSearchAttr : searchAttribute;
|
|
1821
1886
|
setCollectionPages((prev) => ({
|
|
1822
1887
|
...prev,
|
|
1823
1888
|
[colUid]: {
|
|
@@ -1831,6 +1896,9 @@ const BulkUpdater = () => {
|
|
|
1831
1896
|
pageSize: String(size)
|
|
1832
1897
|
});
|
|
1833
1898
|
if (selectedAttribute) params.set("attribute", selectedAttribute);
|
|
1899
|
+
if (searchAttr && searchAttr !== selectedAttribute) {
|
|
1900
|
+
params.set("searchAttribute", searchAttr);
|
|
1901
|
+
}
|
|
1834
1902
|
if (op && op !== "none") {
|
|
1835
1903
|
params.set("filterOperator", op);
|
|
1836
1904
|
if (q) params.set("filterQuery", q);
|
|
@@ -1860,7 +1928,7 @@ const BulkUpdater = () => {
|
|
|
1860
1928
|
loading: false
|
|
1861
1929
|
}
|
|
1862
1930
|
}));
|
|
1863
|
-
const isFilterActiveNow = op !== "none" && (["empty", "not_empty"].includes(op) || Boolean(q.trim())) || Boolean(s.trim());
|
|
1931
|
+
const isFilterActiveNow = Boolean(searchAttr && searchAttr !== selectedAttribute) || op !== "none" && (["empty", "not_empty"].includes(op) || Boolean(q.trim())) || Boolean(s.trim());
|
|
1864
1932
|
if (isFilterActiveNow && autoSelectReturned) {
|
|
1865
1933
|
setSelectedEntries((prev) => {
|
|
1866
1934
|
const next = { ...prev };
|
|
@@ -1947,13 +2015,14 @@ const BulkUpdater = () => {
|
|
|
1947
2015
|
}
|
|
1948
2016
|
const timer = setTimeout(() => {
|
|
1949
2017
|
if (collections.length > 0) {
|
|
1950
|
-
const isFilterActiveNow = filterOperator !== "none" && (["empty", "not_empty"].includes(filterOperator) || Boolean(filterQuery.trim())) || Boolean(entrySearch.trim());
|
|
2018
|
+
const isFilterActiveNow = Boolean(searchAttribute && searchAttribute !== selectedAttribute) || filterOperator !== "none" && (["empty", "not_empty"].includes(filterOperator) || Boolean(filterQuery.trim())) || Boolean(entrySearch.trim());
|
|
1951
2019
|
if (isFilterActiveNow) {
|
|
1952
2020
|
setSelectedEntries({});
|
|
1953
2021
|
}
|
|
2022
|
+
const targetSearchAttr = searchAttribute || selectedAttribute;
|
|
1954
2023
|
const targetCols = collections.filter((col) => {
|
|
1955
2024
|
if (visibleTypeUids[col.uid] === false) return false;
|
|
1956
|
-
if (filterOperator !== "none" && !col.attributes.includes(
|
|
2025
|
+
if (filterOperator !== "none" && targetSearchAttr && !col.attributes.includes(targetSearchAttr)) return false;
|
|
1957
2026
|
return true;
|
|
1958
2027
|
});
|
|
1959
2028
|
targetCols.forEach((col) => {
|
|
@@ -1966,13 +2035,14 @@ const BulkUpdater = () => {
|
|
|
1966
2035
|
filterOperator,
|
|
1967
2036
|
filterQuery,
|
|
1968
2037
|
entrySearch,
|
|
1969
|
-
true
|
|
2038
|
+
true,
|
|
2039
|
+
searchAttribute
|
|
1970
2040
|
);
|
|
1971
2041
|
});
|
|
1972
2042
|
}
|
|
1973
2043
|
}, 350);
|
|
1974
2044
|
return () => clearTimeout(timer);
|
|
1975
|
-
}, [filterOperator, filterQuery, entrySearch]);
|
|
2045
|
+
}, [searchAttribute, filterOperator, filterQuery, entrySearch]);
|
|
1976
2046
|
const KEY_SEP = "@@@";
|
|
1977
2047
|
const handleAttributeChange = (newAttr) => {
|
|
1978
2048
|
if (newAttr !== selectedAttribute) {
|
|
@@ -2041,39 +2111,119 @@ const BulkUpdater = () => {
|
|
|
2041
2111
|
setVisibleTypeUids(newVis);
|
|
2042
2112
|
};
|
|
2043
2113
|
const [attributeSearch, setAttributeSearch] = useState("");
|
|
2114
|
+
const [searchAttributeSearch, setSearchAttributeSearch] = useState("");
|
|
2115
|
+
const getAttrDepth = (attr) => attributesMeta[attr]?.depth ?? (attr.includes(".") ? attr.split(".").length - 1 : 0);
|
|
2116
|
+
const depthFilteredAttributes = useMemo(() => {
|
|
2117
|
+
return attributes.filter((attr) => getAttrDepth(attr) <= componentDepth);
|
|
2118
|
+
}, [attributes, componentDepth, attributesMeta]);
|
|
2044
2119
|
const filteredAttributes = useMemo(() => {
|
|
2045
2120
|
if (!attributeSearch.trim()) {
|
|
2046
|
-
return
|
|
2121
|
+
return depthFilteredAttributes;
|
|
2047
2122
|
}
|
|
2048
2123
|
const q = attributeSearch.toLowerCase().trim();
|
|
2049
2124
|
const cleanQ = q.replace(/[^a-z0-9]/g, "");
|
|
2050
|
-
return
|
|
2125
|
+
return depthFilteredAttributes.filter((attr) => {
|
|
2051
2126
|
const lower = attr.toLowerCase();
|
|
2052
2127
|
const cleanLower = lower.replace(/[^a-z0-9]/g, "");
|
|
2053
2128
|
const rel = relationsMeta[attr];
|
|
2054
2129
|
const relTarget = (rel?.targetDisplayName || "").toLowerCase();
|
|
2055
2130
|
return lower.includes(q) || cleanLower.includes(cleanQ) || relTarget.includes(q);
|
|
2056
2131
|
});
|
|
2057
|
-
}, [
|
|
2132
|
+
}, [depthFilteredAttributes, attributeSearch, relationsMeta]);
|
|
2133
|
+
const filteredSearchAttributes = useMemo(() => {
|
|
2134
|
+
if (!searchAttributeSearch.trim()) {
|
|
2135
|
+
return depthFilteredAttributes;
|
|
2136
|
+
}
|
|
2137
|
+
const q = searchAttributeSearch.toLowerCase().trim();
|
|
2138
|
+
const cleanQ = q.replace(/[^a-z0-9]/g, "");
|
|
2139
|
+
return depthFilteredAttributes.filter((attr) => {
|
|
2140
|
+
const lower = attr.toLowerCase();
|
|
2141
|
+
const cleanLower = lower.replace(/[^a-z0-9]/g, "");
|
|
2142
|
+
const rel = relationsMeta[attr];
|
|
2143
|
+
const relTarget = (rel?.targetDisplayName || "").toLowerCase();
|
|
2144
|
+
return lower.includes(q) || cleanLower.includes(cleanQ) || relTarget.includes(q);
|
|
2145
|
+
});
|
|
2146
|
+
}, [depthFilteredAttributes, searchAttributeSearch, relationsMeta]);
|
|
2058
2147
|
const memoizedComboboxOptions = useMemo(() => {
|
|
2059
2148
|
if (filteredAttributes.length === 0) {
|
|
2060
2149
|
return /* @__PURE__ */ jsx(ComboboxOption, { value: "__none__", disabled: true, textValue: "No matching attributes found", children: /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", children: [
|
|
2061
2150
|
'No matching attributes found for "',
|
|
2062
2151
|
attributeSearch,
|
|
2063
|
-
'"'
|
|
2152
|
+
'" (Depth L',
|
|
2153
|
+
componentDepth,
|
|
2154
|
+
")"
|
|
2064
2155
|
] }) });
|
|
2065
2156
|
}
|
|
2066
2157
|
return filteredAttributes.map((attr) => {
|
|
2067
2158
|
const rel = relationsMeta[attr];
|
|
2159
|
+
const depth = getAttrDepth(attr);
|
|
2068
2160
|
return /* @__PURE__ */ jsx(ComboboxOption, { value: attr, textValue: attr, children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", width: "100%", gap: 2, children: [
|
|
2069
2161
|
/* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: attr === selectedAttribute ? "bold" : "regular", children: attr }),
|
|
2070
2162
|
rel ? /* @__PURE__ */ jsxs(Badge, { backgroundColor: "secondary100", textColor: "secondary700", size: "S", children: [
|
|
2071
2163
|
"relation ➔ ",
|
|
2072
2164
|
rel.targetDisplayName
|
|
2073
|
-
] }) :
|
|
2165
|
+
] }) : depth > 0 ? /* @__PURE__ */ jsxs(Badge, { backgroundColor: depth === 1 ? "neutral150" : depth === 2 ? "primary100" : "secondary100", textColor: depth === 1 ? "neutral700" : depth === 2 ? "primary700" : "secondary700", size: "S", children: [
|
|
2166
|
+
"L",
|
|
2167
|
+
depth,
|
|
2168
|
+
" component"
|
|
2169
|
+
] }) : null
|
|
2074
2170
|
] }) }, attr);
|
|
2075
2171
|
});
|
|
2076
|
-
}, [filteredAttributes, relationsMeta, selectedAttribute, attributeSearch]);
|
|
2172
|
+
}, [filteredAttributes, relationsMeta, selectedAttribute, attributeSearch, componentDepth, attributesMeta]);
|
|
2173
|
+
const memoizedSearchComboboxOptions = useMemo(() => {
|
|
2174
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2175
|
+
/* @__PURE__ */ jsx(
|
|
2176
|
+
ComboboxOption,
|
|
2177
|
+
{
|
|
2178
|
+
value: "__default__",
|
|
2179
|
+
textValue: `Same as Update Attribute (${selectedAttribute || "None"})`,
|
|
2180
|
+
children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", width: "100%", gap: 2, children: [
|
|
2181
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "omega", fontStyle: "italic", textColor: "neutral600", children: [
|
|
2182
|
+
"-- Same as Update Attribute (",
|
|
2183
|
+
selectedAttribute || "None",
|
|
2184
|
+
") --"
|
|
2185
|
+
] }),
|
|
2186
|
+
/* @__PURE__ */ jsx(Badge, { backgroundColor: "neutral150", textColor: "neutral600", size: "S", children: "Default" })
|
|
2187
|
+
] })
|
|
2188
|
+
}
|
|
2189
|
+
),
|
|
2190
|
+
filteredSearchAttributes.map((attr) => {
|
|
2191
|
+
const rel = relationsMeta[attr];
|
|
2192
|
+
const depth = getAttrDepth(attr);
|
|
2193
|
+
return /* @__PURE__ */ jsx(ComboboxOption, { value: attr, textValue: attr, children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", width: "100%", gap: 2, children: [
|
|
2194
|
+
/* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: attr === searchAttribute ? "bold" : "regular", children: attr }),
|
|
2195
|
+
rel ? /* @__PURE__ */ jsxs(Badge, { backgroundColor: "secondary100", textColor: "secondary700", size: "S", children: [
|
|
2196
|
+
"relation ➔ ",
|
|
2197
|
+
rel.targetDisplayName
|
|
2198
|
+
] }) : depth > 0 ? /* @__PURE__ */ jsxs(Badge, { backgroundColor: depth === 1 ? "neutral150" : depth === 2 ? "primary100" : "secondary100", textColor: depth === 1 ? "neutral700" : depth === 2 ? "primary700" : "secondary700", size: "S", children: [
|
|
2199
|
+
"L",
|
|
2200
|
+
depth,
|
|
2201
|
+
" component"
|
|
2202
|
+
] }) : null
|
|
2203
|
+
] }) }, `search_${attr}`);
|
|
2204
|
+
})
|
|
2205
|
+
] });
|
|
2206
|
+
}, [filteredSearchAttributes, relationsMeta, searchAttribute, selectedAttribute, componentDepth, attributesMeta]);
|
|
2207
|
+
const handleSearchAttributeChange = (newAttr) => {
|
|
2208
|
+
const finalAttr = newAttr === "__default__" ? "" : newAttr;
|
|
2209
|
+
setSearchAttribute(finalAttr);
|
|
2210
|
+
if (collections.length > 0) {
|
|
2211
|
+
collections.forEach((col) => {
|
|
2212
|
+
loadCollectionPage(
|
|
2213
|
+
col.uid,
|
|
2214
|
+
1,
|
|
2215
|
+
void 0,
|
|
2216
|
+
void 0,
|
|
2217
|
+
void 0,
|
|
2218
|
+
filterOperator,
|
|
2219
|
+
filterQuery,
|
|
2220
|
+
entrySearch,
|
|
2221
|
+
true,
|
|
2222
|
+
finalAttr
|
|
2223
|
+
);
|
|
2224
|
+
});
|
|
2225
|
+
}
|
|
2226
|
+
};
|
|
2077
2227
|
const handleGlobalPageSizeChange = (newSize) => {
|
|
2078
2228
|
const capped = Math.min(500, Math.max(1, newSize));
|
|
2079
2229
|
setDefaultPageSize(capped);
|
|
@@ -2164,12 +2314,14 @@ const BulkUpdater = () => {
|
|
|
2164
2314
|
setSelectedEntries(updated);
|
|
2165
2315
|
};
|
|
2166
2316
|
const clearFilter = () => {
|
|
2317
|
+
setSearchAttribute("");
|
|
2318
|
+
setSearchAttributeSearch("");
|
|
2167
2319
|
setFilterOperator("none");
|
|
2168
2320
|
setFilterQuery("");
|
|
2169
2321
|
setEntrySearch("");
|
|
2170
2322
|
setSelectedEntries({});
|
|
2171
2323
|
collections.forEach((col) => {
|
|
2172
|
-
loadCollectionPage(col.uid, 1, void 0, void 0, void 0, "none", "", "", false);
|
|
2324
|
+
loadCollectionPage(col.uid, 1, void 0, void 0, void 0, "none", "", "", false, "");
|
|
2173
2325
|
});
|
|
2174
2326
|
};
|
|
2175
2327
|
const isCollectionFullySelected = (col) => {
|
|
@@ -2431,6 +2583,57 @@ const BulkUpdater = () => {
|
|
|
2431
2583
|
setMakerNotesInput("");
|
|
2432
2584
|
}
|
|
2433
2585
|
};
|
|
2586
|
+
const handleBulkExportSelected = async () => {
|
|
2587
|
+
const targets = [];
|
|
2588
|
+
Object.keys(selectedEntries).forEach((key) => {
|
|
2589
|
+
if (selectedEntries[key]) {
|
|
2590
|
+
const parts = key.split(KEY_SEP);
|
|
2591
|
+
if (parts.length === 2) {
|
|
2592
|
+
targets.push({ uid: parts[0], documentId: parts[1] });
|
|
2593
|
+
}
|
|
2594
|
+
}
|
|
2595
|
+
});
|
|
2596
|
+
if (targets.length === 0) {
|
|
2597
|
+
toggleNotification({
|
|
2598
|
+
type: "warning",
|
|
2599
|
+
message: "Please select at least one entry to export"
|
|
2600
|
+
});
|
|
2601
|
+
return;
|
|
2602
|
+
}
|
|
2603
|
+
try {
|
|
2604
|
+
setBulkExporting(true);
|
|
2605
|
+
const res = await post("/bulk-updater/csv/export-bulk", { selectedEntries: targets });
|
|
2606
|
+
const csvStr = res.data?.csvContent || (typeof res.data === "string" ? res.data : "");
|
|
2607
|
+
if (!csvStr) {
|
|
2608
|
+
toggleNotification({
|
|
2609
|
+
type: "warning",
|
|
2610
|
+
message: "No CSV content returned for selected entries"
|
|
2611
|
+
});
|
|
2612
|
+
return;
|
|
2613
|
+
}
|
|
2614
|
+
const safeContent = csvStr.startsWith("\uFEFF") ? csvStr : "\uFEFF" + csvStr;
|
|
2615
|
+
const blob = new Blob([safeContent], { type: "text/csv;charset=utf-8;" });
|
|
2616
|
+
const url = URL.createObjectURL(blob);
|
|
2617
|
+
const link = document.createElement("a");
|
|
2618
|
+
link.href = url;
|
|
2619
|
+
link.setAttribute("download", res.data?.filename || `bulk_export_selected_${targets.length}.csv`);
|
|
2620
|
+
document.body.appendChild(link);
|
|
2621
|
+
link.click();
|
|
2622
|
+
document.body.removeChild(link);
|
|
2623
|
+
URL.revokeObjectURL(url);
|
|
2624
|
+
toggleNotification({
|
|
2625
|
+
type: "success",
|
|
2626
|
+
message: `Successfully exported ${res.data?.count || targets.length} selected records to Excel CSV`
|
|
2627
|
+
});
|
|
2628
|
+
} catch (e) {
|
|
2629
|
+
toggleNotification({
|
|
2630
|
+
type: "danger",
|
|
2631
|
+
message: e.message || "Failed exporting selected records to CSV"
|
|
2632
|
+
});
|
|
2633
|
+
} finally {
|
|
2634
|
+
setBulkExporting(false);
|
|
2635
|
+
}
|
|
2636
|
+
};
|
|
2434
2637
|
const handleOpenPublishModal = () => {
|
|
2435
2638
|
const totalSelected = Object.values(selectedEntries).filter(Boolean).length;
|
|
2436
2639
|
if (totalSelected === 0) {
|
|
@@ -2914,7 +3117,29 @@ const BulkUpdater = () => {
|
|
|
2914
3117
|
marginBottom: 6,
|
|
2915
3118
|
style: { width: "100%", maxWidth: "100%", minWidth: 0, boxSizing: "border-box" },
|
|
2916
3119
|
children: [
|
|
2917
|
-
/* @__PURE__ */
|
|
3120
|
+
/* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 4, wrap: "wrap", gap: 3, children: [
|
|
3121
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
3122
|
+
/* @__PURE__ */ jsx(Typography, { variant: "delta", tag: "h2", fontWeight: "semiBold", children: "1. Configure Attribute Update" }),
|
|
3123
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Select the target attribute to update across collections." })
|
|
3124
|
+
] }),
|
|
3125
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
|
|
3126
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral700", fontWeight: "bold", children: "Component Nesting Depth:" }),
|
|
3127
|
+
[1, 2, 3, 4, 5].map((lvl) => /* @__PURE__ */ jsxs(
|
|
3128
|
+
Button,
|
|
3129
|
+
{
|
|
3130
|
+
variant: componentDepth === lvl ? "default" : "tertiary",
|
|
3131
|
+
size: "S",
|
|
3132
|
+
onClick: () => handleComponentDepthChange(lvl),
|
|
3133
|
+
title: `Discover nested component attributes up to Level ${lvl}`,
|
|
3134
|
+
children: [
|
|
3135
|
+
"Level ",
|
|
3136
|
+
lvl
|
|
3137
|
+
]
|
|
3138
|
+
},
|
|
3139
|
+
`depth_cfg_${lvl}`
|
|
3140
|
+
))
|
|
3141
|
+
] })
|
|
3142
|
+
] }),
|
|
2918
3143
|
/* @__PURE__ */ jsxs(Flex, { gap: 4, alignItems: "flex-end", wrap: "wrap", children: [
|
|
2919
3144
|
/* @__PURE__ */ jsx(Box, { style: { minWidth: 280, flex: 1, maxWidth: 440 }, children: /* @__PURE__ */ jsxs(Field.Root, { children: [
|
|
2920
3145
|
/* @__PURE__ */ jsx(Field.Label, { children: "Attribute to Update" }),
|
|
@@ -3074,6 +3299,23 @@ const BulkUpdater = () => {
|
|
|
3074
3299
|
")"
|
|
3075
3300
|
]
|
|
3076
3301
|
}
|
|
3302
|
+
),
|
|
3303
|
+
/* @__PURE__ */ jsxs(
|
|
3304
|
+
Button,
|
|
3305
|
+
{
|
|
3306
|
+
startIcon: /* @__PURE__ */ jsx(Download, {}),
|
|
3307
|
+
variant: "tertiary",
|
|
3308
|
+
size: "L",
|
|
3309
|
+
onClick: handleBulkExportSelected,
|
|
3310
|
+
loading: bulkExporting,
|
|
3311
|
+
disabled: loading || totalSelectedCount === 0,
|
|
3312
|
+
title: "Export selected entries to Excel-compatible CSV with full nested component support",
|
|
3313
|
+
children: [
|
|
3314
|
+
"Export Selected (",
|
|
3315
|
+
totalSelectedCount,
|
|
3316
|
+
")"
|
|
3317
|
+
]
|
|
3318
|
+
}
|
|
3077
3319
|
)
|
|
3078
3320
|
] })
|
|
3079
3321
|
] }),
|
|
@@ -3228,26 +3470,83 @@ const BulkUpdater = () => {
|
|
|
3228
3470
|
style: { width: "100%", maxWidth: "100%", boxSizing: "border-box" },
|
|
3229
3471
|
children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 3, children: [
|
|
3230
3472
|
/* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", wrap: "wrap", gap: 2, children: [
|
|
3231
|
-
/* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
|
|
3473
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
|
|
3232
3474
|
/* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "bold", children: "Search & Filter Targets:" }),
|
|
3233
3475
|
isFilterActive && /* @__PURE__ */ jsxs(Badge, { backgroundColor: "primary100", textColor: "primary700", children: [
|
|
3234
3476
|
matchingEntriesCount,
|
|
3235
3477
|
" matching ",
|
|
3236
3478
|
matchingEntriesCount === 1 ? "entry" : "entries",
|
|
3237
3479
|
" found in database"
|
|
3480
|
+
] }),
|
|
3481
|
+
searchAttribute && searchAttribute !== selectedAttribute && /* @__PURE__ */ jsxs(Badge, { backgroundColor: "secondary100", textColor: "secondary700", children: [
|
|
3482
|
+
"Searching by: ",
|
|
3483
|
+
searchAttribute,
|
|
3484
|
+
" → Target to update: ",
|
|
3485
|
+
selectedAttribute
|
|
3238
3486
|
] })
|
|
3239
3487
|
] }),
|
|
3240
|
-
|
|
3488
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
|
|
3489
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 1, alignItems: "center", children: [
|
|
3490
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Depth:" }),
|
|
3491
|
+
[1, 2, 3, 4, 5].map((lvl) => /* @__PURE__ */ jsxs(
|
|
3492
|
+
Button,
|
|
3493
|
+
{
|
|
3494
|
+
variant: componentDepth === lvl ? "default" : "tertiary",
|
|
3495
|
+
size: "S",
|
|
3496
|
+
onClick: () => handleComponentDepthChange(lvl),
|
|
3497
|
+
title: `Show component attributes up to Level ${lvl}`,
|
|
3498
|
+
style: { minWidth: 26, padding: "2px 6px" },
|
|
3499
|
+
children: [
|
|
3500
|
+
"L",
|
|
3501
|
+
lvl
|
|
3502
|
+
]
|
|
3503
|
+
},
|
|
3504
|
+
`s2_depth_${lvl}`
|
|
3505
|
+
))
|
|
3506
|
+
] }),
|
|
3507
|
+
isFilterActive && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "S", onClick: clearFilter, children: "Clear Search & Filter" })
|
|
3508
|
+
] })
|
|
3241
3509
|
] }),
|
|
3242
3510
|
/* @__PURE__ */ jsxs(Flex, { gap: 3, alignItems: "flex-end", wrap: "wrap", children: [
|
|
3243
|
-
/* @__PURE__ */ jsx(Box, { style: { width:
|
|
3511
|
+
/* @__PURE__ */ jsx(Box, { style: { width: 280, minWidth: 230 }, children: /* @__PURE__ */ jsxs(Field.Root, { children: [
|
|
3512
|
+
/* @__PURE__ */ jsx(Field.Label, { children: "Search Attribute" }),
|
|
3513
|
+
/* @__PURE__ */ jsx(
|
|
3514
|
+
Combobox,
|
|
3515
|
+
{
|
|
3516
|
+
autocomplete: "none",
|
|
3517
|
+
placeholder: searchAttribute || `Same as Update (${selectedAttribute || "None"})`,
|
|
3518
|
+
value: searchAttribute || "__default__",
|
|
3519
|
+
clearLabel: "Reset search attribute",
|
|
3520
|
+
onClear: () => {
|
|
3521
|
+
handleSearchAttributeChange("");
|
|
3522
|
+
setSearchAttributeSearch("");
|
|
3523
|
+
},
|
|
3524
|
+
onInputChange: (e) => {
|
|
3525
|
+
setSearchAttributeSearch(e.target.value);
|
|
3526
|
+
},
|
|
3527
|
+
onOpenChange: (isOpen) => {
|
|
3528
|
+
if (!isOpen) {
|
|
3529
|
+
setSearchAttributeSearch("");
|
|
3530
|
+
}
|
|
3531
|
+
},
|
|
3532
|
+
onChange: (val) => {
|
|
3533
|
+
if (val && typeof val === "string" && val !== "__none__") {
|
|
3534
|
+
handleSearchAttributeChange(val);
|
|
3535
|
+
setSearchAttributeSearch("");
|
|
3536
|
+
}
|
|
3537
|
+
},
|
|
3538
|
+
children: memoizedSearchComboboxOptions
|
|
3539
|
+
}
|
|
3540
|
+
)
|
|
3541
|
+
] }) }),
|
|
3542
|
+
/* @__PURE__ */ jsx(Box, { style: { width: 200, minWidth: 170 }, children: /* @__PURE__ */ jsxs(
|
|
3244
3543
|
SingleSelect,
|
|
3245
3544
|
{
|
|
3246
|
-
label:
|
|
3545
|
+
label: effectiveSearchAttribute ? `Condition for "${effectiveSearchAttribute}"` : "Filter condition",
|
|
3247
3546
|
value: filterOperator,
|
|
3248
3547
|
onChange: (val) => setFilterOperator(String(val)),
|
|
3249
3548
|
children: [
|
|
3250
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "none", children: "Show All (No
|
|
3549
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "none", children: "Show All (No Value Filter)" }),
|
|
3251
3550
|
/* @__PURE__ */ jsx(SingleSelectOption, { value: "empty", children: "Is Empty or Null" }),
|
|
3252
3551
|
/* @__PURE__ */ jsx(SingleSelectOption, { value: "not_empty", children: "Is Not Empty" }),
|
|
3253
3552
|
/* @__PURE__ */ jsx(SingleSelectOption, { value: "equals", children: "Equals Exact Text" }),
|
|
@@ -3256,16 +3555,16 @@ const BulkUpdater = () => {
|
|
|
3256
3555
|
]
|
|
3257
3556
|
}
|
|
3258
3557
|
) }),
|
|
3259
|
-
(filterOperator === "equals" || filterOperator === "contains" || filterOperator === "starts_with") && /* @__PURE__ */ jsx(Box, { style: { flex: 1, minWidth:
|
|
3558
|
+
(filterOperator === "equals" || filterOperator === "contains" || filterOperator === "starts_with") && /* @__PURE__ */ jsx(Box, { style: { flex: 1, minWidth: 180 }, children: /* @__PURE__ */ jsx(
|
|
3260
3559
|
TextInput,
|
|
3261
3560
|
{
|
|
3262
|
-
label:
|
|
3561
|
+
label: effectiveSearchAttribute ? `Value for "${effectiveSearchAttribute}"` : "Value to match",
|
|
3263
3562
|
placeholder: "Type value to match...",
|
|
3264
3563
|
value: filterQuery,
|
|
3265
3564
|
onChange: (e) => setFilterQuery(e.target.value)
|
|
3266
3565
|
}
|
|
3267
3566
|
) }),
|
|
3268
|
-
/* @__PURE__ */ jsx(Box, { style: { flex: 1, minWidth:
|
|
3567
|
+
/* @__PURE__ */ jsx(Box, { style: { flex: 1, minWidth: 180 }, children: /* @__PURE__ */ jsx(
|
|
3269
3568
|
TextInput,
|
|
3270
3569
|
{
|
|
3271
3570
|
label: "Full-text Entry Search",
|
|
@@ -3463,11 +3762,11 @@ const BulkUpdater = () => {
|
|
|
3463
3762
|
const pageSize = pageState ? pageState.pageSize : defaultPageSize;
|
|
3464
3763
|
const hasAttr = selectedAttribute ? col.attributes.includes(selectedAttribute) : false;
|
|
3465
3764
|
const visibleEntries = getVisibleEntries(col);
|
|
3466
|
-
selectedAttribute ? entries.filter((e) => entryMatchesFilter(e,
|
|
3765
|
+
selectedAttribute ? entries.filter((e) => entryMatchesFilter(e, effectiveSearchAttribute)).length : 0;
|
|
3467
3766
|
const isFullySelected = isCollectionFullySelected(col);
|
|
3468
3767
|
const isPartiallySelected = isCollectionPartiallySelected(col);
|
|
3469
3768
|
const currentSort = collectionSorts[col.uid] || { field: "createdAt", order: "desc" };
|
|
3470
|
-
const availableColumns = getAvailableColumnsForCollection(col, selectedAttribute);
|
|
3769
|
+
const availableColumns = getAvailableColumnsForCollection(col, selectedAttribute, searchAttribute);
|
|
3471
3770
|
const savedColKeys = collectionColumnVisibility[col.uid];
|
|
3472
3771
|
const activeColumns = savedColKeys ? availableColumns.filter((c) => c.isPermanent || savedColKeys.includes(c.key)) : availableColumns.filter((c) => c.defaultVisible);
|
|
3473
3772
|
return /* @__PURE__ */ jsxs(
|
|
@@ -3575,6 +3874,10 @@ const BulkUpdater = () => {
|
|
|
3575
3874
|
if (entrySearch && entrySearch.trim()) {
|
|
3576
3875
|
params.set("search", entrySearch.trim());
|
|
3577
3876
|
}
|
|
3877
|
+
const colSelectedDocIds = col.entries.filter((e) => selectedEntries[`${col.uid}${KEY_SEP}${e.documentId}`]).map((e) => e.documentId);
|
|
3878
|
+
if (colSelectedDocIds.length > 0) {
|
|
3879
|
+
params.set("documentIds", colSelectedDocIds.join(","));
|
|
3880
|
+
}
|
|
3578
3881
|
const res = await get(`/bulk-updater/csv/export/${col.uid}?${params.toString()}`);
|
|
3579
3882
|
const csvStr = res.data?.csvContent || (typeof res.data === "string" ? res.data : "");
|
|
3580
3883
|
if (!csvStr) {
|
|
@@ -3584,7 +3887,8 @@ const BulkUpdater = () => {
|
|
|
3584
3887
|
});
|
|
3585
3888
|
return;
|
|
3586
3889
|
}
|
|
3587
|
-
const
|
|
3890
|
+
const safeContent = csvStr.startsWith("\uFEFF") ? csvStr : "\uFEFF" + csvStr;
|
|
3891
|
+
const blob = new Blob([safeContent], { type: "text/csv;charset=utf-8;" });
|
|
3588
3892
|
const url = URL.createObjectURL(blob);
|
|
3589
3893
|
const link = document.createElement("a");
|
|
3590
3894
|
link.href = url;
|
|
@@ -3595,7 +3899,7 @@ const BulkUpdater = () => {
|
|
|
3595
3899
|
URL.revokeObjectURL(url);
|
|
3596
3900
|
toggleNotification({
|
|
3597
3901
|
type: "success",
|
|
3598
|
-
message: `Exported ${col.displayName} entries to CSV`
|
|
3902
|
+
message: `Exported ${res.data?.count ?? (colSelectedDocIds.length || col.entries.length)} ${col.displayName} entries to Excel CSV`
|
|
3599
3903
|
});
|
|
3600
3904
|
} catch (e) {
|
|
3601
3905
|
toggleNotification({
|
|
@@ -3672,7 +3976,7 @@ const BulkUpdater = () => {
|
|
|
3672
3976
|
),
|
|
3673
3977
|
/* @__PURE__ */ jsx(Box, { className: "bulk-updater-table-container", style: { width: "100%", maxWidth: "100%", minWidth: 0, overflowX: "auto" }, children: /* @__PURE__ */ jsxs(Table, { colCount: activeColumns.length, rowCount: visibleEntries.length + 1, style: { width: "100%" }, children: [
|
|
3674
3978
|
/* @__PURE__ */ jsx(Thead, { children: /* @__PURE__ */ jsx(Tr, { children: activeColumns.map(
|
|
3675
|
-
(colDef) => renderHeaderCell(colDef, col, currentSort, selectedAttribute, handleHeaderSortClick)
|
|
3979
|
+
(colDef) => renderHeaderCell(colDef, col, currentSort, selectedAttribute, searchAttribute, handleHeaderSortClick)
|
|
3676
3980
|
) }) }),
|
|
3677
3981
|
/* @__PURE__ */ jsx(Tbody, { children: visibleEntries.length === 0 ? /* @__PURE__ */ jsx(Tr, { children: /* @__PURE__ */ jsx(Td, { colSpan: activeColumns.length, children: /* @__PURE__ */ jsx(Box, { padding: 4, style: { textAlign: "center" }, children: /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: "No entries in this content type match the active filter criteria." }) }) }) }) : visibleEntries.map((entry) => {
|
|
3678
3982
|
const key = `${col.uid}${KEY_SEP}${entry.documentId}`;
|
|
@@ -3690,6 +3994,7 @@ const BulkUpdater = () => {
|
|
|
3690
3994
|
entry,
|
|
3691
3995
|
col,
|
|
3692
3996
|
selectedAttribute,
|
|
3997
|
+
searchAttribute,
|
|
3693
3998
|
isMatch,
|
|
3694
3999
|
hasAttr,
|
|
3695
4000
|
isSelected,
|
|
@@ -4665,4 +4970,4 @@ export {
|
|
|
4665
4970
|
getAvailableColumnsForCollection,
|
|
4666
4971
|
getNestedValue
|
|
4667
4972
|
};
|
|
4668
|
-
//# sourceMappingURL=BulkUpdater-
|
|
4973
|
+
//# sourceMappingURL=BulkUpdater-DowSmA56.mjs.map
|