strapi-plugin-bulk-updater 1.5.0 → 1.5.3

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.
@@ -2853,6 +2853,91 @@ const CheckerReviewModal = ({
2853
2853
  }
2854
2854
  );
2855
2855
  };
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
+ }
2856
2941
  function parseDynamicZonePath(path) {
2857
2942
  if (!path) return { cleanPath: "", rootKey: "", subPath: "" };
2858
2943
  const bracketMatch = path.match(/^([^.[]+)\[([^\]]+)\]\.(.+)$/);
@@ -3265,67 +3350,6 @@ function formatDisplayValue(val) {
3265
3350
  }
3266
3351
  return String(val);
3267
3352
  }
3268
- function getEntryLifecycleStatus(entry, col, pendingBatches = []) {
3269
- const isPendingApproval = pendingBatches.some((b) => {
3270
- if (b.status !== "pending_approval") return false;
3271
- const targets = b.payload?.selectedEntries || [];
3272
- return targets.some((t) => t.documentId === entry.documentId || String(t.documentId) === String(entry.id));
3273
- });
3274
- if (isPendingApproval) {
3275
- return {
3276
- status: "pending_review",
3277
- label: "Pending Review",
3278
- badgeColor: "warning100",
3279
- textColor: "warning700"
3280
- };
3281
- }
3282
- if (entry.status === "modified") {
3283
- return {
3284
- status: "modified",
3285
- label: "Modified",
3286
- badgeColor: "primary100",
3287
- textColor: "primary700"
3288
- };
3289
- }
3290
- if (entry.status === "draft") {
3291
- return {
3292
- status: "draft",
3293
- label: "Draft",
3294
- badgeColor: "neutral150",
3295
- textColor: "neutral700"
3296
- };
3297
- }
3298
- if (entry.status === "published") {
3299
- return {
3300
- status: "published",
3301
- label: "Published",
3302
- badgeColor: "success100",
3303
- textColor: "success700"
3304
- };
3305
- }
3306
- if (col && col.draftAndPublish === false) {
3307
- return {
3308
- status: "published",
3309
- label: "Published",
3310
- badgeColor: "success100",
3311
- textColor: "success700"
3312
- };
3313
- }
3314
- if (entry.publishedAt) {
3315
- return {
3316
- status: "published",
3317
- label: "Published",
3318
- badgeColor: "success100",
3319
- textColor: "success700"
3320
- };
3321
- }
3322
- return {
3323
- status: "draft",
3324
- label: "Draft",
3325
- badgeColor: "neutral150",
3326
- textColor: "neutral700"
3327
- };
3328
- }
3329
3353
  function renderCellContent(colDef, entry, col, selectedAttribute, searchAttribute, isMatch, hasAttr, isSelected, onToggleSelect, pendingBatches = [], isDzExpanded = false, onToggleExpandDz, filterQuery = "") {
3330
3354
  switch (colDef.key) {
3331
3355
  case "select":
@@ -3732,12 +3756,23 @@ const BulkUpdater = () => {
3732
3756
  cols.forEach((col) => {
3733
3757
  const total = col.totalEntries !== void 0 ? col.totalEntries : col.entries ? col.entries.length : 0;
3734
3758
  const initialPageSize = col.isSingleType ? 1 : 10;
3759
+ const previewSlice = (col.entries || []).slice(0, initialPageSize).map((entry) => {
3760
+ if (!entry.status) {
3761
+ const lifecycle = getEntryLifecycleStatus(entry, col, pendingBatches);
3762
+ return {
3763
+ ...entry,
3764
+ status: lifecycle.status,
3765
+ publishedAt: entry.publishedAt ?? (lifecycle.status === "published" ? entry.updatedAt || null : null)
3766
+ };
3767
+ }
3768
+ return entry;
3769
+ });
3735
3770
  pages[col.uid] = {
3736
3771
  page: 1,
3737
3772
  pageSize: initialPageSize,
3738
3773
  total,
3739
3774
  pageCount: col.isSingleType ? 1 : Math.ceil(total / initialPageSize) || 1,
3740
- entries: (col.entries || []).slice(0, initialPageSize),
3775
+ entries: previewSlice,
3741
3776
  loading: false
3742
3777
  };
3743
3778
  initialVisibility[col.uid] = true;
@@ -3859,6 +3894,18 @@ const BulkUpdater = () => {
3859
3894
  const pageSizeNum = res.data.pagination?.pageSize ?? size ?? defaultPageSize;
3860
3895
  const totalNum = res.data.pagination?.total !== void 0 ? res.data.pagination.total : fetchedEntries.length;
3861
3896
  const pageCountNum = res.data.pagination?.pageCount ?? Math.max(1, Math.ceil(totalNum / pageSizeNum));
3897
+ const col = collections.find((c) => c.uid === colUid) || null;
3898
+ const enrichedEntries = fetchedEntries.map((entry) => {
3899
+ if (!entry.status) {
3900
+ const lifecycle = getEntryLifecycleStatus(entry, col, pendingBatches);
3901
+ return {
3902
+ ...entry,
3903
+ status: lifecycle.status,
3904
+ publishedAt: entry.publishedAt ?? (lifecycle.status === "published" ? entry.updatedAt || null : null)
3905
+ };
3906
+ }
3907
+ return entry;
3908
+ });
3862
3909
  setCollectionPages((prev) => ({
3863
3910
  ...prev,
3864
3911
  [colUid]: {
@@ -3866,7 +3913,7 @@ const BulkUpdater = () => {
3866
3913
  pageSize: pageSizeNum,
3867
3914
  total: totalNum,
3868
3915
  pageCount: pageCountNum,
3869
- entries: fetchedEntries,
3916
+ entries: enrichedEntries,
3870
3917
  loading: false
3871
3918
  }
3872
3919
  }));
@@ -4027,8 +4074,6 @@ const BulkUpdater = () => {
4027
4074
  const filteredCollections = useMemo(() => {
4028
4075
  return selectedCol ? [selectedCol] : [];
4029
4076
  }, [selectedCol]);
4030
- const [attributeSearch, setAttributeSearch] = useState("");
4031
- const [searchAttributeSearch, setSearchAttributeSearch] = useState("");
4032
4077
  const getAttrDepth = (attr) => attributesMeta[attr]?.depth ?? (attr.includes(".") ? attr.split(".").length - 1 : 0);
4033
4078
  const availableColAttributes = useMemo(() => {
4034
4079
  return selectedCol?.attributes || attributes || [];
@@ -4036,48 +4081,20 @@ const BulkUpdater = () => {
4036
4081
  const depthFilteredAttributes = useMemo(() => {
4037
4082
  return availableColAttributes.filter((attr) => getAttrDepth(attr) <= componentDepth);
4038
4083
  }, [availableColAttributes, componentDepth, attributesMeta]);
4039
- const filteredAttributes = useMemo(() => {
4040
- const q = attributeSearch.toLowerCase().trim();
4041
- if (!q || q === (selectedAttribute || "").toLowerCase().trim()) {
4042
- return depthFilteredAttributes;
4043
- }
4044
- const cleanQ = q.replace(/[^a-z0-9]/g, "");
4045
- return depthFilteredAttributes.filter((attr) => {
4046
- const lower = attr.toLowerCase();
4047
- const cleanLower = lower.replace(/[^a-z0-9]/g, "");
4048
- const rel = relationsMeta[attr];
4049
- const relTarget = (rel?.targetDisplayName || "").toLowerCase();
4050
- return lower.includes(q) || cleanLower.includes(cleanQ) || relTarget.includes(q);
4051
- });
4052
- }, [depthFilteredAttributes, attributeSearch, selectedAttribute, relationsMeta]);
4053
- const filteredSearchAttributes = useMemo(() => {
4054
- const q = searchAttributeSearch.toLowerCase().trim();
4055
- if (!q || q === (searchAttribute || "").toLowerCase().trim()) {
4056
- return depthFilteredAttributes;
4057
- }
4058
- const cleanQ = q.replace(/[^a-z0-9]/g, "");
4059
- return depthFilteredAttributes.filter((attr) => {
4060
- const lower = attr.toLowerCase();
4061
- const cleanLower = lower.replace(/[^a-z0-9]/g, "");
4062
- const rel = relationsMeta[attr];
4063
- const relTarget = (rel?.targetDisplayName || "").toLowerCase();
4064
- return lower.includes(q) || cleanLower.includes(cleanQ) || relTarget.includes(q);
4065
- });
4066
- }, [depthFilteredAttributes, searchAttributeSearch, searchAttribute, relationsMeta]);
4067
4084
  const memoizedComboboxOptions = useMemo(() => {
4068
- if (filteredAttributes.length === 0) {
4069
- return /* @__PURE__ */ jsx(ComboboxOption, { value: "__none__", disabled: true, textValue: "No matching attributes found", children: /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", children: [
4070
- 'No matching attributes found for "',
4071
- attributeSearch,
4072
- '" (Depth L',
4085
+ if (depthFilteredAttributes.length === 0) {
4086
+ return /* @__PURE__ */ jsx(ComboboxOption, { value: "__none__", disabled: true, textValue: "No attributes available", children: /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", children: [
4087
+ "No attributes available for this collection type (Depth L",
4073
4088
  componentDepth,
4074
4089
  ")"
4075
4090
  ] }) });
4076
4091
  }
4077
- return filteredAttributes.map((attr) => {
4092
+ return depthFilteredAttributes.map((attr) => {
4078
4093
  const rel = relationsMeta[attr];
4079
4094
  const depth = getAttrDepth(attr);
4080
- return /* @__PURE__ */ jsx(ComboboxOption, { value: attr, textValue: attr, children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", width: "100%", gap: 2, children: [
4095
+ const badgeText = rel ? `relation ${rel.targetDisplayName}` : depth > 0 ? `L${depth} component` : "";
4096
+ const textValue = badgeText ? `${attr} ${badgeText}` : attr;
4097
+ return /* @__PURE__ */ jsx(ComboboxOption, { value: attr, textValue, children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", width: "100%", gap: 2, children: [
4081
4098
  /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: attr === selectedAttribute ? "bold" : "regular", children: attr }),
4082
4099
  rel ? /* @__PURE__ */ jsxs(Badge, { backgroundColor: "secondary100", textColor: "secondary700", size: "S", children: [
4083
4100
  "relation ➔ ",
@@ -4089,14 +4106,14 @@ const BulkUpdater = () => {
4089
4106
  ] }) : null
4090
4107
  ] }) }, attr);
4091
4108
  });
4092
- }, [filteredAttributes, relationsMeta, selectedAttribute, attributeSearch, componentDepth, attributesMeta]);
4109
+ }, [depthFilteredAttributes, relationsMeta, selectedAttribute, componentDepth, attributesMeta]);
4093
4110
  const memoizedSearchComboboxOptions = useMemo(() => {
4094
4111
  return /* @__PURE__ */ jsxs(Fragment, { children: [
4095
4112
  /* @__PURE__ */ jsx(
4096
4113
  ComboboxOption,
4097
4114
  {
4098
4115
  value: "__default__",
4099
- textValue: `Same as Update Attribute (${selectedAttribute || "None"})`,
4116
+ textValue: `Same as Update Attribute (${selectedAttribute || "None"}) default`,
4100
4117
  children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", width: "100%", gap: 2, children: [
4101
4118
  /* @__PURE__ */ jsxs(Typography, { variant: "omega", fontStyle: "italic", textColor: "neutral600", children: [
4102
4119
  "-- Same as Update Attribute (",
@@ -4107,10 +4124,12 @@ const BulkUpdater = () => {
4107
4124
  ] })
4108
4125
  }
4109
4126
  ),
4110
- filteredSearchAttributes.map((attr) => {
4127
+ depthFilteredAttributes.map((attr) => {
4111
4128
  const rel = relationsMeta[attr];
4112
4129
  const depth = getAttrDepth(attr);
4113
- return /* @__PURE__ */ jsx(ComboboxOption, { value: attr, textValue: attr, children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", width: "100%", gap: 2, children: [
4130
+ const badgeText = rel ? `relation ${rel.targetDisplayName}` : depth > 0 ? `L${depth} component` : "";
4131
+ const textValue = badgeText ? `${attr} ${badgeText}` : attr;
4132
+ return /* @__PURE__ */ jsx(ComboboxOption, { value: attr, textValue, children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", width: "100%", gap: 2, children: [
4114
4133
  /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: attr === searchAttribute ? "bold" : "regular", children: attr }),
4115
4134
  rel ? /* @__PURE__ */ jsxs(Badge, { backgroundColor: "secondary100", textColor: "secondary700", size: "S", children: [
4116
4135
  "relation ➔ ",
@@ -4123,7 +4142,7 @@ const BulkUpdater = () => {
4123
4142
  ] }) }, `search_${attr}`);
4124
4143
  })
4125
4144
  ] });
4126
- }, [filteredSearchAttributes, relationsMeta, searchAttribute, selectedAttribute, componentDepth, attributesMeta]);
4145
+ }, [depthFilteredAttributes, relationsMeta, searchAttribute, selectedAttribute, componentDepth, attributesMeta]);
4127
4146
  const handleSearchAttributeChange = (newAttr) => {
4128
4147
  const finalAttr = newAttr === "__default__" ? "" : newAttr;
4129
4148
  setSearchAttribute(finalAttr);
@@ -4298,7 +4317,6 @@ const BulkUpdater = () => {
4298
4317
  };
4299
4318
  const clearFilter = () => {
4300
4319
  setSearchAttribute("");
4301
- setSearchAttributeSearch("");
4302
4320
  setFilterOperator("none");
4303
4321
  setFilterQuery("");
4304
4322
  setEntrySearch("");
@@ -4369,6 +4387,7 @@ const BulkUpdater = () => {
4369
4387
  let modified = 0;
4370
4388
  let draft = 0;
4371
4389
  let pendingReview = 0;
4390
+ let unknown = 0;
4372
4391
  Object.keys(selectedEntries).forEach((key) => {
4373
4392
  if (!selectedEntries[key]) return;
4374
4393
  const parts = key.split(KEY_SEP);
@@ -4384,18 +4403,20 @@ const BulkUpdater = () => {
4384
4403
  else if (status === "modified") modified++;
4385
4404
  else if (status === "draft") draft++;
4386
4405
  else if (status === "pending_review") pendingReview++;
4406
+ else unknown++;
4387
4407
  } else {
4388
4408
  draft++;
4389
4409
  }
4390
4410
  });
4391
- const unreviewedCount = draft + modified + pendingReview;
4411
+ const unreviewedCount = draft + modified + pendingReview + unknown;
4392
4412
  return {
4393
4413
  published,
4394
4414
  modified,
4395
4415
  draft,
4396
4416
  pendingReview,
4417
+ unknown,
4397
4418
  unreviewedCount,
4398
- total: published + modified + draft + pendingReview
4419
+ total: published + modified + draft + pendingReview + unknown
4399
4420
  };
4400
4421
  }, [selectedEntries, collections, collectionPages, pendingBatches]);
4401
4422
  const handleOpenConfirmModal = () => {
@@ -5323,25 +5344,13 @@ const BulkUpdater = () => {
5323
5344
  placeholder: searchAttribute || `Same as Update (${selectedAttribute || "None"})`,
5324
5345
  value: searchAttribute || "__default__",
5325
5346
  clearLabel: "Reset search attribute",
5326
- onClear: () => {
5327
- handleSearchAttributeChange("");
5328
- setSearchAttributeSearch("");
5329
- },
5347
+ onClear: () => handleSearchAttributeChange(""),
5330
5348
  onFocus: (e) => {
5331
5349
  e.target.select();
5332
5350
  },
5333
- onInputChange: (e) => {
5334
- setSearchAttributeSearch(e.target.value);
5335
- },
5336
- onOpenChange: (isOpen) => {
5337
- if (!isOpen) {
5338
- setSearchAttributeSearch("");
5339
- }
5340
- },
5341
5351
  onChange: (val) => {
5342
5352
  if (val && typeof val === "string" && val !== "__none__") {
5343
5353
  handleSearchAttributeChange(val);
5344
- setSearchAttributeSearch("");
5345
5354
  }
5346
5355
  },
5347
5356
  children: memoizedSearchComboboxOptions
@@ -5414,7 +5423,8 @@ const BulkUpdater = () => {
5414
5423
  /* @__PURE__ */ jsx(SingleSelectOption, { value: "pending_review", children: "Pending Review (Due)" }),
5415
5424
  /* @__PURE__ */ jsx(SingleSelectOption, { value: "draft", children: "Draft" }),
5416
5425
  /* @__PURE__ */ jsx(SingleSelectOption, { value: "published", children: "Published" }),
5417
- /* @__PURE__ */ jsx(SingleSelectOption, { value: "modified", children: "Modified" })
5426
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "modified", children: "Modified" }),
5427
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "unknown", children: "Unknown" })
5418
5428
  ]
5419
5429
  }
5420
5430
  ) }),
@@ -6123,27 +6133,15 @@ const BulkUpdater = () => {
6123
6133
  placeholder: "Search attribute by name or relation...",
6124
6134
  value: selectedAttribute || void 0,
6125
6135
  clearLabel: "Clear attribute selection",
6126
- onClear: () => {
6127
- handleAttributeChange("");
6128
- setAttributeSearch("");
6129
- },
6136
+ onClear: () => handleAttributeChange(""),
6130
6137
  onFocus: (e) => {
6131
6138
  e.target.select();
6132
6139
  },
6133
- onInputChange: (e) => {
6134
- setAttributeSearch(e.target.value);
6135
- },
6136
- onOpenChange: (isOpen) => {
6137
- if (!isOpen) {
6138
- setAttributeSearch("");
6139
- }
6140
- },
6141
6140
  loading: loading && attributes.length === 0,
6142
6141
  loadingMessage: "Discovering schema attributes...",
6143
6142
  onChange: (val) => {
6144
6143
  if (val && typeof val === "string" && val !== "__none__") {
6145
6144
  handleAttributeChange(val);
6146
- setAttributeSearch("");
6147
6145
  }
6148
6146
  },
6149
6147
  children: memoizedComboboxOptions
@@ -7518,4 +7516,4 @@ export {
7518
7516
  getSortOptionsForCollection,
7519
7517
  parseDynamicZonePath
7520
7518
  };
7521
- //# sourceMappingURL=BulkUpdater-By9Dd_YF.mjs.map
7519
+ //# sourceMappingURL=BulkUpdater-DUfv52ng.mjs.map