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
|
@@ -1,8 +1,428 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import React__default, { useState, useEffect, useRef } from "react";
|
|
3
3
|
import { useFetchClient, useNotification } from "@strapi/strapi/admin";
|
|
4
|
-
import { Box, Flex, Typography,
|
|
5
|
-
import { ArrowClockwise, Play } from "@strapi/icons";
|
|
4
|
+
import { Box, Flex, Typography, Button, SingleSelect, SingleSelectOption, Checkbox, Badge, Table, Thead, Tr, Th, Tbody, Td, Alert, TextInput } from "@strapi/design-system";
|
|
5
|
+
import { ArrowClockwise, Download, Upload, Check, Play } from "@strapi/icons";
|
|
6
|
+
import { V as ValidationRulesTab } from "./ValidationRulesTab-BGcqM9cN.mjs";
|
|
7
|
+
function CsvManagerTab() {
|
|
8
|
+
const { get, post } = useFetchClient();
|
|
9
|
+
const { toggleNotification } = useNotification();
|
|
10
|
+
const [collections, setCollections] = useState([]);
|
|
11
|
+
const [loadingCollections, setLoadingCollections] = useState(true);
|
|
12
|
+
const [selectedUid, setSelectedUid] = useState("");
|
|
13
|
+
const [exportLimit, setExportLimit] = useState(1e3);
|
|
14
|
+
const [exportOnlyViolations, setExportOnlyViolations] = useState(false);
|
|
15
|
+
const [rules, setRules] = useState([]);
|
|
16
|
+
const [selectedRuleId, setSelectedRuleId] = useState("");
|
|
17
|
+
const [importMode, setImportMode] = useState("update");
|
|
18
|
+
const [publishOnImport, setPublishOnImport] = useState(true);
|
|
19
|
+
const [csvRawText, setCsvRawText] = useState("");
|
|
20
|
+
const [fileName, setFileName] = useState("");
|
|
21
|
+
const [parsedPreview, setParsedPreview] = useState([]);
|
|
22
|
+
const [importing, setImporting] = useState(false);
|
|
23
|
+
const [importResult, setImportResult] = useState(null);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
fetchInitialData();
|
|
26
|
+
}, []);
|
|
27
|
+
const fetchInitialData = async () => {
|
|
28
|
+
try {
|
|
29
|
+
setLoadingCollections(true);
|
|
30
|
+
const [modelsRes, rulesRes] = await Promise.all([
|
|
31
|
+
get("/bulk-updater/models"),
|
|
32
|
+
get("/bulk-updater/validation-rules")
|
|
33
|
+
]);
|
|
34
|
+
if (modelsRes.data?.collections) {
|
|
35
|
+
setCollections(modelsRes.data.collections);
|
|
36
|
+
if (modelsRes.data.collections.length > 0) {
|
|
37
|
+
setSelectedUid(modelsRes.data.collections[0].uid);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (rulesRes.data?.rules) {
|
|
41
|
+
setRules(rulesRes.data.rules);
|
|
42
|
+
if (rulesRes.data.rules.length > 0) {
|
|
43
|
+
setSelectedRuleId(rulesRes.data.rules[0].id);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
} catch (err) {
|
|
47
|
+
toggleNotification({
|
|
48
|
+
type: "danger",
|
|
49
|
+
message: err.message || "Failed loading collections for CSV Manager"
|
|
50
|
+
});
|
|
51
|
+
} finally {
|
|
52
|
+
setLoadingCollections(false);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
const handleDownloadTemplate = async () => {
|
|
56
|
+
if (!selectedUid) return;
|
|
57
|
+
try {
|
|
58
|
+
const res = await get(`/bulk-updater/csv/template/${selectedUid}`);
|
|
59
|
+
const csvStr = res.data?.csvContent || (typeof res.data === "string" ? res.data : "");
|
|
60
|
+
const filename = res.data?.filename || `${selectedUid.split(".").pop()}_template.csv`;
|
|
61
|
+
downloadCsvFile(csvStr, filename);
|
|
62
|
+
toggleNotification({
|
|
63
|
+
type: "success",
|
|
64
|
+
message: "CSV Template downloaded successfully"
|
|
65
|
+
});
|
|
66
|
+
} catch (err) {
|
|
67
|
+
toggleNotification({
|
|
68
|
+
type: "danger",
|
|
69
|
+
message: err.message || "Failed downloading CSV template"
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
const handleExportCollection = async () => {
|
|
74
|
+
if (!selectedUid) return;
|
|
75
|
+
try {
|
|
76
|
+
const res = await get(`/bulk-updater/csv/export/${selectedUid}?limit=${exportLimit}`);
|
|
77
|
+
const csvStr = res.data?.csvContent || (typeof res.data === "string" ? res.data : "");
|
|
78
|
+
const filename = res.data?.filename || `${selectedUid.split(".").pop()}_export.csv`;
|
|
79
|
+
downloadCsvFile(csvStr, filename);
|
|
80
|
+
toggleNotification({
|
|
81
|
+
type: "success",
|
|
82
|
+
message: "Collection exported to CSV successfully"
|
|
83
|
+
});
|
|
84
|
+
} catch (err) {
|
|
85
|
+
toggleNotification({
|
|
86
|
+
type: "danger",
|
|
87
|
+
message: err.message || "Failed exporting collection to CSV"
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
const handleExportViolations = async () => {
|
|
92
|
+
if (!selectedRuleId) return;
|
|
93
|
+
try {
|
|
94
|
+
const res = await get(`/bulk-updater/csv/export-violations/${selectedRuleId}`);
|
|
95
|
+
const csvStr = res.data?.csvContent || (typeof res.data === "string" ? res.data : "");
|
|
96
|
+
const filename = res.data?.filename || `violations_${selectedRuleId}.csv`;
|
|
97
|
+
downloadCsvFile(csvStr, filename);
|
|
98
|
+
toggleNotification({
|
|
99
|
+
type: "success",
|
|
100
|
+
message: "Rule violations exported to CSV successfully"
|
|
101
|
+
});
|
|
102
|
+
} catch (err) {
|
|
103
|
+
toggleNotification({
|
|
104
|
+
type: "danger",
|
|
105
|
+
message: err.message || "Failed exporting violations to CSV"
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
const downloadCsvFile = (content, fallbackName) => {
|
|
110
|
+
if (!content) {
|
|
111
|
+
toggleNotification({
|
|
112
|
+
type: "warning",
|
|
113
|
+
message: "No CSV content to download"
|
|
114
|
+
});
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const blob = new Blob([content], { type: "text/csv;charset=utf-8;" });
|
|
118
|
+
const url = URL.createObjectURL(blob);
|
|
119
|
+
const link = document.createElement("a");
|
|
120
|
+
link.href = url;
|
|
121
|
+
link.setAttribute("download", fallbackName);
|
|
122
|
+
document.body.appendChild(link);
|
|
123
|
+
link.click();
|
|
124
|
+
document.body.removeChild(link);
|
|
125
|
+
URL.revokeObjectURL(url);
|
|
126
|
+
};
|
|
127
|
+
const handleFileUpload = (e) => {
|
|
128
|
+
const file = e.target.files?.[0];
|
|
129
|
+
if (!file) return;
|
|
130
|
+
setFileName(file.name);
|
|
131
|
+
setImportResult(null);
|
|
132
|
+
const reader = new FileReader();
|
|
133
|
+
reader.onload = (event) => {
|
|
134
|
+
const text = event.target?.result;
|
|
135
|
+
setCsvRawText(text);
|
|
136
|
+
try {
|
|
137
|
+
const lines = text.split(/\r?\n/).filter((l) => l.trim().length > 0);
|
|
138
|
+
if (lines.length > 0) {
|
|
139
|
+
const headers = lines[0].split(",").map((h) => h.replace(/^"|"$/g, "").trim());
|
|
140
|
+
const previewRows = [];
|
|
141
|
+
for (let i = 1; i < Math.min(lines.length, 6); i++) {
|
|
142
|
+
const vals = lines[i].split(",").map((v) => v.replace(/^"|"$/g, "").trim());
|
|
143
|
+
const row = {};
|
|
144
|
+
headers.forEach((h, idx) => {
|
|
145
|
+
row[h] = vals[idx] || "";
|
|
146
|
+
});
|
|
147
|
+
previewRows.push(row);
|
|
148
|
+
}
|
|
149
|
+
setParsedPreview(previewRows);
|
|
150
|
+
}
|
|
151
|
+
} catch (err) {
|
|
152
|
+
setParsedPreview([]);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
reader.readAsText(file);
|
|
156
|
+
};
|
|
157
|
+
const handleExecuteImport = async () => {
|
|
158
|
+
if (!selectedUid || !csvRawText) return;
|
|
159
|
+
try {
|
|
160
|
+
setImporting(true);
|
|
161
|
+
setImportResult(null);
|
|
162
|
+
const res = await post("/bulk-updater/csv/import", {
|
|
163
|
+
uid: selectedUid,
|
|
164
|
+
csvText: csvRawText,
|
|
165
|
+
mode: importMode,
|
|
166
|
+
publish: publishOnImport
|
|
167
|
+
});
|
|
168
|
+
if (res.data && res.data.success) {
|
|
169
|
+
setImportResult(res.data);
|
|
170
|
+
toggleNotification({
|
|
171
|
+
type: "success",
|
|
172
|
+
message: `CSV Import complete: ${res.data.stats.created} created, ${res.data.stats.updated} updated.`
|
|
173
|
+
});
|
|
174
|
+
} else {
|
|
175
|
+
throw new Error(res.data?.error || "Import failed");
|
|
176
|
+
}
|
|
177
|
+
} catch (err) {
|
|
178
|
+
toggleNotification({
|
|
179
|
+
type: "danger",
|
|
180
|
+
message: err.message || "Error processing CSV import"
|
|
181
|
+
});
|
|
182
|
+
} finally {
|
|
183
|
+
setImporting(false);
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
const selectedCol = collections.find((c) => c.uid === selectedUid);
|
|
187
|
+
return /* @__PURE__ */ jsx(Box, { padding: 6, background: "neutral0", hasRadius: true, shadow: "filterShadow", children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 6, children: [
|
|
188
|
+
/* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [
|
|
189
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
190
|
+
/* @__PURE__ */ jsx(Typography, { variant: "beta", tag: "h2", fontWeight: "bold", children: "CSV Export & Import Center" }),
|
|
191
|
+
/* @__PURE__ */ jsx(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." })
|
|
192
|
+
] }),
|
|
193
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", startIcon: /* @__PURE__ */ jsx(ArrowClockwise, {}), onClick: fetchInitialData, children: "Refresh" })
|
|
194
|
+
] }),
|
|
195
|
+
/* @__PURE__ */ jsx(Box, { padding: 4, background: "neutral100", hasRadius: true, children: /* @__PURE__ */ jsxs(Flex, { gap: 4, alignItems: "flex-end", children: [
|
|
196
|
+
/* @__PURE__ */ jsxs(Box, { style: { flex: 1 }, children: [
|
|
197
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", marginBottom: 2, children: "Target Collection Type" }),
|
|
198
|
+
/* @__PURE__ */ jsx(
|
|
199
|
+
SingleSelect,
|
|
200
|
+
{
|
|
201
|
+
value: selectedUid,
|
|
202
|
+
onChange: (val) => {
|
|
203
|
+
setSelectedUid(val);
|
|
204
|
+
setImportResult(null);
|
|
205
|
+
},
|
|
206
|
+
disabled: loadingCollections,
|
|
207
|
+
placeholder: "Select a collection...",
|
|
208
|
+
children: collections.map((col) => /* @__PURE__ */ jsxs(SingleSelectOption, { value: col.uid, children: [
|
|
209
|
+
col.displayName,
|
|
210
|
+
" (",
|
|
211
|
+
col.totalEntries ?? 0,
|
|
212
|
+
" records)"
|
|
213
|
+
] }, col.uid))
|
|
214
|
+
}
|
|
215
|
+
)
|
|
216
|
+
] }),
|
|
217
|
+
/* @__PURE__ */ jsx(
|
|
218
|
+
Button,
|
|
219
|
+
{
|
|
220
|
+
variant: "tertiary",
|
|
221
|
+
startIcon: /* @__PURE__ */ jsx(Download, {}),
|
|
222
|
+
onClick: handleDownloadTemplate,
|
|
223
|
+
disabled: !selectedUid,
|
|
224
|
+
children: "Download Sample CSV Template"
|
|
225
|
+
}
|
|
226
|
+
)
|
|
227
|
+
] }) }),
|
|
228
|
+
/* @__PURE__ */ jsxs(Box, { padding: 5, background: "neutral100", hasRadius: true, children: [
|
|
229
|
+
/* @__PURE__ */ jsx(Typography, { variant: "delta", tag: "h3", fontWeight: "bold", marginBottom: 2, children: "1. Export Data to CSV" }),
|
|
230
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", marginBottom: 4, children: "Extract entire collections or pinpoint records violating validation quotas." }),
|
|
231
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 4, wrap: "wrap", alignItems: "center", marginTop: 3, children: [
|
|
232
|
+
/* @__PURE__ */ jsxs(
|
|
233
|
+
Button,
|
|
234
|
+
{
|
|
235
|
+
variant: "default",
|
|
236
|
+
startIcon: /* @__PURE__ */ jsx(Download, {}),
|
|
237
|
+
onClick: handleExportCollection,
|
|
238
|
+
disabled: !selectedUid,
|
|
239
|
+
children: [
|
|
240
|
+
"Export All ",
|
|
241
|
+
selectedCol?.displayName || "Collection",
|
|
242
|
+
" Records (.csv)"
|
|
243
|
+
]
|
|
244
|
+
}
|
|
245
|
+
),
|
|
246
|
+
rules.length > 0 && /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", style: { marginLeft: "auto" }, children: [
|
|
247
|
+
/* @__PURE__ */ jsx(
|
|
248
|
+
SingleSelect,
|
|
249
|
+
{
|
|
250
|
+
value: selectedRuleId,
|
|
251
|
+
onChange: (val) => setSelectedRuleId(val),
|
|
252
|
+
placeholder: "Select Quota Rule...",
|
|
253
|
+
children: rules.map((r) => /* @__PURE__ */ jsxs(SingleSelectOption, { value: r.id, children: [
|
|
254
|
+
"Rule: ",
|
|
255
|
+
r.name
|
|
256
|
+
] }, r.id))
|
|
257
|
+
}
|
|
258
|
+
),
|
|
259
|
+
/* @__PURE__ */ jsx(
|
|
260
|
+
Button,
|
|
261
|
+
{
|
|
262
|
+
variant: "danger-light",
|
|
263
|
+
startIcon: /* @__PURE__ */ jsx(Download, {}),
|
|
264
|
+
onClick: handleExportViolations,
|
|
265
|
+
disabled: !selectedRuleId,
|
|
266
|
+
children: "Export Violators CSV"
|
|
267
|
+
}
|
|
268
|
+
)
|
|
269
|
+
] })
|
|
270
|
+
] })
|
|
271
|
+
] }),
|
|
272
|
+
/* @__PURE__ */ jsxs(Box, { padding: 5, background: "neutral100", hasRadius: true, children: [
|
|
273
|
+
/* @__PURE__ */ jsx(Typography, { variant: "delta", tag: "h3", fontWeight: "bold", marginBottom: 2, children: "2. Import & Batch Override CSV" }),
|
|
274
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", marginBottom: 4, children: "Upload an updated CSV file to bulk update existing records or insert new records." }),
|
|
275
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 6, marginBottom: 4, wrap: "wrap", children: [
|
|
276
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
277
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", marginBottom: 2, children: "Operation Mode" }),
|
|
278
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 4, children: [
|
|
279
|
+
/* @__PURE__ */ jsxs("label", { style: { display: "flex", alignItems: "center", gap: 6, cursor: "pointer" }, children: [
|
|
280
|
+
/* @__PURE__ */ jsx(
|
|
281
|
+
"input",
|
|
282
|
+
{
|
|
283
|
+
type: "radio",
|
|
284
|
+
name: "importMode",
|
|
285
|
+
value: "update",
|
|
286
|
+
checked: importMode === "update",
|
|
287
|
+
onChange: () => setImportMode("update")
|
|
288
|
+
}
|
|
289
|
+
),
|
|
290
|
+
/* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: importMode === "update" ? "bold" : "normal", children: "Update Existing (Matches by documentId)" })
|
|
291
|
+
] }),
|
|
292
|
+
/* @__PURE__ */ jsxs("label", { style: { display: "flex", alignItems: "center", gap: 6, cursor: "pointer" }, children: [
|
|
293
|
+
/* @__PURE__ */ jsx(
|
|
294
|
+
"input",
|
|
295
|
+
{
|
|
296
|
+
type: "radio",
|
|
297
|
+
name: "importMode",
|
|
298
|
+
value: "create_or_override",
|
|
299
|
+
checked: importMode === "create_or_override",
|
|
300
|
+
onChange: () => setImportMode("create_or_override")
|
|
301
|
+
}
|
|
302
|
+
),
|
|
303
|
+
/* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: importMode === "create_or_override" ? "bold" : "normal", children: "Add / Override (Inserts new or replaces existing)" })
|
|
304
|
+
] })
|
|
305
|
+
] })
|
|
306
|
+
] }),
|
|
307
|
+
/* @__PURE__ */ jsxs(Box, { style: { marginLeft: "auto" }, children: [
|
|
308
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", marginBottom: 2, children: "Publish Options" }),
|
|
309
|
+
/* @__PURE__ */ jsx(
|
|
310
|
+
Checkbox,
|
|
311
|
+
{
|
|
312
|
+
checked: publishOnImport,
|
|
313
|
+
onValueChange: (val) => setPublishOnImport(val),
|
|
314
|
+
children: "Auto-publish on import"
|
|
315
|
+
}
|
|
316
|
+
)
|
|
317
|
+
] })
|
|
318
|
+
] }),
|
|
319
|
+
/* @__PURE__ */ jsxs(
|
|
320
|
+
Box,
|
|
321
|
+
{
|
|
322
|
+
padding: 6,
|
|
323
|
+
background: "neutral0",
|
|
324
|
+
hasRadius: true,
|
|
325
|
+
style: {
|
|
326
|
+
border: "2px dashed #dcdce4",
|
|
327
|
+
textAlign: "center",
|
|
328
|
+
cursor: "pointer"
|
|
329
|
+
},
|
|
330
|
+
children: [
|
|
331
|
+
/* @__PURE__ */ jsx(
|
|
332
|
+
"input",
|
|
333
|
+
{
|
|
334
|
+
type: "file",
|
|
335
|
+
accept: ".csv",
|
|
336
|
+
id: "csv-file-input",
|
|
337
|
+
style: { display: "none" },
|
|
338
|
+
onChange: handleFileUpload
|
|
339
|
+
}
|
|
340
|
+
),
|
|
341
|
+
/* @__PURE__ */ jsxs("label", { htmlFor: "csv-file-input", style: { cursor: "pointer", display: "block" }, children: [
|
|
342
|
+
/* @__PURE__ */ jsx(Upload, { style: { width: 32, height: 32, margin: "0 auto 8px", color: "#4945ff" } }),
|
|
343
|
+
/* @__PURE__ */ jsx(Typography, { variant: "delta", fontWeight: "bold", display: "block", children: fileName ? `Selected: ${fileName}` : "Click here or drag a .csv file to upload" }),
|
|
344
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: "UTF-8 encoded CSV matching collection schema headers" })
|
|
345
|
+
] })
|
|
346
|
+
]
|
|
347
|
+
}
|
|
348
|
+
),
|
|
349
|
+
parsedPreview.length > 0 && /* @__PURE__ */ jsxs(Box, { marginTop: 4, background: "neutral0", padding: 4, hasRadius: true, children: [
|
|
350
|
+
/* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 3, children: [
|
|
351
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "sigma", textColor: "neutral700", children: [
|
|
352
|
+
"FILE PREVIEW (FIRST ",
|
|
353
|
+
parsedPreview.length,
|
|
354
|
+
" ROWS)"
|
|
355
|
+
] }),
|
|
356
|
+
/* @__PURE__ */ jsx(Badge, { backgroundColor: "neutral150", textColor: "neutral800", children: "Ready to Import" })
|
|
357
|
+
] }),
|
|
358
|
+
/* @__PURE__ */ jsxs(Table, { colCount: Object.keys(parsedPreview[0]).length, rowCount: parsedPreview.length + 1, children: [
|
|
359
|
+
/* @__PURE__ */ jsx(Thead, { children: /* @__PURE__ */ jsx(Tr, { children: Object.keys(parsedPreview[0]).map((h) => /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: h }) }, h)) }) }),
|
|
360
|
+
/* @__PURE__ */ jsx(Tbody, { children: parsedPreview.map((row, rIdx) => /* @__PURE__ */ jsx(Tr, { children: Object.keys(parsedPreview[0]).map((h) => /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { variant: "omega", children: row[h] || "-" }) }, h)) }, rIdx)) })
|
|
361
|
+
] }),
|
|
362
|
+
/* @__PURE__ */ jsx(Flex, { justifyContent: "flex-end", marginTop: 4, children: /* @__PURE__ */ jsx(
|
|
363
|
+
Button,
|
|
364
|
+
{
|
|
365
|
+
variant: "default",
|
|
366
|
+
size: "L",
|
|
367
|
+
startIcon: /* @__PURE__ */ jsx(Check, {}),
|
|
368
|
+
onClick: handleExecuteImport,
|
|
369
|
+
loading: importing,
|
|
370
|
+
children: importMode === "update" ? "Execute Bulk Update" : "Execute Add / Override"
|
|
371
|
+
}
|
|
372
|
+
) })
|
|
373
|
+
] }),
|
|
374
|
+
importResult && /* @__PURE__ */ jsx(Box, { marginTop: 4, children: /* @__PURE__ */ jsxs(
|
|
375
|
+
Alert,
|
|
376
|
+
{
|
|
377
|
+
variant: importResult.stats.errors.length > 0 ? "warning" : "success",
|
|
378
|
+
title: "CSV Import Results",
|
|
379
|
+
children: [
|
|
380
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "omega", display: "block", marginBottom: 1, children: [
|
|
381
|
+
"Successfully processed: ",
|
|
382
|
+
/* @__PURE__ */ jsxs("strong", { children: [
|
|
383
|
+
importResult.stats.created,
|
|
384
|
+
" created"
|
|
385
|
+
] }),
|
|
386
|
+
",",
|
|
387
|
+
" ",
|
|
388
|
+
/* @__PURE__ */ jsxs("strong", { children: [
|
|
389
|
+
importResult.stats.updated,
|
|
390
|
+
" updated"
|
|
391
|
+
] }),
|
|
392
|
+
",",
|
|
393
|
+
" ",
|
|
394
|
+
/* @__PURE__ */ jsxs("strong", { children: [
|
|
395
|
+
importResult.stats.skipped,
|
|
396
|
+
" skipped"
|
|
397
|
+
] }),
|
|
398
|
+
" out of ",
|
|
399
|
+
importResult.stats.total,
|
|
400
|
+
" total rows."
|
|
401
|
+
] }),
|
|
402
|
+
importResult.stats.errors.length > 0 && /* @__PURE__ */ jsxs(Box, { marginTop: 2, children: [
|
|
403
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "danger700", fontWeight: "bold", children: [
|
|
404
|
+
"Errors encountered (",
|
|
405
|
+
importResult.stats.errors.length,
|
|
406
|
+
"):"
|
|
407
|
+
] }),
|
|
408
|
+
/* @__PURE__ */ jsx("ul", { style: { margin: "4px 0 0 16px", padding: 0 }, children: importResult.stats.errors.slice(0, 5).map((err, idx) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "danger600", children: [
|
|
409
|
+
"Row ",
|
|
410
|
+
err.row,
|
|
411
|
+
": ",
|
|
412
|
+
err.error
|
|
413
|
+
] }) }, idx)) })
|
|
414
|
+
] })
|
|
415
|
+
]
|
|
416
|
+
}
|
|
417
|
+
) })
|
|
418
|
+
] })
|
|
419
|
+
] }) });
|
|
420
|
+
}
|
|
421
|
+
function getNestedValue(obj, path) {
|
|
422
|
+
if (!obj || !path) return void 0;
|
|
423
|
+
if (!path.includes(".")) return obj[path];
|
|
424
|
+
return path.split(".").reduce((acc, part) => acc && typeof acc === "object" ? acc[part] : void 0, obj);
|
|
425
|
+
}
|
|
6
426
|
function getAvailableColumnsForCollection(col, selectedAttribute) {
|
|
7
427
|
const cols = [
|
|
8
428
|
{
|
|
@@ -23,7 +443,7 @@ function getAvailableColumnsForCollection(col, selectedAttribute) {
|
|
|
23
443
|
if (attr === "name" || attr === "title" || attr === selectedAttribute) {
|
|
24
444
|
return;
|
|
25
445
|
}
|
|
26
|
-
const formattedLabel = attr.charAt(0).toUpperCase() + attr.slice(1);
|
|
446
|
+
const formattedLabel = attr.includes(".") ? attr.split(".").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" > ") : attr.charAt(0).toUpperCase() + attr.slice(1);
|
|
27
447
|
cols.push({
|
|
28
448
|
key: `attr_${attr}`,
|
|
29
449
|
label: formattedLabel,
|
|
@@ -109,7 +529,7 @@ function renderCellContent(colDef, entry, col, selectedAttribute, isMatch, hasAt
|
|
|
109
529
|
] });
|
|
110
530
|
}
|
|
111
531
|
case "target_attr": {
|
|
112
|
-
const val = entry
|
|
532
|
+
const val = getNestedValue(entry, selectedAttribute);
|
|
113
533
|
const displayStr = formatDisplayValue(val);
|
|
114
534
|
const isUnset = displayStr === "(empty / not set)" || displayStr === "(empty / unlinked)";
|
|
115
535
|
return /* @__PURE__ */ jsx(
|
|
@@ -139,7 +559,7 @@ function renderCellContent(colDef, entry, col, selectedAttribute, isMatch, hasAt
|
|
|
139
559
|
}
|
|
140
560
|
default: {
|
|
141
561
|
const attrName = colDef.key.replace("attr_", "");
|
|
142
|
-
const rawVal = entry
|
|
562
|
+
const rawVal = getNestedValue(entry, attrName);
|
|
143
563
|
const displayStr = formatDisplayValue(rawVal);
|
|
144
564
|
return /* @__PURE__ */ jsx(
|
|
145
565
|
Typography,
|
|
@@ -159,7 +579,7 @@ const BulkUpdater = () => {
|
|
|
159
579
|
try {
|
|
160
580
|
const params = new URLSearchParams(window.location.search);
|
|
161
581
|
const t = params.get("tab");
|
|
162
|
-
if (t === "audit" || t === "editor") return t;
|
|
582
|
+
if (t === "audit" || t === "editor" || t === "rules" || t === "csv") return t;
|
|
163
583
|
} catch {
|
|
164
584
|
}
|
|
165
585
|
return "editor";
|
|
@@ -178,7 +598,6 @@ const BulkUpdater = () => {
|
|
|
178
598
|
const [updating, setUpdating] = useState(false);
|
|
179
599
|
const [attributes, setAttributes] = useState([]);
|
|
180
600
|
const [collections, setCollections] = useState([]);
|
|
181
|
-
const [license, setLicense] = useState(null);
|
|
182
601
|
const [auditEnabled, setAuditEnabled] = useState(false);
|
|
183
602
|
const [executionWindow, setExecutionWindow] = useState(null);
|
|
184
603
|
const [showConfirmModal, setShowConfirmModal] = useState(false);
|
|
@@ -214,7 +633,8 @@ const BulkUpdater = () => {
|
|
|
214
633
|
const [regexPattern, setRegexPattern] = useState("");
|
|
215
634
|
const [filterOperator, setFilterOperator] = useState("none");
|
|
216
635
|
const [filterQuery, setFilterQuery] = useState("");
|
|
217
|
-
const [
|
|
636
|
+
const [entrySearch, setEntrySearch] = useState("");
|
|
637
|
+
const isFilterActive = filterOperator !== "none" && (["empty", "not_empty"].includes(filterOperator) || Boolean(filterQuery.trim())) || Boolean(entrySearch.trim());
|
|
218
638
|
const [lastResults, setLastResults] = useState(null);
|
|
219
639
|
const [updateSummary, setUpdateSummary] = useState(null);
|
|
220
640
|
const [collectionPages, setCollectionPages] = useState({});
|
|
@@ -266,7 +686,6 @@ const BulkUpdater = () => {
|
|
|
266
686
|
setAttributes(res.data.attributes || []);
|
|
267
687
|
const cols = res.data.collections || [];
|
|
268
688
|
setCollections(cols);
|
|
269
|
-
setLicense(res.data.license || null);
|
|
270
689
|
setAuditEnabled(Boolean(res.data.auditEnabled));
|
|
271
690
|
if (res.data.executionWindow) {
|
|
272
691
|
setExecutionWindow(res.data.executionWindow);
|
|
@@ -311,12 +730,15 @@ const BulkUpdater = () => {
|
|
|
311
730
|
setLoading(false);
|
|
312
731
|
}
|
|
313
732
|
};
|
|
314
|
-
const loadCollectionPage = async (colUid, targetPage, customPageSize, customSortField, customSortOrder) => {
|
|
733
|
+
const loadCollectionPage = async (colUid, targetPage, customPageSize, customSortField, customSortOrder, overrideFilterOp, overrideFilterQuery, overrideEntrySearch, autoSelectReturned = true) => {
|
|
315
734
|
const currentPageState = collectionPages[colUid];
|
|
316
735
|
const size = customPageSize || currentPageState?.pageSize || defaultPageSize;
|
|
317
736
|
const currentSort = collectionSorts[colUid] || { field: "createdAt", order: "desc" };
|
|
318
737
|
const sortField = customSortField !== void 0 ? customSortField : currentSort.field;
|
|
319
738
|
const sortOrder = customSortOrder !== void 0 ? customSortOrder : currentSort.order;
|
|
739
|
+
const op = overrideFilterOp !== void 0 ? overrideFilterOp : filterOperator;
|
|
740
|
+
const q = overrideFilterQuery !== void 0 ? overrideFilterQuery : filterQuery;
|
|
741
|
+
const s = overrideEntrySearch !== void 0 ? overrideEntrySearch : entrySearch;
|
|
320
742
|
setCollectionPages((prev) => ({
|
|
321
743
|
...prev,
|
|
322
744
|
[colUid]: {
|
|
@@ -330,16 +752,20 @@ const BulkUpdater = () => {
|
|
|
330
752
|
pageSize: String(size)
|
|
331
753
|
});
|
|
332
754
|
if (selectedAttribute) params.set("attribute", selectedAttribute);
|
|
333
|
-
if (
|
|
334
|
-
params.set("filterOperator",
|
|
335
|
-
if (
|
|
755
|
+
if (op && op !== "none") {
|
|
756
|
+
params.set("filterOperator", op);
|
|
757
|
+
if (q) params.set("filterQuery", q);
|
|
758
|
+
}
|
|
759
|
+
if (s && s.trim()) {
|
|
760
|
+
params.set("search", s.trim());
|
|
336
761
|
}
|
|
337
762
|
if (sortField) {
|
|
338
763
|
params.set("sortField", sortField);
|
|
339
764
|
params.set("sortOrder", sortOrder);
|
|
340
765
|
}
|
|
341
766
|
const res = await get(`/bulk-updater/collections/${colUid}/entries?${params.toString()}`);
|
|
342
|
-
if (res.data && res.data.success) {
|
|
767
|
+
if (res.data && (res.data.success || res.data.entries !== void 0)) {
|
|
768
|
+
const fetchedEntries = res.data.entries || [];
|
|
343
769
|
setCollectionPages((prev) => ({
|
|
344
770
|
...prev,
|
|
345
771
|
[colUid]: {
|
|
@@ -347,10 +773,20 @@ const BulkUpdater = () => {
|
|
|
347
773
|
pageSize: res.data.pagination.pageSize,
|
|
348
774
|
total: res.data.pagination.total,
|
|
349
775
|
pageCount: res.data.pagination.pageCount,
|
|
350
|
-
entries:
|
|
776
|
+
entries: fetchedEntries,
|
|
351
777
|
loading: false
|
|
352
778
|
}
|
|
353
779
|
}));
|
|
780
|
+
const isFilterActiveNow = op !== "none" && (["empty", "not_empty"].includes(op) || Boolean(q.trim())) || Boolean(s.trim());
|
|
781
|
+
if (isFilterActiveNow && autoSelectReturned) {
|
|
782
|
+
setSelectedEntries((prev) => {
|
|
783
|
+
const next = { ...prev };
|
|
784
|
+
fetchedEntries.forEach((e) => {
|
|
785
|
+
next[`${colUid}${KEY_SEP}${e.documentId}`] = true;
|
|
786
|
+
});
|
|
787
|
+
return next;
|
|
788
|
+
});
|
|
789
|
+
}
|
|
354
790
|
}
|
|
355
791
|
} catch (err) {
|
|
356
792
|
toggleNotification({
|
|
@@ -414,6 +850,35 @@ const BulkUpdater = () => {
|
|
|
414
850
|
fetchPendingBatches();
|
|
415
851
|
}
|
|
416
852
|
}, [activeTab]);
|
|
853
|
+
const isInitialFilterMount = useRef(true);
|
|
854
|
+
useEffect(() => {
|
|
855
|
+
if (isInitialFilterMount.current) {
|
|
856
|
+
isInitialFilterMount.current = false;
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
const timer = setTimeout(() => {
|
|
860
|
+
if (collections.length > 0) {
|
|
861
|
+
const isFilterActiveNow = filterOperator !== "none" && (["empty", "not_empty"].includes(filterOperator) || Boolean(filterQuery.trim())) || Boolean(entrySearch.trim());
|
|
862
|
+
if (isFilterActiveNow) {
|
|
863
|
+
setSelectedEntries({});
|
|
864
|
+
}
|
|
865
|
+
collections.forEach((col) => {
|
|
866
|
+
loadCollectionPage(
|
|
867
|
+
col.uid,
|
|
868
|
+
1,
|
|
869
|
+
void 0,
|
|
870
|
+
void 0,
|
|
871
|
+
void 0,
|
|
872
|
+
filterOperator,
|
|
873
|
+
filterQuery,
|
|
874
|
+
entrySearch,
|
|
875
|
+
true
|
|
876
|
+
);
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
}, 350);
|
|
880
|
+
return () => clearTimeout(timer);
|
|
881
|
+
}, [filterOperator, filterQuery, entrySearch]);
|
|
417
882
|
const KEY_SEP = "@@@";
|
|
418
883
|
const handleAttributeChange = (newAttr) => {
|
|
419
884
|
if (newAttr !== selectedAttribute) {
|
|
@@ -421,7 +886,7 @@ const BulkUpdater = () => {
|
|
|
421
886
|
setSelectedEntries({});
|
|
422
887
|
setFilterOperator("none");
|
|
423
888
|
setFilterQuery("");
|
|
424
|
-
|
|
889
|
+
setEntrySearch("");
|
|
425
890
|
setSelectedRelationDocId("");
|
|
426
891
|
setAttributeValue("");
|
|
427
892
|
if (relationsMeta[newAttr]) {
|
|
@@ -438,7 +903,7 @@ const BulkUpdater = () => {
|
|
|
438
903
|
(c) => visibleTypeUids[c.uid] !== false && (!collectionSearch.trim() || c.displayName.toLowerCase().includes(collectionSearch.toLowerCase().trim()) || c.uid.toLowerCase().includes(collectionSearch.toLowerCase().trim()))
|
|
439
904
|
);
|
|
440
905
|
const handleGlobalPageSizeChange = (newSize) => {
|
|
441
|
-
const capped = Math.min(
|
|
906
|
+
const capped = Math.min(500, Math.max(1, newSize));
|
|
442
907
|
setDefaultPageSize(capped);
|
|
443
908
|
collections.forEach((col) => {
|
|
444
909
|
if (!col.isSingleType) {
|
|
@@ -447,7 +912,7 @@ const BulkUpdater = () => {
|
|
|
447
912
|
});
|
|
448
913
|
};
|
|
449
914
|
const handleCollectionPageSizeChange = (colUid, newSize) => {
|
|
450
|
-
const capped = Math.min(
|
|
915
|
+
const capped = Math.min(500, Math.max(1, newSize));
|
|
451
916
|
loadCollectionPage(colUid, 1, capped);
|
|
452
917
|
};
|
|
453
918
|
const handleCollectionSortChange = (colUid, field, order) => {
|
|
@@ -471,7 +936,7 @@ const BulkUpdater = () => {
|
|
|
471
936
|
};
|
|
472
937
|
const entryMatchesFilter = (entry, attr) => {
|
|
473
938
|
if (filterOperator === "none") return true;
|
|
474
|
-
const val = entry
|
|
939
|
+
const val = getNestedValue(entry, attr);
|
|
475
940
|
const displayStr = formatDisplayValue(val);
|
|
476
941
|
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)";
|
|
477
942
|
switch (filterOperator) {
|
|
@@ -491,64 +956,48 @@ const BulkUpdater = () => {
|
|
|
491
956
|
};
|
|
492
957
|
const getVisibleEntries = (col) => {
|
|
493
958
|
const pageState = collectionPages[col.uid];
|
|
494
|
-
|
|
495
|
-
if (!hideNonMatching || filterOperator === "none") {
|
|
496
|
-
return entries;
|
|
497
|
-
}
|
|
498
|
-
return entries.filter((e) => entryMatchesFilter(e, selectedAttribute));
|
|
959
|
+
return pageState ? pageState.entries : col.entries || [];
|
|
499
960
|
};
|
|
500
|
-
const matchingEntriesCount =
|
|
501
|
-
if (
|
|
961
|
+
const matchingEntriesCount = React__default.useMemo(() => {
|
|
962
|
+
if (!isFilterActive) return 0;
|
|
502
963
|
let count = 0;
|
|
503
964
|
filteredCollections.forEach((col) => {
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
entries.forEach((entry) => {
|
|
508
|
-
if (entryMatchesFilter(entry, selectedAttribute)) {
|
|
509
|
-
count++;
|
|
510
|
-
}
|
|
511
|
-
});
|
|
965
|
+
const pageState = collectionPages[col.uid];
|
|
966
|
+
if (pageState) {
|
|
967
|
+
count += pageState.total;
|
|
512
968
|
}
|
|
513
969
|
});
|
|
514
970
|
return count;
|
|
515
|
-
}, [filteredCollections, collectionPages,
|
|
971
|
+
}, [filteredCollections, collectionPages, isFilterActive]);
|
|
516
972
|
const selectAllMatching = () => {
|
|
517
973
|
const updated = { ...selectedEntries };
|
|
518
974
|
filteredCollections.forEach((col) => {
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
updated[`${col.uid}${KEY_SEP}${e.documentId}`] = true;
|
|
525
|
-
}
|
|
526
|
-
});
|
|
527
|
-
}
|
|
975
|
+
const pageState = collectionPages[col.uid];
|
|
976
|
+
const entries = pageState ? pageState.entries : col.entries || [];
|
|
977
|
+
entries.forEach((e) => {
|
|
978
|
+
updated[`${col.uid}${KEY_SEP}${e.documentId}`] = true;
|
|
979
|
+
});
|
|
528
980
|
});
|
|
529
981
|
setSelectedEntries(updated);
|
|
530
982
|
};
|
|
531
983
|
const deselectAllMatching = () => {
|
|
532
984
|
const updated = { ...selectedEntries };
|
|
533
985
|
filteredCollections.forEach((col) => {
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
delete updated[`${col.uid}${KEY_SEP}${e.documentId}`];
|
|
540
|
-
}
|
|
541
|
-
});
|
|
542
|
-
}
|
|
986
|
+
const pageState = collectionPages[col.uid];
|
|
987
|
+
const entries = pageState ? pageState.entries : col.entries || [];
|
|
988
|
+
entries.forEach((e) => {
|
|
989
|
+
delete updated[`${col.uid}${KEY_SEP}${e.documentId}`];
|
|
990
|
+
});
|
|
543
991
|
});
|
|
544
992
|
setSelectedEntries(updated);
|
|
545
993
|
};
|
|
546
994
|
const clearFilter = () => {
|
|
547
995
|
setFilterOperator("none");
|
|
548
996
|
setFilterQuery("");
|
|
549
|
-
|
|
997
|
+
setEntrySearch("");
|
|
998
|
+
setSelectedEntries({});
|
|
550
999
|
collections.forEach((col) => {
|
|
551
|
-
loadCollectionPage(col.uid, 1);
|
|
1000
|
+
loadCollectionPage(col.uid, 1, void 0, void 0, void 0, "none", "", "", false);
|
|
552
1001
|
});
|
|
553
1002
|
};
|
|
554
1003
|
const isCollectionFullySelected = (col) => {
|
|
@@ -614,13 +1063,6 @@ const BulkUpdater = () => {
|
|
|
614
1063
|
});
|
|
615
1064
|
return;
|
|
616
1065
|
}
|
|
617
|
-
if (useRegex && !license?.isPro) {
|
|
618
|
-
toggleNotification({
|
|
619
|
-
type: "warning",
|
|
620
|
-
message: "Regex replacement is a Pro feature. Please activate your license in Settings."
|
|
621
|
-
});
|
|
622
|
-
return;
|
|
623
|
-
}
|
|
624
1066
|
const totalSelected = Object.values(selectedEntries).filter(Boolean).length;
|
|
625
1067
|
if (totalSelected === 0) {
|
|
626
1068
|
toggleNotification({
|
|
@@ -677,6 +1119,7 @@ const BulkUpdater = () => {
|
|
|
677
1119
|
message: `Bulk update complete! Batch ID: ${res.data.batchId}. Updated: ${res.data.updatedCount}, Skipped: ${res.data.skippedCount}`
|
|
678
1120
|
});
|
|
679
1121
|
await fetchModels();
|
|
1122
|
+
await fetchAuditHistory();
|
|
680
1123
|
}
|
|
681
1124
|
} else {
|
|
682
1125
|
toggleNotification({
|
|
@@ -804,7 +1247,7 @@ const BulkUpdater = () => {
|
|
|
804
1247
|
}
|
|
805
1248
|
};
|
|
806
1249
|
const totalSelectedCount = Object.values(selectedEntries).filter(Boolean).length;
|
|
807
|
-
const rootRef =
|
|
1250
|
+
const rootRef = React__default.useRef(null);
|
|
808
1251
|
useEffect(() => {
|
|
809
1252
|
if (rootRef.current && rootRef.current.parentElement) {
|
|
810
1253
|
rootRef.current.parentElement.style.minWidth = "0";
|
|
@@ -877,14 +1320,6 @@ const BulkUpdater = () => {
|
|
|
877
1320
|
/* @__PURE__ */ jsxs(Box, { children: [
|
|
878
1321
|
/* @__PURE__ */ jsxs(Flex, { gap: 3, alignItems: "center", children: [
|
|
879
1322
|
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", fontWeight: "bold", children: "Bulk Attribute Updater" }),
|
|
880
|
-
/* @__PURE__ */ jsx(
|
|
881
|
-
Badge,
|
|
882
|
-
{
|
|
883
|
-
backgroundColor: license?.isPro ? "success100" : "neutral200",
|
|
884
|
-
textColor: license?.isPro ? "success700" : "neutral700",
|
|
885
|
-
children: license?.isPro ? `${license.tier.toUpperCase()} EDITION` : "COMMUNITY EDITION"
|
|
886
|
-
}
|
|
887
|
-
),
|
|
888
1323
|
auditEnabled && /* @__PURE__ */ jsx(Badge, { backgroundColor: "secondary100", textColor: "secondary700", children: "AUDIT & ROLLBACK ACTIVE" })
|
|
889
1324
|
] }),
|
|
890
1325
|
/* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral600", children: "Cross-collection batch attribute management with declarative audit trail and one-click rollback." })
|
|
@@ -925,6 +1360,24 @@ const BulkUpdater = () => {
|
|
|
925
1360
|
] }) : auditHistory.length > 0 ? ` (${auditHistory.length})` : ""
|
|
926
1361
|
]
|
|
927
1362
|
}
|
|
1363
|
+
),
|
|
1364
|
+
/* @__PURE__ */ jsx(
|
|
1365
|
+
Button,
|
|
1366
|
+
{
|
|
1367
|
+
variant: activeTab === "rules" ? "default" : "tertiary",
|
|
1368
|
+
onClick: () => setActiveTab("rules"),
|
|
1369
|
+
size: "M",
|
|
1370
|
+
children: "Validation & Quota Rules"
|
|
1371
|
+
}
|
|
1372
|
+
),
|
|
1373
|
+
/* @__PURE__ */ jsx(
|
|
1374
|
+
Button,
|
|
1375
|
+
{
|
|
1376
|
+
variant: activeTab === "csv" ? "default" : "tertiary",
|
|
1377
|
+
onClick: () => setActiveTab("csv"),
|
|
1378
|
+
size: "M",
|
|
1379
|
+
children: "CSV Import / Export & Override"
|
|
1380
|
+
}
|
|
928
1381
|
)
|
|
929
1382
|
] }),
|
|
930
1383
|
executionWindow && /* @__PURE__ */ jsx(Flex, { gap: 2, alignItems: "center", children: /* @__PURE__ */ jsx(
|
|
@@ -953,7 +1406,7 @@ const BulkUpdater = () => {
|
|
|
953
1406
|
/* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral700", children: [
|
|
954
1407
|
/* @__PURE__ */ jsx("code", { children: latestActiveBatch.batchId }),
|
|
955
1408
|
" (",
|
|
956
|
-
latestActiveBatch.
|
|
1409
|
+
latestActiveBatch.updatedCount,
|
|
957
1410
|
" entries updated by ",
|
|
958
1411
|
latestActiveBatch.userEmail,
|
|
959
1412
|
")"
|
|
@@ -1104,38 +1557,24 @@ const BulkUpdater = () => {
|
|
|
1104
1557
|
}
|
|
1105
1558
|
) })
|
|
1106
1559
|
] }),
|
|
1107
|
-
/* @__PURE__ */
|
|
1108
|
-
/* @__PURE__ */
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
)
|
|
1126
|
-
] }),
|
|
1127
|
-
useRegex && /* @__PURE__ */ jsx(Box, { style: { flex: 1, minWidth: 240 }, children: /* @__PURE__ */ jsx(
|
|
1128
|
-
TextInput,
|
|
1129
|
-
{
|
|
1130
|
-
placeholder: "Regex pattern (e.g. \\b(OldName)\\b)...",
|
|
1131
|
-
value: regexPattern,
|
|
1132
|
-
onChange: (e) => setRegexPattern(e.target.value),
|
|
1133
|
-
disabled: !license?.isPro
|
|
1134
|
-
}
|
|
1135
|
-
) })
|
|
1136
|
-
] }),
|
|
1137
|
-
!license?.isPro && useRegex && /* @__PURE__ */ jsx(Box, { marginTop: 2, children: /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "warning700", children: "Regex replacement is locked to Pro license holders. Visit Settings > Bulk Updater to activate your key." }) })
|
|
1138
|
-
] }),
|
|
1560
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 4, padding: 4, background: "neutral100", hasRadius: true, children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", wrap: "wrap", gap: 3, children: [
|
|
1561
|
+
/* @__PURE__ */ jsx(Flex, { gap: 2, alignItems: "center", children: /* @__PURE__ */ jsx(
|
|
1562
|
+
Checkbox,
|
|
1563
|
+
{
|
|
1564
|
+
checked: useRegex,
|
|
1565
|
+
onCheckedChange: (checked) => setUseRegex(Boolean(checked)),
|
|
1566
|
+
children: /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: "Enable Regex Find & Replace" })
|
|
1567
|
+
}
|
|
1568
|
+
) }),
|
|
1569
|
+
useRegex && /* @__PURE__ */ jsx(Box, { style: { flex: 1, minWidth: 240 }, children: /* @__PURE__ */ jsx(
|
|
1570
|
+
TextInput,
|
|
1571
|
+
{
|
|
1572
|
+
placeholder: "Regex pattern (e.g. \\b(OldName)\\b)...",
|
|
1573
|
+
value: regexPattern,
|
|
1574
|
+
onChange: (e) => setRegexPattern(e.target.value)
|
|
1575
|
+
}
|
|
1576
|
+
) })
|
|
1577
|
+
] }) }),
|
|
1139
1578
|
selectedAttribute && /* @__PURE__ */ jsx(Box, { marginTop: 4, padding: 3, background: "neutral100", hasRadius: true, children: /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
|
|
1140
1579
|
/* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", children: "Attribute Info:" }),
|
|
1141
1580
|
/* @__PURE__ */ jsxs(Typography, { variant: "pi", children: [
|
|
@@ -1194,24 +1633,25 @@ const BulkUpdater = () => {
|
|
|
1194
1633
|
children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 3, children: [
|
|
1195
1634
|
/* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", wrap: "wrap", gap: 2, children: [
|
|
1196
1635
|
/* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
|
|
1197
|
-
/* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "bold", children: "
|
|
1198
|
-
|
|
1636
|
+
/* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "bold", children: "Search & Filter Targets:" }),
|
|
1637
|
+
isFilterActive && /* @__PURE__ */ jsxs(Badge, { backgroundColor: "primary100", textColor: "primary700", children: [
|
|
1199
1638
|
matchingEntriesCount,
|
|
1200
1639
|
" matching ",
|
|
1201
|
-
matchingEntriesCount === 1 ? "entry" : "entries"
|
|
1640
|
+
matchingEntriesCount === 1 ? "entry" : "entries",
|
|
1641
|
+
" found in database"
|
|
1202
1642
|
] })
|
|
1203
1643
|
] }),
|
|
1204
|
-
|
|
1644
|
+
isFilterActive && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "S", onClick: clearFilter, children: "Clear Search & Filter" })
|
|
1205
1645
|
] }),
|
|
1206
1646
|
/* @__PURE__ */ jsxs(Flex, { gap: 3, alignItems: "flex-end", wrap: "wrap", children: [
|
|
1207
|
-
/* @__PURE__ */ jsx(Box, { style: { width:
|
|
1647
|
+
/* @__PURE__ */ jsx(Box, { style: { width: 220, minWidth: 180 }, children: /* @__PURE__ */ jsxs(
|
|
1208
1648
|
SingleSelect,
|
|
1209
1649
|
{
|
|
1210
1650
|
label: `Filter condition for "${selectedAttribute}"`,
|
|
1211
1651
|
value: filterOperator,
|
|
1212
1652
|
onChange: (val) => setFilterOperator(String(val)),
|
|
1213
1653
|
children: [
|
|
1214
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "none", children: "Show All (No Filter)" }),
|
|
1654
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "none", children: "Show All (No Attribute Filter)" }),
|
|
1215
1655
|
/* @__PURE__ */ jsx(SingleSelectOption, { value: "empty", children: "Is Empty or Null" }),
|
|
1216
1656
|
/* @__PURE__ */ jsx(SingleSelectOption, { value: "not_empty", children: "Is Not Empty" }),
|
|
1217
1657
|
/* @__PURE__ */ jsx(SingleSelectOption, { value: "equals", children: "Equals Exact Text" }),
|
|
@@ -1220,28 +1660,33 @@ const BulkUpdater = () => {
|
|
|
1220
1660
|
]
|
|
1221
1661
|
}
|
|
1222
1662
|
) }),
|
|
1223
|
-
(filterOperator === "equals" || filterOperator === "contains" || filterOperator === "starts_with") && /* @__PURE__ */ jsx(Box, { style: { flex: 1, minWidth:
|
|
1663
|
+
(filterOperator === "equals" || filterOperator === "contains" || filterOperator === "starts_with") && /* @__PURE__ */ jsx(Box, { style: { flex: 1, minWidth: 200 }, children: /* @__PURE__ */ jsx(
|
|
1224
1664
|
TextInput,
|
|
1225
1665
|
{
|
|
1226
|
-
label:
|
|
1666
|
+
label: `Value for "${selectedAttribute}"`,
|
|
1227
1667
|
placeholder: "Type value to match...",
|
|
1228
1668
|
value: filterQuery,
|
|
1229
1669
|
onChange: (e) => setFilterQuery(e.target.value)
|
|
1230
1670
|
}
|
|
1231
1671
|
) }),
|
|
1232
|
-
|
|
1233
|
-
|
|
1672
|
+
/* @__PURE__ */ jsx(Box, { style: { flex: 1, minWidth: 200 }, children: /* @__PURE__ */ jsx(
|
|
1673
|
+
TextInput,
|
|
1674
|
+
{
|
|
1675
|
+
label: "Full-text Entry Search",
|
|
1676
|
+
placeholder: "Search title, name, or text across records...",
|
|
1677
|
+
value: entrySearch,
|
|
1678
|
+
onChange: (e) => setEntrySearch(e.target.value)
|
|
1679
|
+
}
|
|
1680
|
+
) }),
|
|
1681
|
+
isFilterActive && /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
|
|
1682
|
+
/* @__PURE__ */ jsx(
|
|
1234
1683
|
Button,
|
|
1235
1684
|
{
|
|
1236
1685
|
variant: "default",
|
|
1237
1686
|
size: "S",
|
|
1238
1687
|
onClick: selectAllMatching,
|
|
1239
1688
|
disabled: matchingEntriesCount === 0,
|
|
1240
|
-
children:
|
|
1241
|
-
"Select Matching (",
|
|
1242
|
-
matchingEntriesCount,
|
|
1243
|
-
")"
|
|
1244
|
-
]
|
|
1689
|
+
children: "Select All Loaded"
|
|
1245
1690
|
}
|
|
1246
1691
|
),
|
|
1247
1692
|
/* @__PURE__ */ jsx(
|
|
@@ -1251,19 +1696,12 @@ const BulkUpdater = () => {
|
|
|
1251
1696
|
size: "S",
|
|
1252
1697
|
onClick: deselectAllMatching,
|
|
1253
1698
|
disabled: matchingEntriesCount === 0,
|
|
1254
|
-
children: "Deselect
|
|
1699
|
+
children: "Deselect All Loaded"
|
|
1255
1700
|
}
|
|
1256
1701
|
)
|
|
1257
1702
|
] })
|
|
1258
1703
|
] }),
|
|
1259
|
-
|
|
1260
|
-
Checkbox,
|
|
1261
|
-
{
|
|
1262
|
-
checked: hideNonMatching,
|
|
1263
|
-
onCheckedChange: (checked) => setHideNonMatching(Boolean(checked)),
|
|
1264
|
-
children: /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral700", children: "Only display matching entries in tables (hide non-matching)" })
|
|
1265
|
-
}
|
|
1266
|
-
) })
|
|
1704
|
+
isFilterActive && /* @__PURE__ */ jsx(Flex, { gap: 2, alignItems: "center", marginTop: 1, children: /* @__PURE__ */ jsx(Badge, { backgroundColor: "success100", textColor: "success700", size: "S", children: "✓ Filter active: Showing only matching entries. All returned matching records are pre-selected." }) })
|
|
1267
1705
|
] })
|
|
1268
1706
|
}
|
|
1269
1707
|
),
|
|
@@ -1357,8 +1795,8 @@ const BulkUpdater = () => {
|
|
|
1357
1795
|
}
|
|
1358
1796
|
) }),
|
|
1359
1797
|
/* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", style: { marginLeft: "auto" }, children: [
|
|
1360
|
-
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Default page size (max
|
|
1361
|
-
/* @__PURE__ */ jsx(Box, { style: { width:
|
|
1798
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Default page size (max 500):" }),
|
|
1799
|
+
/* @__PURE__ */ jsx(Box, { style: { width: 130 }, children: /* @__PURE__ */ jsxs(
|
|
1362
1800
|
SingleSelect,
|
|
1363
1801
|
{
|
|
1364
1802
|
size: "S",
|
|
@@ -1369,7 +1807,9 @@ const BulkUpdater = () => {
|
|
|
1369
1807
|
/* @__PURE__ */ jsx(SingleSelectOption, { value: "10", children: "10 / page" }),
|
|
1370
1808
|
/* @__PURE__ */ jsx(SingleSelectOption, { value: "25", children: "25 / page" }),
|
|
1371
1809
|
/* @__PURE__ */ jsx(SingleSelectOption, { value: "50", children: "50 / page" }),
|
|
1372
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "100", children: "100 / page" })
|
|
1810
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "100", children: "100 / page" }),
|
|
1811
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "250", children: "250 / page" }),
|
|
1812
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "500", children: "500 / page" })
|
|
1373
1813
|
]
|
|
1374
1814
|
}
|
|
1375
1815
|
) })
|
|
@@ -1384,7 +1824,7 @@ const BulkUpdater = () => {
|
|
|
1384
1824
|
const pageSize = pageState ? pageState.pageSize : defaultPageSize;
|
|
1385
1825
|
const hasAttr = col.attributes.includes(selectedAttribute);
|
|
1386
1826
|
const visibleEntries = getVisibleEntries(col);
|
|
1387
|
-
|
|
1827
|
+
entries.filter((e) => entryMatchesFilter(e, selectedAttribute)).length;
|
|
1388
1828
|
const isFullySelected = isCollectionFullySelected(col);
|
|
1389
1829
|
const isPartiallySelected = isCollectionPartiallySelected(col);
|
|
1390
1830
|
const currentSort = collectionSorts[col.uid] || { field: "createdAt", order: "desc" };
|
|
@@ -1479,7 +1919,56 @@ const BulkUpdater = () => {
|
|
|
1479
1919
|
]
|
|
1480
1920
|
}
|
|
1481
1921
|
),
|
|
1482
|
-
/* @__PURE__ */ jsx(
|
|
1922
|
+
/* @__PURE__ */ jsx(
|
|
1923
|
+
Button,
|
|
1924
|
+
{
|
|
1925
|
+
variant: "tertiary",
|
|
1926
|
+
size: "S",
|
|
1927
|
+
startIcon: /* @__PURE__ */ jsx(Download, {}),
|
|
1928
|
+
onClick: async () => {
|
|
1929
|
+
try {
|
|
1930
|
+
const params = new URLSearchParams();
|
|
1931
|
+
if (selectedAttribute) params.set("attribute", selectedAttribute);
|
|
1932
|
+
if (filterOperator && filterOperator !== "none") {
|
|
1933
|
+
params.set("filterOperator", filterOperator);
|
|
1934
|
+
if (filterQuery) params.set("filterQuery", filterQuery);
|
|
1935
|
+
}
|
|
1936
|
+
if (entrySearch && entrySearch.trim()) {
|
|
1937
|
+
params.set("search", entrySearch.trim());
|
|
1938
|
+
}
|
|
1939
|
+
const res = await get(`/bulk-updater/csv/export/${col.uid}?${params.toString()}`);
|
|
1940
|
+
const csvStr = res.data?.csvContent || (typeof res.data === "string" ? res.data : "");
|
|
1941
|
+
if (!csvStr) {
|
|
1942
|
+
toggleNotification({
|
|
1943
|
+
type: "warning",
|
|
1944
|
+
message: "No CSV content returned for this collection"
|
|
1945
|
+
});
|
|
1946
|
+
return;
|
|
1947
|
+
}
|
|
1948
|
+
const blob = new Blob([csvStr], { type: "text/csv;charset=utf-8;" });
|
|
1949
|
+
const url = URL.createObjectURL(blob);
|
|
1950
|
+
const link = document.createElement("a");
|
|
1951
|
+
link.href = url;
|
|
1952
|
+
link.setAttribute("download", `${col.singularName || "export"}_entries.csv`);
|
|
1953
|
+
document.body.appendChild(link);
|
|
1954
|
+
link.click();
|
|
1955
|
+
document.body.removeChild(link);
|
|
1956
|
+
URL.revokeObjectURL(url);
|
|
1957
|
+
toggleNotification({
|
|
1958
|
+
type: "success",
|
|
1959
|
+
message: `Exported ${col.displayName} entries to CSV`
|
|
1960
|
+
});
|
|
1961
|
+
} catch (e) {
|
|
1962
|
+
toggleNotification({
|
|
1963
|
+
type: "danger",
|
|
1964
|
+
message: e.message || "Failed exporting CSV"
|
|
1965
|
+
});
|
|
1966
|
+
}
|
|
1967
|
+
},
|
|
1968
|
+
children: "Export CSV"
|
|
1969
|
+
}
|
|
1970
|
+
),
|
|
1971
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: col.isSingleType ? "1 single entry" : isFilterActive ? `${totalEntries} matching entries in DB` : `${totalEntries} entries` })
|
|
1483
1972
|
] })
|
|
1484
1973
|
] }),
|
|
1485
1974
|
openColumnPickerUid === col.uid && /* @__PURE__ */ jsx(
|
|
@@ -1549,7 +2038,7 @@ const BulkUpdater = () => {
|
|
|
1549
2038
|
/* @__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) => {
|
|
1550
2039
|
const key = `${col.uid}${KEY_SEP}${entry.documentId}`;
|
|
1551
2040
|
const isSelected = Boolean(selectedEntries[key]);
|
|
1552
|
-
const isMatch =
|
|
2041
|
+
const isMatch = isFilterActive;
|
|
1553
2042
|
return /* @__PURE__ */ jsx(
|
|
1554
2043
|
Tr,
|
|
1555
2044
|
{
|
|
@@ -1581,11 +2070,12 @@ const BulkUpdater = () => {
|
|
|
1581
2070
|
Math.min(page * pageSize, totalEntries),
|
|
1582
2071
|
" of ",
|
|
1583
2072
|
totalEntries,
|
|
1584
|
-
"
|
|
2073
|
+
" ",
|
|
2074
|
+
isFilterActive ? "matching entries" : "entries"
|
|
1585
2075
|
] }),
|
|
1586
2076
|
/* @__PURE__ */ jsxs(Flex, { gap: 1, alignItems: "center", children: [
|
|
1587
2077
|
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Show:" }),
|
|
1588
|
-
/* @__PURE__ */ jsx(Box, { style: { width:
|
|
2078
|
+
/* @__PURE__ */ jsx(Box, { style: { width: 85 }, children: /* @__PURE__ */ jsxs(
|
|
1589
2079
|
SingleSelect,
|
|
1590
2080
|
{
|
|
1591
2081
|
size: "S",
|
|
@@ -1596,12 +2086,27 @@ const BulkUpdater = () => {
|
|
|
1596
2086
|
/* @__PURE__ */ jsx(SingleSelectOption, { value: "10", children: "10" }),
|
|
1597
2087
|
/* @__PURE__ */ jsx(SingleSelectOption, { value: "25", children: "25" }),
|
|
1598
2088
|
/* @__PURE__ */ jsx(SingleSelectOption, { value: "50", children: "50" }),
|
|
1599
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "100", children: "100" })
|
|
2089
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "100", children: "100" }),
|
|
2090
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "250", children: "250" }),
|
|
2091
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "500", children: "500" })
|
|
1600
2092
|
]
|
|
1601
2093
|
}
|
|
1602
2094
|
) }),
|
|
1603
2095
|
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: "per page" })
|
|
1604
|
-
] })
|
|
2096
|
+
] }),
|
|
2097
|
+
totalEntries > visibleEntries.length && /* @__PURE__ */ jsxs(
|
|
2098
|
+
Button,
|
|
2099
|
+
{
|
|
2100
|
+
variant: "tertiary",
|
|
2101
|
+
size: "S",
|
|
2102
|
+
onClick: () => handleCollectionPageSizeChange(col.uid, Math.min(totalEntries, 500)),
|
|
2103
|
+
children: [
|
|
2104
|
+
"Load all ",
|
|
2105
|
+
totalEntries,
|
|
2106
|
+
" entries"
|
|
2107
|
+
]
|
|
2108
|
+
}
|
|
2109
|
+
)
|
|
1605
2110
|
] }),
|
|
1606
2111
|
pageCount > 1 && /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
|
|
1607
2112
|
/* @__PURE__ */ jsx(
|
|
@@ -1884,7 +2389,7 @@ const BulkUpdater = () => {
|
|
|
1884
2389
|
/* @__PURE__ */ jsx(Tbody, { children: auditHistory.map((rec) => {
|
|
1885
2390
|
const isExpanded = expandedDiffBatchId === rec.batchId;
|
|
1886
2391
|
const dateStr = new Date(rec.executedAt).toLocaleString();
|
|
1887
|
-
return /* @__PURE__ */ jsxs(
|
|
2392
|
+
return /* @__PURE__ */ jsxs(React__default.Fragment, { children: [
|
|
1888
2393
|
/* @__PURE__ */ jsxs(
|
|
1889
2394
|
Tr,
|
|
1890
2395
|
{
|
|
@@ -2005,6 +2510,8 @@ const BulkUpdater = () => {
|
|
|
2005
2510
|
]
|
|
2006
2511
|
}
|
|
2007
2512
|
),
|
|
2513
|
+
activeTab === "rules" && /* @__PURE__ */ jsx(ValidationRulesTab, {}),
|
|
2514
|
+
activeTab === "csv" && /* @__PURE__ */ jsx(CsvManagerTab, {}),
|
|
2008
2515
|
showConfirmModal && /* @__PURE__ */ jsx(
|
|
2009
2516
|
"div",
|
|
2010
2517
|
{
|
|
@@ -2049,20 +2556,10 @@ const BulkUpdater = () => {
|
|
|
2049
2556
|
borderBottom: "1px solid rgba(120, 120, 150, 0.2)",
|
|
2050
2557
|
flexShrink: 0
|
|
2051
2558
|
},
|
|
2052
|
-
children: /* @__PURE__ */
|
|
2053
|
-
/* @__PURE__ */
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
] }),
|
|
2057
|
-
/* @__PURE__ */ jsx(
|
|
2058
|
-
Badge,
|
|
2059
|
-
{
|
|
2060
|
-
backgroundColor: license?.tier === "enterprise" ? "primary100" : "neutral200",
|
|
2061
|
-
textColor: license?.tier === "enterprise" ? "primary700" : "neutral700",
|
|
2062
|
-
children: license?.tier === "enterprise" ? "ENTERPRISE 4-EYES" : "STANDARD"
|
|
2063
|
-
}
|
|
2064
|
-
)
|
|
2065
|
-
] })
|
|
2559
|
+
children: /* @__PURE__ */ jsx(Flex, { justifyContent: "space-between", alignItems: "center", children: /* @__PURE__ */ jsxs(Box, { children: [
|
|
2560
|
+
/* @__PURE__ */ jsx(Typography, { variant: "delta", fontWeight: "bold", children: "Confirm Bulk Update" }),
|
|
2561
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", display: "block", children: "Review target attributes, affected counts, and server execution policy before proceeding." })
|
|
2562
|
+
] }) })
|
|
2066
2563
|
}
|
|
2067
2564
|
),
|
|
2068
2565
|
/* @__PURE__ */ jsxs(
|
|
@@ -2206,7 +2703,7 @@ const BulkUpdater = () => {
|
|
|
2206
2703
|
children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", gap: 3, style: { width: "100%" }, children: [
|
|
2207
2704
|
/* @__PURE__ */ jsx(Button, { variant: "tertiary", size: "M", onClick: () => setShowConfirmModal(false), children: "Cancel" }),
|
|
2208
2705
|
/* @__PURE__ */ jsxs(Flex, { gap: 2, wrap: "wrap", justifyContent: "flex-end", alignItems: "center", children: [
|
|
2209
|
-
|
|
2706
|
+
/* @__PURE__ */ jsx(
|
|
2210
2707
|
Button,
|
|
2211
2708
|
{
|
|
2212
2709
|
variant: executionWindow?.isBusinessHours ? "default" : "secondary",
|
|
@@ -2220,7 +2717,7 @@ const BulkUpdater = () => {
|
|
|
2220
2717
|
/* @__PURE__ */ jsxs(
|
|
2221
2718
|
Button,
|
|
2222
2719
|
{
|
|
2223
|
-
variant:
|
|
2720
|
+
variant: "secondary",
|
|
2224
2721
|
size: "M",
|
|
2225
2722
|
onClick: () => executeBatchWithMode("queue_offpeak"),
|
|
2226
2723
|
loading: updating,
|
|
@@ -2267,6 +2764,7 @@ const BulkUpdater = () => {
|
|
|
2267
2764
|
export {
|
|
2268
2765
|
BulkUpdater as default,
|
|
2269
2766
|
formatDisplayValue,
|
|
2270
|
-
getAvailableColumnsForCollection
|
|
2767
|
+
getAvailableColumnsForCollection,
|
|
2768
|
+
getNestedValue
|
|
2271
2769
|
};
|
|
2272
|
-
//# sourceMappingURL=BulkUpdater-
|
|
2770
|
+
//# sourceMappingURL=BulkUpdater-BDszahRM.mjs.map
|