strapi-plugin-bulk-updater 1.3.9 → 1.3.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-DPEJQYYa.js → BulkUpdater-DRHQBZZV.js} +20 -4
- package/dist/_chunks/BulkUpdater-DRHQBZZV.js.map +1 -0
- package/dist/_chunks/{BulkUpdater-CtEymixf.mjs → BulkUpdater-J21ZgJWx.mjs} +20 -4
- package/dist/_chunks/BulkUpdater-J21ZgJWx.mjs.map +1 -0
- package/dist/_chunks/{ScopedQuotaSelectInput-CyGlYa9x.js → ScopedQuotaSelectInput-BsBpmwun.js} +79 -11
- package/dist/_chunks/ScopedQuotaSelectInput-BsBpmwun.js.map +1 -0
- package/dist/_chunks/{ScopedQuotaSelectInput-Cy3eEj9-.mjs → ScopedQuotaSelectInput-YKdQgrPt.mjs} +79 -11
- package/dist/_chunks/ScopedQuotaSelectInput-YKdQgrPt.mjs.map +1 -0
- package/dist/_chunks/{SettingsPage-DLCYx2s4.mjs → SettingsPage-BDObdCIY.mjs} +2 -2
- package/dist/_chunks/{SettingsPage-DLCYx2s4.mjs.map → SettingsPage-BDObdCIY.mjs.map} +1 -1
- package/dist/_chunks/{SettingsPage-BM8B-uUz.js → SettingsPage-M-HQ8Jtr.js} +2 -2
- package/dist/_chunks/{SettingsPage-BM8B-uUz.js.map → SettingsPage-M-HQ8Jtr.js.map} +1 -1
- package/dist/_chunks/{ValidationRulesTab-vr-y8ntX.js → ValidationRulesTab-DuvL-K4F.js} +3 -3
- package/dist/_chunks/ValidationRulesTab-DuvL-K4F.js.map +1 -0
- package/dist/_chunks/{ValidationRulesTab-tT4HIeey.mjs → ValidationRulesTab-VeRr-vxa.mjs} +3 -3
- package/dist/_chunks/ValidationRulesTab-VeRr-vxa.mjs.map +1 -0
- package/dist/admin/index.js +3 -3
- package/dist/admin/index.mjs +3 -3
- package/dist/server/index.js +204 -35
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +204 -35
- package/dist/server/index.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/_chunks/BulkUpdater-CtEymixf.mjs.map +0 -1
- package/dist/_chunks/BulkUpdater-DPEJQYYa.js.map +0 -1
- package/dist/_chunks/ScopedQuotaSelectInput-Cy3eEj9-.mjs.map +0 -1
- package/dist/_chunks/ScopedQuotaSelectInput-CyGlYa9x.js.map +0 -1
- package/dist/_chunks/ValidationRulesTab-tT4HIeey.mjs.map +0 -1
- package/dist/_chunks/ValidationRulesTab-vr-y8ntX.js.map +0 -1
package/dist/server/index.mjs
CHANGED
|
@@ -842,7 +842,9 @@ function buildDeepPopulate$1(attributes, allComponents, depth2 = 0) {
|
|
|
842
842
|
populate2[key] = true;
|
|
843
843
|
}
|
|
844
844
|
} else if (def.type === "dynamiczone") {
|
|
845
|
-
populate2[key] =
|
|
845
|
+
populate2[key] = {
|
|
846
|
+
populate: "*"
|
|
847
|
+
};
|
|
846
848
|
} else if (def.type === "relation" || def.type === "media") {
|
|
847
849
|
populate2[key] = true;
|
|
848
850
|
}
|
|
@@ -856,10 +858,28 @@ function discoverComponentAttributes(strapi2, compUid, prefix, currentDepth, max
|
|
|
856
858
|
const discoveredAttrs = [];
|
|
857
859
|
for (const [subKey, subAttr] of Object.entries(compSchema.attributes)) {
|
|
858
860
|
if (systemFields.includes(subKey)) continue;
|
|
859
|
-
if (subAttr.type === "dynamiczone") continue;
|
|
860
861
|
const fullPath = prefix ? `${prefix}.${subKey}` : subKey;
|
|
862
|
+
if (subAttr.type === "dynamiczone") {
|
|
863
|
+
const dzComps = Array.isArray(subAttr.components) ? subAttr.components : [];
|
|
864
|
+
for (const dzCompUid of dzComps) {
|
|
865
|
+
const deeper = discoverComponentAttributes(
|
|
866
|
+
strapi2,
|
|
867
|
+
dzCompUid,
|
|
868
|
+
fullPath,
|
|
869
|
+
currentDepth + 1,
|
|
870
|
+
maxDepth,
|
|
871
|
+
systemFields,
|
|
872
|
+
allContentTypes,
|
|
873
|
+
relationsByAttr,
|
|
874
|
+
allRelationsMeta,
|
|
875
|
+
attributesMeta
|
|
876
|
+
);
|
|
877
|
+
discoveredAttrs.push(...deeper);
|
|
878
|
+
}
|
|
879
|
+
continue;
|
|
880
|
+
}
|
|
861
881
|
if (subAttr.type === "component") {
|
|
862
|
-
if (
|
|
882
|
+
if (subAttr.component) {
|
|
863
883
|
const deeper = discoverComponentAttributes(
|
|
864
884
|
strapi2,
|
|
865
885
|
subAttr.component,
|
|
@@ -901,46 +921,110 @@ function discoverComponentAttributes(strapi2, compUid, prefix, currentDepth, max
|
|
|
901
921
|
function isDeepComponentField(contentType, allComponents, attribute) {
|
|
902
922
|
if (!attribute || !attribute.includes(".")) return false;
|
|
903
923
|
const parts = attribute.split(".");
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
const
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
if (
|
|
924
|
+
function checkPath(currentSchema, pathParts) {
|
|
925
|
+
if (pathParts.length === 0) return true;
|
|
926
|
+
if (!currentSchema || !currentSchema.attributes) return false;
|
|
927
|
+
const [head, ...tail] = pathParts;
|
|
928
|
+
const attrDef = currentSchema.attributes[head];
|
|
929
|
+
if (!attrDef) return false;
|
|
930
|
+
if (tail.length === 0) {
|
|
931
|
+
return true;
|
|
932
|
+
}
|
|
933
|
+
if (attrDef.type === "component" && attrDef.component) {
|
|
934
|
+
const comp = allComponents[attrDef.component];
|
|
935
|
+
return checkPath(comp, tail);
|
|
936
|
+
}
|
|
937
|
+
if (attrDef.type === "dynamiczone") {
|
|
938
|
+
const compUids = Array.isArray(attrDef.components) ? attrDef.components : [];
|
|
939
|
+
return compUids.some((compUid) => {
|
|
940
|
+
const comp = allComponents[compUid];
|
|
941
|
+
return checkPath(comp, tail);
|
|
942
|
+
});
|
|
943
|
+
}
|
|
944
|
+
return false;
|
|
911
945
|
}
|
|
912
|
-
|
|
913
|
-
return Boolean(currentSchema?.attributes?.[leafField]);
|
|
946
|
+
return checkPath(contentType, parts);
|
|
914
947
|
}
|
|
915
948
|
function getLeafAttributeSchema(contentType, allComponents, attribute) {
|
|
916
949
|
if (!attribute) return null;
|
|
917
950
|
if (!attribute.includes(".")) return contentType?.attributes?.[attribute] || null;
|
|
918
951
|
const parts = attribute.split(".");
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
const
|
|
922
|
-
const attrDef = currentSchema
|
|
923
|
-
if (!attrDef
|
|
924
|
-
|
|
925
|
-
|
|
952
|
+
function resolveLeaf(currentSchema, pathParts) {
|
|
953
|
+
if (!currentSchema || !currentSchema.attributes) return null;
|
|
954
|
+
const [head, ...tail] = pathParts;
|
|
955
|
+
const attrDef = currentSchema.attributes[head];
|
|
956
|
+
if (!attrDef) return null;
|
|
957
|
+
if (tail.length === 0) {
|
|
958
|
+
return attrDef;
|
|
959
|
+
}
|
|
960
|
+
if (attrDef.type === "component" && attrDef.component) {
|
|
961
|
+
return resolveLeaf(allComponents[attrDef.component], tail);
|
|
962
|
+
}
|
|
963
|
+
if (attrDef.type === "dynamiczone") {
|
|
964
|
+
const compUids = Array.isArray(attrDef.components) ? attrDef.components : [];
|
|
965
|
+
for (const compUid of compUids) {
|
|
966
|
+
const found = resolveLeaf(allComponents[compUid], tail);
|
|
967
|
+
if (found) return found;
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
return null;
|
|
926
971
|
}
|
|
927
|
-
return
|
|
972
|
+
return resolveLeaf(contentType, parts);
|
|
928
973
|
}
|
|
929
974
|
function setDeepProperty(obj, pathParts, value) {
|
|
930
975
|
if (pathParts.length === 0) return value;
|
|
931
|
-
const current = { ...obj || {} };
|
|
932
976
|
const [head, ...tail] = pathParts;
|
|
977
|
+
if (Array.isArray(obj)) {
|
|
978
|
+
if (/^\d+$/.test(head)) {
|
|
979
|
+
const idx = parseInt(head, 10);
|
|
980
|
+
const copy = [...obj];
|
|
981
|
+
copy[idx] = setDeepProperty(copy[idx] || {}, tail, value);
|
|
982
|
+
return copy;
|
|
983
|
+
}
|
|
984
|
+
return obj.map((item) => {
|
|
985
|
+
if (!item || typeof item !== "object") return item;
|
|
986
|
+
if (head in item || tail.length > 0 && typeof item[head] === "object") {
|
|
987
|
+
return {
|
|
988
|
+
...item,
|
|
989
|
+
[head]: setDeepProperty(item[head], tail, value)
|
|
990
|
+
};
|
|
991
|
+
}
|
|
992
|
+
return item;
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
const current = { ...obj || {} };
|
|
933
996
|
if (tail.length === 0) {
|
|
934
997
|
current[head] = value;
|
|
935
998
|
} else {
|
|
936
|
-
|
|
999
|
+
const subTarget = current[head];
|
|
1000
|
+
if (Array.isArray(subTarget)) {
|
|
1001
|
+
current[head] = setDeepProperty(subTarget, tail, value);
|
|
1002
|
+
} else {
|
|
1003
|
+
current[head] = setDeepProperty(subTarget || {}, tail, value);
|
|
1004
|
+
}
|
|
937
1005
|
}
|
|
938
1006
|
return current;
|
|
939
1007
|
}
|
|
940
1008
|
function getDeepProperty(obj, path2) {
|
|
941
1009
|
if (!obj || !path2) return void 0;
|
|
942
|
-
|
|
943
|
-
|
|
1010
|
+
const parts = path2.split(".");
|
|
1011
|
+
function extract(current, remainingParts) {
|
|
1012
|
+
if (current === void 0 || current === null) return void 0;
|
|
1013
|
+
if (remainingParts.length === 0) return current;
|
|
1014
|
+
const [head, ...tail] = remainingParts;
|
|
1015
|
+
if (Array.isArray(current)) {
|
|
1016
|
+
if (/^\d+$/.test(head)) {
|
|
1017
|
+
return extract(current[parseInt(head, 10)], tail);
|
|
1018
|
+
}
|
|
1019
|
+
for (const item of current) {
|
|
1020
|
+
const found = extract(item?.[head], tail);
|
|
1021
|
+
if (found !== void 0 && found !== null) return found;
|
|
1022
|
+
}
|
|
1023
|
+
return void 0;
|
|
1024
|
+
}
|
|
1025
|
+
return extract(current[head], tail);
|
|
1026
|
+
}
|
|
1027
|
+
return extract(obj, parts);
|
|
944
1028
|
}
|
|
945
1029
|
function buildDeepFilter(pathParts, condition) {
|
|
946
1030
|
if (pathParts.length === 0) return condition;
|
|
@@ -1170,7 +1254,8 @@ async function executeBatchInternal(strapi2, {
|
|
|
1170
1254
|
findOneArgs.populate = populateOption;
|
|
1171
1255
|
}
|
|
1172
1256
|
const currentEntryWithPopulate = await strapi2.documents(target.uid).findOne(findOneArgs);
|
|
1173
|
-
const
|
|
1257
|
+
const isRootDz = contentType?.attributes?.[rootKey]?.type === "dynamiczone";
|
|
1258
|
+
const existingRoot = currentEntryWithPopulate?.[rootKey] || (isRootDz ? [] : {});
|
|
1174
1259
|
const currentVal2 = getDeepProperty(existingRoot, parts.slice(1).join("."));
|
|
1175
1260
|
let newValue2 = value;
|
|
1176
1261
|
if (regexObj && typeof currentVal2 === "string") {
|
|
@@ -1650,10 +1735,29 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1650
1735
|
const nestedComponentAttrs = [];
|
|
1651
1736
|
const validAttrs = Object.keys(rawAttrs).filter((attrKey) => {
|
|
1652
1737
|
if (systemFields.includes(attrKey)) return false;
|
|
1653
|
-
if (rawAttrs[attrKey].type === "dynamiczone")
|
|
1738
|
+
if (rawAttrs[attrKey].type === "dynamiczone") {
|
|
1739
|
+
const dzDef = rawAttrs[attrKey];
|
|
1740
|
+
const dzComponents = Array.isArray(dzDef.components) ? dzDef.components : [];
|
|
1741
|
+
for (const compUid of dzComponents) {
|
|
1742
|
+
const compAttrs = discoverComponentAttributes(
|
|
1743
|
+
strapi2,
|
|
1744
|
+
compUid,
|
|
1745
|
+
attrKey,
|
|
1746
|
+
1,
|
|
1747
|
+
5,
|
|
1748
|
+
systemFields,
|
|
1749
|
+
allContentTypes,
|
|
1750
|
+
relationsByAttr,
|
|
1751
|
+
allRelationsMeta,
|
|
1752
|
+
colAttributesMeta
|
|
1753
|
+
);
|
|
1754
|
+
nestedComponentAttrs.push(...compAttrs);
|
|
1755
|
+
}
|
|
1756
|
+
return false;
|
|
1757
|
+
}
|
|
1654
1758
|
if (rawAttrs[attrKey].type === "component") {
|
|
1655
1759
|
const compDef = rawAttrs[attrKey];
|
|
1656
|
-
if (
|
|
1760
|
+
if (compDef.component) {
|
|
1657
1761
|
const compAttrs = discoverComponentAttributes(
|
|
1658
1762
|
strapi2,
|
|
1659
1763
|
compDef.component,
|
|
@@ -3625,10 +3729,62 @@ function matchesPath(normalizedPath, leafKey, targetField) {
|
|
|
3625
3729
|
const pClean = cleanKey(normalizedPath);
|
|
3626
3730
|
const kClean = cleanKey(leafKey);
|
|
3627
3731
|
const tClean = cleanKey(targetField);
|
|
3628
|
-
if (
|
|
3629
|
-
|
|
3732
|
+
if (kClean === tClean || pClean === tClean) return true;
|
|
3733
|
+
const targetSegments = targetField.replace(/^api::/i, "").split(".").map(cleanKey).filter(Boolean);
|
|
3734
|
+
const pathSegments = normalizedPath.split(".").map(cleanKey).filter(Boolean);
|
|
3735
|
+
if (targetSegments.length === 0 || pathSegments.length === 0) return false;
|
|
3736
|
+
if (targetSegments.length === 1) {
|
|
3737
|
+
const single = targetSegments[0];
|
|
3738
|
+
return kClean === single || pathSegments[pathSegments.length - 1] === single;
|
|
3739
|
+
}
|
|
3740
|
+
let isSuffix = true;
|
|
3741
|
+
for (let i = 0; i < targetSegments.length; i++) {
|
|
3742
|
+
const tSeg = targetSegments[targetSegments.length - 1 - i];
|
|
3743
|
+
const pSeg = pathSegments[pathSegments.length - 1 - i];
|
|
3744
|
+
if (tSeg !== "*" && tSeg !== pSeg) {
|
|
3745
|
+
isSuffix = false;
|
|
3746
|
+
break;
|
|
3747
|
+
}
|
|
3630
3748
|
}
|
|
3631
|
-
|
|
3749
|
+
if (isSuffix) return true;
|
|
3750
|
+
for (let startIdx = 1; startIdx < targetSegments.length; startIdx++) {
|
|
3751
|
+
const subTarget = targetSegments.slice(startIdx);
|
|
3752
|
+
if (subTarget.length > pathSegments.length) continue;
|
|
3753
|
+
let subSuffix = true;
|
|
3754
|
+
for (let i = 0; i < subTarget.length; i++) {
|
|
3755
|
+
const tSeg = subTarget[subTarget.length - 1 - i];
|
|
3756
|
+
const pSeg = pathSegments[pathSegments.length - 1 - i];
|
|
3757
|
+
if (tSeg !== "*" && tSeg !== pSeg) {
|
|
3758
|
+
subSuffix = false;
|
|
3759
|
+
break;
|
|
3760
|
+
}
|
|
3761
|
+
}
|
|
3762
|
+
if (subSuffix) return true;
|
|
3763
|
+
}
|
|
3764
|
+
let pIdx = 0;
|
|
3765
|
+
let matchesInOrder = true;
|
|
3766
|
+
let tStart = 0;
|
|
3767
|
+
if (targetSegments.length > 2 && targetSegments[0] !== pathSegments[0] && targetSegments[0] !== "*") {
|
|
3768
|
+
tStart = 1;
|
|
3769
|
+
}
|
|
3770
|
+
for (let tIdx = tStart; tIdx < targetSegments.length; tIdx++) {
|
|
3771
|
+
const tSeg = targetSegments[tIdx];
|
|
3772
|
+
if (tSeg === "*") continue;
|
|
3773
|
+
let found = false;
|
|
3774
|
+
while (pIdx < pathSegments.length) {
|
|
3775
|
+
if (pathSegments[pIdx] === tSeg) {
|
|
3776
|
+
found = true;
|
|
3777
|
+
pIdx++;
|
|
3778
|
+
break;
|
|
3779
|
+
}
|
|
3780
|
+
pIdx++;
|
|
3781
|
+
}
|
|
3782
|
+
if (!found) {
|
|
3783
|
+
matchesInOrder = false;
|
|
3784
|
+
break;
|
|
3785
|
+
}
|
|
3786
|
+
}
|
|
3787
|
+
return matchesInOrder;
|
|
3632
3788
|
}
|
|
3633
3789
|
const validationRulesService = ({ strapi: strapi2 }) => ({
|
|
3634
3790
|
async getStore() {
|
|
@@ -3747,6 +3903,8 @@ const validationRulesService = ({ strapi: strapi2 }) => ({
|
|
|
3747
3903
|
if (matchesPath(attrName, attrName, targetField2) || matchesPath(`${compUid}.${attrName}`, attrName, targetField2)) return true;
|
|
3748
3904
|
if (attrDef.type === "component" && attrDef.component) {
|
|
3749
3905
|
if (componentHasField(attrDef.component, targetField2)) return true;
|
|
3906
|
+
} else if (attrDef.type === "dynamiczone" && Array.isArray(attrDef.components)) {
|
|
3907
|
+
if (attrDef.components.some((c) => componentHasField(c, targetField2))) return true;
|
|
3750
3908
|
}
|
|
3751
3909
|
}
|
|
3752
3910
|
return false;
|
|
@@ -3763,7 +3921,7 @@ const validationRulesService = ({ strapi: strapi2 }) => ({
|
|
|
3763
3921
|
if (attrDef.type === "component" && attrDef.component) {
|
|
3764
3922
|
if (componentHasField(attrDef.component, targetField)) {
|
|
3765
3923
|
hasField = true;
|
|
3766
|
-
populateAttrs[attrKey] =
|
|
3924
|
+
populateAttrs[attrKey] = { populate: "*" };
|
|
3767
3925
|
}
|
|
3768
3926
|
} else if (attrDef.type === "dynamiczone" && Array.isArray(attrDef.components)) {
|
|
3769
3927
|
const matchingComp = attrDef.components.some(
|
|
@@ -3771,7 +3929,7 @@ const validationRulesService = ({ strapi: strapi2 }) => ({
|
|
|
3771
3929
|
);
|
|
3772
3930
|
if (matchingComp) {
|
|
3773
3931
|
hasField = true;
|
|
3774
|
-
populateAttrs[attrKey] =
|
|
3932
|
+
populateAttrs[attrKey] = { populate: "*" };
|
|
3775
3933
|
}
|
|
3776
3934
|
}
|
|
3777
3935
|
}
|
|
@@ -3779,7 +3937,11 @@ const validationRulesService = ({ strapi: strapi2 }) => ({
|
|
|
3779
3937
|
}
|
|
3780
3938
|
const candidateUids = Object.keys(allContentTypes).filter((uid) => {
|
|
3781
3939
|
if (!uid.startsWith("api::") || uid.includes("bulk-updater")) return false;
|
|
3782
|
-
if (rule.collectionUid && rule.collectionUid !== "*"
|
|
3940
|
+
if (rule.collectionUid && rule.collectionUid !== "*") {
|
|
3941
|
+
if (rule.collectionUid === uid) return true;
|
|
3942
|
+
const cleanRuleCol = cleanKey(rule.collectionUid);
|
|
3943
|
+
const cleanUid = cleanKey(uid);
|
|
3944
|
+
if (cleanUid.includes(cleanRuleCol) || cleanRuleCol.includes(cleanUid)) return true;
|
|
3783
3945
|
return false;
|
|
3784
3946
|
}
|
|
3785
3947
|
return true;
|
|
@@ -3789,7 +3951,8 @@ const validationRulesService = ({ strapi: strapi2 }) => ({
|
|
|
3789
3951
|
const ct = allContentTypes[uid];
|
|
3790
3952
|
if (!ct) continue;
|
|
3791
3953
|
const { hasField, populateAttrs } = schemaHasField(ct);
|
|
3792
|
-
|
|
3954
|
+
const isTargetCol = rule.collectionUid && (rule.collectionUid === uid || cleanKey(uid).includes(cleanKey(rule.collectionUid)));
|
|
3955
|
+
if (hasField || isTargetCol) {
|
|
3793
3956
|
relevantCollections.push({
|
|
3794
3957
|
uid,
|
|
3795
3958
|
displayName: ct.info?.displayName || uid,
|
|
@@ -34200,7 +34363,13 @@ const index = {
|
|
|
34200
34363
|
strapi2.log.warn("[bulk-updater] Failed to fetch active UI validation rules:", err);
|
|
34201
34364
|
}
|
|
34202
34365
|
const effectiveRules = [
|
|
34203
|
-
...activeUiRules.filter((r) =>
|
|
34366
|
+
...activeUiRules.filter((r) => {
|
|
34367
|
+
if (!r.collectionUid || r.collectionUid === "*") return true;
|
|
34368
|
+
if (r.collectionUid === context.uid) return true;
|
|
34369
|
+
const cleanRuleCol = cleanKey(r.collectionUid);
|
|
34370
|
+
const cleanCtxCol = cleanKey(context.uid);
|
|
34371
|
+
return cleanCtxCol.includes(cleanRuleCol) || cleanRuleCol.includes(cleanCtxCol);
|
|
34372
|
+
}).map((r) => ({
|
|
34204
34373
|
id: r.id || r.targetField,
|
|
34205
34374
|
name: r.name || r.targetField,
|
|
34206
34375
|
collectionUid: r.collectionUid || "*",
|