diff --git a/examples/getstarted/api/address/models/Address.settings.json b/examples/getstarted/api/address/models/Address.settings.json index 484ab0b0d8..a7e440de32 100755 --- a/examples/getstarted/api/address/models/Address.settings.json +++ b/examples/getstarted/api/address/models/Address.settings.json @@ -72,6 +72,10 @@ }, "address": { "model": "address" + }, + "admin_user": { + "plugin": "admin", + "model": "user" } } } diff --git a/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/index.js b/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/index.js index aef96b32e7..6df96f36d4 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/index.js @@ -19,7 +19,6 @@ import { connect, select, styles } from './utils'; function SelectWrapper({ description, - displayNavigationLink, editable, label, isCreatingEntry, @@ -163,7 +162,7 @@ function SelectWrapper({ return null; } - if (!displayNavigationLink) { + if (!queryInfos.shouldDisplayRelationLink) { return null; } @@ -174,7 +173,7 @@ function SelectWrapper({ ); - }, [displayNavigationLink, pathname, to, value]); + }, [queryInfos.shouldDisplayRelationLink, pathname, to, value]); const Component = isSingle ? SelectOne : SelectMany; const associationsLength = isArray(value) ? value.length : 0; @@ -225,7 +224,7 @@ function SelectWrapper({ addRelation({ target: { name, value } }); }} components={{ ClearIndicator, DropdownIndicator, IndicatorSeparator, Option }} - displayNavigationLink={displayNavigationLink} + displayNavigationLink={queryInfos.shouldDisplayRelationLink} id={name} isDisabled={isDisabled} isLoading={isLoading} @@ -269,7 +268,6 @@ SelectWrapper.defaultProps = { }; SelectWrapper.propTypes = { - displayNavigationLink: PropTypes.bool.isRequired, editable: PropTypes.bool, description: PropTypes.string, label: PropTypes.string, @@ -285,6 +283,7 @@ SelectWrapper.propTypes = { containsKey: PropTypes.string.isRequired, defaultParams: PropTypes.object, endPoint: PropTypes.string.isRequired, + shouldDisplayRelationLink: PropTypes.bool.isRequired, }).isRequired, }; diff --git a/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/utils/select.js b/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/utils/select.js index 20c864d7eb..9c320ae904 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/utils/select.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/SelectWrapper/utils/select.js @@ -1,9 +1,7 @@ import { useMemo } from 'react'; -import { get } from 'lodash'; import useDataManager from '../../../hooks/useDataManager'; -import useEditView from '../../../hooks/useEditView'; -function useSelect({ isUserAllowedToEditField, isUserAllowedToReadField, name, targetModel }) { +function useSelect({ isUserAllowedToEditField, isUserAllowedToReadField, name }) { const { isCreatingEntry, createActionAllowedFields, @@ -11,16 +9,6 @@ function useSelect({ isUserAllowedToEditField, isUserAllowedToReadField, name, t updateActionAllowedFields, } = useDataManager(); - // TODO important! remove models dependency from the useEditView hook, - // This info should be handle in the layout? - const { models } = useEditView(); - - const displayNavigationLink = useMemo(() => { - const targetModelSchema = models.find(obj => obj.uid === targetModel); - - return get(targetModelSchema, 'isDisplayed', false); - }, [targetModel, models]); - const isFieldAllowed = useMemo(() => { if (isUserAllowedToEditField === true) { return true; @@ -48,7 +36,6 @@ function useSelect({ isUserAllowedToEditField, isUserAllowedToReadField, name, t }, [isCreatingEntry, isUserAllowedToReadField, name, readActionAllowedFields]); return { - displayNavigationLink, isCreatingEntry, isFieldAllowed, isFieldReadable, diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/EditView/DeleteLink/index.js b/packages/strapi-plugin-content-manager/admin/src/containers/EditView/DeleteLink/index.js index a037503a4e..551e0256bc 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/EditView/DeleteLink/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/EditView/DeleteLink/index.js @@ -11,13 +11,7 @@ import { getTrad } from '../../../utils'; import { DeleteButton } from '../components'; import { connect, select } from './utils'; -const DeleteLink = ({ - canDelete, - isCreatingEntry, - onDelete, - onDeleteSucceeded, - trackerProperty, -}) => { +const DeleteLink = ({ isCreatingEntry, onDelete, onDeleteSucceeded, trackerProperty }) => { const [showWarningDelete, setWarningDelete] = useState(false); const [didDeleteEntry, setDidDeleteEntry] = useState(false); const [isModalConfirmButtonLoading, setIsModalConfirmButtonLoading] = useState(false); @@ -57,7 +51,7 @@ const DeleteLink = ({ } }; - if (isCreatingEntry || !canDelete) { + if (isCreatingEntry) { return null; } @@ -89,7 +83,6 @@ const DeleteLink = ({ }; DeleteLink.propTypes = { - canDelete: PropTypes.bool.isRequired, isCreatingEntry: PropTypes.bool.isRequired, onDelete: PropTypes.func.isRequired, onDeleteSucceeded: PropTypes.func.isRequired, diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/EditView/DeleteLink/utils/select.js b/packages/strapi-plugin-content-manager/admin/src/containers/EditView/DeleteLink/utils/select.js index 9a7d7e1636..3dbf860c42 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/EditView/DeleteLink/utils/select.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/EditView/DeleteLink/utils/select.js @@ -1,12 +1,8 @@ import { isEmpty } from 'lodash'; import useDataManager from '../../../../hooks/useDataManager'; -import useEditView from '../../../../hooks/useEditView'; function useSelect() { const { hasDraftAndPublish, modifiedData } = useDataManager(); - const { - allowedActions: { canDelete }, - } = useEditView(); let trackerProperty = {}; @@ -17,7 +13,6 @@ function useSelect() { } return { - canDelete, hasDraftAndPublish, trackerProperty, }; diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/EditView/Header/index.js b/packages/strapi-plugin-content-manager/admin/src/containers/EditView/Header/index.js index b64751b05c..bd0157e7fc 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/EditView/Header/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/EditView/Header/index.js @@ -19,9 +19,7 @@ const primaryButtonObject = { }; const Header = ({ - canUpdate, - canCreate, - canPublish, + allowedActions: { canUpdate, canCreate, canPublish }, componentLayouts, initialData, isCreatingEntry, @@ -237,9 +235,11 @@ const Header = ({ }; Header.propTypes = { - canUpdate: PropTypes.bool.isRequired, - canCreate: PropTypes.bool.isRequired, - canPublish: PropTypes.bool.isRequired, + allowedActions: PropTypes.shape({ + canUpdate: PropTypes.bool.isRequired, + canCreate: PropTypes.bool.isRequired, + canPublish: PropTypes.bool.isRequired, + }).isRequired, componentLayouts: PropTypes.object.isRequired, initialData: PropTypes.object.isRequired, isCreatingEntry: PropTypes.bool.isRequired, diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/EditView/Header/utils/select.js b/packages/strapi-plugin-content-manager/admin/src/containers/EditView/Header/utils/select.js index 4ffb1a0b3d..39e3c4e941 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/EditView/Header/utils/select.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/EditView/Header/utils/select.js @@ -1,5 +1,4 @@ import useDataManager from '../../../../hooks/useDataManager'; -import useEditView from '../../../../hooks/useEditView'; function useSelect() { const { @@ -14,14 +13,8 @@ function useSelect() { onPublish, onUnpublish, } = useDataManager(); - const { - allowedActions: { canUpdate, canCreate, canPublish }, - } = useEditView(); return { - canUpdate, - canCreate, - canPublish, componentLayouts: allLayoutData.components, initialData, isCreatingEntry, diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/EditView/index.js b/packages/strapi-plugin-content-manager/admin/src/containers/EditView/index.js index 53b19677eb..f33899f68b 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/EditView/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/EditView/index.js @@ -23,7 +23,6 @@ import { useFetchContentTypeLayout } from '../../hooks'; import { generatePermissionsObject, getInjectedComponents } from '../../utils'; import CollectionTypeWrapper from '../CollectionTypeWrapper'; import EditViewDataManagerProvider from '../EditViewDataManagerProvider'; -import EditViewProvider from '../EditViewProvider'; import SingleTypeWrapper from '../SingleTypeWrapper'; import Header from './Header'; import { createAttributesLayout, getFieldsActionMatchingPermissions } from './utils'; @@ -34,7 +33,7 @@ import InformationCard from './InformationCard'; /* eslint-disable react/no-array-index-key */ // TODO check needed props -const EditView = ({ components, currentEnvironment, models, isSingleType, plugins, slug }) => { +const EditView = ({ currentEnvironment, isSingleType, plugins, slug }) => { const { isLoading, layout } = useFetchContentTypeLayout(slug); const { goBack } = useHistory(); // Legacy to remove for the configurations @@ -101,210 +100,195 @@ const EditView = ({ components, currentEnvironment, models, isSingleType, plugin } return ( - - - - {({ - componentsDataStructure, - contentTypeDataStructure, - data, - isCreatingEntry, - isLoadingForData, - onDelete, - onDeleteSucceeded, - onPost, - onPublish, - onPut, - onUnpublish, - status, - }) => { - return ( - - - -
-
-
- {formattedContentTypeLayout.map((block, blockIndex) => { - if (isDynamicZone(block)) { - const { - 0: { - 0: { name, fieldSchema, metadatas }, - }, - } = block; - - return ( - - ); - } + + + {({ + componentsDataStructure, + contentTypeDataStructure, + data, + isCreatingEntry, + isLoadingForData, + onDelete, + onDeleteSucceeded, + onPost, + onPublish, + onPut, + onUnpublish, + status, + }) => { + return ( + + + +
+
+
+ {formattedContentTypeLayout.map((block, blockIndex) => { + if (isDynamicZone(block)) { + const { + 0: { + 0: { name, fieldSchema, metadatas }, + }, + } = block; return ( - - {block.map((fieldsBlock, fieldsBlockIndex) => { - return ( -
- {fieldsBlock.map( - ({ name, size, fieldSchema, metadatas }, fieldIndex) => { - const isComponent = fieldSchema.type === 'component'; + + ); + } - if (isComponent) { - const { - component, - max, - min, - repeatable = false, - } = fieldSchema; - const componentUid = fieldSchema.component; + return ( + + {block.map((fieldsBlock, fieldsBlockIndex) => { + return ( +
+ {fieldsBlock.map( + ({ name, size, fieldSchema, metadatas }, fieldIndex) => { + const isComponent = fieldSchema.type === 'component'; - return ( - - ); - } + if (isComponent) { + const { + component, + max, + min, + repeatable = false, + } = fieldSchema; + const componentUid = fieldSchema.component; return ( -
- -
+ ); } - )} -
- ); - })} -
- ); - })} -
-
- - - {currentContentTypeLayoutData.layouts.editRelations.length > 0 && ( - -
- {currentContentTypeLayoutData.layouts.editRelations.map( - ({ name, fieldSchema, metadatas, queryInfos }) => { - return ( - - ); - } - )} -
-
- )} - -
    - - { - // emitEvent('willEditContentTypeLayoutFromEditView'); - }} - /> - - {getInjectedComponents( - 'editView', - 'right.links', - plugins, - currentEnvironment, - slug - )} - {allowedActions.canDelete && ( - - )} -
-
-
+ + return ( +
+ +
+ ); + } + )} +
+ ); + })} + + ); + })}
- - - ); - }} - - - +
+ + + {currentContentTypeLayoutData.layouts.editRelations.length > 0 && ( + +
+ {currentContentTypeLayoutData.layouts.editRelations.map( + ({ name, fieldSchema, metadatas, queryInfos }) => { + return ( + + ); + } + )} +
+
+ )} + +
    + + { + // emitEvent('willEditContentTypeLayoutFromEditView'); + }} + /> + + {getInjectedComponents( + 'editView', + 'right.links', + plugins, + currentEnvironment, + slug + )} + {allowedActions.canDelete && ( + + )} +
+
+
+
+ + + ); + }} + + ); }; EditView.defaultProps = { - // TODO currentEnvironment: 'production', - emitEvent: () => {}, plugins: {}, isSingleType: false, }; EditView.propTypes = { - components: PropTypes.array.isRequired, currentEnvironment: PropTypes.string, - emitEvent: PropTypes.func, isSingleType: PropTypes.bool, - models: PropTypes.array.isRequired, plugins: PropTypes.object, slug: PropTypes.string.isRequired, }; diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/Main/selectors.js b/packages/strapi-plugin-content-manager/admin/src/containers/Main/selectors.js index 0a0e068b62..ae7f4200d2 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/Main/selectors.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/Main/selectors.js @@ -5,8 +5,7 @@ import { initialState } from './reducer'; /** * Direct selector to the main state domain */ -const selectMainDomain = () => state => - state.get(`${pluginId}_main`) || initialState; +const selectMainDomain = () => state => state.get(`${pluginId}_main`) || initialState; /** * Other specific selectors @@ -17,12 +16,16 @@ const selectMainDomain = () => state => */ const makeSelectMain = () => - createSelector( - selectMainDomain(), - substate => { - return substate.toJS(); - } - ); + createSelector(selectMainDomain(), substate => { + return substate.toJS(); + }); + +const makeSelectModels = () => + createSelector(selectMainDomain(), substate => { + const allModels = substate.get('models').toJS(); + + return allModels.filter(model => model.isDisplayed === true).map(({ uid }) => uid); + }); export default makeSelectMain; -export { selectMainDomain }; +export { makeSelectModels, selectMainDomain }; diff --git a/packages/strapi-plugin-content-manager/admin/src/contexts/EditView.js b/packages/strapi-plugin-content-manager/admin/src/contexts/EditView.js deleted file mode 100644 index bcf05501f6..0000000000 --- a/packages/strapi-plugin-content-manager/admin/src/contexts/EditView.js +++ /dev/null @@ -1,5 +0,0 @@ -import { createContext } from 'react'; - -const EditViewContext = createContext(); - -export default EditViewContext; diff --git a/packages/strapi-plugin-content-manager/admin/src/contexts/index.js b/packages/strapi-plugin-content-manager/admin/src/contexts/index.js index 0952d10d43..81c600771d 100644 --- a/packages/strapi-plugin-content-manager/admin/src/contexts/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/contexts/index.js @@ -1,5 +1,4 @@ export { default as ContentTypeLayoutContext } from './ContentTypeLayout'; -export { default as EditViewContext } from './EditView'; export { default as EditViewDataManagerContext } from './EditViewDataManager'; export { default as LayoutDndContext } from './LayoutDnd'; export { default as ListViewContext } from './ListView'; diff --git a/packages/strapi-plugin-content-manager/admin/src/hooks/index.js b/packages/strapi-plugin-content-manager/admin/src/hooks/index.js index b2efc3ec50..58e67eb0ce 100644 --- a/packages/strapi-plugin-content-manager/admin/src/hooks/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/hooks/index.js @@ -1,7 +1,6 @@ export { default as useContentTypeLayout } from './useContentTypeLayout'; export { default as useFetchContentTypeLayout } from './useFetchContentTypeLayout'; export { default as useDataManager } from './useDataManager'; -export { default as useEditView } from './useEditView'; export { default as useLayoutDnd } from './useLayoutDnd'; export { default as useListView } from './useListView'; export { default as useWysiwyg } from './useWysiwyg'; diff --git a/packages/strapi-plugin-content-manager/admin/src/hooks/useEditView.js b/packages/strapi-plugin-content-manager/admin/src/hooks/useEditView.js deleted file mode 100644 index ea595f4a20..0000000000 --- a/packages/strapi-plugin-content-manager/admin/src/hooks/useEditView.js +++ /dev/null @@ -1,6 +0,0 @@ -import { useContext } from 'react'; -import EditViewContext from '../contexts/EditView'; - -const useEditView = () => useContext(EditViewContext); - -export default useEditView; diff --git a/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/index.js b/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/index.js index 9a5d8e19d0..def9583259 100644 --- a/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/index.js @@ -1,31 +1,38 @@ -import { useCallback, useEffect, useReducer } from 'react'; +import { useCallback, useEffect, useMemo, useReducer } from 'react'; +import { useSelector } from 'react-redux'; import { request } from 'strapi-helper-plugin'; import formatLayouts from './utils/formatLayouts'; import reducer, { initialState } from './reducer'; +import { makeSelectModels } from '../../containers/Main/selectors'; const useFetchContentTypeLayout = contentTypeUID => { const [{ error, isLoading, layout }, dispatch] = useReducer(reducer, initialState); + const modelsSelector = useMemo(makeSelectModels, []); + const models = useSelector(state => modelsSelector(state), []); - const getData = useCallback(async (uid, abortSignal = false) => { - let signal = abortSignal || new AbortController().signal; + const getData = useCallback( + async (uid, abortSignal = false) => { + let signal = abortSignal || new AbortController().signal; - dispatch({ type: 'GET_DATA' }); + dispatch({ type: 'GET_DATA' }); - try { - const { data } = await request(`/content-manager/content-types/${uid}`, { - method: 'GET', - signal, - }); + try { + const { data } = await request(`/content-manager/content-types/${uid}`, { + method: 'GET', + signal, + }); - dispatch({ - type: 'GET_DATA_SUCCEEDED', - data: formatLayouts(data), - }); - } catch (error) { - console.error(error); - dispatch({ type: 'GET_DATA_ERROR', error }); - } - }, []); + dispatch({ + type: 'GET_DATA_SUCCEEDED', + data: formatLayouts(data, models), + }); + } catch (error) { + console.error(error); + dispatch({ type: 'GET_DATA_ERROR', error }); + } + }, + [models] + ); useEffect(() => { const abortController = new AbortController(); diff --git a/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/formatLayouts.js b/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/formatLayouts.js index 5208b78992..aba7e5a91e 100644 --- a/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/formatLayouts.js +++ b/packages/strapi-plugin-content-manager/admin/src/hooks/useFetchContentTypeLayout/utils/formatLayouts.js @@ -1,7 +1,7 @@ import { get, set } from 'lodash'; import pluginId from '../../../pluginId'; -const formatLayoutWithMetas = (obj, ctUid) => { +const formatLayoutWithMetas = (obj, ctUid, models) => { const formatted = obj.layouts.edit.reduce((acc, current) => { const row = current.map(attribute => { const fieldSchema = get(obj, ['schema', 'attributes', attribute.name], {}); @@ -14,8 +14,8 @@ const formatLayoutWithMetas = (obj, ctUid) => { if (fieldSchema.type === 'relation') { const queryInfos = ctUid - ? generateRelationQueryInfosForComponents(obj, attribute.name, ctUid) - : generateRelationQueryInfos(obj, attribute.name); + ? generateRelationQueryInfosForComponents(obj, attribute.name, ctUid, models) + : generateRelationQueryInfos(obj, attribute.name, models); set(data, 'queryInfos', queryInfos); } @@ -31,23 +31,28 @@ const formatLayoutWithMetas = (obj, ctUid) => { return formatted; }; -const generateRelationQueryInfos = (obj, fieldName) => { +const generateRelationQueryInfos = (obj, fieldName, models) => { const uid = obj.uid; const endPoint = `/${pluginId}/explorer/${uid}/relation-list/${fieldName}`; const mainField = get(obj, ['metadatas', fieldName, 'edit', 'mainField'], ''); + const targetModel = get(obj, ['schema', 'attributes', fieldName, 'targetModel'], ''); + const shouldDisplayRelationLink = models.indexOf(targetModel) !== -1; const queryInfos = { endPoint, containsKey: `${mainField}_contains`, defaultParams: {}, + shouldDisplayRelationLink, }; return queryInfos; }; -const generateRelationQueryInfosForComponents = (obj, fieldName, ctUid) => { +const generateRelationQueryInfosForComponents = (obj, fieldName, ctUid, models) => { const endPoint = `/${pluginId}/explorer/${ctUid}/relation-list/${fieldName}`; const mainField = get(obj, ['metadatas', fieldName, 'edit', 'mainField'], ''); + const targetModel = get(obj, ['schema', 'attributes', fieldName, 'targetModel'], ''); + const shouldDisplayRelationLink = models.indexOf(targetModel) !== -1; const queryInfos = { endPoint, @@ -55,19 +60,20 @@ const generateRelationQueryInfosForComponents = (obj, fieldName, ctUid) => { defaultParams: { _component: obj.uid, }, + shouldDisplayRelationLink, }; return queryInfos; }; // editRelations is an array of strings... -const formatEditRelationsLayoutWithMetas = obj => { +const formatEditRelationsLayoutWithMetas = (obj, models) => { const formatted = obj.layouts.editRelations.reduce((acc, current) => { const fieldSchema = get(obj, ['schema', 'attributes', current], {}); const metadatas = get(obj, ['metadatas', current, 'edit'], {}); const size = 6; - const queryInfos = generateRelationQueryInfos(obj, current); + const queryInfos = generateRelationQueryInfos(obj, current, models); acc.push({ name: current, @@ -83,16 +89,20 @@ const formatEditRelationsLayoutWithMetas = obj => { return formatted; }; -const formatLayouts = data => { - const formattedCTEditLayout = formatLayoutWithMetas(data.contentType); +const formatLayouts = (data, models) => { + const formattedCTEditLayout = formatLayoutWithMetas(data.contentType, models); const ctUid = data.contentType.uid; - const formattedEditRelationsLayout = formatEditRelationsLayoutWithMetas(data.contentType); + const formattedEditRelationsLayout = formatEditRelationsLayoutWithMetas(data.contentType, models); set(data, ['contentType', 'layouts', 'edit'], formattedCTEditLayout); set(data, ['contentType', 'layouts', 'editRelations'], formattedEditRelationsLayout); Object.keys(data.components).forEach(compoUID => { - const formattedCompoEditLayout = formatLayoutWithMetas(data.components[compoUID], ctUid); + const formattedCompoEditLayout = formatLayoutWithMetas( + data.components[compoUID], + ctUid, + models + ); set(data, ['components', compoUID, 'layouts', 'edit'], formattedCompoEditLayout); });