mirror of
https://github.com/strapi/strapi.git
synced 2026-01-07 20:58:16 +00:00
Merge pull request #10990 from strapi/cm/body-layout
CM init body layout
This commit is contained in:
commit
942cdf8fc9
@ -3,6 +3,7 @@ import { cloneDeep, get, isEmpty, isEqual, set } from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { Prompt, Redirect } from 'react-router-dom';
|
||||
import { Main } from '@strapi/parts/Main';
|
||||
import {
|
||||
LoadingIndicatorPage,
|
||||
ContentManagerEditViewDataManagerContext,
|
||||
@ -426,14 +427,6 @@ const EditViewDataManagerProvider = ({
|
||||
});
|
||||
}, []);
|
||||
|
||||
// const overlayBlockerParams = useMemo(
|
||||
// () => ({
|
||||
// children: <div />,
|
||||
// noGradient: true,
|
||||
// }),
|
||||
// []
|
||||
// );
|
||||
|
||||
// Redirect the user to the previous page if he is not allowed to read/update a document
|
||||
if (shouldRedirectToHomepageWhenEditingEntry) {
|
||||
return <Redirect to={from} />;
|
||||
@ -477,13 +470,10 @@ const EditViewDataManagerProvider = ({
|
||||
}}
|
||||
>
|
||||
<>
|
||||
{/* <OverlayBlocker
|
||||
key="overlayBlocker"
|
||||
isOpen={status !== 'resolved'}
|
||||
{...overlayBlockerParams}
|
||||
/> */}
|
||||
{isLoadingForData ? (
|
||||
<LoadingIndicatorPage />
|
||||
<Main aria-busy="true">
|
||||
<LoadingIndicatorPage />
|
||||
</Main>
|
||||
) : (
|
||||
<>
|
||||
<Prompt
|
||||
@ -506,7 +496,7 @@ EditViewDataManagerProvider.defaultProps = {
|
||||
EditViewDataManagerProvider.propTypes = {
|
||||
allLayoutData: PropTypes.object.isRequired,
|
||||
allowedActions: PropTypes.object.isRequired,
|
||||
children: PropTypes.arrayOf(PropTypes.element).isRequired,
|
||||
children: PropTypes.node.isRequired,
|
||||
componentsDataStructure: PropTypes.object.isRequired,
|
||||
contentTypeDataStructure: PropTypes.object.isRequired,
|
||||
createActionAllowedFields: PropTypes.array.isRequired,
|
||||
|
||||
@ -0,0 +1,84 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useIntl } from 'react-intl';
|
||||
import styled from 'styled-components';
|
||||
import { Box } from '@strapi/parts/Box';
|
||||
import { Row } from '@strapi/parts/Row';
|
||||
import { Text } from '@strapi/parts/Text';
|
||||
import Bullet from '@strapi/icons/Bullet';
|
||||
import { pxToRem } from '@strapi/helper-plugin';
|
||||
import { getTrad } from '../../../utils';
|
||||
import { connect, select } from './utils';
|
||||
|
||||
const CustomBullet = styled(Bullet)`
|
||||
width: ${pxToRem(6)};
|
||||
height: ${pxToRem(6)};
|
||||
* {
|
||||
fill: ${({ theme, $bulletColor }) => theme.colors[$bulletColor]};
|
||||
}
|
||||
`;
|
||||
|
||||
const DraftAndPublishBadge = ({ hasDraftAndPublish, isPublished }) => {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
if (!hasDraftAndPublish) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const colors = {
|
||||
draft: {
|
||||
textColor: 'secondary700',
|
||||
bulletColor: 'secondary600',
|
||||
box: {
|
||||
background: 'secondary100',
|
||||
borderColor: 'secondary200',
|
||||
},
|
||||
},
|
||||
published: {
|
||||
textColor: 'success700',
|
||||
bullet: 'success600',
|
||||
box: {
|
||||
background: 'success100',
|
||||
borderColor: 'success200',
|
||||
},
|
||||
},
|
||||
};
|
||||
const colorProps = isPublished ? colors.published : colors.draft;
|
||||
|
||||
return (
|
||||
<Box hasRadius as="aside" paddingTop={4} paddingBottom={4} paddingLeft={5} {...colorProps.box}>
|
||||
<Box as={Row}>
|
||||
<CustomBullet $bulletColor={colorProps.bulletColor} />
|
||||
<Box paddingLeft={3}>
|
||||
<Text textColor={colorProps.textColor}>
|
||||
{formatMessage({
|
||||
id: getTrad('containers.Edit.information.editing'),
|
||||
defaultMessage: 'Editing',
|
||||
})}
|
||||
|
||||
</Text>
|
||||
<Text textColor={colorProps.textColor} bold>
|
||||
{isPublished &&
|
||||
formatMessage({
|
||||
id: getTrad('containers.Edit.information.publishedVersion'),
|
||||
defaultMessage: 'published version',
|
||||
})}
|
||||
{!isPublished &&
|
||||
formatMessage({
|
||||
id: getTrad('containers.Edit.information.draftVersion'),
|
||||
defaultMessage: 'draft version',
|
||||
})}
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
DraftAndPublishBadge.propTypes = {
|
||||
hasDraftAndPublish: PropTypes.bool.isRequired,
|
||||
isPublished: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default connect(DraftAndPublishBadge, select);
|
||||
export { DraftAndPublishBadge };
|
||||
@ -0,0 +1,225 @@
|
||||
/**
|
||||
*
|
||||
* Tests for DraftAndPublishBadge
|
||||
*
|
||||
*/
|
||||
|
||||
/* eslint-disable no-irregular-whitespace */
|
||||
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { ThemeProvider, lightTheme } from '@strapi/parts';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
import { DraftAndPublishBadge } from '../index';
|
||||
|
||||
const makeApp = props => (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<IntlProvider locale="en" messages={{}} defaultLocale="en">
|
||||
<DraftAndPublishBadge {...props} />
|
||||
</IntlProvider>
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
describe('<DraftAndPublishBadge />', () => {
|
||||
it('renders and matches the snapshot', () => {
|
||||
const App = makeApp({ hasDraftAndPublish: true, isPublished: true });
|
||||
|
||||
const {
|
||||
container: { firstChild },
|
||||
} = render(App);
|
||||
|
||||
expect(firstChild).toMatchInlineSnapshot(`
|
||||
.c0 {
|
||||
background: #eafbe7;
|
||||
padding-top: 16px;
|
||||
padding-bottom: 16px;
|
||||
padding-left: 20px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #c6f0c2;
|
||||
}
|
||||
|
||||
.c3 {
|
||||
padding-left: 12px;
|
||||
}
|
||||
|
||||
.c1 {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: row;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-webkit-align-items: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.c4 {
|
||||
font-weight: 400;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.43;
|
||||
color: #2f6846;
|
||||
}
|
||||
|
||||
.c5 {
|
||||
font-weight: 500;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.43;
|
||||
color: #2f6846;
|
||||
}
|
||||
|
||||
.c2 {
|
||||
width: 0.375rem;
|
||||
height: 0.375rem;
|
||||
}
|
||||
|
||||
<aside
|
||||
class="c0"
|
||||
>
|
||||
<div
|
||||
class="c1 "
|
||||
>
|
||||
<svg
|
||||
class="c2"
|
||||
fill="none"
|
||||
height="1em"
|
||||
viewBox="0 0 4 4"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect
|
||||
fill="#A5A5BA"
|
||||
height="4"
|
||||
rx="2"
|
||||
width="4"
|
||||
/>
|
||||
</svg>
|
||||
<div
|
||||
class="c3"
|
||||
>
|
||||
<span
|
||||
class="c4"
|
||||
>
|
||||
Editing
|
||||
|
||||
</span>
|
||||
<span
|
||||
class="c5"
|
||||
>
|
||||
published version
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
`);
|
||||
});
|
||||
|
||||
it('should show the draft design when it is not published', () => {
|
||||
const App = makeApp({ hasDraftAndPublish: true, isPublished: false });
|
||||
|
||||
const {
|
||||
container: { firstChild },
|
||||
} = render(App);
|
||||
|
||||
expect(firstChild).toMatchInlineSnapshot(`
|
||||
.c0 {
|
||||
background: #eaf5ff;
|
||||
padding-top: 16px;
|
||||
padding-bottom: 16px;
|
||||
padding-left: 20px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #b8e1ff;
|
||||
}
|
||||
|
||||
.c3 {
|
||||
padding-left: 12px;
|
||||
}
|
||||
|
||||
.c1 {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: row;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-webkit-align-items: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.c4 {
|
||||
font-weight: 400;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.43;
|
||||
color: #006096;
|
||||
}
|
||||
|
||||
.c5 {
|
||||
font-weight: 500;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.43;
|
||||
color: #006096;
|
||||
}
|
||||
|
||||
.c2 {
|
||||
width: 0.375rem;
|
||||
height: 0.375rem;
|
||||
}
|
||||
|
||||
.c2 * {
|
||||
fill: #0c75af;
|
||||
}
|
||||
|
||||
<aside
|
||||
class="c0"
|
||||
>
|
||||
<div
|
||||
class="c1 "
|
||||
>
|
||||
<svg
|
||||
class="c2"
|
||||
fill="none"
|
||||
height="1em"
|
||||
viewBox="0 0 4 4"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect
|
||||
fill="#A5A5BA"
|
||||
height="4"
|
||||
rx="2"
|
||||
width="4"
|
||||
/>
|
||||
</svg>
|
||||
<div
|
||||
class="c3"
|
||||
>
|
||||
<span
|
||||
class="c4"
|
||||
>
|
||||
Editing
|
||||
|
||||
</span>
|
||||
<span
|
||||
class="c5"
|
||||
>
|
||||
draft version
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
`);
|
||||
});
|
||||
|
||||
it('should show return null when hasDraftAndPublish is falsy', () => {
|
||||
const App = makeApp({ hasDraftAndPublish: false, isPublished: false });
|
||||
|
||||
const { queryByText } = render(App);
|
||||
|
||||
expect(queryByText('Editing')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
|
||||
function connect(WrappedComponent, select) {
|
||||
return function(props) {
|
||||
// eslint-disable-next-line react/prop-types
|
||||
const selectors = select();
|
||||
|
||||
return <WrappedComponent {...props} {...selectors} />;
|
||||
};
|
||||
}
|
||||
|
||||
export default connect;
|
||||
@ -0,0 +1,2 @@
|
||||
export { default as connect } from './connect';
|
||||
export { default as select } from './select';
|
||||
@ -0,0 +1,14 @@
|
||||
import { useContentManagerEditViewDataManager } from '@strapi/helper-plugin';
|
||||
|
||||
function useSelect() {
|
||||
const { initialData, hasDraftAndPublish } = useContentManagerEditViewDataManager();
|
||||
|
||||
const isPublished = initialData.published_at !== undefined && initialData.published_at !== null;
|
||||
|
||||
return {
|
||||
hasDraftAndPublish,
|
||||
isPublished,
|
||||
};
|
||||
}
|
||||
|
||||
export default useSelect;
|
||||
@ -1,23 +1,25 @@
|
||||
import React, { memo, useCallback, useMemo, useRef, useState } from 'react';
|
||||
import React, { memo, useRef, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { Header as PluginHeader } from '@buffetjs/custom';
|
||||
import { get, isEqual, isEmpty, toString } from 'lodash';
|
||||
import { useHistory } from 'react-router';
|
||||
import get from 'lodash/get';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import BackIcon from '@strapi/icons/BackIcon';
|
||||
import { HeaderLayout } from '@strapi/parts/Layout';
|
||||
import { Box } from '@strapi/parts/Box';
|
||||
import { Button } from '@strapi/parts/Button';
|
||||
import { Dialog, DialogBody, DialogFooter } from '@strapi/parts/Dialog';
|
||||
import { Link } from '@strapi/parts/Link';
|
||||
import { Row } from '@strapi/parts/Row';
|
||||
import { Text } from '@strapi/parts/Text';
|
||||
import { Stack } from '@strapi/parts/Stack';
|
||||
import AlertWarningIcon from '@strapi/icons/AlertWarningIcon';
|
||||
import CheckIcon from '@strapi/icons/CheckIcon';
|
||||
import PropTypes from 'prop-types';
|
||||
import isEqualFastCompare from 'react-fast-compare';
|
||||
import { Text } from '@buffetjs/core';
|
||||
import { templateObject, ModalConfirm } from '@strapi/helper-plugin';
|
||||
import { getTrad } from '../../../utils';
|
||||
import { connect, getDraftRelations, select } from './utils';
|
||||
|
||||
const primaryButtonObject = {
|
||||
color: 'primary',
|
||||
type: 'button',
|
||||
style: {
|
||||
minWidth: 150,
|
||||
fontWeight: 600,
|
||||
},
|
||||
};
|
||||
|
||||
const Header = ({
|
||||
allowedActions: { canUpdate, canCreate, canPublish },
|
||||
componentLayouts,
|
||||
@ -31,205 +33,255 @@ const Header = ({
|
||||
onUnpublish,
|
||||
status,
|
||||
}) => {
|
||||
const { goBack } = useHistory();
|
||||
const [showWarningUnpublish, setWarningUnpublish] = useState(false);
|
||||
const { formatMessage } = useIntl();
|
||||
const formatMessageRef = useRef(formatMessage);
|
||||
const [draftRelationsCount, setDraftRelationsCount] = useState(0);
|
||||
const [showWarningDraftRelation, setShowWarningDraftRelation] = useState(false);
|
||||
const [shouldUnpublish, setShouldUnpublish] = useState(false);
|
||||
const [shouldPublish, setShouldPublish] = useState(false);
|
||||
const { formatMessage } = useIntl();
|
||||
const draftRelationsCountRef = useRef(0);
|
||||
|
||||
const currentContentTypeMainField = useMemo(() => get(layout, ['settings', 'mainField'], 'id'), [
|
||||
layout,
|
||||
]);
|
||||
const currentContentTypeMainField = get(layout, ['settings', 'mainField'], 'id');
|
||||
const currentContentTypeName = get(layout, ['info', 'displayName'], 'NOT FOUND');
|
||||
const didChangeData =
|
||||
!isEqual(initialData, modifiedData) || (isCreatingEntry && !isEmpty(modifiedData));
|
||||
|
||||
const currentContentTypeName = useMemo(() => get(layout, ['info', 'name']), [layout]);
|
||||
const createEntryIntlTitle = formatMessage({
|
||||
id: getTrad('containers.Edit.pluginHeader.title.new'),
|
||||
defaultMessage: 'Create an entry',
|
||||
});
|
||||
|
||||
const didChangeData = useMemo(() => {
|
||||
return !isEqual(initialData, modifiedData) || (isCreatingEntry && !isEmpty(modifiedData));
|
||||
}, [initialData, isCreatingEntry, modifiedData]);
|
||||
const apiID = useMemo(() => layout.apiID, [layout.apiID]);
|
||||
let title = createEntryIntlTitle;
|
||||
|
||||
/* eslint-disable indent */
|
||||
const entryHeaderTitle = isCreatingEntry
|
||||
? formatMessage({
|
||||
id: getTrad('containers.Edit.pluginHeader.title.new'),
|
||||
})
|
||||
: templateObject({ mainField: currentContentTypeMainField }, initialData).mainField;
|
||||
/* eslint-enable indent */
|
||||
if (!isCreatingEntry && !isSingleType) {
|
||||
title = initialData[currentContentTypeMainField] || currentContentTypeName;
|
||||
}
|
||||
|
||||
const headerTitle = useMemo(() => {
|
||||
const title = isSingleType ? currentContentTypeName : entryHeaderTitle;
|
||||
if (isSingleType) {
|
||||
title = currentContentTypeName;
|
||||
}
|
||||
|
||||
return title || currentContentTypeName;
|
||||
}, [currentContentTypeName, entryHeaderTitle, isSingleType]);
|
||||
|
||||
const checkIfHasDraftRelations = useCallback(() => {
|
||||
const checkIfHasDraftRelations = () => {
|
||||
const count = getDraftRelations(modifiedData, layout, componentLayouts);
|
||||
|
||||
setDraftRelationsCount(count);
|
||||
draftRelationsCountRef.current = count;
|
||||
|
||||
return count > 0;
|
||||
}, [modifiedData, layout, componentLayouts]);
|
||||
return count;
|
||||
};
|
||||
|
||||
const headerActions = useMemo(() => {
|
||||
let headerActions = [];
|
||||
let primaryAction = null;
|
||||
|
||||
if ((isCreatingEntry && canCreate) || (!isCreatingEntry && canUpdate)) {
|
||||
headerActions = [
|
||||
{
|
||||
disabled: !didChangeData,
|
||||
color: 'success',
|
||||
label: formatMessage({
|
||||
id: getTrad('containers.Edit.submit'),
|
||||
}),
|
||||
isLoading: status === 'submit-pending',
|
||||
type: 'submit',
|
||||
style: {
|
||||
minWidth: 150,
|
||||
fontWeight: 600,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
if (isCreatingEntry && canCreate) {
|
||||
primaryAction = (
|
||||
<Button disabled={!didChangeData} isLoading={status === 'submit-pending'} type="submit">
|
||||
{formatMessage({
|
||||
id: getTrad('containers.Edit.submit'),
|
||||
defaultMessage: 'Save',
|
||||
})}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
if (hasDraftAndPublish && canPublish) {
|
||||
const isPublished = !isEmpty(initialData.published_at);
|
||||
const isLoading = isPublished ? status === 'unpublish-pending' : status === 'publish-pending';
|
||||
const labelID = isPublished ? 'app.utils.unpublish' : 'app.utils.publish';
|
||||
/* eslint-disable indent */
|
||||
const onClick = isPublished
|
||||
? () => setWarningUnpublish(true)
|
||||
: e => {
|
||||
if (!checkIfHasDraftRelations()) {
|
||||
onPublish(e);
|
||||
} else {
|
||||
setShowWarningDraftRelation(true);
|
||||
}
|
||||
};
|
||||
/* eslint-enable indent */
|
||||
if (!isCreatingEntry && canUpdate) {
|
||||
const shouldShowPublishButton = hasDraftAndPublish && canPublish;
|
||||
const isPublished = !isEmpty(initialData.published_at);
|
||||
const isPublishButtonLoading = isPublished
|
||||
? status === 'unpublish-pending'
|
||||
: status === 'publish-pending';
|
||||
const pubishButtonLabel = isPublished
|
||||
? { id: 'app.utils.unpublish', defaultMessage: 'Unpublish' }
|
||||
: { id: 'app.utils.publish', defaultMessage: 'Publish' };
|
||||
|
||||
const action = {
|
||||
...primaryButtonObject,
|
||||
disabled: isCreatingEntry || didChangeData,
|
||||
isLoading,
|
||||
label: formatMessage({ id: labelID }),
|
||||
onClick,
|
||||
};
|
||||
/* eslint-disable indent */
|
||||
const onClick = isPublished
|
||||
? () => setWarningUnpublish(true)
|
||||
: () => {
|
||||
if (checkIfHasDraftRelations() === 0) {
|
||||
onPublish();
|
||||
} else {
|
||||
setShowWarningDraftRelation(true);
|
||||
}
|
||||
};
|
||||
/* eslint-enable indent */
|
||||
|
||||
headerActions.unshift(action);
|
||||
}
|
||||
primaryAction = (
|
||||
<Row>
|
||||
{shouldShowPublishButton && (
|
||||
<Button
|
||||
disabled={didChangeData}
|
||||
loading={isPublishButtonLoading}
|
||||
onClick={onClick}
|
||||
startIcon={<CheckIcon />}
|
||||
variant="secondary"
|
||||
>
|
||||
{formatMessage(pubishButtonLabel)}
|
||||
</Button>
|
||||
)}
|
||||
<Box paddingLeft={shouldShowPublishButton ? 2 : 0}>
|
||||
<Button disabled={!didChangeData} loading={status === 'submit-pending'} type="submit">
|
||||
{formatMessage({
|
||||
id: getTrad('containers.Edit.submit'),
|
||||
defaultMessage: 'Save',
|
||||
})}
|
||||
</Button>
|
||||
</Box>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
return headerActions;
|
||||
}, [
|
||||
isCreatingEntry,
|
||||
canCreate,
|
||||
canUpdate,
|
||||
hasDraftAndPublish,
|
||||
canPublish,
|
||||
didChangeData,
|
||||
formatMessage,
|
||||
status,
|
||||
initialData,
|
||||
onPublish,
|
||||
checkIfHasDraftRelations,
|
||||
]);
|
||||
const toggleWarningUnpublish = () => setWarningUnpublish(prevState => !prevState);
|
||||
const toggleWarningDraftRelation = () => setShowWarningDraftRelation(prevState => !prevState);
|
||||
|
||||
const headerProps = useMemo(() => {
|
||||
return {
|
||||
title: {
|
||||
label: toString(headerTitle),
|
||||
},
|
||||
content: `${formatMessageRef.current({ id: getTrad('api.id') })} : ${apiID}`,
|
||||
actions: headerActions,
|
||||
};
|
||||
}, [headerActions, headerTitle, apiID]);
|
||||
const handlePublish = () => {
|
||||
toggleWarningDraftRelation();
|
||||
draftRelationsCountRef.current = 0;
|
||||
onPublish();
|
||||
};
|
||||
|
||||
const toggleWarningPublish = () => setWarningUnpublish(prevState => !prevState);
|
||||
const handleUnpublish = () => {
|
||||
toggleWarningUnpublish();
|
||||
onUnpublish();
|
||||
};
|
||||
|
||||
const toggleWarningDraftRelation = useCallback(() => {
|
||||
setShowWarningDraftRelation(prev => !prev);
|
||||
}, []);
|
||||
|
||||
const handleConfirmPublish = useCallback(() => {
|
||||
setShouldPublish(true);
|
||||
setShowWarningDraftRelation(false);
|
||||
}, []);
|
||||
|
||||
const handleConfirmUnpublish = useCallback(() => {
|
||||
setShouldUnpublish(true);
|
||||
setWarningUnpublish(false);
|
||||
}, []);
|
||||
|
||||
const handleCloseModalPublish = useCallback(
|
||||
e => {
|
||||
if (shouldPublish) {
|
||||
onPublish(e);
|
||||
}
|
||||
|
||||
setShouldUnpublish(false);
|
||||
},
|
||||
[onPublish, shouldPublish]
|
||||
);
|
||||
|
||||
const handleCloseModalUnpublish = useCallback(
|
||||
e => {
|
||||
if (shouldUnpublish) {
|
||||
onUnpublish(e);
|
||||
}
|
||||
|
||||
setShouldUnpublish(false);
|
||||
},
|
||||
[onUnpublish, shouldUnpublish]
|
||||
);
|
||||
|
||||
const contentIdSuffix = draftRelationsCount > 1 ? 'plural' : 'singular';
|
||||
const subtitle = `${formatMessage({
|
||||
id: getTrad('api.id'),
|
||||
defaultMessage: 'API ID ',
|
||||
})} : ${layout.apiID}`;
|
||||
|
||||
return (
|
||||
<>
|
||||
<PluginHeader {...headerProps} />
|
||||
{hasDraftAndPublish && (
|
||||
<>
|
||||
<ModalConfirm
|
||||
isOpen={showWarningUnpublish}
|
||||
toggle={toggleWarningPublish}
|
||||
content={{
|
||||
id: getTrad('popUpWarning.warning.unpublish'),
|
||||
values: {
|
||||
br: () => <br />,
|
||||
},
|
||||
<HeaderLayout
|
||||
title={title}
|
||||
primaryAction={primaryAction}
|
||||
subtitle={subtitle}
|
||||
navigationAction={
|
||||
<Link
|
||||
startIcon={<BackIcon />}
|
||||
// Needed in order to redirect the user with the correct search params
|
||||
// Since parts is using a link from react-router-dom the best way to do it is to disable the
|
||||
// event
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
goBack();
|
||||
}}
|
||||
type="xwarning"
|
||||
onConfirm={handleConfirmUnpublish}
|
||||
onClosed={handleCloseModalUnpublish}
|
||||
to="/"
|
||||
>
|
||||
<Text>{formatMessage({ id: getTrad('popUpWarning.warning.unpublish-question') })}</Text>
|
||||
</ModalConfirm>
|
||||
<ModalConfirm
|
||||
confirmButtonLabel={{
|
||||
id: getTrad('popUpwarning.warning.has-draft-relations.button-confirm'),
|
||||
}}
|
||||
isOpen={showWarningDraftRelation}
|
||||
toggle={toggleWarningDraftRelation}
|
||||
onClosed={handleCloseModalPublish}
|
||||
onConfirm={handleConfirmPublish}
|
||||
type="success"
|
||||
content={{
|
||||
id: getTrad(`popUpwarning.warning.has-draft-relations.message.${contentIdSuffix}`),
|
||||
values: {
|
||||
count: draftRelationsCount,
|
||||
b: chunks => (
|
||||
<Text as="span" fontWeight="bold">
|
||||
{chunks}
|
||||
</Text>
|
||||
),
|
||||
br: () => <br />,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Text>{formatMessage({ id: getTrad('popUpWarning.warning.publish-question') })}</Text>
|
||||
</ModalConfirm>
|
||||
</>
|
||||
{formatMessage({
|
||||
id: 'app.components.HeaderLayout.link.go-back',
|
||||
defaultMessage: 'Back',
|
||||
})}
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
{showWarningUnpublish && (
|
||||
<Dialog
|
||||
onClose={toggleWarningUnpublish}
|
||||
title="Confirmation"
|
||||
labelledBy="confirmation"
|
||||
describedBy="confirm-description"
|
||||
isOpen={showWarningUnpublish}
|
||||
>
|
||||
<DialogBody icon={<AlertWarningIcon />}>
|
||||
<Stack size={2}>
|
||||
<Row justifyContent="center" style={{ textAlign: 'center' }}>
|
||||
<Text id="confirm-description">
|
||||
{formatMessage(
|
||||
{
|
||||
id: getTrad('popUpWarning.warning.unpublish'),
|
||||
defaultMessage:
|
||||
'Unpublish this content will automatically change it to a draft.',
|
||||
},
|
||||
{
|
||||
br: () => <br />,
|
||||
}
|
||||
)}
|
||||
</Text>
|
||||
</Row>
|
||||
<Row justifyContent="center" style={{ textAlign: 'center' }}>
|
||||
<Text id="confirm-description">
|
||||
{formatMessage({
|
||||
id: getTrad('popUpWarning.warning.unpublish-question'),
|
||||
defaultMessage: 'Are you sure you want to unpublish it?',
|
||||
})}
|
||||
</Text>
|
||||
</Row>
|
||||
</Stack>
|
||||
</DialogBody>
|
||||
<DialogFooter
|
||||
startAction={
|
||||
<Button onClick={toggleWarningUnpublish} variant="tertiary">
|
||||
{formatMessage({
|
||||
id: 'components.popUpWarning.button.cancel',
|
||||
defaultMessage: 'No, cancel',
|
||||
})}
|
||||
</Button>
|
||||
}
|
||||
endAction={
|
||||
<Button variant="danger-light" onClick={handleUnpublish}>
|
||||
{formatMessage({
|
||||
id: 'components.popUpWarning.button.confirm',
|
||||
defaultMessage: 'Yes, confirm',
|
||||
})}
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</Dialog>
|
||||
)}
|
||||
|
||||
{showWarningDraftRelation && (
|
||||
<Dialog
|
||||
onClose={toggleWarningDraftRelation}
|
||||
title="Confirmation"
|
||||
labelledBy="confirmation"
|
||||
describedBy="confirm-description"
|
||||
isOpen={showWarningDraftRelation}
|
||||
>
|
||||
<DialogBody icon={<AlertWarningIcon />}>
|
||||
<Stack size={2}>
|
||||
<Row justifyContent="center" style={{ textAlign: 'center' }}>
|
||||
<Text id="confirm-description">
|
||||
{draftRelationsCountRef.current}
|
||||
{formatMessage(
|
||||
{
|
||||
id: getTrad(`popUpwarning.warning.has-draft-relations.message`),
|
||||
defaultMessage:
|
||||
'<b>{count, plural, =0 { of your content relations is} one { of your content relations is} other { of your content relations are}}</b> not published yet.<br></br>It might engender broken links and errors on your project.',
|
||||
},
|
||||
{
|
||||
br: () => <br />,
|
||||
b: chunks => <Text bold>{chunks}</Text>,
|
||||
count: draftRelationsCountRef.current,
|
||||
}
|
||||
)}
|
||||
</Text>
|
||||
</Row>
|
||||
<Row justifyContent="center" style={{ textAlign: 'center' }}>
|
||||
<Text id="confirm-description">
|
||||
{formatMessage({
|
||||
id: getTrad('popUpWarning.warning.publish-question'),
|
||||
defaultMessage: 'Do you still want to publish it?',
|
||||
})}
|
||||
</Text>
|
||||
</Row>
|
||||
</Stack>
|
||||
</DialogBody>
|
||||
<DialogFooter
|
||||
startAction={
|
||||
<Button onClick={toggleWarningDraftRelation} variant="tertiary">
|
||||
{formatMessage({
|
||||
id: 'components.popUpWarning.button.cancel',
|
||||
defaultMessage: 'No, cancel',
|
||||
})}
|
||||
</Button>
|
||||
}
|
||||
endAction={
|
||||
<Button variant="success" onClick={handlePublish}>
|
||||
{formatMessage({
|
||||
id: getTrad('popUpwarning.warning.has-draft-relations.button-confirm'),
|
||||
defaultMessage: 'Yes, publish',
|
||||
})}
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</Dialog>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
@ -256,3 +308,4 @@ Header.propTypes = {
|
||||
const Memoized = memo(Header, isEqualFastCompare);
|
||||
|
||||
export default connect(Memoized, select);
|
||||
export { Header };
|
||||
|
||||
@ -0,0 +1,322 @@
|
||||
/**
|
||||
*
|
||||
* Tests for Header
|
||||
*
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import Theme from '../../../../../components/Theme';
|
||||
import { Header } from '../index';
|
||||
import components from '../utils/tests/data/compos-schema.json';
|
||||
import ct from '../utils/tests/data/ct-schema.json';
|
||||
|
||||
const defaultProps = {
|
||||
allowedActions: { canUpdate: true, canCreate: true, canPublish: true },
|
||||
componentLayouts: components,
|
||||
initialData: {},
|
||||
isCreatingEntry: true,
|
||||
isSingleType: false,
|
||||
hasDraftAndPublish: false,
|
||||
layout: ct,
|
||||
modifiedData: {},
|
||||
onPublish: jest.fn(),
|
||||
onUnpublish: jest.fn(),
|
||||
status: 'resolved',
|
||||
};
|
||||
|
||||
const makeApp = (props = defaultProps) => {
|
||||
return (
|
||||
<MemoryRouter>
|
||||
<IntlProvider locale="en" defaultLocale="en" messages={{}}>
|
||||
<Theme>
|
||||
<Header {...props} />
|
||||
</Theme>
|
||||
</IntlProvider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
};
|
||||
|
||||
describe('CONTENT MANAGER | EditView | Header', () => {
|
||||
it('renders and matches the snapshot', () => {
|
||||
const {
|
||||
container: { firstChild },
|
||||
} = render(makeApp());
|
||||
|
||||
expect(firstChild).toMatchInlineSnapshot(`
|
||||
.c0 {
|
||||
background: #f6f6f9;
|
||||
padding-top: 24px;
|
||||
padding-right: 56px;
|
||||
padding-bottom: 56px;
|
||||
padding-left: 56px;
|
||||
}
|
||||
|
||||
.c1 {
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
.c8 {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: row;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-webkit-box-pack: justify;
|
||||
-webkit-justify-content: space-between;
|
||||
-ms-flex-pack: justify;
|
||||
justify-content: space-between;
|
||||
-webkit-align-items: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.c9 {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: row;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-webkit-align-items: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.c10 {
|
||||
font-weight: 600;
|
||||
font-size: 2rem;
|
||||
line-height: 1.25;
|
||||
color: #32324d;
|
||||
}
|
||||
|
||||
.c15 {
|
||||
font-weight: 400;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.43;
|
||||
color: #666687;
|
||||
}
|
||||
|
||||
.c16 {
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.c14 {
|
||||
font-weight: 500;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.33;
|
||||
color: #32324d;
|
||||
}
|
||||
|
||||
.c11 {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
background: #ffffff;
|
||||
border: 1px solid #dcdce4;
|
||||
}
|
||||
|
||||
.c11 svg {
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
}
|
||||
|
||||
.c11 svg > g,
|
||||
.c11 svg path {
|
||||
fill: #ffffff;
|
||||
}
|
||||
|
||||
.c11[aria-disabled='true'] {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.c12 {
|
||||
padding: 8px 16px;
|
||||
background: #4945ff;
|
||||
border: none;
|
||||
border: 1px solid #4945ff;
|
||||
background: #4945ff;
|
||||
}
|
||||
|
||||
.c12 .c13 {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.c12[aria-disabled='true'] {
|
||||
border: 1px solid #dcdce4;
|
||||
background: #eaeaef;
|
||||
}
|
||||
|
||||
.c12[aria-disabled='true'] .c13 {
|
||||
color: #666687;
|
||||
}
|
||||
|
||||
.c12[aria-disabled='true'] svg > g,
|
||||
.c12[aria-disabled='true'] svg path {
|
||||
fill: #666687;
|
||||
}
|
||||
|
||||
.c12[aria-disabled='true']:active {
|
||||
border: 1px solid #dcdce4;
|
||||
background: #eaeaef;
|
||||
}
|
||||
|
||||
.c12[aria-disabled='true']:active .c13 {
|
||||
color: #666687;
|
||||
}
|
||||
|
||||
.c12[aria-disabled='true']:active svg > g,
|
||||
.c12[aria-disabled='true']:active svg path {
|
||||
fill: #666687;
|
||||
}
|
||||
|
||||
.c12:hover {
|
||||
border: 1px solid #7b79ff;
|
||||
background: #7b79ff;
|
||||
}
|
||||
|
||||
.c12:active {
|
||||
border: 1px solid #4945ff;
|
||||
background: #4945ff;
|
||||
}
|
||||
|
||||
.c5 {
|
||||
font-weight: 400;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.43;
|
||||
color: #4945ff;
|
||||
}
|
||||
|
||||
.c6 {
|
||||
font-weight: 600;
|
||||
line-height: 1.14;
|
||||
}
|
||||
|
||||
.c7 {
|
||||
font-weight: 600;
|
||||
font-size: 0.6875rem;
|
||||
line-height: 1.45;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.c3 {
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.c2 {
|
||||
display: -webkit-inline-box;
|
||||
display: -webkit-inline-flex;
|
||||
display: -ms-inline-flexbox;
|
||||
display: inline-flex;
|
||||
-webkit-align-items: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
text-transform: uppercase;
|
||||
-webkit-text-decoration: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.c2 svg path {
|
||||
fill: #4945ff;
|
||||
}
|
||||
|
||||
.c2 svg {
|
||||
font-size: 0.625rem;
|
||||
}
|
||||
|
||||
.c4 {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
<div
|
||||
class=""
|
||||
style="height: 0px;"
|
||||
>
|
||||
<div
|
||||
class="c0"
|
||||
data-strapi-header="true"
|
||||
>
|
||||
<div
|
||||
class="c1"
|
||||
>
|
||||
<a
|
||||
aria-current="page"
|
||||
class="c2 active"
|
||||
href="/"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="c3 c4"
|
||||
>
|
||||
<svg
|
||||
fill="none"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M24 13.3a.2.2 0 01-.2.2H5.74l8.239 8.239a.2.2 0 010 .282L12.14 23.86a.2.2 0 01-.282 0L.14 12.14a.2.2 0 010-.282L11.86.14a.2.2 0 01.282 0L13.98 1.98a.2.2 0 010 .282L5.74 10.5H23.8c.11 0 .2.09.2.2v2.6z"
|
||||
fill="#212134"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="c5 c6 c7"
|
||||
>
|
||||
Back
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="c8"
|
||||
>
|
||||
<div
|
||||
class="c9"
|
||||
>
|
||||
<h1
|
||||
class="c10"
|
||||
id="main-content-title"
|
||||
>
|
||||
Create an entry
|
||||
</h1>
|
||||
</div>
|
||||
<button
|
||||
aria-disabled="true"
|
||||
class="c11 c12"
|
||||
disabled=""
|
||||
type="submit"
|
||||
>
|
||||
<span
|
||||
class="c13 c14"
|
||||
>
|
||||
Save
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<p
|
||||
class="c15 c16"
|
||||
>
|
||||
API ID : restaurant
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -1,7 +1,21 @@
|
||||
// import React, { memo, useCallback, useMemo } from 'react';
|
||||
// import PropTypes from 'prop-types';
|
||||
// import { get } from 'lodash';
|
||||
// import { BaselineAlignment, LiLink, CheckPermissions, useTracking } from '@strapi/helper-plugin';
|
||||
import React, {
|
||||
memo,
|
||||
// useCallback,
|
||||
useMemo,
|
||||
} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
// import get from 'lodash/get';
|
||||
// import // BaselineAlignment,
|
||||
// LiLink,
|
||||
// CheckPermissions,
|
||||
// useTracking,
|
||||
// '@strapi/helper-plugin';
|
||||
import { ContentLayout } from '@strapi/parts/Layout';
|
||||
import { Box } from '@strapi/parts/Box';
|
||||
import { Grid, GridItem } from '@strapi/parts/Grid';
|
||||
import { Main } from '@strapi/parts/Main';
|
||||
import { Stack } from '@strapi/parts/Stack';
|
||||
|
||||
// import { Padded } from '@buffetjs/core';
|
||||
// import { InjectionZone } from '../../../shared/components';
|
||||
// import permissions from '../../../permissions';
|
||||
@ -11,12 +25,15 @@
|
||||
// import FieldComponent from '../../components/FieldComponent';
|
||||
// import Inputs from '../../components/Inputs';
|
||||
// import SelectWrapper from '../../components/SelectWrapper';
|
||||
// import CollectionTypeFormWrapper from '../../components/CollectionTypeFormWrapper';
|
||||
// import EditViewDataManagerProvider from '../../components/EditViewDataManagerProvider';
|
||||
// import SingleTypeFormWrapper from '../../components/SingleTypeFormWrapper';
|
||||
// import BackHeader from '../../components/BackHeader';
|
||||
// import Header from './Header';
|
||||
// import { createAttributesLayout, getFieldsActionMatchingPermissions } from './utils';
|
||||
import CollectionTypeFormWrapper from '../../components/CollectionTypeFormWrapper';
|
||||
import EditViewDataManagerProvider from '../../components/EditViewDataManagerProvider';
|
||||
import SingleTypeFormWrapper from '../../components/SingleTypeFormWrapper';
|
||||
import DraftAndPublishBadge from './DraftAndPublishBadge';
|
||||
import Header from './Header';
|
||||
import {
|
||||
// createAttributesLayout,
|
||||
getFieldsActionMatchingPermissions,
|
||||
} from './utils';
|
||||
// import { LinkWrapper, SubWrapper } from './components';
|
||||
// import DeleteLink from './DeleteLink';
|
||||
// import InformationCard from './InformationCard';
|
||||
@ -26,282 +43,363 @@
|
||||
// const ctbPermissions = [{ action: 'plugin::content-type-builder.read', subject: null }];
|
||||
|
||||
// /* eslint-disable react/no-array-index-key */
|
||||
// const EditView = ({
|
||||
// allowedActions,
|
||||
// isSingleType,
|
||||
// goBack,
|
||||
// layout,
|
||||
// slug,
|
||||
// id,
|
||||
// origin,
|
||||
// userPermissions,
|
||||
// }) => {
|
||||
// const { trackUsage } = useTracking();
|
||||
// const {
|
||||
// createActionAllowedFields,
|
||||
// readActionAllowedFields,
|
||||
// updateActionAllowedFields,
|
||||
// } = useMemo(() => {
|
||||
// return getFieldsActionMatchingPermissions(userPermissions, slug);
|
||||
// }, [userPermissions, slug]);
|
||||
// const configurationPermissions = useMemo(() => {
|
||||
// return isSingleType
|
||||
// ? cmPermissions.singleTypesConfigurations
|
||||
// : cmPermissions.collectionTypesConfigurations;
|
||||
// }, [isSingleType]);
|
||||
const EditView = ({
|
||||
allowedActions,
|
||||
isSingleType,
|
||||
goBack,
|
||||
layout,
|
||||
slug,
|
||||
id,
|
||||
origin,
|
||||
userPermissions,
|
||||
}) => {
|
||||
// const { trackUsage } = useTracking();
|
||||
const {
|
||||
createActionAllowedFields,
|
||||
readActionAllowedFields,
|
||||
updateActionAllowedFields,
|
||||
} = useMemo(() => {
|
||||
return getFieldsActionMatchingPermissions(userPermissions, slug);
|
||||
}, [userPermissions, slug]);
|
||||
// const configurationPermissions = useMemo(() => {
|
||||
// return isSingleType
|
||||
// ? cmPermissions.singleTypesConfigurations
|
||||
// : cmPermissions.collectionTypesConfigurations;
|
||||
// }, [isSingleType]);
|
||||
|
||||
// // FIXME when changing the routing
|
||||
// const configurationsURL = `/content-manager/${
|
||||
// isSingleType ? 'singleType' : 'collectionType'
|
||||
// }/${slug}/configurations/edit`;
|
||||
// const currentContentTypeLayoutData = useMemo(() => get(layout, ['contentType'], {}), [layout]);
|
||||
// FIXME when changing the routing
|
||||
// const configurationsURL = `/content-manager/${
|
||||
// isSingleType ? 'singleType' : 'collectionType'
|
||||
// }/${slug}/configurations/edit`;
|
||||
// const currentContentTypeLayoutData = get(layout, ['contentType'], {})
|
||||
|
||||
// const DataManagementWrapper = useMemo(
|
||||
// () => (isSingleType ? SingleTypeFormWrapper : CollectionTypeFormWrapper),
|
||||
// [isSingleType]
|
||||
// );
|
||||
const DataManagementWrapper = useMemo(
|
||||
() => (isSingleType ? SingleTypeFormWrapper : CollectionTypeFormWrapper),
|
||||
[isSingleType]
|
||||
);
|
||||
|
||||
// // Check if a block is a dynamic zone
|
||||
// const isDynamicZone = useCallback(block => {
|
||||
// return block.every(subBlock => {
|
||||
// return subBlock.every(obj => obj.fieldSchema.type === 'dynamiczone');
|
||||
// });
|
||||
// }, []);
|
||||
// Check if a block is a dynamic zone
|
||||
// const isDynamicZone = useCallback(block => {
|
||||
// return block.every(subBlock => {
|
||||
// return subBlock.every(obj => obj.fieldSchema.type === 'dynamiczone');
|
||||
// });
|
||||
// }, []);
|
||||
|
||||
// const formattedContentTypeLayout = useMemo(() => {
|
||||
// if (!currentContentTypeLayoutData.layouts) {
|
||||
// return [];
|
||||
// }
|
||||
// const formattedContentTypeLayout = useMemo(() => {
|
||||
// if (!currentContentTypeLayoutData.layouts) {
|
||||
// return [];
|
||||
// }
|
||||
|
||||
// return createAttributesLayout(
|
||||
// currentContentTypeLayoutData.layouts.edit,
|
||||
// currentContentTypeLayoutData.attributes
|
||||
// );
|
||||
// }, [currentContentTypeLayoutData]);
|
||||
// return createAttributesLayout(
|
||||
// currentContentTypeLayoutData.layouts.edit,
|
||||
// currentContentTypeLayoutData.attributes
|
||||
// );
|
||||
// }, [currentContentTypeLayoutData]);
|
||||
|
||||
// return (
|
||||
// <DataManagementWrapper allLayoutData={layout} slug={slug} id={id} origin={origin}>
|
||||
// {({
|
||||
// componentsDataStructure,
|
||||
// contentTypeDataStructure,
|
||||
// data,
|
||||
// isCreatingEntry,
|
||||
// isLoadingForData,
|
||||
// onDelete,
|
||||
// onDeleteSucceeded,
|
||||
// onPost,
|
||||
// onPublish,
|
||||
// onPut,
|
||||
// onUnpublish,
|
||||
// redirectionLink,
|
||||
// status,
|
||||
// }) => {
|
||||
// return (
|
||||
// <EditViewDataManagerProvider
|
||||
// allowedActions={allowedActions}
|
||||
// allLayoutData={layout}
|
||||
// createActionAllowedFields={createActionAllowedFields}
|
||||
// componentsDataStructure={componentsDataStructure}
|
||||
// contentTypeDataStructure={contentTypeDataStructure}
|
||||
// from={redirectionLink}
|
||||
// initialValues={data}
|
||||
// isCreatingEntry={isCreatingEntry}
|
||||
// isLoadingForData={isLoadingForData}
|
||||
// isSingleType={isSingleType}
|
||||
// onPost={onPost}
|
||||
// onPublish={onPublish}
|
||||
// onPut={onPut}
|
||||
// onUnpublish={onUnpublish}
|
||||
// readActionAllowedFields={readActionAllowedFields}
|
||||
// redirectToPreviousPage={goBack}
|
||||
// slug={slug}
|
||||
// status={status}
|
||||
// updateActionAllowedFields={updateActionAllowedFields}
|
||||
// >
|
||||
// <BackHeader onClick={goBack} />
|
||||
// <Container className="container-fluid">
|
||||
// <Header allowedActions={allowedActions} />
|
||||
// <div className="row" style={{ paddingTop: 3 }}>
|
||||
// <div className="col-md-12 col-lg-9" style={{ marginBottom: 13 }}>
|
||||
// {formattedContentTypeLayout.map((block, blockIndex) => {
|
||||
// if (isDynamicZone(block)) {
|
||||
// const {
|
||||
// 0: {
|
||||
// 0: { name, fieldSchema, metadatas, labelIcon },
|
||||
// },
|
||||
// } = block;
|
||||
// const baselineAlignementSize = blockIndex === 0 ? '3px' : '0';
|
||||
return (
|
||||
<DataManagementWrapper allLayoutData={layout} slug={slug} id={id} origin={origin}>
|
||||
{({
|
||||
componentsDataStructure,
|
||||
contentTypeDataStructure,
|
||||
data,
|
||||
isCreatingEntry,
|
||||
isLoadingForData,
|
||||
// onDelete,
|
||||
// onDeleteSucceeded,
|
||||
onPost,
|
||||
onPublish,
|
||||
onPut,
|
||||
onUnpublish,
|
||||
redirectionLink,
|
||||
status,
|
||||
}) => {
|
||||
return (
|
||||
<EditViewDataManagerProvider
|
||||
allowedActions={allowedActions}
|
||||
allLayoutData={layout}
|
||||
createActionAllowedFields={createActionAllowedFields}
|
||||
componentsDataStructure={componentsDataStructure}
|
||||
contentTypeDataStructure={contentTypeDataStructure}
|
||||
from={redirectionLink}
|
||||
initialValues={data}
|
||||
isCreatingEntry={isCreatingEntry}
|
||||
isLoadingForData={isLoadingForData}
|
||||
isSingleType={isSingleType}
|
||||
onPost={onPost}
|
||||
onPublish={onPublish}
|
||||
onPut={onPut}
|
||||
onUnpublish={onUnpublish}
|
||||
readActionAllowedFields={readActionAllowedFields}
|
||||
redirectToPreviousPage={goBack}
|
||||
slug={slug}
|
||||
status={status}
|
||||
updateActionAllowedFields={updateActionAllowedFields}
|
||||
>
|
||||
<Main aria-busy={status !== 'resolved'}>
|
||||
<Header allowedActions={allowedActions} />
|
||||
<ContentLayout>
|
||||
<Grid gap={4}>
|
||||
<GridItem col={9} s={12}>
|
||||
<Box
|
||||
hasRadius
|
||||
background="neutral0"
|
||||
shadow="tableShadow"
|
||||
paddingLeft={8}
|
||||
paddingRight={8}
|
||||
paddingTop={6}
|
||||
paddingBottom={6}
|
||||
>
|
||||
inputs TODO
|
||||
</Box>
|
||||
</GridItem>
|
||||
<GridItem col={3} s={12}>
|
||||
<Stack size={2}>
|
||||
<DraftAndPublishBadge />
|
||||
<Box
|
||||
as="aside"
|
||||
background="neutral0"
|
||||
borderColor="neutral150"
|
||||
hasRadius
|
||||
paddingBottom={4}
|
||||
paddingLeft={4}
|
||||
paddingRight={4}
|
||||
paddingTop={6}
|
||||
>
|
||||
infos + InjectionZone
|
||||
</Box>
|
||||
</Stack>
|
||||
</GridItem>
|
||||
</Grid>
|
||||
</ContentLayout>
|
||||
</Main>
|
||||
</EditViewDataManagerProvider>
|
||||
);
|
||||
}}
|
||||
</DataManagementWrapper>
|
||||
);
|
||||
|
||||
// return (
|
||||
// <BaselineAlignment key={blockIndex} top size={baselineAlignementSize}>
|
||||
// <DynamicZone
|
||||
// name={name}
|
||||
// fieldSchema={fieldSchema}
|
||||
// labelIcon={labelIcon}
|
||||
// metadatas={metadatas}
|
||||
// />
|
||||
// </BaselineAlignment>
|
||||
// );
|
||||
// }
|
||||
// return (
|
||||
// <DataManagementWrapper allLayoutData={layout} slug={slug} id={id} origin={origin}>
|
||||
// {({
|
||||
// componentsDataStructure,
|
||||
// contentTypeDataStructure,
|
||||
// data,
|
||||
// isCreatingEntry,
|
||||
// isLoadingForData,
|
||||
// onDelete,
|
||||
// onDeleteSucceeded,
|
||||
// onPost,
|
||||
// onPublish,
|
||||
// onPut,
|
||||
// onUnpublish,
|
||||
// redirectionLink,
|
||||
// status,
|
||||
// }) => {
|
||||
// return (
|
||||
// <EditViewDataManagerProvider
|
||||
// allowedActions={allowedActions}
|
||||
// allLayoutData={layout}
|
||||
// createActionAllowedFields={createActionAllowedFields}
|
||||
// componentsDataStructure={componentsDataStructure}
|
||||
// contentTypeDataStructure={contentTypeDataStructure}
|
||||
// from={redirectionLink}
|
||||
// initialValues={data}
|
||||
// isCreatingEntry={isCreatingEntry}
|
||||
// isLoadingForData={isLoadingForData}
|
||||
// isSingleType={isSingleType}
|
||||
// onPost={onPost}
|
||||
// onPublish={onPublish}
|
||||
// onPut={onPut}
|
||||
// onUnpublish={onUnpublish}
|
||||
// readActionAllowedFields={readActionAllowedFields}
|
||||
// redirectToPreviousPage={goBack}
|
||||
// slug={slug}
|
||||
// status={status}
|
||||
// updateActionAllowedFields={updateActionAllowedFields}
|
||||
// >
|
||||
// <Container className="container-fluid">
|
||||
// <Header allowedActions={allowedActions} />
|
||||
// <div className="row" style={{ paddingTop: 3 }}>
|
||||
// <div className="col-md-12 col-lg-9" style={{ marginBottom: 13 }}>
|
||||
// {formattedContentTypeLayout.map((block, blockIndex) => {
|
||||
// if (isDynamicZone(block)) {
|
||||
// const {
|
||||
// 0: {
|
||||
// 0: { name, fieldSchema, metadatas, labelIcon },
|
||||
// },
|
||||
// } = block;
|
||||
// const baselineAlignementSize = blockIndex === 0 ? '3px' : '0';
|
||||
|
||||
// return (
|
||||
// <FormWrapper key={blockIndex}>
|
||||
// {block.map((fieldsBlock, fieldsBlockIndex) => {
|
||||
// return (
|
||||
// <div className="row" key={fieldsBlockIndex}>
|
||||
// {fieldsBlock.map(
|
||||
// ({ name, size, fieldSchema, labelIcon, metadatas }, fieldIndex) => {
|
||||
// const isComponent = fieldSchema.type === 'component';
|
||||
// return (
|
||||
// <BaselineAlignment key={blockIndex} top size={baselineAlignementSize}>
|
||||
// <DynamicZone
|
||||
// name={name}
|
||||
// fieldSchema={fieldSchema}
|
||||
// labelIcon={labelIcon}
|
||||
// metadatas={metadatas}
|
||||
// />
|
||||
// </BaselineAlignment>
|
||||
// );
|
||||
// }
|
||||
|
||||
// if (isComponent) {
|
||||
// const { component, max, min, repeatable = false } = fieldSchema;
|
||||
// const componentUid = fieldSchema.component;
|
||||
// return (
|
||||
// <FormWrapper key={blockIndex}>
|
||||
// {block.map((fieldsBlock, fieldsBlockIndex) => {
|
||||
// return (
|
||||
// <div className="row" key={fieldsBlockIndex}>
|
||||
// {fieldsBlock.map(
|
||||
// ({ name, size, fieldSchema, labelIcon, metadatas }, fieldIndex) => {
|
||||
// const isComponent = fieldSchema.type === 'component';
|
||||
|
||||
// return (
|
||||
// <FieldComponent
|
||||
// key={componentUid}
|
||||
// componentUid={component}
|
||||
// labelIcon={labelIcon}
|
||||
// isRepeatable={repeatable}
|
||||
// label={metadatas.label}
|
||||
// max={max}
|
||||
// min={min}
|
||||
// name={name}
|
||||
// />
|
||||
// );
|
||||
// }
|
||||
// if (isComponent) {
|
||||
// const { component, max, min, repeatable = false } = fieldSchema;
|
||||
// const componentUid = fieldSchema.component;
|
||||
|
||||
// return (
|
||||
// <div className={`col-${size}`} key={name}>
|
||||
// <Inputs
|
||||
// autoFocus={
|
||||
// blockIndex === 0 &&
|
||||
// fieldsBlockIndex === 0 &&
|
||||
// fieldIndex === 0
|
||||
// }
|
||||
// fieldSchema={fieldSchema}
|
||||
// keys={name}
|
||||
// labelIcon={labelIcon}
|
||||
// metadatas={metadatas}
|
||||
// />
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
// )}
|
||||
// </div>
|
||||
// );
|
||||
// })}
|
||||
// </FormWrapper>
|
||||
// );
|
||||
// })}
|
||||
// </div>
|
||||
// <div className="col-md-12 col-lg-3">
|
||||
// <InformationCard />
|
||||
// <Padded size="smd" top />
|
||||
// {currentContentTypeLayoutData.layouts.editRelations.length > 0 && (
|
||||
// <SubWrapper style={{ padding: '0 20px 1px', marginBottom: '25px' }}>
|
||||
// <div style={{ paddingTop: '22px' }}>
|
||||
// {currentContentTypeLayoutData.layouts.editRelations.map(
|
||||
// ({ name, fieldSchema, labelIcon, metadatas, queryInfos }) => {
|
||||
// return (
|
||||
// <SelectWrapper
|
||||
// {...fieldSchema}
|
||||
// {...metadatas}
|
||||
// key={name}
|
||||
// labelIcon={labelIcon}
|
||||
// name={name}
|
||||
// relationsType={fieldSchema.relationType}
|
||||
// queryInfos={queryInfos}
|
||||
// />
|
||||
// );
|
||||
// }
|
||||
// )}
|
||||
// </div>
|
||||
// </SubWrapper>
|
||||
// )}
|
||||
// <LinkWrapper>
|
||||
// <ul>
|
||||
// <CheckPermissions permissions={configurationPermissions}>
|
||||
// <LiLink
|
||||
// message={{
|
||||
// id: 'app.links.configure-view',
|
||||
// }}
|
||||
// icon="layout"
|
||||
// url={configurationsURL}
|
||||
// onClick={() => {
|
||||
// // trackUsage('willEditContentTypeLayoutFromEditView');
|
||||
// }}
|
||||
// />
|
||||
// </CheckPermissions>
|
||||
// {slug !== 'strapi::administrator' && (
|
||||
// <CheckPermissions permissions={ctbPermissions}>
|
||||
// <LiLink
|
||||
// message={{
|
||||
// id: getTrad('containers.Edit.Link.Fields'),
|
||||
// }}
|
||||
// onClick={() => {
|
||||
// trackUsage('willEditEditLayout');
|
||||
// }}
|
||||
// icon="fa-cog"
|
||||
// url={`/plugins/content-type-builder/content-types/${slug}`}
|
||||
// />
|
||||
// </CheckPermissions>
|
||||
// )}
|
||||
// {/* TODO add DOCUMENTATION */}
|
||||
// <InjectionZone area="contentManager.editView.right-links" slug={slug} />
|
||||
// return (
|
||||
// <FieldComponent
|
||||
// key={componentUid}
|
||||
// componentUid={component}
|
||||
// labelIcon={labelIcon}
|
||||
// isRepeatable={repeatable}
|
||||
// label={metadatas.label}
|
||||
// max={max}
|
||||
// min={min}
|
||||
// name={name}
|
||||
// />
|
||||
// );
|
||||
// }
|
||||
|
||||
// {allowedActions.canDelete && (
|
||||
// <DeleteLink
|
||||
// isCreatingEntry={isCreatingEntry}
|
||||
// onDelete={onDelete}
|
||||
// onDeleteSucceeded={onDeleteSucceeded}
|
||||
// />
|
||||
// )}
|
||||
// </ul>
|
||||
// </LinkWrapper>
|
||||
// </div>
|
||||
// </div>
|
||||
// </Container>
|
||||
// </EditViewDataManagerProvider>
|
||||
// );
|
||||
// }}
|
||||
// </DataManagementWrapper>
|
||||
// );
|
||||
// };
|
||||
// return (
|
||||
// <div className={`col-${size}`} key={name}>
|
||||
// <Inputs
|
||||
// autoFocus={
|
||||
// blockIndex === 0 &&
|
||||
// fieldsBlockIndex === 0 &&
|
||||
// fieldIndex === 0
|
||||
// }
|
||||
// fieldSchema={fieldSchema}
|
||||
// keys={name}
|
||||
// labelIcon={labelIcon}
|
||||
// metadatas={metadatas}
|
||||
// />
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
// )}
|
||||
// </div>
|
||||
// );
|
||||
// })}
|
||||
// </FormWrapper>
|
||||
// );
|
||||
// })}
|
||||
// </div>
|
||||
// <div className="col-md-12 col-lg-3">
|
||||
// <InformationCard />
|
||||
// <Padded size="smd" top />
|
||||
// {currentContentTypeLayoutData.layouts.editRelations.length > 0 && (
|
||||
// <SubWrapper style={{ padding: '0 20px 1px', marginBottom: '25px' }}>
|
||||
// <div style={{ paddingTop: '22px' }}>
|
||||
// {currentContentTypeLayoutData.layouts.editRelations.map(
|
||||
// ({ name, fieldSchema, labelIcon, metadatas, queryInfos }) => {
|
||||
// return (
|
||||
// <SelectWrapper
|
||||
// {...fieldSchema}
|
||||
// {...metadatas}
|
||||
// key={name}
|
||||
// labelIcon={labelIcon}
|
||||
// name={name}
|
||||
// relationsType={fieldSchema.relationType}
|
||||
// queryInfos={queryInfos}
|
||||
// />
|
||||
// );
|
||||
// }
|
||||
// )}
|
||||
// </div>
|
||||
// </SubWrapper>
|
||||
// )}
|
||||
// <LinkWrapper>
|
||||
// <ul>
|
||||
// <CheckPermissions permissions={configurationPermissions}>
|
||||
// <LiLink
|
||||
// message={{
|
||||
// id: 'app.links.configure-view',
|
||||
// }}
|
||||
// icon="layout"
|
||||
// url={configurationsURL}
|
||||
// onClick={() => {
|
||||
// // trackUsage('willEditContentTypeLayoutFromEditView');
|
||||
// }}
|
||||
// />
|
||||
// </CheckPermissions>
|
||||
// {slug !== 'strapi::administrator' && (
|
||||
// <CheckPermissions permissions={ctbPermissions}>
|
||||
// <LiLink
|
||||
// message={{
|
||||
// id: getTrad('containers.Edit.Link.Fields'),
|
||||
// }}
|
||||
// onClick={() => {
|
||||
// trackUsage('willEditEditLayout');
|
||||
// }}
|
||||
// icon="fa-cog"
|
||||
// url={`/plugins/content-type-builder/content-types/${slug}`}
|
||||
// />
|
||||
// </CheckPermissions>
|
||||
// )}
|
||||
// {/* TODO add DOCUMENTATION */}
|
||||
// <InjectionZone area="contentManager.editView.right-links" slug={slug} />
|
||||
|
||||
// EditView.defaultProps = {
|
||||
// id: null,
|
||||
// isSingleType: false,
|
||||
// origin: null,
|
||||
// userPermissions: [],
|
||||
// };
|
||||
// {allowedActions.canDelete && (
|
||||
// <DeleteLink
|
||||
// isCreatingEntry={isCreatingEntry}
|
||||
// onDelete={onDelete}
|
||||
// onDeleteSucceeded={onDeleteSucceeded}
|
||||
// />
|
||||
// )}
|
||||
// </ul>
|
||||
// </LinkWrapper>
|
||||
// </div>
|
||||
// </div>
|
||||
// </Container>
|
||||
// </EditViewDataManagerProvider>
|
||||
// );
|
||||
// }}
|
||||
// </DataManagementWrapper>
|
||||
// );
|
||||
};
|
||||
|
||||
// EditView.propTypes = {
|
||||
// allowedActions: PropTypes.shape({
|
||||
// canRead: PropTypes.bool.isRequired,
|
||||
// canUpdate: PropTypes.bool.isRequired,
|
||||
// canCreate: PropTypes.bool.isRequired,
|
||||
// canDelete: PropTypes.bool.isRequired,
|
||||
// }).isRequired,
|
||||
// layout: PropTypes.shape({
|
||||
// components: PropTypes.object.isRequired,
|
||||
// contentType: PropTypes.shape({
|
||||
// uid: PropTypes.string.isRequired,
|
||||
// settings: PropTypes.object.isRequired,
|
||||
// metadatas: PropTypes.object.isRequired,
|
||||
// options: PropTypes.object.isRequired,
|
||||
// attributes: PropTypes.object.isRequired,
|
||||
// }).isRequired,
|
||||
// }).isRequired,
|
||||
// id: PropTypes.string,
|
||||
// isSingleType: PropTypes.bool,
|
||||
// goBack: PropTypes.func.isRequired,
|
||||
// origin: PropTypes.string,
|
||||
// slug: PropTypes.string.isRequired,
|
||||
// userPermissions: PropTypes.array,
|
||||
// };
|
||||
EditView.defaultProps = {
|
||||
id: null,
|
||||
isSingleType: false,
|
||||
origin: null,
|
||||
userPermissions: [],
|
||||
};
|
||||
|
||||
// export { EditView };
|
||||
// export default memo(EditView);
|
||||
EditView.propTypes = {
|
||||
allowedActions: PropTypes.shape({
|
||||
canRead: PropTypes.bool.isRequired,
|
||||
canUpdate: PropTypes.bool.isRequired,
|
||||
canCreate: PropTypes.bool.isRequired,
|
||||
canDelete: PropTypes.bool.isRequired,
|
||||
}).isRequired,
|
||||
layout: PropTypes.shape({
|
||||
components: PropTypes.object.isRequired,
|
||||
contentType: PropTypes.shape({
|
||||
uid: PropTypes.string.isRequired,
|
||||
settings: PropTypes.object.isRequired,
|
||||
metadatas: PropTypes.object.isRequired,
|
||||
options: PropTypes.object.isRequired,
|
||||
attributes: PropTypes.object.isRequired,
|
||||
}).isRequired,
|
||||
}).isRequired,
|
||||
id: PropTypes.string,
|
||||
isSingleType: PropTypes.bool,
|
||||
goBack: PropTypes.func.isRequired,
|
||||
origin: PropTypes.string,
|
||||
slug: PropTypes.string.isRequired,
|
||||
userPermissions: PropTypes.array,
|
||||
};
|
||||
|
||||
export default () => 'TODO Edit view';
|
||||
export { EditView };
|
||||
export default memo(EditView);
|
||||
|
||||
// export default () => 'TODO Edit view';
|
||||
|
||||
@ -211,6 +211,7 @@
|
||||
"Users.components.List.empty.withFilters": "There is no users with the applied filters...",
|
||||
"Users.components.List.empty.withSearch": "There is no users corresponding to the search ({search})...",
|
||||
"app.components.go-back": "Go back",
|
||||
"app.components.HeaderLayout.link.go-back": "Back",
|
||||
"app.components.ToggleCheckbox.on-label": "On",
|
||||
"app.components.ToggleCheckbox.off-label": "Off",
|
||||
"app.components.BlockLink.blog": "Blog",
|
||||
@ -594,9 +595,7 @@
|
||||
"content-manager.popUpWarning.warning.unpublish-question": "Are you sure you want to unpublish it?",
|
||||
"content-manager.popUpWarning.warning.updateAllSettings": "This will modify all your settings",
|
||||
"content-manager.popUpwarning.warning.has-draft-relations.button-confirm": "Yes, publish",
|
||||
"content-manager.popUpwarning.warning.has-draft-relations.message.plural": "<b>{count} of your content relations are</b> not published yet.<br></br>It might engender broken links and errors on your project.",
|
||||
"content-manager.popUpwarning.warning.has-draft-relations.message.singular": "<b>{count} of your content relations is</b> not published yet.<br></br>It might engender broken links and errors on your project.",
|
||||
"content-manager.popUpwarning.warning.has-draft-relations.second-message": "It might engender broken links and errors on your project.",
|
||||
"content-manager.popUpwarning.warning.has-draft-relations.message": "<b>{count, plural, =0 { of your content relations is} one { of your content relations is} other { of your content relations are}}</b> not published yet.<br></br>It might engender broken links and errors on your project.",
|
||||
"content-manager.success.record.delete": "Deleted",
|
||||
"content-manager.success.record.publish": "Published",
|
||||
"content-manager.success.record.save": "Saved",
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
|
||||
import React from 'react';
|
||||
import { render {{~#if useRedux}} as tlRender {{~/if}} } from '@testing-library/react';
|
||||
import { ThemeProvider, lightTheme } from '@strapi/parts';
|
||||
{{#if useRedux}}
|
||||
import { Provider } from 'react-redux';
|
||||
import { createStore, combineReducers } from 'redux';
|
||||
@ -49,11 +50,15 @@ describe('<{{name}} />', () => {
|
||||
container: { firstChild },
|
||||
} = render(
|
||||
{{#if useI18n}}
|
||||
<IntlProvider locale="en" messages={messages} defaultLocale="en">
|
||||
<{{name}} />
|
||||
</IntlProvider>,
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<IntlProvider locale="en" messages={messages} defaultLocale="en">
|
||||
<{{name}} />
|
||||
</IntlProvider>
|
||||
</ThemeProvider>
|
||||
{{else}}
|
||||
<{{name}} />
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<{{name}} />
|
||||
</ThemeProvider>
|
||||
{{/if}}
|
||||
);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user