@strapi/admin 4.9.1 → 4.9.2
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/LanguageProvider/index.js +1 -1
- package/admin/src/components/LocalesProvider/index.js +2 -3
- package/admin/src/content-manager/components/CollectionTypeFormWrapper/index.js +3 -6
- package/admin/src/content-manager/components/EditViewDataManagerProvider/reducer.js +9 -5
- package/admin/src/content-manager/components/InputUID/index.js +1 -1
- package/admin/src/content-manager/components/SingleTypeFormWrapper/index.js +4 -8
- package/admin/src/content-manager/pages/App/LeftMenu/index.js +56 -35
- package/admin/src/content-manager/pages/App/actions.js +19 -7
- package/admin/src/content-manager/pages/App/constants.js +3 -3
- package/admin/src/content-manager/pages/App/index.js +3 -2
- package/admin/src/content-manager/pages/App/reducer.js +7 -6
- package/admin/src/content-manager/pages/App/selectors.js +3 -0
- package/admin/src/content-manager/pages/App/{useModels.js → useContentManagerInitData.js} +29 -28
- package/admin/src/content-manager/pages/App/utils/generateModelsLinks.js +2 -2
- package/admin/src/content-manager/pages/App/utils/getContentTypeLinks.js +17 -15
- package/admin/src/content-manager/pages/EditSettingsView/components/ModalForm.js +4 -5
- package/admin/src/content-manager/pages/EditSettingsView/index.js +4 -0
- package/admin/src/content-manager/pages/EditSettingsView/reducer.js +6 -7
- package/admin/src/content-manager/pages/EditSettingsView/utils/layout.js +1 -30
- package/admin/src/content-manager/pages/EditView/DeleteLink/index.js +5 -11
- package/admin/src/content-manager/pages/EditView/index.js +2 -7
- package/admin/src/content-manager/pages/ListSettingsView/index.js +1 -0
- package/admin/src/hooks/useFetchMarketplacePlugins/utils/api.js +7 -8
- package/admin/src/hooks/useFetchMarketplaceProviders/utils/api.js +5 -0
- package/admin/src/pages/HomePage/SocialLinks.js +1 -1
- package/admin/src/pages/MarketplacePage/components/EmptyNpmPackageSearch/index.js +1 -1
- package/admin/src/pages/MarketplacePage/components/NpmPackagesGrid/index.js +42 -9
- package/admin/src/pages/MarketplacePage/components/NpmPackagesPagination/index.js +26 -0
- package/admin/src/pages/MarketplacePage/components/OfflineLayout/index.js +45 -0
- package/admin/src/pages/MarketplacePage/index.js +80 -175
- package/admin/src/pages/MarketplacePage/utils/useMarketplaceData.js +85 -0
- package/admin/src/pages/SettingsPage/pages/Roles/ListPage/components/RoleRow/index.js +12 -4
- package/admin/src/pages/SettingsPage/pages/Roles/ListPage/index.js +21 -2
- package/admin/src/translations/en.json +51 -50
- package/admin/src/translations/ru.json +51 -19
- package/build/{Admin-authenticatedApp.a168aa38.chunk.js → Admin-authenticatedApp.217db666.chunk.js} +5 -5
- package/build/{Admin_homePage.da2181fe.chunk.js → Admin_homePage.f9309c6d.chunk.js} +1 -1
- package/build/Admin_marketplace.56bc1008.chunk.js +31 -0
- package/build/{Admin_settingsPage.cb63220f.chunk.js → Admin_settingsPage.1dbfc9ce.chunk.js} +1 -1
- package/build/{admin-app.8cde5b22.chunk.js → admin-app.558af642.chunk.js} +6 -6
- package/build/admin-roles-list.329c1f63.chunk.js +31 -0
- package/build/audit-logs-settings-page.19d90bda.chunk.js +76 -0
- package/build/content-manager.d1565bfc.chunk.js +1132 -0
- package/build/content-type-builder-translation-en-json.6c8e69ab.chunk.js +1 -0
- package/build/content-type-builder.9d780e7f.chunk.js +126 -0
- package/build/en-json.cf600231.chunk.js +1 -0
- package/build/index.html +1 -1
- package/build/main.ef8db4a2.js +2280 -0
- package/build/ru-json.e0662702.chunk.js +1 -0
- package/build/{runtime~main.03cdff31.js → runtime~main.3a92d953.js} +2 -2
- package/build/users-roles-settings-page.2f85dcec.chunk.js +30 -0
- package/ee/admin/hooks/useLicenseLimitNotification/index.js +1 -1
- package/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/hooks/useAuditLogsData.js +6 -3
- package/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/index.js +15 -5
- package/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/utils/getDisplayedFilters.js +52 -45
- package/package.json +10 -10
- package/webpack.config.js +5 -1
- package/admin/src/content-manager/pages/App/LeftMenu/utils/index.js +0 -1
- package/admin/src/content-manager/pages/App/LeftMenu/utils/matchByTitle.js +0 -24
- package/build/9347.058ddb22.chunk.js +0 -1
- package/build/Admin_marketplace.99e25059.chunk.js +0 -31
- package/build/admin-roles-list.97e198f9.chunk.js +0 -31
- package/build/audit-logs-settings-page.ca9a3c46.chunk.js +0 -76
- package/build/content-manager.ba088a66.chunk.js +0 -1132
- package/build/content-type-builder-translation-en-json.e577d595.chunk.js +0 -1
- package/build/content-type-builder.fef159db.chunk.js +0 -126
- package/build/en-json.b052667a.chunk.js +0 -1
- package/build/main.0df5f5ca.js +0 -2280
- package/build/ru-json.6a01cea6.chunk.js +0 -1
- package/build/users-roles-settings-page.9359e4d1.chunk.js +0 -30
- /package/admin/src/{content-manager/components/InputUID/useDebounce.js → hooks/useDebounce/index.js} +0 -0
|
@@ -35,7 +35,7 @@ const LanguageProvider = ({ children, localeNames, messages }) => {
|
|
|
35
35
|
|
|
36
36
|
return (
|
|
37
37
|
<IntlProvider locale={locale} defaultLocale="en" messages={appMessages} textComponent="span">
|
|
38
|
-
<LocalesProvider changeLocale={changeLocale} localeNames={localeNames}
|
|
38
|
+
<LocalesProvider changeLocale={changeLocale} localeNames={localeNames}>
|
|
39
39
|
{children}
|
|
40
40
|
</LocalesProvider>
|
|
41
41
|
</IntlProvider>
|
|
@@ -2,9 +2,9 @@ import React from 'react';
|
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import LocalesProviderContext from './context';
|
|
4
4
|
|
|
5
|
-
const LocalesProvider = ({ changeLocale, children, localeNames
|
|
5
|
+
const LocalesProvider = ({ changeLocale, children, localeNames }) => {
|
|
6
6
|
return (
|
|
7
|
-
<LocalesProviderContext.Provider value={{ changeLocale, localeNames
|
|
7
|
+
<LocalesProviderContext.Provider value={{ changeLocale, localeNames }}>
|
|
8
8
|
{children}
|
|
9
9
|
</LocalesProviderContext.Provider>
|
|
10
10
|
);
|
|
@@ -14,7 +14,6 @@ LocalesProvider.propTypes = {
|
|
|
14
14
|
changeLocale: PropTypes.func.isRequired,
|
|
15
15
|
children: PropTypes.element.isRequired,
|
|
16
16
|
localeNames: PropTypes.object.isRequired,
|
|
17
|
-
messages: PropTypes.object.isRequired,
|
|
18
17
|
};
|
|
19
18
|
|
|
20
19
|
export default LocalesProvider;
|
|
@@ -222,6 +222,8 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin }
|
|
|
222
222
|
|
|
223
223
|
trackUsageRef.current('didDeleteEntry', trackerProperty);
|
|
224
224
|
|
|
225
|
+
replace(redirectionLink);
|
|
226
|
+
|
|
225
227
|
return Promise.resolve(data);
|
|
226
228
|
} catch (err) {
|
|
227
229
|
trackUsageRef.current('didNotDeleteEntry', { error: err, ...trackerProperty });
|
|
@@ -229,13 +231,9 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin }
|
|
|
229
231
|
return Promise.reject(err);
|
|
230
232
|
}
|
|
231
233
|
},
|
|
232
|
-
[id, slug, toggleNotification, del]
|
|
234
|
+
[id, slug, toggleNotification, del, redirectionLink, replace]
|
|
233
235
|
);
|
|
234
236
|
|
|
235
|
-
const onDeleteSucceeded = useCallback(() => {
|
|
236
|
-
replace(redirectionLink);
|
|
237
|
-
}, [redirectionLink, replace]);
|
|
238
|
-
|
|
239
237
|
const onPost = useCallback(
|
|
240
238
|
async (body, trackerProperty) => {
|
|
241
239
|
const endPoint = `${getRequestUrl(`collection-types/${slug}`)}${rawQuery}`;
|
|
@@ -409,7 +407,6 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin }
|
|
|
409
407
|
isCreatingEntry,
|
|
410
408
|
isLoadingForData: isLoading,
|
|
411
409
|
onDelete,
|
|
412
|
-
onDeleteSucceeded,
|
|
413
410
|
onPost,
|
|
414
411
|
onPublish,
|
|
415
412
|
onDraftRelationCheck,
|
|
@@ -186,11 +186,15 @@ const reducer = (state, action) =>
|
|
|
186
186
|
const newRelations = [...modifiedDataRelations];
|
|
187
187
|
|
|
188
188
|
if (action.type === 'REORDER_RELATION') {
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
189
|
+
const startKey =
|
|
190
|
+
oldIndex > newIndex
|
|
191
|
+
? modifiedDataRelations[newIndex - 1]?.__temp_key__
|
|
192
|
+
: modifiedDataRelations[newIndex]?.__temp_key__;
|
|
193
|
+
const endKey =
|
|
194
|
+
oldIndex > newIndex
|
|
195
|
+
? modifiedDataRelations[newIndex]?.__temp_key__
|
|
196
|
+
: modifiedDataRelations[newIndex + 1]?.__temp_key__;
|
|
197
|
+
const [newKey] = generateNKeysBetween(startKey, endKey, 1);
|
|
194
198
|
|
|
195
199
|
newRelations.splice(oldIndex, 1);
|
|
196
200
|
newRelations.splice(newIndex, 0, { ...currentItem, __temp_key__: newKey });
|
|
@@ -11,7 +11,7 @@ import { Flex, TextInput, Typography } from '@strapi/design-system';
|
|
|
11
11
|
import { Refresh, CheckCircle, ExclamationMarkCircle, Loader } from '@strapi/icons';
|
|
12
12
|
|
|
13
13
|
import { getRequestUrl } from '../../utils';
|
|
14
|
-
import useDebounce from '
|
|
14
|
+
import useDebounce from '../../../hooks/useDebounce';
|
|
15
15
|
import UID_REGEX from './regex';
|
|
16
16
|
import { FieldActionWrapper, TextValidation, LoadingWrapper } from './endActionStyle';
|
|
17
17
|
|
|
@@ -172,6 +172,9 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => {
|
|
|
172
172
|
|
|
173
173
|
trackUsageRef.current('didDeleteEntry', trackerProperty);
|
|
174
174
|
|
|
175
|
+
setIsCreatingEntry(true);
|
|
176
|
+
dispatch(initForm(rawQuery, true));
|
|
177
|
+
|
|
175
178
|
return Promise.resolve(data);
|
|
176
179
|
} catch (err) {
|
|
177
180
|
trackUsageRef.current('didNotDeleteEntry', { error: err, ...trackerProperty });
|
|
@@ -181,15 +184,9 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => {
|
|
|
181
184
|
return Promise.reject(err);
|
|
182
185
|
}
|
|
183
186
|
},
|
|
184
|
-
[del, slug, displayErrors, toggleNotification, searchToSend]
|
|
187
|
+
[del, slug, displayErrors, toggleNotification, searchToSend, dispatch, rawQuery]
|
|
185
188
|
);
|
|
186
189
|
|
|
187
|
-
const onDeleteSucceeded = useCallback(() => {
|
|
188
|
-
setIsCreatingEntry(true);
|
|
189
|
-
|
|
190
|
-
dispatch(initForm(rawQuery, true));
|
|
191
|
-
}, [dispatch, rawQuery]);
|
|
192
|
-
|
|
193
190
|
const onPost = useCallback(
|
|
194
191
|
async (body, trackerProperty) => {
|
|
195
192
|
const endPoint = getRequestUrl(`${slug}${rawQuery}`);
|
|
@@ -370,7 +367,6 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => {
|
|
|
370
367
|
isCreatingEntry,
|
|
371
368
|
isLoadingForData: isLoading,
|
|
372
369
|
onDelete,
|
|
373
|
-
onDeleteSucceeded,
|
|
374
370
|
onPost,
|
|
375
371
|
onDraftRelationCheck,
|
|
376
372
|
onPublish,
|
|
@@ -16,51 +16,72 @@ import {
|
|
|
16
16
|
SubNavSections,
|
|
17
17
|
SubNavLink,
|
|
18
18
|
} from '@strapi/design-system/v2';
|
|
19
|
+
import { useFilter, useCollator } from '@strapi/helper-plugin';
|
|
19
20
|
|
|
20
|
-
import { matchByTitle } from './utils';
|
|
21
21
|
import getTrad from '../../../utils/getTrad';
|
|
22
22
|
import { makeSelectModelLinks } from '../selectors';
|
|
23
23
|
|
|
24
24
|
const LeftMenu = () => {
|
|
25
25
|
const [search, setSearch] = useState('');
|
|
26
|
-
const { formatMessage } = useIntl();
|
|
26
|
+
const { formatMessage, locale } = useIntl();
|
|
27
27
|
const modelLinksSelector = useMemo(makeSelectModelLinks, []);
|
|
28
|
-
const { collectionTypeLinks, singleTypeLinks } = useSelector(
|
|
29
|
-
(state) => modelLinksSelector(state),
|
|
30
|
-
shallowEqual
|
|
31
|
-
);
|
|
28
|
+
const { collectionTypeLinks, singleTypeLinks } = useSelector(modelLinksSelector, shallowEqual);
|
|
32
29
|
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
...link,
|
|
37
|
-
title: formatMessage({ id: link.title, defaultMessage: link.title }),
|
|
38
|
-
};
|
|
39
|
-
});
|
|
30
|
+
const { startsWith } = useFilter(locale, {
|
|
31
|
+
sensitivity: 'base',
|
|
32
|
+
});
|
|
40
33
|
|
|
41
|
-
|
|
42
|
-
|
|
34
|
+
/**
|
|
35
|
+
* @type {Intl.Collator}
|
|
36
|
+
*/
|
|
37
|
+
const formatter = useCollator(locale, {
|
|
38
|
+
sensitivity: 'base',
|
|
39
|
+
});
|
|
43
40
|
|
|
44
|
-
const menu =
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
41
|
+
const menu = useMemo(
|
|
42
|
+
() =>
|
|
43
|
+
[
|
|
44
|
+
{
|
|
45
|
+
id: 'collectionTypes',
|
|
46
|
+
title: {
|
|
47
|
+
id: getTrad('components.LeftMenu.collection-types'),
|
|
48
|
+
defaultMessage: 'Collection Types',
|
|
49
|
+
},
|
|
50
|
+
searchable: true,
|
|
51
|
+
links: collectionTypeLinks,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: 'singleTypes',
|
|
55
|
+
title: {
|
|
56
|
+
id: getTrad('components.LeftMenu.single-types'),
|
|
57
|
+
defaultMessage: 'Single Types',
|
|
58
|
+
},
|
|
59
|
+
searchable: true,
|
|
60
|
+
links: singleTypeLinks,
|
|
61
|
+
},
|
|
62
|
+
].map((section) => ({
|
|
63
|
+
...section,
|
|
64
|
+
links: section.links
|
|
65
|
+
/**
|
|
66
|
+
* Filter by the search value
|
|
67
|
+
*/
|
|
68
|
+
.filter((link) => startsWith(link.title, search))
|
|
69
|
+
/**
|
|
70
|
+
* Sort correctly using the language
|
|
71
|
+
*/
|
|
72
|
+
.sort((a, b) => formatter.compare(a.title, b.title))
|
|
73
|
+
/**
|
|
74
|
+
* Apply the formated strings to the links from react-intl
|
|
75
|
+
*/
|
|
76
|
+
.map((link) => {
|
|
77
|
+
return {
|
|
78
|
+
...link,
|
|
79
|
+
title: formatMessage({ id: link.title, defaultMessage: link.title }),
|
|
80
|
+
};
|
|
81
|
+
}),
|
|
82
|
+
})),
|
|
83
|
+
[collectionTypeLinks, search, singleTypeLinks, startsWith, formatMessage, formatter]
|
|
84
|
+
);
|
|
64
85
|
|
|
65
86
|
const handleClear = () => {
|
|
66
87
|
setSearch('');
|
|
@@ -1,12 +1,24 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { GET_INIT_DATA, RESET_INIT_DATA, SET_INIT_DATA } from './constants';
|
|
2
2
|
|
|
3
|
-
export const
|
|
4
|
-
type:
|
|
3
|
+
export const getInitData = () => ({
|
|
4
|
+
type: GET_INIT_DATA,
|
|
5
5
|
});
|
|
6
6
|
|
|
7
|
-
export const
|
|
7
|
+
export const resetInitData = () => ({ type: RESET_INIT_DATA });
|
|
8
8
|
|
|
9
|
-
export const
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
export const setInitData = ({
|
|
10
|
+
authorizedCollectionTypeLinks,
|
|
11
|
+
authorizedSingleTypeLinks,
|
|
12
|
+
contentTypeSchemas,
|
|
13
|
+
components,
|
|
14
|
+
fieldSizes,
|
|
15
|
+
}) => ({
|
|
16
|
+
type: SET_INIT_DATA,
|
|
17
|
+
data: {
|
|
18
|
+
authorizedCollectionTypeLinks,
|
|
19
|
+
authorizedSingleTypeLinks,
|
|
20
|
+
components,
|
|
21
|
+
contentTypeSchemas,
|
|
22
|
+
fieldSizes,
|
|
23
|
+
},
|
|
12
24
|
});
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export const
|
|
2
|
-
export const
|
|
3
|
-
export const
|
|
1
|
+
export const GET_INIT_DATA = 'ContentManager/App/GET_INIT_DATA';
|
|
2
|
+
export const RESET_INIT_DATA = 'ContentManager/App/RESET_INIT_DATA';
|
|
3
|
+
export const SET_INIT_DATA = 'ContentManager/App/SET_INIT_DATA';
|
|
@@ -20,13 +20,14 @@ import NoContentType from '../NoContentType';
|
|
|
20
20
|
import NoPermissions from '../NoPermissions';
|
|
21
21
|
import SingleTypeRecursivePath from '../SingleTypeRecursivePath';
|
|
22
22
|
import LeftMenu from './LeftMenu';
|
|
23
|
-
import
|
|
23
|
+
import useContentManagerInitData from './useContentManagerInitData';
|
|
24
24
|
|
|
25
25
|
const cmPermissions = permissions.contentManager;
|
|
26
26
|
|
|
27
27
|
const App = () => {
|
|
28
28
|
const contentTypeMatch = useRouteMatch(`/content-manager/:kind/:uid`);
|
|
29
|
-
const { status, collectionTypeLinks, singleTypeLinks, models, refetchData } =
|
|
29
|
+
const { status, collectionTypeLinks, singleTypeLinks, models, refetchData } =
|
|
30
|
+
useContentManagerInitData();
|
|
30
31
|
const authorisedModels = sortBy([...collectionTypeLinks, ...singleTypeLinks], (model) =>
|
|
31
32
|
model.title.toLowerCase()
|
|
32
33
|
);
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
/* eslint-disable consistent-return */
|
|
6
6
|
import produce from 'immer';
|
|
7
|
-
import {
|
|
7
|
+
import { GET_INIT_DATA, RESET_INIT_DATA, SET_INIT_DATA } from './constants';
|
|
8
8
|
|
|
9
9
|
const initialState = {
|
|
10
10
|
components: [],
|
|
@@ -20,22 +20,23 @@ const initialState = {
|
|
|
20
20
|
const mainReducer = (state = initialState, action) =>
|
|
21
21
|
produce(state, (draftState) => {
|
|
22
22
|
switch (action.type) {
|
|
23
|
-
case
|
|
23
|
+
case GET_INIT_DATA: {
|
|
24
24
|
draftState.status = 'loading';
|
|
25
25
|
break;
|
|
26
26
|
}
|
|
27
|
-
case
|
|
27
|
+
case RESET_INIT_DATA: {
|
|
28
28
|
return initialState;
|
|
29
29
|
}
|
|
30
|
-
case
|
|
31
|
-
draftState.collectionTypeLinks = action.data.
|
|
30
|
+
case SET_INIT_DATA: {
|
|
31
|
+
draftState.collectionTypeLinks = action.data.authorizedCollectionTypeLinks.filter(
|
|
32
32
|
({ isDisplayed }) => isDisplayed
|
|
33
33
|
);
|
|
34
|
-
draftState.singleTypeLinks = action.data.
|
|
34
|
+
draftState.singleTypeLinks = action.data.authorizedSingleTypeLinks.filter(
|
|
35
35
|
({ isDisplayed }) => isDisplayed
|
|
36
36
|
);
|
|
37
37
|
draftState.components = action.data.components;
|
|
38
38
|
draftState.models = action.data.contentTypeSchemas;
|
|
39
|
+
draftState.fieldSizes = action.data.fieldSizes;
|
|
39
40
|
draftState.status = 'resolved';
|
|
40
41
|
break;
|
|
41
42
|
}
|
|
@@ -23,10 +23,13 @@ const makeSelectModelAndComponentSchemas = () =>
|
|
|
23
23
|
schemas: [...components, ...models],
|
|
24
24
|
}));
|
|
25
25
|
|
|
26
|
+
const selectFieldSizes = createSelector(selectAppDomain(), (state) => state.fieldSizes);
|
|
27
|
+
|
|
26
28
|
export default makeSelectApp;
|
|
27
29
|
export {
|
|
28
30
|
makeSelectModelAndComponentSchemas,
|
|
29
31
|
makeSelectModelLinks,
|
|
30
32
|
makeSelectModels,
|
|
33
|
+
selectFieldSizes,
|
|
31
34
|
selectAppDomain,
|
|
32
35
|
};
|
|
@@ -11,11 +11,11 @@ import axios from 'axios';
|
|
|
11
11
|
import { useIntl } from 'react-intl';
|
|
12
12
|
import { MUTATE_COLLECTION_TYPES_LINKS, MUTATE_SINGLE_TYPES_LINKS } from '../../../exposedHooks';
|
|
13
13
|
import { getRequestUrl, getTrad } from '../../utils';
|
|
14
|
-
import {
|
|
14
|
+
import { getInitData, resetInitData, setInitData } from './actions';
|
|
15
15
|
import { selectAppDomain } from './selectors';
|
|
16
16
|
import getContentTypeLinks from './utils/getContentTypeLinks';
|
|
17
17
|
|
|
18
|
-
const
|
|
18
|
+
const useContentManagerInitData = () => {
|
|
19
19
|
const dispatch = useDispatch();
|
|
20
20
|
const toggleNotification = useNotification();
|
|
21
21
|
const state = useSelector(selectAppDomain());
|
|
@@ -29,22 +29,14 @@ const useModels = () => {
|
|
|
29
29
|
const { get } = useFetchClient();
|
|
30
30
|
|
|
31
31
|
const fetchData = async () => {
|
|
32
|
-
dispatch(
|
|
32
|
+
dispatch(getInitData());
|
|
33
33
|
|
|
34
34
|
try {
|
|
35
|
-
const
|
|
36
|
-
{
|
|
37
|
-
data: {
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
data: { data: models },
|
|
35
|
+
const {
|
|
36
|
+
data: {
|
|
37
|
+
data: { components, contentTypes: models, fieldSizes },
|
|
41
38
|
},
|
|
42
|
-
|
|
43
|
-
['components', 'content-types'].map((endPoint) =>
|
|
44
|
-
get(getRequestUrl(endPoint), { cancelToken: source.token })
|
|
45
|
-
)
|
|
46
|
-
);
|
|
47
|
-
|
|
39
|
+
} = await get(getRequestUrl('init'), { cancelToken: source.token });
|
|
48
40
|
notifyStatus(
|
|
49
41
|
formatMessage({
|
|
50
42
|
id: getTrad('App.schemas.data-loaded'),
|
|
@@ -52,22 +44,31 @@ const useModels = () => {
|
|
|
52
44
|
})
|
|
53
45
|
);
|
|
54
46
|
|
|
55
|
-
const
|
|
56
|
-
models,
|
|
57
|
-
allPermissions,
|
|
58
|
-
toggleNotification
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
const { ctLinks } = runHookWaterfall(MUTATE_COLLECTION_TYPES_LINKS, {
|
|
62
|
-
ctLinks: authorizedCtLinks,
|
|
47
|
+
const unmutatedContentTypeLinks = await getContentTypeLinks({
|
|
63
48
|
models,
|
|
49
|
+
userPermissions: allPermissions,
|
|
50
|
+
toggleNotification,
|
|
64
51
|
});
|
|
65
|
-
|
|
66
|
-
|
|
52
|
+
|
|
53
|
+
const { ctLinks: authorizedCollectionTypeLinks } = runHookWaterfall(
|
|
54
|
+
MUTATE_COLLECTION_TYPES_LINKS,
|
|
55
|
+
{
|
|
56
|
+
ctLinks: unmutatedContentTypeLinks.authorizedCollectionTypeLinks,
|
|
57
|
+
models,
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
const { stLinks: authorizedSingleTypeLinks } = runHookWaterfall(MUTATE_SINGLE_TYPES_LINKS, {
|
|
61
|
+
stLinks: unmutatedContentTypeLinks.authorizedSingleTypeLinks,
|
|
67
62
|
models,
|
|
68
63
|
});
|
|
69
64
|
|
|
70
|
-
const actionToDispatch =
|
|
65
|
+
const actionToDispatch = setInitData({
|
|
66
|
+
authorizedCollectionTypeLinks,
|
|
67
|
+
authorizedSingleTypeLinks,
|
|
68
|
+
contentTypeSchemas: models,
|
|
69
|
+
components,
|
|
70
|
+
fieldSizes,
|
|
71
|
+
});
|
|
71
72
|
|
|
72
73
|
dispatch(actionToDispatch);
|
|
73
74
|
} catch (err) {
|
|
@@ -88,7 +89,7 @@ const useModels = () => {
|
|
|
88
89
|
|
|
89
90
|
return () => {
|
|
90
91
|
source.cancel('Operation canceled by the user.');
|
|
91
|
-
dispatch(
|
|
92
|
+
dispatch(resetInitData());
|
|
92
93
|
};
|
|
93
94
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
94
95
|
}, [dispatch, toggleNotification]);
|
|
@@ -96,4 +97,4 @@ const useModels = () => {
|
|
|
96
97
|
return { ...state, refetchData: fetchDataRef.current };
|
|
97
98
|
};
|
|
98
99
|
|
|
99
|
-
export default
|
|
100
|
+
export default useContentManagerInitData;
|
|
@@ -52,12 +52,12 @@ const generateModelsLinks = (models, modelsConfigurations) => {
|
|
|
52
52
|
const [collectionTypes, singleTypes] = sortBy(groupedModels, 'name');
|
|
53
53
|
|
|
54
54
|
return {
|
|
55
|
-
|
|
55
|
+
collectionTypeSectionLinks: generateLinks(
|
|
56
56
|
collectionTypes?.links || [],
|
|
57
57
|
'collectionTypes',
|
|
58
58
|
modelsConfigurations
|
|
59
59
|
),
|
|
60
|
-
|
|
60
|
+
singleTypeSectionLinks: generateLinks(singleTypes?.links ?? [], 'singleTypes'),
|
|
61
61
|
};
|
|
62
62
|
};
|
|
63
63
|
|
|
@@ -3,36 +3,38 @@ import generateModelsLinks from './generateModelsLinks';
|
|
|
3
3
|
import checkPermissions from './checkPermissions';
|
|
4
4
|
import { getRequestUrl } from '../../../utils';
|
|
5
5
|
|
|
6
|
-
const getContentTypeLinks = async (models, userPermissions, toggleNotification) => {
|
|
6
|
+
const getContentTypeLinks = async ({ models, userPermissions, toggleNotification }) => {
|
|
7
7
|
const { get } = getFetchClient();
|
|
8
8
|
try {
|
|
9
9
|
const {
|
|
10
10
|
data: { data: contentTypeConfigurations },
|
|
11
11
|
} = await get(getRequestUrl('content-types-settings'));
|
|
12
12
|
|
|
13
|
-
const {
|
|
13
|
+
const { collectionTypeSectionLinks, singleTypeSectionLinks } = generateModelsLinks(
|
|
14
14
|
models,
|
|
15
15
|
contentTypeConfigurations
|
|
16
16
|
);
|
|
17
17
|
|
|
18
|
-
//
|
|
19
|
-
const
|
|
20
|
-
userPermissions,
|
|
21
|
-
collectionTypesSectionLinks
|
|
18
|
+
// Collection Types verifications
|
|
19
|
+
const collectionTypeLinksPermissions = await Promise.all(
|
|
20
|
+
checkPermissions(userPermissions, collectionTypeSectionLinks)
|
|
22
21
|
);
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
(_, index) => ctLinksPermissions[index]
|
|
22
|
+
const authorizedCollectionTypeLinks = collectionTypeSectionLinks.filter(
|
|
23
|
+
(_, index) => collectionTypeLinksPermissions[index]
|
|
26
24
|
);
|
|
27
25
|
|
|
28
26
|
// Single Types verifications
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
const singleTypeLinksPermissions = await Promise.all(
|
|
28
|
+
checkPermissions(userPermissions, singleTypeSectionLinks)
|
|
29
|
+
);
|
|
30
|
+
const authorizedSingleTypeLinks = singleTypeSectionLinks.filter(
|
|
31
|
+
(_, index) => singleTypeLinksPermissions[index]
|
|
33
32
|
);
|
|
34
33
|
|
|
35
|
-
return {
|
|
34
|
+
return {
|
|
35
|
+
authorizedCollectionTypeLinks,
|
|
36
|
+
authorizedSingleTypeLinks,
|
|
37
|
+
};
|
|
36
38
|
} catch (err) {
|
|
37
39
|
console.error(err);
|
|
38
40
|
|
|
@@ -41,7 +43,7 @@ const getContentTypeLinks = async (models, userPermissions, toggleNotification)
|
|
|
41
43
|
message: { id: 'notification.error' },
|
|
42
44
|
});
|
|
43
45
|
|
|
44
|
-
return {
|
|
46
|
+
return { authorizedCollectionTypeLinks: [], authorizedSingleTypeLinks: [] };
|
|
45
47
|
}
|
|
46
48
|
};
|
|
47
49
|
|
|
@@ -6,7 +6,7 @@ import { useSelector, shallowEqual } from 'react-redux';
|
|
|
6
6
|
import { useIntl } from 'react-intl';
|
|
7
7
|
import { useLayoutDnd } from '../../../hooks';
|
|
8
8
|
import { createPossibleMainFieldsForModelsAndComponents, getInputProps } from '../utils';
|
|
9
|
-
import { makeSelectModelAndComponentSchemas } from '../../App/selectors';
|
|
9
|
+
import { makeSelectModelAndComponentSchemas, selectFieldSizes } from '../../App/selectors';
|
|
10
10
|
import getTrad from '../../../utils/getTrad';
|
|
11
11
|
import GenericInput from './GenericInput';
|
|
12
12
|
|
|
@@ -17,8 +17,6 @@ const FIELD_SIZES = [
|
|
|
17
17
|
[12, '100%'],
|
|
18
18
|
];
|
|
19
19
|
|
|
20
|
-
const NON_RESIZABLE_FIELD_TYPES = ['dynamiczone', 'component', 'json', 'richtext'];
|
|
21
|
-
|
|
22
20
|
const TIME_FIELD_OPTIONS = [1, 5, 10, 15, 30, 60];
|
|
23
21
|
|
|
24
22
|
const TIME_FIELD_TYPES = ['datetime', 'time'];
|
|
@@ -28,6 +26,7 @@ const ModalForm = ({ onMetaChange, onSizeChange }) => {
|
|
|
28
26
|
const { modifiedData, selectedField, attributes, fieldForm } = useLayoutDnd();
|
|
29
27
|
const schemasSelector = useMemo(makeSelectModelAndComponentSchemas, []);
|
|
30
28
|
const { schemas } = useSelector((state) => schemasSelector(state), shallowEqual);
|
|
29
|
+
const fieldSizes = useSelector(selectFieldSizes);
|
|
31
30
|
|
|
32
31
|
const formToDisplay = useMemo(() => {
|
|
33
32
|
if (!selectedField) {
|
|
@@ -103,7 +102,7 @@ const ModalForm = ({ onMetaChange, onSizeChange }) => {
|
|
|
103
102
|
);
|
|
104
103
|
});
|
|
105
104
|
|
|
106
|
-
const
|
|
105
|
+
const { isResizable } = fieldSizes[attributes[selectedField].type];
|
|
107
106
|
|
|
108
107
|
const sizeField = (
|
|
109
108
|
<GridItem col={6} key="size">
|
|
@@ -152,7 +151,7 @@ const ModalForm = ({ onMetaChange, onSizeChange }) => {
|
|
|
152
151
|
return (
|
|
153
152
|
<>
|
|
154
153
|
{metaFields}
|
|
155
|
-
{
|
|
154
|
+
{isResizable && sizeField}
|
|
156
155
|
{hasTimePicker && timeStepField}
|
|
157
156
|
</>
|
|
158
157
|
);
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
Divider,
|
|
27
27
|
} from '@strapi/design-system';
|
|
28
28
|
import { ArrowLeft, Check } from '@strapi/icons';
|
|
29
|
+
import { useSelector } from 'react-redux';
|
|
29
30
|
import { getTrad } from '../../utils';
|
|
30
31
|
import reducer, { initialState } from './reducer';
|
|
31
32
|
import init from './init';
|
|
@@ -34,6 +35,7 @@ import ModalForm from './components/FormModal';
|
|
|
34
35
|
import LayoutDndProvider from '../../components/LayoutDndProvider';
|
|
35
36
|
import { unformatLayout } from './utils/layout';
|
|
36
37
|
import putCMSettingsEV from './utils/api';
|
|
38
|
+
import { selectFieldSizes } from '../App/selectors';
|
|
37
39
|
|
|
38
40
|
const EditSettingsView = ({ mainLayout, components, isContentTypeView, slug, updateLayout }) => {
|
|
39
41
|
const [reducerState, dispatch] = useReducer(reducer, initialState, () =>
|
|
@@ -49,6 +51,7 @@ const EditSettingsView = ({ mainLayout, components, isContentTypeView, slug, upd
|
|
|
49
51
|
const { formatMessage } = useIntl();
|
|
50
52
|
const modelName = get(mainLayout, ['info', 'displayName'], '');
|
|
51
53
|
const attributes = get(modifiedData, ['attributes'], {});
|
|
54
|
+
const fieldSizes = useSelector(selectFieldSizes);
|
|
52
55
|
|
|
53
56
|
const entryTitleOptions = Object.keys(attributes).filter((attr) => {
|
|
54
57
|
const type = get(attributes, [attr, 'type'], '');
|
|
@@ -318,6 +321,7 @@ const EditSettingsView = ({ mainLayout, components, isContentTypeView, slug, upd
|
|
|
318
321
|
dispatch({
|
|
319
322
|
type: 'ON_ADD_FIELD',
|
|
320
323
|
name: field,
|
|
324
|
+
fieldSizes,
|
|
321
325
|
});
|
|
322
326
|
}}
|
|
323
327
|
onRemoveField={(rowId, index) => {
|
|
@@ -2,9 +2,10 @@ import produce from 'immer';
|
|
|
2
2
|
import set from 'lodash/set';
|
|
3
3
|
import get from 'lodash/get';
|
|
4
4
|
import cloneDeep from 'lodash/cloneDeep';
|
|
5
|
-
|
|
6
5
|
import { arrayMoveItem } from '../../utils';
|
|
7
|
-
import { formatLayout,
|
|
6
|
+
import { formatLayout, getFieldSize, setFieldSize } from './utils/layout';
|
|
7
|
+
|
|
8
|
+
const DEFAULT_FIELD_SIZE = 6;
|
|
8
9
|
|
|
9
10
|
const initialState = {
|
|
10
11
|
fieldForm: {},
|
|
@@ -29,9 +30,8 @@ const reducer = (state = initialState, action) =>
|
|
|
29
30
|
}
|
|
30
31
|
case 'ON_ADD_FIELD': {
|
|
31
32
|
const newState = cloneDeep(state);
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
);
|
|
33
|
+
const type = get(newState, ['modifiedData', 'attributes', action.name, 'type'], '');
|
|
34
|
+
const size = action.fieldSizes[type]?.default ?? DEFAULT_FIELD_SIZE;
|
|
35
35
|
const listSize = get(newState, layoutPathEdit, []).length;
|
|
36
36
|
const actualRowContentPath = [...layoutPathEdit, listSize - 1, 'rowContent'];
|
|
37
37
|
const rowContentToSet = get(newState, actualRowContentPath, []);
|
|
@@ -149,8 +149,7 @@ const reducer = (state = initialState, action) =>
|
|
|
149
149
|
draftState.metaToEdit = action.name;
|
|
150
150
|
draftState.metaForm = {
|
|
151
151
|
metadata: get(state, ['modifiedData', 'metadatas', action.name, 'edit'], {}),
|
|
152
|
-
size:
|
|
153
|
-
getFieldSize(action.name, state.modifiedData?.layouts?.edit) ?? getDefaultInputSize(),
|
|
152
|
+
size: getFieldSize(action.name, state.modifiedData?.layouts?.edit) ?? DEFAULT_FIELD_SIZE,
|
|
154
153
|
};
|
|
155
154
|
|
|
156
155
|
break;
|