@strapi/admin 4.7.2-exp.175f7ac70ee76d6c825e4429e15fc85ee78d23bb → 4.8.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/admin/src/content-manager/components/ComponentInitializer/index.js +1 -1
- package/admin/src/content-manager/components/EditViewDataManagerProvider/index.js +3 -31
- package/admin/src/content-manager/components/EditViewDataManagerProvider/reducer.js +65 -134
- package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/findAllAndReplace.js +85 -0
- package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/index.js +1 -2
- package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/schema.js +7 -1
- package/admin/src/content-manager/components/NonRepeatableComponent/index.js +1 -1
- package/admin/src/content-manager/components/RelationInput/RelationInput.js +1 -2
- package/admin/src/content-manager/components/RelationInputDataManager/RelationInputDataManager.js +39 -33
- package/admin/src/content-manager/hooks/useRelation/useRelation.js +2 -2
- package/admin/src/content-manager/pages/EditView/Header/index.js +1 -1
- package/admin/src/content-manager/utils/createDefaultForm.js +0 -8
- package/admin/src/pages/AuthPage/components/Register/index.js +1 -1
- package/admin/src/pages/SettingsPage/components/Tokens/FormHead/index.js +1 -0
- package/admin/src/pages/SettingsPage/components/Tokens/Table/index.js +2 -2
- package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/schema.js +1 -1
- package/admin/src/pages/SettingsPage/pages/Roles/CreatePage/index.js +266 -4
- package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ConditionsModal/ActionRow/index.js +1 -2
- package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/Collapse/index.js +2 -3
- package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/CollapsePropertyMatrix/ActionRow/index.js +2 -3
- package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/CollapsePropertyMatrix/SubActionRow/index.js +2 -3
- package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/GlobalActions/index.js +9 -4
- package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/PluginsAndSettings/SubCategory/index.js +3 -7
- package/admin/src/pages/SettingsPage/pages/Roles/ListPage/index.js +303 -124
- package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/utils/schema.js +1 -1
- package/admin/src/pages/SettingsPage/utils/defaultRoutes.js +18 -10
- package/admin/src/translations/ca.json +7 -13
- package/admin/src/translations/de.json +0 -6
- package/admin/src/translations/dk.json +0 -6
- package/admin/src/translations/en.json +0 -6
- package/admin/src/translations/es.json +0 -6
- package/admin/src/translations/eu.json +165 -171
- package/admin/src/translations/fr.json +0 -6
- package/admin/src/translations/gu.json +0 -6
- package/admin/src/translations/he.json +0 -6
- package/admin/src/translations/hi.json +0 -6
- package/admin/src/translations/hu.json +0 -6
- package/admin/src/translations/id.json +0 -6
- package/admin/src/translations/it.json +0 -6
- package/admin/src/translations/ja.json +0 -6
- package/admin/src/translations/ko.json +0 -6
- package/admin/src/translations/ml.json +0 -6
- package/admin/src/translations/nl.json +0 -6
- package/admin/src/translations/no.json +0 -6
- package/admin/src/translations/pl.json +0 -6
- package/admin/src/translations/pt-BR.json +0 -6
- package/admin/src/translations/ru.json +0 -6
- package/admin/src/translations/sa.json +0 -6
- package/admin/src/translations/sk.json +0 -6
- package/admin/src/translations/sv.json +0 -6
- package/admin/src/translations/th.json +0 -6
- package/admin/src/translations/tr.json +0 -6
- package/admin/src/translations/zh-Hans.json +0 -6
- package/admin/src/translations/zh.json +0 -6
- package/build/{4649.daa290f6.chunk.js → 4649.33220ac3.chunk.js} +2 -2
- package/build/{6891.ef7464be.chunk.js → 7112.2bf13da3.chunk.js} +6 -6
- package/build/7259.3675c199.chunk.js +1 -0
- package/build/{3094.1cac9087.chunk.js → 8580.0aa21940.chunk.js} +5 -5
- package/build/{Admin-authenticatedApp.25bdcdc0.chunk.js → Admin-authenticatedApp.5abacdd4.chunk.js} +4 -4
- package/build/Admin_settingsPage.caf3b9ab.chunk.js +9 -0
- package/build/{admin-app.d9d96db4.chunk.js → admin-app.4b313104.chunk.js} +2 -2
- package/build/admin-edit-roles-page.3b196317.chunk.js +216 -0
- package/build/{admin-edit-users.48031e30.chunk.js → admin-edit-users.af3b0f15.chunk.js} +1 -1
- package/build/admin-roles-list.0ad504a7.chunk.js +2 -0
- package/build/{admin-users.77b4188a.chunk.js → admin-users.af8c3123.chunk.js} +1 -1
- package/build/api-tokens-list-page.93f24348.chunk.js +16 -0
- package/build/ca-json.43e14418.chunk.js +1 -0
- package/build/content-manager.84afc839.chunk.js +1139 -0
- package/build/{content-type-builder.cdd117c3.chunk.js → content-type-builder.55dac849.chunk.js} +1 -1
- package/build/de-json.fcac7381.chunk.js +1 -0
- package/build/dk-json.e34cad0d.chunk.js +1 -0
- package/build/{en-json.e688dfe2.chunk.js → en-json.01a88a30.chunk.js} +1 -1
- package/build/es-json.715b6fd8.chunk.js +1 -0
- package/build/eu-json.fb17c8f9.chunk.js +1 -0
- package/build/fr-json.f66c3211.chunk.js +1 -0
- package/build/gu-json.4d667d0c.chunk.js +1 -0
- package/build/{he-json.f0de8cdb.chunk.js → he-json.3cf0b48a.chunk.js} +1 -1
- package/build/{hi-json.14a17920.chunk.js → hi-json.323be97d.chunk.js} +1 -1
- package/build/{hu-json.33172d09.chunk.js → hu-json.fe71e6c8.chunk.js} +1 -1
- package/build/id-json.41e07c46.chunk.js +1 -0
- package/build/index.html +1 -1
- package/build/it-json.bfe27ed8.chunk.js +1 -0
- package/build/ja-json.81b6d1e3.chunk.js +1 -0
- package/build/ko-json.4539f4ba.chunk.js +1 -0
- package/build/main.5b92c1d6.js +3809 -0
- package/build/{ml-json.3e69969b.chunk.js → ml-json.8988e374.chunk.js} +1 -1
- package/build/{nl-json.641782d5.chunk.js → nl-json.98345913.chunk.js} +1 -1
- package/build/{no-json.9b3cd181.chunk.js → no-json.19a2dbfa.chunk.js} +1 -1
- package/build/pl-json.59a5dab3.chunk.js +1 -0
- package/build/pt-BR-json.9410688b.chunk.js +1 -0
- package/build/{ru-json.c4a4f50b.chunk.js → ru-json.6a01cea6.chunk.js} +1 -1
- package/build/runtime~main.0bf1f619.js +2 -0
- package/build/sa-json.6359a11c.chunk.js +1 -0
- package/build/sk-json.2374f129.chunk.js +1 -0
- package/build/{sv-json.207afc0d.chunk.js → sv-json.ae6e71ea.chunk.js} +1 -1
- package/build/th-json.5f659396.chunk.js +1 -0
- package/build/{tr-json.f1a0d19d.chunk.js → tr-json.bac5dbd3.chunk.js} +1 -1
- package/build/transfer-tokens-list-page.ce37354b.chunk.js +16 -0
- package/build/zh-Hans-json.4c9706a6.chunk.js +1 -0
- package/build/{zh-json.085a34f4.chunk.js → zh-json.3529f1e5.chunk.js} +1 -1
- package/ee/server/controllers/index.js +0 -1
- package/ee/server/controllers/role.js +0 -39
- package/ee/server/controllers/user.js +1 -35
- package/ee/server/routes/index.js +0 -49
- package/ee/server/validation/role.js +28 -20
- package/package.json +13 -13
- package/server/bootstrap.js +0 -1
- package/server/controllers/api-token.js +4 -2
- package/server/controllers/permission.js +2 -4
- package/server/controllers/role.js +70 -23
- package/server/controllers/transfer/runner.js +5 -3
- package/server/domain/user.js +3 -0
- package/server/routes/roles.js +48 -0
- package/server/services/permission/permissions-manager/sanitize.js +2 -2
- package/server/services/permission/queries.js +1 -74
- package/server/strategies/data-transfer.js +3 -1
- package/server/validation/permission.js +1 -82
- package/server/validation/role.js +44 -0
- package/admin/src/assets/images/hot-air-balloon.png +0 -0
- package/admin/src/assets/images/upgrade-details.png +0 -0
- package/admin/src/components/UpgradePlanModal/index.js +0 -123
- package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/findLeafByPathAndReplace.js +0 -51
- package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/recursivelyFindPathsBasedOnCondition.js +0 -79
- package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ConditionsModal/ActionRow/utils/constants.js +0 -3
- package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/Collapse/utils/constants.js +0 -3
- package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/CollapsePropertyMatrix/ActionRow/utils/constants.js +0 -3
- package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/CollapsePropertyMatrix/SubActionRow/utils/constants.js +0 -3
- package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/GlobalActions/utils/constants.js +0 -3
- package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/PluginsAndSettings/SubCategory/utils/constants.js +0 -3
- package/build/617f9c948fa79e6d73bd.png +0 -0
- package/build/6d21938306785f176538.png +0 -0
- package/build/7259.63e91b59.chunk.js +0 -1
- package/build/Admin_settingsPage.6814a96e.chunk.js +0 -177
- package/build/admin-edit-roles-page.bf130aaf.chunk.js +0 -1
- package/build/api-tokens-list-page.149903c8.chunk.js +0 -16
- package/build/ca-json.59c4502c.chunk.js +0 -1
- package/build/content-manager.d792c194.chunk.js +0 -1139
- package/build/de-json.dbc2cf1b.chunk.js +0 -1
- package/build/dk-json.52f67b15.chunk.js +0 -1
- package/build/es-json.c40c57dd.chunk.js +0 -1
- package/build/eu-json.6702a0d2.chunk.js +0 -1
- package/build/fr-json.ea9ec573.chunk.js +0 -1
- package/build/gu-json.94f0d242.chunk.js +0 -1
- package/build/id-json.e0d83d41.chunk.js +0 -1
- package/build/it-json.8be59205.chunk.js +0 -1
- package/build/ja-json.3008b720.chunk.js +0 -1
- package/build/ko-json.7d2f95b1.chunk.js +0 -1
- package/build/main.64fe0c37.js +0 -3928
- package/build/pl-json.05814145.chunk.js +0 -1
- package/build/pt-BR-json.d72350de.chunk.js +0 -1
- package/build/runtime~main.122b5a09.js +0 -2
- package/build/sa-json.e5e7ccaf.chunk.js +0 -1
- package/build/sk-json.3529b8aa.chunk.js +0 -1
- package/build/th-json.f664b96d.chunk.js +0 -1
- package/build/transfer-tokens-list-page.c6f8039a.chunk.js +0 -16
- package/build/zh-Hans-json.993d085f.chunk.js +0 -1
- package/ee/admin/pages/SettingsPage/pages/Roles/CreatePage/index.js +0 -270
- package/ee/admin/pages/SettingsPage/pages/Roles/EditPage/components/ConditionsModal/ActionRow/utils/constants.js +0 -3
- package/ee/admin/pages/SettingsPage/pages/Roles/EditPage/components/ConditionsModal/ConditionsSelect/MenuList/utils/constants.js +0 -3
- package/ee/admin/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/Collapse/utils/constants.js +0 -3
- package/ee/admin/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/CollapsePropertyMatrix/ActionRow/utils/constants.js +0 -3
- package/ee/admin/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/CollapsePropertyMatrix/SubActionRow/utils/constants.js +0 -3
- package/ee/admin/pages/SettingsPage/pages/Roles/EditPage/components/GlobalActions/utils/constants.js +0 -3
- package/ee/admin/pages/SettingsPage/pages/Roles/EditPage/components/PluginsAndSettings/SubCategory/utils/constants.js +0 -3
- package/ee/admin/pages/SettingsPage/pages/Roles/ListPage/index.js +0 -376
- package/ee/admin/pages/SettingsPage/pages/Roles/ProtectedListPage/index.js +0 -12
- package/ee/server/controllers/permission.js +0 -21
- package/ee/server/validation/permission.js +0 -8
- package/server/domain/role.js +0 -29
- /package/{ee/admin → admin/src}/pages/SettingsPage/pages/Roles/CreatePage/utils/schema.js +0 -0
- /package/{ee/admin → admin/src}/pages/SettingsPage/pages/Roles/ListPage/reducer.js +0 -0
|
@@ -36,7 +36,7 @@ const ComponentInitializer = ({ error, isReadOnly, onClick }) => {
|
|
|
36
36
|
paddingBottom={9}
|
|
37
37
|
type="button"
|
|
38
38
|
>
|
|
39
|
-
<Flex direction="column"
|
|
39
|
+
<Flex direction="column" gap={2}>
|
|
40
40
|
<Flex justifyContent="center" style={{ cursor: isReadOnly ? 'not-allowed' : 'inherit' }}>
|
|
41
41
|
<IconWrapper>
|
|
42
42
|
<PlusCircle />
|
|
@@ -26,7 +26,7 @@ import { getTrad } from '../../utils';
|
|
|
26
26
|
import selectCrudReducer from '../../sharedReducers/crudReducer/selectors';
|
|
27
27
|
|
|
28
28
|
import reducer, { initialState } from './reducer';
|
|
29
|
-
import { cleanData, createYupSchema
|
|
29
|
+
import { cleanData, createYupSchema } from './utils';
|
|
30
30
|
import { clearSetModifiedDataOnly } from '../../sharedReducers/crudReducer/actions';
|
|
31
31
|
import { usePrev } from '../../hooks';
|
|
32
32
|
|
|
@@ -166,39 +166,11 @@ const EditViewDataManagerProvider = ({
|
|
|
166
166
|
currentContentTypeLayout?.attributes &&
|
|
167
167
|
!isEqual(previousInitialValues, initialValues)
|
|
168
168
|
) {
|
|
169
|
-
/**
|
|
170
|
-
* This will return an array of paths:
|
|
171
|
-
* ['many_to_one', 'one_to_many', 'one_to_one']
|
|
172
|
-
* it can also return a path to a relation:
|
|
173
|
-
* ['relation_component.categories']
|
|
174
|
-
*/
|
|
175
|
-
const relationalFieldPaths = recursivelyFindPathsBasedOnCondition(
|
|
176
|
-
components,
|
|
177
|
-
(value) => value.type === 'relation'
|
|
178
|
-
)(currentContentTypeLayout.attributes);
|
|
179
|
-
|
|
180
|
-
const componentPaths = recursivelyFindPathsBasedOnCondition(
|
|
181
|
-
components,
|
|
182
|
-
(value) => value.type === 'component' && !value.repeatable
|
|
183
|
-
)(currentContentTypeLayout.attributes);
|
|
184
|
-
|
|
185
|
-
const repeatableComponentPaths = recursivelyFindPathsBasedOnCondition(
|
|
186
|
-
components,
|
|
187
|
-
(value) => value.type === 'component' && value.repeatable
|
|
188
|
-
)(currentContentTypeLayout.attributes);
|
|
189
|
-
|
|
190
|
-
const dynamicZonePaths = recursivelyFindPathsBasedOnCondition(
|
|
191
|
-
components,
|
|
192
|
-
(value) => value.type === 'dynamiczone'
|
|
193
|
-
)(currentContentTypeLayout.attributes);
|
|
194
|
-
|
|
195
169
|
dispatch({
|
|
196
170
|
type: 'INIT_FORM',
|
|
197
171
|
initialValues,
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
repeatableComponentPaths,
|
|
201
|
-
dynamicZonePaths,
|
|
172
|
+
components,
|
|
173
|
+
attributes: currentContentTypeLayout.attributes,
|
|
202
174
|
setModifiedDataOnly,
|
|
203
175
|
});
|
|
204
176
|
|
|
@@ -5,16 +5,9 @@ import set from 'lodash/set';
|
|
|
5
5
|
import take from 'lodash/take';
|
|
6
6
|
import cloneDeep from 'lodash/cloneDeep';
|
|
7
7
|
import uniqBy from 'lodash/uniqBy';
|
|
8
|
-
import merge from 'lodash/merge';
|
|
9
|
-
import castArray from 'lodash/castArray';
|
|
10
|
-
import isNil from 'lodash/isNil';
|
|
11
8
|
import { generateNKeysBetween } from 'fractional-indexing';
|
|
12
9
|
|
|
13
|
-
import {
|
|
14
|
-
findLeafByPathAndReplace,
|
|
15
|
-
moveFields,
|
|
16
|
-
recursivelyFindPathsBasedOnCondition,
|
|
17
|
-
} from './utils';
|
|
10
|
+
import { findAllAndReplace, moveFields } from './utils';
|
|
18
11
|
import { getMaxTempKey } from '../../utils';
|
|
19
12
|
|
|
20
13
|
const initialState = {
|
|
@@ -38,35 +31,20 @@ const reducer = (state, action) =>
|
|
|
38
31
|
case 'ADD_NON_REPEATABLE_COMPONENT_TO_FIELD': {
|
|
39
32
|
const { componentLayoutData, allComponents } = action;
|
|
40
33
|
|
|
41
|
-
const relationPaths = recursivelyFindPathsBasedOnCondition(
|
|
42
|
-
allComponents,
|
|
43
|
-
(value) => value.type === 'relation'
|
|
44
|
-
)(componentLayoutData.attributes);
|
|
45
|
-
|
|
46
34
|
const defaultDataStructure = {
|
|
47
35
|
...state.componentsDataStructure[componentLayoutData.uid],
|
|
48
36
|
};
|
|
49
37
|
|
|
50
|
-
const
|
|
38
|
+
const findAllRelationsAndReplaceWithEmptyArray = findAllAndReplace(
|
|
51
39
|
allComponents,
|
|
52
|
-
(value) => value.type === '
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const componentDataStructure = relationPaths.reduce((acc, current) => {
|
|
56
|
-
const [componentName] = current.split('.');
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Why do we do this? Because if a repeatable component
|
|
60
|
-
* has another repeatable component inside of it we
|
|
61
|
-
* don't need to attach the array at this point because that will be
|
|
62
|
-
* done again deeper in the nest.
|
|
63
|
-
*/
|
|
64
|
-
if (!repeatableFields.includes(componentName)) {
|
|
65
|
-
set(acc, current, []);
|
|
66
|
-
}
|
|
40
|
+
(value) => value.type === 'relation',
|
|
41
|
+
[]
|
|
42
|
+
);
|
|
67
43
|
|
|
68
|
-
|
|
69
|
-
|
|
44
|
+
const componentDataStructure = findAllRelationsAndReplaceWithEmptyArray(
|
|
45
|
+
defaultDataStructure,
|
|
46
|
+
componentLayoutData.attributes
|
|
47
|
+
);
|
|
70
48
|
|
|
71
49
|
set(draftState, ['modifiedData', ...action.keys], componentDataStructure);
|
|
72
50
|
|
|
@@ -98,49 +76,16 @@ const reducer = (state, action) =>
|
|
|
98
76
|
__temp_key__: getMaxTempKey(currentValue) + 1,
|
|
99
77
|
};
|
|
100
78
|
|
|
101
|
-
const
|
|
102
|
-
allComponents,
|
|
103
|
-
(value) => value.type === 'relation'
|
|
104
|
-
)(componentLayoutData.attributes);
|
|
105
|
-
|
|
106
|
-
const repeatableFields = recursivelyFindPathsBasedOnCondition(
|
|
107
|
-
allComponents,
|
|
108
|
-
(value) => value.type === 'component' && value.repeatable
|
|
109
|
-
)(componentLayoutData.attributes);
|
|
110
|
-
|
|
111
|
-
const nonRepeatableComponentPaths = recursivelyFindPathsBasedOnCondition(
|
|
79
|
+
const findAllRelationsAndReplaceWithEmptyArray = findAllAndReplace(
|
|
112
80
|
allComponents,
|
|
113
|
-
(value) => value.type === '
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const componentDataStructure = relationPaths.reduce((acc, current) => {
|
|
117
|
-
const [componentName] = current.split('.');
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Why do we do this? Because if a repeatable component
|
|
121
|
-
* has another repeatable component inside of it we
|
|
122
|
-
* don't need to attach the array at this point because that will be
|
|
123
|
-
* done again deeper in the nest.
|
|
124
|
-
*
|
|
125
|
-
* We also need to handle cases with single components nested within
|
|
126
|
-
* repeatables by checking that the relation path does not match a
|
|
127
|
-
* non-repeatable component path. This accounts for component
|
|
128
|
-
* structures such as:
|
|
129
|
-
* - outer_single_compo
|
|
130
|
-
* - level_one_repeatable
|
|
131
|
-
* - level_two_single_component
|
|
132
|
-
* - level_three_repeatable
|
|
133
|
-
*/
|
|
134
|
-
|
|
135
|
-
if (
|
|
136
|
-
!repeatableFields.includes(componentName) &&
|
|
137
|
-
!nonRepeatableComponentPaths.includes(componentName)
|
|
138
|
-
) {
|
|
139
|
-
set(acc, current, []);
|
|
140
|
-
}
|
|
81
|
+
(value) => value.type === 'relation',
|
|
82
|
+
[]
|
|
83
|
+
);
|
|
141
84
|
|
|
142
|
-
|
|
143
|
-
|
|
85
|
+
const componentDataStructure = findAllRelationsAndReplaceWithEmptyArray(
|
|
86
|
+
defaultDataStructure,
|
|
87
|
+
componentLayoutData.attributes
|
|
88
|
+
);
|
|
144
89
|
|
|
145
90
|
const newValue = Array.isArray(currentValue)
|
|
146
91
|
? [...currentValue, componentDataStructure]
|
|
@@ -156,11 +101,13 @@ const reducer = (state, action) =>
|
|
|
156
101
|
const initialDataRelations = get(state, initialDataPath);
|
|
157
102
|
const modifiedDataRelations = get(state, modifiedDataPath);
|
|
158
103
|
|
|
159
|
-
const valuesToLoad =
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
104
|
+
const valuesToLoad = !initialDataRelations
|
|
105
|
+
? value
|
|
106
|
+
: value.filter((relation) => {
|
|
107
|
+
return !initialDataRelations.some((initialDataRelation) => {
|
|
108
|
+
return initialDataRelation.id === relation.id;
|
|
109
|
+
});
|
|
110
|
+
});
|
|
164
111
|
|
|
165
112
|
const keys = generateNKeysBetween(
|
|
166
113
|
null,
|
|
@@ -261,14 +208,7 @@ const reducer = (state, action) =>
|
|
|
261
208
|
* but also every time you press publish.
|
|
262
209
|
*/
|
|
263
210
|
case 'INIT_FORM': {
|
|
264
|
-
const {
|
|
265
|
-
initialValues,
|
|
266
|
-
relationalFieldPaths = [],
|
|
267
|
-
componentPaths = [],
|
|
268
|
-
repeatableComponentPaths = [],
|
|
269
|
-
dynamicZonePaths = [],
|
|
270
|
-
setModifiedDataOnly,
|
|
271
|
-
} = action;
|
|
211
|
+
const { initialValues, components = {}, attributes = {}, setModifiedDataOnly } = action;
|
|
272
212
|
|
|
273
213
|
/**
|
|
274
214
|
* You can't mutate an actions value.
|
|
@@ -278,63 +218,54 @@ const reducer = (state, action) =>
|
|
|
278
218
|
*/
|
|
279
219
|
const data = cloneDeep(initialValues);
|
|
280
220
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
221
|
+
const findAllRelationsAndReplaceWithEmptyArray = findAllAndReplace(
|
|
222
|
+
components,
|
|
223
|
+
(value) => value.type === 'relation',
|
|
224
|
+
(_, { path }) => {
|
|
225
|
+
if (state.modifiedData?.id === data.id && get(state.modifiedData, path)) {
|
|
226
|
+
return get(state.modifiedData, path);
|
|
227
|
+
}
|
|
287
228
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
const [componentName] = currentPaths;
|
|
229
|
+
return [];
|
|
230
|
+
}
|
|
231
|
+
);
|
|
292
232
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
}
|
|
233
|
+
const mergedDataWithPreparedRelations = findAllRelationsAndReplaceWithEmptyArray(
|
|
234
|
+
data,
|
|
235
|
+
attributes
|
|
236
|
+
);
|
|
298
237
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
) {
|
|
319
|
-
/**
|
|
320
|
-
* if the componentName is a repeatable field or dynamic zone we collect the list of paths e.g.
|
|
321
|
-
* ["repeatable_single_component_relation","categories"] and then reduce this
|
|
322
|
-
* recursively
|
|
323
|
-
*/
|
|
324
|
-
const findleaf = findLeafByPathAndReplace(currentPaths.slice(-1)[0], []);
|
|
325
|
-
currentPaths.reduce(findleaf, acc);
|
|
326
|
-
} else {
|
|
327
|
-
set(acc, currentPaths, []);
|
|
328
|
-
}
|
|
238
|
+
const findComponentsAndReplaceWithTempKey = findAllAndReplace(
|
|
239
|
+
components,
|
|
240
|
+
(value) =>
|
|
241
|
+
value.type === 'dynamiczone' || (value.type === 'component' && !value.repeatable),
|
|
242
|
+
(data) => {
|
|
243
|
+
/**
|
|
244
|
+
* If the data is an array, we have the dynamic zone if it's not, its a regular component.
|
|
245
|
+
*/
|
|
246
|
+
return Array.isArray(data)
|
|
247
|
+
? data.map((datum, index) => ({
|
|
248
|
+
...datum,
|
|
249
|
+
__temp_key__: index,
|
|
250
|
+
}))
|
|
251
|
+
: {
|
|
252
|
+
...data,
|
|
253
|
+
__temp_key__: 0,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
);
|
|
329
257
|
|
|
330
|
-
|
|
331
|
-
|
|
258
|
+
const mergedDataWithTmpKeys = findComponentsAndReplaceWithTempKey(
|
|
259
|
+
mergedDataWithPreparedRelations,
|
|
260
|
+
attributes,
|
|
261
|
+
{ ignoreFalseyValues: true }
|
|
262
|
+
);
|
|
332
263
|
|
|
333
264
|
if (!setModifiedDataOnly) {
|
|
334
|
-
draftState.initialData =
|
|
265
|
+
draftState.initialData = mergedDataWithTmpKeys;
|
|
335
266
|
}
|
|
336
267
|
|
|
337
|
-
draftState.modifiedData =
|
|
268
|
+
draftState.modifiedData = mergedDataWithTmpKeys;
|
|
338
269
|
|
|
339
270
|
draftState.formErrors = {};
|
|
340
271
|
|
package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/findAllAndReplace.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef Attribute
|
|
3
|
+
* @type { { type: string; repeatable: boolean }}
|
|
4
|
+
*
|
|
5
|
+
* @typedef Attributes
|
|
6
|
+
* @type {{ [key: string]: Attribute }}
|
|
7
|
+
*
|
|
8
|
+
* @typedef ReplacementFn
|
|
9
|
+
* @type {<TData extends object, TKey extends string>(data: TData[TKey], { path: string[]; parent: TData }) => any}
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* This function will recursively find everything and replace it with a value
|
|
14
|
+
* based on the boolean return of the predicate function e.g. `type === 'relation'`.
|
|
15
|
+
*
|
|
16
|
+
* If you provide a function it will call that function with data value you're replacing with
|
|
17
|
+
* a second argument with the path to the value and it's parent.
|
|
18
|
+
*
|
|
19
|
+
* It's original use was for the preperation of action items for the INIT_FORM action. It requires
|
|
20
|
+
* knowledge of the `components` in the entity, however `components` doesn't change nor does the predicate
|
|
21
|
+
* function so we don't need to pass it everytime hence why it's curried.
|
|
22
|
+
*
|
|
23
|
+
* @type {<TData extends object = object>(data: { [key: string]: { attributes: Attributes } }, predicate?: (value: Attribute, { path: string[]; parent: TData }) => boolean, replacement?: ReplacementFn<TData, keyof TKey> | any) => (data: TData, attributes: Attributes) => TData}
|
|
24
|
+
*/
|
|
25
|
+
const findAllAndReplaceSetup = (components, predicate = () => false, replacement = undefined) => {
|
|
26
|
+
/**
|
|
27
|
+
* @type {<TData extends object = object>(data: TData, attributes: Attributes, options?: { ignoreFalseyValues?: boolean}) => TData}
|
|
28
|
+
*/
|
|
29
|
+
const findAllAndReplace = (data, attributes, { ignoreFalseyValues = false, path = [] } = {}) => {
|
|
30
|
+
return Object.entries(attributes).reduce(
|
|
31
|
+
(acc, [key, value]) => {
|
|
32
|
+
if (
|
|
33
|
+
ignoreFalseyValues &&
|
|
34
|
+
(acc === null || acc === undefined || acc[key] === undefined || acc[key] === null)
|
|
35
|
+
) {
|
|
36
|
+
return acc;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (predicate(value, { path: [...path, key], parent: acc })) {
|
|
40
|
+
acc[key] =
|
|
41
|
+
typeof replacement === 'function'
|
|
42
|
+
? replacement(acc[key], { path: [...path, key], parent: acc })
|
|
43
|
+
: replacement;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (value.type === 'component') {
|
|
47
|
+
const componentAttributes = components[value.component].attributes;
|
|
48
|
+
|
|
49
|
+
if (!value.repeatable) {
|
|
50
|
+
acc[key] = findAllAndReplace(acc[key], componentAttributes, {
|
|
51
|
+
ignoreFalseyValues,
|
|
52
|
+
path: [...path, key],
|
|
53
|
+
});
|
|
54
|
+
} else if (value.repeatable && Array.isArray(acc[key])) {
|
|
55
|
+
acc[key] = acc[key].map((datum, index) => {
|
|
56
|
+
const data = findAllAndReplace(datum, componentAttributes, {
|
|
57
|
+
ignoreFalseyValues,
|
|
58
|
+
path: [...path, key, index],
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
return data;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
} else if (value.type === 'dynamiczone' && Array.isArray(acc[key])) {
|
|
65
|
+
acc[key] = acc[key].map((datum, index) => {
|
|
66
|
+
const componentAttributes = components[datum.__component].attributes;
|
|
67
|
+
const data = findAllAndReplace(datum, componentAttributes, {
|
|
68
|
+
ignoreFalseyValues,
|
|
69
|
+
path: [...path, key, index],
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return data;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return acc;
|
|
77
|
+
},
|
|
78
|
+
{ ...data }
|
|
79
|
+
);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
return findAllAndReplace;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export { findAllAndReplaceSetup as findAllAndReplace };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export { default as moveFields } from './moveFields';
|
|
2
2
|
export { default as cleanData } from './cleanData';
|
|
3
3
|
export { default as createYupSchema } from './schema';
|
|
4
|
-
export {
|
|
5
|
-
export { findLeafByPathAndReplace } from './findLeafByPathAndReplace';
|
|
4
|
+
export { findAllAndReplace } from './findAllAndReplace';
|
|
@@ -216,6 +216,10 @@ const createYupSchemaAttribute = (type, validations, options) => {
|
|
|
216
216
|
schema = yup
|
|
217
217
|
.mixed(errorsTrads.json)
|
|
218
218
|
.test('isJSON', errorsTrads.json, (value) => {
|
|
219
|
+
if (!value || !value.length) {
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
|
|
219
223
|
try {
|
|
220
224
|
JSON.parse(value);
|
|
221
225
|
|
|
@@ -226,7 +230,9 @@ const createYupSchemaAttribute = (type, validations, options) => {
|
|
|
226
230
|
})
|
|
227
231
|
.nullable()
|
|
228
232
|
.test('required', errorsTrads.required, (value) => {
|
|
229
|
-
if (validations.required && !value.length)
|
|
233
|
+
if (validations.required && (!value || !value.length)) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
230
236
|
|
|
231
237
|
return true;
|
|
232
238
|
});
|
|
@@ -29,7 +29,7 @@ const NonRepeatableComponent = ({ componentUid, isFromDynamicZone, isNested, nam
|
|
|
29
29
|
hasRadius={isNested}
|
|
30
30
|
borderColor={isNested ? 'neutral200' : ''}
|
|
31
31
|
>
|
|
32
|
-
<Flex direction="column" alignItems="stretch"
|
|
32
|
+
<Flex direction="column" alignItems="stretch" gap={6}>
|
|
33
33
|
{fields.map((fieldRow, key) => {
|
|
34
34
|
return (
|
|
35
35
|
<Grid gap={4} key={key}>
|
|
@@ -107,8 +107,7 @@ const RelationInput = ({
|
|
|
107
107
|
[totalNumberOfRelations, numberOfRelationsToDisplay]
|
|
108
108
|
);
|
|
109
109
|
|
|
110
|
-
const shouldDisplayLoadMoreButton =
|
|
111
|
-
(!!labelLoadMore && paginatedRelations.hasNextPage) || paginatedRelations.isLoading;
|
|
110
|
+
const shouldDisplayLoadMoreButton = !!labelLoadMore && paginatedRelations.hasNextPage;
|
|
112
111
|
|
|
113
112
|
const options = useMemo(
|
|
114
113
|
() =>
|
package/admin/src/content-manager/components/RelationInputDataManager/RelationInputDataManager.js
CHANGED
|
@@ -57,41 +57,47 @@ export const RelationInputDataManager = ({
|
|
|
57
57
|
|
|
58
58
|
const currentLastPage = Math.ceil(get(initialData, name, []).length / RELATIONS_TO_DISPLAY);
|
|
59
59
|
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
60
|
+
const { relations, search, searchFor } = useRelation(
|
|
61
|
+
[slug, initialDataPath.join('.'), modifiedData.id, defaultParams],
|
|
62
|
+
{
|
|
63
|
+
relation: {
|
|
64
|
+
enabled: !!endpoints.relation,
|
|
65
|
+
endpoint: endpoints.relation,
|
|
66
|
+
pageGoal: currentLastPage,
|
|
67
|
+
pageParams: {
|
|
68
|
+
...defaultParams,
|
|
69
|
+
pageSize: RELATIONS_TO_DISPLAY,
|
|
70
|
+
},
|
|
71
|
+
onLoad(value) {
|
|
72
|
+
relationLoad({
|
|
73
|
+
target: {
|
|
74
|
+
initialDataPath: ['initialData', ...initialDataPath],
|
|
75
|
+
modifiedDataPath: ['modifiedData', ...nameSplit],
|
|
76
|
+
value,
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
},
|
|
80
|
+
normalizeArguments: {
|
|
81
|
+
mainFieldName: mainField.name,
|
|
82
|
+
shouldAddLink: shouldDisplayRelationLink,
|
|
83
|
+
targetModel,
|
|
84
|
+
},
|
|
83
85
|
},
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
86
|
+
search: {
|
|
87
|
+
endpoint: endpoints.search,
|
|
88
|
+
pageParams: {
|
|
89
|
+
...defaultParams,
|
|
90
|
+
// eslint-disable-next-line no-nested-ternary
|
|
91
|
+
entityId: isCreatingEntry
|
|
92
|
+
? undefined
|
|
93
|
+
: isComponentRelation
|
|
94
|
+
? componentId
|
|
95
|
+
: initialData.id,
|
|
96
|
+
pageSize: SEARCH_RESULTS_TO_DISPLAY,
|
|
97
|
+
},
|
|
92
98
|
},
|
|
93
|
-
}
|
|
94
|
-
|
|
99
|
+
}
|
|
100
|
+
);
|
|
95
101
|
|
|
96
102
|
const isMorph = useMemo(() => relationType.toLowerCase().includes('morph'), [relationType]);
|
|
97
103
|
const toOneRelation = [
|
|
@@ -49,7 +49,7 @@ export const useRelation = (cacheKey, { relation, search }) => {
|
|
|
49
49
|
|
|
50
50
|
const { onLoad: onLoadRelations, normalizeArguments = {} } = relation;
|
|
51
51
|
|
|
52
|
-
const relationsRes = useInfiniteQuery(['relation', cacheKey], fetchRelations, {
|
|
52
|
+
const relationsRes = useInfiniteQuery(['relation', ...cacheKey], fetchRelations, {
|
|
53
53
|
cacheTime: 0,
|
|
54
54
|
enabled: relation.enabled,
|
|
55
55
|
/**
|
|
@@ -138,7 +138,7 @@ export const useRelation = (cacheKey, { relation, search }) => {
|
|
|
138
138
|
}, [status, onLoadRelationsCallback, data]);
|
|
139
139
|
|
|
140
140
|
const searchRes = useInfiniteQuery(
|
|
141
|
-
['relation', cacheKey, 'search', JSON.stringify(searchParams)],
|
|
141
|
+
['relation', ...cacheKey, 'search', JSON.stringify(searchParams)],
|
|
142
142
|
fetchSearch,
|
|
143
143
|
{
|
|
144
144
|
enabled: Object.keys(searchParams).length > 0,
|
|
@@ -167,7 +167,7 @@ const Header = ({
|
|
|
167
167
|
isOpen={showWarningUnpublish}
|
|
168
168
|
>
|
|
169
169
|
<DialogBody icon={<ExclamationMarkCircle />}>
|
|
170
|
-
<Flex direction="column" alignItems="stretch"
|
|
170
|
+
<Flex direction="column" alignItems="stretch" gap={2}>
|
|
171
171
|
<Flex justifyContent="center" style={{ textAlign: 'center' }}>
|
|
172
172
|
<Typography id="confirm-description">
|
|
173
173
|
{formatMessage(
|
|
@@ -5,14 +5,6 @@ const createDefaultForm = (attributes, allComponentsSchema) => {
|
|
|
5
5
|
const attribute = get(attributes, [current], {});
|
|
6
6
|
const { default: defaultValue, component, type, required, min, repeatable } = attribute;
|
|
7
7
|
|
|
8
|
-
if (type === 'json') {
|
|
9
|
-
acc[current] = null;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
if (type === 'json' && required === true) {
|
|
13
|
-
acc[current] = {};
|
|
14
|
-
}
|
|
15
|
-
|
|
16
8
|
if (defaultValue !== undefined) {
|
|
17
9
|
acc[current] = defaultValue;
|
|
18
10
|
}
|
|
@@ -158,7 +158,7 @@ const Register = ({ authType, fieldsToDisable, noSignin, onSubmit, schema }) =>
|
|
|
158
158
|
</Typography>
|
|
159
159
|
</CenteredBox>
|
|
160
160
|
</Column>
|
|
161
|
-
<Flex direction="column" alignItems="stretch"
|
|
161
|
+
<Flex direction="column" alignItems="stretch" gap={6}>
|
|
162
162
|
<Grid gap={4}>
|
|
163
163
|
<GridItem col={6}>
|
|
164
164
|
<TextInput
|
|
@@ -63,8 +63,8 @@ const Table = ({
|
|
|
63
63
|
condition: canUpdate,
|
|
64
64
|
})}
|
|
65
65
|
>
|
|
66
|
-
<Td>
|
|
67
|
-
<Typography textColor="neutral800" fontWeight="bold">
|
|
66
|
+
<Td maxWidth={pxToRem(250)}>
|
|
67
|
+
<Typography textColor="neutral800" fontWeight="bold" ellipsis>
|
|
68
68
|
{token.name}
|
|
69
69
|
</Typography>
|
|
70
70
|
</Td>
|
|
@@ -2,7 +2,7 @@ import * as yup from 'yup';
|
|
|
2
2
|
import { translatedErrors } from '@strapi/helper-plugin';
|
|
3
3
|
|
|
4
4
|
const schema = yup.object().shape({
|
|
5
|
-
name: yup.string(translatedErrors.string).required(translatedErrors.required),
|
|
5
|
+
name: yup.string(translatedErrors.string).max(100).required(translatedErrors.required),
|
|
6
6
|
type: yup
|
|
7
7
|
.string(translatedErrors.string)
|
|
8
8
|
.oneOf(['read-only', 'full-access', 'custom'])
|