@akemona-org/strapi-plugin-content-type-builder 3.7.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 (223) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +19 -0
  3. package/admin/src/InjectedComponents/ContentManager/EditSettingViewButton.js +76 -0
  4. package/admin/src/InjectedComponents/ContentManager/EditViewLink.js +44 -0
  5. package/admin/src/assets/images/logo.svg +1 -0
  6. package/admin/src/components/AllowedTypesSelect/MenuList.js +115 -0
  7. package/admin/src/components/AllowedTypesSelect/Text.js +26 -0
  8. package/admin/src/components/AllowedTypesSelect/index.js +55 -0
  9. package/admin/src/components/AttributeOption/Button.js +50 -0
  10. package/admin/src/components/AttributeOption/Card.js +26 -0
  11. package/admin/src/components/AttributeOption/index.js +127 -0
  12. package/admin/src/components/BooleanBox/CT.js +21 -0
  13. package/admin/src/components/BooleanBox/Enumeration.js +10 -0
  14. package/admin/src/components/BooleanBox/EnumerationWrapper.js +14 -0
  15. package/admin/src/components/BooleanBox/Label.js +9 -0
  16. package/admin/src/components/BooleanBox/ST.js +21 -0
  17. package/admin/src/components/BooleanBox/Wrapper.js +75 -0
  18. package/admin/src/components/BooleanBox/icons/CTSelected.js +136 -0
  19. package/admin/src/components/BooleanBox/icons/CTUnselected.js +136 -0
  20. package/admin/src/components/BooleanBox/icons/STSelected.js +80 -0
  21. package/admin/src/components/BooleanBox/icons/STUnselected.js +76 -0
  22. package/admin/src/components/BooleanBox/index.js +103 -0
  23. package/admin/src/components/CheckboxWithDescription/Wrapper.js +12 -0
  24. package/admin/src/components/CheckboxWithDescription/index.js +40 -0
  25. package/admin/src/components/ComponentCard/Close.js +12 -0
  26. package/admin/src/components/ComponentCard/Wrapper.js +84 -0
  27. package/admin/src/components/ComponentCard/index.js +62 -0
  28. package/admin/src/components/ComponentIconPicker/Cell.js +40 -0
  29. package/admin/src/components/ComponentIconPicker/CellRenderer.js +36 -0
  30. package/admin/src/components/ComponentIconPicker/Search.js +12 -0
  31. package/admin/src/components/ComponentIconPicker/SearchWrapper.js +34 -0
  32. package/admin/src/components/ComponentIconPicker/Wrapper.js +60 -0
  33. package/admin/src/components/ComponentIconPicker/index.js +143 -0
  34. package/admin/src/components/ComponentList/index.js +78 -0
  35. package/admin/src/components/ComponentSelect/Category.js +20 -0
  36. package/admin/src/components/ComponentSelect/CategoryName.js +11 -0
  37. package/admin/src/components/ComponentSelect/MenuList.js +110 -0
  38. package/admin/src/components/ComponentSelect/MultipleMenuList.js +271 -0
  39. package/admin/src/components/ComponentSelect/Value.js +83 -0
  40. package/admin/src/components/ComponentSelect/index.js +83 -0
  41. package/admin/src/components/ComponentSelect/utils/HasSomeSubArray.js +5 -0
  42. package/admin/src/components/ComponentSelect/utils/hasSubArray.js +5 -0
  43. package/admin/src/components/CreatableSelect/index.js +58 -0
  44. package/admin/src/components/CustomCheckbox/StyledCustomCheckbox.js +25 -0
  45. package/admin/src/components/CustomCheckbox/index.js +71 -0
  46. package/admin/src/components/CustomLink/P.js +17 -0
  47. package/admin/src/components/CustomLink/StyledCustomLink.js +20 -0
  48. package/admin/src/components/CustomLink/index.js +31 -0
  49. package/admin/src/components/DynamicZoneList/ComponentButton.js +39 -0
  50. package/admin/src/components/DynamicZoneList/index.js +124 -0
  51. package/admin/src/components/HeaderModalNavContainer/index.js +25 -0
  52. package/admin/src/components/HeaderNavLink/Wrapper.js +21 -0
  53. package/admin/src/components/HeaderNavLink/index.js +50 -0
  54. package/admin/src/components/List/List.js +131 -0
  55. package/admin/src/components/List/index.js +295 -0
  56. package/admin/src/components/ListButton/index.js +9 -0
  57. package/admin/src/components/ListHeader/Title.js +19 -0
  58. package/admin/src/components/ListHeader/Wrapper.js +24 -0
  59. package/admin/src/components/ListHeader/index.js +37 -0
  60. package/admin/src/components/ListRow/Wrapper.js +76 -0
  61. package/admin/src/components/ListRow/index.js +334 -0
  62. package/admin/src/components/ModalHeader/ComponentIcon.js +21 -0
  63. package/admin/src/components/ModalHeader/ComponentInfos.js +22 -0
  64. package/admin/src/components/ModalHeader/ComponentInfosWrapper.js +9 -0
  65. package/admin/src/components/ModalHeader/DropdownInfos.js +50 -0
  66. package/admin/src/components/ModalHeader/Icon.js +26 -0
  67. package/admin/src/components/ModalHeader/IconWrapper.js +11 -0
  68. package/admin/src/components/ModalHeader/Item.js +19 -0
  69. package/admin/src/components/ModalHeader/Menu.js +8 -0
  70. package/admin/src/components/ModalHeader/Toggle.js +14 -0
  71. package/admin/src/components/ModalHeader/Wrapper.js +12 -0
  72. package/admin/src/components/ModalHeader/index.js +105 -0
  73. package/admin/src/components/RelationForm/Wrapper.js +9 -0
  74. package/admin/src/components/RelationForm/index.js +66 -0
  75. package/admin/src/components/RelationFormBox/Wrapper.js +34 -0
  76. package/admin/src/components/RelationFormBox/index.js +85 -0
  77. package/admin/src/components/RelationFormNaturePicker/Wrapper.js +53 -0
  78. package/admin/src/components/RelationFormNaturePicker/index.js +112 -0
  79. package/admin/src/components/RelationTargetPicker/Item.js +62 -0
  80. package/admin/src/components/RelationTargetPicker/Wrapper.js +89 -0
  81. package/admin/src/components/RelationTargetPicker/index.js +88 -0
  82. package/admin/src/components/SelectCheckbox/index.js +8 -0
  83. package/admin/src/components/SelectMenuSubUl/ToggleUl.js +23 -0
  84. package/admin/src/components/SelectMenuSubUl/index.js +23 -0
  85. package/admin/src/components/SelectMenuUl/index.js +66 -0
  86. package/admin/src/components/Td/index.js +37 -0
  87. package/admin/src/components/UpperFirst/index.js +14 -0
  88. package/admin/src/components/WrapperSelect/index.js +89 -0
  89. package/admin/src/containers/App/Wrapper.js +14 -0
  90. package/admin/src/containers/App/index.js +39 -0
  91. package/admin/src/containers/App/utils/icons.json +962 -0
  92. package/admin/src/containers/DataManagerProvider/constants.js +15 -0
  93. package/admin/src/containers/DataManagerProvider/index.js +610 -0
  94. package/admin/src/containers/DataManagerProvider/reducer.js +461 -0
  95. package/admin/src/containers/DataManagerProvider/selectors.js +25 -0
  96. package/admin/src/containers/DataManagerProvider/utils/cleanData.js +167 -0
  97. package/admin/src/containers/DataManagerProvider/utils/createDataObject.js +8 -0
  98. package/admin/src/containers/DataManagerProvider/utils/createModifiedDataSchema.js +91 -0
  99. package/admin/src/containers/DataManagerProvider/utils/retrieveComponentsFromSchema.js +55 -0
  100. package/admin/src/containers/DataManagerProvider/utils/retrieveComponentsThatHaveComponents.js +35 -0
  101. package/admin/src/containers/DataManagerProvider/utils/retrieveNestedComponents.js +34 -0
  102. package/admin/src/containers/DataManagerProvider/utils/retrieveSpecificInfoFromComponents.js +12 -0
  103. package/admin/src/containers/FormModal/CustomButton.js +12 -0
  104. package/admin/src/containers/FormModal/attributes/advancedForm.js +269 -0
  105. package/admin/src/containers/FormModal/attributes/attributeOptions.js +99 -0
  106. package/admin/src/containers/FormModal/attributes/baseForm.js +322 -0
  107. package/admin/src/containers/FormModal/attributes/commonBaseForm.js +7 -0
  108. package/admin/src/containers/FormModal/attributes/form.js +9 -0
  109. package/admin/src/containers/FormModal/attributes/index.js +4 -0
  110. package/admin/src/containers/FormModal/attributes/nameField.js +19 -0
  111. package/admin/src/containers/FormModal/attributes/types.js +309 -0
  112. package/admin/src/containers/FormModal/attributes/uiHelpers.js +11 -0
  113. package/admin/src/containers/FormModal/attributes/validation/common.js +151 -0
  114. package/admin/src/containers/FormModal/category/createCategorySchema.js +28 -0
  115. package/admin/src/containers/FormModal/category/form.js +27 -0
  116. package/admin/src/containers/FormModal/category/index.js +3 -0
  117. package/admin/src/containers/FormModal/category/regex.js +3 -0
  118. package/admin/src/containers/FormModal/component/componentField.js +25 -0
  119. package/admin/src/containers/FormModal/component/createComponentSchema.js +49 -0
  120. package/admin/src/containers/FormModal/component/form.js +67 -0
  121. package/admin/src/containers/FormModal/component/index.js +4 -0
  122. package/admin/src/containers/FormModal/constants.js +11 -0
  123. package/admin/src/containers/FormModal/contentType/createContentTypeSchema.js +44 -0
  124. package/admin/src/containers/FormModal/contentType/form.js +116 -0
  125. package/admin/src/containers/FormModal/contentType/index.js +2 -0
  126. package/admin/src/containers/FormModal/dynamicZone/form.js +45 -0
  127. package/admin/src/containers/FormModal/dynamicZone/index.js +2 -0
  128. package/admin/src/containers/FormModal/forms/index.js +164 -0
  129. package/admin/src/containers/FormModal/index.js +1552 -0
  130. package/admin/src/containers/FormModal/reducer.js +293 -0
  131. package/admin/src/containers/FormModal/selectors.js +24 -0
  132. package/admin/src/containers/FormModal/utils/canEditContentType.js +19 -0
  133. package/admin/src/containers/FormModal/utils/createHeadersArray.js +37 -0
  134. package/admin/src/containers/FormModal/utils/createHeadersObjectFromArray.js +27 -0
  135. package/admin/src/containers/FormModal/utils/createUid.js +17 -0
  136. package/admin/src/containers/FormModal/utils/getAttributesToDisplay.js +35 -0
  137. package/admin/src/containers/FormModal/utils/getModalTitleSubHeader.js +25 -0
  138. package/admin/src/containers/FormModal/utils/getNextSearch.js +17 -0
  139. package/admin/src/containers/FormModal/utils/index.js +6 -0
  140. package/admin/src/containers/FormModal/utils/relations.js +9 -0
  141. package/admin/src/containers/FormModal/utils/staticData.js +43 -0
  142. package/admin/src/containers/Initializer/index.js +26 -0
  143. package/admin/src/containers/LeftMenu/Wrapper.js +14 -0
  144. package/admin/src/containers/LeftMenu/index.js +220 -0
  145. package/admin/src/containers/ListView/Wrapper.js +16 -0
  146. package/admin/src/containers/ListView/index.js +322 -0
  147. package/admin/src/containers/NotFoundPage/index.js +20 -0
  148. package/admin/src/containers/RecursivePath/index.js +22 -0
  149. package/admin/src/contexts/DataManagerContext.js +5 -0
  150. package/admin/src/contexts/ListViewContext.js +5 -0
  151. package/admin/src/hooks/useDataManager.js +6 -0
  152. package/admin/src/hooks/useListView.js +6 -0
  153. package/admin/src/icons/Curve.js +26 -0
  154. package/admin/src/icons/ManyToMany.js +98 -0
  155. package/admin/src/icons/ManyToOne.js +64 -0
  156. package/admin/src/icons/ManyWay.js +36 -0
  157. package/admin/src/icons/OneToMany.js +65 -0
  158. package/admin/src/icons/OneToOne.js +47 -0
  159. package/admin/src/icons/OneWay.js +38 -0
  160. package/admin/src/index.js +83 -0
  161. package/admin/src/lifecycles.js +13 -0
  162. package/admin/src/permissions.js +9 -0
  163. package/admin/src/pluginId.js +5 -0
  164. package/admin/src/reducers.js +10 -0
  165. package/admin/src/translations/ar.json +48 -0
  166. package/admin/src/translations/cs.json +151 -0
  167. package/admin/src/translations/de.json +187 -0
  168. package/admin/src/translations/dk.json +181 -0
  169. package/admin/src/translations/en.json +188 -0
  170. package/admin/src/translations/es.json +188 -0
  171. package/admin/src/translations/fr.json +87 -0
  172. package/admin/src/translations/id.json +187 -0
  173. package/admin/src/translations/index.js +51 -0
  174. package/admin/src/translations/it.json +187 -0
  175. package/admin/src/translations/ja.json +50 -0
  176. package/admin/src/translations/ko.json +57 -0
  177. package/admin/src/translations/ms.json +179 -0
  178. package/admin/src/translations/nl.json +171 -0
  179. package/admin/src/translations/pl.json +152 -0
  180. package/admin/src/translations/pt-BR.json +51 -0
  181. package/admin/src/translations/pt.json +51 -0
  182. package/admin/src/translations/ru.json +188 -0
  183. package/admin/src/translations/sk.json +186 -0
  184. package/admin/src/translations/th.json +181 -0
  185. package/admin/src/translations/tr.json +51 -0
  186. package/admin/src/translations/uk.json +180 -0
  187. package/admin/src/translations/zh-Hans.json +188 -0
  188. package/admin/src/translations/zh.json +178 -0
  189. package/admin/src/utils/convertAttrObjToArray.js +7 -0
  190. package/admin/src/utils/formAPI.js +112 -0
  191. package/admin/src/utils/getAttributeDisplayedType.js +31 -0
  192. package/admin/src/utils/getComponents.js +31 -0
  193. package/admin/src/utils/getTrad.js +5 -0
  194. package/admin/src/utils/makeSearch.js +15 -0
  195. package/admin/src/utils/makeUnique.js +3 -0
  196. package/config/functions/bootstrap.js +14 -0
  197. package/config/routes.json +144 -0
  198. package/controllers/Builder.js +7 -0
  199. package/controllers/ComponentCategories.js +43 -0
  200. package/controllers/Components.js +152 -0
  201. package/controllers/Connections.js +9 -0
  202. package/controllers/ContentTypes.js +143 -0
  203. package/controllers/validation/common.js +118 -0
  204. package/controllers/validation/component-category.js +21 -0
  205. package/controllers/validation/component.js +89 -0
  206. package/controllers/validation/content-type.js +161 -0
  207. package/controllers/validation/data-transform.js +32 -0
  208. package/controllers/validation/model-schema.js +91 -0
  209. package/controllers/validation/relations.js +56 -0
  210. package/controllers/validation/types.js +277 -0
  211. package/package.json +63 -0
  212. package/services/Builder.js +7 -0
  213. package/services/ComponentCategories.js +88 -0
  214. package/services/Components.js +103 -0
  215. package/services/ContentTypes.js +263 -0
  216. package/services/api-handler.js +158 -0
  217. package/services/constants.js +59 -0
  218. package/services/schema-builder/component-builder.js +137 -0
  219. package/services/schema-builder/content-type-builder.js +256 -0
  220. package/services/schema-builder/index.js +196 -0
  221. package/services/schema-builder/schema-handler.js +297 -0
  222. package/utils/attributes.js +154 -0
  223. package/utils/helpers.js +31 -0
