@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.
Files changed (146) hide show
  1. package/dist/admin/components/AIChat/lib/transforms/schemas/toCTB.js +117 -13
  2. package/dist/admin/components/AIChat/lib/transforms/schemas/toCTB.js.map +1 -1
  3. package/dist/admin/components/AIChat/lib/transforms/schemas/toCTB.mjs +118 -13
  4. package/dist/admin/components/AIChat/lib/transforms/schemas/toCTB.mjs.map +1 -1
  5. package/dist/admin/components/AIChat/providers/SchemaProvider.js +31 -19
  6. package/dist/admin/components/AIChat/providers/SchemaProvider.js.map +1 -1
  7. package/dist/admin/components/AIChat/providers/SchemaProvider.mjs +31 -19
  8. package/dist/admin/components/AIChat/providers/SchemaProvider.mjs.map +1 -1
  9. package/dist/admin/components/DataManager/DataManagerContext.js.map +1 -1
  10. package/dist/admin/components/DataManager/DataManagerContext.mjs.map +1 -1
  11. package/dist/admin/components/DataManager/DataManagerProvider.js +166 -6
  12. package/dist/admin/components/DataManager/DataManagerProvider.js.map +1 -1
  13. package/dist/admin/components/DataManager/DataManagerProvider.mjs +165 -7
  14. package/dist/admin/components/DataManager/DataManagerProvider.mjs.map +1 -1
  15. package/dist/admin/components/DataManager/RenameMigrationModal.js +285 -0
  16. package/dist/admin/components/DataManager/RenameMigrationModal.js.map +1 -0
  17. package/dist/admin/components/DataManager/RenameMigrationModal.mjs +257 -0
  18. package/dist/admin/components/DataManager/RenameMigrationModal.mjs.map +1 -0
  19. package/dist/admin/components/DataManager/reducer.js +107 -2
  20. package/dist/admin/components/DataManager/reducer.js.map +1 -1
  21. package/dist/admin/components/DataManager/reducer.mjs +106 -2
  22. package/dist/admin/components/DataManager/reducer.mjs.map +1 -1
  23. package/dist/admin/components/DataManager/utils/cleanData.js +8 -1
  24. package/dist/admin/components/DataManager/utils/cleanData.js.map +1 -1
  25. package/dist/admin/components/DataManager/utils/cleanData.mjs +8 -1
  26. package/dist/admin/components/DataManager/utils/cleanData.mjs.map +1 -1
  27. package/dist/admin/components/DataManager/utils/groupRenameChains.js +86 -0
  28. package/dist/admin/components/DataManager/utils/groupRenameChains.js.map +1 -0
  29. package/dist/admin/components/DataManager/utils/groupRenameChains.mjs +84 -0
  30. package/dist/admin/components/DataManager/utils/groupRenameChains.mjs.map +1 -0
  31. package/dist/admin/components/DataManager/utils/isStorageCompatibleRename.js +29 -0
  32. package/dist/admin/components/DataManager/utils/isStorageCompatibleRename.js.map +1 -0
  33. package/dist/admin/components/DataManager/utils/isStorageCompatibleRename.mjs +27 -0
  34. package/dist/admin/components/DataManager/utils/isStorageCompatibleRename.mjs.map +1 -0
  35. package/dist/admin/components/DataManager/utils/resolveAfterEditRenameConsent.js +35 -0
  36. package/dist/admin/components/DataManager/utils/resolveAfterEditRenameConsent.js.map +1 -0
  37. package/dist/admin/components/DataManager/utils/resolveAfterEditRenameConsent.mjs +33 -0
  38. package/dist/admin/components/DataManager/utils/resolveAfterEditRenameConsent.mjs.map +1 -0
  39. package/dist/admin/components/DataManager/utils/splitChainsByInheritedConsent.js +48 -0
  40. package/dist/admin/components/DataManager/utils/splitChainsByInheritedConsent.js.map +1 -0
  41. package/dist/admin/components/DataManager/utils/splitChainsByInheritedConsent.mjs +45 -0
  42. package/dist/admin/components/DataManager/utils/splitChainsByInheritedConsent.mjs.map +1 -0
  43. package/dist/admin/components/FormModal/FormModal.js +142 -8
  44. package/dist/admin/components/FormModal/FormModal.js.map +1 -1
  45. package/dist/admin/components/FormModal/FormModal.mjs +143 -9
  46. package/dist/admin/components/FormModal/FormModal.mjs.map +1 -1
  47. package/dist/admin/components/FormModal/attributes/validation/common.js +6 -5
  48. package/dist/admin/components/FormModal/attributes/validation/common.js.map +1 -1
  49. package/dist/admin/components/FormModal/attributes/validation/common.mjs +1 -1
  50. package/dist/admin/components/FormModal/attributes/validation/common.mjs.map +1 -1
  51. package/dist/admin/components/FormModal/component/createComponentSchema.js +10 -7
  52. package/dist/admin/components/FormModal/component/createComponentSchema.js.map +1 -1
  53. package/dist/admin/components/FormModal/component/createComponentSchema.mjs +1 -1
  54. package/dist/admin/components/FormModal/component/createComponentSchema.mjs.map +1 -1
  55. package/dist/admin/components/FormModal/contentType/createContentTypeSchema.js +24 -21
  56. package/dist/admin/components/FormModal/contentType/createContentTypeSchema.js.map +1 -1
  57. package/dist/admin/components/FormModal/contentType/createContentTypeSchema.mjs +1 -1
  58. package/dist/admin/components/FormModal/contentType/createContentTypeSchema.mjs.map +1 -1
  59. package/dist/admin/components/FormModal/forms/utils/createCollectionName.js +3 -2
  60. package/dist/admin/components/FormModal/forms/utils/createCollectionName.js.map +1 -1
  61. package/dist/admin/components/FormModal/forms/utils/createCollectionName.mjs +1 -1
  62. package/dist/admin/components/FormModal/forms/utils/createCollectionName.mjs.map +1 -1
  63. package/dist/admin/components/FormModal/utils/getRenameStorageChange.js +73 -0
  64. package/dist/admin/components/FormModal/utils/getRenameStorageChange.js.map +1 -0
  65. package/dist/admin/components/FormModal/utils/getRenameStorageChange.mjs +70 -0
  66. package/dist/admin/components/FormModal/utils/getRenameStorageChange.mjs.map +1 -0
  67. package/dist/admin/src/components/AIChat/lib/transforms/schemas/toCTB.d.ts +4 -3
  68. package/dist/admin/src/components/AIChat/lib/types/schema.d.ts +6 -1
  69. package/dist/admin/src/components/DataManager/DataManagerContext.d.ts +28 -2
  70. package/dist/admin/src/components/DataManager/RenameMigrationModal.d.ts +73 -0
  71. package/dist/admin/src/components/DataManager/reducer.d.ts +17 -2
  72. package/dist/admin/src/components/DataManager/utils/cleanData.d.ts +16 -0
  73. package/dist/admin/src/components/DataManager/utils/groupRenameChains.d.ts +31 -0
  74. package/dist/admin/src/components/DataManager/utils/isStorageCompatibleRename.d.ts +10 -0
  75. package/dist/admin/src/components/DataManager/utils/resolveAfterEditRenameConsent.d.ts +24 -0
  76. package/dist/admin/src/components/DataManager/utils/splitChainsByInheritedConsent.d.ts +26 -0
  77. package/dist/admin/src/components/FormModal/utils/getRenameStorageChange.d.ts +40 -0
  78. package/dist/admin/src/types.d.ts +23 -0
  79. package/dist/admin/translations/en.json.js +12 -0
  80. package/dist/admin/translations/en.json.js.map +1 -1
  81. package/dist/admin/translations/en.json.mjs +12 -0
  82. package/dist/admin/translations/en.json.mjs.map +1 -1
  83. package/dist/server/config.js +24 -3
  84. package/dist/server/config.js.map +1 -1
  85. package/dist/server/config.mjs +21 -3
  86. package/dist/server/config.mjs.map +1 -1
  87. package/dist/server/controllers/schema.js +2 -2
  88. package/dist/server/controllers/schema.js.map +1 -1
  89. package/dist/server/controllers/schema.mjs +1 -1
  90. package/dist/server/controllers/schema.mjs.map +1 -1
  91. package/dist/server/controllers/validation/content-type.js +9 -11
  92. package/dist/server/controllers/validation/content-type.js.map +1 -1
  93. package/dist/server/controllers/validation/content-type.mjs +7 -9
  94. package/dist/server/controllers/validation/content-type.mjs.map +1 -1
  95. package/dist/server/controllers/validation/model-schema.js +2 -3
  96. package/dist/server/controllers/validation/model-schema.js.map +1 -1
  97. package/dist/server/controllers/validation/model-schema.mjs +1 -2
  98. package/dist/server/controllers/validation/model-schema.mjs.map +1 -1
  99. package/dist/server/controllers/validation/relations.js +1 -2
  100. package/dist/server/controllers/validation/relations.js.map +1 -1
  101. package/dist/server/controllers/validation/relations.mjs +1 -2
  102. package/dist/server/controllers/validation/relations.mjs.map +1 -1
  103. package/dist/server/controllers/validation/schema.js +42 -23
  104. package/dist/server/controllers/validation/schema.js.map +1 -1
  105. package/dist/server/controllers/validation/schema.mjs +43 -24
  106. package/dist/server/controllers/validation/schema.mjs.map +1 -1
  107. package/dist/server/index.js +1 -1
  108. package/dist/server/index.js.map +1 -1
  109. package/dist/server/services/content-types.js +1 -2
  110. package/dist/server/services/content-types.js.map +1 -1
  111. package/dist/server/services/content-types.mjs +2 -3
  112. package/dist/server/services/content-types.mjs.map +1 -1
  113. package/dist/server/services/migration-builder/index.js +580 -0
  114. package/dist/server/services/migration-builder/index.js.map +1 -0
  115. package/dist/server/services/migration-builder/index.mjs +573 -0
  116. package/dist/server/services/migration-builder/index.mjs.map +1 -0
  117. package/dist/server/services/schema-builder/content-type-builder.js +31 -1
  118. package/dist/server/services/schema-builder/content-type-builder.js.map +1 -1
  119. package/dist/server/services/schema-builder/content-type-builder.mjs +31 -1
  120. package/dist/server/services/schema-builder/content-type-builder.mjs.map +1 -1
  121. package/dist/server/services/schema-mutation.js +30 -2
  122. package/dist/server/services/schema-mutation.js.map +1 -1
  123. package/dist/server/services/schema-mutation.mjs +10 -2
  124. package/dist/server/services/schema-mutation.mjs.map +1 -1
  125. package/dist/server/services/schema.js +259 -15
  126. package/dist/server/services/schema.js.map +1 -1
  127. package/dist/server/services/schema.mjs +252 -9
  128. package/dist/server/services/schema.mjs.map +1 -1
  129. package/dist/server/src/config.d.ts +23 -2
  130. package/dist/server/src/config.d.ts.map +1 -1
  131. package/dist/server/src/controllers/validation/content-type.d.ts +0 -1
  132. package/dist/server/src/controllers/validation/content-type.d.ts.map +1 -1
  133. package/dist/server/src/controllers/validation/relations.d.ts.map +1 -1
  134. package/dist/server/src/controllers/validation/schema.d.ts +28 -0
  135. package/dist/server/src/controllers/validation/schema.d.ts.map +1 -1
  136. package/dist/server/src/index.d.ts +10 -2
  137. package/dist/server/src/index.d.ts.map +1 -1
  138. package/dist/server/src/services/content-types.d.ts.map +1 -1
  139. package/dist/server/src/services/migration-builder/index.d.ts +83 -0
  140. package/dist/server/src/services/migration-builder/index.d.ts.map +1 -0
  141. package/dist/server/src/services/schema-builder/content-type-builder.d.ts.map +1 -1
  142. package/dist/server/src/services/schema-mutation.d.ts +4 -2
  143. package/dist/server/src/services/schema-mutation.d.ts.map +1 -1
  144. package/dist/server/src/services/schema.d.ts +19 -0
  145. package/dist/server/src/services/schema.d.ts.map +1 -1
  146. package/package.json +7 -6
