@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.
- 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 +129 -2
- package/dist/admin/components/DataManager/reducer.js.map +1 -1
- package/dist/admin/components/DataManager/reducer.mjs +128 -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 +178 -70
- package/dist/admin/components/FormModal/FormModal.js.map +1 -1
- package/dist/admin/components/FormModal/FormModal.mjs +179 -71
- 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 +24 -8
- 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/cs.json.js +0 -2
- package/dist/admin/translations/cs.json.js.map +1 -1
- package/dist/admin/translations/cs.json.mjs +0 -2
- package/dist/admin/translations/cs.json.mjs.map +1 -1
- package/dist/admin/translations/de.json.js +0 -2
- package/dist/admin/translations/de.json.js.map +1 -1
- package/dist/admin/translations/de.json.mjs +0 -2
- package/dist/admin/translations/de.json.mjs.map +1 -1
- package/dist/admin/translations/en.json.js +12 -2
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +12 -2
- package/dist/admin/translations/en.json.mjs.map +1 -1
- package/dist/admin/translations/ja.json.js +0 -2
- package/dist/admin/translations/ja.json.js.map +1 -1
- package/dist/admin/translations/ja.json.mjs +0 -2
- package/dist/admin/translations/ja.json.mjs.map +1 -1
- package/dist/admin/translations/ko.json.js +0 -2
- package/dist/admin/translations/ko.json.js.map +1 -1
- package/dist/admin/translations/ko.json.mjs +0 -2
- package/dist/admin/translations/ko.json.mjs.map +1 -1
- package/dist/admin/translations/nl.json.js +0 -2
- package/dist/admin/translations/nl.json.js.map +1 -1
- package/dist/admin/translations/nl.json.mjs +0 -2
- package/dist/admin/translations/nl.json.mjs.map +1 -1
- package/dist/admin/translations/pl.json.js +0 -2
- package/dist/admin/translations/pl.json.js.map +1 -1
- package/dist/admin/translations/pl.json.mjs +0 -2
- package/dist/admin/translations/pl.json.mjs.map +1 -1
- package/dist/admin/translations/ru.json.js +0 -2
- package/dist/admin/translations/ru.json.js.map +1 -1
- package/dist/admin/translations/ru.json.mjs +0 -2
- package/dist/admin/translations/ru.json.mjs.map +1 -1
- package/dist/admin/translations/sk.json.js +0 -2
- package/dist/admin/translations/sk.json.js.map +1 -1
- package/dist/admin/translations/sk.json.mjs +0 -2
- package/dist/admin/translations/sk.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 +312 -15
- package/dist/server/services/schema.js.map +1 -1
- package/dist/server/services/schema.mjs +305 -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,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) {
|