@@ -0,0 +1,461 @@
1
+ import { fromJS, OrderedMap } from 'immutable';
2
+ import { get, has } from 'lodash';
3
+ import makeUnique from '../../utils/makeUnique';
4
+ import retrieveComponentsFromSchema from './utils/retrieveComponentsFromSchema';
5
+ import * as actions from './constants';
6
+
7
+ const initialState = fromJS({
8
+ components: {},
9
+ contentTypes: {},
10
+ initialComponents: {},
11
+ initialContentTypes: {},
12
+ initialData: {},
13
+ modifiedData: {},
14
+ reservedNames: {},
15
+ isLoading: true,
16
+ isLoadingForDataToBeSet: true,
17
+ });
18
+
19
+ const ONE_SIDE_RELATIONS = ['oneWay', 'manyWay'];
20
+
21
+ const getOppositeNature = originalNature => {
22
+ if (originalNature === 'manyToOne') {
23
+ return 'oneToMany';
24
+ }
25
+
26
+ if (originalNature === 'oneToMany') {
27
+ return 'manyToOne';
28
+ }
29
+
30
+ return originalNature;
31
+ };
32
+
33
+ const addComponentsToState = (state, componentToAddUid, objToUpdate) => {
34
+ let newObj = objToUpdate;
35
+ const componentToAdd = state.getIn(['components', componentToAddUid]);
36
+ const isTemporaryComponent = componentToAdd.get('isTemporary');
37
+ const componentToAddSchema = componentToAdd.getIn(['schema', 'attributes']);
38
+ const hasComponentAlreadyBeenAdded =
39
+ state.getIn(['modifiedData', 'components', componentToAddUid]) !== undefined;
40
+
41
+ // created components are already in the modifiedData.components
42
+ // We don't add them because all modifications will be lost
43
+ if (isTemporaryComponent || hasComponentAlreadyBeenAdded) {
44
+ return newObj;
45
+ }
46
+
47
+ // Add the added components to the modifiedData.compontnes
48
+ newObj = newObj.set(componentToAddUid, componentToAdd);
49
+ const nestedComponents = retrieveComponentsFromSchema(
50
+ componentToAddSchema.toJS(),
51
+ state.get('components').toJS()
52
+ );
53
+
54
+ // We need to add the nested components to the modifiedData.components as well
55
+ nestedComponents.forEach(componentUid => {
56
+ const isTemporary = state.getIn(['components', componentUid, 'isTemporary']) || false;
57
+ const hasNestedComponentAlreadyBeenAdded =
58
+ state.getIn(['modifiedData', 'components', componentUid]) !== undefined;
59
+
60
+ // Same logic here otherwise we will lose the modifications added to the components
61
+ if (!isTemporary && !hasNestedComponentAlreadyBeenAdded) {
62
+ newObj = newObj.set(componentUid, state.getIn(['components', componentUid]));
63
+ }
64
+ });
65
+
66
+ return newObj;
67
+ };
68
+
69
+ const reducer = (state = initialState, action) => {
70
+ switch (action.type) {
71
+ case actions.ADD_ATTRIBUTE: {
72
+ const {
73
+ attributeToSet: { name, ...rest },
74
+ forTarget,
75
+ targetUid,
76
+ } = action;
77
+ delete rest.createComponent;
78
+
79
+ const pathToDataToEdit = ['component', 'contentType'].includes(forTarget)
80
+ ? [forTarget]
81
+ : [forTarget, targetUid];
82
+
83
+ return state
84
+ .updateIn(['modifiedData', ...pathToDataToEdit, 'schema', 'attributes', name], () => {
85
+ return fromJS(rest);
86
+ })
87
+ .updateIn(['modifiedData', ...pathToDataToEdit, 'schema', 'attributes'], obj => {
88
+ const type = get(rest, 'type', 'relation');
89
+ const target = get(rest, 'target', null);
90
+ const nature = get(rest, 'nature', null);
91
+ const currentUid = state.getIn(['modifiedData', ...pathToDataToEdit, 'uid']);
92
+
93
+ // When the user in creating a relation with the same content type we need to create another attribute
94
+ // that is the opposite of the created one
95
+ if (
96
+ type === 'relation' &&
97
+ nature !== 'oneWay' &&
98
+ nature !== 'manyWay' &&
99
+ target === currentUid
100
+ ) {
101
+ const oppositeAttribute = {
102
+ nature: getOppositeNature(nature),
103
+ target,
104
+ unique: rest.unique,
105
+ // Leave this if we allow the required on the relation
106
+ // required: rest.required,
107
+ dominant: nature === 'manyToMany' ? !rest.dominant : null,
108
+ targetAttribute: name,
109
+ columnName: rest.targetColumnName,
110
+ targetColumnName: rest.columnName,
111
+ };
112
+
113
+ return obj.update(rest.targetAttribute, () => {
114
+ return fromJS(oppositeAttribute);
115
+ });
116
+ }
117
+
118
+ return obj;
119
+ })
120
+ .updateIn(['modifiedData', 'components'], existingCompos => {
121
+ if (action.shouldAddComponentToData) {
122
+ return addComponentsToState(state, rest.component, existingCompos);
123
+ }
124
+
125
+ return existingCompos;
126
+ });
127
+ }
128
+ case actions.ADD_CREATED_COMPONENT_TO_DYNAMIC_ZONE: {
129
+ const { dynamicZoneTarget, componentsToAdd } = action;
130
+
131
+ return state.updateIn(
132
+ ['modifiedData', 'contentType', 'schema', 'attributes', dynamicZoneTarget, 'components'],
133
+ list => {
134
+ return list.concat(componentsToAdd);
135
+ }
136
+ );
137
+ }
138
+ case actions.CANCEL_CHANGES: {
139
+ return state
140
+ .update('modifiedData', () => state.get('initialData'))
141
+ .update('components', () => state.get('initialComponents'));
142
+ }
143
+ case actions.CHANGE_DYNAMIC_ZONE_COMPONENTS: {
144
+ const { dynamicZoneTarget, newComponents } = action;
145
+
146
+ return state
147
+ .updateIn(
148
+ ['modifiedData', 'contentType', 'schema', 'attributes', dynamicZoneTarget, 'components'],
149
+ list => {
150
+ return fromJS(makeUnique([...list.toJS(), ...newComponents]));
151
+ }
152
+ )
153
+ .updateIn(['modifiedData', 'components'], old => {
154
+ const componentsSchema = newComponents.reduce((acc, current) => {
155
+ return addComponentsToState(state, current, acc);
156
+ }, old);
157
+
158
+ return componentsSchema;
159
+ });
160
+ }
161
+
162
+ case actions.CREATE_SCHEMA: {
163
+ const newSchema = {
164
+ uid: action.uid,
165
+ isTemporary: true,
166
+ schema: {
167
+ ...action.data,
168
+ attributes: {},
169
+ },
170
+ };
171
+
172
+ return state.updateIn(['contentTypes', action.uid], () => fromJS(newSchema));
173
+ }
174
+ case actions.CREATE_COMPONENT_SCHEMA: {
175
+ const newSchema = {
176
+ uid: action.uid,
177
+ isTemporary: true,
178
+ category: action.componentCategory,
179
+ schema: {
180
+ ...action.data,
181
+ attributes: {},
182
+ },
183
+ };
184
+
185
+ if (action.shouldAddComponentToData) {
186
+ return state
187
+ .updateIn(['components', action.uid], () => fromJS(newSchema))
188
+ .updateIn(['modifiedData', 'components', action.uid], () => fromJS(newSchema));
189
+ }
190
+
191
+ return state.updateIn(['components', action.uid], () => fromJS(newSchema));
192
+ }
193
+ case actions.DELETE_NOT_SAVED_TYPE: {
194
+ // Doing so will also reset the modified and the initial data
195
+ return state
196
+ .update('contentTypes', () => state.get('initialContentTypes'))
197
+ .update('components', () => state.get('initialComponents'));
198
+ }
199
+ case actions.EDIT_ATTRIBUTE: {
200
+ const {
201
+ attributeToSet: { name, ...rest },
202
+ forTarget,
203
+ targetUid,
204
+ initialAttribute,
205
+ } = action;
206
+ let newState = state;
207
+
208
+ const initialAttributeName = get(initialAttribute, ['name'], '');
209
+ const pathToDataToEdit = ['component', 'contentType'].includes(forTarget)
210
+ ? [forTarget]
211
+ : [forTarget, targetUid];
212
+
213
+ return newState.updateIn(['modifiedData', ...pathToDataToEdit, 'schema'], obj => {
214
+ let oppositeAttributeNameToRemove = null;
215
+ let oppositeAttributeNameToUpdate = null;
216
+ let oppositeAttributeNameToCreateBecauseOfNatureChange = null;
217
+ let oppositeAttributeToCreate = null;
218
+
219
+ const newObj = OrderedMap(
220
+ obj
221
+ .get('attributes')
222
+ .keySeq()
223
+ .reduce((acc, current) => {
224
+ const isEditingCurrentAttribute = current === initialAttributeName;
225
+
226
+ if (isEditingCurrentAttribute) {
227
+ const currentUid = state.getIn(['modifiedData', ...pathToDataToEdit, 'uid']);
228
+ const isEditingRelation = has(initialAttribute, 'nature');
229
+ const didChangeTargetRelation = initialAttribute.target !== rest.target;
230
+ const didCreateInternalRelation = rest.target === currentUid;
231
+ const nature = rest.nature;
232
+ const initialNature = initialAttribute.nature;
233
+ const hadInternalRelation = initialAttribute.target === currentUid;
234
+ const didChangeRelationNature = initialAttribute.nature !== nature;
235
+ const shouldRemoveOppositeAttributeBecauseOfTargetChange =
236
+ didChangeTargetRelation &&
237
+ !didCreateInternalRelation &&
238
+ hadInternalRelation &&
239
+ isEditingRelation;
240
+ const shouldRemoveOppositeAttributeBecauseOfNatureChange =
241
+ didChangeRelationNature &&
242
+ hadInternalRelation &&
243
+ ['oneWay', 'manyWay'].includes(nature) &&
244
+ isEditingRelation;
245
+ const shouldUpdateOppositeAttributeBecauseOfNatureChange =
246
+ !ONE_SIDE_RELATIONS.includes(initialNature) &&
247
+ !ONE_SIDE_RELATIONS.includes(nature) &&
248
+ hadInternalRelation &&
249
+ didCreateInternalRelation &&
250
+ isEditingRelation;
251
+ const shouldCreateOppositeAttributeBecauseOfNatureChange =
252
+ ONE_SIDE_RELATIONS.includes(initialNature) &&
253
+ !ONE_SIDE_RELATIONS.includes(nature) &&
254
+ hadInternalRelation &&
255
+ didCreateInternalRelation &&
256
+ isEditingRelation;
257
+ const shouldCreateOppositeAttributeBecauseOfTargetChange =
258
+ didChangeTargetRelation &&
259
+ didCreateInternalRelation &&
260
+ !ONE_SIDE_RELATIONS.includes(nature);
261
+
262
+ // Update the opposite attribute name so it is removed at the end of the loop
263
+ if (
264
+ shouldRemoveOppositeAttributeBecauseOfTargetChange ||
265
+ shouldRemoveOppositeAttributeBecauseOfNatureChange
266
+ ) {
267
+ oppositeAttributeNameToRemove = initialAttribute.targetAttribute;
268
+ }
269
+
270
+ // Set the opposite attribute that will be updated when the loop attribute matches the name
271
+ if (
272
+ shouldUpdateOppositeAttributeBecauseOfNatureChange ||
273
+ shouldCreateOppositeAttributeBecauseOfNatureChange ||
274
+ shouldCreateOppositeAttributeBecauseOfTargetChange
275
+ ) {
276
+ oppositeAttributeNameToUpdate = initialAttribute.targetAttribute;
277
+ oppositeAttributeNameToCreateBecauseOfNatureChange = rest.targetAttribute;
278
+
279
+ oppositeAttributeToCreate = {
280
+ nature: getOppositeNature(rest.nature),
281
+ target: rest.target,
282
+ unique: rest.unique,
283
+ // Leave this if we allow the required on the relation
284
+ // required: rest.required,
285
+ dominant: rest.nature === 'manyToMany' ? !rest.dominant : null,
286
+ targetAttribute: name,
287
+ columnName: rest.targetColumnName,
288
+ targetColumnName: rest.columnName,
289
+ };
290
+
291
+ // First update the current attribute with the value
292
+ acc[name] = fromJS(rest);
293
+
294
+ // Then (if needed) create the opposite attribute the case is changing the relation from
295
+ // We do it here so keep the order of the attributes
296
+ // oneWay || manyWay to something another relation
297
+ if (
298
+ shouldCreateOppositeAttributeBecauseOfNatureChange ||
299
+ shouldCreateOppositeAttributeBecauseOfTargetChange
300
+ ) {
301
+ acc[oppositeAttributeNameToCreateBecauseOfNatureChange] = fromJS(
302
+ oppositeAttributeToCreate
303
+ );
304
+
305
+ oppositeAttributeToCreate = null;
306
+ oppositeAttributeNameToCreateBecauseOfNatureChange = null;
307
+ }
308
+
309
+ return acc;
310
+ }
311
+
312
+ acc[name] = fromJS(rest);
313
+ } else if (current === oppositeAttributeNameToUpdate) {
314
+ acc[oppositeAttributeNameToCreateBecauseOfNatureChange] = fromJS(
315
+ oppositeAttributeToCreate
316
+ );
317
+ } else {
318
+ acc[current] = obj.getIn(['attributes', current]);
319
+ }
320
+
321
+ return acc;
322
+ }, {})
323
+ );
324
+
325
+ let updatedObj;
326
+
327
+ // Remove the opposite attribute
328
+ if (oppositeAttributeNameToRemove !== null) {
329
+ updatedObj = newObj.remove(oppositeAttributeNameToRemove);
330
+ } else {
331
+ updatedObj = newObj;
332
+ }
333
+
334
+ return obj.set('attributes', updatedObj);
335
+ });
336
+ }
337
+
338
+ case actions.GET_DATA_SUCCEEDED: {
339
+ return state
340
+ .update('components', () => fromJS(action.components))
341
+ .update('initialComponents', () => fromJS(action.components))
342
+ .update('initialContentTypes', () => fromJS(action.contentTypes))
343
+ .update('contentTypes', () => fromJS(action.contentTypes))
344
+ .update('reservedNames', () => fromJS(action.reservedNames))
345
+
346
+ .update('isLoading', () => false);
347
+ }
348
+ case actions.RELOAD_PLUGIN:
349
+ return initialState;
350
+ case actions.REMOVE_FIELD_FROM_DISPLAYED_COMPONENT: {
351
+ const { attributeToRemoveName, componentUid } = action;
352
+
353
+ return state.removeIn([
354
+ 'modifiedData',
355
+ 'components',
356
+ componentUid,
357
+ 'schema',
358
+ 'attributes',
359
+ attributeToRemoveName,
360
+ ]);
361
+ }
362
+ case actions.REMOVE_COMPONENT_FROM_DYNAMIC_ZONE:
363
+ return state.removeIn([
364
+ 'modifiedData',
365
+ 'contentType',
366
+ 'schema',
367
+ 'attributes',
368
+ action.dzName,
369
+ 'components',
370
+ action.componentToRemoveIndex,
371
+ ]);
372
+ case actions.REMOVE_FIELD: {
373
+ const { mainDataKey, attributeToRemoveName } = action;
374
+ const pathToAttributes = ['modifiedData', mainDataKey, 'schema', 'attributes'];
375
+ const pathToAttributeToRemove = [...pathToAttributes, attributeToRemoveName];
376
+
377
+ const attributeToRemoveData = state.getIn(pathToAttributeToRemove);
378
+
379
+ const isRemovingRelationAttribute = attributeToRemoveData.get('nature') !== undefined;
380
+ // Only content types can have relations with themselves since
381
+ // components can only have oneWay or manyWay relations
382
+ const canTheAttributeToRemoveHaveARelationWithItself = mainDataKey === 'contentType';
383
+
384
+ if (isRemovingRelationAttribute && canTheAttributeToRemoveHaveARelationWithItself) {
385
+ const { target, nature, targetAttribute } = attributeToRemoveData.toJS();
386
+ const uid = state.getIn(['modifiedData', 'contentType', 'uid']);
387
+ const shouldRemoveOppositeAttribute =
388
+ target === uid && !ONE_SIDE_RELATIONS.includes(nature);
389
+
390
+ if (shouldRemoveOppositeAttribute) {
391
+ return state
392
+ .removeIn(pathToAttributeToRemove)
393
+ .removeIn([...pathToAttributes, targetAttribute]);
394
+ }
395
+ }
396
+
397
+ return state.removeIn(pathToAttributeToRemove).updateIn([...pathToAttributes], attributes => {
398
+ return attributes.keySeq().reduce((acc, current) => {
399
+ if (acc.getIn([current, 'targetField']) === attributeToRemoveName) {
400
+ return acc.removeIn([current, 'targetField']);
401
+ }
402
+
403
+ return acc;
404
+ }, attributes);
405
+ });
406
+ }
407
+ case actions.SET_MODIFIED_DATA: {
408
+ let newState = state
409
+ .update('isLoadingForDataToBeSet', () => false)
410
+ .update('initialData', () => fromJS(action.schemaToSet))
411
+ .update('modifiedData', () => fromJS(action.schemaToSet));
412
+
413
+ // Reset the state with the initial data
414
+ // All created components and content types will be lost
415
+ if (!action.hasJustCreatedSchema) {
416
+ newState = newState
417
+ .update('components', () => state.get('initialComponents'))
418
+ .update('contentTypes', () => state.get('initialContentTypes'));
419
+ }
420
+
421
+ return newState;
422
+ }
423
+ case actions.UPDATE_SCHEMA: {
424
+ const {
425
+ data: { name, collectionName, category, icon, kind },
426
+ schemaType,
427
+ uid,
428
+ } = action;
429
+
430
+ let newState = state.updateIn(['modifiedData', schemaType], obj => {
431
+ let updatedObj = obj
432
+ .updateIn(['schema', 'name'], () => name)
433
+ .updateIn(['schema', 'collectionName'], () => collectionName);
434
+
435
+ if (action.schemaType === 'component') {
436
+ updatedObj = updatedObj
437
+ .update('category', () => category)
438
+ .updateIn(['schema', 'icon'], () => icon);
439
+ }
440
+ if (action.schemaType === 'contentType') {
441
+ updatedObj = updatedObj.updateIn(['schema', 'kind'], () => kind);
442
+ }
443
+
444
+ return updatedObj;
445
+ });
446
+
447
+ if (schemaType === 'component') {
448
+ newState = newState.updateIn(['components'], obj => {
449
+ return obj.update(uid, () => newState.getIn(['modifiedData', 'component']));
450
+ });
451
+ }
452
+
453
+ return newState;
454
+ }
455
+ default:
456
+ return state;
457
+ }
458
+ };
459
+
460
+ export default reducer;
461
+ export { addComponentsToState, initialState };
@@ -0,0 +1,25 @@
1
+ import { createSelector } from 'reselect';
2
+ import pluginId from '../../pluginId';
3
+ import { initialState } from './reducer';
4
+
5
+ /**
6
+ * Direct selector to the dataManagerProvider state domain
7
+ */
8
+ const dataManagerProviderDomain = () => state =>
9
+ state.get(`${pluginId}_dataManagerProvider`) || initialState;
10
+
11
+ /**
12
+ * Other specific selectors
13
+ */
14
+
15
+ /**
16
+ * Default selector used by dataManagerProvider
17
+ */
18
+
19
+ const makeSelectDataManagerProvider = () =>
20
+ createSelector(dataManagerProviderDomain(), substate => {
21
+ return substate.toJS();
22
+ });
23
+
24
+ export default makeSelectDataManagerProvider;
25
+ export { dataManagerProviderDomain };
@@ -0,0 +1,167 @@
1
+ import { get, has, isEqual, omit, sortBy, camelCase } from 'lodash';
2
+
3
+ import pluginId from '../../../pluginId';
4
+ import makeUnique from '../../../utils/makeUnique';
5
+
6
+ const getCreatedAndModifiedComponents = (allComponents, initialComponents) => {
7
+ const componentUIDsToReturn = Object.keys(allComponents).filter(compoUid => {
8
+ const currentCompo = get(allComponents, compoUid, {});
9
+ const initialCompo = get(initialComponents, compoUid, {});
10
+ const hasComponentBeenCreated = get(currentCompo, ['isTemporary'], false);
11
+ const hasComponentBeenModified = !isEqual(currentCompo, initialCompo);
12
+
13
+ return hasComponentBeenCreated || hasComponentBeenModified;
14
+ });
15
+
16
+ return makeUnique(componentUIDsToReturn);
17
+ };
18
+
19
+ const formatComponent = (component, mainDataUID, isCreatingData = false) => {
20
+ const formattedAttributes = formatAttributes(
21
+ get(component, 'schema.attributes', {}),
22
+ mainDataUID,
23
+ isCreatingData,
24
+ true
25
+ );
26
+
27
+ // Set tmpUID if the component has just been created
28
+ // Keep the uid if the component already exists
29
+ const compoUID = get(component, 'isTemporary', false)
30
+ ? { tmpUID: component.uid }
31
+ : { uid: component.uid };
32
+
33
+ const formattedComponent = Object.assign(
34
+ {},
35
+ compoUID,
36
+ { category: component.category },
37
+ // Omit the attributes since we want to format them
38
+ omit(component.schema, 'attributes'),
39
+ // Add the formatted attributes
40
+ { attributes: formattedAttributes }
41
+ );
42
+
43
+ return formattedComponent;
44
+ };
45
+
46
+ const formatMainDataType = (data, isComponent = false) => {
47
+ const isCreatingData = get(data, 'isTemporary', false);
48
+ const mainDataUID = get(data, 'uid', null);
49
+
50
+ const formattedAttributes = formatAttributes(
51
+ get(data, 'schema.attributes', {}),
52
+ mainDataUID,
53
+ isCreatingData,
54
+ false
55
+ );
56
+ const initObj = isComponent ? { category: get(data, 'category', '') } : {};
57
+
58
+ const formattedContentType = Object.assign(initObj, omit(data.schema, 'attributes'), {
59
+ attributes: formattedAttributes,
60
+ });
61
+
62
+ delete formattedContentType.uid;
63
+ delete formattedContentType.isTemporary;
64
+ delete formattedContentType.visible;
65
+ delete formattedContentType.restrictRelationsTo;
66
+
67
+ return formattedContentType;
68
+ };
69
+
70
+ /**
71
+ *
72
+ * @param {Object} attributes
73
+ * @param {String} mainDataUID uid of the main data type
74
+ * @param {Boolean} isCreatingMainData
75
+ * @param {Boolean} isComponent
76
+ */
77
+ const formatAttributes = (attributes, mainDataUID, isCreatingMainData, isComponent) => {
78
+ return Object.keys(attributes).reduce((acc, current) => {
79
+ const currentAttribute = get(attributes, current, {});
80
+ const hasARelationWithMainDataUID = currentAttribute.target === mainDataUID;
81
+ const isRelationType = has(currentAttribute, 'nature');
82
+ const currentTargetAttribute = get(currentAttribute, 'targetAttribute', null);
83
+
84
+ if (!hasARelationWithMainDataUID) {
85
+ if (isRelationType) {
86
+ const relationAttr = Object.assign({}, currentAttribute, {
87
+ targetAttribute: formatRelationTargetAttribute(currentTargetAttribute),
88
+ });
89
+
90
+ acc[current] = removeNullKeys(relationAttr);
91
+ } else {
92
+ acc[current] = removeNullKeys(currentAttribute);
93
+ }
94
+ }
95
+
96
+ if (hasARelationWithMainDataUID) {
97
+ let target = currentAttribute.target;
98
+
99
+ if (isCreatingMainData) {
100
+ target = isComponent ? '__contentType__' : '__self__';
101
+ }
102
+
103
+ const formattedRelationAttribute = Object.assign({}, currentAttribute, {
104
+ target,
105
+ targetAttribute: formatRelationTargetAttribute(currentTargetAttribute),
106
+ });
107
+
108
+ acc[current] = removeNullKeys(formattedRelationAttribute);
109
+ }
110
+
111
+ return acc;
112
+ }, {});
113
+ };
114
+
115
+ const formatRelationTargetAttribute = targetAttribute =>
116
+ targetAttribute === '-' ? null : targetAttribute;
117
+
118
+ const removeNullKeys = obj =>
119
+ Object.keys(obj).reduce((acc, current) => {
120
+ if (obj[current] !== null && current !== 'plugin') {
121
+ acc[current] = obj[current];
122
+ }
123
+
124
+ return acc;
125
+ }, {});
126
+
127
+ const getComponentsToPost = (
128
+ allComponents,
129
+ initialComponents,
130
+ mainDataUID,
131
+ isCreatingData = false
132
+ ) => {
133
+ const componentsToFormat = getCreatedAndModifiedComponents(allComponents, initialComponents);
134
+ const formattedComponents = componentsToFormat.map(compoUID => {
135
+ const currentCompo = get(allComponents, compoUID, {});
136
+ const formattedComponent = formatComponent(currentCompo, mainDataUID, isCreatingData);
137
+
138
+ return formattedComponent;
139
+ });
140
+
141
+ return formattedComponents;
142
+ };
143
+
144
+ const sortContentType = types =>
145
+ sortBy(
146
+ Object.keys(types)
147
+ .map(uid => ({
148
+ visible: types[uid].schema.visible,
149
+ name: uid,
150
+ title: types[uid].schema.name,
151
+ plugin: types[uid].plugin || null,
152
+ uid,
153
+ to: `/plugins/${pluginId}/content-types/${uid}`,
154
+ kind: types[uid].schema.kind,
155
+ restrictRelationsTo: types[uid].schema.restrictRelationsTo,
156
+ }))
157
+ .filter(obj => obj !== null),
158
+ obj => camelCase(obj.title)
159
+ );
160
+
161
+ export {
162
+ formatComponent,
163
+ getComponentsToPost,
164
+ getCreatedAndModifiedComponents,
165
+ formatMainDataType,
166
+ sortContentType,
167
+ };
@@ -0,0 +1,8 @@
1
+ const createDataObject = arr =>
2
+ arr.reduce((acc, current) => {
3
+ acc[current.uid] = current;
4
+
5
+ return acc;
6
+ }, {});
7
+
8
+ export default createDataObject;