@@ -0,0 +1,257 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import * as React from 'react';
3
+ import { Modal, Flex, Typography, Checkbox, Button } from '@strapi/design-system';
4
+ import { ArrowRight } from '@strapi/icons';
5
+ import { useIntl } from 'react-intl';
6
+ import { getTrad } from '../../utils/getTrad.mjs';
7
+ import { groupRenameChains } from './utils/groupRenameChains.mjs';
8
+
9
+ const getAttributeRenameDecision = (mode)=>{
10
+ if (mode === 'never') {
11
+ return false;
12
+ }
13
+ if (mode === 'prompt-after-edit') {
14
+ return 'prompt';
15
+ }
16
+ return true;
17
+ };
18
+ const shouldPromptForRenamesBeforeSave = (mode)=>mode === 'prompt-before-save';
19
+ const RenameMigrationModal = ({ renames, onConfirm, onCancel })=>{
20
+ const { formatMessage } = useIntl();
21
+ const descriptionId = React.useId();
22
+ const [checkedKeys, setCheckedKeys] = React.useState(()=>new Set(renames.map((rename)=>rename.key)));
23
+ const chainNames = (rename)=>rename.pairs.map((pair)=>pair.oldName).join(', ');
24
+ const toggle = (key, checked)=>{
25
+ setCheckedKeys((previous)=>{
26
+ const next = new Set(previous);
27
+ if (checked) {
28
+ next.add(key);
29
+ } else {
30
+ next.delete(key);
31
+ }
32
+ return next;
33
+ });
34
+ };
35
+ return /*#__PURE__*/ jsx(Modal.Root, {
36
+ open: true,
37
+ onOpenChange: (open)=>!open && onCancel(),
38
+ children: /*#__PURE__*/ jsxs(Modal.Content, {
39
+ "aria-describedby": descriptionId,
40
+ children: [
41
+ /*#__PURE__*/ jsx(Modal.Header, {
42
+ children: /*#__PURE__*/ jsx(Modal.Title, {
43
+ children: formatMessage({
44
+ id: getTrad('migration.confirmation.title'),
45
+ defaultMessage: 'Preserve data for renamed fields?'
46
+ })
47
+ })
48
+ }),
49
+ /*#__PURE__*/ jsx(Modal.Body, {
50
+ children: /*#__PURE__*/ jsxs(Flex, {
51
+ direction: "column",
52
+ alignItems: "stretch",
53
+ gap: 4,
54
+ children: [
55
+ /*#__PURE__*/ jsx(Typography, {
56
+ id: descriptionId,
57
+ variant: "omega",
58
+ textColor: "neutral600",
59
+ children: formatMessage({
60
+ id: getTrad('migration.confirmation.description'),
61
+ defaultMessage: '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.'
62
+ })
63
+ }),
64
+ /*#__PURE__*/ jsx(Flex, {
65
+ direction: "column",
66
+ alignItems: "stretch",
67
+ gap: 2,
68
+ children: renames.map((rename)=>/*#__PURE__*/ jsxs(Flex, {
69
+ justifyContent: "space-between",
70
+ alignItems: "center",
71
+ hasRadius: true,
72
+ borderColor: "neutral200",
73
+ padding: 3,
74
+ gap: 3,
75
+ children: [
76
+ /*#__PURE__*/ jsxs(Flex, {
77
+ direction: "column",
78
+ alignItems: "start",
79
+ gap: 1,
80
+ children: [
81
+ rename.pairs.map((pair)=>/*#__PURE__*/ jsxs(Flex, {
82
+ gap: 2,
83
+ alignItems: "center",
84
+ children: [
85
+ /*#__PURE__*/ jsx(Typography, {
86
+ variant: "omega",
87
+ fontWeight: "bold",
88
+ children: pair.oldName
89
+ }),
90
+ /*#__PURE__*/ jsx(ArrowRight, {
91
+ width: "1.2rem",
92
+ height: "1.2rem",
93
+ fill: "neutral500"
94
+ }),
95
+ /*#__PURE__*/ jsx(Typography, {
96
+ variant: "omega",
97
+ fontWeight: "bold",
98
+ children: pair.newName
99
+ })
100
+ ]
101
+ }, `${pair.oldName}->${pair.newName}`)),
102
+ rename.isSwapBack && /*#__PURE__*/ jsx(Typography, {
103
+ variant: "pi",
104
+ textColor: "neutral600",
105
+ children: formatMessage({
106
+ id: getTrad('migration.confirmation.field.swap'),
107
+ defaultMessage: 'Fields swapped back to their original names; data still moves.'
108
+ })
109
+ }),
110
+ rename.via.length > 0 && /*#__PURE__*/ jsx(Typography, {
111
+ variant: "pi",
112
+ textColor: "neutral600",
113
+ children: formatMessage({
114
+ id: getTrad('migration.confirmation.field.via'),
115
+ defaultMessage: 'via {names}'
116
+ }, {
117
+ names: rename.via.join(', ')
118
+ })
119
+ }),
120
+ /*#__PURE__*/ jsx(Typography, {
121
+ variant: "pi",
122
+ textColor: "neutral600",
123
+ children: formatMessage({
124
+ id: getTrad('migration.confirmation.field.in'),
125
+ defaultMessage: 'in {typeName}'
126
+ }, {
127
+ typeName: rename.typeName
128
+ })
129
+ })
130
+ ]
131
+ }),
132
+ /*#__PURE__*/ jsx(Checkbox, {
133
+ "aria-label": formatMessage({
134
+ id: getTrad('migration.confirmation.field.preserve'),
135
+ defaultMessage: 'Preserve data of {names} in {typeName}'
136
+ }, {
137
+ names: chainNames(rename),
138
+ typeName: rename.typeName
139
+ }),
140
+ checked: checkedKeys.has(rename.key),
141
+ onCheckedChange: (checked)=>toggle(rename.key, checked === true)
142
+ })
143
+ ]
144
+ }, rename.key))
145
+ })
146
+ ]
147
+ })
148
+ }),
149
+ /*#__PURE__*/ jsxs(Modal.Footer, {
150
+ children: [
151
+ /*#__PURE__*/ jsx(Modal.Close, {
152
+ children: /*#__PURE__*/ jsx(Button, {
153
+ variant: "tertiary",
154
+ onClick: onCancel,
155
+ children: formatMessage({
156
+ id: getTrad('migration.confirmation.cancel'),
157
+ defaultMessage: 'Cancel'
158
+ })
159
+ })
160
+ }),
161
+ /*#__PURE__*/ jsx(Button, {
162
+ variant: "danger-light",
163
+ onClick: ()=>onConfirm(new Set()),
164
+ children: formatMessage({
165
+ id: getTrad('migration.confirmation.decline'),
166
+ defaultMessage: "Don't preserve data"
167
+ })
168
+ }),
169
+ /*#__PURE__*/ jsx(Button, {
170
+ disabled: checkedKeys.size === 0,
171
+ onClick: ()=>onConfirm(checkedKeys),
172
+ children: formatMessage({
173
+ id: getTrad('migration.confirmation.confirm'),
174
+ defaultMessage: 'Preserve data'
175
+ })
176
+ })
177
+ ]
178
+ })
179
+ ]
180
+ })
181
+ });
182
+ };
183
+ const getTypeName = (entry)=>entry.displayName ?? entry.uid;
184
+ /**
185
+ * Builds the modal row for one chain. A chain whose net effect is empty (the
186
+ * user renamed fields back to their original names through a swap) still has
187
+ * to run every hop, so its raw hops are shown instead of an empty row.
188
+ */ const toPendingRename = (chain, renames, { uid, typeName })=>{
189
+ const isSwapBack = chain.pairs.length === 0;
190
+ return {
191
+ key: chain.id,
192
+ uid,
193
+ typeName,
194
+ pairs: isSwapBack ? chain.hopIndexes.map((index)=>renames[index]) : chain.pairs,
195
+ via: chain.via,
196
+ ...isSwapBack ? {
197
+ isSwapBack: true
198
+ } : {}
199
+ };
200
+ };
201
+ /**
202
+ * Groups the ordered per-type `renames` arrays in a request payload into
203
+ * chains for display, one `PendingRename` per chain, preserving order.
204
+ */ const collectPendingRenames = (requestData)=>{
205
+ const items = [];
206
+ const visit = (entries)=>{
207
+ entries.forEach((entry)=>{
208
+ if (entry.action === 'update' && Array.isArray(entry.renames)) {
209
+ const { renames } = entry;
210
+ groupRenameChains(entry.uid, renames).forEach((chain)=>{
211
+ items.push(toPendingRename(chain, renames, {
212
+ uid: entry.uid,
213
+ typeName: getTypeName(entry)
214
+ }));
215
+ });
216
+ }
217
+ });
218
+ };
219
+ visit(requestData.contentTypes ?? []);
220
+ visit(requestData.components ?? []);
221
+ return items;
222
+ };
223
+ /**
224
+ * Keeps only the hops of `renames` that belong to an accepted chain. Filtering
225
+ * by index preserves the original order, and a chain is always kept or dropped
226
+ * as a whole, so the result can never be a truncated chain.
227
+ */ const filterRenamesByAcceptedChains = (uid, renames, acceptedChainIds)=>{
228
+ const keptIndexes = new Set();
229
+ groupRenameChains(uid, renames).forEach((chain)=>{
230
+ if (acceptedChainIds.has(chain.id)) {
231
+ chain.hopIndexes.forEach((index)=>keptIndexes.add(index));
232
+ }
233
+ });
234
+ return renames.filter((_, index)=>keptIndexes.has(index));
235
+ };
236
+ /**
237
+ * Mutates the request payload so each type keeps only the rename chains the
238
+ * user accepted; types left with no accepted hops drop their `renames` entirely.
239
+ */ const applyRenameDecisions = (requestData, acceptedKeys)=>{
240
+ const apply = (entries)=>{
241
+ entries.forEach((entry)=>{
242
+ if (entry.action === 'update' && Array.isArray(entry.renames)) {
243
+ const kept = filterRenamesByAcceptedChains(entry.uid, entry.renames, acceptedKeys);
244
+ if (kept.length > 0) {
245
+ entry.renames = kept;
246
+ } else {
247
+ delete entry.renames;
248
+ }
249
+ }
250
+ });
251
+ };
252
+ apply(requestData.contentTypes ?? []);
253
+ apply(requestData.components ?? []);
254
+ };
255
+
256
+ export { RenameMigrationModal, applyRenameDecisions, collectPendingRenames, filterRenamesByAcceptedChains, getAttributeRenameDecision, shouldPromptForRenamesBeforeSave, toPendingRename };
257
+ //# sourceMappingURL=RenameMigrationModal.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RenameMigrationModal.mjs","sources":["../../../../admin/src/components/DataManager/RenameMigrationModal.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { Button, Checkbox, Flex, Modal, Typography } from '@strapi/design-system';\nimport { ArrowRight } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\n\nimport { getTrad } from '../../utils/getTrad';\n\nimport { groupRenameChains, type RenameChain, type RenamePair } from './utils/groupRenameChains';\n\nimport type { RenameHop } from '../../types';\n\nexport type AttributeRenameMigrationMode =\n | 'always'\n | 'never'\n | 'prompt-after-edit'\n | 'prompt-before-save';\n\nexport type AttributeRenameDecision = boolean | 'prompt';\n\nexport const getAttributeRenameDecision = (\n mode: AttributeRenameMigrationMode\n): AttributeRenameDecision => {\n if (mode === 'never') {\n return false;\n }\n\n if (mode === 'prompt-after-edit') {\n return 'prompt';\n }\n\n return true;\n};\n\nexport const shouldPromptForRenamesBeforeSave = (mode: AttributeRenameMigrationMode): boolean =>\n mode === 'prompt-before-save';\n\n/**\n * One rename *chain* on an existing type, shown as a single row in the\n * confirmation modal. Consent is given per chain, never per hop: replaying a\n * partial chain either fails or silently skips hops whose target column still\n * exists. `key` is the chain id (`${uid}:chain:${firstHopIndex}`) so a decision\n * maps back to every hop of that chain in the type's ordered `renames` array.\n */\nexport interface PendingRename {\n key: string;\n uid: string;\n typeName: string;\n /** Net effect of the chain (`old -> new`); the raw hops for a pure swap-back. */\n pairs: RenamePair[];\n /** Intermediate names the chain routes through (e.g. `tmp`). */\n via: string[];\n /** True when the chain's net effect is empty (fields swapped back) but data still moves. */\n isSwapBack?: boolean;\n}\n\ninterface RenameMigrationModalProps {\n renames: PendingRename[];\n /**\n * Resolves with the keys of the hops the user chose to preserve (every row\n * is checked by default), or an empty set for \"don't preserve data\".\n */\n onConfirm: (acceptedKeys: Set<string>) => void;\n /** Aborts the current edit or save and returns to editing. */\n onCancel: () => void;\n}\n\nconst RenameMigrationModal = ({ renames, onConfirm, onCancel }: RenameMigrationModalProps) => {\n const { formatMessage } = useIntl();\n const descriptionId = React.useId();\n\n const [checkedKeys, setCheckedKeys] = React.useState<Set<string>>(\n () => new Set(renames.map((rename) => rename.key))\n );\n\n const chainNames = (rename: PendingRename) => rename.pairs.map((pair) => pair.oldName).join(', ');\n\n const toggle = (key: string, checked: boolean) => {\n setCheckedKeys((previous) => {\n const next = new Set(previous);\n if (checked) {\n next.add(key);\n } else {\n next.delete(key);\n }\n return next;\n });\n };\n\n return (\n <Modal.Root open onOpenChange={(open) => !open && onCancel()}>\n <Modal.Content aria-describedby={descriptionId}>\n <Modal.Header>\n <Modal.Title>\n {formatMessage({\n id: getTrad('migration.confirmation.title'),\n defaultMessage: 'Preserve data for renamed fields?',\n })}\n </Modal.Title>\n </Modal.Header>\n <Modal.Body>\n <Flex direction=\"column\" alignItems=\"stretch\" gap={4}>\n <Typography id={descriptionId} variant=\"omega\" textColor=\"neutral600\">\n {formatMessage({\n id: getTrad('migration.confirmation.description'),\n defaultMessage:\n '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.',\n })}\n </Typography>\n <Flex direction=\"column\" alignItems=\"stretch\" gap={2}>\n {renames.map((rename) => (\n <Flex\n key={rename.key}\n justifyContent=\"space-between\"\n alignItems=\"center\"\n hasRadius\n borderColor=\"neutral200\"\n padding={3}\n gap={3}\n >\n <Flex direction=\"column\" alignItems=\"start\" gap={1}>\n {rename.pairs.map((pair) => (\n <Flex key={`${pair.oldName}->${pair.newName}`} gap={2} alignItems=\"center\">\n <Typography variant=\"omega\" fontWeight=\"bold\">\n {pair.oldName}\n </Typography>\n <ArrowRight width=\"1.2rem\" height=\"1.2rem\" fill=\"neutral500\" />\n <Typography variant=\"omega\" fontWeight=\"bold\">\n {pair.newName}\n </Typography>\n </Flex>\n ))}\n {rename.isSwapBack && (\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {formatMessage({\n id: getTrad('migration.confirmation.field.swap'),\n defaultMessage:\n 'Fields swapped back to their original names; data still moves.',\n })}\n </Typography>\n )}\n {rename.via.length > 0 && (\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {formatMessage(\n {\n id: getTrad('migration.confirmation.field.via'),\n defaultMessage: 'via {names}',\n },\n { names: rename.via.join(', ') }\n )}\n </Typography>\n )}\n <Typography variant=\"pi\" textColor=\"neutral600\">\n {formatMessage(\n {\n id: getTrad('migration.confirmation.field.in'),\n defaultMessage: 'in {typeName}',\n },\n { typeName: rename.typeName }\n )}\n </Typography>\n </Flex>\n <Checkbox\n aria-label={formatMessage(\n {\n id: getTrad('migration.confirmation.field.preserve'),\n defaultMessage: 'Preserve data of {names} in {typeName}',\n },\n { names: chainNames(rename), typeName: rename.typeName }\n )}\n checked={checkedKeys.has(rename.key)}\n onCheckedChange={(checked) => toggle(rename.key, checked === true)}\n />\n </Flex>\n ))}\n </Flex>\n </Flex>\n </Modal.Body>\n <Modal.Footer>\n <Modal.Close>\n <Button variant=\"tertiary\" onClick={onCancel}>\n {formatMessage({\n id: getTrad('migration.confirmation.cancel'),\n defaultMessage: 'Cancel',\n })}\n </Button>\n </Modal.Close>\n <Button variant=\"danger-light\" onClick={() => onConfirm(new Set())}>\n {formatMessage({\n id: getTrad('migration.confirmation.decline'),\n defaultMessage: \"Don't preserve data\",\n })}\n </Button>\n <Button disabled={checkedKeys.size === 0} onClick={() => onConfirm(checkedKeys)}>\n {formatMessage({\n id: getTrad('migration.confirmation.confirm'),\n defaultMessage: 'Preserve data',\n })}\n </Button>\n </Modal.Footer>\n </Modal.Content>\n </Modal.Root>\n );\n};\n\nexport { RenameMigrationModal };\n\nconst getTypeName = (entry: { displayName?: string; uid: string }): string =>\n entry.displayName ?? entry.uid;\n\ntype RenameAwareEntry = {\n action?: string;\n uid: string;\n displayName?: string;\n renames?: RenameHop[];\n};\n\n/**\n * Builds the modal row for one chain. A chain whose net effect is empty (the\n * user renamed fields back to their original names through a swap) still has\n * to run every hop, so its raw hops are shown instead of an empty row.\n */\nexport const toPendingRename = (\n chain: RenameChain,\n renames: RenameHop[],\n { uid, typeName }: { uid: string; typeName: string }\n): PendingRename => {\n const isSwapBack = chain.pairs.length === 0;\n\n return {\n key: chain.id,\n uid,\n typeName,\n pairs: isSwapBack ? chain.hopIndexes.map((index) => renames[index]) : chain.pairs,\n via: chain.via,\n ...(isSwapBack ? { isSwapBack: true } : {}),\n };\n};\n\n/**\n * Groups the ordered per-type `renames` arrays in a request payload into\n * chains for display, one `PendingRename` per chain, preserving order.\n */\nexport const collectPendingRenames = (requestData: {\n contentTypes: RenameAwareEntry[];\n components: RenameAwareEntry[];\n}): PendingRename[] => {\n const items: PendingRename[] = [];\n\n const visit = (entries: RenameAwareEntry[]) => {\n entries.forEach((entry) => {\n if (entry.action === 'update' && Array.isArray(entry.renames)) {\n const { renames } = entry;\n groupRenameChains(entry.uid, renames).forEach((chain) => {\n items.push(\n toPendingRename(chain, renames, { uid: entry.uid, typeName: getTypeName(entry) })\n );\n });\n }\n });\n };\n\n visit(requestData.contentTypes ?? []);\n visit(requestData.components ?? []);\n\n return items;\n};\n\n/**\n * Keeps only the hops of `renames` that belong to an accepted chain. Filtering\n * by index preserves the original order, and a chain is always kept or dropped\n * as a whole, so the result can never be a truncated chain.\n */\nexport const filterRenamesByAcceptedChains = (\n uid: string,\n renames: RenameHop[],\n acceptedChainIds: Set<string>\n): RenameHop[] => {\n const keptIndexes = new Set<number>();\n groupRenameChains(uid, renames).forEach((chain) => {\n if (acceptedChainIds.has(chain.id)) {\n chain.hopIndexes.forEach((index) => keptIndexes.add(index));\n }\n });\n\n return renames.filter((_, index) => keptIndexes.has(index));\n};\n\n/**\n * Mutates the request payload so each type keeps only the rename chains the\n * user accepted; types left with no accepted hops drop their `renames` entirely.\n */\nexport const applyRenameDecisions = (\n requestData: { contentTypes: RenameAwareEntry[]; components: RenameAwareEntry[] },\n acceptedKeys: Set<string>\n): void => {\n const apply = (entries: RenameAwareEntry[]) => {\n entries.forEach((entry) => {\n if (entry.action === 'update' && Array.isArray(entry.renames)) {\n const kept = filterRenamesByAcceptedChains(entry.uid, entry.renames, acceptedKeys);\n if (kept.length > 0) {\n entry.renames = kept;\n } else {\n delete entry.renames;\n }\n }\n });\n };\n\n apply(requestData.contentTypes ?? []);\n apply(requestData.components ?? []);\n};\n"],"names":["getAttributeRenameDecision","mode","shouldPromptForRenamesBeforeSave","RenameMigrationModal","renames","onConfirm","onCancel","formatMessage","useIntl","descriptionId","React","useId","checkedKeys","setCheckedKeys","useState","Set","map","rename","key","chainNames","pairs","pair","oldName","join","toggle","checked","previous","next","add","delete","_jsx","Modal","Root","open","onOpenChange","_jsxs","Content","aria-describedby","Header","Title","id","getTrad","defaultMessage","Body","Flex","direction","alignItems","gap","Typography","variant","textColor","justifyContent","hasRadius","borderColor","padding","fontWeight","ArrowRight","width","height","fill","newName","isSwapBack","via","length","names","typeName","Checkbox","aria-label","has","onCheckedChange","Footer","Close","Button","onClick","disabled","size","getTypeName","entry","displayName","uid","toPendingRename","chain","hopIndexes","index","collectPendingRenames","requestData","items","visit","entries","forEach","action","Array","isArray","groupRenameChains","push","contentTypes","components","filterRenamesByAcceptedChains","acceptedChainIds","keptIndexes","filter","_","applyRenameDecisions","acceptedKeys","apply","kept"],"mappings":"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"}
@@ -2,16 +2,19 @@
2
2
 
