strapi-plugin-bulk-updater 1.0.1 → 1.2.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 +47 -24
- package/dist/_chunks/{BulkUpdater-R78pX-om.mjs → BulkUpdater-BDszahRM.mjs} +657 -159
- package/dist/_chunks/BulkUpdater-BDszahRM.mjs.map +1 -0
- package/dist/_chunks/{BulkUpdater-CooMo-Hc.js → BulkUpdater-DCrCPKSe.js} +649 -151
- package/dist/_chunks/BulkUpdater-DCrCPKSe.js.map +1 -0
- package/dist/_chunks/ScopedQuotaSelectInput-ChWrQIBV.mjs +183 -0
- package/dist/_chunks/ScopedQuotaSelectInput-ChWrQIBV.mjs.map +1 -0
- package/dist/_chunks/ScopedQuotaSelectInput-s4oUMLgK.js +201 -0
- package/dist/_chunks/ScopedQuotaSelectInput-s4oUMLgK.js.map +1 -0
- package/dist/_chunks/SettingsPage-BRGTrW9H.js +43 -0
- package/dist/_chunks/SettingsPage-BRGTrW9H.js.map +1 -0
- package/dist/_chunks/SettingsPage-ieu-Out8.mjs +43 -0
- package/dist/_chunks/SettingsPage-ieu-Out8.mjs.map +1 -0
- package/dist/_chunks/ValidationRulesTab-BGcqM9cN.mjs +598 -0
- package/dist/_chunks/ValidationRulesTab-BGcqM9cN.mjs.map +1 -0
- package/dist/_chunks/ValidationRulesTab-BoqhoTjo.js +597 -0
- package/dist/_chunks/ValidationRulesTab-BoqhoTjo.js.map +1 -0
- package/dist/admin/index.js +19 -3
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +19 -3
- package/dist/admin/index.mjs.map +1 -1
- package/dist/server/index.js +30795 -318
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +30785 -318
- package/dist/server/index.mjs.map +1 -1
- package/package.json +10 -3
- package/dist/_chunks/BulkUpdater-CooMo-Hc.js.map +0 -1
- package/dist/_chunks/BulkUpdater-R78pX-om.mjs.map +0 -1
- package/dist/_chunks/SettingsPage-C6QyloJe.js +0 -176
- package/dist/_chunks/SettingsPage-C6QyloJe.js.map +0 -1
- package/dist/_chunks/SettingsPage-Drb7s719.mjs +0 -176
- package/dist/_chunks/SettingsPage-Drb7s719.mjs.map +0 -1
|
@@ -5,8 +5,428 @@ 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-BoqhoTjo.js");
|
|
8
9
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
9
10
|
const React__default = /* @__PURE__ */ _interopDefault(React);
|
|
11
|
+
function CsvManagerTab() {
|
|
12
|
+
const { get, post } = admin.useFetchClient();
|
|
13
|
+
const { toggleNotification } = admin.useNotification();
|
|
14
|
+
const [collections, setCollections] = React.useState([]);
|
|
15
|
+
const [loadingCollections, setLoadingCollections] = React.useState(true);
|
|
16
|
+
const [selectedUid, setSelectedUid] = React.useState("");
|
|
17
|
+
const [exportLimit, setExportLimit] = React.useState(1e3);
|
|
18
|
+
const [exportOnlyViolations, setExportOnlyViolations] = React.useState(false);
|
|
19
|
+
const [rules, setRules] = React.useState([]);
|
|
20
|
+
const [selectedRuleId, setSelectedRuleId] = React.useState("");
|
|
21
|
+
const [importMode, setImportMode] = React.useState("update");
|
|
22
|
+
const [publishOnImport, setPublishOnImport] = React.useState(true);
|
|
23
|
+
const [csvRawText, setCsvRawText] = React.useState("");
|
|
24
|
+
const [fileName, setFileName] = React.useState("");
|
|
25
|
+
const [parsedPreview, setParsedPreview] = React.useState([]);
|
|
26
|
+
const [importing, setImporting] = React.useState(false);
|
|
27
|
+
const [importResult, setImportResult] = React.useState(null);
|
|
28
|
+
React.useEffect(() => {
|
|
29
|
+
fetchInitialData();
|
|
30
|
+
}, []);
|
|
31
|
+
const fetchInitialData = async () => {
|
|
32
|
+
try {
|
|
33
|
+
setLoadingCollections(true);
|
|
34
|
+
const [modelsRes, rulesRes] = await Promise.all([
|
|
35
|
+
get("/bulk-updater/models"),
|
|
36
|
+
get("/bulk-updater/validation-rules")
|
|
37
|
+
]);
|
|
38
|
+
if (modelsRes.data?.collections) {
|
|
39
|
+
setCollections(modelsRes.data.collections);
|
|
40
|
+
if (modelsRes.data.collections.length > 0) {
|
|
41
|
+
setSelectedUid(modelsRes.data.collections[0].uid);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (rulesRes.data?.rules) {
|
|
45
|
+
setRules(rulesRes.data.rules);
|
|
46
|
+
if (rulesRes.data.rules.length > 0) {
|
|
47
|
+
setSelectedRuleId(rulesRes.data.rules[0].id);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
} catch (err) {
|
|
51
|
+
toggleNotification({
|
|
52
|
+
type: "danger",
|
|
53
|
+
message: err.message || "Failed loading collections for CSV Manager"
|
|
54
|
+
});
|
|
55
|
+
} finally {
|
|
56
|
+
setLoadingCollections(false);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
const handleDownloadTemplate = async () => {
|
|
60
|
+
if (!selectedUid) return;
|
|
61
|
+
try {
|
|
62
|
+
const res = await get(`/bulk-updater/csv/template/${selectedUid}`);
|
|
63
|
+
const csvStr = res.data?.csvContent || (typeof res.data === "string" ? res.data : "");
|
|
64
|
+
const filename = res.data?.filename || `${selectedUid.split(".").pop()}_template.csv`;
|
|
65
|
+
downloadCsvFile(csvStr, filename);
|
|
66
|
+
toggleNotification({
|
|
67
|
+
type: "success",
|
|
68
|
+
message: "CSV Template downloaded successfully"
|
|
69
|
+
});
|
|
70
|
+
} catch (err) {
|
|
71
|
+
toggleNotification({
|
|
72
|
+
type: "danger",
|
|
73
|
+
message: err.message || "Failed downloading CSV template"
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
const handleExportCollection = async () => {
|
|
78
|
+
if (!selectedUid) return;
|
|
79
|
+
try {
|
|
80
|
+
const res = await get(`/bulk-updater/csv/export/${selectedUid}?limit=${exportLimit}`);
|
|
81
|
+
const csvStr = res.data?.csvContent || (typeof res.data === "string" ? res.data : "");
|
|
82
|
+
const filename = res.data?.filename || `${selectedUid.split(".").pop()}_export.csv`;
|
|
83
|
+
downloadCsvFile(csvStr, filename);
|
|
84
|
+
toggleNotification({
|
|
85
|
+
type: "success",
|
|
86
|
+
message: "Collection exported to CSV successfully"
|
|
87
|
+
});
|
|
88
|
+
} catch (err) {
|
|
89
|
+
toggleNotification({
|
|
90
|
+
type: "danger",
|
|
91
|
+
message: err.message || "Failed exporting collection to CSV"
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const handleExportViolations = async () => {
|
|
96
|
+
if (!selectedRuleId) return;
|
|
97
|
+
try {
|
|
98
|
+
const res = await get(`/bulk-updater/csv/export-violations/${selectedRuleId}`);
|
|
99
|
+
const csvStr = res.data?.csvContent || (typeof res.data === "string" ? res.data : "");
|
|
100
|
+
const filename = res.data?.filename || `violations_${selectedRuleId}.csv`;
|
|
101
|
+
downloadCsvFile(csvStr, filename);
|
|
102
|
+
toggleNotification({
|
|
103
|
+
type: "success",
|
|
104
|
+
message: "Rule violations exported to CSV successfully"
|
|
105
|
+
});
|
|
106
|
+
} catch (err) {
|
|
107
|
+
toggleNotification({
|
|
108
|
+
type: "danger",
|
|
109
|
+
message: err.message || "Failed exporting violations to CSV"
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
const downloadCsvFile = (content, fallbackName) => {
|
|
114
|
+
if (!content) {
|
|
115
|
+
toggleNotification({
|
|
116
|
+
type: "warning",
|
|
117
|
+
message: "No CSV content to download"
|
|
118
|
+
});
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const blob = new Blob([content], { type: "text/csv;charset=utf-8;" });
|
|
122
|
+
const url = URL.createObjectURL(blob);
|
|
123
|
+
const link = document.createElement("a");
|
|
124
|
+
link.href = url;
|
|
125
|
+
link.setAttribute("download", fallbackName);
|
|
126
|
+
document.body.appendChild(link);
|
|
127
|
+
link.click();
|
|
128
|
+
document.body.removeChild(link);
|
|
129
|
+
URL.revokeObjectURL(url);
|
|
130
|
+
};
|
|
131
|
+
const handleFileUpload = (e) => {
|
|
132
|
+
const file = e.target.files?.[0];
|
|
133
|
+
if (!file) return;
|
|
134
|
+
setFileName(file.name);
|
|
135
|
+
setImportResult(null);
|
|
136
|
+
const reader = new FileReader();
|
|
137
|
+
reader.onload = (event) => {
|
|
138
|
+
const text = event.target?.result;
|
|
139
|
+
setCsvRawText(text);
|
|
140
|
+
try {
|
|
141
|
+
const lines = text.split(/\r?\n/).filter((l) => l.trim().length > 0);
|
|
142
|
+
if (lines.length > 0) {
|
|
143
|
+
const headers = lines[0].split(",").map((h) => h.replace(/^"|"$/g, "").trim());
|
|
144
|
+
const previewRows = [];
|
|
145
|
+
for (let i = 1; i < Math.min(lines.length, 6); i++) {
|
|
146
|
+
const vals = lines[i].split(",").map((v) => v.replace(/^"|"$/g, "").trim());
|
|
147
|
+
const row = {};
|
|
148
|
+
headers.forEach((h, idx) => {
|
|
149
|
+
row[h] = vals[idx] || "";
|
|
150
|
+
});
|
|
151
|
+
previewRows.push(row);
|
|
152
|
+
}
|
|
153
|
+
setParsedPreview(previewRows);
|
|
154
|
+
}
|
|
155
|
+
} catch (err) {
|
|
156
|
+
setParsedPreview([]);
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
reader.readAsText(file);
|
|
160
|
+
};
|
|
161
|
+
const handleExecuteImport = async () => {
|
|
162
|
+
if (!selectedUid || !csvRawText) return;
|
|
163
|
+
try {
|
|
164
|
+
setImporting(true);
|
|
165
|
+
setImportResult(null);
|
|
166
|
+
const res = await post("/bulk-updater/csv/import", {
|
|
167
|
+
uid: selectedUid,
|
|
168
|
+
csvText: csvRawText,
|
|
169
|
+
mode: importMode,
|
|
170
|
+
publish: publishOnImport
|
|
171
|
+
});
|
|
172
|
+
if (res.data && res.data.success) {
|
|
173
|
+
setImportResult(res.data);
|
|
174
|
+
toggleNotification({
|
|
175
|
+
type: "success",
|
|
176
|
+
message: `CSV Import complete: ${res.data.stats.created} created, ${res.data.stats.updated} updated.`
|
|
177
|
+
});
|
|
178
|
+
} else {
|
|
179
|
+
throw new Error(res.data?.error || "Import failed");
|
|
180
|
+
}
|
|
181
|
+
} catch (err) {
|
|
182
|
+
toggleNotification({
|
|
183
|
+
type: "danger",
|
|
184
|
+
message: err.message || "Error processing CSV import"
|
|
185
|
+
});
|
|
186
|
+
} finally {
|
|
187
|
+
setImporting(false);
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
const selectedCol = collections.find((c) => c.uid === selectedUid);
|
|
191
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 6, background: "neutral0", hasRadius: true, shadow: "filterShadow", children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 6, children: [
|
|
192
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", children: [
|
|
193
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
|
|
194
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", tag: "h2", fontWeight: "bold", children: "CSV Export & Import Center" }),
|
|
195
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: "Export all records, filtered subsets, or rule violations into CSV. Correct or add records in spreadsheets and re-upload with full schema & quota enforcement." })
|
|
196
|
+
] }),
|
|
197
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "secondary", startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowClockwise, {}), onClick: fetchInitialData, children: "Refresh" })
|
|
198
|
+
] }),
|
|
199
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 4, background: "neutral100", hasRadius: true, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 4, alignItems: "flex-end", children: [
|
|
200
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { style: { flex: 1 }, children: [
|
|
201
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", marginBottom: 2, children: "Target Collection Type" }),
|
|
202
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
203
|
+
designSystem.SingleSelect,
|
|
204
|
+
{
|
|
205
|
+
value: selectedUid,
|
|
206
|
+
onChange: (val) => {
|
|
207
|
+
setSelectedUid(val);
|
|
208
|
+
setImportResult(null);
|
|
209
|
+
},
|
|
210
|
+
disabled: loadingCollections,
|
|
211
|
+
placeholder: "Select a collection...",
|
|
212
|
+
children: collections.map((col) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.SingleSelectOption, { value: col.uid, children: [
|
|
213
|
+
col.displayName,
|
|
214
|
+
" (",
|
|
215
|
+
col.totalEntries ?? 0,
|
|
216
|
+
" records)"
|
|
217
|
+
] }, col.uid))
|
|
218
|
+
}
|
|
219
|
+
)
|
|
220
|
+
] }),
|
|
221
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
222
|
+
designSystem.Button,
|
|
223
|
+
{
|
|
224
|
+
variant: "tertiary",
|
|
225
|
+
startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Download, {}),
|
|
226
|
+
onClick: handleDownloadTemplate,
|
|
227
|
+
disabled: !selectedUid,
|
|
228
|
+
children: "Download Sample CSV Template"
|
|
229
|
+
}
|
|
230
|
+
)
|
|
231
|
+
] }) }),
|
|
232
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { padding: 5, background: "neutral100", hasRadius: true, children: [
|
|
233
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", tag: "h3", fontWeight: "bold", marginBottom: 2, children: "1. Export Data to CSV" }),
|
|
234
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", marginBottom: 4, children: "Extract entire collections or pinpoint records violating validation quotas." }),
|
|
235
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 4, wrap: "wrap", alignItems: "center", marginTop: 3, children: [
|
|
236
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
237
|
+
designSystem.Button,
|
|
238
|
+
{
|
|
239
|
+
variant: "default",
|
|
240
|
+
startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Download, {}),
|
|
241
|
+
onClick: handleExportCollection,
|
|
242
|
+
disabled: !selectedUid,
|
|
243
|
+
children: [
|
|
244
|
+
"Export All ",
|
|
245
|
+
selectedCol?.displayName || "Collection",
|
|
246
|
+
" Records (.csv)"
|
|
247
|
+
]
|
|
248
|
+
}
|
|
249
|
+
),
|
|
250
|
+
rules.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", style: { marginLeft: "auto" }, children: [
|
|
251
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
252
|
+
designSystem.SingleSelect,
|
|
253
|
+
{
|
|
254
|
+
value: selectedRuleId,
|
|
255
|
+
onChange: (val) => setSelectedRuleId(val),
|
|
256
|
+
placeholder: "Select Quota Rule...",
|
|
257
|
+
children: rules.map((r) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.SingleSelectOption, { value: r.id, children: [
|
|
258
|
+
"Rule: ",
|
|
259
|
+
r.name
|
|
260
|
+
] }, r.id))
|
|
261
|
+
}
|
|
262
|
+
),
|
|
263
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
264
|
+
designSystem.Button,
|
|
265
|
+
{
|
|
266
|
+
variant: "danger-light",
|
|
267
|
+
startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Download, {}),
|
|
268
|
+
onClick: handleExportViolations,
|
|
269
|
+
disabled: !selectedRuleId,
|
|
270
|
+
children: "Export Violators CSV"
|
|
271
|
+
}
|
|
272
|
+
)
|
|
273
|
+
] })
|
|
274
|
+
] })
|
|
275
|
+
] }),
|
|
276
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { padding: 5, background: "neutral100", hasRadius: true, children: [
|
|
277
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", tag: "h3", fontWeight: "bold", marginBottom: 2, children: "2. Import & Batch Override CSV" }),
|
|
278
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", marginBottom: 4, children: "Upload an updated CSV file to bulk update existing records or insert new records." }),
|
|
279
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 6, marginBottom: 4, wrap: "wrap", children: [
|
|
280
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
|
|
281
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", marginBottom: 2, children: "Operation Mode" }),
|
|
282
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 4, children: [
|
|
283
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { style: { display: "flex", alignItems: "center", gap: 6, cursor: "pointer" }, children: [
|
|
284
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
285
|
+
"input",
|
|
286
|
+
{
|
|
287
|
+
type: "radio",
|
|
288
|
+
name: "importMode",
|
|
289
|
+
value: "update",
|
|
290
|
+
checked: importMode === "update",
|
|
291
|
+
onChange: () => setImportMode("update")
|
|
292
|
+
}
|
|
293
|
+
),
|
|
294
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: importMode === "update" ? "bold" : "normal", children: "Update Existing (Matches by documentId)" })
|
|
295
|
+
] }),
|
|
296
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { style: { display: "flex", alignItems: "center", gap: 6, cursor: "pointer" }, children: [
|
|
297
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
298
|
+
"input",
|
|
299
|
+
{
|
|
300
|
+
type: "radio",
|
|
301
|
+
name: "importMode",
|
|
302
|
+
value: "create_or_override",
|
|
303
|
+
checked: importMode === "create_or_override",
|
|
304
|
+
onChange: () => setImportMode("create_or_override")
|
|
305
|
+
}
|
|
306
|
+
),
|
|
307
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: importMode === "create_or_override" ? "bold" : "normal", children: "Add / Override (Inserts new or replaces existing)" })
|
|
308
|
+
] })
|
|
309
|
+
] })
|
|
310
|
+
] }),
|
|
311
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { style: { marginLeft: "auto" }, children: [
|
|
312
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", marginBottom: 2, children: "Publish Options" }),
|
|
313
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
314
|
+
designSystem.Checkbox,
|
|
315
|
+
{
|
|
316
|
+
checked: publishOnImport,
|
|
317
|
+
onValueChange: (val) => setPublishOnImport(val),
|
|
318
|
+
children: "Auto-publish on import"
|
|
319
|
+
}
|
|
320
|
+
)
|
|
321
|
+
] })
|
|
322
|
+
] }),
|
|
323
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
324
|
+
designSystem.Box,
|
|
325
|
+
{
|
|
326
|
+
padding: 6,
|
|
327
|
+
background: "neutral0",
|
|
328
|
+
hasRadius: true,
|
|
329
|
+
style: {
|
|
330
|
+
border: "2px dashed #dcdce4",
|
|
331
|
+
textAlign: "center",
|
|
332
|
+
cursor: "pointer"
|
|
333
|
+
},
|
|
334
|
+
children: [
|
|
335
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
336
|
+
"input",
|
|
337
|
+
{
|
|
338
|
+
type: "file",
|
|
339
|
+
accept: ".csv",
|
|
340
|
+
id: "csv-file-input",
|
|
341
|
+
style: { display: "none" },
|
|
342
|
+
onChange: handleFileUpload
|
|
343
|
+
}
|
|
344
|
+
),
|
|
345
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: "csv-file-input", style: { cursor: "pointer", display: "block" }, children: [
|
|
346
|
+
/* @__PURE__ */ jsxRuntime.jsx(icons.Upload, { style: { width: 32, height: 32, margin: "0 auto 8px", color: "#4945ff" } }),
|
|
347
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", fontWeight: "bold", display: "block", children: fileName ? `Selected: ${fileName}` : "Click here or drag a .csv file to upload" }),
|
|
348
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral500", children: "UTF-8 encoded CSV matching collection schema headers" })
|
|
349
|
+
] })
|
|
350
|
+
]
|
|
351
|
+
}
|
|
352
|
+
),
|
|
353
|
+
parsedPreview.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { marginTop: 4, background: "neutral0", padding: 4, hasRadius: true, children: [
|
|
354
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 3, children: [
|
|
355
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "sigma", textColor: "neutral700", children: [
|
|
356
|
+
"FILE PREVIEW (FIRST ",
|
|
357
|
+
parsedPreview.length,
|
|
358
|
+
" ROWS)"
|
|
359
|
+
] }),
|
|
360
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: "neutral150", textColor: "neutral800", children: "Ready to Import" })
|
|
361
|
+
] }),
|
|
362
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Table, { colCount: Object.keys(parsedPreview[0]).length, rowCount: parsedPreview.length + 1, children: [
|
|
363
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Thead, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tr, { children: Object.keys(parsedPreview[0]).map((h) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: h }) }, h)) }) }),
|
|
364
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Tbody, { children: parsedPreview.map((row, rIdx) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tr, { children: Object.keys(parsedPreview[0]).map((h) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", children: row[h] || "-" }) }, h)) }, rIdx)) })
|
|
365
|
+
] }),
|
|
366
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "flex-end", marginTop: 4, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
367
|
+
designSystem.Button,
|
|
368
|
+
{
|
|
369
|
+
variant: "default",
|
|
370
|
+
size: "L",
|
|
371
|
+
startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Check, {}),
|
|
372
|
+
onClick: handleExecuteImport,
|
|
373
|
+
loading: importing,
|
|
374
|
+
children: importMode === "update" ? "Execute Bulk Update" : "Execute Add / Override"
|
|
375
|
+
}
|
|
376
|
+
) })
|
|
377
|
+
] }),
|
|
378
|
+
importResult && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 4, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
379
|
+
designSystem.Alert,
|
|
380
|
+
{
|
|
381
|
+
variant: importResult.stats.errors.length > 0 ? "warning" : "success",
|
|
382
|
+
title: "CSV Import Results",
|
|
383
|
+
children: [
|
|
384
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "omega", display: "block", marginBottom: 1, children: [
|
|
385
|
+
"Successfully processed: ",
|
|
386
|
+
/* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
|
|
387
|
+
importResult.stats.created,
|
|
388
|
+
" created"
|
|
389
|
+
] }),
|
|
390
|
+
",",
|
|
391
|
+
" ",
|
|
392
|
+
/* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
|
|
393
|
+
importResult.stats.updated,
|
|
394
|
+
" updated"
|
|
395
|
+
] }),
|
|
396
|
+
",",
|
|
397
|
+
" ",
|
|
398
|
+
/* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
|
|
399
|
+
importResult.stats.skipped,
|
|
400
|
+
" skipped"
|
|
401
|
+
] }),
|
|
402
|
+
" out of ",
|
|
403
|
+
importResult.stats.total,
|
|
404
|
+
" total rows."
|
|
405
|
+
] }),
|
|
406
|
+
importResult.stats.errors.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { marginTop: 2, children: [
|
|
407
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "pi", textColor: "danger700", fontWeight: "bold", children: [
|
|
408
|
+
"Errors encountered (",
|
|
409
|
+
importResult.stats.errors.length,
|
|
410
|
+
"):"
|
|
411
|
+
] }),
|
|
412
|
+
/* @__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: [
|
|
413
|
+
"Row ",
|
|
414
|
+
err.row,
|
|
415
|
+
": ",
|
|
416
|
+
err.error
|
|
417
|
+
] }) }, idx)) })
|
|
418
|
+
] })
|
|
419
|
+
]
|
|
420
|
+
}
|
|
421
|
+
) })
|
|
422
|
+
] })
|
|
423
|
+
] }) });
|
|
424
|
+
}
|
|
425
|
+
function getNestedValue(obj, path) {
|
|
426
|
+
if (!obj || !path) return void 0;
|
|
427
|
+
if (!path.includes(".")) return obj[path];
|
|
428
|
+
return path.split(".").reduce((acc, part) => acc && typeof acc === "object" ? acc[part] : void 0, obj);
|
|
429
|
+
}
|
|
10
430
|
function getAvailableColumnsForCollection(col, selectedAttribute) {
|
|
11
431
|
const cols = [
|
|
12
432
|
{
|
|
@@ -27,7 +447,7 @@ function getAvailableColumnsForCollection(col, selectedAttribute) {
|
|
|
27
447
|
if (attr === "name" || attr === "title" || attr === selectedAttribute) {
|
|
28
448
|
return;
|
|
29
449
|
}
|
|
30
|
-
const formattedLabel = attr.charAt(0).toUpperCase() + attr.slice(1);
|
|
450
|
+
const formattedLabel = attr.includes(".") ? attr.split(".").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" > ") : attr.charAt(0).toUpperCase() + attr.slice(1);
|
|
31
451
|
cols.push({
|
|
32
452
|
key: `attr_${attr}`,
|
|
33
453
|
label: formattedLabel,
|
|
@@ -113,7 +533,7 @@ function renderCellContent(colDef, entry, col, selectedAttribute, isMatch, hasAt
|
|
|
113
533
|
] });
|
|
114
534
|
}
|
|
115
535
|
case "target_attr": {
|
|
116
|
-
const val = entry
|
|
536
|
+
const val = getNestedValue(entry, selectedAttribute);
|
|
117
537
|
const displayStr = formatDisplayValue(val);
|
|
118
538
|
const isUnset = displayStr === "(empty / not set)" || displayStr === "(empty / unlinked)";
|
|
119
539
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -143,7 +563,7 @@ function renderCellContent(colDef, entry, col, selectedAttribute, isMatch, hasAt
|
|
|
143
563
|
}
|
|
144
564
|
default: {
|
|
145
565
|
const attrName = colDef.key.replace("attr_", "");
|
|
146
|
-
const rawVal = entry
|
|
566
|
+
const rawVal = getNestedValue(entry, attrName);
|
|
147
567
|
const displayStr = formatDisplayValue(rawVal);
|
|
148
568
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
149
569
|
designSystem.Typography,
|
|
@@ -163,7 +583,7 @@ const BulkUpdater = () => {
|
|
|
163
583
|
try {
|
|
164
584
|
const params = new URLSearchParams(window.location.search);
|
|
165
585
|
const t = params.get("tab");
|
|
166
|
-
if (t === "audit" || t === "editor") return t;
|
|
586
|
+
if (t === "audit" || t === "editor" || t === "rules" || t === "csv") return t;
|
|
167
587
|
} catch {
|
|
168
588
|
}
|
|
169
589
|
return "editor";
|
|
@@ -182,7 +602,6 @@ const BulkUpdater = () => {
|
|
|
182
602
|
const [updating, setUpdating] = React.useState(false);
|
|
183
603
|
const [attributes, setAttributes] = React.useState([]);
|
|
184
604
|
const [collections, setCollections] = React.useState([]);
|
|
185
|
-
const [license, setLicense] = React.useState(null);
|
|
186
605
|
const [auditEnabled, setAuditEnabled] = React.useState(false);
|
|
187
606
|
const [executionWindow, setExecutionWindow] = React.useState(null);
|
|
188
607
|
const [showConfirmModal, setShowConfirmModal] = React.useState(false);
|
|
@@ -218,7 +637,8 @@ const BulkUpdater = () => {
|
|
|
218
637
|
const [regexPattern, setRegexPattern] = React.useState("");
|
|
219
638
|
const [filterOperator, setFilterOperator] = React.useState("none");
|
|
220
639
|
const [filterQuery, setFilterQuery] = React.useState("");
|
|
221
|
-
const [
|
|
640
|
+
const [entrySearch, setEntrySearch] = React.useState("");
|
|
641
|
+
const isFilterActive = filterOperator !== "none" && (["empty", "not_empty"].includes(filterOperator) || Boolean(filterQuery.trim())) || Boolean(entrySearch.trim());
|
|
222
642
|
const [lastResults, setLastResults] = React.useState(null);
|
|
223
643
|
const [updateSummary, setUpdateSummary] = React.useState(null);
|
|
224
644
|
const [collectionPages, setCollectionPages] = React.useState({});
|
|
@@ -270,7 +690,6 @@ const BulkUpdater = () => {
|
|
|
270
690
|
setAttributes(res.data.attributes || []);
|
|
271
691
|
const cols = res.data.collections || [];
|
|
272
692
|
setCollections(cols);
|
|
273
|
-
setLicense(res.data.license || null);
|
|
274
693
|
setAuditEnabled(Boolean(res.data.auditEnabled));
|
|
275
694
|
if (res.data.executionWindow) {
|
|
276
695
|
setExecutionWindow(res.data.executionWindow);
|
|
@@ -315,12 +734,15 @@ const BulkUpdater = () => {
|
|
|
315
734
|
setLoading(false);
|
|
316
735
|
}
|
|
317
736
|
};
|
|
318
|
-
const loadCollectionPage = async (colUid, targetPage, customPageSize, customSortField, customSortOrder) => {
|
|
737
|
+
const loadCollectionPage = async (colUid, targetPage, customPageSize, customSortField, customSortOrder, overrideFilterOp, overrideFilterQuery, overrideEntrySearch, autoSelectReturned = true) => {
|
|
319
738
|
const currentPageState = collectionPages[colUid];
|
|
320
739
|
const size = customPageSize || currentPageState?.pageSize || defaultPageSize;
|
|
321
740
|
const currentSort = collectionSorts[colUid] || { field: "createdAt", order: "desc" };
|
|
322
741
|
const sortField = customSortField !== void 0 ? customSortField : currentSort.field;
|
|
323
742
|
const sortOrder = customSortOrder !== void 0 ? customSortOrder : currentSort.order;
|
|
743
|
+
const op = overrideFilterOp !== void 0 ? overrideFilterOp : filterOperator;
|
|
744
|
+
const q = overrideFilterQuery !== void 0 ? overrideFilterQuery : filterQuery;
|
|
745
|
+
const s = overrideEntrySearch !== void 0 ? overrideEntrySearch : entrySearch;
|
|
324
746
|
setCollectionPages((prev) => ({
|
|
325
747
|
...prev,
|
|
326
748
|
[colUid]: {
|
|
@@ -334,16 +756,20 @@ const BulkUpdater = () => {
|
|
|
334
756
|
pageSize: String(size)
|
|
335
757
|
});
|
|
336
758
|
if (selectedAttribute) params.set("attribute", selectedAttribute);
|
|
337
|
-
if (
|
|
338
|
-
params.set("filterOperator",
|
|
339
|
-
if (
|
|
759
|
+
if (op && op !== "none") {
|
|
760
|
+
params.set("filterOperator", op);
|
|
761
|
+
if (q) params.set("filterQuery", q);
|
|
762
|
+
}
|
|
763
|
+
if (s && s.trim()) {
|
|
764
|
+
params.set("search", s.trim());
|
|
340
765
|
}
|
|
341
766
|
if (sortField) {
|
|
342
767
|
params.set("sortField", sortField);
|
|
343
768
|
params.set("sortOrder", sortOrder);
|
|
344
769
|
}
|
|
345
770
|
const res = await get(`/bulk-updater/collections/${colUid}/entries?${params.toString()}`);
|
|
346
|
-
if (res.data && res.data.success) {
|
|
771
|
+
if (res.data && (res.data.success || res.data.entries !== void 0)) {
|
|
772
|
+
const fetchedEntries = res.data.entries || [];
|
|
347
773
|
setCollectionPages((prev) => ({
|
|
348
774
|
...prev,
|
|
349
775
|
[colUid]: {
|
|
@@ -351,10 +777,20 @@ const BulkUpdater = () => {
|
|
|
351
777
|
pageSize: res.data.pagination.pageSize,
|
|
352
778
|
total: res.data.pagination.total,
|
|
353
779
|
pageCount: res.data.pagination.pageCount,
|
|
354
|
-
entries:
|
|
780
|
+
entries: fetchedEntries,
|
|
355
781
|
loading: false
|
|
356
782
|
}
|
|
357
783
|
}));
|
|
784
|
+
const isFilterActiveNow = op !== "none" && (["empty", "not_empty"].includes(op) || Boolean(q.trim())) || Boolean(s.trim());
|
|
785
|
+
if (isFilterActiveNow && autoSelectReturned) {
|
|
786
|
+
setSelectedEntries((prev) => {
|
|
787
|
+
const next = { ...prev };
|
|
788
|
+
fetchedEntries.forEach((e) => {
|
|
789
|
+
next[`${colUid}${KEY_SEP}${e.documentId}`] = true;
|
|
790
|
+
});
|
|
791
|
+
return next;
|
|
792
|
+
});
|
|
793
|
+
}
|
|
358
794
|
}
|
|
359
795
|
} catch (err) {
|
|
360
796
|
toggleNotification({
|
|
@@ -418,6 +854,35 @@ const BulkUpdater = () => {
|
|
|
418
854
|
fetchPendingBatches();
|
|
419
855
|
}
|
|
420
856
|
}, [activeTab]);
|
|
857
|
+
const isInitialFilterMount = React.useRef(true);
|
|
858
|
+
React.useEffect(() => {
|
|
859
|
+
if (isInitialFilterMount.current) {
|
|
860
|
+
isInitialFilterMount.current = false;
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
const timer = setTimeout(() => {
|
|
864
|
+
if (collections.length > 0) {
|
|
865
|
+
const isFilterActiveNow = filterOperator !== "none" && (["empty", "not_empty"].includes(filterOperator) || Boolean(filterQuery.trim())) || Boolean(entrySearch.trim());
|
|
866
|
+
if (isFilterActiveNow) {
|
|
867
|
+
setSelectedEntries({});
|
|
868
|
+
}
|
|
869
|
+
collections.forEach((col) => {
|
|
870
|
+
loadCollectionPage(
|
|
871
|
+
col.uid,
|
|
872
|
+
1,
|
|
873
|
+
void 0,
|
|
874
|
+
void 0,
|
|
875
|
+
void 0,
|
|
876
|
+
filterOperator,
|
|
877
|
+
filterQuery,
|
|
878
|
+
entrySearch,
|
|
879
|
+
true
|
|
880
|
+
);
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
}, 350);
|
|
884
|
+
return () => clearTimeout(timer);
|
|
885
|
+
}, [filterOperator, filterQuery, entrySearch]);
|
|
421
886
|
const KEY_SEP = "@@@";
|
|
422
887
|
const handleAttributeChange = (newAttr) => {
|
|
423
888
|
if (newAttr !== selectedAttribute) {
|
|
@@ -425,7 +890,7 @@ const BulkUpdater = () => {
|
|
|
425
890
|
setSelectedEntries({});
|
|
426
891
|
setFilterOperator("none");
|
|
427
892
|
setFilterQuery("");
|
|
428
|
-
|
|
893
|
+
setEntrySearch("");
|
|
429
894
|
setSelectedRelationDocId("");
|
|
430
895
|
setAttributeValue("");
|
|
431
896
|
if (relationsMeta[newAttr]) {
|
|
@@ -442,7 +907,7 @@ const BulkUpdater = () => {
|
|
|
442
907
|
(c) => visibleTypeUids[c.uid] !== false && (!collectionSearch.trim() || c.displayName.toLowerCase().includes(collectionSearch.toLowerCase().trim()) || c.uid.toLowerCase().includes(collectionSearch.toLowerCase().trim()))
|
|
443
908
|
);
|
|
444
909
|
const handleGlobalPageSizeChange = (newSize) => {
|
|
445
|
-
const capped = Math.min(
|
|
910
|
+
const capped = Math.min(500, Math.max(1, newSize));
|
|
446
911
|
setDefaultPageSize(capped);
|
|
447
912
|
collections.forEach((col) => {
|
|
448
913
|
if (!col.isSingleType) {
|
|
@@ -451,7 +916,7 @@ const BulkUpdater = () => {
|
|
|
451
916
|
});
|
|
452
917
|
};
|
|
453
918
|
const handleCollectionPageSizeChange = (colUid, newSize) => {
|
|
454
|
-
const capped = Math.min(
|
|
919
|
+
const capped = Math.min(500, Math.max(1, newSize));
|
|
455
920
|
loadCollectionPage(colUid, 1, capped);
|
|
456
921
|
};
|
|
457
922
|
const handleCollectionSortChange = (colUid, field, order) => {
|
|
@@ -475,7 +940,7 @@ const BulkUpdater = () => {
|
|
|
475
940
|
};
|
|
476
941
|
const entryMatchesFilter = (entry, attr) => {
|
|
477
942
|
if (filterOperator === "none") return true;
|
|
478
|
-
const val = entry
|
|
943
|
+
const val = getNestedValue(entry, attr);
|
|
479
944
|
const displayStr = formatDisplayValue(val);
|
|
480
945
|
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)";
|
|
481
946
|
switch (filterOperator) {
|
|
@@ -495,64 +960,48 @@ const BulkUpdater = () => {
|
|
|
495
960
|
};
|
|
496
961
|
const getVisibleEntries = (col) => {
|
|
497
962
|
const pageState = collectionPages[col.uid];
|
|
498
|
-
|
|
499
|
-
if (!hideNonMatching || filterOperator === "none") {
|
|
500
|
-
return entries;
|
|
501
|
-
}
|
|
502
|
-
return entries.filter((e) => entryMatchesFilter(e, selectedAttribute));
|
|
963
|
+
return pageState ? pageState.entries : col.entries || [];
|
|
503
964
|
};
|
|
504
965
|
const matchingEntriesCount = React__default.default.useMemo(() => {
|
|
505
|
-
if (
|
|
966
|
+
if (!isFilterActive) return 0;
|
|
506
967
|
let count = 0;
|
|
507
968
|
filteredCollections.forEach((col) => {
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
entries.forEach((entry) => {
|
|
512
|
-
if (entryMatchesFilter(entry, selectedAttribute)) {
|
|
513
|
-
count++;
|
|
514
|
-
}
|
|
515
|
-
});
|
|
969
|
+
const pageState = collectionPages[col.uid];
|
|
970
|
+
if (pageState) {
|
|
971
|
+
count += pageState.total;
|
|
516
972
|
}
|
|
517
973
|
});
|
|
518
974
|
return count;
|
|
519
|
-
}, [filteredCollections, collectionPages,
|
|
975
|
+
}, [filteredCollections, collectionPages, isFilterActive]);
|
|
520
976
|
const selectAllMatching = () => {
|
|
521
977
|
const updated = { ...selectedEntries };
|
|
522
978
|
filteredCollections.forEach((col) => {
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
updated[`${col.uid}${KEY_SEP}${e.documentId}`] = true;
|
|
529
|
-
}
|
|
530
|
-
});
|
|
531
|
-
}
|
|
979
|
+
const pageState = collectionPages[col.uid];
|
|
980
|
+
const entries = pageState ? pageState.entries : col.entries || [];
|
|
981
|
+
entries.forEach((e) => {
|
|
982
|
+
updated[`${col.uid}${KEY_SEP}${e.documentId}`] = true;
|
|
983
|
+
});
|
|
532
984
|
});
|
|
533
985
|
setSelectedEntries(updated);
|
|
534
986
|
};
|
|
535
987
|
const deselectAllMatching = () => {
|
|
536
988
|
const updated = { ...selectedEntries };
|
|
537
989
|
filteredCollections.forEach((col) => {
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
delete updated[`${col.uid}${KEY_SEP}${e.documentId}`];
|
|
544
|
-
}
|
|
545
|
-
});
|
|
546
|
-
}
|
|
990
|
+
const pageState = collectionPages[col.uid];
|
|
991
|
+
const entries = pageState ? pageState.entries : col.entries || [];
|
|
992
|
+
entries.forEach((e) => {
|
|
993
|
+
delete updated[`${col.uid}${KEY_SEP}${e.documentId}`];
|
|
994
|
+
});
|
|
547
995
|
});
|
|
548
996
|
setSelectedEntries(updated);
|
|
549
997
|
};
|
|
550
998
|
const clearFilter = () => {
|
|
551
999
|
setFilterOperator("none");
|
|
552
1000
|
setFilterQuery("");
|
|
553
|
-
|
|
1001
|
+
setEntrySearch("");
|
|
1002
|
+
setSelectedEntries({});
|
|
554
1003
|
collections.forEach((col) => {
|
|
555
|
-
loadCollectionPage(col.uid, 1);
|
|
1004
|
+
loadCollectionPage(col.uid, 1, void 0, void 0, void 0, "none", "", "", false);
|
|
556
1005
|
});
|
|
557
1006
|
};
|
|
558
1007
|
const isCollectionFullySelected = (col) => {
|
|
@@ -618,13 +1067,6 @@ const BulkUpdater = () => {
|
|
|
618
1067
|
});
|
|
619
1068
|
return;
|
|
620
1069
|
}
|
|
621
|
-
if (useRegex && !license?.isPro) {
|
|
622
|
-
toggleNotification({
|
|
623
|
-
type: "warning",
|
|
624
|
-
message: "Regex replacement is a Pro feature. Please activate your license in Settings."
|
|
625
|
-
});
|
|
626
|
-
return;
|
|
627
|
-
}
|
|
628
1070
|
const totalSelected = Object.values(selectedEntries).filter(Boolean).length;
|
|
629
1071
|
if (totalSelected === 0) {
|
|
630
1072
|
toggleNotification({
|
|
@@ -681,6 +1123,7 @@ const BulkUpdater = () => {
|
|
|
681
1123
|
message: `Bulk update complete! Batch ID: ${res.data.batchId}. Updated: ${res.data.updatedCount}, Skipped: ${res.data.skippedCount}`
|
|
682
1124
|
});
|
|
683
1125
|
await fetchModels();
|
|
1126
|
+
await fetchAuditHistory();
|
|
684
1127
|
}
|
|
685
1128
|
} else {
|
|
686
1129
|
toggleNotification({
|
|
@@ -881,14 +1324,6 @@ const BulkUpdater = () => {
|
|
|
881
1324
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
|
|
882
1325
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 3, alignItems: "center", children: [
|
|
883
1326
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", fontWeight: "bold", children: "Bulk Attribute Updater" }),
|
|
884
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
885
|
-
designSystem.Badge,
|
|
886
|
-
{
|
|
887
|
-
backgroundColor: license?.isPro ? "success100" : "neutral200",
|
|
888
|
-
textColor: license?.isPro ? "success700" : "neutral700",
|
|
889
|
-
children: license?.isPro ? `${license.tier.toUpperCase()} EDITION` : "COMMUNITY EDITION"
|
|
890
|
-
}
|
|
891
|
-
),
|
|
892
1327
|
auditEnabled && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: "secondary100", textColor: "secondary700", children: "AUDIT & ROLLBACK ACTIVE" })
|
|
893
1328
|
] }),
|
|
894
1329
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", textColor: "neutral600", children: "Cross-collection batch attribute management with declarative audit trail and one-click rollback." })
|
|
@@ -929,6 +1364,24 @@ const BulkUpdater = () => {
|
|
|
929
1364
|
] }) : auditHistory.length > 0 ? ` (${auditHistory.length})` : ""
|
|
930
1365
|
]
|
|
931
1366
|
}
|
|
1367
|
+
),
|
|
1368
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1369
|
+
designSystem.Button,
|
|
1370
|
+
{
|
|
1371
|
+
variant: activeTab === "rules" ? "default" : "tertiary",
|
|
1372
|
+
onClick: () => setActiveTab("rules"),
|
|
1373
|
+
size: "M",
|
|
1374
|
+
children: "Validation & Quota Rules"
|
|
1375
|
+
}
|
|
1376
|
+
),
|
|
1377
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1378
|
+
designSystem.Button,
|
|
1379
|
+
{
|
|
1380
|
+
variant: activeTab === "csv" ? "default" : "tertiary",
|
|
1381
|
+
onClick: () => setActiveTab("csv"),
|
|
1382
|
+
size: "M",
|
|
1383
|
+
children: "CSV Import / Export & Override"
|
|
1384
|
+
}
|
|
932
1385
|
)
|
|
933
1386
|
] }),
|
|
934
1387
|
executionWindow && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 2, alignItems: "center", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -957,7 +1410,7 @@ const BulkUpdater = () => {
|
|
|
957
1410
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "pi", textColor: "neutral700", children: [
|
|
958
1411
|
/* @__PURE__ */ jsxRuntime.jsx("code", { children: latestActiveBatch.batchId }),
|
|
959
1412
|
" (",
|
|
960
|
-
latestActiveBatch.
|
|
1413
|
+
latestActiveBatch.updatedCount,
|
|
961
1414
|
" entries updated by ",
|
|
962
1415
|
latestActiveBatch.userEmail,
|
|
963
1416
|
")"
|
|
@@ -1108,38 +1561,24 @@ const BulkUpdater = () => {
|
|
|
1108
1561
|
}
|
|
1109
1562
|
) })
|
|
1110
1563
|
] }),
|
|
1111
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1112
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
)
|
|
1130
|
-
] }),
|
|
1131
|
-
useRegex && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 1, minWidth: 240 }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1132
|
-
designSystem.TextInput,
|
|
1133
|
-
{
|
|
1134
|
-
placeholder: "Regex pattern (e.g. \\b(OldName)\\b)...",
|
|
1135
|
-
value: regexPattern,
|
|
1136
|
-
onChange: (e) => setRegexPattern(e.target.value),
|
|
1137
|
-
disabled: !license?.isPro
|
|
1138
|
-
}
|
|
1139
|
-
) })
|
|
1140
|
-
] }),
|
|
1141
|
-
!license?.isPro && useRegex && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 2, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "warning700", children: "Regex replacement is locked to Pro license holders. Visit Settings > Bulk Updater to activate your key." }) })
|
|
1142
|
-
] }),
|
|
1564
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 4, padding: 4, background: "neutral100", hasRadius: true, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", wrap: "wrap", gap: 3, children: [
|
|
1565
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 2, alignItems: "center", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1566
|
+
designSystem.Checkbox,
|
|
1567
|
+
{
|
|
1568
|
+
checked: useRegex,
|
|
1569
|
+
onCheckedChange: (checked) => setUseRegex(Boolean(checked)),
|
|
1570
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: "Enable Regex Find & Replace" })
|
|
1571
|
+
}
|
|
1572
|
+
) }),
|
|
1573
|
+
useRegex && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 1, minWidth: 240 }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1574
|
+
designSystem.TextInput,
|
|
1575
|
+
{
|
|
1576
|
+
placeholder: "Regex pattern (e.g. \\b(OldName)\\b)...",
|
|
1577
|
+
value: regexPattern,
|
|
1578
|
+
onChange: (e) => setRegexPattern(e.target.value)
|
|
1579
|
+
}
|
|
1580
|
+
) })
|
|
1581
|
+
] }) }),
|
|
1143
1582
|
selectedAttribute && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 4, padding: 3, background: "neutral100", hasRadius: true, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
|
|
1144
1583
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", children: "Attribute Info:" }),
|
|
1145
1584
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "pi", children: [
|
|
@@ -1198,24 +1637,25 @@ const BulkUpdater = () => {
|
|
|
1198
1637
|
children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 3, children: [
|
|
1199
1638
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", wrap: "wrap", gap: 2, children: [
|
|
1200
1639
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", children: [
|
|
1201
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "bold", children: "
|
|
1202
|
-
|
|
1640
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "bold", children: "Search & Filter Targets:" }),
|
|
1641
|
+
isFilterActive && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Badge, { backgroundColor: "primary100", textColor: "primary700", children: [
|
|
1203
1642
|
matchingEntriesCount,
|
|
1204
1643
|
" matching ",
|
|
1205
|
-
matchingEntriesCount === 1 ? "entry" : "entries"
|
|
1644
|
+
matchingEntriesCount === 1 ? "entry" : "entries",
|
|
1645
|
+
" found in database"
|
|
1206
1646
|
] })
|
|
1207
1647
|
] }),
|
|
1208
|
-
|
|
1648
|
+
isFilterActive && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "ghost", size: "S", onClick: clearFilter, children: "Clear Search & Filter" })
|
|
1209
1649
|
] }),
|
|
1210
1650
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 3, alignItems: "flex-end", wrap: "wrap", children: [
|
|
1211
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width:
|
|
1651
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: 220, minWidth: 180 }, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1212
1652
|
designSystem.SingleSelect,
|
|
1213
1653
|
{
|
|
1214
1654
|
label: `Filter condition for "${selectedAttribute}"`,
|
|
1215
1655
|
value: filterOperator,
|
|
1216
1656
|
onChange: (val) => setFilterOperator(String(val)),
|
|
1217
1657
|
children: [
|
|
1218
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "none", children: "Show All (No Filter)" }),
|
|
1658
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "none", children: "Show All (No Attribute Filter)" }),
|
|
1219
1659
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "empty", children: "Is Empty or Null" }),
|
|
1220
1660
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "not_empty", children: "Is Not Empty" }),
|
|
1221
1661
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "equals", children: "Equals Exact Text" }),
|
|
@@ -1224,28 +1664,33 @@ const BulkUpdater = () => {
|
|
|
1224
1664
|
]
|
|
1225
1665
|
}
|
|
1226
1666
|
) }),
|
|
1227
|
-
(filterOperator === "equals" || filterOperator === "contains" || filterOperator === "starts_with") && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 1, minWidth:
|
|
1667
|
+
(filterOperator === "equals" || filterOperator === "contains" || filterOperator === "starts_with") && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 1, minWidth: 200 }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1228
1668
|
designSystem.TextInput,
|
|
1229
1669
|
{
|
|
1230
|
-
label:
|
|
1670
|
+
label: `Value for "${selectedAttribute}"`,
|
|
1231
1671
|
placeholder: "Type value to match...",
|
|
1232
1672
|
value: filterQuery,
|
|
1233
1673
|
onChange: (e) => setFilterQuery(e.target.value)
|
|
1234
1674
|
}
|
|
1235
1675
|
) }),
|
|
1236
|
-
|
|
1237
|
-
|
|
1676
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 1, minWidth: 200 }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1677
|
+
designSystem.TextInput,
|
|
1678
|
+
{
|
|
1679
|
+
label: "Full-text Entry Search",
|
|
1680
|
+
placeholder: "Search title, name, or text across records...",
|
|
1681
|
+
value: entrySearch,
|
|
1682
|
+
onChange: (e) => setEntrySearch(e.target.value)
|
|
1683
|
+
}
|
|
1684
|
+
) }),
|
|
1685
|
+
isFilterActive && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", children: [
|
|
1686
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1238
1687
|
designSystem.Button,
|
|
1239
1688
|
{
|
|
1240
1689
|
variant: "default",
|
|
1241
1690
|
size: "S",
|
|
1242
1691
|
onClick: selectAllMatching,
|
|
1243
1692
|
disabled: matchingEntriesCount === 0,
|
|
1244
|
-
children:
|
|
1245
|
-
"Select Matching (",
|
|
1246
|
-
matchingEntriesCount,
|
|
1247
|
-
")"
|
|
1248
|
-
]
|
|
1693
|
+
children: "Select All Loaded"
|
|
1249
1694
|
}
|
|
1250
1695
|
),
|
|
1251
1696
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1255,19 +1700,12 @@ const BulkUpdater = () => {
|
|
|
1255
1700
|
size: "S",
|
|
1256
1701
|
onClick: deselectAllMatching,
|
|
1257
1702
|
disabled: matchingEntriesCount === 0,
|
|
1258
|
-
children: "Deselect
|
|
1703
|
+
children: "Deselect All Loaded"
|
|
1259
1704
|
}
|
|
1260
1705
|
)
|
|
1261
1706
|
] })
|
|
1262
1707
|
] }),
|
|
1263
|
-
|
|
1264
|
-
designSystem.Checkbox,
|
|
1265
|
-
{
|
|
1266
|
-
checked: hideNonMatching,
|
|
1267
|
-
onCheckedChange: (checked) => setHideNonMatching(Boolean(checked)),
|
|
1268
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral700", children: "Only display matching entries in tables (hide non-matching)" })
|
|
1269
|
-
}
|
|
1270
|
-
) })
|
|
1708
|
+
isFilterActive && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 2, alignItems: "center", marginTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { backgroundColor: "success100", textColor: "success700", size: "S", children: "✓ Filter active: Showing only matching entries. All returned matching records are pre-selected." }) })
|
|
1271
1709
|
] })
|
|
1272
1710
|
}
|
|
1273
1711
|
),
|
|
@@ -1361,8 +1799,8 @@ const BulkUpdater = () => {
|
|
|
1361
1799
|
}
|
|
1362
1800
|
) }),
|
|
1363
1801
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", style: { marginLeft: "auto" }, children: [
|
|
1364
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: "Default page size (max
|
|
1365
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width:
|
|
1802
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: "Default page size (max 500):" }),
|
|
1803
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: 130 }, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1366
1804
|
designSystem.SingleSelect,
|
|
1367
1805
|
{
|
|
1368
1806
|
size: "S",
|
|
@@ -1373,7 +1811,9 @@ const BulkUpdater = () => {
|
|
|
1373
1811
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "10", children: "10 / page" }),
|
|
1374
1812
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "25", children: "25 / page" }),
|
|
1375
1813
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "50", children: "50 / page" }),
|
|
1376
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "100", children: "100 / page" })
|
|
1814
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "100", children: "100 / page" }),
|
|
1815
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "250", children: "250 / page" }),
|
|
1816
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "500", children: "500 / page" })
|
|
1377
1817
|
]
|
|
1378
1818
|
}
|
|
1379
1819
|
) })
|
|
@@ -1388,7 +1828,7 @@ const BulkUpdater = () => {
|
|
|
1388
1828
|
const pageSize = pageState ? pageState.pageSize : defaultPageSize;
|
|
1389
1829
|
const hasAttr = col.attributes.includes(selectedAttribute);
|
|
1390
1830
|
const visibleEntries = getVisibleEntries(col);
|
|
1391
|
-
|
|
1831
|
+
entries.filter((e) => entryMatchesFilter(e, selectedAttribute)).length;
|
|
1392
1832
|
const isFullySelected = isCollectionFullySelected(col);
|
|
1393
1833
|
const isPartiallySelected = isCollectionPartiallySelected(col);
|
|
1394
1834
|
const currentSort = collectionSorts[col.uid] || { field: "createdAt", order: "desc" };
|
|
@@ -1483,7 +1923,56 @@ const BulkUpdater = () => {
|
|
|
1483
1923
|
]
|
|
1484
1924
|
}
|
|
1485
1925
|
),
|
|
1486
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1926
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1927
|
+
designSystem.Button,
|
|
1928
|
+
{
|
|
1929
|
+
variant: "tertiary",
|
|
1930
|
+
size: "S",
|
|
1931
|
+
startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Download, {}),
|
|
1932
|
+
onClick: async () => {
|
|
1933
|
+
try {
|
|
1934
|
+
const params = new URLSearchParams();
|
|
1935
|
+
if (selectedAttribute) params.set("attribute", selectedAttribute);
|
|
1936
|
+
if (filterOperator && filterOperator !== "none") {
|
|
1937
|
+
params.set("filterOperator", filterOperator);
|
|
1938
|
+
if (filterQuery) params.set("filterQuery", filterQuery);
|
|
1939
|
+
}
|
|
1940
|
+
if (entrySearch && entrySearch.trim()) {
|
|
1941
|
+
params.set("search", entrySearch.trim());
|
|
1942
|
+
}
|
|
1943
|
+
const res = await get(`/bulk-updater/csv/export/${col.uid}?${params.toString()}`);
|
|
1944
|
+
const csvStr = res.data?.csvContent || (typeof res.data === "string" ? res.data : "");
|
|
1945
|
+
if (!csvStr) {
|
|
1946
|
+
toggleNotification({
|
|
1947
|
+
type: "warning",
|
|
1948
|
+
message: "No CSV content returned for this collection"
|
|
1949
|
+
});
|
|
1950
|
+
return;
|
|
1951
|
+
}
|
|
1952
|
+
const blob = new Blob([csvStr], { type: "text/csv;charset=utf-8;" });
|
|
1953
|
+
const url = URL.createObjectURL(blob);
|
|
1954
|
+
const link = document.createElement("a");
|
|
1955
|
+
link.href = url;
|
|
1956
|
+
link.setAttribute("download", `${col.singularName || "export"}_entries.csv`);
|
|
1957
|
+
document.body.appendChild(link);
|
|
1958
|
+
link.click();
|
|
1959
|
+
document.body.removeChild(link);
|
|
1960
|
+
URL.revokeObjectURL(url);
|
|
1961
|
+
toggleNotification({
|
|
1962
|
+
type: "success",
|
|
1963
|
+
message: `Exported ${col.displayName} entries to CSV`
|
|
1964
|
+
});
|
|
1965
|
+
} catch (e) {
|
|
1966
|
+
toggleNotification({
|
|
1967
|
+
type: "danger",
|
|
1968
|
+
message: e.message || "Failed exporting CSV"
|
|
1969
|
+
});
|
|
1970
|
+
}
|
|
1971
|
+
},
|
|
1972
|
+
children: "Export CSV"
|
|
1973
|
+
}
|
|
1974
|
+
),
|
|
1975
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral500", children: col.isSingleType ? "1 single entry" : isFilterActive ? `${totalEntries} matching entries in DB` : `${totalEntries} entries` })
|
|
1487
1976
|
] })
|
|
1488
1977
|
] }),
|
|
1489
1978
|
openColumnPickerUid === col.uid && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1553,7 +2042,7 @@ const BulkUpdater = () => {
|
|
|
1553
2042
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Tbody, { children: visibleEntries.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tr, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { colSpan: activeColumns.length, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 4, style: { textAlign: "center" }, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral500", children: "No entries in this content type match the active filter criteria." }) }) }) }) : visibleEntries.map((entry) => {
|
|
1554
2043
|
const key = `${col.uid}${KEY_SEP}${entry.documentId}`;
|
|
1555
2044
|
const isSelected = Boolean(selectedEntries[key]);
|
|
1556
|
-
const isMatch =
|
|
2045
|
+
const isMatch = isFilterActive;
|
|
1557
2046
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1558
2047
|
designSystem.Tr,
|
|
1559
2048
|
{
|
|
@@ -1585,11 +2074,12 @@ const BulkUpdater = () => {
|
|
|
1585
2074
|
Math.min(page * pageSize, totalEntries),
|
|
1586
2075
|
" of ",
|
|
1587
2076
|
totalEntries,
|
|
1588
|
-
"
|
|
2077
|
+
" ",
|
|
2078
|
+
isFilterActive ? "matching entries" : "entries"
|
|
1589
2079
|
] }),
|
|
1590
2080
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 1, alignItems: "center", children: [
|
|
1591
2081
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: "Show:" }),
|
|
1592
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width:
|
|
2082
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: 85 }, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1593
2083
|
designSystem.SingleSelect,
|
|
1594
2084
|
{
|
|
1595
2085
|
size: "S",
|
|
@@ -1600,12 +2090,27 @@ const BulkUpdater = () => {
|
|
|
1600
2090
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "10", children: "10" }),
|
|
1601
2091
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "25", children: "25" }),
|
|
1602
2092
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "50", children: "50" }),
|
|
1603
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "100", children: "100" })
|
|
2093
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "100", children: "100" }),
|
|
2094
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "250", children: "250" }),
|
|
2095
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "500", children: "500" })
|
|
1604
2096
|
]
|
|
1605
2097
|
}
|
|
1606
2098
|
) }),
|
|
1607
2099
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral500", children: "per page" })
|
|
1608
|
-
] })
|
|
2100
|
+
] }),
|
|
2101
|
+
totalEntries > visibleEntries.length && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2102
|
+
designSystem.Button,
|
|
2103
|
+
{
|
|
2104
|
+
variant: "tertiary",
|
|
2105
|
+
size: "S",
|
|
2106
|
+
onClick: () => handleCollectionPageSizeChange(col.uid, Math.min(totalEntries, 500)),
|
|
2107
|
+
children: [
|
|
2108
|
+
"Load all ",
|
|
2109
|
+
totalEntries,
|
|
2110
|
+
" entries"
|
|
2111
|
+
]
|
|
2112
|
+
}
|
|
2113
|
+
)
|
|
1609
2114
|
] }),
|
|
1610
2115
|
pageCount > 1 && /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", children: [
|
|
1611
2116
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2009,6 +2514,8 @@ const BulkUpdater = () => {
|
|
|
2009
2514
|
]
|
|
2010
2515
|
}
|
|
2011
2516
|
),
|
|
2517
|
+
activeTab === "rules" && /* @__PURE__ */ jsxRuntime.jsx(ValidationRulesTab.ValidationRulesTab, {}),
|
|
2518
|
+
activeTab === "csv" && /* @__PURE__ */ jsxRuntime.jsx(CsvManagerTab, {}),
|
|
2012
2519
|
showConfirmModal && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2013
2520
|
"div",
|
|
2014
2521
|
{
|
|
@@ -2053,20 +2560,10 @@ const BulkUpdater = () => {
|
|
|
2053
2560
|
borderBottom: "1px solid rgba(120, 120, 150, 0.2)",
|
|
2054
2561
|
flexShrink: 0
|
|
2055
2562
|
},
|
|
2056
|
-
children: /* @__PURE__ */ jsxRuntime.
|
|
2057
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
] }),
|
|
2061
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2062
|
-
designSystem.Badge,
|
|
2063
|
-
{
|
|
2064
|
-
backgroundColor: license?.tier === "enterprise" ? "primary100" : "neutral200",
|
|
2065
|
-
textColor: license?.tier === "enterprise" ? "primary700" : "neutral700",
|
|
2066
|
-
children: license?.tier === "enterprise" ? "ENTERPRISE 4-EYES" : "STANDARD"
|
|
2067
|
-
}
|
|
2068
|
-
)
|
|
2069
|
-
] })
|
|
2563
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
|
|
2564
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", fontWeight: "bold", children: "Confirm Bulk Update" }),
|
|
2565
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", display: "block", children: "Review target attributes, affected counts, and server execution policy before proceeding." })
|
|
2566
|
+
] }) })
|
|
2070
2567
|
}
|
|
2071
2568
|
),
|
|
2072
2569
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -2210,7 +2707,7 @@ const BulkUpdater = () => {
|
|
|
2210
2707
|
children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", gap: 3, style: { width: "100%" }, children: [
|
|
2211
2708
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", size: "M", onClick: () => setShowConfirmModal(false), children: "Cancel" }),
|
|
2212
2709
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, wrap: "wrap", justifyContent: "flex-end", alignItems: "center", children: [
|
|
2213
|
-
|
|
2710
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2214
2711
|
designSystem.Button,
|
|
2215
2712
|
{
|
|
2216
2713
|
variant: executionWindow?.isBusinessHours ? "default" : "secondary",
|
|
@@ -2224,7 +2721,7 @@ const BulkUpdater = () => {
|
|
|
2224
2721
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2225
2722
|
designSystem.Button,
|
|
2226
2723
|
{
|
|
2227
|
-
variant:
|
|
2724
|
+
variant: "secondary",
|
|
2228
2725
|
size: "M",
|
|
2229
2726
|
onClick: () => executeBatchWithMode("queue_offpeak"),
|
|
2230
2727
|
loading: updating,
|
|
@@ -2271,4 +2768,5 @@ const BulkUpdater = () => {
|
|
|
2271
2768
|
exports.default = BulkUpdater;
|
|
2272
2769
|
exports.formatDisplayValue = formatDisplayValue;
|
|
2273
2770
|
exports.getAvailableColumnsForCollection = getAvailableColumnsForCollection;
|
|
2274
|
-
|
|
2771
|
+
exports.getNestedValue = getNestedValue;
|
|
2772
|
+
//# sourceMappingURL=BulkUpdater-DCrCPKSe.js.map
|