@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.
Files changed (171) hide show
  1. package/admin/src/content-manager/components/ComponentInitializer/index.js +1 -1
  2. package/admin/src/content-manager/components/EditViewDataManagerProvider/index.js +3 -31
  3. package/admin/src/content-manager/components/EditViewDataManagerProvider/reducer.js +65 -134
  4. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/findAllAndReplace.js +85 -0
  5. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/index.js +1 -2
  6. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/schema.js +7 -1
  7. package/admin/src/content-manager/components/NonRepeatableComponent/index.js +1 -1
  8. package/admin/src/content-manager/components/RelationInput/RelationInput.js +1 -2
  9. package/admin/src/content-manager/components/RelationInputDataManager/RelationInputDataManager.js +39 -33
  10. package/admin/src/content-manager/hooks/useRelation/useRelation.js +2 -2
  11. package/admin/src/content-manager/pages/EditView/Header/index.js +1 -1
  12. package/admin/src/content-manager/utils/createDefaultForm.js +0 -8
  13. package/admin/src/pages/AuthPage/components/Register/index.js +1 -1
  14. package/admin/src/pages/SettingsPage/components/Tokens/FormHead/index.js +1 -0
  15. package/admin/src/pages/SettingsPage/components/Tokens/Table/index.js +2 -2
  16. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/utils/schema.js +1 -1
  17. package/admin/src/pages/SettingsPage/pages/Roles/CreatePage/index.js +266 -4
  18. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ConditionsModal/ActionRow/index.js +1 -2
  19. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/Collapse/index.js +2 -3
  20. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/CollapsePropertyMatrix/ActionRow/index.js +2 -3
  21. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/CollapsePropertyMatrix/SubActionRow/index.js +2 -3
  22. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/GlobalActions/index.js +9 -4
  23. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/PluginsAndSettings/SubCategory/index.js +3 -7
  24. package/admin/src/pages/SettingsPage/pages/Roles/ListPage/index.js +303 -124
  25. package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/utils/schema.js +1 -1
  26. package/admin/src/pages/SettingsPage/utils/defaultRoutes.js +18 -10
  27. package/admin/src/translations/ca.json +7 -13
  28. package/admin/src/translations/de.json +0 -6
  29. package/admin/src/translations/dk.json +0 -6
  30. package/admin/src/translations/en.json +0 -6
  31. package/admin/src/translations/es.json +0 -6
  32. package/admin/src/translations/eu.json +165 -171
  33. package/admin/src/translations/fr.json +0 -6
  34. package/admin/src/translations/gu.json +0 -6
  35. package/admin/src/translations/he.json +0 -6
  36. package/admin/src/translations/hi.json +0 -6
  37. package/admin/src/translations/hu.json +0 -6
  38. package/admin/src/translations/id.json +0 -6
  39. package/admin/src/translations/it.json +0 -6
  40. package/admin/src/translations/ja.json +0 -6
  41. package/admin/src/translations/ko.json +0 -6
  42. package/admin/src/translations/ml.json +0 -6
  43. package/admin/src/translations/nl.json +0 -6
  44. package/admin/src/translations/no.json +0 -6
  45. package/admin/src/translations/pl.json +0 -6
  46. package/admin/src/translations/pt-BR.json +0 -6
  47. package/admin/src/translations/ru.json +0 -6
  48. package/admin/src/translations/sa.json +0 -6
  49. package/admin/src/translations/sk.json +0 -6
  50. package/admin/src/translations/sv.json +0 -6
  51. package/admin/src/translations/th.json +0 -6
  52. package/admin/src/translations/tr.json +0 -6
  53. package/admin/src/translations/zh-Hans.json +0 -6
  54. package/admin/src/translations/zh.json +0 -6
  55. package/build/{4649.daa290f6.chunk.js → 4649.33220ac3.chunk.js} +2 -2
  56. package/build/{6891.ef7464be.chunk.js → 7112.2bf13da3.chunk.js} +6 -6
  57. package/build/7259.3675c199.chunk.js +1 -0
  58. package/build/{3094.1cac9087.chunk.js → 8580.0aa21940.chunk.js} +5 -5
  59. package/build/{Admin-authenticatedApp.25bdcdc0.chunk.js → Admin-authenticatedApp.5abacdd4.chunk.js} +4 -4
  60. package/build/Admin_settingsPage.caf3b9ab.chunk.js +9 -0
  61. package/build/{admin-app.d9d96db4.chunk.js → admin-app.4b313104.chunk.js} +2 -2
  62. package/build/admin-edit-roles-page.3b196317.chunk.js +216 -0
  63. package/build/{admin-edit-users.48031e30.chunk.js → admin-edit-users.af3b0f15.chunk.js} +1 -1
  64. package/build/admin-roles-list.0ad504a7.chunk.js +2 -0
  65. package/build/{admin-users.77b4188a.chunk.js → admin-users.af8c3123.chunk.js} +1 -1
  66. package/build/api-tokens-list-page.93f24348.chunk.js +16 -0
  67. package/build/ca-json.43e14418.chunk.js +1 -0
  68. package/build/content-manager.84afc839.chunk.js +1139 -0
  69. package/build/{content-type-builder.cdd117c3.chunk.js → content-type-builder.55dac849.chunk.js} +1 -1
  70. package/build/de-json.fcac7381.chunk.js +1 -0
  71. package/build/dk-json.e34cad0d.chunk.js +1 -0
  72. package/build/{en-json.e688dfe2.chunk.js → en-json.01a88a30.chunk.js} +1 -1
  73. package/build/es-json.715b6fd8.chunk.js +1 -0
  74. package/build/eu-json.fb17c8f9.chunk.js +1 -0
  75. package/build/fr-json.f66c3211.chunk.js +1 -0
  76. package/build/gu-json.4d667d0c.chunk.js +1 -0
  77. package/build/{he-json.f0de8cdb.chunk.js → he-json.3cf0b48a.chunk.js} +1 -1
  78. package/build/{hi-json.14a17920.chunk.js → hi-json.323be97d.chunk.js} +1 -1
  79. package/build/{hu-json.33172d09.chunk.js → hu-json.fe71e6c8.chunk.js} +1 -1
  80. package/build/id-json.41e07c46.chunk.js +1 -0
  81. package/build/index.html +1 -1
  82. package/build/it-json.bfe27ed8.chunk.js +1 -0
  83. package/build/ja-json.81b6d1e3.chunk.js +1 -0
  84. package/build/ko-json.4539f4ba.chunk.js +1 -0
  85. package/build/main.5b92c1d6.js +3809 -0
  86. package/build/{ml-json.3e69969b.chunk.js → ml-json.8988e374.chunk.js} +1 -1
  87. package/build/{nl-json.641782d5.chunk.js → nl-json.98345913.chunk.js} +1 -1
  88. package/build/{no-json.9b3cd181.chunk.js → no-json.19a2dbfa.chunk.js} +1 -1
  89. package/build/pl-json.59a5dab3.chunk.js +1 -0
  90. package/build/pt-BR-json.9410688b.chunk.js +1 -0
  91. package/build/{ru-json.c4a4f50b.chunk.js → ru-json.6a01cea6.chunk.js} +1 -1
  92. package/build/runtime~main.0bf1f619.js +2 -0
  93. package/build/sa-json.6359a11c.chunk.js +1 -0
  94. package/build/sk-json.2374f129.chunk.js +1 -0
  95. package/build/{sv-json.207afc0d.chunk.js → sv-json.ae6e71ea.chunk.js} +1 -1
  96. package/build/th-json.5f659396.chunk.js +1 -0
  97. package/build/{tr-json.f1a0d19d.chunk.js → tr-json.bac5dbd3.chunk.js} +1 -1
  98. package/build/transfer-tokens-list-page.ce37354b.chunk.js +16 -0
  99. package/build/zh-Hans-json.4c9706a6.chunk.js +1 -0
  100. package/build/{zh-json.085a34f4.chunk.js → zh-json.3529f1e5.chunk.js} +1 -1
  101. package/ee/server/controllers/index.js +0 -1
  102. package/ee/server/controllers/role.js +0 -39
  103. package/ee/server/controllers/user.js +1 -35
  104. package/ee/server/routes/index.js +0 -49
  105. package/ee/server/validation/role.js +28 -20
  106. package/package.json +13 -13
  107. package/server/bootstrap.js +0 -1
  108. package/server/controllers/api-token.js +4 -2
  109. package/server/controllers/permission.js +2 -4
  110. package/server/controllers/role.js +70 -23
  111. package/server/controllers/transfer/runner.js +5 -3
  112. package/server/domain/user.js +3 -0
  113. package/server/routes/roles.js +48 -0
  114. package/server/services/permission/permissions-manager/sanitize.js +2 -2
  115. package/server/services/permission/queries.js +1 -74
  116. package/server/strategies/data-transfer.js +3 -1
  117. package/server/validation/permission.js +1 -82
  118. package/server/validation/role.js +44 -0
  119. package/admin/src/assets/images/hot-air-balloon.png +0 -0
  120. package/admin/src/assets/images/upgrade-details.png +0 -0
  121. package/admin/src/components/UpgradePlanModal/index.js +0 -123
  122. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/findLeafByPathAndReplace.js +0 -51
  123. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/recursivelyFindPathsBasedOnCondition.js +0 -79
  124. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ConditionsModal/ActionRow/utils/constants.js +0 -3
  125. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/Collapse/utils/constants.js +0 -3
  126. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/CollapsePropertyMatrix/ActionRow/utils/constants.js +0 -3
  127. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/CollapsePropertyMatrix/SubActionRow/utils/constants.js +0 -3
  128. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/GlobalActions/utils/constants.js +0 -3
  129. package/admin/src/pages/SettingsPage/pages/Roles/EditPage/components/PluginsAndSettings/SubCategory/utils/constants.js +0 -3
  130. package/build/617f9c948fa79e6d73bd.png +0 -0
  131. package/build/6d21938306785f176538.png +0 -0
  132. package/build/7259.63e91b59.chunk.js +0 -1
  133. package/build/Admin_settingsPage.6814a96e.chunk.js +0 -177
  134. package/build/admin-edit-roles-page.bf130aaf.chunk.js +0 -1
  135. package/build/api-tokens-list-page.149903c8.chunk.js +0 -16
  136. package/build/ca-json.59c4502c.chunk.js +0 -1
  137. package/build/content-manager.d792c194.chunk.js +0 -1139
  138. package/build/de-json.dbc2cf1b.chunk.js +0 -1
  139. package/build/dk-json.52f67b15.chunk.js +0 -1
  140. package/build/es-json.c40c57dd.chunk.js +0 -1
  141. package/build/eu-json.6702a0d2.chunk.js +0 -1
  142. package/build/fr-json.ea9ec573.chunk.js +0 -1
  143. package/build/gu-json.94f0d242.chunk.js +0 -1
  144. package/build/id-json.e0d83d41.chunk.js +0 -1
  145. package/build/it-json.8be59205.chunk.js +0 -1
  146. package/build/ja-json.3008b720.chunk.js +0 -1
  147. package/build/ko-json.7d2f95b1.chunk.js +0 -1
  148. package/build/main.64fe0c37.js +0 -3928
  149. package/build/pl-json.05814145.chunk.js +0 -1
  150. package/build/pt-BR-json.d72350de.chunk.js +0 -1
  151. package/build/runtime~main.122b5a09.js +0 -2
  152. package/build/sa-json.e5e7ccaf.chunk.js +0 -1
  153. package/build/sk-json.3529b8aa.chunk.js +0 -1
  154. package/build/th-json.f664b96d.chunk.js +0 -1
  155. package/build/transfer-tokens-list-page.c6f8039a.chunk.js +0 -16
  156. package/build/zh-Hans-json.993d085f.chunk.js +0 -1
  157. package/ee/admin/pages/SettingsPage/pages/Roles/CreatePage/index.js +0 -270
  158. package/ee/admin/pages/SettingsPage/pages/Roles/EditPage/components/ConditionsModal/ActionRow/utils/constants.js +0 -3
  159. package/ee/admin/pages/SettingsPage/pages/Roles/EditPage/components/ConditionsModal/ConditionsSelect/MenuList/utils/constants.js +0 -3
  160. package/ee/admin/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/Collapse/utils/constants.js +0 -3
  161. package/ee/admin/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/CollapsePropertyMatrix/ActionRow/utils/constants.js +0 -3
  162. package/ee/admin/pages/SettingsPage/pages/Roles/EditPage/components/ContentTypeCollapse/CollapsePropertyMatrix/SubActionRow/utils/constants.js +0 -3
  163. package/ee/admin/pages/SettingsPage/pages/Roles/EditPage/components/GlobalActions/utils/constants.js +0 -3
  164. package/ee/admin/pages/SettingsPage/pages/Roles/EditPage/components/PluginsAndSettings/SubCategory/utils/constants.js +0 -3
  165. package/ee/admin/pages/SettingsPage/pages/Roles/ListPage/index.js +0 -376
  166. package/ee/admin/pages/SettingsPage/pages/Roles/ProtectedListPage/index.js +0 -12
  167. package/ee/server/controllers/permission.js +0 -21
  168. package/ee/server/validation/permission.js +0 -8
  169. package/server/domain/role.js +0 -29
  170. /package/{ee/admin → admin/src}/pages/SettingsPage/pages/Roles/CreatePage/utils/schema.js +0 -0
  171. /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" alignItems="flex-start" gap={2}>
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, recursivelyFindPathsBasedOnCondition } from './utils';
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
- relationalFieldPaths,
199
- componentPaths,
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 repeatableFields = recursivelyFindPathsBasedOnCondition(
38
+ const findAllRelationsAndReplaceWithEmptyArray = findAllAndReplace(
51
39
  allComponents,
52
- (value) => value.type === 'component' && value.repeatable
53
- )(componentLayoutData.attributes);
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
- return acc;
69
- }, defaultDataStructure);
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 relationPaths = recursivelyFindPathsBasedOnCondition(
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 === 'component' && !value.repeatable
114
- )(componentLayoutData.attributes);
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
- return acc;
143
- }, defaultDataStructure);
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 = value.filter((relation) => {
160
- return !initialDataRelations.some((initialDataRelation) => {
161
- return initialDataRelation.id === relation.id;
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
- * relationalFieldPaths won't be an array which is what we're expecting
283
- * Therefore we reset these bits of state to the correct data type
284
- * which is an array. Hence why we replace those fields.
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
- const mergeDataWithPreparedRelations = relationalFieldPaths
289
- .map((path) => path.split('.'))
290
- .reduce((acc, currentPaths) => {
291
- const [componentName] = currentPaths;
229
+ return [];
230
+ }
231
+ );
292
232
 
293
- const existingComponents = castArray(acc[componentName] || []);
294
- existingComponents.reduce((result, currentEntry) => {
295
- if (!isNil(get(currentEntry, [`__temp_key__`]))) {
296
- return result;
297
- }
233
+ const mergedDataWithPreparedRelations = findAllRelationsAndReplaceWithEmptyArray(
234
+ data,
235
+ attributes
236
+ );
298
237
 
299
- set(currentEntry, [`__temp_key__`], getMaxTempKey(result) + 1);
300
-
301
- return result;
302
- }, existingComponents);
303
-
304
- if (state.modifiedData && get(state.modifiedData, componentName)) {
305
- /**
306
- * this will be null on initial load, however subsequent calls
307
- * will have data in them correlating to the names of the relational fields.
308
- *
309
- * We also merge the fetched data so that things like `id` for components can be copied over
310
- * which would be `undefined` in the `browserState`.
311
- */
312
- const currentState = cloneDeep(get(state.modifiedData, componentName));
313
- set(acc, componentName, merge(currentState, get(initialValues, componentName)));
314
- } else if (
315
- repeatableComponentPaths.includes(componentName) ||
316
- dynamicZonePaths.includes(componentName) ||
317
- componentPaths.includes(componentName)
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
- return acc;
331
- }, data);
258
+ const mergedDataWithTmpKeys = findComponentsAndReplaceWithTempKey(
259
+ mergedDataWithPreparedRelations,
260
+ attributes,
261
+ { ignoreFalseyValues: true }
262
+ );
332
263
 
333
264
  if (!setModifiedDataOnly) {
334
- draftState.initialData = mergeDataWithPreparedRelations;
265
+ draftState.initialData = mergedDataWithTmpKeys;
335
266
  }
336
267
 
337
- draftState.modifiedData = mergeDataWithPreparedRelations;
268
+ draftState.modifiedData = mergedDataWithTmpKeys;
338
269
 
339
270
  draftState.formErrors = {};
340
271
 
@@ -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 { recursivelyFindPathsBasedOnCondition } from './recursivelyFindPathsBasedOnCondition';
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) return false;
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" spacing={6}>
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
  () =>
@@ -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 cacheKey = `${slug}-${initialDataPath.join('.')}`;
61
- const { relations, search, searchFor } = useRelation(cacheKey, {
62
- relation: {
63
- enabled: !!endpoints.relation,
64
- endpoint: endpoints.relation,
65
- pageGoal: currentLastPage,
66
- pageParams: {
67
- ...defaultParams,
68
- pageSize: RELATIONS_TO_DISPLAY,
69
- },
70
- onLoad(value) {
71
- relationLoad({
72
- target: {
73
- initialDataPath: ['initialData', ...initialDataPath],
74
- modifiedDataPath: ['modifiedData', ...nameSplit],
75
- value,
76
- },
77
- });
78
- },
79
- normalizeArguments: {
80
- mainFieldName: mainField.name,
81
- shouldAddLink: shouldDisplayRelationLink,
82
- targetModel,
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
- search: {
86
- endpoint: endpoints.search,
87
- pageParams: {
88
- ...defaultParams,
89
- // eslint-disable-next-line no-nested-ternary
90
- entityId: isCreatingEntry ? undefined : isComponentRelation ? componentId : initialData.id,
91
- pageSize: SEARCH_RESULTS_TO_DISPLAY,
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" spacing={2}>
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" spacing={6}>
161
+ <Flex direction="column" alignItems="stretch" gap={6}>
162
162
  <Grid gap={4}>
163
163
  <GridItem col={6}>
164
164
  <TextInput
@@ -69,6 +69,7 @@ const FormHead = ({
69
69
  })}
70
70
  </Link>
71
71
  }
72
+ ellipsis
72
73
  />
73
74
  );
74
75
  };
@@ -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'])