strapi-plugin-bulk-updater 1.5.7 → 1.5.9

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.
@@ -136,12 +136,99 @@ function extractDocId(row) {
136
136
  }
137
137
  return "";
138
138
  }
139
+ function getEntryLifecycleStatus(entry, col, pendingBatches = []) {
140
+ const isPendingApproval = pendingBatches.some((b) => {
141
+ if (b.status !== "pending_approval") return false;
142
+ const targets = b.payload?.selectedEntries || [];
143
+ return targets.some((t) => entry.documentId && t.documentId === entry.documentId || String(t.documentId) === String(entry.id));
144
+ });
145
+ if (isPendingApproval) {
146
+ return {
147
+ status: "pending_review",
148
+ label: "Pending Review",
149
+ badgeColor: "warning100",
150
+ textColor: "warning700"
151
+ };
152
+ }
153
+ if (col && col.draftAndPublish === false) {
154
+ return {
155
+ status: "published",
156
+ label: "Published",
157
+ badgeColor: "success100",
158
+ textColor: "success700"
159
+ };
160
+ }
161
+ if (entry.status === "modified") {
162
+ return {
163
+ status: "modified",
164
+ label: "Modified",
165
+ badgeColor: "primary100",
166
+ textColor: "primary700"
167
+ };
168
+ }
169
+ if (entry.status === "draft") {
170
+ return {
171
+ status: "draft",
172
+ label: "Draft",
173
+ badgeColor: "neutral150",
174
+ textColor: "neutral700"
175
+ };
176
+ }
177
+ if (entry.status === "published") {
178
+ return {
179
+ status: "published",
180
+ label: "Published",
181
+ badgeColor: "success100",
182
+ textColor: "success700"
183
+ };
184
+ }
185
+ if (entry.status === "unknown") {
186
+ return {
187
+ status: "unknown",
188
+ label: "Unknown",
189
+ badgeColor: "neutral200",
190
+ textColor: "neutral600"
191
+ };
192
+ }
193
+ if (!entry.documentId && !entry.id && !entry.slug) {
194
+ return {
195
+ status: "unknown",
196
+ label: "Unknown",
197
+ badgeColor: "neutral200",
198
+ textColor: "neutral600"
199
+ };
200
+ }
201
+ if (entry.publishedAt) {
202
+ if (entry.updatedAt && new Date(entry.updatedAt).getTime() > new Date(entry.publishedAt).getTime()) {
203
+ return {
204
+ status: "modified",
205
+ label: "Modified",
206
+ badgeColor: "primary100",
207
+ textColor: "primary700"
208
+ };
209
+ }
210
+ return {
211
+ status: "published",
212
+ label: "Published",
213
+ badgeColor: "success100",
214
+ textColor: "success700"
215
+ };
216
+ }
217
+ return {
218
+ status: "draft",
219
+ label: "Draft",
220
+ badgeColor: "neutral150",
221
+ textColor: "neutral700"
222
+ };
223
+ }
139
224
  function CsvManagerTab() {
140
225
  const { get, post } = useFetchClient();
141
226
  const { toggleNotification } = useNotification();
142
227
  const [collections, setCollections] = useState([]);
143
228
  const [loadingCollections, setLoadingCollections] = useState(true);
144
229
  const [selectedUid, setSelectedUid] = useState("");
230
+ const [collectionEntries, setCollectionEntries] = useState([]);
231
+ const [pendingBatches, setPendingBatches] = useState([]);
145
232
  const [exportLimit, setExportLimit] = useState(0);
146
233
  const [exportOnlyViolations, setExportOnlyViolations] = useState(false);
147
234
  const [rules, setRules] = useState([]);
@@ -170,17 +257,25 @@ function CsvManagerTab() {
170
257
  const fetchInitialData = async () => {
171
258
  try {
172
259
  setLoadingCollections(true);
173
- const [modelsRes, rulesRes] = await Promise.all([
260
+ const [modelsRes, rulesRes, batchesRes] = await Promise.all([
174
261
  get("/bulk-updater/models"),
175
- get("/bulk-updater/validation-rules")
262
+ get("/bulk-updater/validation-rules"),
263
+ get("/bulk-updater/pending-batches").catch(() => ({ data: { batches: [] } }))
176
264
  ]);
177
265
  if (modelsRes.data?.executionWindow) {
178
266
  setExecutionWindow(modelsRes.data.executionWindow);
179
267
  }
268
+ if (batchesRes.data?.batches) {
269
+ setPendingBatches(batchesRes.data.batches);
270
+ }
271
+ let loadedCollections = [];
180
272
  if (modelsRes.data?.collections) {
181
- setCollections(modelsRes.data.collections);
182
- if (modelsRes.data.collections.length > 0) {
183
- setSelectedUid(modelsRes.data.collections[0].uid);
273
+ loadedCollections = modelsRes.data.collections;
274
+ setCollections(loadedCollections);
275
+ if (loadedCollections.length > 0) {
276
+ const firstUid = loadedCollections[0].uid;
277
+ setSelectedUid(firstUid);
278
+ fetchAndEnrichEntries(firstUid, loadedCollections, batchesRes.data?.batches || []);
184
279
  }
185
280
  }
186
281
  if (rulesRes.data?.rules) {
@@ -199,6 +294,67 @@ function CsvManagerTab() {
199
294
  setLoadingCollections(false);
200
295
  }
201
296
  };
297
+ const fetchAndEnrichEntries = async (colUid, cols = collections, batches = pendingBatches) => {
298
+ if (!colUid) return [];
299
+ try {
300
+ const res = await get(`/bulk-updater/collections/${colUid}/entries?page=1&pageSize=500`);
301
+ if (res.data && (res.data.success || res.data.entries !== void 0)) {
302
+ const fetchedEntries = res.data.entries || [];
303
+ const col = (cols || []).find((c) => c.uid === colUid) || null;
304
+ const enrichedEntries = fetchedEntries.map((entry) => {
305
+ if (!entry.status) {
306
+ const lifecycle = getEntryLifecycleStatus(entry, col, batches);
307
+ return {
308
+ ...entry,
309
+ status: lifecycle.status,
310
+ publishedAt: entry.publishedAt ?? (lifecycle.status === "published" ? entry.updatedAt || null : null)
311
+ };
312
+ }
313
+ return entry;
314
+ });
315
+ setCollectionEntries(enrichedEntries);
316
+ return enrichedEntries;
317
+ }
318
+ } catch (err) {
319
+ if (isAbortError(err)) return [];
320
+ }
321
+ return [];
322
+ };
323
+ const enrichCsvRowsWithLifecycle = (rows, knownEntries = collectionEntries) => {
324
+ if (!rows || rows.length === 0) return rows;
325
+ const entryByDocId = /* @__PURE__ */ new Map();
326
+ for (const e of knownEntries) {
327
+ if (e.documentId) entryByDocId.set(String(e.documentId), e);
328
+ if (e.id) entryByDocId.set(String(e.id), e);
329
+ }
330
+ return rows.map((row) => {
331
+ const docId = extractDocId(row);
332
+ const matched = docId ? entryByDocId.get(docId) : void 0;
333
+ const existingStatus = row.status || row.Status;
334
+ const existingPubAt = row.publishedAt || row.published_at;
335
+ let status = existingStatus;
336
+ let publishedAt = existingPubAt;
337
+ if (!status && matched?.status) {
338
+ status = matched.status;
339
+ }
340
+ if (!publishedAt && matched?.publishedAt) {
341
+ publishedAt = matched.publishedAt;
342
+ }
343
+ if (status || publishedAt) {
344
+ return {
345
+ ...row,
346
+ ...status ? { status } : {},
347
+ ...publishedAt ? { publishedAt } : {}
348
+ };
349
+ }
350
+ return row;
351
+ });
352
+ };
353
+ useEffect(() => {
354
+ if (selectedUid) {
355
+ fetchAndEnrichEntries(selectedUid);
356
+ }
357
+ }, [selectedUid]);
202
358
  const handleDownloadTemplate = async () => {
203
359
  if (!selectedUid) return;
204
360
  try {
@@ -221,6 +377,7 @@ function CsvManagerTab() {
221
377
  const handleExportCollection = async () => {
222
378
  if (!selectedUid) return;
223
379
  try {
380
+ await fetchAndEnrichEntries(selectedUid);
224
381
  const res = await get(`/bulk-updater/csv/export/${selectedUid}?limit=${exportLimit}`);
225
382
  const csvStr = res.data?.csvContent || (typeof res.data === "string" ? res.data : "");
226
383
  const filename = res.data?.filename || `${selectedUid.split(".").pop()}_export.csv`;
@@ -287,7 +444,8 @@ function CsvManagerTab() {
287
444
  setCsvRawText(text);
288
445
  try {
289
446
  const records = parseCsv(text);
290
- setAllParsedRecords(records);
447
+ const enriched = enrichCsvRowsWithLifecycle(records, collectionEntries);
448
+ setAllParsedRecords(enriched);
291
449
  setPreviewPage(1);
292
450
  } catch (err) {
293
451
  setAllParsedRecords([]);
@@ -297,7 +455,12 @@ function CsvManagerTab() {
297
455
  };
298
456
  const handleExecuteImport = async () => {
299
457
  if (!selectedUid || allParsedRecords.length === 0) return;
300
- const totalRows = allParsedRecords.length;
458
+ let currentEntries = collectionEntries;
459
+ if (currentEntries.length === 0) {
460
+ currentEntries = await fetchAndEnrichEntries(selectedUid);
461
+ }
462
+ const enrichedRecords = enrichCsvRowsWithLifecycle(allParsedRecords, currentEntries);
463
+ const totalRows = enrichedRecords.length;
301
464
  const CHUNK_SIZE = 100;
302
465
  const totalChunks = Math.ceil(totalRows / CHUNK_SIZE);
303
466
  const batchId = `csv_batch_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;
@@ -323,7 +486,7 @@ function CsvManagerTab() {
323
486
  for (let chunkIdx = 0; chunkIdx < totalChunks; chunkIdx++) {
324
487
  const startIdx = chunkIdx * CHUNK_SIZE;
325
488
  const endIdx = Math.min(startIdx + CHUNK_SIZE, totalRows);
326
- const chunkRows = allParsedRecords.slice(startIdx, endIdx);
489
+ const chunkRows = enrichedRecords.slice(startIdx, endIdx);
327
490
  const isFirst = chunkIdx === 0;
328
491
  const isLast = chunkIdx === totalChunks - 1;
329
492
  const startRowNumber = startIdx + 2;
@@ -391,9 +554,14 @@ function CsvManagerTab() {
391
554
  if (!selectedUid || allParsedRecords.length === 0) return;
392
555
  try {
393
556
  setPreflightLoading(true);
557
+ let currentEntries = collectionEntries;
558
+ if (currentEntries.length === 0) {
559
+ currentEntries = await fetchAndEnrichEntries(selectedUid);
560
+ }
561
+ const enrichedRecords = enrichCsvRowsWithLifecycle(allParsedRecords, currentEntries);
394
562
  const res = await post("/bulk-updater/csv/validate-preflight", {
395
563
  uid: selectedUid,
396
- rows: allParsedRecords,
564
+ rows: enrichedRecords,
397
565
  mode: importMode
398
566
  });
399
567
  if (res.data && res.data.success) {
@@ -434,9 +602,14 @@ function CsvManagerTab() {
434
602
  }
435
603
  try {
436
604
  setSubmittingBatch(true);
605
+ let currentEntries = collectionEntries;
606
+ if (currentEntries.length === 0) {
607
+ currentEntries = await fetchAndEnrichEntries(selectedUid);
608
+ }
609
+ const enrichedRecords = enrichCsvRowsWithLifecycle(allParsedRecords, currentEntries);
437
610
  const res = await post("/bulk-updater/csv/submit-batch", {
438
611
  uid: selectedUid,
439
- rows: allParsedRecords,
612
+ rows: enrichedRecords,
440
613
  executionMode,
441
614
  makerNotes: makerNotesInput,
442
615
  forceImmediate,
@@ -2853,91 +3026,6 @@ const CheckerReviewModal = ({
2853
3026
  }
2854
3027
  );
2855
3028
  };
2856
- function getEntryLifecycleStatus(entry, col, pendingBatches = []) {
2857
- const isPendingApproval = pendingBatches.some((b) => {
2858
- if (b.status !== "pending_approval") return false;
2859
- const targets = b.payload?.selectedEntries || [];
2860
- return targets.some((t) => entry.documentId && t.documentId === entry.documentId || String(t.documentId) === String(entry.id));
2861
- });
2862
- if (isPendingApproval) {
2863
- return {
2864
- status: "pending_review",
2865
- label: "Pending Review",
2866
- badgeColor: "warning100",
2867
- textColor: "warning700"
2868
- };
2869
- }
2870
- if (col && col.draftAndPublish === false) {
2871
- return {
2872
- status: "published",
2873
- label: "Published",
2874
- badgeColor: "success100",
2875
- textColor: "success700"
2876
- };
2877
- }
2878
- if (entry.status === "modified") {
2879
- return {
2880
- status: "modified",
2881
- label: "Modified",
2882
- badgeColor: "primary100",
2883
- textColor: "primary700"
2884
- };
2885
- }
2886
- if (entry.status === "draft") {
2887
- return {
2888
- status: "draft",
2889
- label: "Draft",
2890
- badgeColor: "neutral150",
2891
- textColor: "neutral700"
2892
- };
2893
- }
2894
- if (entry.status === "published") {
2895
- return {
2896
- status: "published",
2897
- label: "Published",
2898
- badgeColor: "success100",
2899
- textColor: "success700"
2900
- };
2901
- }
2902
- if (entry.status === "unknown") {
2903
- return {
2904
- status: "unknown",
2905
- label: "Unknown",
2906
- badgeColor: "neutral200",
2907
- textColor: "neutral600"
2908
- };
2909
- }
2910
- if (!entry.documentId && !entry.id && !entry.slug) {
2911
- return {
2912
- status: "unknown",
2913
- label: "Unknown",
2914
- badgeColor: "neutral200",
2915
- textColor: "neutral600"
2916
- };
2917
- }
2918
- if (entry.publishedAt) {
2919
- if (entry.updatedAt && new Date(entry.updatedAt).getTime() > new Date(entry.publishedAt).getTime()) {
2920
- return {
2921
- status: "modified",
2922
- label: "Modified",
2923
- badgeColor: "primary100",
2924
- textColor: "primary700"
2925
- };
2926
- }
2927
- return {
2928
- status: "published",
2929
- label: "Published",
2930
- badgeColor: "success100",
2931
- textColor: "success700"
2932
- };
2933
- }
2934
- return {
2935
- status: "draft",
2936
- label: "Draft",
2937
- badgeColor: "neutral150",
2938
- textColor: "neutral700"
2939
- };
2940
- }
2941
3029
  function parseDynamicZonePath(path) {
2942
3030
  if (!path) return { cleanPath: "", rootKey: "", subPath: "" };
2943
3031
  const bracketMatch = path.match(/^([^.[]+)\[([^\]]+)\]\.(.+)$/);
@@ -4461,8 +4549,8 @@ const BulkUpdater = () => {
4461
4549
  const cachedEntry = colPage?.entries?.find((e) => e.documentId === docId);
4462
4550
  if (cachedEntry) {
4463
4551
  if (cachedEntry.status) targetObj.status = cachedEntry.status;
4464
- if (cachedEntry.strapi_stage) targetObj.strapi_stage = cachedEntry.strapi_stage;
4465
4552
  if (cachedEntry.publishedAt) targetObj.publishedAt = cachedEntry.publishedAt;
4553
+ if (cachedEntry.locale) targetObj.locale = cachedEntry.locale;
4466
4554
  }
4467
4555
  targets.push(targetObj);
4468
4556
  }
@@ -4519,8 +4607,8 @@ const BulkUpdater = () => {
4519
4607
  const cachedEntry = colPage?.entries?.find((e) => e.documentId === docId);
4520
4608
  if (cachedEntry) {
4521
4609
  if (cachedEntry.status) targetObj.status = cachedEntry.status;
4522
- if (cachedEntry.strapi_stage) targetObj.strapi_stage = cachedEntry.strapi_stage;
4523
4610
  if (cachedEntry.publishedAt) targetObj.publishedAt = cachedEntry.publishedAt;
4611
+ if (cachedEntry.locale) targetObj.locale = cachedEntry.locale;
4524
4612
  }
4525
4613
  targets.push(targetObj);
4526
4614
  }
@@ -7533,4 +7621,4 @@ export {
7533
7621
  getSortOptionsForCollection,
7534
7622
  parseDynamicZonePath
7535
7623
  };
7536
- //# sourceMappingURL=BulkUpdater-Ci_Uojtf.mjs.map
7624
+ //# sourceMappingURL=BulkUpdater-RWXTJOa6.mjs.map