mirror of
https://github.com/strapi/strapi.git
synced 2025-08-15 20:27:23 +00:00
Add single type navigation
Signed-off-by: HichamELBSI <elabbassih@gmail.com>
This commit is contained in:
parent
79870fbd15
commit
f5c6ef0a44
@ -26,9 +26,15 @@ const LeftMenuLinksSection = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const getLinkDestination = link => {
|
const getLinkDestination = link => {
|
||||||
return ['plugins', 'general'].includes(section)
|
if (['plugins', 'general'].includes(section)) {
|
||||||
? link.destination
|
return link.destination;
|
||||||
: `/plugins/${link.plugin}/${link.destination || link.uid}`;
|
}
|
||||||
|
if (link.schema && link.schema.kind) {
|
||||||
|
return `/plugins/${link.plugin}/${link.schema.kind}/${link.destination ||
|
||||||
|
link.uid}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `/plugins/${link.plugin}/${link.destination || link.uid}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -3,14 +3,13 @@ import PropTypes from 'prop-types';
|
|||||||
import { withRouter } from 'react-router';
|
import { withRouter } from 'react-router';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { upperFirst } from 'lodash';
|
import { upperFirst } from 'lodash';
|
||||||
import pluginId from '../../pluginId';
|
|
||||||
import useListView from '../../hooks/useListView';
|
import useListView from '../../hooks/useListView';
|
||||||
import TableHeader from './TableHeader';
|
import TableHeader from './TableHeader';
|
||||||
import { Table, TableEmpty, TableRow } from './styledComponents';
|
import { Table, TableEmpty, TableRow } from './styledComponents';
|
||||||
import ActionCollapse from './ActionCollapse';
|
import ActionCollapse from './ActionCollapse';
|
||||||
import Row from './Row';
|
import Row from './Row';
|
||||||
|
|
||||||
function CustomTable({
|
const CustomTable = ({
|
||||||
data,
|
data,
|
||||||
headers,
|
headers,
|
||||||
history: {
|
history: {
|
||||||
@ -18,13 +17,12 @@ function CustomTable({
|
|||||||
push,
|
push,
|
||||||
},
|
},
|
||||||
isBulkable,
|
isBulkable,
|
||||||
}) {
|
}) => {
|
||||||
const {
|
const {
|
||||||
emitEvent,
|
emitEvent,
|
||||||
entriesToDelete,
|
entriesToDelete,
|
||||||
label,
|
label,
|
||||||
searchParams: { filters, _q },
|
searchParams: { filters, _q },
|
||||||
slug,
|
|
||||||
} = useListView();
|
} = useListView();
|
||||||
|
|
||||||
const redirectUrl = `redirectUrl=${pathname}${search}`;
|
const redirectUrl = `redirectUrl=${pathname}${search}`;
|
||||||
@ -33,7 +31,7 @@ function CustomTable({
|
|||||||
const handleGoTo = id => {
|
const handleGoTo = id => {
|
||||||
emitEvent('willEditEntryFromList');
|
emitEvent('willEditEntryFromList');
|
||||||
push({
|
push({
|
||||||
pathname: `/plugins/${pluginId}/${slug}/${id}`,
|
pathname: `${pathname}/${id}`,
|
||||||
search: redirectUrl,
|
search: redirectUrl,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -88,7 +86,7 @@ function CustomTable({
|
|||||||
</tbody>
|
</tbody>
|
||||||
</Table>
|
</Table>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
CustomTable.defaultProps = {
|
CustomTable.defaultProps = {
|
||||||
data: [],
|
data: [],
|
||||||
|
@ -7,7 +7,7 @@ const EditSettingsView = lazy(() => import('../EditSettingsView'));
|
|||||||
const ListView = lazy(() => import('../ListView'));
|
const ListView = lazy(() => import('../ListView'));
|
||||||
const ListSettingsView = lazy(() => import('../ListSettingsView'));
|
const ListSettingsView = lazy(() => import('../ListSettingsView'));
|
||||||
|
|
||||||
const RecursivePath = props => {
|
const CollectionTypeRecursivePath = props => {
|
||||||
const { url } = useRouteMatch();
|
const { url } = useRouteMatch();
|
||||||
const { slug } = useParams();
|
const { slug } = useParams();
|
||||||
|
|
||||||
@ -41,4 +41,4 @@ const RecursivePath = props => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default RecursivePath;
|
export default CollectionTypeRecursivePath;
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams, useLocation } from 'react-router-dom';
|
||||||
import { Header as PluginHeader } from '@buffetjs/custom';
|
import { Header as PluginHeader } from '@buffetjs/custom';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -20,6 +20,7 @@ const Header = () => {
|
|||||||
|
|
||||||
const { formatMessage, emitEvent } = useGlobalContext();
|
const { formatMessage, emitEvent } = useGlobalContext();
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
|
const { pathname } = useLocation();
|
||||||
const {
|
const {
|
||||||
deleteSuccess,
|
deleteSuccess,
|
||||||
initialData,
|
initialData,
|
||||||
@ -28,23 +29,28 @@ const Header = () => {
|
|||||||
resetData,
|
resetData,
|
||||||
setIsSubmitting,
|
setIsSubmitting,
|
||||||
slug,
|
slug,
|
||||||
|
clearData,
|
||||||
} = useDataManager();
|
} = useDataManager();
|
||||||
|
const isSingleType = pathname.split('/')[3] === 'singleType';
|
||||||
|
|
||||||
const currentContentTypeMainField = get(
|
const currentContentTypeMainField = get(
|
||||||
layout,
|
layout,
|
||||||
['settings', 'mainField'],
|
['settings', 'mainField'],
|
||||||
'id'
|
'id'
|
||||||
);
|
);
|
||||||
|
const currentContentTypeName = get(layout, ['schema', 'info', 'name']);
|
||||||
|
const apiId = layout.uid.split('.')[1];
|
||||||
const isCreatingEntry = id === 'create';
|
const isCreatingEntry = id === 'create';
|
||||||
|
|
||||||
/* eslint-disable indent */
|
/* eslint-disable indent */
|
||||||
const headerTitle = isCreatingEntry
|
const entryHeaderTitle = isCreatingEntry
|
||||||
? formatMessage({
|
? formatMessage({
|
||||||
id: `${pluginId}.containers.Edit.pluginHeader.title.new`,
|
id: `${pluginId}.containers.Edit.pluginHeader.title.new`,
|
||||||
})
|
})
|
||||||
: templateObject({ mainField: currentContentTypeMainField }, initialData)
|
: templateObject({ mainField: currentContentTypeMainField }, initialData)
|
||||||
.mainField;
|
.mainField;
|
||||||
/* eslint-enable indent */
|
/* eslint-enable indent */
|
||||||
|
const headerTitle = isSingleType ? currentContentTypeName : entryHeaderTitle;
|
||||||
|
|
||||||
const getHeaderActions = () => {
|
const getHeaderActions = () => {
|
||||||
const headerActions = [
|
const headerActions = [
|
||||||
@ -101,6 +107,9 @@ const Header = () => {
|
|||||||
title: {
|
title: {
|
||||||
label: headerTitle && headerTitle.toString(),
|
label: headerTitle && headerTitle.toString(),
|
||||||
},
|
},
|
||||||
|
content: isSingleType
|
||||||
|
? `${formatMessage({ id: `${pluginId}.api.id` })} : ${apiId}`
|
||||||
|
: '',
|
||||||
actions: getHeaderActions(),
|
actions: getHeaderActions(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -114,17 +123,21 @@ const Header = () => {
|
|||||||
const handleConfirmDelete = async () => {
|
const handleConfirmDelete = async () => {
|
||||||
toggleWarningDelete();
|
toggleWarningDelete();
|
||||||
setIsSubmitting();
|
setIsSubmitting();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
emitEvent('willDeleteEntry');
|
emitEvent('willDeleteEntry');
|
||||||
await request(getRequestUrl(`${slug}/${id}`), {
|
await request(getRequestUrl(`${slug}/${initialData.id}`), {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
});
|
});
|
||||||
|
|
||||||
strapi.notification.success(`${pluginId}.success.record.delete`);
|
strapi.notification.success(`${pluginId}.success.record.delete`);
|
||||||
deleteSuccess();
|
deleteSuccess();
|
||||||
emitEvent('didDeleteEntry');
|
emitEvent('didDeleteEntry');
|
||||||
redirectToPreviousPage();
|
|
||||||
|
if (!isSingleType) {
|
||||||
|
redirectToPreviousPage();
|
||||||
|
} else {
|
||||||
|
clearData();
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setIsSubmitting(false);
|
setIsSubmitting(false);
|
||||||
emitEvent('didNotDeleteEntry', { error: err });
|
emitEvent('didNotDeleteEntry', { error: err });
|
||||||
|
@ -39,8 +39,8 @@ const EditView = ({
|
|||||||
formatLayoutRef.current = createAttributesLayout;
|
formatLayoutRef.current = createAttributesLayout;
|
||||||
// Retrieve push to programmatically navigate between views
|
// Retrieve push to programmatically navigate between views
|
||||||
const { push } = useHistory();
|
const { push } = useHistory();
|
||||||
// Retrieve the search
|
// Retrieve the search and the location
|
||||||
const { search } = useLocation();
|
const { search, pathname } = useLocation();
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
const [reducerState, dispatch] = useReducer(reducer, initialState, () =>
|
const [reducerState, dispatch] = useReducer(reducer, initialState, () =>
|
||||||
init(initialState)
|
init(initialState)
|
||||||
@ -129,6 +129,7 @@ const EditView = ({
|
|||||||
.filter((_, index) => index !== 0)
|
.filter((_, index) => index !== 0)
|
||||||
.join('');
|
.join('');
|
||||||
const redirectToPreviousPage = () => push(redirectURL);
|
const redirectToPreviousPage = () => push(redirectURL);
|
||||||
|
const isSingleType = pathname.includes('singleType');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EditViewProvider
|
<EditViewProvider
|
||||||
@ -152,7 +153,7 @@ const EditView = ({
|
|||||||
redirectToPreviousPage={redirectToPreviousPage}
|
redirectToPreviousPage={redirectToPreviousPage}
|
||||||
slug={slug}
|
slug={slug}
|
||||||
>
|
>
|
||||||
<BackHeader onClick={() => redirectToPreviousPage()} />
|
<BackHeader onClick={redirectToPreviousPage} />
|
||||||
<Container className="container-fluid">
|
<Container className="container-fluid">
|
||||||
<Header />
|
<Header />
|
||||||
<div className="row" style={{ paddingTop: 3 }}>
|
<div className="row" style={{ paddingTop: 3 }}>
|
||||||
@ -276,7 +277,9 @@ const EditView = ({
|
|||||||
}}
|
}}
|
||||||
icon="layout"
|
icon="layout"
|
||||||
key={`${pluginId}.link`}
|
key={`${pluginId}.link`}
|
||||||
url="ctm-configurations/edit-settings/content-types"
|
url={`${
|
||||||
|
isSingleType ? `${pathname}/` : ''
|
||||||
|
}ctm-configurations/edit-settings/content-types`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
// emitEvent('willEditContentTypeLayoutFromEditView');
|
// emitEvent('willEditContentTypeLayoutFromEditView');
|
||||||
}}
|
}}
|
||||||
|
@ -1,21 +1,23 @@
|
|||||||
import React, { useEffect, useReducer } from 'react';
|
|
||||||
import { Prompt, useParams } from 'react-router-dom';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { cloneDeep, get, isEmpty, isEqual, set } from 'lodash';
|
import { cloneDeep, get, isEmpty, isEqual, set } from 'lodash';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React, { useEffect, useReducer, useState } from 'react';
|
||||||
|
import { Prompt, useParams, useLocation } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
request,
|
|
||||||
LoadingIndicatorPage,
|
LoadingIndicatorPage,
|
||||||
|
request,
|
||||||
useGlobalContext,
|
useGlobalContext,
|
||||||
} from 'strapi-helper-plugin';
|
} from 'strapi-helper-plugin';
|
||||||
import pluginId from '../../pluginId';
|
|
||||||
import EditViewDataManagerContext from '../../contexts/EditViewDataManager';
|
import EditViewDataManagerContext from '../../contexts/EditViewDataManager';
|
||||||
import createYupSchema from './utils/schema';
|
import pluginId from '../../pluginId';
|
||||||
import createDefaultForm from './utils/createDefaultForm';
|
|
||||||
import getFilesToUpload from './utils/getFilesToUpload';
|
|
||||||
import cleanData from './utils/cleanData';
|
|
||||||
import getYupInnerErrors from './utils/getYupInnerErrors';
|
|
||||||
import init from './init';
|
import init from './init';
|
||||||
import reducer, { initialState } from './reducer';
|
import reducer, { initialState } from './reducer';
|
||||||
|
import {
|
||||||
|
createYupSchema,
|
||||||
|
getYupInnerErrors,
|
||||||
|
getFilesToUpload,
|
||||||
|
createDefaultForm,
|
||||||
|
cleanData,
|
||||||
|
} from './utils';
|
||||||
|
|
||||||
const getRequestUrl = path => `/${pluginId}/explorer/${path}`;
|
const getRequestUrl = path => `/${pluginId}/explorer/${path}`;
|
||||||
|
|
||||||
@ -26,6 +28,7 @@ const EditViewDataManagerProvider = ({
|
|||||||
slug,
|
slug,
|
||||||
}) => {
|
}) => {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
|
const { pathname } = useLocation();
|
||||||
// Retrieve the search
|
// Retrieve the search
|
||||||
const [reducerState, dispatch] = useReducer(reducer, initialState, init);
|
const [reducerState, dispatch] = useReducer(reducer, initialState, init);
|
||||||
const {
|
const {
|
||||||
@ -37,13 +40,12 @@ const EditViewDataManagerProvider = ({
|
|||||||
shouldShowLoadingState,
|
shouldShowLoadingState,
|
||||||
shouldCheckErrors,
|
shouldCheckErrors,
|
||||||
} = reducerState.toJS();
|
} = reducerState.toJS();
|
||||||
|
const [isCreatingEntry, setIsCreatingEntry] = useState(id === 'create');
|
||||||
const currentContentTypeLayout = get(allLayoutData, ['contentType'], {});
|
const currentContentTypeLayout = get(allLayoutData, ['contentType'], {});
|
||||||
const abortController = new AbortController();
|
const abortController = new AbortController();
|
||||||
const { signal } = abortController;
|
const { signal } = abortController;
|
||||||
const isCreatingEntry = id === 'create';
|
|
||||||
|
|
||||||
const { emitEvent, formatMessage } = useGlobalContext();
|
const { emitEvent, formatMessage } = useGlobalContext();
|
||||||
|
const isSingleType = pathname.split('/')[3] === 'singleType';
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isLoading) {
|
if (!isLoading) {
|
||||||
@ -55,7 +57,7 @@ const EditViewDataManagerProvider = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
try {
|
try {
|
||||||
const data = await request(getRequestUrl(`${slug}/${id}`), {
|
const data = await request(getRequestUrl(`${slug}/${id || ''}`), {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
signal,
|
signal,
|
||||||
});
|
});
|
||||||
@ -65,9 +67,12 @@ const EditViewDataManagerProvider = ({
|
|||||||
data,
|
data,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.code !== 20) {
|
if (id && err.code !== 20) {
|
||||||
strapi.notification.error(`${pluginId}.error.record.fetch`);
|
strapi.notification.error(`${pluginId}.error.record.fetch`);
|
||||||
}
|
}
|
||||||
|
if (!id && err.response.status === 404) {
|
||||||
|
setIsCreatingEntry(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -108,7 +113,7 @@ const EditViewDataManagerProvider = ({
|
|||||||
abortController.abort();
|
abortController.abort();
|
||||||
};
|
};
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [id, slug]);
|
}, [id, slug, isCreatingEntry]);
|
||||||
|
|
||||||
const addComponentToDynamicZone = (
|
const addComponentToDynamicZone = (
|
||||||
keys,
|
keys,
|
||||||
@ -246,7 +251,15 @@ const EditViewDataManagerProvider = ({
|
|||||||
// Change the request helper default headers so we can pass a FormData
|
// Change the request helper default headers so we can pass a FormData
|
||||||
const headers = {};
|
const headers = {};
|
||||||
const method = isCreatingEntry ? 'POST' : 'PUT';
|
const method = isCreatingEntry ? 'POST' : 'PUT';
|
||||||
const endPoint = isCreatingEntry ? slug : `${slug}/${id}`;
|
let endPoint;
|
||||||
|
|
||||||
|
if (isCreatingEntry) {
|
||||||
|
endPoint = slug;
|
||||||
|
} else if (modifiedData) {
|
||||||
|
endPoint = `${slug}/${modifiedData.id}`;
|
||||||
|
} else {
|
||||||
|
endPoint = `${slug}/${id}`;
|
||||||
|
}
|
||||||
|
|
||||||
emitEvent(isCreatingEntry ? 'willCreateEntry' : 'willEditEntry');
|
emitEvent(isCreatingEntry ? 'willCreateEntry' : 'willEditEntry');
|
||||||
|
|
||||||
@ -267,7 +280,13 @@ const EditViewDataManagerProvider = ({
|
|||||||
dispatch({
|
dispatch({
|
||||||
type: 'SUBMIT_SUCCESS',
|
type: 'SUBMIT_SUCCESS',
|
||||||
});
|
});
|
||||||
redirectToPreviousPage();
|
strapi.notification.success(`${pluginId}.success.record.save`);
|
||||||
|
|
||||||
|
if (isSingleType) {
|
||||||
|
setIsCreatingEntry(false);
|
||||||
|
} else {
|
||||||
|
redirectToPreviousPage();
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error({ err });
|
console.error({ err });
|
||||||
const error = get(
|
const error = get(
|
||||||
@ -375,6 +394,31 @@ const EditViewDataManagerProvider = ({
|
|||||||
dispatch({ type: 'IS_SUBMITTING', value });
|
dispatch({ type: 'IS_SUBMITTING', value });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const deleteSuccess = () => {
|
||||||
|
dispatch({
|
||||||
|
type: 'DELETE_SUCCEEDED',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetData = () => {
|
||||||
|
dispatch({
|
||||||
|
type: 'RESET_DATA',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearData = () => {
|
||||||
|
dispatch({
|
||||||
|
type: 'SET_DEFAULT_MODIFIED_DATA_STRUCTURE',
|
||||||
|
contentTypeDataStructure: {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const triggerFormValidation = () => {
|
||||||
|
dispatch({
|
||||||
|
type: 'TRIGGER_FORM_VALIDATION',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const showLoader = !isCreatingEntry && isLoading;
|
const showLoader = !isCreatingEntry && isLoading;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -386,11 +430,8 @@ const EditViewDataManagerProvider = ({
|
|||||||
addRepeatableComponentToField,
|
addRepeatableComponentToField,
|
||||||
allLayoutData,
|
allLayoutData,
|
||||||
checkFormErrors,
|
checkFormErrors,
|
||||||
deleteSuccess: () => {
|
clearData,
|
||||||
dispatch({
|
deleteSuccess,
|
||||||
type: 'DELETE_SUCCEEDED',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
formErrors,
|
formErrors,
|
||||||
initialData,
|
initialData,
|
||||||
layout: currentContentTypeLayout,
|
layout: currentContentTypeLayout,
|
||||||
@ -405,19 +446,11 @@ const EditViewDataManagerProvider = ({
|
|||||||
removeComponentFromDynamicZone,
|
removeComponentFromDynamicZone,
|
||||||
removeComponentFromField,
|
removeComponentFromField,
|
||||||
removeRepeatableField,
|
removeRepeatableField,
|
||||||
resetData: () => {
|
resetData,
|
||||||
dispatch({
|
|
||||||
type: 'RESET_DATA',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
setIsSubmitting,
|
setIsSubmitting,
|
||||||
shouldShowLoadingState,
|
shouldShowLoadingState,
|
||||||
slug,
|
slug,
|
||||||
triggerFormValidation: () => {
|
triggerFormValidation,
|
||||||
dispatch({
|
|
||||||
type: 'TRIGGER_FORM_VALIDATION',
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{showLoader ? (
|
{showLoader ? (
|
||||||
|
@ -232,7 +232,9 @@ const reducer = (state, action) => {
|
|||||||
.update('shouldShowLoadingState', () => false);
|
.update('shouldShowLoadingState', () => false);
|
||||||
case 'SUBMIT_SUCCESS':
|
case 'SUBMIT_SUCCESS':
|
||||||
case 'DELETE_SUCCEEDED':
|
case 'DELETE_SUCCEEDED':
|
||||||
return state.update('initialData', () => state.get('modifiedData'));
|
return state
|
||||||
|
.update('isLoading', () => false)
|
||||||
|
.update('initialData', () => state.get('modifiedData'));
|
||||||
case 'TRIGGER_FORM_VALIDATION':
|
case 'TRIGGER_FORM_VALIDATION':
|
||||||
return state.update('shouldCheckErrors', v => {
|
return state.update('shouldCheckErrors', v => {
|
||||||
const hasErrors = state.get('formErrors').keySeq().size > 0;
|
const hasErrors = state.get('formErrors').keySeq().size > 0;
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
export { default as cleanData } from './cleanData';
|
||||||
|
export { default as createDefaultForm } from './createDefaultForm';
|
||||||
|
export { default as getFilesToUpload } from './getFilesToUpload';
|
||||||
|
export { default as getYupInnerErrors } from './getYupInnerErrors';
|
||||||
|
export { default as createYupSchema } from './schema';
|
@ -23,12 +23,18 @@ const Initializer = ({ updatePlugin }) => {
|
|||||||
try {
|
try {
|
||||||
const { data } = await request(requestURL, { method: 'GET' });
|
const { data } = await request(requestURL, { method: 'GET' });
|
||||||
|
|
||||||
|
// Two thinks to know here:
|
||||||
|
// First, we group content types by schema.kind to get an object with two separated content types (singleTypes, collectionTypes)
|
||||||
|
// Then, we sort by name to keep collection types at the first position everytime.
|
||||||
|
// As all content types are sort by name, if a single type name start with abc, the single types section will be at the first position.
|
||||||
|
// However, we want to keep collection types at the first position in the admin menu
|
||||||
ref.current(
|
ref.current(
|
||||||
pluginId,
|
pluginId,
|
||||||
'leftMenuSections',
|
'leftMenuSections',
|
||||||
chain(data)
|
chain(data)
|
||||||
.groupBy('schema.kind')
|
.groupBy('schema.kind')
|
||||||
.map((value, key) => ({ name: key, links: value }))
|
.map((value, key) => ({ name: key, links: value }))
|
||||||
|
.sortBy('name')
|
||||||
.value()
|
.value()
|
||||||
);
|
);
|
||||||
ref.current(pluginId, 'isReady', true);
|
ref.current(pluginId, 'isReady', true);
|
||||||
|
@ -25,7 +25,12 @@ import reducer from './reducer';
|
|||||||
import makeSelectMain from './selectors';
|
import makeSelectMain from './selectors';
|
||||||
|
|
||||||
const EditSettingsView = lazy(() => import('../EditSettingsView'));
|
const EditSettingsView = lazy(() => import('../EditSettingsView'));
|
||||||
const RecursivePath = lazy(() => import('../RecursivePath'));
|
const CollectionTypeRecursivePath = lazy(() =>
|
||||||
|
import('../CollectionTypeRecursivePath')
|
||||||
|
);
|
||||||
|
const SingleTypeRecursivePath = lazy(() =>
|
||||||
|
import('../SingleTypeRecursivePath')
|
||||||
|
);
|
||||||
|
|
||||||
function Main({
|
function Main({
|
||||||
deleteLayout,
|
deleteLayout,
|
||||||
@ -45,7 +50,7 @@ function Main({
|
|||||||
strapi.useInjectReducer({ key: 'main', reducer, pluginId });
|
strapi.useInjectReducer({ key: 'main', reducer, pluginId });
|
||||||
|
|
||||||
const { emitEvent } = useGlobalContext();
|
const { emitEvent } = useGlobalContext();
|
||||||
const slug = pathname.split('/')[3];
|
const slug = pathname.split('/')[4];
|
||||||
const getDataRef = useRef();
|
const getDataRef = useRef();
|
||||||
const getLayoutRef = useRef();
|
const getLayoutRef = useRef();
|
||||||
const resetPropsRef = useRef();
|
const resetPropsRef = useRef();
|
||||||
@ -123,7 +128,8 @@ function Main({
|
|||||||
path: 'ctm-configurations/edit-settings/:type/:componentSlug',
|
path: 'ctm-configurations/edit-settings/:type/:componentSlug',
|
||||||
comp: EditSettingsView,
|
comp: EditSettingsView,
|
||||||
},
|
},
|
||||||
{ path: ':slug', comp: RecursivePath },
|
{ path: 'singleType/:slug', comp: SingleTypeRecursivePath },
|
||||||
|
{ path: 'collectionType/:slug', comp: CollectionTypeRecursivePath },
|
||||||
].map(({ path, comp }) => (
|
].map(({ path, comp }) => (
|
||||||
<Route
|
<Route
|
||||||
key={path}
|
key={path}
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
import React, { Suspense, lazy } from 'react';
|
||||||
|
import { Switch, Route, useRouteMatch, useParams } from 'react-router-dom';
|
||||||
|
import { LoadingIndicatorPage } from 'strapi-helper-plugin';
|
||||||
|
|
||||||
|
const EditView = lazy(() => import('../EditView'));
|
||||||
|
const EditSettingsView = lazy(() => import('../EditSettingsView'));
|
||||||
|
|
||||||
|
const SingleTypeRecursivePath = props => {
|
||||||
|
const { url } = useRouteMatch();
|
||||||
|
const { slug } = useParams();
|
||||||
|
|
||||||
|
const renderRoute = (routeProps, Component) => {
|
||||||
|
return <Component {...props} {...routeProps} slug={slug} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const routes = [
|
||||||
|
{
|
||||||
|
path: 'ctm-configurations/edit-settings/:type',
|
||||||
|
comp: EditSettingsView,
|
||||||
|
},
|
||||||
|
{ path: '', comp: EditView },
|
||||||
|
].map(({ path, comp }) => (
|
||||||
|
<Route
|
||||||
|
key={path}
|
||||||
|
path={`${url}/${path}`}
|
||||||
|
render={props => renderRoute(props, comp)}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Suspense fallback={<LoadingIndicatorPage />}>
|
||||||
|
<Switch>{routes}</Switch>
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SingleTypeRecursivePath;
|
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"api.id": "API ID",
|
||||||
"models": "Collection Types",
|
"models": "Collection Types",
|
||||||
"models.numbered": "Collection Types ({number})",
|
"models.numbered": "Collection Types ({number})",
|
||||||
"groups": "Groups",
|
"groups": "Groups",
|
||||||
|
@ -482,6 +482,7 @@ const DataManagerProvider = ({ allIcons, children }) => {
|
|||||||
chain(data)
|
chain(data)
|
||||||
.groupBy('schema.kind')
|
.groupBy('schema.kind')
|
||||||
.map((value, key) => ({ name: key, links: value }))
|
.map((value, key) => ({ name: key, links: value }))
|
||||||
|
.sortBy('name')
|
||||||
.value()
|
.value()
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -88,7 +88,7 @@ const FormModal = () => {
|
|||||||
const dynamicZoneTarget = query.get('dynamicZoneTarget');
|
const dynamicZoneTarget = query.get('dynamicZoneTarget');
|
||||||
const forTarget = query.get('forTarget');
|
const forTarget = query.get('forTarget');
|
||||||
const modalType = query.get('modalType');
|
const modalType = query.get('modalType');
|
||||||
const contentTypeKind = query.get('kind');
|
const kind = query.get('kind');
|
||||||
const targetUid = query.get('targetUid');
|
const targetUid = query.get('targetUid');
|
||||||
const settingType = query.get('settingType');
|
const settingType = query.get('settingType');
|
||||||
const headerId = query.get('headerId');
|
const headerId = query.get('headerId');
|
||||||
@ -127,7 +127,7 @@ const FormModal = () => {
|
|||||||
actionType,
|
actionType,
|
||||||
attributeName,
|
attributeName,
|
||||||
attributeType,
|
attributeType,
|
||||||
contentTypeKind,
|
kind,
|
||||||
dynamicZoneTarget,
|
dynamicZoneTarget,
|
||||||
forTarget,
|
forTarget,
|
||||||
modalType,
|
modalType,
|
||||||
@ -626,7 +626,7 @@ const FormModal = () => {
|
|||||||
// Create the content type schema
|
// Create the content type schema
|
||||||
if (isCreating) {
|
if (isCreating) {
|
||||||
createSchema(
|
createSchema(
|
||||||
{ ...modifiedData, kind: state.contentTypeKind },
|
{ ...modifiedData, kind: state.kind },
|
||||||
state.modalType,
|
state.modalType,
|
||||||
uid
|
uid
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user