@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,220 @@
1
+ /**
2
+ *
3
+ * LeftMenu
4
+ *
5
+ */
6
+
7
+ import React, { useMemo } from 'react';
8
+ import PropTypes from 'prop-types';
9
+ import { sortBy, camelCase, upperFirst } from 'lodash';
10
+ import { useHistory } from 'react-router-dom';
11
+ import { LeftMenuList, useGlobalContext } from 'strapi-helper-plugin';
12
+ import { Text } from '@buffetjs/core';
13
+ import pluginId from '../../pluginId';
14
+ import getTrad from '../../utils/getTrad';
15
+ import CustomLink from '../../components/CustomLink';
16
+ import useDataManager from '../../hooks/useDataManager';
17
+ import makeSearch from '../../utils/makeSearch';
18
+ import Wrapper from './Wrapper';
19
+
20
+ /* eslint-disable indent */
21
+
22
+ const displayNotificationCTNotSaved = () => {
23
+ strapi.notification.toggle({
24
+ type: 'info',
25
+ message: { id: `${pluginId}.notification.info.creating.notSaved` },
26
+ });
27
+ };
28
+
29
+ function LeftMenu({ wait }) {
30
+ const {
31
+ components,
32
+ componentsGroupedByCategory,
33
+ contentTypes,
34
+ isInDevelopmentMode,
35
+ sortedContentTypesList,
36
+ } = useDataManager();
37
+ const { emitEvent, formatMessage } = useGlobalContext();
38
+ const { push } = useHistory();
39
+ const componentsData = sortBy(
40
+ Object.keys(componentsGroupedByCategory).map(category => ({
41
+ name: category,
42
+ title: category,
43
+ isEditable: isInDevelopmentMode,
44
+ onClickEdit: (e, data) => {
45
+ e.stopPropagation();
46
+
47
+ const search = makeSearch({
48
+ actionType: 'edit',
49
+ modalType: 'editCategory',
50
+ categoryName: data.name,
51
+ header_label_1: formatMessage({
52
+ id: getTrad('modalForm.header.categories'),
53
+ }),
54
+ header_icon_name_1: 'component',
55
+ header_icon_isCustom_1: false,
56
+ header_info_category_1: null,
57
+ header_info_name_1: null,
58
+ header_label_2: data.name,
59
+ header_icon_name_2: null,
60
+ header_icon_isCustom_2: false,
61
+ header_info_category_2: null,
62
+ header_info_name_2: null,
63
+
64
+ settingType: 'base',
65
+ });
66
+
67
+ push({ search });
68
+ },
69
+ links: sortBy(
70
+ componentsGroupedByCategory[category].map(compo => ({
71
+ name: compo.uid,
72
+ to: `/plugins/${pluginId}/component-categories/${category}/${compo.uid}`,
73
+ title: compo.schema.name,
74
+ })),
75
+ obj => obj.title
76
+ ),
77
+ })),
78
+ obj => obj.title
79
+ );
80
+
81
+ const canOpenModalCreateCTorComponent = () => {
82
+ return (
83
+ !Object.keys(contentTypes).some(ct => contentTypes[ct].isTemporary === true) &&
84
+ !Object.keys(components).some(component => components[component].isTemporary === true)
85
+ );
86
+ };
87
+
88
+ const handleClickOpenModal = async (modalType, kind = '') => {
89
+ const type = kind === 'singleType' ? kind : modalType;
90
+
91
+ if (canOpenModalCreateCTorComponent()) {
92
+ emitEvent(`willCreate${upperFirst(camelCase(type))}`);
93
+
94
+ await wait();
95
+ const search = makeSearch({
96
+ modalType,
97
+ kind,
98
+ actionType: 'create',
99
+ settingType: 'base',
100
+ forTarget: modalType,
101
+ headerId: getTrad(`modalForm.${type}.header-create`),
102
+ header_icon_isCustom_1: 'false',
103
+ header_icon_name_1: type,
104
+ header_label_1: 'null',
105
+ });
106
+ push({
107
+ search,
108
+ });
109
+ } else {
110
+ displayNotificationCTNotSaved();
111
+ }
112
+ };
113
+
114
+ const displayedContentTypes = useMemo(() => {
115
+ return sortedContentTypesList
116
+ .filter(obj => obj.visible)
117
+ .map(obj => {
118
+ if (obj.plugin) {
119
+ return {
120
+ ...obj,
121
+ CustomComponent: () => (
122
+ <p style={{ justifyContent: 'normal' }}>
123
+ {obj.title}&nbsp;
124
+ <Text
125
+ as="span"
126
+ ellipsis
127
+ // This is needed here
128
+ style={{ fontStyle: 'italic' }}
129
+ fontWeight="inherit"
130
+ lineHeight="inherit"
131
+ >
132
+ ({formatMessage({ id: getTrad('from') })}: {obj.plugin})&nbsp;
133
+ </Text>
134
+ </p>
135
+ ),
136
+ };
137
+ }
138
+
139
+ return obj;
140
+ });
141
+ }, [sortedContentTypesList, formatMessage]);
142
+
143
+ const data = [
144
+ {
145
+ name: 'models',
146
+ title: {
147
+ id: `${pluginId}.menu.section.models.name.`,
148
+ },
149
+ searchable: true,
150
+ customLink: isInDevelopmentMode
151
+ ? {
152
+ Component: CustomLink,
153
+ componentProps: {
154
+ id: `${pluginId}.button.model.create`,
155
+ onClick: () => {
156
+ handleClickOpenModal('contentType', 'collectionType');
157
+ },
158
+ },
159
+ }
160
+ : null,
161
+ links: displayedContentTypes.filter(contentType => contentType.kind === 'collectionType'),
162
+ },
163
+ {
164
+ name: 'singleTypes',
165
+ title: {
166
+ id: `${pluginId}.menu.section.single-types.name.`,
167
+ },
168
+ searchable: true,
169
+ customLink: isInDevelopmentMode
170
+ ? {
171
+ Component: CustomLink,
172
+ componentProps: {
173
+ id: `${pluginId}.button.single-types.create`,
174
+ onClick: () => {
175
+ handleClickOpenModal('contentType', 'singleType');
176
+ },
177
+ },
178
+ }
179
+ : null,
180
+ links: displayedContentTypes.filter(singleType => singleType.kind === 'singleType'),
181
+ },
182
+ {
183
+ name: 'components',
184
+ title: {
185
+ id: `${pluginId}.menu.section.components.name.`,
186
+ },
187
+ searchable: true,
188
+ customLink: isInDevelopmentMode
189
+ ? {
190
+ Component: CustomLink,
191
+ componentProps: {
192
+ id: `${pluginId}.button.component.create`,
193
+ onClick: () => {
194
+ handleClickOpenModal('component');
195
+ },
196
+ },
197
+ }
198
+ : null,
199
+ links: componentsData,
200
+ },
201
+ ];
202
+
203
+ return (
204
+ <Wrapper className="col-md-3">
205
+ {data.map(list => {
206
+ return <LeftMenuList {...list} key={list.name} />;
207
+ })}
208
+ </Wrapper>
209
+ );
210
+ }
211
+
212
+ LeftMenu.defaultProps = {
213
+ wait: () => {},
214
+ };
215
+
216
+ LeftMenu.propTypes = {
217
+ wait: PropTypes.func,
218
+ };
219
+
220
+ export default LeftMenu;
@@ -0,0 +1,16 @@
1
+ import styled from 'styled-components';
2
+ import { ViewContainer } from 'strapi-helper-plugin';
3
+
4
+ const Wrapper = styled(ViewContainer)`
5
+ .button-secondary {
6
+ &:hover {
7
+ background-color: #ffffff !important;
8
+ box-shadow: 0 0 0 #fff;
9
+ }
10
+ }
11
+ .button-submit {
12
+ min-width: 140px;
13
+ }
14
+ `;
15
+
16
+ export default Wrapper;
@@ -0,0 +1,322 @@
1
+ import React, { useEffect, useMemo, useState } from 'react';
2
+ import { Prompt, useHistory, useLocation } from 'react-router-dom';
3
+ import PropTypes from 'prop-types';
4
+ import { get, has, isEqual } from 'lodash';
5
+ import { BackHeader, ListWrapper, useGlobalContext } from 'strapi-helper-plugin';
6
+ import { Header } from '@buffetjs/custom';
7
+ import ListViewContext from '../../contexts/ListViewContext';
8
+ import convertAttrObjToArray from '../../utils/convertAttrObjToArray';
9
+ import getAttributeDisplayedType from '../../utils/getAttributeDisplayedType';
10
+ import pluginId from '../../pluginId';
11
+ import getComponents from '../../utils/getComponents';
12
+ import getTrad from '../../utils/getTrad';
13
+ import makeSearch from '../../utils/makeSearch';
14
+ import ListRow from '../../components/ListRow';
15
+ import List from '../../components/List';
16
+ import ListButton from '../../components/ListButton';
17
+ import useDataManager from '../../hooks/useDataManager';
18
+ import ListHeader from '../../components/ListHeader';
19
+ import LeftMenu from '../LeftMenu';
20
+ import Wrapper from './Wrapper';
21
+
22
+ /* eslint-disable indent */
23
+
24
+ const ListView = () => {
25
+ const {
26
+ initialData,
27
+ modifiedData,
28
+ isInDevelopmentMode,
29
+ isInContentTypeView,
30
+ submitData,
31
+ toggleModalCancel,
32
+ } = useDataManager();
33
+
34
+ const { emitEvent, formatMessage, plugins } = useGlobalContext();
35
+ const { push, goBack } = useHistory();
36
+ const { search } = useLocation();
37
+ const [enablePrompt, togglePrompt] = useState(true);
38
+
39
+ useEffect(() => {
40
+ if (search === '') {
41
+ togglePrompt(true);
42
+ }
43
+ }, [search]);
44
+
45
+ // Disabling the prompt on the first render if one of the modal is open
46
+ useEffect(() => {
47
+ if (search !== '') {
48
+ togglePrompt(false);
49
+ }
50
+ // eslint-disable-next-line react-hooks/exhaustive-deps
51
+ }, []);
52
+
53
+ const firstMainDataPath = isInContentTypeView ? 'contentType' : 'component';
54
+ const mainDataTypeAttributesPath = [firstMainDataPath, 'schema', 'attributes'];
55
+ const targetUid = get(modifiedData, [firstMainDataPath, 'uid']);
56
+ const isTemporary = get(modifiedData, [firstMainDataPath, 'isTemporary'], false);
57
+ const contentTypeKind = get(modifiedData, [firstMainDataPath, 'schema', 'kind'], null);
58
+
59
+ const attributes = get(modifiedData, mainDataTypeAttributesPath, {});
60
+ const attributesLength = Object.keys(attributes).length;
61
+ const currentDataName = get(initialData, [firstMainDataPath, 'schema', 'name'], '');
62
+ const isFromPlugin = has(initialData, [firstMainDataPath, 'plugin']);
63
+ const hasModelBeenModified = !isEqual(modifiedData, initialData);
64
+ const forTarget = isInContentTypeView ? 'contentType' : 'component';
65
+
66
+ const handleClickAddField = async (
67
+ forTarget,
68
+ targetUid,
69
+ firstHeaderObj,
70
+ secondHeaderObj,
71
+ thirdHeaderObj,
72
+ fourthHeaderObj
73
+ ) => {
74
+ // disable the prompt
75
+ await wait();
76
+
77
+ const searchObj = {
78
+ modalType: 'chooseAttribute',
79
+ forTarget,
80
+ targetUid,
81
+ ...firstHeaderObj,
82
+ ...secondHeaderObj,
83
+ ...thirdHeaderObj,
84
+ ...fourthHeaderObj,
85
+ };
86
+
87
+ push({ search: makeSearch(searchObj) });
88
+ };
89
+
90
+ const handleClickAddComponentToDZ = async dzName => {
91
+ const firstHeaderObject = {
92
+ header_label_1: currentDataName,
93
+ header_icon_name_1: 'dynamiczone',
94
+ header_icon_isCustom_1: false,
95
+ };
96
+ const secondHeaderObj = {
97
+ header_label_2: dzName,
98
+ };
99
+ const search = {
100
+ modalType: 'addComponentToDynamicZone',
101
+ forTarget: 'contentType',
102
+ targetUid,
103
+ dynamicZoneTarget: dzName,
104
+ settingType: 'base',
105
+ step: '1',
106
+ actionType: 'edit',
107
+ ...firstHeaderObject,
108
+ ...secondHeaderObj,
109
+ };
110
+
111
+ await wait();
112
+
113
+ push({ search: makeSearch(search, true) });
114
+ };
115
+
116
+ const handleClickEditField = async (
117
+ forTarget,
118
+ targetUid,
119
+ attributeName,
120
+ type,
121
+ firstHeaderObj,
122
+ secondHeaderObj,
123
+ thirdHeaderObj,
124
+ fourthHeaderObj,
125
+ fifthHeaderObj
126
+ ) => {
127
+ const attributeType = getAttributeDisplayedType(type);
128
+
129
+ await wait();
130
+
131
+ const search = {
132
+ modalType: 'attribute',
133
+ actionType: 'edit',
134
+ settingType: 'base',
135
+ forTarget,
136
+ targetUid,
137
+ attributeName,
138
+ attributeType,
139
+ step: type === 'component' ? '2' : null,
140
+ ...firstHeaderObj,
141
+ ...secondHeaderObj,
142
+ ...thirdHeaderObj,
143
+ ...fourthHeaderObj,
144
+ ...fifthHeaderObj,
145
+ };
146
+
147
+ await wait();
148
+
149
+ push({ search: makeSearch(search, true) });
150
+ };
151
+
152
+ const getDescription = () => {
153
+ const description = get(modifiedData, [firstMainDataPath, 'schema', 'description'], null);
154
+
155
+ return (
156
+ description ||
157
+ formatMessage({
158
+ id: `${pluginId}.modelPage.contentHeader.emptyDescription.description`,
159
+ })
160
+ );
161
+ };
162
+
163
+ const wait = async () => {
164
+ togglePrompt(false);
165
+
166
+ return new Promise(resolve => setTimeout(resolve, 100));
167
+ };
168
+ const label = get(modifiedData, [firstMainDataPath, 'schema', 'name'], '');
169
+ const kind = get(modifiedData, [firstMainDataPath, 'schema', 'kind'], '');
170
+
171
+ const headerProps = {
172
+ actions: isInDevelopmentMode
173
+ ? [
174
+ {
175
+ color: 'cancel',
176
+ onClick: () => {
177
+ toggleModalCancel();
178
+ },
179
+ label: formatMessage({
180
+ id: `${pluginId}.form.button.cancel`,
181
+ }),
182
+ type: 'button',
183
+ disabled: isEqual(modifiedData, initialData),
184
+ },
185
+ {
186
+ className: 'button-submit',
187
+ color: 'success',
188
+ onClick: () => submitData(),
189
+ label: formatMessage({
190
+ id: `${pluginId}.form.button.save`,
191
+ }),
192
+ type: 'submit',
193
+ disabled: isEqual(modifiedData, initialData),
194
+ },
195
+ ]
196
+ : [],
197
+ title: {
198
+ label,
199
+ cta:
200
+ isInDevelopmentMode && !isFromPlugin
201
+ ? {
202
+ icon: 'pencil-alt',
203
+ onClick: async () => {
204
+ await wait();
205
+
206
+ const contentType = kind || firstMainDataPath;
207
+
208
+ if (contentType === 'collectionType') {
209
+ emitEvent('willEditNameOfContentType');
210
+ }
211
+ if (contentType === 'singleType') {
212
+ emitEvent('willEditNameOfSingleType');
213
+ }
214
+
215
+ push({
216
+ search: makeSearch({
217
+ modalType: firstMainDataPath,
218
+ actionType: 'edit',
219
+ settingType: 'base',
220
+ forTarget: firstMainDataPath,
221
+ targetUid,
222
+ header_label_1: label,
223
+ header_icon_isCustom_1: false,
224
+ header_icon_name_1:
225
+ contentType === 'singleType' ? contentType : firstMainDataPath,
226
+ headerId: getTrad('modalForm.header-edit'),
227
+ }),
228
+ });
229
+ },
230
+ }
231
+ : null,
232
+ },
233
+ content: getDescription(),
234
+ };
235
+
236
+ const listTitle = [
237
+ formatMessage(
238
+ {
239
+ id: `${pluginId}.table.attributes.title.${attributesLength > 1 ? 'plural' : 'singular'}`,
240
+ },
241
+ { number: attributesLength }
242
+ ),
243
+ ];
244
+
245
+ const addButtonProps = {
246
+ icon: true,
247
+ color: 'primary',
248
+ label: formatMessage({ id: `${pluginId}.button.attributes.add.another` }),
249
+ onClick: () => {
250
+ const headerDisplayObject = {
251
+ header_label_1: currentDataName,
252
+ header_icon_name_1: forTarget === 'contentType' ? contentTypeKind : forTarget,
253
+ header_icon_isCustom_1: false,
254
+ };
255
+ handleClickAddField(forTarget, targetUid, headerDisplayObject);
256
+ },
257
+ };
258
+
259
+ const listInjectedComponents = useMemo(() => {
260
+ return getComponents('listView', 'list.link', plugins, {
261
+ targetUid,
262
+ isTemporary,
263
+ isInContentTypeView,
264
+ contentTypeKind,
265
+ });
266
+ }, [plugins, isTemporary, targetUid, isInContentTypeView, contentTypeKind]);
267
+
268
+ const listActions = isInDevelopmentMode
269
+ ? [...listInjectedComponents, <ListButton {...addButtonProps} key="add-button" />]
270
+ : listInjectedComponents;
271
+
272
+ const CustomRow = props => {
273
+ const { name } = props;
274
+
275
+ return <ListRow {...props} attributeName={name} name={name} onClick={handleClickEditField} />;
276
+ };
277
+
278
+ CustomRow.defaultProps = {
279
+ name: null,
280
+ };
281
+
282
+ CustomRow.propTypes = {
283
+ name: PropTypes.string,
284
+ };
285
+
286
+ return (
287
+ <ListViewContext.Provider value={{ openModalAddField: handleClickAddField }}>
288
+ <Wrapper>
289
+ <BackHeader onClick={goBack} />
290
+ <Prompt
291
+ message={formatMessage({ id: getTrad('prompt.unsaved') })}
292
+ when={hasModelBeenModified && enablePrompt}
293
+ />
294
+ <div className="container-fluid">
295
+ <div className="row">
296
+ <LeftMenu wait={wait} />
297
+ <div className="col-md-9 content" style={{ paddingLeft: '30px', paddingRight: '30px' }}>
298
+ <Header {...headerProps} />
299
+
300
+ <ListWrapper style={{ marginBottom: 80 }}>
301
+ <ListHeader actions={listActions} title={listTitle} />
302
+ <List
303
+ items={convertAttrObjToArray(attributes)}
304
+ customRowComponent={props => <CustomRow {...props} />}
305
+ addComponentToDZ={handleClickAddComponentToDZ}
306
+ targetUid={targetUid}
307
+ dataType={forTarget}
308
+ dataTypeName={currentDataName}
309
+ mainTypeName={currentDataName}
310
+ editTarget={forTarget}
311
+ isMain
312
+ />
313
+ </ListWrapper>
314
+ </div>
315
+ </div>
316
+ </div>
317
+ </Wrapper>
318
+ </ListViewContext.Provider>
319
+ );
320
+ };
321
+
322
+ export default ListView;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * NotFoundPage
3
+ *
4
+ * This is the page we show when the user visits a url that doesn't have a route
5
+ *
6
+ * NOTE: while this component should technically be a stateless functional
7
+ * component (SFC), hot reloading does not currently support SFCs. If hot
8
+ * reloading is not a neccessity for you then you can refactor it and remove
9
+ * the linting exception.
10
+ */
11
+
12
+ import React from 'react';
13
+
14
+ import { NotFound } from 'strapi-helper-plugin';
15
+
16
+ function NotFoundPage(props) {
17
+ return <NotFound {...props} />;
18
+ }
19
+
20
+ export default NotFoundPage;
@@ -0,0 +1,22 @@
1
+ import React, { Suspense, lazy } from 'react';
2
+ import { Switch, Route, useRouteMatch, useParams } from 'react-router-dom';
3
+ import { LoadingIndicatorPage } from 'strapi-helper-plugin';
4
+
5
+ const ListView = lazy(() => import('../ListView'));
6
+
7
+ const RecursivePath = () => {
8
+ const { url } = useRouteMatch();
9
+ const { categoryUid } = useParams();
10
+
11
+ return (
12
+ <Suspense fallback={<LoadingIndicatorPage />}>
13
+ <Switch>
14
+ <Route path={`${url}/:componentUid`}>
15
+ <ListView categoryId={categoryUid} />
16
+ </Route>
17
+ </Switch>
18
+ </Suspense>
19
+ );
20
+ };
21
+
22
+ export default RecursivePath;
@@ -0,0 +1,5 @@
1
+ import { createContext } from 'react';
2
+
3
+ const DataManagerContext = createContext();
4
+
5
+ export default DataManagerContext;
@@ -0,0 +1,5 @@
1
+ import { createContext } from 'react';
2
+
3
+ const ListViewContext = createContext();
4
+
5
+ export default ListViewContext;
@@ -0,0 +1,6 @@
1
+ import { useContext } from 'react';
2
+ import DataManagerContext from '../contexts/DataManagerContext';
3
+
4
+ const useDataManager = () => useContext(DataManagerContext);
5
+
6
+ export default useDataManager;
@@ -0,0 +1,6 @@
1
+ import { useContext } from 'react';
2
+ import ListViewContext from '../contexts/ListViewContext';
3
+
4
+ const useListView = () => useContext(ListViewContext);
5
+
6
+ export default useListView;
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+
4
+ const Curve = props => (
5
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.08 21" {...props}>
6
+ <g>
7
+ <path
8
+ d="M2.58 2.5q-1.2 16 16 16"
9
+ fill="none"
10
+ stroke={props.fill}
11
+ strokeLinecap="round"
12
+ strokeLinejoin="round"
13
+ strokeWidth="5"
14
+ />
15
+ </g>
16
+ </svg>
17
+ );
18
+
19
+ Curve.defaultProps = {
20
+ fill: '#f3f4f4',
21
+ };
22
+ Curve.propTypes = {
23
+ fill: PropTypes.string,
24
+ };
25
+
26
+ export default Curve;