diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/CollectionTypeFormWrapper/index.js b/packages/strapi-plugin-content-manager/admin/src/containers/CollectionTypeFormWrapper/index.js index 14dfa8c0d3..0a641539b7 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/CollectionTypeFormWrapper/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/CollectionTypeFormWrapper/index.js @@ -1,5 +1,5 @@ import { memo, useCallback, useEffect, useMemo, useRef, useReducer } from 'react'; -import { useParams, useHistory } from 'react-router-dom'; +import { useHistory } from 'react-router-dom'; import { get } from 'lodash'; import { request, useGlobalContext } from 'strapi-helper-plugin'; import PropTypes from 'prop-types'; @@ -15,11 +15,10 @@ import { crudInitialState, crudReducer } from '../../sharedReducers'; import { getRequestUrl } from './utils'; // This container is used to handle the CRUD -const CollectionTypeFormWrapper = ({ allLayoutData, children, from, slug }) => { +const CollectionTypeFormWrapper = ({ allLayoutData, children, from, slug, id, origin }) => { const { emitEvent } = useGlobalContext(); const { push, replace } = useHistory(); - const { id, origin } = useParams(); const [ { componentsDataStructure, contentTypeDataStructure, data, isLoading, status }, dispatch, @@ -99,8 +98,6 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, from, slug }) => { }); }, [allLayoutData]); - const shouldFetch = useRef(true); - useEffect(() => { const abortController = new AbortController(); const { signal } = abortController; @@ -139,7 +136,7 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, from, slug }) => { } }; - if (requestURL && shouldFetch.current) { + if (requestURL) { getData(signal); } else { dispatch({ type: 'INIT_FORM' }); @@ -147,7 +144,6 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, from, slug }) => { return () => { abortController.abort(); - shouldFetch.current = requestURL === null; }; }, [requestURL, push, from, cleanReceivedData, cleanClonedData]); @@ -315,6 +311,7 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, from, slug }) => { CollectionTypeFormWrapper.defaultProps = { from: '/', + origin: null, }; CollectionTypeFormWrapper.propTypes = { @@ -335,6 +332,8 @@ CollectionTypeFormWrapper.propTypes = { }).isRequired, children: PropTypes.func.isRequired, from: PropTypes.string, + id: PropTypes.string.isRequired, + origin: PropTypes.string, slug: PropTypes.string.isRequired, }; diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/CollectionTypeRecursivePath/index.js b/packages/strapi-plugin-content-manager/admin/src/containers/CollectionTypeRecursivePath/index.js index b0a0872a96..e24522ef57 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/CollectionTypeRecursivePath/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/CollectionTypeRecursivePath/index.js @@ -1,5 +1,7 @@ import React, { memo, useMemo } from 'react'; -import { Switch, Route, useRouteMatch, useParams } from 'react-router-dom'; +import { Switch, Route } from 'react-router-dom'; +import { get } from 'lodash'; +import PropTypes from 'prop-types'; import { LoadingIndicatorPage, CheckPagePermissions } from 'strapi-helper-plugin'; import pluginPermissions from '../../permissions'; import { ContentTypeLayoutContext } from '../../contexts'; @@ -10,9 +12,12 @@ import EditSettingsView from '../EditSettingsView'; import ListView from '../ListView'; import ListSettingsView from '../ListSettingsView'; -const CollectionTypeRecursivePath = () => { - const { url } = useRouteMatch(); - const { slug } = useParams(); +const CollectionTypeRecursivePath = ({ + match: { + params: { slug }, + url, + }, +}) => { const { isLoading, layout, updateLayout } = useFetchContentTypeLayout(slug); const { rawContentTypeLayout, rawComponentsLayouts } = useMemo(() => { @@ -34,12 +39,37 @@ const CollectionTypeRecursivePath = () => { return { rawContentTypeLayout, rawComponentsLayouts }; }, [layout]); - if (isLoading) { + const uid = get(layout, ['contentType', 'uid'], null); + + // This statement is needed in order to prevent the CollectionTypeFormWrapper effects clean up phase to be run twice. + // What can happen is that when navigating from one entry to another the cleanup phase of the fetch data effect is run twice : once when + // unmounting, once when the url changes. + // Since it can happen that the layout there's a delay when the layout is being fetched and the url changes adding the uid ! == slug + // statement prevent the component from being mounted and unmounted twice. + if (uid !== slug || isLoading) { return ; } - const renderRoute = (_, Component) => { - return ; + const renderRoute = ( + { + location: { state }, + history: { goBack }, + match: { + params: { id, origin }, + }, + }, + Component + ) => { + return ( + + ); }; const routes = [ @@ -79,4 +109,13 @@ const CollectionTypeRecursivePath = () => { ); }; +CollectionTypeRecursivePath.propTypes = { + match: PropTypes.shape({ + url: PropTypes.string.isRequired, + params: PropTypes.shape({ + slug: PropTypes.string.isRequired, + }).isRequired, + }).isRequired, +}; + export default memo(CollectionTypeRecursivePath); 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 7fbc003c29..c713a3a4ff 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 @@ -1,7 +1,6 @@ import React, { memo, useCallback, useMemo } from 'react'; import PropTypes from 'prop-types'; import { get } from 'lodash'; -import { useHistory, useLocation } from 'react-router-dom'; import { BackHeader, LiLink, @@ -31,10 +30,8 @@ import DeleteLink from './DeleteLink'; import InformationCard from './InformationCard'; /* eslint-disable react/no-array-index-key */ -const EditView = ({ isSingleType, layout, slug }) => { - const { goBack } = useHistory(); +const EditView = ({ isSingleType, goBack, layout, slug, state, id, origin }) => { const { currentEnvironment, plugins } = useGlobalContext(); - const { state } = useLocation(); // Permissions const viewPermissions = useMemo(() => generatePermissionsObject(slug), [slug]); const { allowedActions, isLoading: isLoadingForPermissions } = useUserPermissions( @@ -59,7 +56,9 @@ const EditView = ({ isSingleType, layout, slug }) => { : pluginPermissions.collectionTypesConfigurations; }, [isSingleType]); - const configurationsURL = `/plugins/${pluginId}/collectionType/${slug}/configurations/edit`; + const configurationsURL = `/plugins/${pluginId}/${ + isSingleType ? 'singleType' : 'collectionType' + }/${slug}/configurations/edit`; const currentContentTypeLayoutData = useMemo(() => get(layout, ['contentType'], {}), [layout]); const DataManagementWrapper = useMemo( @@ -91,7 +90,7 @@ const EditView = ({ isSingleType, layout, slug }) => { // TODO: create a hook to handle/provide the permissions this should be done for the i18n feature return ( - + {({ componentsDataStructure, contentTypeDataStructure, @@ -264,7 +263,10 @@ const EditView = ({ isSingleType, layout, slug }) => { }; EditView.defaultProps = { + id: null, isSingleType: false, + origin: null, + state: {}, }; EditView.propTypes = { @@ -278,7 +280,11 @@ EditView.propTypes = { attributes: PropTypes.object.isRequired, }).isRequired, }).isRequired, + id: PropTypes.string, isSingleType: PropTypes.bool, + goBack: PropTypes.func.isRequired, + origin: PropTypes.string, + state: PropTypes.object, slug: PropTypes.string.isRequired, }; diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/SingleTypeRecursivePath/index.js b/packages/strapi-plugin-content-manager/admin/src/containers/SingleTypeRecursivePath/index.js index 6bdb20f24d..7fab28500b 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/SingleTypeRecursivePath/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/SingleTypeRecursivePath/index.js @@ -1,16 +1,40 @@ -import React from 'react'; -import { Switch, Route, useRouteMatch, useParams } from 'react-router-dom'; +import React, { memo, useMemo } from 'react'; +import { Switch, Route } from 'react-router-dom'; +import PropTypes from 'prop-types'; import { LoadingIndicatorPage, CheckPagePermissions } from 'strapi-helper-plugin'; import pluginPermissions from '../../permissions'; import { ContentTypeLayoutContext } from '../../contexts'; import { useFetchContentTypeLayout } from '../../hooks'; +import { formatLayoutToApi } from '../../utils'; import EditView from '../EditView'; import EditSettingsView from '../EditSettingsView'; -const SingleTypeRecursivePath = props => { - const { url } = useRouteMatch(); - const { slug } = useParams(); - const { isLoading, layout } = useFetchContentTypeLayout(slug); +const SingleTypeRecursivePath = ({ + match: { + params: { slug }, + url, + }, +}) => { + const { isLoading, layout, updateLayout } = useFetchContentTypeLayout(slug); + + const { rawContentTypeLayout, rawComponentsLayouts } = useMemo(() => { + let rawComponentsLayouts = {}; + let rawContentTypeLayout = {}; + + if (layout.contentType) { + rawContentTypeLayout = formatLayoutToApi(layout.contentType); + } + + if (layout.components) { + rawComponentsLayouts = Object.keys(layout.components).reduce((acc, current) => { + acc[current] = formatLayoutToApi(layout.components[current]); + + return acc; + }, {}); + } + + return { rawContentTypeLayout, rawComponentsLayouts }; + }, [layout]); if (isLoading) { return ; @@ -19,21 +43,36 @@ const SingleTypeRecursivePath = props => { return ( + + + + + ( - - - - )} - /> - } + path={url} + render={({ location: { state }, history: { goBack } }) => { + return ( + + ); + }} /> ); }; -export default SingleTypeRecursivePath; +SingleTypeRecursivePath.propTypes = { + match: PropTypes.shape({ + url: PropTypes.string.isRequired, + params: PropTypes.shape({ + slug: PropTypes.string.isRequired, + }).isRequired, + }).isRequired, +}; +export default memo(SingleTypeRecursivePath);