mirror of
https://github.com/strapi/strapi.git
synced 2025-09-14 19:19:43 +00:00
Merge pull request #16387 from strapi/chore/cm-field-sizes
Refactor content manager field sizes management
This commit is contained in:
commit
ecf439ab56
@ -1,12 +1,24 @@
|
||||
import { GET_DATA, RESET_PROPS, SET_CONTENT_TYPE_LINKS } from './constants';
|
||||
import { GET_INIT_DATA, RESET_INIT_DATA, SET_INIT_DATA } from './constants';
|
||||
|
||||
export const getData = () => ({
|
||||
type: GET_DATA,
|
||||
export const getInitData = () => ({
|
||||
type: GET_INIT_DATA,
|
||||
});
|
||||
|
||||
export const resetProps = () => ({ type: RESET_PROPS });
|
||||
export const resetInitData = () => ({ type: RESET_INIT_DATA });
|
||||
|
||||
export const setContentTypeLinks = (authorizedCtLinks, authorizedStLinks, models, components) => ({
|
||||
type: SET_CONTENT_TYPE_LINKS,
|
||||
data: { authorizedCtLinks, authorizedStLinks, components, contentTypeSchemas: models },
|
||||
export const setInitData = ({
|
||||
authorizedCollectionTypeLinks,
|
||||
authorizedSingleTypeLinks,
|
||||
contentTypeSchemas,
|
||||
components,
|
||||
fieldSizes,
|
||||
}) => ({
|
||||
type: SET_INIT_DATA,
|
||||
data: {
|
||||
authorizedCollectionTypeLinks,
|
||||
authorizedSingleTypeLinks,
|
||||
components,
|
||||
contentTypeSchemas,
|
||||
fieldSizes,
|
||||
},
|
||||
});
|
||||
|
@ -1,3 +1,3 @@
|
||||
export const GET_DATA = 'ContentManager/App/GET_DATA';
|
||||
export const RESET_PROPS = 'ContentManager/App/RESET_PROPS';
|
||||
export const SET_CONTENT_TYPE_LINKS = 'ContentManager/App/SET_CONTENT_TYPE_LINKS';
|
||||
export const GET_INIT_DATA = 'ContentManager/App/GET_INIT_DATA';
|
||||
export const RESET_INIT_DATA = 'ContentManager/App/RESET_INIT_DATA';
|
||||
export const SET_INIT_DATA = 'ContentManager/App/SET_INIT_DATA';
|
||||
|
@ -20,13 +20,14 @@ import NoContentType from '../NoContentType';
|
||||
import NoPermissions from '../NoPermissions';
|
||||
import SingleTypeRecursivePath from '../SingleTypeRecursivePath';
|
||||
import LeftMenu from './LeftMenu';
|
||||
import useModels from './useModels';
|
||||
import useContentManagerInitData from './useContentManagerInitData';
|
||||
|
||||
const cmPermissions = permissions.contentManager;
|
||||
|
||||
const App = () => {
|
||||
const contentTypeMatch = useRouteMatch(`/content-manager/:kind/:uid`);
|
||||
const { status, collectionTypeLinks, singleTypeLinks, models, refetchData } = useModels();
|
||||
const { status, collectionTypeLinks, singleTypeLinks, models, refetchData } =
|
||||
useContentManagerInitData();
|
||||
const authorisedModels = sortBy([...collectionTypeLinks, ...singleTypeLinks], (model) =>
|
||||
model.title.toLowerCase()
|
||||
);
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
/* eslint-disable consistent-return */
|
||||
import produce from 'immer';
|
||||
import { GET_DATA, RESET_PROPS, SET_CONTENT_TYPE_LINKS } from './constants';
|
||||
import { GET_INIT_DATA, RESET_INIT_DATA, SET_INIT_DATA } from './constants';
|
||||
|
||||
const initialState = {
|
||||
components: [],
|
||||
@ -20,22 +20,23 @@ const initialState = {
|
||||
const mainReducer = (state = initialState, action) =>
|
||||
produce(state, (draftState) => {
|
||||
switch (action.type) {
|
||||
case GET_DATA: {
|
||||
case GET_INIT_DATA: {
|
||||
draftState.status = 'loading';
|
||||
break;
|
||||
}
|
||||
case RESET_PROPS: {
|
||||
case RESET_INIT_DATA: {
|
||||
return initialState;
|
||||
}
|
||||
case SET_CONTENT_TYPE_LINKS: {
|
||||
draftState.collectionTypeLinks = action.data.authorizedCtLinks.filter(
|
||||
case SET_INIT_DATA: {
|
||||
draftState.collectionTypeLinks = action.data.authorizedCollectionTypeLinks.filter(
|
||||
({ isDisplayed }) => isDisplayed
|
||||
);
|
||||
draftState.singleTypeLinks = action.data.authorizedStLinks.filter(
|
||||
draftState.singleTypeLinks = action.data.authorizedSingleTypeLinks.filter(
|
||||
({ isDisplayed }) => isDisplayed
|
||||
);
|
||||
draftState.components = action.data.components;
|
||||
draftState.models = action.data.contentTypeSchemas;
|
||||
draftState.fieldSizes = action.data.fieldSizes;
|
||||
draftState.status = 'resolved';
|
||||
break;
|
||||
}
|
||||
|
@ -23,10 +23,13 @@ const makeSelectModelAndComponentSchemas = () =>
|
||||
schemas: [...components, ...models],
|
||||
}));
|
||||
|
||||
const selectFieldSizes = createSelector(selectAppDomain(), (state) => state.fieldSizes);
|
||||
|
||||
export default makeSelectApp;
|
||||
export {
|
||||
makeSelectModelAndComponentSchemas,
|
||||
makeSelectModelLinks,
|
||||
makeSelectModels,
|
||||
selectFieldSizes,
|
||||
selectAppDomain,
|
||||
};
|
||||
|
@ -1,27 +1,32 @@
|
||||
import { setContentTypeLinks } from '../actions';
|
||||
import { setInitData } from '../actions';
|
||||
|
||||
describe('Content Manager | App | actions', () => {
|
||||
it('should format the setContentTypeLinks action', () => {
|
||||
const authorizedCtLinks = [{ title: 'addresses', uid: 'address' }];
|
||||
const authorizedStLinks = [{ title: 'Home page', uid: 'homepage' }];
|
||||
const models = [
|
||||
it('should format the setInitData action', () => {
|
||||
const authorizedCollectionTypeLinks = [{ title: 'addresses', uid: 'address' }];
|
||||
const authorizedSingleTypeLinks = [{ title: 'Home page', uid: 'homepage' }];
|
||||
const contentTypeSchemas = [
|
||||
{ kind: 'singleType', uid: 'homepage' },
|
||||
{ kind: 'collectionType', uid: 'address' },
|
||||
];
|
||||
const components = [];
|
||||
|
||||
const expected = {
|
||||
type: 'ContentManager/App/SET_CONTENT_TYPE_LINKS',
|
||||
type: 'ContentManager/App/SET_INIT_DATA',
|
||||
data: {
|
||||
authorizedCtLinks,
|
||||
authorizedStLinks,
|
||||
contentTypeSchemas: models,
|
||||
authorizedCollectionTypeLinks,
|
||||
authorizedSingleTypeLinks,
|
||||
contentTypeSchemas,
|
||||
components,
|
||||
},
|
||||
};
|
||||
|
||||
expect(setContentTypeLinks(authorizedCtLinks, authorizedStLinks, models, components)).toEqual(
|
||||
expected
|
||||
);
|
||||
expect(
|
||||
setInitData({
|
||||
authorizedCollectionTypeLinks,
|
||||
authorizedSingleTypeLinks,
|
||||
contentTypeSchemas,
|
||||
components,
|
||||
})
|
||||
).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
@ -13,9 +13,9 @@ import Theme from '../../../../components/Theme';
|
||||
import ThemeToggleProvider from '../../../../components/ThemeToggleProvider';
|
||||
import { App as ContentManagerApp } from '..';
|
||||
import cmReducers from '../../../../reducers';
|
||||
import useModels from '../useModels';
|
||||
import useContentManagerInitData from '../useContentManagerInitData';
|
||||
|
||||
jest.mock('../useModels', () =>
|
||||
jest.mock('../useContentManagerInitData', () =>
|
||||
jest.fn(() => {
|
||||
return {};
|
||||
})
|
||||
@ -88,7 +88,7 @@ describe('Content manager | App | main', () => {
|
||||
components: [],
|
||||
status: 'resolved',
|
||||
};
|
||||
useModels.mockImplementation(() => contentManagerState);
|
||||
useContentManagerInitData.mockImplementation(() => contentManagerState);
|
||||
const rootReducer = combineReducers(cmReducers);
|
||||
const store = createStore(rootReducer, { 'content-manager_app': contentManagerState });
|
||||
const history = createMemoryHistory();
|
||||
@ -815,7 +815,7 @@ describe('Content manager | App | main', () => {
|
||||
components: [],
|
||||
status: 'resolved',
|
||||
};
|
||||
useModels.mockImplementation(() => contentManagerState);
|
||||
useContentManagerInitData.mockImplementation(() => contentManagerState);
|
||||
const rootReducer = combineReducers(cmReducers);
|
||||
const store = createStore(rootReducer, { 'content-manager_app': contentManagerState });
|
||||
const history = createMemoryHistory();
|
||||
@ -857,8 +857,8 @@ describe('Content manager | App | main', () => {
|
||||
components: [],
|
||||
status: 'resolved',
|
||||
};
|
||||
useModels.mockImplementation(() => contentManagerState);
|
||||
jest.mock('../useModels', () =>
|
||||
useContentManagerInitData.mockImplementation(() => contentManagerState);
|
||||
jest.mock('../useContentManagerInitData', () =>
|
||||
jest.fn(() => {
|
||||
return contentManagerState;
|
||||
})
|
||||
@ -902,8 +902,8 @@ describe('Content manager | App | main', () => {
|
||||
components: [],
|
||||
status: 'resolved',
|
||||
};
|
||||
useModels.mockImplementation(() => contentManagerState);
|
||||
jest.mock('../useModels', () =>
|
||||
useContentManagerInitData.mockImplementation(() => contentManagerState);
|
||||
jest.mock('../useContentManagerInitData', () =>
|
||||
jest.fn(() => {
|
||||
return contentManagerState;
|
||||
})
|
||||
|
@ -1,5 +1,5 @@
|
||||
import produce from 'immer';
|
||||
import { getData, setContentTypeLinks, resetProps } from '../actions';
|
||||
import { getInitData, setInitData, resetInitData } from '../actions';
|
||||
import mainReducer from '../reducer';
|
||||
|
||||
describe('Content Manager | App | reducer', () => {
|
||||
@ -12,6 +12,7 @@ describe('Content Manager | App | reducer', () => {
|
||||
models: [],
|
||||
collectionTypeLinks: [],
|
||||
singleTypeLinks: [],
|
||||
fieldSizes: {},
|
||||
};
|
||||
});
|
||||
|
||||
@ -19,18 +20,18 @@ describe('Content Manager | App | reducer', () => {
|
||||
expect(mainReducer(state, {})).toEqual(state);
|
||||
});
|
||||
|
||||
it('should handle the getData action correctly', () => {
|
||||
it('should handle the getInitData action correctly', () => {
|
||||
state.status = 'resolved';
|
||||
|
||||
const expected = produce(state, (draft) => {
|
||||
draft.status = 'loading';
|
||||
});
|
||||
|
||||
expect(mainReducer(state, getData())).toEqual(expected);
|
||||
expect(mainReducer(state, getInitData())).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should handle the getData action correctly', () => {
|
||||
const collectionTypeLinks = [
|
||||
it('should handle the setInitData action correctly', () => {
|
||||
const authorizedCollectionTypeLinks = [
|
||||
{
|
||||
name: 'authorizedCt',
|
||||
isDisplayed: true,
|
||||
@ -40,7 +41,7 @@ describe('Content Manager | App | reducer', () => {
|
||||
isDisplayed: false,
|
||||
},
|
||||
];
|
||||
const singleTypeLinks = [
|
||||
const authorizedSingleTypeLinks = [
|
||||
{
|
||||
name: 'authorizedSt',
|
||||
isDisplayed: false,
|
||||
@ -71,15 +72,21 @@ describe('Content Manager | App | reducer', () => {
|
||||
expect(
|
||||
mainReducer(
|
||||
state,
|
||||
setContentTypeLinks(collectionTypeLinks, singleTypeLinks, ['test'], ['test'])
|
||||
setInitData({
|
||||
authorizedCollectionTypeLinks,
|
||||
authorizedSingleTypeLinks,
|
||||
contentTypeSchemas: ['test'],
|
||||
components: ['test'],
|
||||
fieldSizes: {},
|
||||
})
|
||||
)
|
||||
).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should handle the resetProps action correctly', () => {
|
||||
it('should handle the resetInitData action correctly', () => {
|
||||
state = 'test';
|
||||
|
||||
expect(mainReducer(state, resetProps())).toEqual({
|
||||
expect(mainReducer(state, resetInitData())).toEqual({
|
||||
components: [],
|
||||
models: [],
|
||||
collectionTypeLinks: [],
|
||||
|
@ -11,11 +11,11 @@ import axios from 'axios';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { MUTATE_COLLECTION_TYPES_LINKS, MUTATE_SINGLE_TYPES_LINKS } from '../../../exposedHooks';
|
||||
import { getRequestUrl, getTrad } from '../../utils';
|
||||
import { getData, resetProps, setContentTypeLinks } from './actions';
|
||||
import { getInitData, resetInitData, setInitData } from './actions';
|
||||
import { selectAppDomain } from './selectors';
|
||||
import getContentTypeLinks from './utils/getContentTypeLinks';
|
||||
|
||||
const useModels = () => {
|
||||
const useContentManagerInitData = () => {
|
||||
const dispatch = useDispatch();
|
||||
const toggleNotification = useNotification();
|
||||
const state = useSelector(selectAppDomain());
|
||||
@ -29,22 +29,14 @@ const useModels = () => {
|
||||
const { get } = useFetchClient();
|
||||
|
||||
const fetchData = async () => {
|
||||
dispatch(getData());
|
||||
dispatch(getInitData());
|
||||
|
||||
try {
|
||||
const [
|
||||
{
|
||||
data: { data: components },
|
||||
const {
|
||||
data: {
|
||||
data: { components, contentTypes: models, fieldSizes },
|
||||
},
|
||||
{
|
||||
data: { data: models },
|
||||
},
|
||||
] = await Promise.all(
|
||||
['components', 'content-types'].map((endPoint) =>
|
||||
get(getRequestUrl(endPoint), { cancelToken: source.token })
|
||||
)
|
||||
);
|
||||
|
||||
} = await get(getRequestUrl('init'), { cancelToken: source.token });
|
||||
notifyStatus(
|
||||
formatMessage({
|
||||
id: getTrad('App.schemas.data-loaded'),
|
||||
@ -52,22 +44,31 @@ const useModels = () => {
|
||||
})
|
||||
);
|
||||
|
||||
const { authorizedCtLinks, authorizedStLinks } = await getContentTypeLinks(
|
||||
const unmutatedContentTypeLinks = await getContentTypeLinks({
|
||||
models,
|
||||
allPermissions,
|
||||
toggleNotification
|
||||
userPermissions: allPermissions,
|
||||
toggleNotification,
|
||||
});
|
||||
|
||||
const { ctLinks: authorizedCollectionTypeLinks } = runHookWaterfall(
|
||||
MUTATE_COLLECTION_TYPES_LINKS,
|
||||
{
|
||||
ctLinks: unmutatedContentTypeLinks.authorizedCollectionTypeLinks,
|
||||
models,
|
||||
}
|
||||
);
|
||||
|
||||
const { ctLinks } = runHookWaterfall(MUTATE_COLLECTION_TYPES_LINKS, {
|
||||
ctLinks: authorizedCtLinks,
|
||||
models,
|
||||
});
|
||||
const { stLinks } = runHookWaterfall(MUTATE_SINGLE_TYPES_LINKS, {
|
||||
stLinks: authorizedStLinks,
|
||||
const { stLinks: authorizedSingleTypeLinks } = runHookWaterfall(MUTATE_SINGLE_TYPES_LINKS, {
|
||||
stLinks: unmutatedContentTypeLinks.authorizedSingleTypeLinks,
|
||||
models,
|
||||
});
|
||||
|
||||
const actionToDispatch = setContentTypeLinks(ctLinks, stLinks, models, components);
|
||||
const actionToDispatch = setInitData({
|
||||
authorizedCollectionTypeLinks,
|
||||
authorizedSingleTypeLinks,
|
||||
contentTypeSchemas: models,
|
||||
components,
|
||||
fieldSizes,
|
||||
});
|
||||
|
||||
dispatch(actionToDispatch);
|
||||
} catch (err) {
|
||||
@ -88,7 +89,7 @@ const useModels = () => {
|
||||
|
||||
return () => {
|
||||
source.cancel('Operation canceled by the user.');
|
||||
dispatch(resetProps());
|
||||
dispatch(resetInitData());
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [dispatch, toggleNotification]);
|
||||
@ -96,4 +97,4 @@ const useModels = () => {
|
||||
return { ...state, refetchData: fetchDataRef.current };
|
||||
};
|
||||
|
||||
export default useModels;
|
||||
export default useContentManagerInitData;
|
@ -52,12 +52,12 @@ const generateModelsLinks = (models, modelsConfigurations) => {
|
||||
const [collectionTypes, singleTypes] = sortBy(groupedModels, 'name');
|
||||
|
||||
return {
|
||||
collectionTypesSectionLinks: generateLinks(
|
||||
collectionTypeSectionLinks: generateLinks(
|
||||
collectionTypes?.links || [],
|
||||
'collectionTypes',
|
||||
modelsConfigurations
|
||||
),
|
||||
singleTypesSectionLinks: generateLinks(singleTypes?.links ?? [], 'singleTypes'),
|
||||
singleTypeSectionLinks: generateLinks(singleTypes?.links ?? [], 'singleTypes'),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -3,36 +3,38 @@ import generateModelsLinks from './generateModelsLinks';
|
||||
import checkPermissions from './checkPermissions';
|
||||
import { getRequestUrl } from '../../../utils';
|
||||
|
||||
const getContentTypeLinks = async (models, userPermissions, toggleNotification) => {
|
||||
const getContentTypeLinks = async ({ models, userPermissions, toggleNotification }) => {
|
||||
const { get } = getFetchClient();
|
||||
try {
|
||||
const {
|
||||
data: { data: contentTypeConfigurations },
|
||||
} = await get(getRequestUrl('content-types-settings'));
|
||||
|
||||
const { collectionTypesSectionLinks, singleTypesSectionLinks } = generateModelsLinks(
|
||||
const { collectionTypeSectionLinks, singleTypeSectionLinks } = generateModelsLinks(
|
||||
models,
|
||||
contentTypeConfigurations
|
||||
);
|
||||
|
||||
// Content Types verifications
|
||||
const ctLinksPermissionsPromises = checkPermissions(
|
||||
userPermissions,
|
||||
collectionTypesSectionLinks
|
||||
// Collection Types verifications
|
||||
const collectionTypeLinksPermissions = await Promise.all(
|
||||
checkPermissions(userPermissions, collectionTypeSectionLinks)
|
||||
);
|
||||
const ctLinksPermissions = await Promise.all(ctLinksPermissionsPromises);
|
||||
const authorizedCtLinks = collectionTypesSectionLinks.filter(
|
||||
(_, index) => ctLinksPermissions[index]
|
||||
const authorizedCollectionTypeLinks = collectionTypeSectionLinks.filter(
|
||||
(_, index) => collectionTypeLinksPermissions[index]
|
||||
);
|
||||
|
||||
// Single Types verifications
|
||||
const stLinksPermissionsPromises = checkPermissions(userPermissions, singleTypesSectionLinks);
|
||||
const stLinksPermissions = await Promise.all(stLinksPermissionsPromises);
|
||||
const authorizedStLinks = singleTypesSectionLinks.filter(
|
||||
(_, index) => stLinksPermissions[index]
|
||||
const singleTypeLinksPermissions = await Promise.all(
|
||||
checkPermissions(userPermissions, singleTypeSectionLinks)
|
||||
);
|
||||
const authorizedSingleTypeLinks = singleTypeSectionLinks.filter(
|
||||
(_, index) => singleTypeLinksPermissions[index]
|
||||
);
|
||||
|
||||
return { authorizedCtLinks, authorizedStLinks };
|
||||
return {
|
||||
authorizedCollectionTypeLinks,
|
||||
authorizedSingleTypeLinks,
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
||||
@ -41,7 +43,7 @@ const getContentTypeLinks = async (models, userPermissions, toggleNotification)
|
||||
message: { id: 'notification.error' },
|
||||
});
|
||||
|
||||
return { authorizedCtLinks: [], authorizedStLinks: [], contentTypes: [] };
|
||||
return { authorizedCollectionTypeLinks: [], authorizedSingleTypeLinks: [] };
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -119,7 +119,7 @@ describe('ADMIN | LeftMenu | utils', () => {
|
||||
];
|
||||
|
||||
const expected = {
|
||||
collectionTypesSectionLinks: [
|
||||
collectionTypeSectionLinks: [
|
||||
{
|
||||
isDisplayed: true,
|
||||
search: null,
|
||||
@ -140,7 +140,7 @@ describe('ADMIN | LeftMenu | utils', () => {
|
||||
],
|
||||
},
|
||||
],
|
||||
singleTypesSectionLinks: [
|
||||
singleTypeSectionLinks: [
|
||||
{
|
||||
isDisplayed: true,
|
||||
kind: 'singleType',
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { request, hasPermissions } from '@strapi/helper-plugin';
|
||||
import { getFetchClient, hasPermissions } from '@strapi/helper-plugin';
|
||||
import getContentTypeLinks from '../getContentTypeLinks';
|
||||
|
||||
// FIXME
|
||||
@ -44,24 +44,24 @@ describe('checkPermissions', () => {
|
||||
},
|
||||
];
|
||||
|
||||
const data = [
|
||||
const contentTypes = [
|
||||
{
|
||||
uid: 'api::address.address',
|
||||
isDisplayed: true,
|
||||
apiID: 'address',
|
||||
kind: 'collectionType',
|
||||
info: {
|
||||
label: 'address',
|
||||
displayName: 'Address',
|
||||
},
|
||||
isDisplayed: true,
|
||||
kind: 'collectionType',
|
||||
uid: 'api::address.address',
|
||||
},
|
||||
{
|
||||
uid: 'api::article.article',
|
||||
isDisplayed: true,
|
||||
apiID: 'article',
|
||||
kind: 'collectionType',
|
||||
info: {
|
||||
label: 'article',
|
||||
displayName: 'Article',
|
||||
},
|
||||
isDisplayed: true,
|
||||
kind: 'collectionType',
|
||||
uid: 'api::article.article',
|
||||
pluginOptions: {
|
||||
i18n: {
|
||||
localized: true,
|
||||
@ -70,32 +70,36 @@ describe('checkPermissions', () => {
|
||||
},
|
||||
];
|
||||
|
||||
request.mockImplementation((url) => {
|
||||
if (url === '/content-manager/content-types') {
|
||||
return Promise.resolve({ data });
|
||||
}
|
||||
|
||||
return Promise.resolve({
|
||||
data: [
|
||||
{
|
||||
uid: 'api::address.address',
|
||||
settings: {
|
||||
pageSize: 10,
|
||||
defaultSortBy: 'name',
|
||||
defaultSortOrder: 'ASC',
|
||||
getFetchClient.mockImplementation(() => ({
|
||||
get(url) {
|
||||
if (url === '/content-manager/content-types-settings') {
|
||||
return Promise.resolve({
|
||||
data: {
|
||||
data: [
|
||||
{
|
||||
uid: 'api::address.address',
|
||||
settings: {
|
||||
pageSize: 10,
|
||||
defaultSortBy: 'name',
|
||||
defaultSortOrder: 'ASC',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// To please the linter
|
||||
return Promise.resolve(null);
|
||||
},
|
||||
}));
|
||||
|
||||
const expected = {
|
||||
authorizedCtLinks: [
|
||||
authorizedCollectionTypeLinks: [
|
||||
{
|
||||
destination: '/content-manager/collectionType/api::address.address',
|
||||
icon: 'circle',
|
||||
isDisplayed: true,
|
||||
label: 'address',
|
||||
kind: 'collectionType',
|
||||
name: 'api::address.address',
|
||||
permissions: [
|
||||
{
|
||||
action: 'plugin::content-manager.explorer.create',
|
||||
@ -107,13 +111,14 @@ describe('checkPermissions', () => {
|
||||
},
|
||||
],
|
||||
search: 'page=1&pageSize=10&sort=name:ASC',
|
||||
title: 'Address',
|
||||
to: '/content-manager/collectionType/api::address.address',
|
||||
uid: 'api::address.address',
|
||||
},
|
||||
{
|
||||
destination: '/content-manager/collectionType/api::article.article',
|
||||
icon: 'circle',
|
||||
isDisplayed: true,
|
||||
label: 'article',
|
||||
search: null,
|
||||
kind: 'collectionType',
|
||||
name: 'api::article.article',
|
||||
permissions: [
|
||||
{
|
||||
action: 'plugin::content-manager.explorer.create',
|
||||
@ -124,12 +129,15 @@ describe('checkPermissions', () => {
|
||||
subject: 'api::article.article',
|
||||
},
|
||||
],
|
||||
search: null,
|
||||
title: 'Article',
|
||||
to: '/content-manager/collectionType/api::article.article',
|
||||
uid: 'api::article.article',
|
||||
},
|
||||
],
|
||||
authorizedStLinks: [],
|
||||
contentTypes: data,
|
||||
authorizedSingleTypeLinks: [],
|
||||
};
|
||||
const actual = await getContentTypeLinks(userPermissions);
|
||||
const actual = await getContentTypeLinks({ userPermissions, models: contentTypes });
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
@ -139,11 +147,13 @@ describe('checkPermissions', () => {
|
||||
const toggleNotification = jest.fn();
|
||||
const userPermissions = [];
|
||||
|
||||
request.mockImplementation(() => {
|
||||
throw new Error('Something went wrong');
|
||||
});
|
||||
getFetchClient.mockImplementation(() => ({
|
||||
get() {
|
||||
throw new Error('Something went wrong');
|
||||
},
|
||||
}));
|
||||
|
||||
await getContentTypeLinks(userPermissions, toggleNotification);
|
||||
await getContentTypeLinks({ userPermissions, toggleNotification });
|
||||
expect(toggleNotification).toBeCalled();
|
||||
});
|
||||
});
|
@ -6,7 +6,7 @@ import { useSelector, shallowEqual } from 'react-redux';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useLayoutDnd } from '../../../hooks';
|
||||
import { createPossibleMainFieldsForModelsAndComponents, getInputProps } from '../utils';
|
||||
import { makeSelectModelAndComponentSchemas } from '../../App/selectors';
|
||||
import { makeSelectModelAndComponentSchemas, selectFieldSizes } from '../../App/selectors';
|
||||
import getTrad from '../../../utils/getTrad';
|
||||
import GenericInput from './GenericInput';
|
||||
|
||||
@ -17,8 +17,6 @@ const FIELD_SIZES = [
|
||||
[12, '100%'],
|
||||
];
|
||||
|
||||
const NON_RESIZABLE_FIELD_TYPES = ['dynamiczone', 'component', 'json', 'richtext'];
|
||||
|
||||
const TIME_FIELD_OPTIONS = [1, 5, 10, 15, 30, 60];
|
||||
|
||||
const TIME_FIELD_TYPES = ['datetime', 'time'];
|
||||
@ -28,6 +26,7 @@ const ModalForm = ({ onMetaChange, onSizeChange }) => {
|
||||
const { modifiedData, selectedField, attributes, fieldForm } = useLayoutDnd();
|
||||
const schemasSelector = useMemo(makeSelectModelAndComponentSchemas, []);
|
||||
const { schemas } = useSelector((state) => schemasSelector(state), shallowEqual);
|
||||
const fieldSizes = useSelector(selectFieldSizes);
|
||||
|
||||
const formToDisplay = useMemo(() => {
|
||||
if (!selectedField) {
|
||||
@ -103,7 +102,7 @@ const ModalForm = ({ onMetaChange, onSizeChange }) => {
|
||||
);
|
||||
});
|
||||
|
||||
const canResize = !NON_RESIZABLE_FIELD_TYPES.includes(attributes[selectedField].type);
|
||||
const { isResizable } = fieldSizes[attributes[selectedField].type];
|
||||
|
||||
const sizeField = (
|
||||
<GridItem col={6} key="size">
|
||||
@ -152,7 +151,7 @@ const ModalForm = ({ onMetaChange, onSizeChange }) => {
|
||||
return (
|
||||
<>
|
||||
{metaFields}
|
||||
{canResize && sizeField}
|
||||
{isResizable && sizeField}
|
||||
{hasTimePicker && timeStepField}
|
||||
</>
|
||||
);
|
||||
|
@ -26,6 +26,7 @@ import {
|
||||
Divider,
|
||||
} from '@strapi/design-system';
|
||||
import { ArrowLeft, Check } from '@strapi/icons';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { getTrad } from '../../utils';
|
||||
import reducer, { initialState } from './reducer';
|
||||
import init from './init';
|
||||
@ -34,6 +35,7 @@ import ModalForm from './components/FormModal';
|
||||
import LayoutDndProvider from '../../components/LayoutDndProvider';
|
||||
import { unformatLayout } from './utils/layout';
|
||||
import putCMSettingsEV from './utils/api';
|
||||
import { selectFieldSizes } from '../App/selectors';
|
||||
|
||||
const EditSettingsView = ({ mainLayout, components, isContentTypeView, slug, updateLayout }) => {
|
||||
const [reducerState, dispatch] = useReducer(reducer, initialState, () =>
|
||||
@ -49,6 +51,7 @@ const EditSettingsView = ({ mainLayout, components, isContentTypeView, slug, upd
|
||||
const { formatMessage } = useIntl();
|
||||
const modelName = get(mainLayout, ['info', 'displayName'], '');
|
||||
const attributes = get(modifiedData, ['attributes'], {});
|
||||
const fieldSizes = useSelector(selectFieldSizes);
|
||||
|
||||
const entryTitleOptions = Object.keys(attributes).filter((attr) => {
|
||||
const type = get(attributes, [attr, 'type'], '');
|
||||
@ -318,6 +321,7 @@ const EditSettingsView = ({ mainLayout, components, isContentTypeView, slug, upd
|
||||
dispatch({
|
||||
type: 'ON_ADD_FIELD',
|
||||
name: field,
|
||||
fieldSizes,
|
||||
});
|
||||
}}
|
||||
onRemoveField={(rowId, index) => {
|
||||
|
@ -2,9 +2,10 @@ import produce from 'immer';
|
||||
import set from 'lodash/set';
|
||||
import get from 'lodash/get';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
|
||||
import { arrayMoveItem } from '../../utils';
|
||||
import { formatLayout, getDefaultInputSize, getFieldSize, setFieldSize } from './utils/layout';
|
||||
import { formatLayout, getFieldSize, setFieldSize } from './utils/layout';
|
||||
|
||||
const DEFAULT_FIELD_SIZE = 6;
|
||||
|
||||
const initialState = {
|
||||
fieldForm: {},
|
||||
@ -29,9 +30,8 @@ const reducer = (state = initialState, action) =>
|
||||
}
|
||||
case 'ON_ADD_FIELD': {
|
||||
const newState = cloneDeep(state);
|
||||
const size = getDefaultInputSize(
|
||||
get(newState, ['modifiedData', 'attributes', action.name, 'type'], '')
|
||||
);
|
||||
const type = get(newState, ['modifiedData', 'attributes', action.name, 'type'], '');
|
||||
const size = action.fieldSizes[type]?.default ?? DEFAULT_FIELD_SIZE;
|
||||
const listSize = get(newState, layoutPathEdit, []).length;
|
||||
const actualRowContentPath = [...layoutPathEdit, listSize - 1, 'rowContent'];
|
||||
const rowContentToSet = get(newState, actualRowContentPath, []);
|
||||
@ -149,8 +149,7 @@ const reducer = (state = initialState, action) =>
|
||||
draftState.metaToEdit = action.name;
|
||||
draftState.metaForm = {
|
||||
metadata: get(state, ['modifiedData', 'metadatas', action.name, 'edit'], {}),
|
||||
size:
|
||||
getFieldSize(action.name, state.modifiedData?.layouts?.edit) ?? getDefaultInputSize(),
|
||||
size: getFieldSize(action.name, state.modifiedData?.layouts?.edit) ?? DEFAULT_FIELD_SIZE,
|
||||
};
|
||||
|
||||
break;
|
||||
|
@ -4,10 +4,13 @@ import { Router } from 'react-router-dom';
|
||||
import { createMemoryHistory } from 'history';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
import { QueryClient, QueryClientProvider } from 'react-query';
|
||||
import { combineReducers, createStore } from 'redux';
|
||||
import { Provider } from 'react-redux';
|
||||
import { DndProvider } from 'react-dnd';
|
||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||
import { ThemeProvider, lightTheme } from '@strapi/design-system';
|
||||
import EditSettingsView from '../index';
|
||||
import cmReducers from '../../../../reducers';
|
||||
|
||||
jest.mock('@strapi/helper-plugin', () => ({
|
||||
...jest.requireActual('@strapi/helper-plugin'),
|
||||
@ -57,22 +60,31 @@ const makeApp = (history, layout) => {
|
||||
compo1: { uid: 'compo1' },
|
||||
};
|
||||
|
||||
const rootReducer = combineReducers(cmReducers);
|
||||
const store = createStore(rootReducer, {
|
||||
'content-manager_app': {
|
||||
fieldSizes: {},
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<Router history={history}>
|
||||
<QueryClientProvider client={client}>
|
||||
<IntlProvider messages={{ en: {} }} textComponent="span" locale="en">
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
<EditSettingsView
|
||||
mainLayout={layout || mainLayout}
|
||||
components={components}
|
||||
isContentTypeView
|
||||
slug="api::address.address"
|
||||
/>
|
||||
</DndProvider>
|
||||
</ThemeProvider>
|
||||
</IntlProvider>
|
||||
</QueryClientProvider>
|
||||
<Provider store={store}>
|
||||
<QueryClientProvider client={client}>
|
||||
<IntlProvider messages={{ en: {} }} textComponent="span" locale="en">
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
<EditSettingsView
|
||||
mainLayout={layout || mainLayout}
|
||||
components={components}
|
||||
isContentTypeView
|
||||
slug="api::address.address"
|
||||
/>
|
||||
</DndProvider>
|
||||
</ThemeProvider>
|
||||
</IntlProvider>
|
||||
</QueryClientProvider>
|
||||
</Provider>
|
||||
</Router>
|
||||
);
|
||||
};
|
||||
|
@ -1,5 +1,11 @@
|
||||
import reducer from '../reducer';
|
||||
|
||||
const fieldSizes = {
|
||||
richtext: { default: 12, isResizable: false },
|
||||
string: { default: 6, isResizable: true },
|
||||
boolean: { default: 4, isResizable: true },
|
||||
};
|
||||
|
||||
describe('CONTENT MANAGER | CONTAINERS | EditSettingsView | reducer', () => {
|
||||
let state;
|
||||
|
||||
@ -82,7 +88,11 @@ describe('CONTENT MANAGER | CONTAINERS | EditSettingsView | reducer', () => {
|
||||
},
|
||||
},
|
||||
};
|
||||
const action = { type: 'ON_ADD_FIELD', name: 'description' };
|
||||
const action = {
|
||||
type: 'ON_ADD_FIELD',
|
||||
name: 'description',
|
||||
fieldSizes,
|
||||
};
|
||||
expect(reducer(state, action)).toEqual(expected);
|
||||
});
|
||||
|
||||
@ -121,7 +131,7 @@ describe('CONTENT MANAGER | CONTAINERS | EditSettingsView | reducer', () => {
|
||||
},
|
||||
},
|
||||
};
|
||||
const action = { type: 'ON_ADD_FIELD', name: 'title' };
|
||||
const action = { type: 'ON_ADD_FIELD', name: 'title', fieldSizes };
|
||||
expect(reducer(state, action)).toEqual(expected);
|
||||
});
|
||||
|
||||
@ -163,7 +173,7 @@ describe('CONTENT MANAGER | CONTAINERS | EditSettingsView | reducer', () => {
|
||||
},
|
||||
},
|
||||
};
|
||||
const action = { type: 'ON_ADD_FIELD', name: 'isActive' };
|
||||
const action = { type: 'ON_ADD_FIELD', name: 'isActive', fieldSizes };
|
||||
expect(reducer(state, action)).toEqual(expected);
|
||||
});
|
||||
|
||||
@ -214,7 +224,7 @@ describe('CONTENT MANAGER | CONTAINERS | EditSettingsView | reducer', () => {
|
||||
},
|
||||
},
|
||||
};
|
||||
const action = { type: 'ON_ADD_FIELD', name: 'title' };
|
||||
const action = { type: 'ON_ADD_FIELD', name: 'title', fieldSizes };
|
||||
expect(reducer(state, action)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,3 @@
|
||||
/* eslint-disable indent */
|
||||
const getRowSize = (arr) => arr.reduce((sum, value) => sum + value.size, 0);
|
||||
|
||||
const createLayout = (arr) => {
|
||||
@ -75,26 +74,6 @@ const unformatLayout = (arr) => {
|
||||
}, []);
|
||||
};
|
||||
|
||||
const getDefaultInputSize = (type) => {
|
||||
switch (type) {
|
||||
case 'boolean':
|
||||
case 'date':
|
||||
case 'integer':
|
||||
case 'float':
|
||||
case 'biginteger':
|
||||
case 'decimal':
|
||||
case 'time':
|
||||
return 4;
|
||||
case 'json':
|
||||
case 'component':
|
||||
case 'richtext':
|
||||
case 'dynamiczone':
|
||||
return 12;
|
||||
default:
|
||||
return 6;
|
||||
}
|
||||
};
|
||||
|
||||
const getFieldSize = (name, layouts = []) => {
|
||||
return layouts.reduce((acc, { rowContent }) => {
|
||||
const size = rowContent.find((row) => row.name === name)?.size ?? null;
|
||||
@ -124,12 +103,4 @@ const setFieldSize = (name, size, layouts = []) => {
|
||||
});
|
||||
};
|
||||
|
||||
export {
|
||||
createLayout,
|
||||
formatLayout,
|
||||
getDefaultInputSize,
|
||||
getFieldSize,
|
||||
setFieldSize,
|
||||
getRowSize,
|
||||
unformatLayout,
|
||||
};
|
||||
export { createLayout, formatLayout, getFieldSize, setFieldSize, getRowSize, unformatLayout };
|
||||
|
@ -1,7 +1,6 @@
|
||||
import {
|
||||
createLayout,
|
||||
formatLayout,
|
||||
getDefaultInputSize,
|
||||
getFieldSize,
|
||||
setFieldSize,
|
||||
getRowSize,
|
||||
@ -118,24 +117,6 @@ describe('Content Manager | containers | EditSettingsView | utils | layout', ()
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDefaultInputSize', () => {
|
||||
it('Should return 6 if the type is unknown, undefined or text', () => {
|
||||
expect(getDefaultInputSize(undefined)).toBe(6);
|
||||
expect(getDefaultInputSize('unkown')).toBe(6);
|
||||
expect(getDefaultInputSize('text')).toBe(6);
|
||||
});
|
||||
|
||||
it('Should return 12 if the type is either json, component or richtext', () => {
|
||||
expect(getDefaultInputSize('json')).toBe(12);
|
||||
expect(getDefaultInputSize('richtext')).toBe(12);
|
||||
expect(getDefaultInputSize('component')).toBe(12);
|
||||
});
|
||||
|
||||
it('Should return 4 if the type is boolean', () => {
|
||||
expect(getDefaultInputSize('boolean')).toBe(4);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFieldSize', () => {
|
||||
const fixture = [
|
||||
{
|
||||
|
@ -3,6 +3,7 @@
|
||||
const collectionTypes = require('./collection-types');
|
||||
const components = require('./components');
|
||||
const contentTypes = require('./content-types');
|
||||
const init = require('./init');
|
||||
const relations = require('./relations');
|
||||
const singleTypes = require('./single-types');
|
||||
const uid = require('./uid');
|
||||
@ -11,6 +12,7 @@ module.exports = {
|
||||
'collection-types': collectionTypes,
|
||||
components,
|
||||
'content-types': contentTypes,
|
||||
init,
|
||||
relations,
|
||||
'single-types': singleTypes,
|
||||
uid,
|
||||
|
20
packages/core/content-manager/server/controllers/init.js
Normal file
20
packages/core/content-manager/server/controllers/init.js
Normal file
@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
const { getService } = require('../utils');
|
||||
|
||||
module.exports = {
|
||||
getInitData(ctx) {
|
||||
const { toDto } = getService('data-mapper');
|
||||
const { findAllComponents } = getService('components');
|
||||
const { getAllFieldSizes } = getService('field-sizes');
|
||||
const { findAllContentTypes } = getService('content-types');
|
||||
|
||||
ctx.body = {
|
||||
data: {
|
||||
fieldSizes: getAllFieldSizes(),
|
||||
components: findAllComponents().map(toDto),
|
||||
contentTypes: findAllContentTypes().map(toDto),
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
@ -5,6 +5,14 @@ const { routing } = require('../middlewares');
|
||||
module.exports = {
|
||||
type: 'admin',
|
||||
routes: [
|
||||
{
|
||||
method: 'GET',
|
||||
path: '/init',
|
||||
handler: 'init.getInitData',
|
||||
config: {
|
||||
policies: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
method: 'GET',
|
||||
path: '/content-types',
|
||||
|
@ -0,0 +1,33 @@
|
||||
'use strict';
|
||||
|
||||
const fieldSizesService = require('../field-sizes');
|
||||
|
||||
describe('field sizes service', () => {
|
||||
it('should return the correct field sizes', () => {
|
||||
const { getAllFieldSizes } = fieldSizesService();
|
||||
const fieldSizes = getAllFieldSizes();
|
||||
Object.values(fieldSizes).forEach((fieldSize) => {
|
||||
expect(typeof fieldSize.isResizable).toBe('boolean');
|
||||
expect([4, 6, 8, 12]).toContain(fieldSize.default);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return the correct field size for a given type', () => {
|
||||
const { getFieldSize } = fieldSizesService();
|
||||
const fieldSize = getFieldSize('string');
|
||||
expect(fieldSize.isResizable).toBe(true);
|
||||
expect(fieldSize.default).toBe(6);
|
||||
});
|
||||
|
||||
it('should throw an error if the type is not found', () => {
|
||||
const { getFieldSize } = fieldSizesService();
|
||||
expect(() => getFieldSize('not-found')).toThrowError(
|
||||
'Could not find field size for type not-found'
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw an error if the type is not provided', () => {
|
||||
const { getFieldSize } = fieldSizesService();
|
||||
expect(() => getFieldSize()).toThrowError('The type is required');
|
||||
});
|
||||
});
|
63
packages/core/content-manager/server/services/field-sizes.js
Normal file
63
packages/core/content-manager/server/services/field-sizes.js
Normal file
@ -0,0 +1,63 @@
|
||||
'use strict';
|
||||
|
||||
const needsFullSize = {
|
||||
default: 12,
|
||||
isResizable: false,
|
||||
};
|
||||
|
||||
const smallSize = {
|
||||
default: 4,
|
||||
isResizable: true,
|
||||
};
|
||||
|
||||
const defaultSize = {
|
||||
default: 6,
|
||||
isResizable: true,
|
||||
};
|
||||
|
||||
const fieldSizes = {
|
||||
// Full row and not resizable
|
||||
dynamiczone: needsFullSize,
|
||||
component: needsFullSize,
|
||||
json: needsFullSize,
|
||||
richtext: needsFullSize,
|
||||
// Small and resizable
|
||||
checkbox: smallSize,
|
||||
boolean: smallSize,
|
||||
date: smallSize,
|
||||
time: smallSize,
|
||||
biginteger: smallSize,
|
||||
decimal: smallSize,
|
||||
float: smallSize,
|
||||
integer: smallSize,
|
||||
number: smallSize,
|
||||
// Medium and resizable
|
||||
datetime: defaultSize,
|
||||
email: defaultSize,
|
||||
enumeration: defaultSize,
|
||||
media: defaultSize,
|
||||
password: defaultSize,
|
||||
relation: defaultSize,
|
||||
string: defaultSize,
|
||||
text: defaultSize,
|
||||
timestamp: defaultSize,
|
||||
uid: defaultSize,
|
||||
};
|
||||
|
||||
module.exports = () => ({
|
||||
getAllFieldSizes() {
|
||||
return fieldSizes;
|
||||
},
|
||||
getFieldSize(type) {
|
||||
if (!type) {
|
||||
throw new Error('The type is required');
|
||||
}
|
||||
|
||||
const fieldSize = fieldSizes[type];
|
||||
if (!fieldSize) {
|
||||
throw new Error(`Could not find field size for type ${type}`);
|
||||
}
|
||||
|
||||
return fieldSize;
|
||||
},
|
||||
});
|
@ -3,19 +3,21 @@
|
||||
const components = require('./components');
|
||||
const contentTypes = require('./content-types');
|
||||
const dataMapper = require('./data-mapper');
|
||||
const entityManager = require('./entity-manager');
|
||||
const fieldSizes = require('./field-sizes');
|
||||
const metrics = require('./metrics');
|
||||
const permissionChecker = require('./permission-checker');
|
||||
const permission = require('./permission');
|
||||
const uid = require('./uid');
|
||||
const entityManager = require('./entity-manager');
|
||||
|
||||
module.exports = {
|
||||
components,
|
||||
'content-types': contentTypes,
|
||||
'data-mapper': dataMapper,
|
||||
'entity-manager': entityManager,
|
||||
'field-sizes': fieldSizes,
|
||||
metrics,
|
||||
'permission-checker': permissionChecker,
|
||||
permission,
|
||||
uid,
|
||||
'entity-manager': entityManager,
|
||||
};
|
||||
|
@ -1,42 +1,28 @@
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash');
|
||||
const { getService } = require('../../../utils');
|
||||
const { isListable, hasEditableAttribute, hasRelationAttribute } = require('./attributes');
|
||||
|
||||
const DEFAULT_LIST_LENGTH = 4;
|
||||
const MAX_ROW_SIZE = 12;
|
||||
const FIELD_TYPES_FULL_SIZE = ['dynamiczone', 'component', 'json', 'richtext'];
|
||||
const FIELD_TYPES_SMALL = [
|
||||
'checkbox',
|
||||
'boolean',
|
||||
'date',
|
||||
'time',
|
||||
'biginteger',
|
||||
'decimal',
|
||||
'float',
|
||||
'integer',
|
||||
'number',
|
||||
];
|
||||
|
||||
const isAllowedFieldSize = (type, size) => {
|
||||
if (FIELD_TYPES_FULL_SIZE.includes(type)) {
|
||||
return size === MAX_ROW_SIZE;
|
||||
const { getFieldSize } = getService('field-sizes');
|
||||
const fieldSize = getFieldSize(type);
|
||||
|
||||
// Check if field was locked to another size
|
||||
if (!fieldSize.isResizable && size !== fieldSize.default) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// validate, whether the field has 4, 6, 8 or 12 columns?
|
||||
// Otherwise allow unless it's bigger than a row
|
||||
return size <= MAX_ROW_SIZE;
|
||||
};
|
||||
|
||||
const getDefaultFieldSize = (type) => {
|
||||
if (FIELD_TYPES_FULL_SIZE.includes(type)) {
|
||||
return MAX_ROW_SIZE;
|
||||
}
|
||||
|
||||
if (FIELD_TYPES_SMALL.includes(type)) {
|
||||
return MAX_ROW_SIZE / 3;
|
||||
}
|
||||
|
||||
return MAX_ROW_SIZE / 2;
|
||||
const { getFieldSize } = getService('field-sizes');
|
||||
return getFieldSize(type).default;
|
||||
};
|
||||
|
||||
async function createDefaultLayouts(schema) {
|
||||
|
@ -3,6 +3,7 @@ import * as configuration from '../services/configuration';
|
||||
import * as contentTypes from '../services/content-types';
|
||||
import * as dataMapper from '../services/data-mapper';
|
||||
import * as entityManager from '../services/entity-manager';
|
||||
import * as fieldSizes from '../services/field-sizes';
|
||||
import * as metris from '../services/metris';
|
||||
import * as permissionChecker from '../services/permission-checker';
|
||||
import * as permission from '../services/permission';
|
||||
@ -15,6 +16,7 @@ type S = {
|
||||
['permission-checker']: typeof permissionChecker;
|
||||
components: typeof components;
|
||||
configuration: typeof configuration;
|
||||
['field-sizes']: typeof fieldSizes;
|
||||
metris: typeof metris;
|
||||
permission: typeof permission;
|
||||
uid: typeof uid;
|
||||
|
Loading…
x
Reference in New Issue
Block a user