strapi-plugin-bulk-updater 1.5.9 → 1.5.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.
@@ -1,7 +1,7 @@
1
1
  import { jsxs, jsx, 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
- import { Box, Flex, Typography, Button, Combobox, ComboboxOption, SingleSelect, SingleSelectOption, Badge, Checkbox, Alert, Table, Thead, Tr, Th, Tbody, Td, TextInput, Loader, Field } from "@strapi/design-system";
4
+ import { Box, Flex, Typography, Button, Combobox, ComboboxOption, TextInput, SingleSelect, SingleSelectOption, Badge, Checkbox, Alert, Table, Thead, Tr, Th, Tbody, Td, Loader, Field } from "@strapi/design-system";
5
5
  import { ArrowClockwise, Download, Upload, ChevronLeft, ChevronRight, Eye, Check, Cog, Play } from "@strapi/icons";
6
6
  import { i as isAbortError, V as ValidationRulesTab } from "./ValidationRulesTab-BtOCWK8E.mjs";
7
7
  function parseCsvRows(csvText) {
@@ -230,6 +230,10 @@ function CsvManagerTab() {
230
230
  const [collectionEntries, setCollectionEntries] = useState([]);
231
231
  const [pendingBatches, setPendingBatches] = useState([]);
232
232
  const [exportLimit, setExportLimit] = useState(0);
233
+ const [exportLimitInput, setExportLimitInput] = useState("");
234
+ const [exportingCollection, setExportingCollection] = useState(false);
235
+ const [downloadingTemplate, setDownloadingTemplate] = useState(false);
236
+ const [exportingViolations, setExportingViolations] = useState(false);
233
237
  const [exportOnlyViolations, setExportOnlyViolations] = useState(false);
234
238
  const [rules, setRules] = useState([]);
235
239
  const [selectedRuleId, setSelectedRuleId] = useState("");
@@ -275,7 +279,6 @@ function CsvManagerTab() {
275
279
  if (loadedCollections.length > 0) {
276
280
  const firstUid = loadedCollections[0].uid;
277
281
  setSelectedUid(firstUid);
278
- fetchAndEnrichEntries(firstUid, loadedCollections, batchesRes.data?.batches || []);
279
282
  }
280
283
  }
281
284
  if (rulesRes.data?.rules) {
@@ -350,14 +353,10 @@ function CsvManagerTab() {
350
353
  return row;
351
354
  });
352
355
  };
353
- useEffect(() => {
354
- if (selectedUid) {
355
- fetchAndEnrichEntries(selectedUid);
356
- }
357
- }, [selectedUid]);
358
356
  const handleDownloadTemplate = async () => {
359
- if (!selectedUid) return;
357
+ if (!selectedUid || downloadingTemplate) return;
360
358
  try {
359
+ setDownloadingTemplate(true);
361
360
  const res = await get(`/bulk-updater/csv/template/${selectedUid}`);
362
361
  const csvStr = res.data?.csvContent || (typeof res.data === "string" ? res.data : "");
363
362
  const filename = res.data?.filename || `${selectedUid.split(".").pop()}_template.csv`;
@@ -372,12 +371,14 @@ function CsvManagerTab() {
372
371
  type: "danger",
373
372
  message: err.message || "Failed downloading CSV template"
374
373
  });
374
+ } finally {
375
+ setDownloadingTemplate(false);
375
376
  }
376
377
  };
377
378
  const handleExportCollection = async () => {
378
- if (!selectedUid) return;
379
+ if (!selectedUid || exportingCollection) return;
379
380
  try {
380
- await fetchAndEnrichEntries(selectedUid);
381
+ setExportingCollection(true);
381
382
  const res = await get(`/bulk-updater/csv/export/${selectedUid}?limit=${exportLimit}`);
382
383
  const csvStr = res.data?.csvContent || (typeof res.data === "string" ? res.data : "");
383
384
  const filename = res.data?.filename || `${selectedUid.split(".").pop()}_export.csv`;
@@ -392,11 +393,14 @@ function CsvManagerTab() {
392
393
  type: "danger",
393
394
  message: err.message || "Failed exporting collection to CSV"
394
395
  });
396
+ } finally {
397
+ setExportingCollection(false);
395
398
  }
396
399
  };
397
400
  const handleExportViolations = async () => {
398
- if (!selectedRuleId) return;
401
+ if (!selectedRuleId || exportingViolations) return;
399
402
  try {
403
+ setExportingViolations(true);
400
404
  const res = await get(`/bulk-updater/csv/export-violations/${selectedRuleId}`);
401
405
  const csvStr = res.data?.csvContent || (typeof res.data === "string" ? res.data : "");
402
406
  const filename = res.data?.filename || `violations_${selectedRuleId}.csv`;
@@ -411,6 +415,8 @@ function CsvManagerTab() {
411
415
  type: "danger",
412
416
  message: err.message || "Failed exporting violations to CSV"
413
417
  });
418
+ } finally {
419
+ setExportingViolations(false);
414
420
  }
415
421
  };
416
422
  const downloadCsvFile = (content, fallbackName) => {
@@ -691,7 +697,8 @@ function CsvManagerTab() {
691
697
  variant: "tertiary",
692
698
  startIcon: /* @__PURE__ */ jsx(Download, {}),
693
699
  onClick: handleDownloadTemplate,
694
- disabled: !selectedUid,
700
+ disabled: !selectedUid || downloadingTemplate,
701
+ loading: downloadingTemplate,
695
702
  children: "Download Sample CSV Template"
696
703
  }
697
704
  )
