@strapi/content-type-builder 5.56.0 → 5.58.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 (178) 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 +129 -2
  20. package/dist/admin/components/DataManager/reducer.js.map +1 -1
  21. package/dist/admin/components/DataManager/reducer.mjs +128 -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 +178 -70
  44. package/dist/admin/components/FormModal/FormModal.js.map +1 -1
  45. package/dist/admin/components/FormModal/FormModal.mjs +179 -71
  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 +24 -8
  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/cs.json.js +0 -2
  80. package/dist/admin/translations/cs.json.js.map +1 -1
  81. package/dist/admin/translations/cs.json.mjs +0 -2
  82. package/dist/admin/translations/cs.json.mjs.map +1 -1
  83. package/dist/admin/translations/de.json.js +0 -2
  84. package/dist/admin/translations/de.json.js.map +1 -1
  85. package/dist/admin/translations/de.json.mjs +0 -2
  86. package/dist/admin/translations/de.json.mjs.map +1 -1
  87. package/dist/admin/translations/en.json.js +12 -2
  88. package/dist/admin/translations/en.json.js.map +1 -1
  89. package/dist/admin/translations/en.json.mjs +12 -2
  90. package/dist/admin/translations/en.json.mjs.map +1 -1
  91. package/dist/admin/translations/ja.json.js +0 -2
  92. package/dist/admin/translations/ja.json.js.map +1 -1
  93. package/dist/admin/translations/ja.json.mjs +0 -2
  94. package/dist/admin/translations/ja.json.mjs.map +1 -1
  95. package/dist/admin/translations/ko.json.js +0 -2
  96. package/dist/admin/translations/ko.json.js.map +1 -1
  97. package/dist/admin/translations/ko.json.mjs +0 -2
  98. package/dist/admin/translations/ko.json.mjs.map +1 -1
  99. package/dist/admin/translations/nl.json.js +0 -2
  100. package/dist/admin/translations/nl.json.js.map +1 -1
  101. package/dist/admin/translations/nl.json.mjs +0 -2
  102. package/dist/admin/translations/nl.json.mjs.map +1 -1
  103. package/dist/admin/translations/pl.json.js +0 -2
  104. package/dist/admin/translations/pl.json.js.map +1 -1
  105. package/dist/admin/translations/pl.json.mjs +0 -2
  106. package/dist/admin/translations/pl.json.mjs.map +1 -1
  107. package/dist/admin/translations/ru.json.js +0 -2
  108. package/dist/admin/translations/ru.json.js.map +1 -1
  109. package/dist/admin/translations/ru.json.mjs +0 -2
  110. package/dist/admin/translations/ru.json.mjs.map +1 -1
  111. package/dist/admin/translations/sk.json.js +0 -2
  112. package/dist/admin/translations/sk.json.js.map +1 -1
  113. package/dist/admin/translations/sk.json.mjs +0 -2
  114. package/dist/admin/translations/sk.json.mjs.map +1 -1
  115. package/dist/server/config.js +24 -3
  116. package/dist/server/config.js.map +1 -1
  117. package/dist/server/config.mjs +21 -3
  118. package/dist/server/config.mjs.map +1 -1
  119. package/dist/server/controllers/schema.js +2 -2
  120. package/dist/server/controllers/schema.js.map +1 -1
  121. package/dist/server/controllers/schema.mjs +1 -1
  122. package/dist/server/controllers/schema.mjs.map +1 -1
  123. package/dist/server/controllers/validation/content-type.js +9 -11
  124. package/dist/server/controllers/validation/content-type.js.map +1 -1
  125. package/dist/server/controllers/validation/content-type.mjs +7 -9
  126. package/dist/server/controllers/validation/content-type.mjs.map +1 -1
  127. package/dist/server/controllers/validation/model-schema.js +2 -3
  128. package/dist/server/controllers/validation/model-schema.js.map +1 -1
  129. package/dist/server/controllers/validation/model-schema.mjs +1 -2
  130. package/dist/server/controllers/validation/model-schema.mjs.map +1 -1
  131. package/dist/server/controllers/validation/relations.js +1 -2
  132. package/dist/server/controllers/validation/relations.js.map +1 -1
  133. package/dist/server/controllers/validation/relations.mjs +1 -2
  134. package/dist/server/controllers/validation/relations.mjs.map +1 -1
  135. package/dist/server/controllers/validation/schema.js +42 -23
  136. package/dist/server/controllers/validation/schema.js.map +1 -1
  137. package/dist/server/controllers/validation/schema.mjs +43 -24
  138. package/dist/server/controllers/validation/schema.mjs.map +1 -1
  139. package/dist/server/index.js +1 -1
  140. package/dist/server/index.js.map +1 -1
  141. package/dist/server/services/content-types.js +1 -2
  142. package/dist/server/services/content-types.js.map +1 -1
  143. package/dist/server/services/content-types.mjs +2 -3
  144. package/dist/server/services/content-types.mjs.map +1 -1
  145. package/dist/server/services/migration-builder/index.js +580 -0
  146. package/dist/server/services/migration-builder/index.js.map +1 -0
  147. package/dist/server/services/migration-builder/index.mjs +573 -0
  148. package/dist/server/services/migration-builder/index.mjs.map +1 -0
  149. package/dist/server/services/schema-builder/content-type-builder.js +31 -1
  150. package/dist/server/services/schema-builder/content-type-builder.js.map +1 -1
  151. package/dist/server/services/schema-builder/content-type-builder.mjs +31 -1
  152. package/dist/server/services/schema-builder/content-type-builder.mjs.map +1 -1
  153. package/dist/server/services/schema-mutation.js +30 -2
  154. package/dist/server/services/schema-mutation.js.map +1 -1
  155. package/dist/server/services/schema-mutation.mjs +10 -2
  156. package/dist/server/services/schema-mutation.mjs.map +1 -1
  157. package/dist/server/services/schema.js +312 -15
  158. package/dist/server/services/schema.js.map +1 -1
  159. package/dist/server/services/schema.mjs +305 -9
  160. package/dist/server/services/schema.mjs.map +1 -1
  161. package/dist/server/src/config.d.ts +23 -2
  162. package/dist/server/src/config.d.ts.map +1 -1
  163. package/dist/server/src/controllers/validation/content-type.d.ts +0 -1
  164. package/dist/server/src/controllers/validation/content-type.d.ts.map +1 -1
  165. package/dist/server/src/controllers/validation/relations.d.ts.map +1 -1
  166. package/dist/server/src/controllers/validation/schema.d.ts +28 -0
  167. package/dist/server/src/controllers/validation/schema.d.ts.map +1 -1
  168. package/dist/server/src/index.d.ts +10 -2
  169. package/dist/server/src/index.d.ts.map +1 -1
  170. package/dist/server/src/services/content-types.d.ts.map +1 -1
  171. package/dist/server/src/services/migration-builder/index.d.ts +83 -0
  172. package/dist/server/src/services/migration-builder/index.d.ts.map +1 -0
  173. package/dist/server/src/services/schema-builder/content-type-builder.d.ts.map +1 -1
  174. package/dist/server/src/services/schema-mutation.d.ts +4 -2
  175. package/dist/server/src/services/schema-mutation.d.ts.map +1 -1
  176. package/dist/server/src/services/schema.d.ts +19 -0
  177. package/dist/server/src/services/schema.d.ts.map +1 -1
  178. 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,20 @@
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');
7
+ var conditions = require('../../utils/conditions.js');
6
8
  var getRelationType = require('../../utils/getRelationType.js');
