@strapi/content-type-builder 5.56.0 → 5.57.0
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/admin/components/AIChat/lib/transforms/schemas/toCTB.js +117 -13
- package/dist/admin/components/AIChat/lib/transforms/schemas/toCTB.js.map +1 -1
- package/dist/admin/components/AIChat/lib/transforms/schemas/toCTB.mjs +118 -13
- package/dist/admin/components/AIChat/lib/transforms/schemas/toCTB.mjs.map +1 -1
- package/dist/admin/components/AIChat/providers/SchemaProvider.js +31 -19
- package/dist/admin/components/AIChat/providers/SchemaProvider.js.map +1 -1
- package/dist/admin/components/AIChat/providers/SchemaProvider.mjs +31 -19
- package/dist/admin/components/AIChat/providers/SchemaProvider.mjs.map +1 -1
- package/dist/admin/components/DataManager/DataManagerContext.js.map +1 -1
- package/dist/admin/components/DataManager/DataManagerContext.mjs.map +1 -1
- package/dist/admin/components/DataManager/DataManagerProvider.js +166 -6
- package/dist/admin/components/DataManager/DataManagerProvider.js.map +1 -1
- package/dist/admin/components/DataManager/DataManagerProvider.mjs +165 -7
- package/dist/admin/components/DataManager/DataManagerProvider.mjs.map +1 -1
- package/dist/admin/components/DataManager/RenameMigrationModal.js +285 -0
- package/dist/admin/components/DataManager/RenameMigrationModal.js.map +1 -0
- package/dist/admin/components/DataManager/RenameMigrationModal.mjs +257 -0
- package/dist/admin/components/DataManager/RenameMigrationModal.mjs.map +1 -0
- package/dist/admin/components/DataManager/reducer.js +107 -2
- package/dist/admin/components/DataManager/reducer.js.map +1 -1
- package/dist/admin/components/DataManager/reducer.mjs +106 -2
- package/dist/admin/components/DataManager/reducer.mjs.map +1 -1
- package/dist/admin/components/DataManager/utils/cleanData.js +8 -1
- package/dist/admin/components/DataManager/utils/cleanData.js.map +1 -1
- package/dist/admin/components/DataManager/utils/cleanData.mjs +8 -1
- package/dist/admin/components/DataManager/utils/cleanData.mjs.map +1 -1
- package/dist/admin/components/DataManager/utils/groupRenameChains.js +86 -0
- package/dist/admin/components/DataManager/utils/groupRenameChains.js.map +1 -0
- package/dist/admin/components/DataManager/utils/groupRenameChains.mjs +84 -0
- package/dist/admin/components/DataManager/utils/groupRenameChains.mjs.map +1 -0
- package/dist/admin/components/DataManager/utils/isStorageCompatibleRename.js +29 -0
- package/dist/admin/components/DataManager/utils/isStorageCompatibleRename.js.map +1 -0
- package/dist/admin/components/DataManager/utils/isStorageCompatibleRename.mjs +27 -0
- package/dist/admin/components/DataManager/utils/isStorageCompatibleRename.mjs.map +1 -0
- package/dist/admin/components/DataManager/utils/resolveAfterEditRenameConsent.js +35 -0
- package/dist/admin/components/DataManager/utils/resolveAfterEditRenameConsent.js.map +1 -0
- package/dist/admin/components/DataManager/utils/resolveAfterEditRenameConsent.mjs +33 -0
- package/dist/admin/components/DataManager/utils/resolveAfterEditRenameConsent.mjs.map +1 -0
- package/dist/admin/components/DataManager/utils/splitChainsByInheritedConsent.js +48 -0
- package/dist/admin/components/DataManager/utils/splitChainsByInheritedConsent.js.map +1 -0
- package/dist/admin/components/DataManager/utils/splitChainsByInheritedConsent.mjs +45 -0
- package/dist/admin/components/DataManager/utils/splitChainsByInheritedConsent.mjs.map +1 -0
- package/dist/admin/components/FormModal/FormModal.js +142 -8
- package/dist/admin/components/FormModal/FormModal.js.map +1 -1
- package/dist/admin/components/FormModal/FormModal.mjs +143 -9
- package/dist/admin/components/FormModal/FormModal.mjs.map +1 -1
- package/dist/admin/components/FormModal/attributes/validation/common.js +6 -5
- package/dist/admin/components/FormModal/attributes/validation/common.js.map +1 -1
- package/dist/admin/components/FormModal/attributes/validation/common.mjs +1 -1
- package/dist/admin/components/FormModal/attributes/validation/common.mjs.map +1 -1
- package/dist/admin/components/FormModal/component/createComponentSchema.js +10 -7
- package/dist/admin/components/FormModal/component/createComponentSchema.js.map +1 -1
- package/dist/admin/components/FormModal/component/createComponentSchema.mjs +1 -1
- package/dist/admin/components/FormModal/component/createComponentSchema.mjs.map +1 -1
- package/dist/admin/components/FormModal/contentType/createContentTypeSchema.js +24 -21
- package/dist/admin/components/FormModal/contentType/createContentTypeSchema.js.map +1 -1
- package/dist/admin/components/FormModal/contentType/createContentTypeSchema.mjs +1 -1
- package/dist/admin/components/FormModal/contentType/createContentTypeSchema.mjs.map +1 -1
- package/dist/admin/components/FormModal/forms/utils/createCollectionName.js +3 -2
- package/dist/admin/components/FormModal/forms/utils/createCollectionName.js.map +1 -1
- package/dist/admin/components/FormModal/forms/utils/createCollectionName.mjs +1 -1
- package/dist/admin/components/FormModal/forms/utils/createCollectionName.mjs.map +1 -1
- package/dist/admin/components/FormModal/utils/getRenameStorageChange.js +73 -0
- package/dist/admin/components/FormModal/utils/getRenameStorageChange.js.map +1 -0
- package/dist/admin/components/FormModal/utils/getRenameStorageChange.mjs +70 -0
- package/dist/admin/components/FormModal/utils/getRenameStorageChange.mjs.map +1 -0
- package/dist/admin/src/components/AIChat/lib/transforms/schemas/toCTB.d.ts +4 -3
- package/dist/admin/src/components/AIChat/lib/types/schema.d.ts +6 -1
- package/dist/admin/src/components/DataManager/DataManagerContext.d.ts +28 -2
- package/dist/admin/src/components/DataManager/RenameMigrationModal.d.ts +73 -0
- package/dist/admin/src/components/DataManager/reducer.d.ts +17 -2
- package/dist/admin/src/components/DataManager/utils/cleanData.d.ts +16 -0
- package/dist/admin/src/components/DataManager/utils/groupRenameChains.d.ts +31 -0
- package/dist/admin/src/components/DataManager/utils/isStorageCompatibleRename.d.ts +10 -0
- package/dist/admin/src/components/DataManager/utils/resolveAfterEditRenameConsent.d.ts +24 -0
- package/dist/admin/src/components/DataManager/utils/splitChainsByInheritedConsent.d.ts +26 -0
- package/dist/admin/src/components/FormModal/utils/getRenameStorageChange.d.ts +40 -0
- package/dist/admin/src/types.d.ts +23 -0
- package/dist/admin/translations/en.json.js +12 -0
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +12 -0
- package/dist/admin/translations/en.json.mjs.map +1 -1
- package/dist/server/config.js +24 -3
- package/dist/server/config.js.map +1 -1
- package/dist/server/config.mjs +21 -3
- package/dist/server/config.mjs.map +1 -1
- package/dist/server/controllers/schema.js +2 -2
- package/dist/server/controllers/schema.js.map +1 -1
- package/dist/server/controllers/schema.mjs +1 -1
- package/dist/server/controllers/schema.mjs.map +1 -1
- package/dist/server/controllers/validation/content-type.js +9 -11
- package/dist/server/controllers/validation/content-type.js.map +1 -1
- package/dist/server/controllers/validation/content-type.mjs +7 -9
- package/dist/server/controllers/validation/content-type.mjs.map +1 -1
- package/dist/server/controllers/validation/model-schema.js +2 -3
- package/dist/server/controllers/validation/model-schema.js.map +1 -1
- package/dist/server/controllers/validation/model-schema.mjs +1 -2
- package/dist/server/controllers/validation/model-schema.mjs.map +1 -1
- package/dist/server/controllers/validation/relations.js +1 -2
- package/dist/server/controllers/validation/relations.js.map +1 -1
- package/dist/server/controllers/validation/relations.mjs +1 -2
- package/dist/server/controllers/validation/relations.mjs.map +1 -1
- package/dist/server/controllers/validation/schema.js +42 -23
- package/dist/server/controllers/validation/schema.js.map +1 -1
- package/dist/server/controllers/validation/schema.mjs +43 -24
- package/dist/server/controllers/validation/schema.mjs.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/services/content-types.js +1 -2
- package/dist/server/services/content-types.js.map +1 -1
- package/dist/server/services/content-types.mjs +2 -3
- package/dist/server/services/content-types.mjs.map +1 -1
- package/dist/server/services/migration-builder/index.js +580 -0
- package/dist/server/services/migration-builder/index.js.map +1 -0
- package/dist/server/services/migration-builder/index.mjs +573 -0
- package/dist/server/services/migration-builder/index.mjs.map +1 -0
- package/dist/server/services/schema-builder/content-type-builder.js +31 -1
- package/dist/server/services/schema-builder/content-type-builder.js.map +1 -1
- package/dist/server/services/schema-builder/content-type-builder.mjs +31 -1
- package/dist/server/services/schema-builder/content-type-builder.mjs.map +1 -1
- package/dist/server/services/schema-mutation.js +30 -2
- package/dist/server/services/schema-mutation.js.map +1 -1
- package/dist/server/services/schema-mutation.mjs +10 -2
- package/dist/server/services/schema-mutation.mjs.map +1 -1
- package/dist/server/services/schema.js +259 -15
- package/dist/server/services/schema.js.map +1 -1
- package/dist/server/services/schema.mjs +252 -9
- package/dist/server/services/schema.mjs.map +1 -1
- package/dist/server/src/config.d.ts +23 -2
- package/dist/server/src/config.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/content-type.d.ts +0 -1
- package/dist/server/src/controllers/validation/content-type.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/relations.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/schema.d.ts +28 -0
- package/dist/server/src/controllers/validation/schema.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +10 -2
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/services/content-types.d.ts.map +1 -1
- package/dist/server/src/services/migration-builder/index.d.ts +83 -0
- package/dist/server/src/services/migration-builder/index.d.ts.map +1 -0
- package/dist/server/src/services/schema-builder/content-type-builder.d.ts.map +1 -1
- package/dist/server/src/services/schema-mutation.d.ts +4 -2
- package/dist/server/src/services/schema-mutation.d.ts.map +1 -1
- package/dist/server/src/services/schema.d.ts +19 -0
- package/dist/server/src/services/schema.d.ts.map +1 -1
- package/package.json +7 -6
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { isStorageCompatibleRename } from '../../DataManager/utils/isStorageCompatibleRename.mjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Human label for what defines an attribute's storage: the type, plus the
|
|
5
|
+
* relation kind/target for relations and the component uid (+ repeatable) for
|
|
6
|
+
* components, so a warning can say what changed.
|
|
7
|
+
*/ const describeAttributeStorage = (attribute)=>{
|
|
8
|
+
const type = attribute.type ?? 'unknown';
|
|
9
|
+
if (type === 'relation') {
|
|
10
|
+
const details = [
|
|
11
|
+
attribute.relation,
|
|
12
|
+
attribute.target ? `to ${attribute.target}` : undefined
|
|
13
|
+
].filter(Boolean).join(' ');
|
|
14
|
+
return details ? `${type} (${details})` : type;
|
|
15
|
+
}
|
|
16
|
+
if (type === 'component') {
|
|
17
|
+
const details = [
|
|
18
|
+
attribute.component,
|
|
19
|
+
attribute.repeatable ? 'repeatable' : undefined
|
|
20
|
+
].filter(Boolean).join(', ');
|
|
21
|
+
return details ? `${type} (${details})` : type;
|
|
22
|
+
}
|
|
23
|
+
return type;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Detects an attribute edit that renames an existing field *and* changes its
|
|
27
|
+
* storage (type, relation kind/target, component uid/repeatable). Such a rename
|
|
28
|
+
* cannot be replayed as a data-preserving migration, so the field is dropped
|
|
29
|
+
* and recreated empty — the user should be warned before saving.
|
|
30
|
+
*
|
|
31
|
+
* For a relation, renaming the other side (`targetAttribute`) counts as well:
|
|
32
|
+
* the warning then names that field.
|
|
33
|
+
*
|
|
34
|
+
* Returns `null` when there is nothing to warn about: rename migrations are
|
|
35
|
+
* disabled, the field is brand new (no data yet), no name changed, or the
|
|
36
|
+
* storage is unchanged.
|
|
37
|
+
*/ const getRenameStorageChange = (initial, modified, mode)=>{
|
|
38
|
+
if (mode === 'never' || initial.status === 'NEW') {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
const isRenamed = (oldName, newName)=>Boolean(oldName) && Boolean(newName) && oldName !== newName;
|
|
42
|
+
const renamed = [
|
|
43
|
+
[
|
|
44
|
+
initial.name,
|
|
45
|
+
modified.name
|
|
46
|
+
],
|
|
47
|
+
...initial.type === 'relation' ? [
|
|
48
|
+
[
|
|
49
|
+
initial.targetAttribute,
|
|
50
|
+
modified.targetAttribute
|
|
51
|
+
]
|
|
52
|
+
] : []
|
|
53
|
+
].find(([oldName, newName])=>isRenamed(oldName, newName));
|
|
54
|
+
if (!renamed) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
const [oldName, newName] = renamed;
|
|
58
|
+
if (isStorageCompatibleRename(initial, modified)) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
oldName,
|
|
63
|
+
newName,
|
|
64
|
+
oldType: describeAttributeStorage(initial),
|
|
65
|
+
newType: describeAttributeStorage(modified)
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export { describeAttributeStorage, getRenameStorageChange };
|
|
70
|
+
//# sourceMappingURL=getRenameStorageChange.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getRenameStorageChange.mjs","sources":["../../../../../admin/src/components/FormModal/utils/getRenameStorageChange.ts"],"sourcesContent":["import { isStorageCompatibleRename } from '../../DataManager/utils/isStorageCompatibleRename';\n\nimport type { AnyAttribute, Status } from '../../../types';\nimport type { AttributeRenameMigrationMode } from '../../DataManager/RenameMigrationModal';\n\n/** The loosely typed attribute data held by the form reducer (`FormModalData`). */\nexport type AttributeFormData = Record<string, unknown> & {\n name?: string;\n status?: Status;\n type?: string;\n relation?: string;\n target?: string | null;\n component?: string;\n repeatable?: boolean;\n};\n\nexport interface RenameStorageChange {\n oldName: string;\n newName: string;\n /** Human label of the field's storage before the edit (e.g. `relation (oneToMany to api::tag.tag)`). */\n oldType: string;\n /** Human label of the field's storage after the edit. */\n newType: string;\n}\n\n/**\n * Human label for what defines an attribute's storage: the type, plus the\n * relation kind/target for relations and the component uid (+ repeatable) for\n * components, so a warning can say what changed.\n */\nexport const describeAttributeStorage = (attribute: AttributeFormData): string => {\n const type = attribute.type ?? 'unknown';\n\n if (type === 'relation') {\n const details = [attribute.relation, attribute.target ? `to ${attribute.target}` : undefined]\n .filter(Boolean)\n .join(' ');\n return details ? `${type} (${details})` : type;\n }\n\n if (type === 'component') {\n const details = [attribute.component, attribute.repeatable ? 'repeatable' : undefined]\n .filter(Boolean)\n .join(', ');\n return details ? `${type} (${details})` : type;\n }\n\n return type;\n};\n\n/**\n * Detects an attribute edit that renames an existing field *and* changes its\n * storage (type, relation kind/target, component uid/repeatable). Such a rename\n * cannot be replayed as a data-preserving migration, so the field is dropped\n * and recreated empty — the user should be warned before saving.\n *\n * For a relation, renaming the other side (`targetAttribute`) counts as well:\n * the warning then names that field.\n *\n * Returns `null` when there is nothing to warn about: rename migrations are\n * disabled, the field is brand new (no data yet), no name changed, or the\n * storage is unchanged.\n */\nexport const getRenameStorageChange = (\n initial: AttributeFormData,\n modified: AttributeFormData,\n mode: AttributeRenameMigrationMode\n): RenameStorageChange | null => {\n if (mode === 'never' || initial.status === 'NEW') {\n return null;\n }\n\n const isRenamed = (oldName: unknown, newName: unknown) =>\n Boolean(oldName) && Boolean(newName) && oldName !== newName;\n\n const renamed = [\n [initial.name, modified.name],\n ...(initial.type === 'relation' ? [[initial.targetAttribute, modified.targetAttribute]] : []),\n ].find(([oldName, newName]) => isRenamed(oldName, newName));\n if (!renamed) {\n return null;\n }\n\n const [oldName, newName] = renamed as [string, string];\n\n if (\n isStorageCompatibleRename(\n initial as unknown as AnyAttribute,\n modified as unknown as AnyAttribute\n )\n ) {\n return null;\n }\n\n return {\n oldName,\n newName,\n oldType: describeAttributeStorage(initial),\n newType: describeAttributeStorage(modified),\n };\n};\n"],"names":["describeAttributeStorage","attribute","type","details","relation","target","undefined","filter","Boolean","join","component","repeatable","getRenameStorageChange","initial","modified","mode","status","isRenamed","oldName","newName","renamed","name","targetAttribute","find","isStorageCompatibleRename","oldType","newType"],"mappings":";;AAyBA;;;;IAKO,MAAMA,wBAAAA,GAA2B,CAACC,SAAAA,GAAAA;IACvC,MAAMC,IAAAA,GAAOD,SAAAA,CAAUC,IAAI,IAAI,SAAA;AAE/B,IAAA,IAAIA,SAAS,UAAA,EAAY;AACvB,QAAA,MAAMC,OAAAA,GAAU;AAACF,YAAAA,SAAAA,CAAUG,QAAQ;YAAEH,SAAAA,CAAUI,MAAM,GAAG,CAAC,GAAG,EAAEJ,SAAAA,CAAUI,MAAM,EAAE,GAAGC;AAAU,SAAA,CAC1FC,MAAM,CAACC,OAAAA,CAAAA,CACPC,IAAI,CAAC,GAAA,CAAA;QACR,OAAON,OAAAA,GAAU,GAAGD,IAAAA,CAAK,EAAE,EAAEC,OAAAA,CAAQ,CAAC,CAAC,GAAGD,IAAAA;AAC5C,IAAA;AAEA,IAAA,IAAIA,SAAS,WAAA,EAAa;AACxB,QAAA,MAAMC,OAAAA,GAAU;AAACF,YAAAA,SAAAA,CAAUS,SAAS;YAAET,SAAAA,CAAUU,UAAU,GAAG,YAAA,GAAeL;AAAU,SAAA,CACnFC,MAAM,CAACC,OAAAA,CAAAA,CACPC,IAAI,CAAC,IAAA,CAAA;QACR,OAAON,OAAAA,GAAU,GAAGD,IAAAA,CAAK,EAAE,EAAEC,OAAAA,CAAQ,CAAC,CAAC,GAAGD,IAAAA;AAC5C,IAAA;IAEA,OAAOA,IAAAA;AACT;AAEA;;;;;;;;;;;;AAYC,IACM,MAAMU,sBAAAA,GAAyB,CACpCC,SACAC,QAAAA,EACAC,IAAAA,GAAAA;AAEA,IAAA,IAAIA,IAAAA,KAAS,OAAA,IAAWF,OAAAA,CAAQG,MAAM,KAAK,KAAA,EAAO;QAChD,OAAO,IAAA;AACT,IAAA;IAEA,MAAMC,SAAAA,GAAY,CAACC,OAAAA,EAAkBC,OAAAA,GACnCX,QAAQU,OAAAA,CAAAA,IAAYV,OAAAA,CAAQW,YAAYD,OAAAA,KAAYC,OAAAA;AAEtD,IAAA,MAAMC,OAAAA,GAAU;AACd,QAAA;AAACP,YAAAA,OAAAA,CAAQQ,IAAI;AAAEP,YAAAA,QAAAA,CAASO;AAAK,SAAA;WACzBR,OAAAA,CAAQX,IAAI,KAAK,UAAA,GAAa;AAAC,YAAA;AAACW,gBAAAA,OAAAA,CAAQS,eAAe;AAAER,gBAAAA,QAAAA,CAASQ;AAAgB;AAAC,SAAA,GAAG;KAC3F,CAACC,IAAI,CAAC,CAAC,CAACL,SAASC,OAAAA,CAAQ,GAAKF,UAAUC,OAAAA,EAASC,OAAAA,CAAAA,CAAAA;AAClD,IAAA,IAAI,CAACC,OAAAA,EAAS;QACZ,OAAO,IAAA;AACT,IAAA;IAEA,MAAM,CAACF,OAAAA,EAASC,OAAAA,CAAQ,GAAGC,OAAAA;IAE3B,IACEI,yBAAAA,CACEX,SACAC,QAAAA,CAAAA,EAEF;QACA,OAAO,IAAA;AACT,IAAA;IAEA,OAAO;AACLI,QAAAA,OAAAA;AACAC,QAAAA,OAAAA;AACAM,QAAAA,OAAAA,EAASzB,wBAAAA,CAAyBa,OAAAA,CAAAA;AAClCa,QAAAA,OAAAA,EAAS1B,wBAAAA,CAAyBc,QAAAA;AACpC,KAAA;AACF;;;;"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { ContentType, Component, AnyAttribute } from '../../../../../types';
|
|
2
2
|
import type { Schema } from '../../types/schema';
|
|
3
3
|
/**
|
|
4
|
-
* Transform attributes from Chat format to CTB format
|
|
5
|
-
*
|
|
4
|
+
* Transform attributes from Chat format to CTB format.
|
|
5
|
+
*
|
|
6
|
+
* Keep the existing array return type for callers that only need attributes.
|
|
6
7
|
*/
|
|
7
|
-
export declare const transformAttributesFromChatToCTB: (
|
|
8
|
+
export declare const transformAttributesFromChatToCTB: (schema: Schema, oldSchema?: ContentType | Component) => AnyAttribute[];
|
|
8
9
|
/**
|
|
9
10
|
* Transform schema format
|
|
10
11
|
* AI chat -> CTB
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AnyAttribute } from '../../../../types';
|
|
1
|
+
import type { AnyAttribute, RenameHop } from '../../../../types';
|
|
2
2
|
export type SchemaAttribute = Omit<AnyAttribute, 'name' | 'status'> & Record<string, unknown>;
|
|
3
3
|
/**
|
|
4
4
|
* Strapi schema, this is a simplification to make it easier to work with
|
|
@@ -17,6 +17,11 @@ export type Schema = {
|
|
|
17
17
|
draftAndPublish?: boolean;
|
|
18
18
|
localized?: boolean;
|
|
19
19
|
};
|
|
20
|
+
/**
|
|
21
|
+
* Optional ordered rename hops for this schema. The AI server does not emit
|
|
22
|
+
* this today, but the CTB admin transform accepts it for forward compatibility.
|
|
23
|
+
*/
|
|
24
|
+
renames?: RenameHop[];
|
|
20
25
|
attributes: Record<string, SchemaAttribute>;
|
|
21
26
|
sources?: unknown;
|
|
22
27
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AttributeRenameMigrationMode } from './RenameMigrationModal';
|
|
1
2
|
import type { ContentStructure, FolderSelection, SectionKey } from './utils/contentStructure';
|
|
2
3
|
import type { Component, ContentType } from '../../types';
|
|
3
4
|
import type { ComponentWithChildren } from './utils/retrieveComponentsThatHaveComponents';
|
|
@@ -15,6 +16,10 @@ export interface DataManagerContextValue {
|
|
|
15
16
|
forTarget: Struct.ModelType;
|
|
16
17
|
targetUid: Internal.UID.Schema;
|
|
17
18
|
name: string;
|
|
19
|
+
recordRename?: boolean;
|
|
20
|
+
declineRename?: boolean;
|
|
21
|
+
recordTargetRename?: boolean;
|
|
22
|
+
declineTargetRename?: boolean;
|
|
18
23
|
}) => void;
|
|
19
24
|
moveAttribute: (opts: {
|
|
20
25
|
forTarget: Struct.ModelType;
|
|
@@ -32,7 +37,22 @@ export interface DataManagerContextValue {
|
|
|
32
37
|
forTarget: Struct.ModelType;
|
|
33
38
|
targetUid: Internal.UID.Schema;
|
|
34
39
|
name: string;
|
|
35
|
-
|
|
40
|
+
recordRename?: boolean;
|
|
41
|
+
declineRename?: boolean;
|
|
42
|
+
}) => void;
|
|
43
|
+
/**
|
|
44
|
+
* Resolves the user's consent to preserve data for one rename hop performed
|
|
45
|
+
* in the attribute form: `true` records the hop, `false` declines it (and the
|
|
46
|
+
* rest of its chain), `null` means the user cancelled the edit.
|
|
47
|
+
*/
|
|
48
|
+
confirmAttributeRenameMigration: (rename: {
|
|
49
|
+
forTarget: Struct.ModelType;
|
|
50
|
+
uid: Internal.UID.Schema;
|
|
51
|
+
oldName: string;
|
|
52
|
+
newName: string;
|
|
53
|
+
}) => Promise<boolean | null>;
|
|
54
|
+
/** Effective `renameMigrations.attributes` plugin setting. */
|
|
55
|
+
attributeRenameMigrationMode: AttributeRenameMigrationMode;
|
|
36
56
|
addCreatedComponentToDynamicZone: (opts: {
|
|
37
57
|
forTarget: Struct.ModelType;
|
|
38
58
|
targetUid: Internal.UID.Schema;
|
|
@@ -164,10 +184,16 @@ export interface DataManagerContextValue {
|
|
|
164
184
|
saveSchema(): Promise<void>;
|
|
165
185
|
isModified: boolean;
|
|
166
186
|
isSaving: boolean;
|
|
187
|
+
/**
|
|
188
|
+
* Applies a whole-type change (AI chat). Rename hops declared by the change
|
|
189
|
+
* go through the same preservation consent as manual renames, so this may
|
|
190
|
+
* prompt the user. Resolves `false` when the user cancelled and nothing was
|
|
191
|
+
* applied.
|
|
192
|
+
*/
|
|
167
193
|
applyChange: (opts: {
|
|
168
194
|
action: 'add' | 'update' | 'delete';
|
|
169
195
|
schema: ContentType | Component;
|
|
170
|
-
}) =>
|
|
196
|
+
}) => Promise<boolean>;
|
|
171
197
|
history: {
|
|
172
198
|
undo(): void;
|
|
173
199
|
redo(): void;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { type RenameChain, type RenamePair } from './utils/groupRenameChains';
|
|
2
|
+
import type { RenameHop } from '../../types';
|
|
3
|
+
export type AttributeRenameMigrationMode = 'always' | 'never' | 'prompt-after-edit' | 'prompt-before-save';
|
|
4
|
+
export type AttributeRenameDecision = boolean | 'prompt';
|
|
5
|
+
export declare const getAttributeRenameDecision: (mode: AttributeRenameMigrationMode) => AttributeRenameDecision;
|
|
6
|
+
export declare const shouldPromptForRenamesBeforeSave: (mode: AttributeRenameMigrationMode) => boolean;
|
|
7
|
+
/**
|
|
8
|
+
* One rename *chain* on an existing type, shown as a single row in the
|
|
9
|
+
* confirmation modal. Consent is given per chain, never per hop: replaying a
|
|
10
|
+
* partial chain either fails or silently skips hops whose target column still
|
|
11
|
+
* exists. `key` is the chain id (`${uid}:chain:${firstHopIndex}`) so a decision
|
|
12
|
+
* maps back to every hop of that chain in the type's ordered `renames` array.
|
|
13
|
+
*/
|
|
14
|
+
export interface PendingRename {
|
|
15
|
+
key: string;
|
|
16
|
+
uid: string;
|
|
17
|
+
typeName: string;
|
|
18
|
+
/** Net effect of the chain (`old -> new`); the raw hops for a pure swap-back. */
|
|
19
|
+
pairs: RenamePair[];
|
|
20
|
+
/** Intermediate names the chain routes through (e.g. `tmp`). */
|
|
21
|
+
via: string[];
|
|
22
|
+
/** True when the chain's net effect is empty (fields swapped back) but data still moves. */
|
|
23
|
+
isSwapBack?: boolean;
|
|
24
|
+
}
|
|
25
|
+
interface RenameMigrationModalProps {
|
|
26
|
+
renames: PendingRename[];
|
|
27
|
+
/**
|
|
28
|
+
* Resolves with the keys of the hops the user chose to preserve (every row
|
|
29
|
+
* is checked by default), or an empty set for "don't preserve data".
|
|
30
|
+
*/
|
|
31
|
+
onConfirm: (acceptedKeys: Set<string>) => void;
|
|
32
|
+
/** Aborts the current edit or save and returns to editing. */
|
|
33
|
+
onCancel: () => void;
|
|
34
|
+
}
|
|
35
|
+
declare const RenameMigrationModal: ({ renames, onConfirm, onCancel }: RenameMigrationModalProps) => import("react/jsx-runtime").JSX.Element;
|
|
36
|
+
export { RenameMigrationModal };
|
|
37
|
+
type RenameAwareEntry = {
|
|
38
|
+
action?: string;
|
|
39
|
+
uid: string;
|
|
40
|
+
displayName?: string;
|
|
41
|
+
renames?: RenameHop[];
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Builds the modal row for one chain. A chain whose net effect is empty (the
|
|
45
|
+
* user renamed fields back to their original names through a swap) still has
|
|
46
|
+
* to run every hop, so its raw hops are shown instead of an empty row.
|
|
47
|
+
*/
|
|
48
|
+
export declare const toPendingRename: (chain: RenameChain, renames: RenameHop[], { uid, typeName }: {
|
|
49
|
+
uid: string;
|
|
50
|
+
typeName: string;
|
|
51
|
+
}) => PendingRename;
|
|
52
|
+
/**
|
|
53
|
+
* Groups the ordered per-type `renames` arrays in a request payload into
|
|
54
|
+
* chains for display, one `PendingRename` per chain, preserving order.
|
|
55
|
+
*/
|
|
56
|
+
export declare const collectPendingRenames: (requestData: {
|
|
57
|
+
contentTypes: RenameAwareEntry[];
|
|
58
|
+
components: RenameAwareEntry[];
|
|
59
|
+
}) => PendingRename[];
|
|
60
|
+
/**
|
|
61
|
+
* Keeps only the hops of `renames` that belong to an accepted chain. Filtering
|
|
62
|
+
* by index preserves the original order, and a chain is always kept or dropped
|
|
63
|
+
* as a whole, so the result can never be a truncated chain.
|
|
64
|
+
*/
|
|
65
|
+
export declare const filterRenamesByAcceptedChains: (uid: string, renames: RenameHop[], acceptedChainIds: Set<string>) => RenameHop[];
|
|
66
|
+
/**
|
|
67
|
+
* Mutates the request payload so each type keeps only the rename chains the
|
|
68
|
+
* user accepted; types left with no accepted hops drop their `renames` entirely.
|
|
69
|
+
*/
|
|
70
|
+
export declare const applyRenameDecisions: (requestData: {
|
|
71
|
+
contentTypes: RenameAwareEntry[];
|
|
72
|
+
components: RenameAwareEntry[];
|
|
73
|
+
}, acceptedKeys: Set<string>) => void;
|
|
@@ -110,13 +110,28 @@ type CreateSchemaPayload = {
|
|
|
110
110
|
};
|
|
111
111
|
folder?: FolderAssignmentPayload;
|
|
112
112
|
};
|
|
113
|
-
type
|
|
113
|
+
type RenameConsentPayload = {
|
|
114
|
+
/** Record the hop so the server preserves data (default). */
|
|
115
|
+
recordRename?: boolean;
|
|
116
|
+
/**
|
|
117
|
+
* The user declined to preserve data for this hop: remember both names so
|
|
118
|
+
* later hops of the same chain are declined without another prompt.
|
|
119
|
+
*/
|
|
120
|
+
declineRename?: boolean;
|
|
121
|
+
/**
|
|
122
|
+
* Same pair for the other side of a bidirectional relation, when the edit
|
|
123
|
+
* renames it on the target type.
|
|
124
|
+
*/
|
|
125
|
+
recordTargetRename?: boolean;
|
|
126
|
+
declineTargetRename?: boolean;
|
|
127
|
+
};
|
|
128
|
+
type EditAttributePayload = RenameConsentPayload & {
|
|
114
129
|
attributeToSet: AttributeMutation;
|
|
115
130
|
forTarget: Struct.ModelType;
|
|
116
131
|
targetUid: string;
|
|
117
132
|
name: string;
|
|
118
133
|
};
|
|
119
|
-
type EditCustomFieldAttributePayload = {
|
|
134
|
+
type EditCustomFieldAttributePayload = RenameConsentPayload & {
|
|
120
135
|
attributeToSet: AttributeMutation;
|
|
121
136
|
forTarget: Struct.ModelType;
|
|
122
137
|
targetUid: string;
|
|
@@ -46,6 +46,7 @@ declare const stateToRequestData: ({ components, contentTypes, contentStructure,
|
|
|
46
46
|
[k: string]: unknown;
|
|
47
47
|
};
|
|
48
48
|
})[];
|
|
49
|
+
renames?: import("../../../types").RenameHop[];
|
|
49
50
|
displayName: string;
|
|
50
51
|
description?: string;
|
|
51
52
|
icon?: string;
|
|
@@ -66,6 +67,7 @@ declare const stateToRequestData: ({ components, contentTypes, contentStructure,
|
|
|
66
67
|
plugin?: string | undefined;
|
|
67
68
|
info?: import("@strapi/types/dist/struct/schema.js").SchemaInfo | undefined;
|
|
68
69
|
status?: import("../../../types").Status | undefined;
|
|
70
|
+
declinedRenameNames?: import("../../../types").DeclinedRenameNames | undefined;
|
|
69
71
|
action: string;
|
|
70
72
|
} | {
|
|
71
73
|
attributes: ({
|
|
@@ -79,6 +81,7 @@ declare const stateToRequestData: ({ components, contentTypes, contentStructure,
|
|
|
79
81
|
[k: string]: unknown;
|
|
80
82
|
};
|
|
81
83
|
})[];
|
|
84
|
+
renames?: import("../../../types").RenameHop[];
|
|
82
85
|
singularName: string;
|
|
83
86
|
pluralName: string;
|
|
84
87
|
displayName: string;
|
|
@@ -101,6 +104,7 @@ declare const stateToRequestData: ({ components, contentTypes, contentStructure,
|
|
|
101
104
|
plugin?: string | undefined;
|
|
102
105
|
info?: import("@strapi/types/dist/struct/schema.js").SchemaInfo | undefined;
|
|
103
106
|
status?: import("../../../types").Status | undefined;
|
|
107
|
+
declinedRenameNames?: import("../../../types").DeclinedRenameNames | undefined;
|
|
104
108
|
action: string;
|
|
105
109
|
} | {
|
|
106
110
|
attributes: ({
|
|
@@ -114,6 +118,7 @@ declare const stateToRequestData: ({ components, contentTypes, contentStructure,
|
|
|
114
118
|
[k: string]: unknown;
|
|
115
119
|
};
|
|
116
120
|
})[];
|
|
121
|
+
renames?: import("../../../types").RenameHop[];
|
|
117
122
|
displayName: string;
|
|
118
123
|
description?: string;
|
|
119
124
|
icon?: string;
|
|
@@ -138,6 +143,7 @@ declare const stateToRequestData: ({ components, contentTypes, contentStructure,
|
|
|
138
143
|
visible?: boolean | undefined;
|
|
139
144
|
status?: import("../../../types").Status | undefined;
|
|
140
145
|
restrictRelationsTo?: import("@strapi/types/dist/schema/attribute/index.js").RelationKind.Any[] | null | undefined;
|
|
146
|
+
declinedRenameNames?: import("../../../types").DeclinedRenameNames | undefined;
|
|
141
147
|
action: string;
|
|
142
148
|
category: string | undefined;
|
|
143
149
|
} | {
|
|
@@ -152,6 +158,7 @@ declare const stateToRequestData: ({ components, contentTypes, contentStructure,
|
|
|
152
158
|
[k: string]: unknown;
|
|
153
159
|
};
|
|
154
160
|
})[];
|
|
161
|
+
renames?: import("../../../types").RenameHop[];
|
|
155
162
|
singularName: string;
|
|
156
163
|
pluralName: string;
|
|
157
164
|
displayName: string;
|
|
@@ -178,6 +185,7 @@ declare const stateToRequestData: ({ components, contentTypes, contentStructure,
|
|
|
178
185
|
visible?: boolean | undefined;
|
|
179
186
|
status?: import("../../../types").Status | undefined;
|
|
180
187
|
restrictRelationsTo?: import("@strapi/types/dist/schema/attribute/index.js").RelationKind.Any[] | null | undefined;
|
|
188
|
+
declinedRenameNames?: import("../../../types").DeclinedRenameNames | undefined;
|
|
181
189
|
action: string;
|
|
182
190
|
category: string | undefined;
|
|
183
191
|
})[];
|
|
@@ -196,6 +204,7 @@ declare const stateToRequestData: ({ components, contentTypes, contentStructure,
|
|
|
196
204
|
[k: string]: unknown;
|
|
197
205
|
};
|
|
198
206
|
})[];
|
|
207
|
+
renames?: import("../../../types").RenameHop[];
|
|
199
208
|
displayName: string;
|
|
200
209
|
description?: string;
|
|
201
210
|
icon?: string;
|
|
@@ -216,6 +225,7 @@ declare const stateToRequestData: ({ components, contentTypes, contentStructure,
|
|
|
216
225
|
plugin?: string | undefined;
|
|
217
226
|
info?: import("@strapi/types/dist/struct/schema.js").SchemaInfo | undefined;
|
|
218
227
|
status?: import("../../../types").Status | undefined;
|
|
228
|
+
declinedRenameNames?: import("../../../types").DeclinedRenameNames | undefined;
|
|
219
229
|
action: string;
|
|
220
230
|
} | {
|
|
221
231
|
attributes: ({
|
|
@@ -229,6 +239,7 @@ declare const stateToRequestData: ({ components, contentTypes, contentStructure,
|
|
|
229
239
|
[k: string]: unknown;
|
|
230
240
|
};
|
|
231
241
|
})[];
|
|
242
|
+
renames?: import("../../../types").RenameHop[];
|
|
232
243
|
singularName: string;
|
|
233
244
|
pluralName: string;
|
|
234
245
|
displayName: string;
|
|
@@ -251,6 +262,7 @@ declare const stateToRequestData: ({ components, contentTypes, contentStructure,
|
|
|
251
262
|
plugin?: string | undefined;
|
|
252
263
|
info?: import("@strapi/types/dist/struct/schema.js").SchemaInfo | undefined;
|
|
253
264
|
status?: import("../../../types").Status | undefined;
|
|
265
|
+
declinedRenameNames?: import("../../../types").DeclinedRenameNames | undefined;
|
|
254
266
|
action: string;
|
|
255
267
|
} | {
|
|
256
268
|
attributes: ({
|
|
@@ -264,6 +276,7 @@ declare const stateToRequestData: ({ components, contentTypes, contentStructure,
|
|
|
264
276
|
[k: string]: unknown;
|
|
265
277
|
};
|
|
266
278
|
})[];
|
|
279
|
+
renames?: import("../../../types").RenameHop[];
|
|
267
280
|
displayName: string;
|
|
268
281
|
description?: string;
|
|
269
282
|
icon?: string;
|
|
@@ -288,6 +301,7 @@ declare const stateToRequestData: ({ components, contentTypes, contentStructure,
|
|
|
288
301
|
visible?: boolean | undefined;
|
|
289
302
|
status?: import("../../../types").Status | undefined;
|
|
290
303
|
restrictRelationsTo?: import("@strapi/types/dist/schema/attribute/index.js").RelationKind.Any[] | null | undefined;
|
|
304
|
+
declinedRenameNames?: import("../../../types").DeclinedRenameNames | undefined;
|
|
291
305
|
action: string;
|
|
292
306
|
category: string | undefined;
|
|
293
307
|
} | {
|
|
@@ -302,6 +316,7 @@ declare const stateToRequestData: ({ components, contentTypes, contentStructure,
|
|
|
302
316
|
[k: string]: unknown;
|
|
303
317
|
};
|
|
304
318
|
})[];
|
|
319
|
+
renames?: import("../../../types").RenameHop[];
|
|
305
320
|
singularName: string;
|
|
306
321
|
pluralName: string;
|
|
307
322
|
displayName: string;
|
|
@@ -328,6 +343,7 @@ declare const stateToRequestData: ({ components, contentTypes, contentStructure,
|
|
|
328
343
|
visible?: boolean | undefined;
|
|
329
344
|
status?: import("../../../types").Status | undefined;
|
|
330
345
|
restrictRelationsTo?: import("@strapi/types/dist/schema/attribute/index.js").RelationKind.Any[] | null | undefined;
|
|
346
|
+
declinedRenameNames?: import("../../../types").DeclinedRenameNames | undefined;
|
|
331
347
|
action: string;
|
|
332
348
|
category: string | undefined;
|
|
333
349
|
})[];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { RenameHop } from '../../../types';
|
|
2
|
+
export interface RenamePair {
|
|
3
|
+
oldName: string;
|
|
4
|
+
newName: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* A group of rename hops on one type that share attribute names, transitively:
|
|
8
|
+
* `a -> b`, `b -> c` is one chain, so is the swap `a -> tmp`, `b -> a`,
|
|
9
|
+
* `tmp -> b`, while `a -> b` and `x -> y` are two chains. Consent to preserve
|
|
10
|
+
* data is given per chain, never per hop, because replaying a partial chain
|
|
11
|
+
* either fails or silently skips hops whose target column still exists.
|
|
12
|
+
*/
|
|
13
|
+
export interface RenameChain {
|
|
14
|
+
/** `${uid}:chain:${firstHopIndex}` — stable key for consent decisions. */
|
|
15
|
+
id: string;
|
|
16
|
+
/** Indexes into the type's ordered `renames[]`, ascending. */
|
|
17
|
+
hopIndexes: number[];
|
|
18
|
+
/** Net effect after replaying the chain's hops, in first-appearance order. */
|
|
19
|
+
pairs: RenamePair[];
|
|
20
|
+
/** Names that only ever appear as intermediates (e.g. `tmp`). */
|
|
21
|
+
via: string[];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Groups a type's ordered `renames[]` into chains (see `RenameChain`). Chains
|
|
25
|
+
* are ordered by their first hop; hops inside a chain keep their index order.
|
|
26
|
+
*/
|
|
27
|
+
export declare const groupRenameChains: (uid: string, renames: RenameHop[]) => RenameChain[];
|
|
28
|
+
/**
|
|
29
|
+
* Maps every hop index of `renames` to the chain it belongs to.
|
|
30
|
+
*/
|
|
31
|
+
export declare const chainByHopIndex: (chains: RenameChain[]) => Map<number, RenameChain>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AnyAttribute } from '../../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Whether `newAttribute` keeps the storage of `previousAttribute`, i.e. whether
|
|
4
|
+
* renaming the underlying database artifact is enough to carry the data over.
|
|
5
|
+
* A type change (or a relation retargeted or its direction switched, or a
|
|
6
|
+
* component swapped) must go through the regular drop-and-recreate path:
|
|
7
|
+
* renaming the column and letting schema sync alter its type in place can fail
|
|
8
|
+
* at startup on Postgres/MySQL.
|
|
9
|
+
*/
|
|
10
|
+
export declare const isStorageCompatibleRename: (previousAttribute: AnyAttribute, newAttribute: AnyAttribute) => boolean;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type AttributeRenameMigrationMode } from '../RenameMigrationModal';
|
|
2
|
+
import type { RenameHop } from '../../../types';
|
|
3
|
+
export type AfterEditRenameConsent = 'accept' | 'decline' | 'prompt';
|
|
4
|
+
/**
|
|
5
|
+
* Decides whether a single rename hop (`oldName -> newName`) performed in the
|
|
6
|
+
* attribute form needs the user's consent to preserve data, given the hops
|
|
7
|
+
* already recorded on the type and the names of chains the user has declined.
|
|
8
|
+
*
|
|
9
|
+
* Consent inherits along a chain, so a chain is always accepted or declined as
|
|
10
|
+
* a whole (replaying a partial chain either fails or silently skips hops):
|
|
11
|
+
*
|
|
12
|
+
* 1. A hop that joins an accepted chain — it continues a recorded hop
|
|
13
|
+
* (`oldName` was produced by one) or swaps into a name a recorded hop
|
|
14
|
+
* vacated (`newName`) — is accepted without a prompt.
|
|
15
|
+
* 2. A hop that touches a declined name is declined without a prompt.
|
|
16
|
+
* 3. Otherwise the mode decides; `prompt-after-edit` asks the user.
|
|
17
|
+
*/
|
|
18
|
+
export declare const resolveAfterEditRenameConsent: ({ renames, declinedRenameNames, oldName, newName, mode, }: {
|
|
19
|
+
renames: RenameHop[];
|
|
20
|
+
declinedRenameNames: string[];
|
|
21
|
+
oldName: string;
|
|
22
|
+
newName: string;
|
|
23
|
+
mode: AttributeRenameMigrationMode;
|
|
24
|
+
}) => AfterEditRenameConsent;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { RenameChain } from './groupRenameChains';
|
|
2
|
+
import type { RenameHop } from '../../../types';
|
|
3
|
+
export interface SplitChains {
|
|
4
|
+
/** Chains that join a chain the user already accepted: kept without a prompt. */
|
|
5
|
+
keep: RenameChain[];
|
|
6
|
+
/** Chains touching a name the user already declined: dropped without a prompt. */
|
|
7
|
+
decline: RenameChain[];
|
|
8
|
+
/** Chains with no prior decision: the user has to be asked. */
|
|
9
|
+
prompt: RenameChain[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Buckets incoming rename chains (e.g. declared by the AI chat) by the consent
|
|
13
|
+
* the user already gave for the hops recorded on the type, using the same rules
|
|
14
|
+
* as the per-edit prompt (see `resolveAfterEditRenameConsent`): a chain that
|
|
15
|
+
* continues a recorded hop or swaps into a name one vacated is kept, a chain
|
|
16
|
+
* touching a declined name is declined, anything else needs a prompt.
|
|
17
|
+
*/
|
|
18
|
+
export declare const splitChainsByInheritedConsent: ({ recorded, declinedRenameNames, chains, renames, }: {
|
|
19
|
+
recorded: RenameHop[];
|
|
20
|
+
declinedRenameNames: string[];
|
|
21
|
+
chains: RenameChain[];
|
|
22
|
+
/** The ordered hops the chains index into. */
|
|
23
|
+
renames: RenameHop[];
|
|
24
|
+
}) => SplitChains;
|
|
25
|
+
/** Every attribute name a set of chains touches, deduplicated, in hop order. */
|
|
26
|
+
export declare const namesOfChains: (chains: RenameChain[], renames: RenameHop[]) => string[];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Status } from '../../../types';
|
|
2
|
+
import type { AttributeRenameMigrationMode } from '../../DataManager/RenameMigrationModal';
|
|
3
|
+
/** The loosely typed attribute data held by the form reducer (`FormModalData`). */
|
|
4
|
+
export type AttributeFormData = Record<string, unknown> & {
|
|
5
|
+
name?: string;
|
|
6
|
+
status?: Status;
|
|
7
|
+
type?: string;
|
|
8
|
+
relation?: string;
|
|
9
|
+
target?: string | null;
|
|
10
|
+
component?: string;
|
|
11
|
+
repeatable?: boolean;
|
|
12
|
+
};
|
|
13
|
+
export interface RenameStorageChange {
|
|
14
|
+
oldName: string;
|
|
15
|
+
newName: string;
|
|
16
|
+
/** Human label of the field's storage before the edit (e.g. `relation (oneToMany to api::tag.tag)`). */
|
|
17
|
+
oldType: string;
|
|
18
|
+
/** Human label of the field's storage after the edit. */
|
|
19
|
+
newType: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Human label for what defines an attribute's storage: the type, plus the
|
|
23
|
+
* relation kind/target for relations and the component uid (+ repeatable) for
|
|
24
|
+
* components, so a warning can say what changed.
|
|
25
|
+
*/
|
|
26
|
+
export declare const describeAttributeStorage: (attribute: AttributeFormData) => string;
|
|
27
|
+
/**
|
|
28
|
+
* Detects an attribute edit that renames an existing field *and* changes its
|
|
29
|
+
* storage (type, relation kind/target, component uid/repeatable). Such a rename
|
|
30
|
+
* cannot be replayed as a data-preserving migration, so the field is dropped
|
|
31
|
+
* and recreated empty — the user should be warned before saving.
|
|
32
|
+
*
|
|
33
|
+
* For a relation, renaming the other side (`targetAttribute`) counts as well:
|
|
34
|
+
* the warning then names that field.
|
|
35
|
+
*
|
|
36
|
+
* Returns `null` when there is nothing to warn about: rename migrations are
|
|
37
|
+
* disabled, the field is brand new (no data yet), no name changed, or the
|
|
38
|
+
* storage is unchanged.
|
|
39
|
+
*/
|
|
40
|
+
export declare const getRenameStorageChange: (initial: AttributeFormData, modified: AttributeFormData, mode: AttributeRenameMigrationMode) => RenameStorageChange | null;
|
|
@@ -28,6 +28,18 @@ export type Base = {
|
|
|
28
28
|
customField?: string;
|
|
29
29
|
conditions?: AttributeConditions;
|
|
30
30
|
};
|
|
31
|
+
/**
|
|
32
|
+
* A single attribute rename hop, recorded in the exact order the user performed
|
|
33
|
+
* it so the server can replay it as a data-preserving migration. Because the CTB
|
|
34
|
+
* forbids duplicate field names at any instant, the recorded sequence is always
|
|
35
|
+
* collision-free (a swap is expressed through the user's own intermediate name).
|
|
36
|
+
* Only renames of fields that already exist in the database are tracked — never
|
|
37
|
+
* brand-new fields. Transient (admin only).
|
|
38
|
+
*/
|
|
39
|
+
export type RenameHop = {
|
|
40
|
+
oldName: string;
|
|
41
|
+
newName: string;
|
|
42
|
+
};
|
|
31
43
|
export type Relation = Base & {
|
|
32
44
|
type: 'relation';
|
|
33
45
|
relation: Schema.Attribute.RelationKind.Any;
|
|
@@ -48,9 +60,18 @@ export type Media = Base & {
|
|
|
48
60
|
pluginOptions?: Record<string, unknown>;
|
|
49
61
|
};
|
|
50
62
|
export type AnyAttribute = Base & (Schema.Attribute.BigInteger | Schema.Attribute.Boolean | Schema.Attribute.Blocks | Schema.Attribute.Component<UID.Component, boolean> | Schema.Attribute.DateTime | Schema.Attribute.Date | Schema.Attribute.Decimal | Schema.Attribute.DynamicZone | Schema.Attribute.Email | Schema.Attribute.Enumeration<string[]> | Schema.Attribute.Float | Schema.Attribute.Integer | Schema.Attribute.JSON | Schema.Attribute.Password | Schema.Attribute.RichText | Schema.Attribute.String | Schema.Attribute.Text | Schema.Attribute.Time | Schema.Attribute.Timestamp | Schema.Attribute.UID | Media | Relation);
|
|
63
|
+
/**
|
|
64
|
+
* Attribute names involved in rename chains the user declined to preserve data
|
|
65
|
+
* for (`prompt-after-edit` mode). A later hop touching one of these names is
|
|
66
|
+
* declined without a prompt so a chain is never partially preserved. Transient
|
|
67
|
+
* (admin only), never sent to the server.
|
|
68
|
+
*/
|
|
69
|
+
export type DeclinedRenameNames = string[];
|
|
51
70
|
export type Component = Omit<Struct.ComponentSchema, 'attributes'> & {
|
|
52
71
|
status: Status;
|
|
53
72
|
attributes: Array<AnyAttribute>;
|
|
73
|
+
renames?: RenameHop[];
|
|
74
|
+
declinedRenameNames?: DeclinedRenameNames;
|
|
54
75
|
};
|
|
55
76
|
export type ContentType = Omit<Struct.ContentTypeSchema, 'attributes'> & {
|
|
56
77
|
plugin?: string;
|
|
@@ -58,6 +79,8 @@ export type ContentType = Omit<Struct.ContentTypeSchema, 'attributes'> & {
|
|
|
58
79
|
status: Status;
|
|
59
80
|
restrictRelationsTo: Schema.Attribute.RelationKind.Any[] | null;
|
|
60
81
|
attributes: Array<AnyAttribute>;
|
|
82
|
+
renames?: RenameHop[];
|
|
83
|
+
declinedRenameNames?: DeclinedRenameNames;
|
|
61
84
|
};
|
|
62
85
|
export type Components = Record<string, Component>;
|
|
63
86
|
export type ContentTypes = Record<string, ContentType>;
|
|
@@ -153,6 +153,9 @@ var en = {
|
|
|
153
153
|
"form.attribute.condition.enum-change-warning-end": " will break these conditions. Do you want to proceed?",
|
|
154
154
|
"form.attribute.condition.field-change-warning": "The following fields have conditions that depend on this field: {fieldNames}. Renaming it will break these conditions. Do you want to proceed?",
|
|
155
155
|
"form.attribute.condition.field-change-warning-end": ". Renaming it will break these conditions. Do you want to proceed?",
|
|
156
|
+
"form.attribute.rename-type-change-warning.title": "Existing data will be lost",
|
|
157
|
+
"form.attribute.rename-type-change-warning.body": "You are renaming {oldName} to {newName} and changing it from {oldType} to {newType}. Strapi cannot preserve the existing data of this field when both change at once. The field will be recreated empty when you save.",
|
|
158
|
+
"form.attribute.rename-type-change-warning.confirm": "Continue",
|
|
156
159
|
"form.button.add-components-to-dynamiczone": "Add components to the zone",
|
|
157
160
|
"form.button.add-field": "Add another field",
|
|
158
161
|
"form.button.add-first-field-to-created-component": "Add first field to the component",
|
|
@@ -173,6 +176,15 @@ var en = {
|
|
|
173
176
|
"menu.section.components.name": "Components",
|
|
174
177
|
"menu.section.models.name": "Collection Types",
|
|
175
178
|
"menu.section.single-types.name": "Single Types",
|
|
179
|
+
"migration.confirmation.title": "Preserve data for renamed fields?",
|
|
180
|
+
"migration.confirmation.description": "You renamed the fields below. Strapi can generate a migration to preserve existing data by renaming the underlying database columns. Untick a rename to let those fields start empty instead.",
|
|
181
|
+
"migration.confirmation.field.in": "in {typeName}",
|
|
182
|
+
"migration.confirmation.field.preserve": "Preserve data of {names} in {typeName}",
|
|
183
|
+
"migration.confirmation.field.via": "via {names}",
|
|
184
|
+
"migration.confirmation.field.swap": "Fields swapped back to their original names; data still moves.",
|
|
185
|
+
"migration.confirmation.cancel": "Cancel",
|
|
186
|
+
"migration.confirmation.decline": "Don't preserve data",
|
|
187
|
+
"migration.confirmation.confirm": "Preserve data",
|
|
176
188
|
"nav.action.new-collection-type": "New Collection-Type",
|
|
177
189
|
"nav.action.new-folder": "New folder",
|
|
178
190
|
"nav.action.new-single-type": "New Single-Type",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -149,6 +149,9 @@ var en = {
|
|
|
149
149
|
"form.attribute.condition.enum-change-warning-end": " will break these conditions. Do you want to proceed?",
|
|
150
150
|
"form.attribute.condition.field-change-warning": "The following fields have conditions that depend on this field: {fieldNames}. Renaming it will break these conditions. Do you want to proceed?",
|
|
151
151
|
"form.attribute.condition.field-change-warning-end": ". Renaming it will break these conditions. Do you want to proceed?",
|
|
152
|
+
"form.attribute.rename-type-change-warning.title": "Existing data will be lost",
|
|
153
|
+
"form.attribute.rename-type-change-warning.body": "You are renaming {oldName} to {newName} and changing it from {oldType} to {newType}. Strapi cannot preserve the existing data of this field when both change at once. The field will be recreated empty when you save.",
|
|
154
|
+
"form.attribute.rename-type-change-warning.confirm": "Continue",
|
|
152
155
|
"form.button.add-components-to-dynamiczone": "Add components to the zone",
|
|
153
156
|
"form.button.add-field": "Add another field",
|
|
154
157
|
"form.button.add-first-field-to-created-component": "Add first field to the component",
|
|
@@ -169,6 +172,15 @@ var en = {
|
|
|
169
172
|
"menu.section.components.name": "Components",
|
|
170
173
|
"menu.section.models.name": "Collection Types",
|
|
171
174
|
"menu.section.single-types.name": "Single Types",
|
|
175
|
+
"migration.confirmation.title": "Preserve data for renamed fields?",
|
|
176
|
+
"migration.confirmation.description": "You renamed the fields below. Strapi can generate a migration to preserve existing data by renaming the underlying database columns. Untick a rename to let those fields start empty instead.",
|
|
177
|
+
"migration.confirmation.field.in": "in {typeName}",
|
|
178
|
+
"migration.confirmation.field.preserve": "Preserve data of {names} in {typeName}",
|
|
179
|
+
"migration.confirmation.field.via": "via {names}",
|
|
180
|
+
"migration.confirmation.field.swap": "Fields swapped back to their original names; data still moves.",
|
|
181
|
+
"migration.confirmation.cancel": "Cancel",
|
|
182
|
+
"migration.confirmation.decline": "Don't preserve data",
|
|
183
|
+
"migration.confirmation.confirm": "Preserve data",
|
|
172
184
|
"nav.action.new-collection-type": "New Collection-Type",
|
|
173
185
|
"nav.action.new-folder": "New folder",
|
|
174
186
|
"nav.action.new-single-type": "New Single-Type",
|