3
3
  var merge = require('lodash/merge');
4
4
  var omit = require('lodash/omit');
5
+ var uniq = require('lodash/uniq');
5
6
  var applyPrivateSearchDefault = require('../../utils/applyPrivateSearchDefault.js');
6
7
  var getRelationType = require('../../utils/getRelationType.js');
7
8
  var makeUnique = require('../../utils/makeUnique.js');
8
9
  var undoRedo = require('./undoRedo.js');
9
10
  var contentStructure = require('./utils/contentStructure.js');
11
+ var isStorageCompatibleRename = require('./utils/isStorageCompatibleRename.js');
10
12
 
11
13
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
12
14
 
13
15
  var merge__default = /*#__PURE__*/_interopDefault(merge);
14
16
  var omit__default = /*#__PURE__*/_interopDefault(omit);
17
+ var uniq__default = /*#__PURE__*/_interopDefault(uniq);
15
18
 
16
19
  const initialState = {
17
20
  components: {},
@@ -80,6 +83,65 @@ const createAttribute = (properties)=>{
80
83
  status: 'NEW'
81
84
  };
82
85
  };
86
+ /**
87
+ * Records an attribute rename hop in the order the user performed it, so the
88
+ * server can replay the exact path as a data-preserving migration.
89
+ *
90
+ * - Only renames of fields that already exist in the database are recorded; a
91
+ * brand-new field (status NEW) has no data yet, so its renames are ignored.
92
+ * - A rename that also changes the field's type / relation / component is not
93
+ * recorded (see `isStorageCompatibleRename`).
94
+ * - Each hop (`previousName -> newName`) is appended verbatim. The recorded
95
+ * sequence is inherently collision-free because the CTB never allows two
96
+ * fields to share a name — a "swap" is expressed through the user's own
97
+ * intermediate-name hop, so no synthetic temp column is ever needed.
98
+ */ const recordRename = (type, previousAttribute, newAttribute)=>{
99
+ if (previousAttribute.status === 'NEW') {
100
+ return;
101
+ }
102
+ const oldName = previousAttribute.name;
103
+ const newName = newAttribute?.name;
104
+ if (!newName || oldName === newName) {
105
+ return;
106
+ }
107
+ if (!isStorageCompatibleRename.isStorageCompatibleRename(previousAttribute, newAttribute)) {
108
+ return;
109
+ }
110
+ if (!type.renames) {
111
+ type.renames = [];
112
+ }
113
+ type.renames.push({
114
+ oldName,
115
+ newName
116
+ });
117
+ };
118
+ /**
119
+ * Remembers the names of a rename hop the user declined to preserve data for,
120
+ * so the rest of that chain is declined without another prompt.
121
+ */ const recordDeclinedRename = (type, previousAttribute, newAttribute)=>{
122
+ const oldName = previousAttribute.name;
123
+ const newName = newAttribute?.name;
124
+ if (!newName || oldName === newName) {
125
+ return;
126
+ }
127
+ type.declinedRenameNames = uniq__default.default([
128
+ ...type.declinedRenameNames ?? [],
129
+ oldName,
130
+ newName
131
+ ]);
132
+ };
133
+ /**
134
+ * Applies the rename consent carried by an edit: either records the hop or
135
+ * remembers it as declined. Never both.
136
+ */ const applyRenameConsent = (type, previousAttribute, newAttribute, { recordRename: shouldRecordRename = true, declineRename: shouldDecline = false })=>{
137
+ if (shouldDecline) {
138
+ recordDeclinedRename(type, previousAttribute, newAttribute);
139
+ return;
140
+ }
141
+ if (shouldRecordRename) {
142
+ recordRename(type, previousAttribute, newAttribute);
143
+ }
144
+ };
83
145
  const setAttributeAt = (type, index, attribute)=>{
84
146
  const previousAttribute = type.attributes[index];
85
147
  const newStatus = getNewStatus(previousAttribute.status, 'CHANGED');
@@ -119,6 +181,30 @@ const removeAttributeByName = (type, name)=>{
119
181
  setAttributeStatus(attr, 'REMOVED');
120
182
  }
121
183
  };