7
9
  var makeUnique = require('../../utils/makeUnique.js');
8
10
  var undoRedo = require('./undoRedo.js');
9
11
  var contentStructure = require('./utils/contentStructure.js');
12
+ var isStorageCompatibleRename = require('./utils/isStorageCompatibleRename.js');
10
13
 
11
14
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
12
15
 
13
16
  var merge__default = /*#__PURE__*/_interopDefault(merge);
14
17
  var omit__default = /*#__PURE__*/_interopDefault(omit);
18
+ var uniq__default = /*#__PURE__*/_interopDefault(uniq);
15
19
 
16
20
  const initialState = {
17
21
  components: {},
@@ -80,6 +84,84 @@ const createAttribute = (properties)=>{
80
84
  status: 'NEW'
81
85
  };
82
86
  };
87
+ /**
88
+ * Records an attribute rename hop in the order the user performed it, so the
89
+ * server can replay the exact path as a data-preserving migration.
90
+ *
91
+ * - Only renames of fields that already exist in the database are recorded; a
92
+ * brand-new field (status NEW) has no data yet, so its renames are ignored.
93
+ * - A rename that also changes the field's type / relation / component is not
94
+ * recorded (see `isStorageCompatibleRename`).
95
+ * - Each hop (`previousName -> newName`) is appended verbatim. The recorded
96
+ * sequence is inherently collision-free because the CTB never allows two
97
+ * fields to share a name — a "swap" is expressed through the user's own
98
+ * intermediate-name hop, so no synthetic temp column is ever needed.
99
+ */ const recordRename = (type, previousAttribute, newAttribute)=>{
100
+ if (previousAttribute.status === 'NEW') {
101
+ return;
102
+ }
103
+ const oldName = previousAttribute.name;
104
+ const newName = newAttribute?.name;
105
+ if (!newName || oldName === newName) {
106
+ return;
107
+ }
108
+ if (!isStorageCompatibleRename.isStorageCompatibleRename(previousAttribute, newAttribute)) {
109
+ return;
110
+ }
111
+ if (!type.renames) {
112
+ type.renames = [];
113
+ }
114
+ type.renames.push({
115
+ oldName,
116
+ newName
117
+ });
118
+ };
119
+ /**
120
+ * Remembers the names of a rename hop the user declined to preserve data for,
121
+ * so the rest of that chain is declined without another prompt.
122
+ */ const recordDeclinedRename = (type, previousAttribute, newAttribute)=>{
123
+ const oldName = previousAttribute.name;
124
+ const newName = newAttribute?.name;
125
+ if (!newName || oldName === newName) {
126
+ return;
127
+ }
128
+ type.declinedRenameNames = uniq__default.default([
129
+ ...type.declinedRenameNames ?? [],
130
+ oldName,
131
+ newName
132
+ ]);
133
+ };
134
+ /**
135
+ * Applies the rename consent carried by an edit: either records the hop or
136
+ * remembers it as declined. Never both.
137
+ */ const applyRenameConsent = (type, previousAttribute, newAttribute, { recordRename: shouldRecordRename = true, declineRename: shouldDecline = false })=>{
138
+ if (shouldDecline) {
139
+ recordDeclinedRename(type, previousAttribute, newAttribute);
140
+ return;
141
+ }
142
+ if (shouldRecordRename) {
143
+ recordRename(type, previousAttribute, newAttribute);
144
+ }
145
+ };
146
+ /**
147
+ * Points the conditions of the type's other fields at the new name of a renamed
148
+ * field. Runs for every rename, recorded or not, so the conditions follow the
149
+ * field whether or not its data is preserved.
150
+ */ const renameConditionVars = (type, previousAttribute, newAttribute)=>{
151
+ const oldName = previousAttribute.name;
152
+ const newName = newAttribute?.name;
153
+ if (!newName || oldName === newName) {
154
+ return;
155
+ }
156
+ type.attributes.forEach((attribute)=>{
157
+ conditions.getVisibleConditionEntries(attribute.conditions).forEach(({ fieldVar })=>{
158
+ if (fieldVar.var === oldName) {
159
+ fieldVar.var = newName;
160
+ setAttributeStatus(attribute, 'CHANGED');
161
+ }
162
+ });
163
+ });
164
+ };
83
165
  const setAttributeAt = (type, index, attribute)=>{
84
166
  const previousAttribute = type.attributes[index];
85
167
  const newStatus = getNewStatus(previousAttribute.status, 'CHANGED');
@@ -119,6 +201,30 @@ const removeAttributeByName = (type, name)=>{
119
201
  setAttributeStatus(attr, 'REMOVED');
120
202
  }
121
203
  };