@@ -699,35 +706,61 @@ function CsvManagerTab() {
699
706
  /* @__PURE__ */ jsxs(Box, { padding: 5, background: "neutral100", hasRadius: true, children: [
700
707
  /* @__PURE__ */ jsx(Typography, { variant: "delta", tag: "h3", fontWeight: "bold", marginBottom: 2, children: "1. Export Data to CSV" }),
701
708
  /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", marginBottom: 4, children: "Extract entire collections without artificial limits (streams 10,000+ records in paged chunks) or pinpoint records violating validation quotas." }),
702
- /* @__PURE__ */ jsxs(Flex, { gap: 4, wrap: "wrap", alignItems: "center", marginTop: 3, children: [
703
- /* @__PURE__ */ jsx(Box, { style: { width: 220 }, children: /* @__PURE__ */ jsxs(
704
- SingleSelect,
705
- {
706
- value: String(exportLimit),
707
- onChange: (val) => setExportLimit(Number(val)),
708
- placeholder: "Export Limit",
709
- children: [
710
- /* @__PURE__ */ jsx(SingleSelectOption, { value: "0", children: "All Records (No Limit)" }),
711
- /* @__PURE__ */ jsx(SingleSelectOption, { value: "10000", children: "Up to 10,000 Records" }),
712
- /* @__PURE__ */ jsx(SingleSelectOption, { value: "5000", children: "Up to 5,000 Records" }),
713
- /* @__PURE__ */ jsx(SingleSelectOption, { value: "1000", children: "Up to 1,000 Records" })
714
- ]
715
- }
716
- ) }),
717
- /* @__PURE__ */ jsxs(
709
+ /* @__PURE__ */ jsxs(Flex, { gap: 4, wrap: "wrap", alignItems: "flex-end", marginTop: 3, children: [
710
+ /* @__PURE__ */ jsxs(Box, { style: { width: 220 }, children: [
711
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", marginBottom: 1, display: "block", children: "Records to Download" }),
712
+ /* @__PURE__ */ jsx(
713
+ TextInput,
714
+ {
715
+ type: "number",
716
+ min: 0,
717
+ placeholder: "All records (or enter count)",
718
+ value: exportLimitInput,
719
+ onChange: (e) => {
720
+ const raw = e.target.value;
721
+ setExportLimitInput(raw);
722
+ const parsed = parseInt(raw, 10);
723
+ setExportLimit(!raw || isNaN(parsed) || parsed <= 0 ? 0 : parsed);
724
+ },
725
+ hint: exportLimit === 0 ? "Exporting all records (no limit)" : `Exporting first ${exportLimit.toLocaleString()} records`
726
+ }
727
+ )
728
+ ] }),
729
+ /* @__PURE__ */ jsxs(Box, { children: [
730
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", marginBottom: 1, display: "block", children: "Quick Presets:" }),
731
+ /* @__PURE__ */ jsx(Flex, { gap: 1, wrap: "wrap", children: [
732
+ { label: "All", value: 0 },
733
+ { label: "100", value: 100 },
734
+ { label: "500", value: 500 },
735
+ { label: "1,000", value: 1e3 },
736
+ { label: "5,000", value: 5e3 },
737
+ { label: "10,000", value: 1e4 }
738
+ ].map((preset) => {
739
+ const isSelected = preset.value === 0 ? exportLimit === 0 && (!exportLimitInput || exportLimitInput === "0") : exportLimit === preset.value && exportLimitInput === String(preset.value);
740
+ return /* @__PURE__ */ jsx(
741
+ Button,
742
+ {
743
+ variant: isSelected ? "secondary" : "tertiary",
744
+ size: "S",
745
+ onClick: () => {
746
+ setExportLimit(preset.value);
747
+ setExportLimitInput(preset.value === 0 ? "" : String(preset.value));
748
+ },
749
+ children: preset.label
750
+ },
751
+ preset.value
752
+ );
753
+ }) })
754
+ ] }),
755
+ /* @__PURE__ */ jsx(
718
756
  Button,
719
757
  {
720
758
  variant: "default",
721
759
  startIcon: /* @__PURE__ */ jsx(Download, {}),
722
760
  onClick: handleExportCollection,
723
- disabled: !selectedUid,
724
- children: [
725
- "Export ",
726
- exportLimit === 0 ? "All" : `${exportLimit}`,
727
- " ",
728
- selectedCol?.displayName || "Collection",
729
- " Records (.csv)"
730
- ]
761
+ disabled: !selectedUid || exportingCollection,
762
+ loading: exportingCollection,
763
+ children: exportingCollection ? "Preparing CSV download..." : `Export ${exportLimit === 0 ? "All" : exportLimit.toLocaleString()} ${selectedCol?.displayName || "Collection"} Records (.csv)`
731
764
  }
732
765
  ),
733
766
  rules.length > 0 && /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", style: { marginLeft: "auto" }, children: [
@@ -749,7 +782,8 @@ function CsvManagerTab() {
749
782
  variant: "danger-light",
750
783
  startIcon: /* @__PURE__ */ jsx(Download, {}),
751
784
  onClick: handleExportViolations,
752
- disabled: !selectedRuleId,
785
+ disabled: !selectedRuleId || exportingViolations,
786
+ loading: exportingViolations,
753
787
  children: "Export Violators CSV"
754
788
  }
755
789
  )
@@ -7621,4 +7655,4 @@ export {
7621
7655
  getSortOptionsForCollection,
7622
7656
  parseDynamicZonePath
7623
7657
  };
7624
- //# sourceMappingURL=BulkUpdater-RWXTJOa6.mjs.map
7658
+ //# sourceMappingURL=BulkUpdater-7rkObCic.mjs.map