184
+ /**
185
+ * Carries the pending rename state of `existing` over to a full replacement of
186
+ * the type (the AI chat's `applyChange`). Appending the incoming hops after the
187
+ * existing ones is order-correct: the chat transform diffs against the current
188
+ * reducer entry, whose attributes already carry the manual renames, so its hops
189
+ * start from where the manual hops ended.
190
+ */ const mergeRenameState = (existing, incoming)=>{
191
+ const renames = [
192
+ ...existing?.renames ?? [],
193
+ ...incoming.renames ?? []
194
+ ];
195
+ const declinedRenameNames = uniq__default.default([
196
+ ...existing?.declinedRenameNames ?? [],
197
+ ...incoming.declinedRenameNames ?? []
198
+ ]);
199
+ return {
200
+ ...renames.length > 0 ? {
201
+ renames
202
+ } : {},
203
+ ...declinedRenameNames.length > 0 ? {
204
+ declinedRenameNames
205
+ } : {}
206
+ };
207
+ };
122
208
  const updateType = (type, data)=>{
123
209
  merge__default.default(type, data);
124
210
  setStatus(type, 'CHANGED');
@@ -408,7 +494,7 @@ const slice = undoRedo.createUndoRedoSlice({
408
494
  attr.components = updatedComponents;
409
495
  },
410
496
  editAttribute: (state, action)=>{
411
- const { name, attributeToSet, forTarget, targetUid } = action.payload;
497
+ const { name, attributeToSet, forTarget, targetUid, recordRename, declineRename, recordTargetRename, declineTargetRename } = action.payload;
412
498
  const type = getType(state, {
413
499
  forTarget,
414
500
  targetUid
@@ -418,6 +504,10 @@ const slice = undoRedo.createUndoRedoSlice({
418
504
  return;
419
505
  }
420
506
  const previousAttribute = type.attributes[initialAttributeIndex];
507
+ applyRenameConsent(type, previousAttribute, attributeToSet, {
508
+ recordRename,
509
+ declineRename
510
+ });
421
511
  setAttributeAt(type, initialAttributeIndex, attributeToSet);
422
512
  if (previousAttribute.type !== attributeToSet.type) {
423
513
  return;
@@ -457,6 +547,14 @@ const slice = undoRedo.createUndoRedoSlice({
457
547
  };
458
548
  // create or recreate(at old index) targetAttribute
459
549
  if (previousTargetAttributeIndex !== -1 && previousTarget.uid === newTarget.uid) {
550
+ // The counterpart is renamed on the target type: without a hop
551
+ // there, the side owning the join table would lose its links.
552
+ if (previousTargetAttribute) {
553
+ applyRenameConsent(newTarget, previousTargetAttribute, newTargetAttribute, {
554
+ recordRename: recordTargetRename,
555
+ declineRename: declineTargetRename
556
+ });
557
+ }
460
558
  // re-create at previousIdx if possible
461
559
  replaceAttributeAt(newTarget, previousTargetAttributeIndex, newTargetAttribute);
462
560
  } else {
@@ -468,14 +566,19 @@ const slice = undoRedo.createUndoRedoSlice({
468
566
  }
469
567
  },
470
568
  editCustomFieldAttribute: (state, action)=>{
471
- const { forTarget, targetUid, name, attributeToSet } = action.payload;
569
+ const { forTarget, targetUid, name, attributeToSet, recordRename, declineRename } = action.payload;
472
570
  const initialAttributeName = name;
473
571
  const type = getType(state, {
474
572
  forTarget,
475
573
  targetUid
476
574
  });
477
575
  const initialAttributeIndex = findAttributeIndex(type, initialAttributeName);
576
+ const previousAttribute = type.attributes[initialAttributeIndex];
478
577
  setAttributeAt(type, initialAttributeIndex, attributeToSet);
578
+ applyRenameConsent(type, previousAttribute, attributeToSet, {
579
+ recordRename,
580
+ declineRename
581
+ });
479
582
  },
480
583
  reloadPlugin: ()=>{
481
584
  return initialState;
@@ -894,6 +997,7 @@ const slice = undoRedo.createUndoRedoSlice({
894
997
  const component = state.components[uid];
895
998
  state.components[uid] = {
896
999
  ...schema,
1000
+ ...mergeRenameState(component, schema),
897
1001
  status: component?.status === 'NEW' ? 'NEW' : schema.status
898
1002
  };
899
1003
  } else {
@@ -901,6 +1005,7 @@ const slice = undoRedo.createUndoRedoSlice({
901
1005
  const previousKind = contentType?.kind;
902
1006
  state.contentTypes[uid] = {
903
1007
  ...schema,
1008
+ ...mergeRenameState(contentType, schema),
904
1009
  status: contentType?.status === 'NEW' ? 'NEW' : schema.status
905
1010
  };
906
1011
  if (previousKind && schema.kind && schema.kind !== previousKind) {