204
+ /**
205
+ * Carries the pending rename state of `existing` over to a full replacement of
206
+ * the type (the AI chat's `applyChange`). Appending the incoming hops after the
207
+ * existing ones is order-correct: the chat transform diffs against the current
208
+ * reducer entry, whose attributes already carry the manual renames, so its hops
209
+ * start from where the manual hops ended.
210
+ */ const mergeRenameState = (existing, incoming)=>{
211
+ const renames = [
212
+ ...existing?.renames ?? [],
213
+ ...incoming.renames ?? []
214
+ ];
215
+ const declinedRenameNames = uniq__default.default([
216
+ ...existing?.declinedRenameNames ?? [],
217
+ ...incoming.declinedRenameNames ?? []
218
+ ]);
219
+ return {
220
+ ...renames.length > 0 ? {
221
+ renames
222
+ } : {},
223
+ ...declinedRenameNames.length > 0 ? {
224
+ declinedRenameNames
225
+ } : {}
226
+ };
227
+ };
122
228
  const updateType = (type, data)=>{
123
229
  merge__default.default(type, data);
124
230
  setStatus(type, 'CHANGED');
@@ -408,7 +514,7 @@ const slice = undoRedo.createUndoRedoSlice({
408
514
  attr.components = updatedComponents;
409
515
  },
410
516
  editAttribute: (state, action)=>{
411
- const { name, attributeToSet, forTarget, targetUid } = action.payload;
517
+ const { name, attributeToSet, forTarget, targetUid, recordRename, declineRename, recordTargetRename, declineTargetRename } = action.payload;
412
518
  const type = getType(state, {
413
519
  forTarget,
414
520
  targetUid
@@ -418,6 +524,11 @@ const slice = undoRedo.createUndoRedoSlice({
418
524
  return;
419
525
  }
420
526
  const previousAttribute = type.attributes[initialAttributeIndex];
527
+ applyRenameConsent(type, previousAttribute, attributeToSet, {
528
+ recordRename,
529
+ declineRename
530
+ });
531
+ renameConditionVars(type, previousAttribute, attributeToSet);
421
532
  setAttributeAt(type, initialAttributeIndex, attributeToSet);
422
533
  if (previousAttribute.type !== attributeToSet.type) {
423
534
  return;
@@ -457,6 +568,14 @@ const slice = undoRedo.createUndoRedoSlice({
457
568
  };
458
569
  // create or recreate(at old index) targetAttribute
459
570
  if (previousTargetAttributeIndex !== -1 && previousTarget.uid === newTarget.uid) {
571
+ // The counterpart is renamed on the target type: without a hop
572
+ // there, the side owning the join table would lose its links.
573
+ if (previousTargetAttribute) {
574
+ applyRenameConsent(newTarget, previousTargetAttribute, newTargetAttribute, {
575
+ recordRename: recordTargetRename,
576
+ declineRename: declineTargetRename
577
+ });
578
+ }
460
579
  // re-create at previousIdx if possible
461
580
  replaceAttributeAt(newTarget, previousTargetAttributeIndex, newTargetAttribute);
462
581
  } else {
@@ -468,14 +587,20 @@ const slice = undoRedo.createUndoRedoSlice({
468
587
  }
469
588
  },
470
589
  editCustomFieldAttribute: (state, action)=>{
471
- const { forTarget, targetUid, name, attributeToSet } = action.payload;
590
+ const { forTarget, targetUid, name, attributeToSet, recordRename, declineRename } = action.payload;
472
591
  const initialAttributeName = name;
473
592
  const type = getType(state, {
474
593
  forTarget,
475
594
  targetUid
476
595
  });
477
596
  const initialAttributeIndex = findAttributeIndex(type, initialAttributeName);
597
+ const previousAttribute = type.attributes[initialAttributeIndex];
478
598
  setAttributeAt(type, initialAttributeIndex, attributeToSet);
599
+ applyRenameConsent(type, previousAttribute, attributeToSet, {
600
+ recordRename,
601
+ declineRename
602
+ });
603
+ renameConditionVars(type, previousAttribute, attributeToSet);
479
604
  },
480
605
  reloadPlugin: ()=>{
481
606
  return initialState;
@@ -894,6 +1019,7 @@ const slice = undoRedo.createUndoRedoSlice({
894
1019
  const component = state.components[uid];
895
1020
  state.components[uid] = {
896
1021
  ...schema,
1022
+ ...mergeRenameState(component, schema),
897
1023
  status: component?.status === 'NEW' ? 'NEW' : schema.status
898
1024
  };
899
1025
  } else {
@@ -901,6 +1027,7 @@ const slice = undoRedo.createUndoRedoSlice({
901
1027
  const previousKind = contentType?.kind;
902
1028
  state.contentTypes[uid] = {
903
1029
  ...schema,
1030
+ ...mergeRenameState(contentType, schema),
904
1031
  status: contentType?.status === 'NEW' ? 'NEW' : schema.status
905
1032
  };
906
1033
  if (previousKind && schema.kind && schema.kind !== previousKind) {