@strapi/admin 4.5.1 → 4.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin/src/components/LeftMenu/index.js +22 -4
- package/admin/src/content-manager/components/DynamicTable/CellContent/RelationMultiple/index.js +4 -3
- package/admin/src/content-manager/components/Inputs/index.js +5 -19
- package/admin/src/content-manager/hooks/useLazyComponents/index.js +44 -0
- package/admin/src/content-manager/pages/CollectionTypeRecursivePath/components/ErrorFallback.js +13 -0
- package/admin/src/content-manager/pages/CollectionTypeRecursivePath/index.js +2 -1
- package/admin/src/content-manager/pages/EditView/GridRow/index.js +62 -0
- package/admin/src/content-manager/pages/EditView/index.js +74 -154
- package/admin/src/content-manager/pages/EditView/selectors.js +14 -0
- package/admin/src/content-manager/pages/EditView/utils/createAttributesLayout.js +11 -6
- package/admin/src/content-manager/pages/EditView/utils/getCustomFieldUidsFromLayout.js +18 -0
- package/admin/src/content-manager/pages/EditView/utils/index.js +1 -0
- package/admin/src/content-manager/pages/EditViewLayoutManager/index.js +1 -1
- package/admin/src/content-manager/pages/ListSettingsView/components/Settings.js +79 -76
- package/admin/src/core/apis/CustomFields.js +46 -1
- package/admin/src/pages/MarketplacePage/components/SortSelect/index.js +20 -0
- package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/FormApiTokenContainer/index.js +2 -2
- package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/FormBody/index.js +1 -1
- package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/components/FormHead/index.js +1 -1
- package/admin/src/translations/en.json +4 -0
- package/admin/src/translations/nl.json +210 -23
- package/admin/src/translations/pt.json +33 -32
- package/admin/src/translations/ru.json +789 -489
- package/admin/src/translations/zh.json +280 -95
- package/build/{7692.31e83caa.chunk.js → 1233.80b05d66.chunk.js} +144 -445
- package/build/1920.74a262e7.chunk.js +245 -0
- package/build/2438.61291207.chunk.js +2183 -0
- package/build/2517.9b4940f3.chunk.js +117 -0
- package/build/4306.f03c2b46.chunk.js +98 -0
- package/build/4318.7931eee7.chunk.js +30 -0
- package/build/4986.3820d11d.chunk.js +145 -0
- package/build/{8469.41c8d25f.chunk.js → 5015.f080b64e.chunk.js} +6 -1
- package/build/504.9aeff724.chunk.js +758 -0
- package/build/805.e991a370.chunk.js +138 -0
- package/build/8633.8da5488a.chunk.js +1 -0
- package/build/9707.a0cc4ad8.chunk.js +70 -0
- package/build/Admin-authenticatedApp.1e1d3bdd.chunk.js +80 -0
- package/build/Admin_InternalErrorPage.e0317a5e.chunk.js +1 -0
- package/build/Admin_homePage.54e33c2d.chunk.js +77 -0
- package/build/Admin_marketplace.8219fda6.chunk.js +26 -0
- package/build/Admin_pluginsPage.3c872de7.chunk.js +6 -0
- package/build/Admin_profilePage.e9fcce92.chunk.js +15 -0
- package/build/Admin_settingsPage.a1a5218b.chunk.js +178 -0
- package/build/admin-app.9cb0abc7.chunk.js +112 -0
- package/build/admin-edit-roles-page.23f15909.chunk.js +1 -0
- package/build/admin-edit-users.283b49ed.chunk.js +10 -0
- package/build/admin-users.a0748674.chunk.js +11 -0
- package/build/api-tokens-list-page.700e575f.chunk.js +16 -0
- package/build/content-manager.01e04e11.chunk.js +1200 -0
- package/build/content-type-builder-list-view.4412efc3.chunk.js +201 -0
- package/build/content-type-builder-translation-pt-json.96a31576.chunk.js +1 -0
- package/build/content-type-builder-translation-zh-json.3b0afd31.chunk.js +1 -0
- package/build/content-type-builder.848a9610.chunk.js +145 -0
- package/build/email-settings-page.d44a57cb.chunk.js +15 -0
- package/build/email-translation-pt-json.159505ab.chunk.js +1 -0
- package/build/email-translation-zh-json.62b1c6fe.chunk.js +1 -0
- package/build/en-json.7dd57947.chunk.js +1 -0
- package/build/i18n-settings-page.195d42fe.chunk.js +1 -0
- package/build/i18n-translation-zh-json.eeebb849.chunk.js +1 -0
- package/build/index.html +1 -1
- package/build/main.f31112a5.js +2034 -0
- package/build/nl-json.26f39180.chunk.js +1 -0
- package/build/pt-json.cd67ba86.chunk.js +1 -0
- package/build/ru-json.8830286f.chunk.js +1 -0
- package/build/runtime~main.f91e75cd.js +2 -0
- package/build/sso-settings-page.9f091262.chunk.js +1 -0
- package/build/upload-settings.450cab1a.chunk.js +18 -0
- package/build/upload-translation-pt-json.5c452b48.chunk.js +1 -0
- package/build/upload-translation-zh-json.ac5711de.chunk.js +1 -0
- package/build/upload.a73936d9.chunk.js +64 -0
- package/build/users-advanced-settings-page.dc23bc56.chunk.js +13 -0
- package/build/users-email-settings-page.6541d372.chunk.js +28 -0
- package/build/users-permissions-translation-zh-json.92f406f9.chunk.js +1 -0
- package/build/users-providers-settings-page.e11a2f64.chunk.js +33 -0
- package/build/users-roles-settings-page.445e5e16.chunk.js +30 -0
- package/build/webhook-edit-page.14ad1e6e.chunk.js +75 -0
- package/build/webhook-list-page.b87821f2.chunk.js +42 -0
- package/build/zh-json.2ecc6b99.chunk.js +1 -0
- package/jest.config.front.js +0 -1
- package/package.json +11 -10
- package/webpack.alias.js +3 -2
- package/webpack.config.js +13 -1
- package/build/1856.db9f5782.chunk.js +0 -174
- package/build/2077.fed8c9c3.chunk.js +0 -206
- package/build/2912.fccb2c43.chunk.js +0 -259
- package/build/4318.5e670740.chunk.js +0 -30
- package/build/4610.7614b003.chunk.js +0 -342
- package/build/4715.8e33d630.chunk.js +0 -387
- package/build/4800.a6935af6.chunk.js +0 -1
- package/build/4982.9e58ea3f.chunk.js +0 -325
- package/build/6925.bb6dd64d.chunk.js +0 -762
- package/build/7379.e972985f.chunk.js +0 -1
- package/build/7841.4804bd98.chunk.js +0 -259
- package/build/7866.6db2248d.chunk.js +0 -505
- package/build/8380.37126e0d.chunk.js +0 -299
- package/build/8549.5e5fb6b6.chunk.js +0 -159
- package/build/8738.5a02bffb.chunk.js +0 -463
- package/build/9066.5d980488.chunk.js +0 -101
- package/build/9420.7addc099.chunk.js +0 -505
- package/build/9649.b6afc945.chunk.js +0 -199
- package/build/Admin-authenticatedApp.c07d2a86.chunk.js +0 -80
- package/build/Admin_InternalErrorPage.12e24216.chunk.js +0 -1
- package/build/Admin_homePage.26d32e30.chunk.js +0 -72
- package/build/Admin_marketplace.444ff7b8.chunk.js +0 -22
- package/build/Admin_pluginsPage.4d59785a.chunk.js +0 -1
- package/build/Admin_profilePage.da32abbc.chunk.js +0 -15
- package/build/Admin_settingsPage.bf2234e1.chunk.js +0 -178
- package/build/admin-app.b157c10a.chunk.js +0 -112
- package/build/admin-edit-roles-page.69d9fcb2.chunk.js +0 -1
- package/build/admin-edit-users.c585212f.chunk.js +0 -10
- package/build/admin-users.d71f198a.chunk.js +0 -11
- package/build/api-tokens-list-page.bb36535f.chunk.js +0 -16
- package/build/content-manager.f38edbb6.chunk.js +0 -1202
- package/build/content-type-builder-list-view.5b3cd768.chunk.js +0 -194
- package/build/content-type-builder-translation-pt-json.766bd747.chunk.js +0 -1
- package/build/content-type-builder-translation-zh-json.2cc55621.chunk.js +0 -1
- package/build/content-type-builder.16af63a6.chunk.js +0 -145
- package/build/email-settings-page.91c925a5.chunk.js +0 -103
- package/build/email-translation-pt-json.959ea070.chunk.js +0 -1
- package/build/email-translation-zh-json.3455468b.chunk.js +0 -1
- package/build/en-json.4a269f6b.chunk.js +0 -1
- package/build/i18n-settings-page.4ef64441.chunk.js +0 -101
- package/build/main.ca8b0ee3.js +0 -9465
- package/build/nl-json.2b8cc3a0.chunk.js +0 -1
- package/build/pt-json.3161ca22.chunk.js +0 -1
- package/build/ru-json.d7cfc2ff.chunk.js +0 -1
- package/build/runtime~main.ede9da1e.js +0 -2
- package/build/sso-settings-page.9ceb0140.chunk.js +0 -1
- package/build/upload-settings.3f7ad973.chunk.js +0 -101
- package/build/upload-translation-zh-json.ee8fba96.chunk.js +0 -1
- package/build/upload.7084cea6.chunk.js +0 -7
- package/build/users-advanced-settings-page.6a838320.chunk.js +0 -101
- package/build/users-email-settings-page.73c41236.chunk.js +0 -1
- package/build/users-permissions-translation-zh-json.e03ae2a4.chunk.js +0 -1
- package/build/users-providers-settings-page.f8e78537.chunk.js +0 -1
- package/build/users-roles-settings-page.b33ec5e5.chunk.js +0 -30
- package/build/webhook-edit-page.dc9442ce.chunk.js +0 -23
- package/build/webhook-list-page.a110c462.chunk.js +0 -134
- package/build/zh-json.608aaf24.chunk.js +0 -1
|
@@ -2,7 +2,7 @@ import React, { useRef, useState } from 'react';
|
|
|
2
2
|
import styled from 'styled-components';
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
4
|
import { useIntl } from 'react-intl';
|
|
5
|
-
import { NavLink as RouterNavLink } from 'react-router-dom';
|
|
5
|
+
import { NavLink as RouterNavLink, useLocation } from 'react-router-dom';
|
|
6
6
|
import { Divider } from '@strapi/design-system/Divider';
|
|
7
7
|
import {
|
|
8
8
|
MainNav,
|
|
@@ -19,7 +19,7 @@ import { Typography } from '@strapi/design-system/Typography';
|
|
|
19
19
|
import { Stack } from '@strapi/design-system/Stack';
|
|
20
20
|
import Write from '@strapi/icons/Write';
|
|
21
21
|
import Exit from '@strapi/icons/Exit';
|
|
22
|
-
import { auth, usePersistentState, useAppInfos } from '@strapi/helper-plugin';
|
|
22
|
+
import { auth, usePersistentState, useAppInfos, useTracking } from '@strapi/helper-plugin';
|
|
23
23
|
import useConfigurations from '../../hooks/useConfigurations';
|
|
24
24
|
|
|
25
25
|
const LinkUserWrapper = styled(Box)`
|
|
@@ -59,6 +59,8 @@ const LeftMenu = ({ generalSectionLinks, pluginsSectionLinks }) => {
|
|
|
59
59
|
const [condensed, setCondensed] = usePersistentState('navbar-condensed', false);
|
|
60
60
|
const { userDisplayName } = useAppInfos();
|
|
61
61
|
const { formatMessage } = useIntl();
|
|
62
|
+
const { trackUsage } = useTracking();
|
|
63
|
+
const { pathname } = useLocation();
|
|
62
64
|
|
|
63
65
|
const initials = userDisplayName
|
|
64
66
|
.split(' ')
|
|
@@ -82,6 +84,10 @@ const LeftMenu = ({ generalSectionLinks, pluginsSectionLinks }) => {
|
|
|
82
84
|
}
|
|
83
85
|
};
|
|
84
86
|
|
|
87
|
+
const handleClickOnLink = (destination = null) => {
|
|
88
|
+
trackUsage('willNavigate', { from: pathname, to: destination });
|
|
89
|
+
};
|
|
90
|
+
|
|
85
91
|
const menuTitle = formatMessage({
|
|
86
92
|
id: 'app.components.LeftMenu.navbrand.title',
|
|
87
93
|
defaultMessage: 'Strapi Dashboard',
|
|
@@ -110,7 +116,12 @@ const LeftMenu = ({ generalSectionLinks, pluginsSectionLinks }) => {
|
|
|
110
116
|
<Divider />
|
|
111
117
|
|
|
112
118
|
<NavSections>
|
|
113
|
-
<NavLink
|
|
119
|
+
<NavLink
|
|
120
|
+
as={RouterNavLink}
|
|
121
|
+
to="/content-manager"
|
|
122
|
+
icon={<Write />}
|
|
123
|
+
onClick={() => handleClickOnLink('/content-manager')}
|
|
124
|
+
>
|
|
114
125
|
{formatMessage({ id: 'global.content-manager', defaultMessage: 'Content manager' })}
|
|
115
126
|
</NavLink>
|
|
116
127
|
|
|
@@ -125,7 +136,13 @@ const LeftMenu = ({ generalSectionLinks, pluginsSectionLinks }) => {
|
|
|
125
136
|
const Icon = link.icon;
|
|
126
137
|
|
|
127
138
|
return (
|
|
128
|
-
<NavLink
|
|
139
|
+
<NavLink
|
|
140
|
+
as={RouterNavLink}
|
|
141
|
+
to={link.to}
|
|
142
|
+
key={link.to}
|
|
143
|
+
icon={<Icon />}
|
|
144
|
+
onClick={() => handleClickOnLink(link.to)}
|
|
145
|
+
>
|
|
129
146
|
{formatMessage(link.intlLabel)}
|
|
130
147
|
</NavLink>
|
|
131
148
|
);
|
|
@@ -152,6 +169,7 @@ const LeftMenu = ({ generalSectionLinks, pluginsSectionLinks }) => {
|
|
|
152
169
|
to={link.to}
|
|
153
170
|
key={link.to}
|
|
154
171
|
icon={<LinkIcon />}
|
|
172
|
+
onClick={() => handleClickOnLink(link.to)}
|
|
155
173
|
>
|
|
156
174
|
{formatMessage(link.intlLabel)}
|
|
157
175
|
</NavLink>
|
package/admin/src/content-manager/components/DynamicTable/CellContent/RelationMultiple/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { useIntl } from 'react-intl';
|
|
|
5
5
|
import { Typography } from '@strapi/design-system/Typography';
|
|
6
6
|
import { Box } from '@strapi/design-system/Box';
|
|
7
7
|
import { Badge } from '@strapi/design-system/Badge';
|
|
8
|
+
import { Flex } from '@strapi/design-system/Flex';
|
|
8
9
|
import { SimpleMenu, MenuItem } from '@strapi/design-system/SimpleMenu';
|
|
9
10
|
import { Loader } from '@strapi/design-system/Loader';
|
|
10
11
|
import styled from 'styled-components';
|
|
@@ -38,8 +39,8 @@ const RelationMultiple = ({ fieldSchema, metadatas, name, entityId, value, conte
|
|
|
38
39
|
const [isOpen, setIsOpen] = useState(false);
|
|
39
40
|
|
|
40
41
|
const Label = (
|
|
41
|
-
|
|
42
|
-
<Badge>{value.count}</Badge>
|
|
42
|
+
<Flex gap={1} wrap="nowrap">
|
|
43
|
+
<Badge>{value.count}</Badge>
|
|
43
44
|
{formatMessage(
|
|
44
45
|
{
|
|
45
46
|
id: 'content-manager.containers.ListPage.items',
|
|
@@ -47,7 +48,7 @@ const RelationMultiple = ({ fieldSchema, metadatas, name, entityId, value, conte
|
|
|
47
48
|
},
|
|
48
49
|
{ number: value.count }
|
|
49
50
|
)}
|
|
50
|
-
|
|
51
|
+
</Flex>
|
|
51
52
|
);
|
|
52
53
|
|
|
53
54
|
const notify = () => {
|
|
@@ -5,7 +5,7 @@ import get from 'lodash/get';
|
|
|
5
5
|
import omit from 'lodash/omit';
|
|
6
6
|
import take from 'lodash/take';
|
|
7
7
|
import isEqual from 'react-fast-compare';
|
|
8
|
-
import { GenericInput, NotAllowedInput, useLibrary
|
|
8
|
+
import { GenericInput, NotAllowedInput, useLibrary } from '@strapi/helper-plugin';
|
|
9
9
|
import { useContentTypeLayout } from '../../hooks';
|
|
10
10
|
import { getFieldName } from '../../utils';
|
|
11
11
|
import Wysiwyg from '../Wysiwyg';
|
|
@@ -37,11 +37,11 @@ function Inputs({
|
|
|
37
37
|
queryInfos,
|
|
38
38
|
value,
|
|
39
39
|
size,
|
|
40
|
+
customFieldInputs,
|
|
40
41
|
}) {
|
|
41
42
|
const { fields } = useLibrary();
|
|
42
43
|
const { formatMessage } = useIntl();
|
|
43
44
|
const { contentType: currentContentTypeLayout } = useContentTypeLayout();
|
|
44
|
-
const customFieldsRegistry = useCustomFields();
|
|
45
45
|
|
|
46
46
|
const disabled = useMemo(() => !get(metadatas, 'editable', true), [metadatas]);
|
|
47
47
|
const { type, customField: customFieldUid } = fieldSchema;
|
|
@@ -194,19 +194,6 @@ function Inputs({
|
|
|
194
194
|
return minutes % metadatas.step === 0 ? metadatas.step : step;
|
|
195
195
|
}, [inputType, inputValue, metadatas.step, step]);
|
|
196
196
|
|
|
197
|
-
// Memoize the component to avoid remounting it and losing state
|
|
198
|
-
const CustomFieldInput = useMemo(() => {
|
|
199
|
-
if (customFieldUid) {
|
|
200
|
-
const customField = customFieldsRegistry.get(customFieldUid);
|
|
201
|
-
const CustomFieldInput = React.lazy(customField.components.Input);
|
|
202
|
-
|
|
203
|
-
return CustomFieldInput;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Not a custom field, component won't be used
|
|
207
|
-
return null;
|
|
208
|
-
}, [customFieldUid, customFieldsRegistry]);
|
|
209
|
-
|
|
210
197
|
if (visible === false) {
|
|
211
198
|
return null;
|
|
212
199
|
}
|
|
@@ -268,12 +255,9 @@ function Inputs({
|
|
|
268
255
|
media: fields.media,
|
|
269
256
|
wysiwyg: Wysiwyg,
|
|
270
257
|
...fields,
|
|
258
|
+
...customFieldInputs,
|
|
271
259
|
};
|
|
272
260
|
|
|
273
|
-
if (customFieldUid) {
|
|
274
|
-
customInputs[customFieldUid] = CustomFieldInput;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
261
|
return (
|
|
278
262
|
<GenericInput
|
|
279
263
|
attribute={fieldSchema}
|
|
@@ -309,6 +293,7 @@ Inputs.defaultProps = {
|
|
|
309
293
|
size: undefined,
|
|
310
294
|
value: null,
|
|
311
295
|
queryInfos: {},
|
|
296
|
+
customFieldInputs: {},
|
|
312
297
|
};
|
|
313
298
|
|
|
314
299
|
Inputs.propTypes = {
|
|
@@ -330,6 +315,7 @@ Inputs.propTypes = {
|
|
|
330
315
|
defaultParams: PropTypes.object,
|
|
331
316
|
endPoint: PropTypes.string,
|
|
332
317
|
}),
|
|
318
|
+
customFieldInputs: PropTypes.object,
|
|
333
319
|
};
|
|
334
320
|
|
|
335
321
|
const Memoized = memo(Inputs, isEqual);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { useCustomFields } from '@strapi/helper-plugin';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @description
|
|
6
|
+
* A hook to lazy load custom field components
|
|
7
|
+
* @param {Array.<string>} componentUids - The uids to look up components
|
|
8
|
+
* @returns object
|
|
9
|
+
*/
|
|
10
|
+
const useLazyComponents = (componentUids) => {
|
|
11
|
+
const [lazyComponentStore, setLazyComponentStore] = useState({});
|
|
12
|
+
const [loading, setLoading] = useState(true);
|
|
13
|
+
const customFieldsRegistry = useCustomFields();
|
|
14
|
+
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
const lazyLoadComponents = async (uids, components) => {
|
|
17
|
+
const modules = await Promise.all(components);
|
|
18
|
+
|
|
19
|
+
uids.forEach((uid, index) => {
|
|
20
|
+
if (!Object.keys(lazyComponentStore).includes(uid)) {
|
|
21
|
+
setLazyComponentStore({ ...lazyComponentStore, [uid]: modules[index].default });
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
if (componentUids.length) {
|
|
27
|
+
const componentPromises = componentUids.map((uid) => {
|
|
28
|
+
const customField = customFieldsRegistry.get(uid);
|
|
29
|
+
|
|
30
|
+
return customField.components.Input();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
lazyLoadComponents(componentUids, componentPromises);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (componentUids.length === Object.keys(lazyComponentStore).length) {
|
|
37
|
+
setLoading(false);
|
|
38
|
+
}
|
|
39
|
+
}, [componentUids, customFieldsRegistry, loading, lazyComponentStore]);
|
|
40
|
+
|
|
41
|
+
return { isLazyLoading: loading, lazyComponentStore };
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export default useLazyComponents;
|
package/admin/src/content-manager/pages/CollectionTypeRecursivePath/components/ErrorFallback.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AnErrorOccurred } from '@strapi/helper-plugin';
|
|
3
|
+
import { Box } from '@strapi/design-system/Box';
|
|
4
|
+
|
|
5
|
+
const ErrorFallback = () => {
|
|
6
|
+
return (
|
|
7
|
+
<Box padding={8}>
|
|
8
|
+
<AnErrorOccurred />
|
|
9
|
+
</Box>
|
|
10
|
+
);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default ErrorFallback;
|
|
@@ -3,7 +3,7 @@ import { Switch, Route } from 'react-router-dom';
|
|
|
3
3
|
import { ErrorBoundary } from 'react-error-boundary';
|
|
4
4
|
import { get } from 'lodash';
|
|
5
5
|
import PropTypes from 'prop-types';
|
|
6
|
-
import {
|
|
6
|
+
import { LoadingIndicatorPage, CheckPagePermissions } from '@strapi/helper-plugin';
|
|
7
7
|
import permissions from '../../../permissions';
|
|
8
8
|
import { ContentTypeLayoutContext } from '../../contexts';
|
|
9
9
|
import { useFetchContentTypeLayout } from '../../hooks';
|
|
@@ -12,6 +12,7 @@ import EditViewLayoutManager from '../EditViewLayoutManager';
|
|
|
12
12
|
import EditSettingsView from '../EditSettingsView';
|
|
13
13
|
import ListViewLayout from '../ListViewLayoutManager';
|
|
14
14
|
import ListSettingsView from '../ListSettingsView';
|
|
15
|
+
import ErrorFallback from './components/ErrorFallback';
|
|
15
16
|
|
|
16
17
|
const cmPermissions = permissions.contentManager;
|
|
17
18
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { Grid, GridItem } from '@strapi/design-system/Grid';
|
|
4
|
+
import Inputs from '../../../components/Inputs';
|
|
5
|
+
import FieldComponent from '../../../components/FieldComponent';
|
|
6
|
+
|
|
7
|
+
const GridRow = ({ columns, customFieldInputs }) => {
|
|
8
|
+
return (
|
|
9
|
+
<Grid gap={4}>
|
|
10
|
+
{columns.map(({ fieldSchema, labelAction, metadatas, name, size, queryInfos }) => {
|
|
11
|
+
const isComponent = fieldSchema.type === 'component';
|
|
12
|
+
|
|
13
|
+
if (isComponent) {
|
|
14
|
+
const { component, max, min, repeatable = false, required = false } = fieldSchema;
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<GridItem col={size} s={12} xs={12} key={component}>
|
|
18
|
+
<FieldComponent
|
|
19
|
+
componentUid={component}
|
|
20
|
+
labelAction={labelAction}
|
|
21
|
+
isRepeatable={repeatable}
|
|
22
|
+
intlLabel={{
|
|
23
|
+
id: metadatas.label,
|
|
24
|
+
defaultMessage: metadatas.label,
|
|
25
|
+
}}
|
|
26
|
+
max={max}
|
|
27
|
+
min={min}
|
|
28
|
+
name={name}
|
|
29
|
+
required={required}
|
|
30
|
+
/>
|
|
31
|
+
</GridItem>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<GridItem col={size} key={name} s={12} xs={12}>
|
|
37
|
+
<Inputs
|
|
38
|
+
size={size}
|
|
39
|
+
fieldSchema={fieldSchema}
|
|
40
|
+
keys={name}
|
|
41
|
+
labelAction={labelAction}
|
|
42
|
+
metadatas={metadatas}
|
|
43
|
+
queryInfos={queryInfos}
|
|
44
|
+
customFieldInputs={customFieldInputs}
|
|
45
|
+
/>
|
|
46
|
+
</GridItem>
|
|
47
|
+
);
|
|
48
|
+
})}
|
|
49
|
+
</Grid>
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
GridRow.defaultProps = {
|
|
54
|
+
customFieldInputs: {},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
GridRow.propTypes = {
|
|
58
|
+
columns: PropTypes.array.isRequired,
|
|
59
|
+
customFieldInputs: PropTypes.object,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export default GridRow;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { memo } from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import
|
|
3
|
+
import { useSelector } from 'react-redux';
|
|
4
4
|
import {
|
|
5
5
|
CheckPermissions,
|
|
6
|
-
LoadingIndicatorPage,
|
|
7
6
|
useTracking,
|
|
8
7
|
LinkButton,
|
|
8
|
+
LoadingIndicatorPage,
|
|
9
9
|
} from '@strapi/helper-plugin';
|
|
10
10
|
import { useIntl } from 'react-intl';
|
|
11
11
|
import { ContentLayout } from '@strapi/design-system/Layout';
|
|
@@ -18,73 +18,60 @@ import Pencil from '@strapi/icons/Pencil';
|
|
|
18
18
|
import { InjectionZone } from '../../../shared/components';
|
|
19
19
|
import permissions from '../../../permissions';
|
|
20
20
|
import DynamicZone from '../../components/DynamicZone';
|
|
21
|
-
|
|
22
|
-
import Inputs from '../../components/Inputs';
|
|
21
|
+
|
|
23
22
|
import CollectionTypeFormWrapper from '../../components/CollectionTypeFormWrapper';
|
|
24
23
|
import EditViewDataManagerProvider from '../../components/EditViewDataManagerProvider';
|
|
25
24
|
import SingleTypeFormWrapper from '../../components/SingleTypeFormWrapper';
|
|
26
25
|
import { getTrad } from '../../utils';
|
|
26
|
+
import useLazyComponents from '../../hooks/useLazyComponents';
|
|
27
27
|
import DraftAndPublishBadge from './DraftAndPublishBadge';
|
|
28
28
|
import Informations from './Informations';
|
|
29
29
|
import Header from './Header';
|
|
30
|
-
import {
|
|
30
|
+
import { getFieldsActionMatchingPermissions } from './utils';
|
|
31
31
|
import DeleteLink from './DeleteLink';
|
|
32
|
+
import GridRow from './GridRow';
|
|
33
|
+
import { selectCurrentLayout, selectAttributesLayout, selectCustomFieldUids } from './selectors';
|
|
32
34
|
|
|
33
35
|
const cmPermissions = permissions.contentManager;
|
|
34
36
|
const ctbPermissions = [{ action: 'plugin::content-type-builder.read', subject: null }];
|
|
35
37
|
|
|
36
38
|
/* eslint-disable react/no-array-index-key */
|
|
37
|
-
const EditView = ({
|
|
38
|
-
allowedActions,
|
|
39
|
-
isSingleType,
|
|
40
|
-
goBack,
|
|
41
|
-
layout,
|
|
42
|
-
slug,
|
|
43
|
-
id,
|
|
44
|
-
origin,
|
|
45
|
-
userPermissions,
|
|
46
|
-
}) => {
|
|
39
|
+
const EditView = ({ allowedActions, isSingleType, goBack, slug, id, origin, userPermissions }) => {
|
|
47
40
|
const { trackUsage } = useTracking();
|
|
48
41
|
const { formatMessage } = useIntl();
|
|
42
|
+
|
|
43
|
+
const { layout, formattedContentTypeLayout, customFieldUids } = useSelector((state) => ({
|
|
44
|
+
layout: selectCurrentLayout(state),
|
|
45
|
+
formattedContentTypeLayout: selectAttributesLayout(state),
|
|
46
|
+
customFieldUids: selectCustomFieldUids(state),
|
|
47
|
+
}));
|
|
48
|
+
|
|
49
|
+
const { isLazyLoading, lazyComponentStore } = useLazyComponents(customFieldUids);
|
|
50
|
+
|
|
49
51
|
const { createActionAllowedFields, readActionAllowedFields, updateActionAllowedFields } =
|
|
50
|
-
|
|
51
|
-
return getFieldsActionMatchingPermissions(userPermissions, slug);
|
|
52
|
-
}, [userPermissions, slug]);
|
|
52
|
+
getFieldsActionMatchingPermissions(userPermissions, slug);
|
|
53
53
|
|
|
54
|
-
const configurationPermissions =
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
: cmPermissions.collectionTypesConfigurations;
|
|
58
|
-
}, [isSingleType]);
|
|
54
|
+
const configurationPermissions = isSingleType
|
|
55
|
+
? cmPermissions.singleTypesConfigurations
|
|
56
|
+
: cmPermissions.collectionTypesConfigurations;
|
|
59
57
|
|
|
60
58
|
// // FIXME when changing the routing
|
|
61
59
|
const configurationsURL = `/content-manager/${
|
|
62
60
|
isSingleType ? 'singleType' : 'collectionType'
|
|
63
61
|
}/${slug}/configurations/edit`;
|
|
64
|
-
const currentContentTypeLayoutData = get(layout, ['contentType'], {});
|
|
65
62
|
|
|
66
|
-
const DataManagementWrapper =
|
|
67
|
-
() => (isSingleType ? SingleTypeFormWrapper : CollectionTypeFormWrapper),
|
|
68
|
-
[isSingleType]
|
|
69
|
-
);
|
|
63
|
+
const DataManagementWrapper = isSingleType ? SingleTypeFormWrapper : CollectionTypeFormWrapper;
|
|
70
64
|
|
|
71
65
|
// Check if a block is a dynamic zone
|
|
72
|
-
const isDynamicZone =
|
|
66
|
+
const isDynamicZone = (block) => {
|
|
73
67
|
return block.every((subBlock) => {
|
|
74
68
|
return subBlock.every((obj) => obj.fieldSchema.type === 'dynamiczone');
|
|
75
69
|
});
|
|
76
|
-
}
|
|
70
|
+
};
|
|
77
71
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return createAttributesLayout(
|
|
84
|
-
currentContentTypeLayoutData.layouts.edit,
|
|
85
|
-
currentContentTypeLayoutData.attributes
|
|
86
|
-
);
|
|
87
|
-
}, [currentContentTypeLayoutData]);
|
|
72
|
+
if (isLazyLoading) {
|
|
73
|
+
return <LoadingIndicatorPage />;
|
|
74
|
+
}
|
|
88
75
|
|
|
89
76
|
return (
|
|
90
77
|
<DataManagementWrapper allLayoutData={layout} slug={slug} id={id} origin={origin}>
|
|
@@ -132,110 +119,56 @@ const EditView = ({
|
|
|
132
119
|
<ContentLayout>
|
|
133
120
|
<Grid gap={4}>
|
|
134
121
|
<GridItem col={9} s={12}>
|
|
135
|
-
<
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
0: {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
} = row;
|
|
144
|
-
|
|
145
|
-
return (
|
|
146
|
-
<Box key={index}>
|
|
147
|
-
<Grid gap={4}>
|
|
148
|
-
<GridItem col={12} s={12} xs={12}>
|
|
149
|
-
<DynamicZone
|
|
150
|
-
name={name}
|
|
151
|
-
fieldSchema={fieldSchema}
|
|
152
|
-
labelAction={labelAction}
|
|
153
|
-
metadatas={metadatas}
|
|
154
|
-
/>
|
|
155
|
-
</GridItem>
|
|
156
|
-
</Grid>
|
|
157
|
-
</Box>
|
|
158
|
-
);
|
|
159
|
-
}
|
|
122
|
+
<Stack spacing={6}>
|
|
123
|
+
{formattedContentTypeLayout.map((row, index) => {
|
|
124
|
+
if (isDynamicZone(row)) {
|
|
125
|
+
const {
|
|
126
|
+
0: {
|
|
127
|
+
0: { name, fieldSchema, metadatas, labelAction },
|
|
128
|
+
},
|
|
129
|
+
} = row;
|
|
160
130
|
|
|
161
131
|
return (
|
|
162
|
-
<Box
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
<Stack spacing={6}>
|
|
174
|
-
{row.map((grid, gridIndex) => {
|
|
175
|
-
return (
|
|
176
|
-
<Grid gap={4} key={gridIndex}>
|
|
177
|
-
{grid.map(
|
|
178
|
-
({
|
|
179
|
-
fieldSchema,
|
|
180
|
-
labelAction,
|
|
181
|
-
metadatas,
|
|
182
|
-
name,
|
|
183
|
-
size,
|
|
184
|
-
queryInfos,
|
|
185
|
-
}) => {
|
|
186
|
-
const isComponent = fieldSchema.type === 'component';
|
|
187
|
-
|
|
188
|
-
if (isComponent) {
|
|
189
|
-
const {
|
|
190
|
-
component,
|
|
191
|
-
max,
|
|
192
|
-
min,
|
|
193
|
-
repeatable = false,
|
|
194
|
-
required = false,
|
|
195
|
-
} = fieldSchema;
|
|
196
|
-
|
|
197
|
-
return (
|
|
198
|
-
<GridItem col={size} s={12} xs={12} key={component}>
|
|
199
|
-
<FieldComponent
|
|
200
|
-
componentUid={component}
|
|
201
|
-
labelAction={labelAction}
|
|
202
|
-
isRepeatable={repeatable}
|
|
203
|
-
intlLabel={{
|
|
204
|
-
id: metadatas.label,
|
|
205
|
-
defaultMessage: metadatas.label,
|
|
206
|
-
}}
|
|
207
|
-
max={max}
|
|
208
|
-
min={min}
|
|
209
|
-
name={name}
|
|
210
|
-
required={required}
|
|
211
|
-
/>
|
|
212
|
-
</GridItem>
|
|
213
|
-
);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
return (
|
|
217
|
-
<GridItem col={size} key={name} s={12} xs={12}>
|
|
218
|
-
<Inputs
|
|
219
|
-
size={size}
|
|
220
|
-
fieldSchema={fieldSchema}
|
|
221
|
-
keys={name}
|
|
222
|
-
labelAction={labelAction}
|
|
223
|
-
metadatas={metadatas}
|
|
224
|
-
queryInfos={queryInfos}
|
|
225
|
-
/>
|
|
226
|
-
</GridItem>
|
|
227
|
-
);
|
|
228
|
-
}
|
|
229
|
-
)}
|
|
230
|
-
</Grid>
|
|
231
|
-
);
|
|
232
|
-
})}
|
|
233
|
-
</Stack>
|
|
132
|
+
<Box key={index}>
|
|
133
|
+
<Grid gap={4}>
|
|
134
|
+
<GridItem col={12} s={12} xs={12}>
|
|
135
|
+
<DynamicZone
|
|
136
|
+
name={name}
|
|
137
|
+
fieldSchema={fieldSchema}
|
|
138
|
+
labelAction={labelAction}
|
|
139
|
+
metadatas={metadatas}
|
|
140
|
+
/>
|
|
141
|
+
</GridItem>
|
|
142
|
+
</Grid>
|
|
234
143
|
</Box>
|
|
235
144
|
);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return (
|
|
148
|
+
<Box
|
|
149
|
+
key={index}
|
|
150
|
+
hasRadius
|
|
151
|
+
background="neutral0"
|
|
152
|
+
shadow="tableShadow"
|
|
153
|
+
paddingLeft={6}
|
|
154
|
+
paddingRight={6}
|
|
155
|
+
paddingTop={6}
|
|
156
|
+
paddingBottom={6}
|
|
157
|
+
borderColor="neutral150"
|
|
158
|
+
>
|
|
159
|
+
<Stack spacing={6}>
|
|
160
|
+
{row.map((grid, gridRowIndex) => (
|
|
161
|
+
<GridRow
|
|
162
|
+
columns={grid}
|
|
163
|
+
customFieldInputs={lazyComponentStore}
|
|
164
|
+
key={gridRowIndex}
|
|
165
|
+
/>
|
|
166
|
+
))}
|
|
167
|
+
</Stack>
|
|
168
|
+
</Box>
|
|
169
|
+
);
|
|
170
|
+
})}
|
|
171
|
+
</Stack>
|
|
239
172
|
</GridItem>
|
|
240
173
|
<GridItem col={3} s={12}>
|
|
241
174
|
<Stack spacing={2}>
|
|
@@ -328,16 +261,6 @@ EditView.propTypes = {
|
|
|
328
261
|
canCreate: PropTypes.bool.isRequired,
|
|
329
262
|
canDelete: PropTypes.bool.isRequired,
|
|
330
263
|
}).isRequired,
|
|
331
|
-
layout: PropTypes.shape({
|
|
332
|
-
components: PropTypes.object.isRequired,
|
|
333
|
-
contentType: PropTypes.shape({
|
|
334
|
-
uid: PropTypes.string.isRequired,
|
|
335
|
-
settings: PropTypes.object.isRequired,
|
|
336
|
-
metadatas: PropTypes.object.isRequired,
|
|
337
|
-
options: PropTypes.object.isRequired,
|
|
338
|
-
attributes: PropTypes.object.isRequired,
|
|
339
|
-
}).isRequired,
|
|
340
|
-
}).isRequired,
|
|
341
264
|
id: PropTypes.string,
|
|
342
265
|
isSingleType: PropTypes.bool,
|
|
343
266
|
goBack: PropTypes.func.isRequired,
|
|
@@ -346,7 +269,4 @@ EditView.propTypes = {
|
|
|
346
269
|
userPermissions: PropTypes.array,
|
|
347
270
|
};
|
|
348
271
|
|
|
349
|
-
export { EditView };
|
|
350
272
|
export default memo(EditView);
|
|
351
|
-
|
|
352
|
-
// export default () => 'TODO Edit view';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createSelector } from 'reselect';
|
|
2
|
+
import { createAttributesLayout, getCustomFieldUidsFromLayout } from './utils';
|
|
3
|
+
|
|
4
|
+
const selectCurrentLayout = (state) => state['content-manager_editViewLayoutManager'].currentLayout;
|
|
5
|
+
|
|
6
|
+
const selectAttributesLayout = createSelector(selectCurrentLayout, (layout) =>
|
|
7
|
+
createAttributesLayout(layout?.contentType ?? {})
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
const selectCustomFieldUids = createSelector(selectCurrentLayout, (layout) =>
|
|
11
|
+
getCustomFieldUidsFromLayout(layout)
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
export { selectCurrentLayout, selectAttributesLayout, selectCustomFieldUids };
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { get, isEmpty } from 'lodash';
|
|
2
|
-
// TODO: refacto this file to avoid eslint issues
|
|
3
|
-
/* eslint-disable no-restricted-syntax */
|
|
4
|
-
/* eslint-disable no-unused-vars */
|
|
5
2
|
|
|
6
|
-
const createAttributesLayout = (
|
|
3
|
+
const createAttributesLayout = (currentContentTypeLayoutData) => {
|
|
4
|
+
if (!currentContentTypeLayoutData.layouts) {
|
|
5
|
+
return [];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const currentLayout = currentContentTypeLayoutData.layouts.edit;
|
|
9
|
+
const attributes = currentContentTypeLayoutData.attributes;
|
|
10
|
+
|
|
7
11
|
const getType = (name) => get(attributes, [name, 'type'], '');
|
|
12
|
+
|
|
8
13
|
let currentRowIndex = 0;
|
|
9
14
|
const newLayout = [];
|
|
10
15
|
|
|
11
|
-
|
|
16
|
+
currentLayout.forEach((row) => {
|
|
12
17
|
const hasDynamicZone = row.some(({ name }) => getType(name) === 'dynamiczone');
|
|
13
18
|
|
|
14
19
|
if (!newLayout[currentRowIndex]) {
|
|
@@ -27,7 +32,7 @@ const createAttributesLayout = (currentLayout, attributes) => {
|
|
|
27
32
|
} else {
|
|
28
33
|
newLayout[currentRowIndex].push(row);
|
|
29
34
|
}
|
|
30
|
-
}
|
|
35
|
+
});
|
|
31
36
|
|
|
32
37
|
return newLayout.filter((arr) => arr.length > 0);
|
|
33
38
|
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const getCustomFieldUidsFromLayout = (layout) => {
|
|
2
|
+
if (!layout) return [];
|
|
3
|
+
// Get all the fields on the content-type and its components
|
|
4
|
+
const allFields = [
|
|
5
|
+
...layout.contentType.layouts.edit,
|
|
6
|
+
...Object.values(layout.components).flatMap((component) => component.layouts.edit),
|
|
7
|
+
].flat();
|
|
8
|
+
// Filter that down to custom fields and map the uids
|
|
9
|
+
const customFieldUids = allFields
|
|
10
|
+
.filter((field) => field.fieldSchema.customField)
|
|
11
|
+
.map((customField) => customField.fieldSchema.customField);
|
|
12
|
+
// Make sure the list is unique
|
|
13
|
+
const uniqueCustomFieldUids = [...new Set(customFieldUids)];
|
|
14
|
+
|
|
15
|
+
return uniqueCustomFieldUids;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default getCustomFieldUidsFromLayout;
|