strapi-plugin-bulk-updater 1.2.8 → 1.2.10
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/dist/_chunks/{BulkUpdater-DR8Z9z95.mjs → BulkUpdater-Cg9utqzm.mjs} +507 -40
- package/dist/_chunks/BulkUpdater-Cg9utqzm.mjs.map +1 -0
- package/dist/_chunks/{BulkUpdater-2TTEWMXI.js → BulkUpdater-EI4sKaLN.js} +506 -39
- package/dist/_chunks/BulkUpdater-EI4sKaLN.js.map +1 -0
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +264 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +264 -0
- package/dist/server/index.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/_chunks/BulkUpdater-2TTEWMXI.js.map +0 -1
- package/dist/_chunks/BulkUpdater-DR8Z9z95.mjs.map +0 -1
|
@@ -2,7 +2,7 @@ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
|
2
2
|
import React__default, { useState, useEffect, useMemo, useRef } from "react";
|
|
3
3
|
import { useFetchClient, useNotification } from "@strapi/strapi/admin";
|
|
4
4
|
import { Box, Flex, Typography, Button, SingleSelect, SingleSelectOption, Checkbox, Badge, Alert, Table, Thead, Tr, Th, Tbody, Td, Loader, TextInput, ComboboxOption, Field, Combobox } from "@strapi/design-system";
|
|
5
|
-
import { ArrowClockwise, Download, Upload, Check, Play } from "@strapi/icons";
|
|
5
|
+
import { ArrowClockwise, Download, Upload, Check, Eye, Play } from "@strapi/icons";
|
|
6
6
|
import { V as ValidationRulesTab } from "./ValidationRulesTab-BGcqM9cN.mjs";
|
|
7
7
|
function CsvManagerTab() {
|
|
8
8
|
const { get, post } = useFetchClient();
|
|
@@ -1113,6 +1113,330 @@ function ProcessingDashboardModal({
|
|
|
1113
1113
|
}
|
|
1114
1114
|
);
|
|
1115
1115
|
}
|
|
1116
|
+
const BulkUpdatePreviewModal = ({
|
|
1117
|
+
isOpen,
|
|
1118
|
+
onClose,
|
|
1119
|
+
onProceed,
|
|
1120
|
+
loading,
|
|
1121
|
+
previewData,
|
|
1122
|
+
attribute,
|
|
1123
|
+
targetValueDisplay
|
|
1124
|
+
}) => {
|
|
1125
|
+
const [filterTab, setFilterTab] = useState("all");
|
|
1126
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
1127
|
+
const filteredDiffs = useMemo(() => {
|
|
1128
|
+
if (!previewData || !previewData.diffs) return [];
|
|
1129
|
+
let items = previewData.diffs;
|
|
1130
|
+
if (filterTab !== "all") {
|
|
1131
|
+
items = items.filter((d) => d.status === filterTab);
|
|
1132
|
+
}
|
|
1133
|
+
if (searchQuery.trim()) {
|
|
1134
|
+
const q = searchQuery.toLowerCase().trim();
|
|
1135
|
+
items = items.filter(
|
|
1136
|
+
(d) => d.label.toLowerCase().includes(q) || d.documentId.toLowerCase().includes(q) || d.collectionName.toLowerCase().includes(q) || String(d.oldDisplay || "").toLowerCase().includes(q) || String(d.newDisplay || "").toLowerCase().includes(q)
|
|
1137
|
+
);
|
|
1138
|
+
}
|
|
1139
|
+
return items;
|
|
1140
|
+
}, [previewData, filterTab, searchQuery]);
|
|
1141
|
+
if (!isOpen) return null;
|
|
1142
|
+
return /* @__PURE__ */ jsx(
|
|
1143
|
+
"div",
|
|
1144
|
+
{
|
|
1145
|
+
style: {
|
|
1146
|
+
position: "fixed",
|
|
1147
|
+
inset: 0,
|
|
1148
|
+
backgroundColor: "rgba(20, 20, 30, 0.7)",
|
|
1149
|
+
backdropFilter: "blur(3px)",
|
|
1150
|
+
display: "flex",
|
|
1151
|
+
alignItems: "center",
|
|
1152
|
+
justifyContent: "center",
|
|
1153
|
+
zIndex: 9999,
|
|
1154
|
+
padding: 16,
|
|
1155
|
+
boxSizing: "border-box"
|
|
1156
|
+
},
|
|
1157
|
+
onClick: onClose,
|
|
1158
|
+
children: /* @__PURE__ */ jsxs(
|
|
1159
|
+
Box,
|
|
1160
|
+
{
|
|
1161
|
+
background: "neutral0",
|
|
1162
|
+
hasRadius: true,
|
|
1163
|
+
shadow: "popupShadow",
|
|
1164
|
+
style: {
|
|
1165
|
+
maxWidth: 1040,
|
|
1166
|
+
width: "95%",
|
|
1167
|
+
maxHeight: "calc(100vh - 48px)",
|
|
1168
|
+
display: "flex",
|
|
1169
|
+
flexDirection: "column",
|
|
1170
|
+
overflow: "hidden",
|
|
1171
|
+
position: "relative",
|
|
1172
|
+
boxShadow: "0 24px 48px rgba(0, 0, 0, 0.35), 0 0 1px rgba(0, 0, 0, 0.2)"
|
|
1173
|
+
},
|
|
1174
|
+
onClick: (e) => e.stopPropagation(),
|
|
1175
|
+
children: [
|
|
1176
|
+
/* @__PURE__ */ jsx(
|
|
1177
|
+
Box,
|
|
1178
|
+
{
|
|
1179
|
+
padding: 5,
|
|
1180
|
+
background: "neutral100",
|
|
1181
|
+
style: {
|
|
1182
|
+
borderBottom: "1px solid rgba(120, 120, 150, 0.2)",
|
|
1183
|
+
flexShrink: 0
|
|
1184
|
+
},
|
|
1185
|
+
children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", wrap: "wrap", gap: 3, children: [
|
|
1186
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
1187
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", marginBottom: 1, children: [
|
|
1188
|
+
/* @__PURE__ */ jsx(Typography, { variant: "delta", fontWeight: "bold", children: "Pre-Update Change Preview" }),
|
|
1189
|
+
/* @__PURE__ */ jsxs(Badge, { backgroundColor: "primary100", textColor: "primary700", children: [
|
|
1190
|
+
"Target: ",
|
|
1191
|
+
attribute
|
|
1192
|
+
] })
|
|
1193
|
+
] }),
|
|
1194
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Inspect exact before & after values across target records before applying changes to the database." })
|
|
1195
|
+
] }),
|
|
1196
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
|
|
1197
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "New Value:" }),
|
|
1198
|
+
/* @__PURE__ */ jsx(Badge, { backgroundColor: "success100", textColor: "success700", children: targetValueDisplay || "(empty)" })
|
|
1199
|
+
] })
|
|
1200
|
+
] })
|
|
1201
|
+
}
|
|
1202
|
+
),
|
|
1203
|
+
/* @__PURE__ */ jsx(
|
|
1204
|
+
Box,
|
|
1205
|
+
{
|
|
1206
|
+
padding: 5,
|
|
1207
|
+
style: {
|
|
1208
|
+
flex: "1 1 auto",
|
|
1209
|
+
minHeight: 0,
|
|
1210
|
+
overflowY: "auto",
|
|
1211
|
+
WebkitOverflowScrolling: "touch"
|
|
1212
|
+
},
|
|
1213
|
+
children: loading ? /* @__PURE__ */ jsx(Box, { padding: 8, style: { textAlign: "center" }, children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "center", gap: 3, children: [
|
|
1214
|
+
/* @__PURE__ */ jsx(Loader, { children: "Inspecting target records from database..." }),
|
|
1215
|
+
/* @__PURE__ */ jsx(Typography, { variant: "delta", fontWeight: "semiBold", children: "Inspecting Target Records..." }),
|
|
1216
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Computing proposed diffs and verifying against database schema." })
|
|
1217
|
+
] }) }) : !previewData ? /* @__PURE__ */ jsx(Box, { padding: 6, style: { textAlign: "center" }, children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", children: "No preview data available." }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1218
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 3, marginBottom: 4, wrap: "wrap", children: [
|
|
1219
|
+
/* @__PURE__ */ jsxs(
|
|
1220
|
+
Box,
|
|
1221
|
+
{
|
|
1222
|
+
padding: 3,
|
|
1223
|
+
background: "neutral100",
|
|
1224
|
+
hasRadius: true,
|
|
1225
|
+
style: { flex: 1, minWidth: 140, border: "1px solid rgba(120, 120, 150, 0.15)" },
|
|
1226
|
+
children: [
|
|
1227
|
+
/* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", display: "block", children: "TOTAL TARGETS" }),
|
|
1228
|
+
/* @__PURE__ */ jsx(Typography, { variant: "beta", fontWeight: "bold", textColor: "neutral800", children: previewData.summary.total })
|
|
1229
|
+
]
|
|
1230
|
+
}
|
|
1231
|
+
),
|
|
1232
|
+
/* @__PURE__ */ jsxs(
|
|
1233
|
+
Box,
|
|
1234
|
+
{
|
|
1235
|
+
padding: 3,
|
|
1236
|
+
background: "success100",
|
|
1237
|
+
hasRadius: true,
|
|
1238
|
+
style: { flex: 1, minWidth: 140, border: "1px solid #b7eb8f" },
|
|
1239
|
+
children: [
|
|
1240
|
+
/* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "success700", display: "block", children: "WILL UPDATE" }),
|
|
1241
|
+
/* @__PURE__ */ jsx(Typography, { variant: "beta", fontWeight: "bold", textColor: "success700", children: previewData.summary.willUpdate })
|
|
1242
|
+
]
|
|
1243
|
+
}
|
|
1244
|
+
),
|
|
1245
|
+
/* @__PURE__ */ jsxs(
|
|
1246
|
+
Box,
|
|
1247
|
+
{
|
|
1248
|
+
padding: 3,
|
|
1249
|
+
background: "neutral100",
|
|
1250
|
+
hasRadius: true,
|
|
1251
|
+
style: { flex: 1, minWidth: 140, border: "1px solid rgba(120, 120, 150, 0.15)" },
|
|
1252
|
+
children: [
|
|
1253
|
+
/* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", display: "block", children: "ALREADY UP-TO-DATE" }),
|
|
1254
|
+
/* @__PURE__ */ jsx(Typography, { variant: "beta", fontWeight: "bold", textColor: "neutral600", children: previewData.summary.unchanged })
|
|
1255
|
+
]
|
|
1256
|
+
}
|
|
1257
|
+
),
|
|
1258
|
+
/* @__PURE__ */ jsxs(
|
|
1259
|
+
Box,
|
|
1260
|
+
{
|
|
1261
|
+
padding: 3,
|
|
1262
|
+
background: previewData.summary.skipped > 0 ? "warning100" : "neutral100",
|
|
1263
|
+
hasRadius: true,
|
|
1264
|
+
style: { flex: 1, minWidth: 140, border: "1px solid rgba(120, 120, 150, 0.15)" },
|
|
1265
|
+
children: [
|
|
1266
|
+
/* @__PURE__ */ jsx(
|
|
1267
|
+
Typography,
|
|
1268
|
+
{
|
|
1269
|
+
variant: "sigma",
|
|
1270
|
+
textColor: previewData.summary.skipped > 0 ? "warning700" : "neutral600",
|
|
1271
|
+
display: "block",
|
|
1272
|
+
children: "WILL SKIP (NO FIELD)"
|
|
1273
|
+
}
|
|
1274
|
+
),
|
|
1275
|
+
/* @__PURE__ */ jsx(
|
|
1276
|
+
Typography,
|
|
1277
|
+
{
|
|
1278
|
+
variant: "beta",
|
|
1279
|
+
fontWeight: "bold",
|
|
1280
|
+
textColor: previewData.summary.skipped > 0 ? "warning700" : "neutral600",
|
|
1281
|
+
children: previewData.summary.skipped
|
|
1282
|
+
}
|
|
1283
|
+
)
|
|
1284
|
+
]
|
|
1285
|
+
}
|
|
1286
|
+
)
|
|
1287
|
+
] }),
|
|
1288
|
+
/* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", marginBottom: 3, wrap: "wrap", gap: 3, children: [
|
|
1289
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, wrap: "wrap", children: [
|
|
1290
|
+
/* @__PURE__ */ jsxs(
|
|
1291
|
+
Button,
|
|
1292
|
+
{
|
|
1293
|
+
variant: filterTab === "all" ? "default" : "tertiary",
|
|
1294
|
+
size: "S",
|
|
1295
|
+
onClick: () => setFilterTab("all"),
|
|
1296
|
+
children: [
|
|
1297
|
+
"All (",
|
|
1298
|
+
previewData.summary.total,
|
|
1299
|
+
")"
|
|
1300
|
+
]
|
|
1301
|
+
}
|
|
1302
|
+
),
|
|
1303
|
+
/* @__PURE__ */ jsxs(
|
|
1304
|
+
Button,
|
|
1305
|
+
{
|
|
1306
|
+
variant: filterTab === "will_update" ? "default" : "tertiary",
|
|
1307
|
+
size: "S",
|
|
1308
|
+
onClick: () => setFilterTab("will_update"),
|
|
1309
|
+
children: [
|
|
1310
|
+
"Will Update (",
|
|
1311
|
+
previewData.summary.willUpdate,
|
|
1312
|
+
")"
|
|
1313
|
+
]
|
|
1314
|
+
}
|
|
1315
|
+
),
|
|
1316
|
+
/* @__PURE__ */ jsxs(
|
|
1317
|
+
Button,
|
|
1318
|
+
{
|
|
1319
|
+
variant: filterTab === "unchanged" ? "default" : "tertiary",
|
|
1320
|
+
size: "S",
|
|
1321
|
+
onClick: () => setFilterTab("unchanged"),
|
|
1322
|
+
children: [
|
|
1323
|
+
"Unchanged (",
|
|
1324
|
+
previewData.summary.unchanged,
|
|
1325
|
+
")"
|
|
1326
|
+
]
|
|
1327
|
+
}
|
|
1328
|
+
),
|
|
1329
|
+
previewData.summary.skipped > 0 && /* @__PURE__ */ jsxs(
|
|
1330
|
+
Button,
|
|
1331
|
+
{
|
|
1332
|
+
variant: filterTab === "will_skip" ? "default" : "tertiary",
|
|
1333
|
+
size: "S",
|
|
1334
|
+
onClick: () => setFilterTab("will_skip"),
|
|
1335
|
+
children: [
|
|
1336
|
+
"Skipped (",
|
|
1337
|
+
previewData.summary.skipped,
|
|
1338
|
+
")"
|
|
1339
|
+
]
|
|
1340
|
+
}
|
|
1341
|
+
)
|
|
1342
|
+
] }),
|
|
1343
|
+
/* @__PURE__ */ jsx(Box, { style: { width: 260 }, children: /* @__PURE__ */ jsx(
|
|
1344
|
+
TextInput,
|
|
1345
|
+
{
|
|
1346
|
+
placeholder: "Search records or values...",
|
|
1347
|
+
size: "S",
|
|
1348
|
+
value: searchQuery,
|
|
1349
|
+
onChange: (e) => setSearchQuery(e.target.value)
|
|
1350
|
+
}
|
|
1351
|
+
) })
|
|
1352
|
+
] }),
|
|
1353
|
+
/* @__PURE__ */ jsx(
|
|
1354
|
+
Box,
|
|
1355
|
+
{
|
|
1356
|
+
hasRadius: true,
|
|
1357
|
+
style: {
|
|
1358
|
+
border: "1px solid #eaeaef",
|
|
1359
|
+
maxHeight: 380,
|
|
1360
|
+
overflowY: "auto",
|
|
1361
|
+
overflowX: "auto"
|
|
1362
|
+
},
|
|
1363
|
+
children: /* @__PURE__ */ jsxs(Table, { colCount: 5, rowCount: filteredDiffs.length + 1, style: { width: "100%", minWidth: 780 }, children: [
|
|
1364
|
+
/* @__PURE__ */ jsx(Thead, { children: /* @__PURE__ */ jsxs(Tr, { children: [
|
|
1365
|
+
/* @__PURE__ */ jsx(Th, { style: { width: 150 }, children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", children: "COLLECTION" }) }),
|
|
1366
|
+
/* @__PURE__ */ jsx(Th, { style: { minWidth: 200 }, children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", children: "RECORD IDENTIFIER" }) }),
|
|
1367
|
+
/* @__PURE__ */ jsx(Th, { style: { minWidth: 180 }, children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", children: "CURRENT VALUE (BEFORE)" }) }),
|
|
1368
|
+
/* @__PURE__ */ jsx(Th, { style: { minWidth: 180 }, children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", children: "NEW VALUE (AFTER)" }) }),
|
|
1369
|
+
/* @__PURE__ */ jsx(Th, { style: { width: 140, textAlign: "right" }, children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", children: "IMPACT" }) })
|
|
1370
|
+
] }) }),
|
|
1371
|
+
/* @__PURE__ */ jsx(Tbody, { children: filteredDiffs.length === 0 ? /* @__PURE__ */ jsx(Tr, { children: /* @__PURE__ */ jsx(Td, { colSpan: 5, style: { textAlign: "center", padding: "24px" }, children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", children: "No records match the current filter or search criteria." }) }) }) : filteredDiffs.map((diff) => /* @__PURE__ */ jsxs(Tr, { children: [
|
|
1372
|
+
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Badge, { backgroundColor: "neutral150", textColor: "neutral700", children: diff.collectionName }) }),
|
|
1373
|
+
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsxs(Box, { children: [
|
|
1374
|
+
/* @__PURE__ */ jsx(Typography, { fontWeight: "bold", display: "block", children: diff.label }),
|
|
1375
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: /* @__PURE__ */ jsx("code", { children: diff.documentId }) })
|
|
1376
|
+
] }) }),
|
|
1377
|
+
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(
|
|
1378
|
+
Typography,
|
|
1379
|
+
{
|
|
1380
|
+
variant: "omega",
|
|
1381
|
+
style: {
|
|
1382
|
+
color: diff.hasChange ? "#666687" : "#272635",
|
|
1383
|
+
textDecoration: diff.hasChange ? "line-through" : "none",
|
|
1384
|
+
wordBreak: "break-all"
|
|
1385
|
+
},
|
|
1386
|
+
children: diff.oldDisplay || "(empty)"
|
|
1387
|
+
}
|
|
1388
|
+
) }),
|
|
1389
|
+
/* @__PURE__ */ jsx(Td, { children: diff.status === "will_skip" ? /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "warning700", children: "— Skipped (field absent) —" }) : diff.hasChange ? /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "bold", textColor: "success700", style: { wordBreak: "break-all" }, children: diff.newDisplay || "(empty)" }) : /* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral600", children: diff.newDisplay || "(already matching)" }) }),
|
|
1390
|
+
/* @__PURE__ */ jsxs(Td, { style: { textAlign: "right" }, children: [
|
|
1391
|
+
diff.status === "will_update" && /* @__PURE__ */ jsx(Badge, { backgroundColor: "success100", textColor: "success700", children: "✓ Will Update" }),
|
|
1392
|
+
diff.status === "unchanged" && /* @__PURE__ */ jsx(Badge, { backgroundColor: "neutral150", textColor: "neutral600", children: "= Unchanged" }),
|
|
1393
|
+
diff.status === "will_skip" && /* @__PURE__ */ jsx(Badge, { backgroundColor: "warning100", textColor: "warning700", children: "⚠ Will Skip" })
|
|
1394
|
+
] })
|
|
1395
|
+
] }, `${diff.uid}-${diff.documentId}`)) })
|
|
1396
|
+
] })
|
|
1397
|
+
}
|
|
1398
|
+
)
|
|
1399
|
+
] })
|
|
1400
|
+
}
|
|
1401
|
+
),
|
|
1402
|
+
/* @__PURE__ */ jsx(
|
|
1403
|
+
Box,
|
|
1404
|
+
{
|
|
1405
|
+
padding: 4,
|
|
1406
|
+
background: "neutral100",
|
|
1407
|
+
style: {
|
|
1408
|
+
borderTop: "1px solid rgba(120, 120, 150, 0.2)",
|
|
1409
|
+
flexShrink: 0
|
|
1410
|
+
},
|
|
1411
|
+
children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [
|
|
1412
|
+
/* @__PURE__ */ jsx(Button, { variant: "tertiary", size: "M", onClick: onClose, children: "Close Preview" }),
|
|
1413
|
+
/* @__PURE__ */ jsxs(
|
|
1414
|
+
Button,
|
|
1415
|
+
{
|
|
1416
|
+
variant: "default",
|
|
1417
|
+
size: "M",
|
|
1418
|
+
startIcon: /* @__PURE__ */ jsx(Check, {}),
|
|
1419
|
+
onClick: () => {
|
|
1420
|
+
onClose();
|
|
1421
|
+
onProceed();
|
|
1422
|
+
},
|
|
1423
|
+
disabled: loading || !previewData || previewData.summary.total === 0,
|
|
1424
|
+
children: [
|
|
1425
|
+
"Proceed to Execute (",
|
|
1426
|
+
previewData?.summary.willUpdate || 0,
|
|
1427
|
+
" updates)"
|
|
1428
|
+
]
|
|
1429
|
+
}
|
|
1430
|
+
)
|
|
1431
|
+
] })
|
|
1432
|
+
}
|
|
1433
|
+
)
|
|
1434
|
+
]
|
|
1435
|
+
}
|
|
1436
|
+
)
|
|
1437
|
+
}
|
|
1438
|
+
);
|
|
1439
|
+
};
|
|
1116
1440
|
function getNestedValue(obj, path) {
|
|
1117
1441
|
if (!obj || !path) return void 0;
|
|
1118
1442
|
if (!path.includes(".")) return obj[path];
|
|
@@ -1307,6 +1631,9 @@ const BulkUpdater = () => {
|
|
|
1307
1631
|
const [dashboardBatchId, setDashboardBatchId] = useState("");
|
|
1308
1632
|
const [dashboardJob, setDashboardJob] = useState(null);
|
|
1309
1633
|
const [isSubmittingBatch, setIsSubmittingBatch] = useState(false);
|
|
1634
|
+
const [showPreviewModal, setShowPreviewModal] = useState(false);
|
|
1635
|
+
const [previewLoading, setPreviewLoading] = useState(false);
|
|
1636
|
+
const [previewData, setPreviewData] = useState(null);
|
|
1310
1637
|
const MODELS_CACHE_KEY = "strapi_bulk_updater_models_cache";
|
|
1311
1638
|
const LAST_ATTR_KEY = "strapi_bulk_updater_last_attr";
|
|
1312
1639
|
const getInitialAttribute = () => {
|
|
@@ -1428,7 +1755,7 @@ const BulkUpdater = () => {
|
|
|
1428
1755
|
storedAttr = localStorage.getItem(LAST_ATTR_KEY);
|
|
1429
1756
|
} catch {
|
|
1430
1757
|
}
|
|
1431
|
-
const resolvedAttr = storedAttr && attrs.includes(storedAttr) ? storedAttr : attrs.includes(selectedAttribute) ? selectedAttribute :
|
|
1758
|
+
const resolvedAttr = storedAttr && attrs.includes(storedAttr) ? storedAttr : selectedAttribute && attrs.includes(selectedAttribute) ? selectedAttribute : "";
|
|
1432
1759
|
setSelectedAttribute(resolvedAttr);
|
|
1433
1760
|
if (resolvedAttr && data.relationsMeta && data.relationsMeta[resolvedAttr]) {
|
|
1434
1761
|
fetchRelationOptions(data.relationsMeta[resolvedAttr].targetUid);
|
|
@@ -1626,7 +1953,11 @@ const BulkUpdater = () => {
|
|
|
1626
1953
|
if (newAttr !== selectedAttribute) {
|
|
1627
1954
|
setSelectedAttribute(newAttr);
|
|
1628
1955
|
try {
|
|
1629
|
-
|
|
1956
|
+
if (newAttr) {
|
|
1957
|
+
localStorage.setItem(LAST_ATTR_KEY, newAttr);
|
|
1958
|
+
} else {
|
|
1959
|
+
localStorage.removeItem(LAST_ATTR_KEY);
|
|
1960
|
+
}
|
|
1630
1961
|
} catch {
|
|
1631
1962
|
}
|
|
1632
1963
|
setSelectedEntries({});
|
|
@@ -1635,17 +1966,19 @@ const BulkUpdater = () => {
|
|
|
1635
1966
|
setEntrySearch("");
|
|
1636
1967
|
setSelectedRelationDocId("");
|
|
1637
1968
|
setAttributeValue("");
|
|
1638
|
-
if (relationsMeta[newAttr]) {
|
|
1969
|
+
if (newAttr && relationsMeta[newAttr]) {
|
|
1639
1970
|
fetchRelationOptions(relationsMeta[newAttr].targetUid);
|
|
1640
1971
|
} else {
|
|
1641
1972
|
setRelationOptions([]);
|
|
1642
1973
|
}
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1974
|
+
if (newAttr) {
|
|
1975
|
+
const collectionsToLoad = collections.filter(
|
|
1976
|
+
(col) => visibleTypeUids[col.uid] !== false && col.attributes.includes(newAttr) && (!collectionPages[col.uid]?.entries || collectionPages[col.uid].entries.length === 0)
|
|
1977
|
+
);
|
|
1978
|
+
collectionsToLoad.forEach((col) => {
|
|
1979
|
+
loadCollectionPage(col.uid, 1);
|
|
1980
|
+
});
|
|
1981
|
+
}
|
|
1649
1982
|
}
|
|
1650
1983
|
};
|
|
1651
1984
|
const filteredCollections = collections.filter(
|
|
@@ -1682,8 +2015,30 @@ const BulkUpdater = () => {
|
|
|
1682
2015
|
});
|
|
1683
2016
|
setVisibleTypeUids(newVis);
|
|
1684
2017
|
};
|
|
2018
|
+
const [attributeSearch, setAttributeSearch] = useState("");
|
|
2019
|
+
const filteredAttributes = useMemo(() => {
|
|
2020
|
+
if (!attributeSearch.trim()) {
|
|
2021
|
+
return attributes;
|
|
2022
|
+
}
|
|
2023
|
+
const q = attributeSearch.toLowerCase().trim();
|
|
2024
|
+
const cleanQ = q.replace(/[^a-z0-9]/g, "");
|
|
2025
|
+
return attributes.filter((attr) => {
|
|
2026
|
+
const lower = attr.toLowerCase();
|
|
2027
|
+
const cleanLower = lower.replace(/[^a-z0-9]/g, "");
|
|
2028
|
+
const rel = relationsMeta[attr];
|
|
2029
|
+
const relTarget = (rel?.targetDisplayName || "").toLowerCase();
|
|
2030
|
+
return lower.includes(q) || cleanLower.includes(cleanQ) || relTarget.includes(q);
|
|
2031
|
+
});
|
|
2032
|
+
}, [attributes, attributeSearch, relationsMeta]);
|
|
1685
2033
|
const memoizedComboboxOptions = useMemo(() => {
|
|
1686
|
-
|
|
2034
|
+
if (filteredAttributes.length === 0) {
|
|
2035
|
+
return /* @__PURE__ */ jsx(ComboboxOption, { value: "__none__", disabled: true, textValue: "No matching attributes found", children: /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", children: [
|
|
2036
|
+
'No matching attributes found for "',
|
|
2037
|
+
attributeSearch,
|
|
2038
|
+
'"'
|
|
2039
|
+
] }) });
|
|
2040
|
+
}
|
|
2041
|
+
return filteredAttributes.map((attr) => {
|
|
1687
2042
|
const rel = relationsMeta[attr];
|
|
1688
2043
|
return /* @__PURE__ */ jsx(ComboboxOption, { value: attr, textValue: attr, children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", width: "100%", gap: 2, children: [
|
|
1689
2044
|
/* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: attr === selectedAttribute ? "bold" : "regular", children: attr }),
|
|
@@ -1693,7 +2048,7 @@ const BulkUpdater = () => {
|
|
|
1693
2048
|
] }) : attr.includes(".") ? /* @__PURE__ */ jsx(Badge, { backgroundColor: "neutral150", textColor: "neutral700", size: "S", children: "component" }) : null
|
|
1694
2049
|
] }) }, attr);
|
|
1695
2050
|
});
|
|
1696
|
-
}, [
|
|
2051
|
+
}, [filteredAttributes, relationsMeta, selectedAttribute, attributeSearch]);
|
|
1697
2052
|
const handleGlobalPageSizeChange = (newSize) => {
|
|
1698
2053
|
const capped = Math.min(500, Math.max(1, newSize));
|
|
1699
2054
|
setDefaultPageSize(capped);
|
|
@@ -1865,6 +2220,56 @@ const BulkUpdater = () => {
|
|
|
1865
2220
|
}
|
|
1866
2221
|
setShowConfirmModal(true);
|
|
1867
2222
|
};
|
|
2223
|
+
const handleOpenPreviewModal = async () => {
|
|
2224
|
+
if (!selectedAttribute) {
|
|
2225
|
+
toggleNotification({
|
|
2226
|
+
type: "warning",
|
|
2227
|
+
message: "Please select an attribute from the dropdown"
|
|
2228
|
+
});
|
|
2229
|
+
return;
|
|
2230
|
+
}
|
|
2231
|
+
const targets = [];
|
|
2232
|
+
Object.keys(selectedEntries).forEach((key) => {
|
|
2233
|
+
if (selectedEntries[key]) {
|
|
2234
|
+
const parts = key.split(KEY_SEP);
|
|
2235
|
+
if (parts.length === 2) {
|
|
2236
|
+
targets.push({ uid: parts[0], documentId: parts[1] });
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
});
|
|
2240
|
+
if (targets.length === 0) {
|
|
2241
|
+
toggleNotification({
|
|
2242
|
+
type: "warning",
|
|
2243
|
+
message: "Please select at least one collection type or entry to preview"
|
|
2244
|
+
});
|
|
2245
|
+
return;
|
|
2246
|
+
}
|
|
2247
|
+
setShowPreviewModal(true);
|
|
2248
|
+
setPreviewLoading(true);
|
|
2249
|
+
try {
|
|
2250
|
+
const res = await post("/bulk-updater/preview", {
|
|
2251
|
+
attribute: selectedAttribute,
|
|
2252
|
+
value: attributeValue,
|
|
2253
|
+
selectedEntries: targets,
|
|
2254
|
+
isRegex: useRegex,
|
|
2255
|
+
regexPattern,
|
|
2256
|
+
publishOnApproval
|
|
2257
|
+
});
|
|
2258
|
+
if (res.data && res.data.success) {
|
|
2259
|
+
setPreviewData(res.data);
|
|
2260
|
+
} else {
|
|
2261
|
+
throw new Error(res.data?.error || "Failed to generate preview");
|
|
2262
|
+
}
|
|
2263
|
+
} catch (err) {
|
|
2264
|
+
toggleNotification({
|
|
2265
|
+
type: "danger",
|
|
2266
|
+
message: err.message || "Failed to fetch preview diffs"
|
|
2267
|
+
});
|
|
2268
|
+
setShowPreviewModal(false);
|
|
2269
|
+
} finally {
|
|
2270
|
+
setPreviewLoading(false);
|
|
2271
|
+
}
|
|
2272
|
+
};
|
|
1868
2273
|
const executeBatchWithMode = async (executionMode, forceImmediate = false) => {
|
|
1869
2274
|
const targets = [];
|
|
1870
2275
|
Object.keys(selectedEntries).forEach((key) => {
|
|
@@ -2349,15 +2754,28 @@ const BulkUpdater = () => {
|
|
|
2349
2754
|
/* @__PURE__ */ jsx(
|
|
2350
2755
|
Combobox,
|
|
2351
2756
|
{
|
|
2352
|
-
autocomplete:
|
|
2757
|
+
autocomplete: "none",
|
|
2353
2758
|
placeholder: "Search attribute by name or relation...",
|
|
2354
|
-
value: selectedAttribute,
|
|
2355
|
-
|
|
2759
|
+
value: selectedAttribute || void 0,
|
|
2760
|
+
clearLabel: "Clear attribute selection",
|
|
2761
|
+
onClear: () => {
|
|
2762
|
+
handleAttributeChange("");
|
|
2763
|
+
setAttributeSearch("");
|
|
2764
|
+
},
|
|
2765
|
+
onInputChange: (e) => {
|
|
2766
|
+
setAttributeSearch(e.target.value);
|
|
2767
|
+
},
|
|
2768
|
+
onOpenChange: (isOpen) => {
|
|
2769
|
+
if (!isOpen) {
|
|
2770
|
+
setAttributeSearch("");
|
|
2771
|
+
}
|
|
2772
|
+
},
|
|
2356
2773
|
loading: loading && attributes.length === 0,
|
|
2357
2774
|
loadingMessage: "Discovering schema attributes...",
|
|
2358
2775
|
onChange: (val) => {
|
|
2359
|
-
if (val && typeof val === "string") {
|
|
2776
|
+
if (val && typeof val === "string" && val !== "__none__") {
|
|
2360
2777
|
handleAttributeChange(val);
|
|
2778
|
+
setAttributeSearch("");
|
|
2361
2779
|
}
|
|
2362
2780
|
},
|
|
2363
2781
|
children: memoizedComboboxOptions
|
|
@@ -2440,22 +2858,40 @@ const BulkUpdater = () => {
|
|
|
2440
2858
|
onChange: (e) => setAttributeValue(e.target.value)
|
|
2441
2859
|
}
|
|
2442
2860
|
) }),
|
|
2443
|
-
/* @__PURE__ */
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2861
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
|
|
2862
|
+
/* @__PURE__ */ jsxs(
|
|
2863
|
+
Button,
|
|
2864
|
+
{
|
|
2865
|
+
startIcon: /* @__PURE__ */ jsx(Eye, {}),
|
|
2866
|
+
variant: "secondary",
|
|
2867
|
+
size: "L",
|
|
2868
|
+
onClick: handleOpenPreviewModal,
|
|
2869
|
+
loading: previewLoading,
|
|
2870
|
+
disabled: loading || totalSelectedCount === 0 || !selectedAttribute,
|
|
2871
|
+
children: [
|
|
2872
|
+
"Preview Changes (",
|
|
2873
|
+
totalSelectedCount,
|
|
2874
|
+
")"
|
|
2875
|
+
]
|
|
2876
|
+
}
|
|
2877
|
+
),
|
|
2878
|
+
/* @__PURE__ */ jsxs(
|
|
2879
|
+
Button,
|
|
2880
|
+
{
|
|
2881
|
+
startIcon: /* @__PURE__ */ jsx(Play, {}),
|
|
2882
|
+
variant: "default",
|
|
2883
|
+
size: "L",
|
|
2884
|
+
onClick: handleOpenConfirmModal,
|
|
2885
|
+
loading: updating,
|
|
2886
|
+
disabled: loading || totalSelectedCount === 0 || !selectedAttribute,
|
|
2887
|
+
children: [
|
|
2888
|
+
"Update Selected (",
|
|
2889
|
+
totalSelectedCount,
|
|
2890
|
+
")"
|
|
2891
|
+
]
|
|
2892
|
+
}
|
|
2893
|
+
)
|
|
2894
|
+
] })
|
|
2459
2895
|
] }),
|
|
2460
2896
|
/* @__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: [
|
|
2461
2897
|
/* @__PURE__ */ jsx(Flex, { gap: 2, alignItems: "center", children: /* @__PURE__ */ jsx(
|
|
@@ -2602,7 +3038,7 @@ const BulkUpdater = () => {
|
|
|
2602
3038
|
/* @__PURE__ */ jsx(Box, { style: { width: 220, minWidth: 180 }, children: /* @__PURE__ */ jsxs(
|
|
2603
3039
|
SingleSelect,
|
|
2604
3040
|
{
|
|
2605
|
-
label: `Filter condition for "${selectedAttribute}"
|
|
3041
|
+
label: selectedAttribute ? `Filter condition for "${selectedAttribute}"` : "Filter condition",
|
|
2606
3042
|
value: filterOperator,
|
|
2607
3043
|
onChange: (val) => setFilterOperator(String(val)),
|
|
2608
3044
|
children: [
|
|
@@ -2618,7 +3054,7 @@ const BulkUpdater = () => {
|
|
|
2618
3054
|
(filterOperator === "equals" || filterOperator === "contains" || filterOperator === "starts_with") && /* @__PURE__ */ jsx(Box, { style: { flex: 1, minWidth: 200 }, children: /* @__PURE__ */ jsx(
|
|
2619
3055
|
TextInput,
|
|
2620
3056
|
{
|
|
2621
|
-
label: `Value for "${selectedAttribute}"
|
|
3057
|
+
label: selectedAttribute ? `Value for "${selectedAttribute}"` : "Value to match",
|
|
2622
3058
|
placeholder: "Type value to match...",
|
|
2623
3059
|
value: filterQuery,
|
|
2624
3060
|
onChange: (e) => setFilterQuery(e.target.value)
|
|
@@ -2746,7 +3182,7 @@ const BulkUpdater = () => {
|
|
|
2746
3182
|
(col) => !typeVisibilitySearch.trim() || col.displayName.toLowerCase().includes(typeVisibilitySearch.toLowerCase().trim()) || col.uid.toLowerCase().includes(typeVisibilitySearch.toLowerCase().trim())
|
|
2747
3183
|
).map((col) => {
|
|
2748
3184
|
const isVisible = visibleTypeUids[col.uid] !== false;
|
|
2749
|
-
const hasAttr = col.attributes.includes(selectedAttribute);
|
|
3185
|
+
const hasAttr = selectedAttribute ? col.attributes.includes(selectedAttribute) : false;
|
|
2750
3186
|
return /* @__PURE__ */ jsx(
|
|
2751
3187
|
Box,
|
|
2752
3188
|
{
|
|
@@ -2820,9 +3256,9 @@ const BulkUpdater = () => {
|
|
|
2820
3256
|
const page = pageState ? pageState.page : 1;
|
|
2821
3257
|
const pageCount = pageState ? pageState.pageCount : 1;
|
|
2822
3258
|
const pageSize = pageState ? pageState.pageSize : defaultPageSize;
|
|
2823
|
-
const hasAttr = col.attributes.includes(selectedAttribute);
|
|
3259
|
+
const hasAttr = selectedAttribute ? col.attributes.includes(selectedAttribute) : false;
|
|
2824
3260
|
const visibleEntries = getVisibleEntries(col);
|
|
2825
|
-
entries.filter((e) => entryMatchesFilter(e, selectedAttribute)).length;
|
|
3261
|
+
selectedAttribute ? entries.filter((e) => entryMatchesFilter(e, selectedAttribute)).length : 0;
|
|
2826
3262
|
const isFullySelected = isCollectionFullySelected(col);
|
|
2827
3263
|
const isPartiallySelected = isCollectionPartiallySelected(col);
|
|
2828
3264
|
const currentSort = collectionSorts[col.uid] || { field: "createdAt", order: "desc" };
|
|
@@ -2856,14 +3292,14 @@ const BulkUpdater = () => {
|
|
|
2856
3292
|
] })
|
|
2857
3293
|
}
|
|
2858
3294
|
),
|
|
2859
|
-
col.isSingleType ? /* @__PURE__ */ jsx(Badge, { backgroundColor: "secondary100", textColor: "secondary700", children: "Single Type" }) : /* @__PURE__ */ jsx(
|
|
3295
|
+
col.isSingleType ? /* @__PURE__ */ jsx(Badge, { backgroundColor: "secondary100", textColor: "secondary700", children: "Single Type" }) : selectedAttribute ? /* @__PURE__ */ jsx(
|
|
2860
3296
|
Badge,
|
|
2861
3297
|
{
|
|
2862
3298
|
backgroundColor: hasAttr ? "success100" : "warning100",
|
|
2863
3299
|
textColor: hasAttr ? "success700" : "warning700",
|
|
2864
3300
|
children: hasAttr ? `Schema has "${selectedAttribute}"` : `Schema lacks "${selectedAttribute}" (will skip)`
|
|
2865
3301
|
}
|
|
2866
|
-
)
|
|
3302
|
+
) : null
|
|
2867
3303
|
] }),
|
|
2868
3304
|
/* @__PURE__ */ jsxs(Flex, { gap: 3, alignItems: "center", wrap: "wrap", children: [
|
|
2869
3305
|
!col.isSingleType && /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
|
|
@@ -3632,6 +4068,22 @@ const BulkUpdater = () => {
|
|
|
3632
4068
|
children: publishOnApproval ? "Publish Immediately" : "Keep as Draft"
|
|
3633
4069
|
}
|
|
3634
4070
|
)
|
|
4071
|
+
] }),
|
|
4072
|
+
/* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", marginTop: 2, paddingTop: 2, style: { borderTop: "1px solid #eaeaef" }, children: [
|
|
4073
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Need to inspect before & after values?" }),
|
|
4074
|
+
/* @__PURE__ */ jsx(
|
|
4075
|
+
Button,
|
|
4076
|
+
{
|
|
4077
|
+
variant: "secondary",
|
|
4078
|
+
size: "S",
|
|
4079
|
+
startIcon: /* @__PURE__ */ jsx(Eye, {}),
|
|
4080
|
+
onClick: () => {
|
|
4081
|
+
setShowConfirmModal(false);
|
|
4082
|
+
handleOpenPreviewModal();
|
|
4083
|
+
},
|
|
4084
|
+
children: "Open Change Preview"
|
|
4085
|
+
}
|
|
4086
|
+
)
|
|
3635
4087
|
] })
|
|
3636
4088
|
] })
|
|
3637
4089
|
] }),
|
|
@@ -3768,6 +4220,21 @@ const BulkUpdater = () => {
|
|
|
3768
4220
|
)
|
|
3769
4221
|
}
|
|
3770
4222
|
),
|
|
4223
|
+
/* @__PURE__ */ jsx(
|
|
4224
|
+
BulkUpdatePreviewModal,
|
|
4225
|
+
{
|
|
4226
|
+
isOpen: showPreviewModal,
|
|
4227
|
+
onClose: () => setShowPreviewModal(false),
|
|
4228
|
+
onProceed: () => {
|
|
4229
|
+
setShowPreviewModal(false);
|
|
4230
|
+
handleOpenConfirmModal();
|
|
4231
|
+
},
|
|
4232
|
+
loading: previewLoading,
|
|
4233
|
+
previewData,
|
|
4234
|
+
attribute: selectedAttribute,
|
|
4235
|
+
targetValueDisplay: relationsMeta[selectedAttribute] ? selectedRelationDocId === "__clear__" ? "Clear / Unlink Relation" : relationOptions.find((o) => o.documentId === selectedRelationDocId)?.label || selectedRelationDocId || "(none)" : useRegex ? `Replace /${regexPattern}/g with "${attributeValue}"` : attributeValue
|
|
4236
|
+
}
|
|
4237
|
+
),
|
|
3771
4238
|
/* @__PURE__ */ jsx(
|
|
3772
4239
|
ProcessingDashboardModal,
|
|
3773
4240
|
{
|
|
@@ -3788,4 +4255,4 @@ export {
|
|
|
3788
4255
|
getAvailableColumnsForCollection,
|
|
3789
4256
|
getNestedValue
|
|
3790
4257
|
};
|
|
3791
|
-
//# sourceMappingURL=BulkUpdater-
|
|
4258
|
+
//# sourceMappingURL=BulkUpdater-Cg9utqzm.mjs.map
|