Merge pull request #11384 from strapi/edit-settings/modal-submit

Edit settings/modal submit
This commit is contained in:
ELABBASSI Hicham 2021-10-28 17:39:52 +02:00 committed by GitHub
commit e381ff23f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 6769 additions and 2034 deletions

View File

@ -0,0 +1,48 @@
import React from 'react';
import PropTypes from 'prop-types';
import Date from '@strapi/icons/Date';
import Boolean from '@strapi/icons/Boolean';
import Email from '@strapi/icons/Email';
import Enumeration from '@strapi/icons/Enumeration';
import Media from '@strapi/icons/Media';
import Relation from '@strapi/icons/Relation';
import Text from '@strapi/icons/Text';
import Uid from '@strapi/icons/Uid';
import Number from '@strapi/icons/Number';
import Json from '@strapi/icons/Json';
import Component from '@strapi/icons/Component';
import DynamicZone from '@strapi/icons/DynamicZone';
const iconByTypes = {
biginteger: <Number />,
boolean: <Boolean />,
date: <Date />,
datetime: <Date />,
decimal: <Number />,
email: <Email />,
enum: <Enumeration />,
enumeration: <Enumeration />,
file: <Media />,
files: <Media />,
float: <Number />,
integer: <Number />,
media: <Media />,
number: <Number />,
relation: <Relation />,
string: <Text />,
text: <Text />,
time: <Date />,
timestamp: <Date />,
json: <Json />,
uid: <Uid />,
component: <Component />,
dynamiczone: <DynamicZone />,
};
const FieldTypeIcon = ({ type }) => iconByTypes[type];
FieldTypeIcon.propTypes = {
type: PropTypes.string.isRequired,
};
export default FieldTypeIcon;

View File

@ -16,15 +16,9 @@ import { useLayoutDnd } from '../../../hooks';
import FieldButton from './FieldButton';
import LinkToCTB from './LinkToCTB';
const DisplayedFields = ({
attributes,
editLayout,
editLayoutRemainingFields,
onRemoveField,
onAddField,
}) => {
const DisplayedFields = ({ editLayout, editLayoutRemainingFields, onRemoveField, onAddField }) => {
const { formatMessage } = useIntl();
const { setEditFieldToSelect } = useLayoutDnd();
const { setEditFieldToSelect, attributes, modifiedData } = useLayoutDnd();
return (
<Stack size={4}>
@ -56,6 +50,11 @@ const DisplayedFields = ({
<Grid gap={4} key={row.rowId}>
{row.rowContent.map((rowItem, index) => {
const attribute = get(attributes, [rowItem.name], {});
const attributeLabel = get(
modifiedData,
['metadatas', rowItem.name, 'edit', 'label'],
''
);
return (
<GridItem key={rowItem.name} col={rowItem.size}>
@ -65,7 +64,7 @@ const DisplayedFields = ({
onDeleteField={() => onRemoveField(row.rowId, index)}
attribute={attribute}
>
{rowItem.name}
{attributeLabel || rowItem.name}
</FieldButton>
) : (
<VisuallyHidden />
@ -82,6 +81,7 @@ const DisplayedFields = ({
defaultMessage: 'Insert another field',
})}
as={Button}
data-testid="add-field"
fullWidth
startIcon={<Plus />}
endIcon={null}
@ -103,7 +103,6 @@ const DisplayedFields = ({
DisplayedFields.propTypes = {
editLayout: PropTypes.array.isRequired,
editLayoutRemainingFields: PropTypes.array.isRequired,
attributes: PropTypes.object.isRequired,
onAddField: PropTypes.func.isRequired,
onRemoveField: PropTypes.func.isRequired,
};

View File

@ -15,6 +15,9 @@ import getTrad from '../../../utils/getTrad';
const CustomIconButton = styled(IconButton)`
background-color: transparent;
path {
fill: ${({ theme }) => theme.colors.neutral600};
}
`;
const CustomDragIcon = styled(Drag)`
height: ${12 / 16}rem;
@ -81,6 +84,7 @@ const FieldButton = ({ attribute, onEditField, onDeleteField, children }) => {
target: children,
}
)}
data-testid="delete-field"
onClick={onDeleteField}
icon={<Trash />}
noBorder

View File

@ -0,0 +1,91 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import upperFirst from 'lodash/upperFirst';
import {
ModalLayout,
ModalHeader,
ModalFooter,
ModalBody,
} from '@strapi/design-system/ModalLayout';
import { ButtonText } from '@strapi/design-system/Text';
import { Button } from '@strapi/design-system/Button';
import { Flex } from '@strapi/design-system/Flex';
import { Grid } from '@strapi/design-system/Grid';
import styled from 'styled-components';
import { getTrad } from '../../../utils';
import { useLayoutDnd } from '../../../hooks';
import FieldTypeIcon from '../../../components/FieldTypeIcon';
import ModalForm from './ModalForm';
const HeaderContainer = styled(Flex)`
svg {
width: ${32 / 16}rem;
height: ${24 / 16}rem;
margin-right: ${({ theme }) => theme.spaces[3]};
}
`;
const FormModal = ({ onToggle, onChange, onSubmit, type }) => {
const { selectedField } = useLayoutDnd();
const { formatMessage } = useIntl();
const getAttrType = () => {
if (type === 'timestamp') {
return 'date';
}
if (['decimal', 'float', 'integer', 'biginter'].includes(type)) {
return 'number';
}
return type;
};
return (
<ModalLayout onClose={onToggle} labelledBy="title">
<form onSubmit={onSubmit}>
<ModalHeader>
<HeaderContainer>
<FieldTypeIcon type={getAttrType(type)} />
<ButtonText textColor="neutral800" as="h2" id="title">
{formatMessage(
{
id: getTrad('containers.ListSettingsView.modal-form.edit-label'),
defaultMessage: 'Edit {fieldName}',
},
{ fieldName: upperFirst(selectedField) }
)}
</ButtonText>
</HeaderContainer>
</ModalHeader>
<ModalBody>
<Grid gap={4}>
<ModalForm onChange={onChange} />
</Grid>
</ModalBody>
<ModalFooter
startActions={
<Button onClick={onToggle} variant="tertiary">
{formatMessage({ id: 'app.components.Button.cancel', defaultMessage: 'Cancel' })}
</Button>
}
endActions={
<Button type="submit">
{formatMessage({ id: 'form.button.finish', defaultMessage: 'Finish' })}
</Button>
}
/>
</form>
</ModalLayout>
);
};
FormModal.propTypes = {
onSubmit: PropTypes.func.isRequired,
onToggle: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
type: PropTypes.string.isRequired,
};
export default FormModal;

View File

@ -0,0 +1,68 @@
import React from 'react';
import PropTypes from 'prop-types';
import { TextInput } from '@strapi/design-system/TextInput';
import { ToggleInput } from '@strapi/design-system/ToggleInput';
import { Select, Option } from '@strapi/design-system/Select';
import { useIntl } from 'react-intl';
const GenericInput = ({ type, options, onChange, value, name, ...inputProps }) => {
const { formatMessage } = useIntl();
switch (type) {
case 'text': {
return <TextInput onChange={onChange} value={value} name={name} {...inputProps} />;
}
case 'bool': {
return (
<ToggleInput
onChange={e => {
onChange({ target: { name, value: e.target.checked } });
}}
checked={value}
name={name}
onLabel={formatMessage({
id: 'app.components.ToggleCheckbox.on-label',
defaultMessage: 'On',
})}
offLabel={formatMessage({
id: 'app.components.ToggleCheckbox.off-label',
defaultMessage: 'Off',
})}
{...inputProps}
/>
);
}
case 'select': {
return (
<Select
value={value}
name={name}
onChange={value => onChange({ target: { name, value } })}
{...inputProps}
>
{options.map(option => (
<Option key={option} value={option}>
{option}
</Option>
))}
</Select>
);
}
default:
return null;
}
};
GenericInput.defaultProps = {
options: undefined,
};
GenericInput.propTypes = {
type: PropTypes.string.isRequired,
options: PropTypes.arrayOf(PropTypes.string),
onChange: PropTypes.func.isRequired,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]).isRequired,
name: PropTypes.string.isRequired,
};
export default GenericInput;

View File

@ -1,129 +1,90 @@
import React from 'react';
import PropTypes from 'prop-types';
import React, { useMemo, useCallback } from 'react';
import get from 'lodash/get';
import { GridItem } from '@strapi/design-system/Grid';
import { useSelector, shallowEqual } from 'react-redux';
import { useIntl } from 'react-intl';
import upperFirst from 'lodash/upperFirst';
import {
ModalLayout,
ModalHeader,
ModalFooter,
ModalBody,
} from '@strapi/design-system/ModalLayout';
import { ButtonText } from '@strapi/design-system/Text';
import { Button } from '@strapi/design-system/Button';
import { Flex } from '@strapi/design-system/Flex';
import { Grid, GridItem } from '@strapi/design-system/Grid';
import Date from '@strapi/icons/Date';
import Boolean from '@strapi/icons/Boolean';
import Email from '@strapi/icons/Email';
import Enumeration from '@strapi/icons/Enumeration';
import Media from '@strapi/icons/Media';
import Relation from '@strapi/icons/Relation';
import Text from '@strapi/icons/Text';
import Uid from '@strapi/icons/Uid';
import Number from '@strapi/icons/Number';
import Json from '@strapi/icons/Json';
import Component from '@strapi/icons/Component';
import DynamicZone from '@strapi/icons/DynamicZone';
import styled from 'styled-components';
import { getTrad } from '../../../utils';
import { useLayoutDnd } from '../../../hooks';
import { createPossibleMainFieldsForModelsAndComponents, getInputProps } from '../utils';
import { makeSelectModelAndComponentSchemas } from '../../App/selectors';
import getTrad from '../../../utils/getTrad';
import GenericInput from './GenericInput';
// Create a file
const iconByTypes = {
biginteger: <Number />,
boolean: <Boolean />,
date: <Date />,
datetime: <Date />,
decimal: <Number />,
email: <Email />,
enum: <Enumeration />,
enumeration: <Enumeration />,
file: <Media />,
files: <Media />,
float: <Number />,
integer: <Number />,
media: <Media />,
number: <Number />,
relation: <Relation />,
string: <Text />,
text: <Text />,
time: <Date />,
timestamp: <Date />,
json: <Json />,
uid: <Uid />,
component: <Component />,
dynamiczone: <DynamicZone />,
};
const HeaderContainer = styled(Flex)`
svg {
width: ${32 / 16}rem;
height: ${24 / 16}rem;
margin-right: ${({ theme }) => theme.spaces[3]};
}
`;
const ModalForm = ({ onToggle, onSubmit, type }) => {
const { selectedField } = useLayoutDnd();
const ModalForm = ({ onChange }) => {
const { formatMessage } = useIntl();
const { modifiedData, selectedField, attributes, fieldForm } = useLayoutDnd();
const schemasSelector = useMemo(makeSelectModelAndComponentSchemas, []);
const { schemas } = useSelector(state => schemasSelector(state), shallowEqual);
const getAttrType = () => {
if (type === 'timestamp') {
return 'date';
const formToDisplay = useMemo(() => {
if (!selectedField) {
return [];
}
if (['decimal', 'float', 'integer', 'biginter'].includes(type)) {
return 'number';
}
const associatedMetas = get(modifiedData, ['metadatas', selectedField, 'edit'], {});
return type;
};
return Object.keys(associatedMetas).filter(meta => meta !== 'visible');
}, [selectedField, modifiedData]);
return (
<ModalLayout onClose={onToggle} labelledBy="title">
<form onSubmit={onSubmit}>
<ModalHeader>
<HeaderContainer>
{iconByTypes[getAttrType(type)]}
<ButtonText textColor="neutral800" as="h2" id="title">
{formatMessage(
{
id: getTrad('containers.ListSettingsView.modal-form.edit-label'),
defaultMessage: 'Edit {fieldName}',
},
{ fieldName: upperFirst(selectedField) }
)}
</ButtonText>
</HeaderContainer>
</ModalHeader>
<ModalBody>
<Grid gap={4}>
<GridItem s={12} col={6}>
TO DO
</GridItem>
</Grid>
</ModalBody>
<ModalFooter
startActions={
<Button onClick={onToggle} variant="tertiary">
{formatMessage({ id: 'app.components.Button.cancel', defaultMessage: 'Cancel' })}
</Button>
}
endActions={
<Button type="submit">
{formatMessage({ id: 'form.button.finish', defaultMessage: 'Finish' })}
</Button>
}
/>
</form>
</ModalLayout>
const componentsAndModelsPossibleMainFields = useMemo(() => {
return createPossibleMainFieldsForModelsAndComponents(schemas);
}, [schemas]);
const getSelectedItemSelectOptions = useCallback(
formType => {
if (formType !== 'relation' && formType !== 'component') {
return [];
}
const targetKey = formType === 'component' ? 'component' : 'targetModel';
const key = get(modifiedData, ['attributes', selectedField, targetKey], '');
return get(componentsAndModelsPossibleMainFields, [key], []);
},
[selectedField, componentsAndModelsPossibleMainFields, modifiedData]
);
};
ModalForm.propTypes = {
onSubmit: PropTypes.func.isRequired,
onToggle: PropTypes.func.isRequired,
type: PropTypes.string.isRequired,
return formToDisplay.map(meta => {
const formType = get(attributes, [selectedField, 'type']);
if (formType === 'dynamiczone' && !['label', 'description'].includes(meta)) {
return null;
}
if ((formType === 'component' || formType === 'media') && meta !== 'label') {
return null;
}
if ((formType === 'json' || formType === 'boolean') && meta === 'placeholder') {
return null;
}
if (formType === 'richtext' && meta === 'editable') {
return null;
}
return (
<GridItem col={6} key={meta}>
<GenericInput
type={getInputProps(meta).type}
hint={
meta === 'mainField'
? formatMessage({
id: getTrad('containers.SettingPage.editSettings.relation-field.description'),
})
: ''
}
label={formatMessage({
id: get(getInputProps(meta), 'label.id', 'app.utils.defaultMessage'),
})}
name={meta}
onChange={onChange}
value={get(fieldForm, meta, '')}
options={getSelectedItemSelectOptions(formType)}
/>
</GridItem>
);
});
};
export default ModalForm;

View File

@ -1,5 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import get from 'lodash/get';
import { useIntl } from 'react-intl';
import { Button } from '@strapi/design-system/Button';
import { Box } from '@strapi/design-system/Box';
@ -9,6 +10,7 @@ import { SimpleMenu, MenuItem } from '@strapi/design-system/SimpleMenu';
import Plus from '@strapi/icons/Plus';
import { getTrad } from '../../../utils';
import FieldButton from './FieldButton';
import { useLayoutDnd } from '../../../hooks';
const RelationalFields = ({
relationsLayout,
@ -17,6 +19,7 @@ const RelationalFields = ({
onAddField,
}) => {
const { formatMessage } = useIntl();
const { setEditFieldToSelect, modifiedData } = useLayoutDnd();
return (
<Stack size={4}>
@ -41,21 +44,30 @@ const RelationalFields = ({
</div>
<Box padding={4} hasRadius borderStyle="dashed" borderWidth="1px" borderColor="neutral300">
<Stack size={2}>
{relationsLayout.map((relationName, index) => (
<FieldButton
onEditField={() => console.log(relationName)}
onDeleteField={() => onRemoveField(index)}
key={relationName}
>
{relationName}
</FieldButton>
))}
{relationsLayout.map((relationName, index) => {
const relationLabel = get(
modifiedData,
['metadatas', relationName, 'edit', 'label'],
''
);
return (
<FieldButton
onEditField={() => setEditFieldToSelect(relationName)}
onDeleteField={() => onRemoveField(index)}
key={relationName}
>
{relationLabel || relationName}
</FieldButton>
);
})}
<SimpleMenu
id="label"
label={formatMessage({
id: 'containers.SettingPage.add.relational-field',
defaultMessage: 'Insert another relational field',
})}
data-testid="add-relation"
as={Button}
fullWidth
startIcon={<Plus />}

View File

@ -1,10 +1,15 @@
import React, { useReducer, useState } from 'react';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import { useMutation } from 'react-query';
import upperFirst from 'lodash/upperFirst';
import pick from 'lodash/pick';
import cloneDeep from 'lodash/cloneDeep';
import flatMap from 'lodash/flatMap';
import isEqual from 'lodash/isEqual';
import get from 'lodash/get';
import set from 'lodash/set';
import { useNotification, useTracking, ConfirmDialog } from '@strapi/helper-plugin';
import { useHistory } from 'react-router-dom';
import { Main } from '@strapi/design-system/Main';
import { HeaderLayout, ContentLayout } from '@strapi/design-system/Layout';
@ -24,15 +29,20 @@ import reducer, { initialState } from './reducer';
import init from './init';
import DisplayedFields from './components/DisplayedFields';
import RelationalFields from './components/RelationalFields';
import ModalForm from './components/ModalForm';
import ModalForm from './components/FormModal';
import LayoutDndProvider from '../../components/LayoutDndProvider';
import { unformatLayout } from './utils/layout';
import putCMSettingsEV from './utils/api';
const EditSettingsView = ({ mainLayout, components, isContentTypeView, slug }) => {
const EditSettingsView = ({ mainLayout, components, isContentTypeView, slug, updateLayout }) => {
const [reducerState, dispatch] = useReducer(reducer, initialState, () =>
init(initialState, mainLayout, components)
);
const { trackUsage } = useTracking();
const toggleNotification = useNotification();
const { goBack } = useHistory();
const [isModalFormOpen, setIsModalFormOpen] = useState(false);
const [isConfirmDialogOpen, setIsConfirmDialogOpen] = useState(false);
const { componentLayouts, initialData, modifiedData, metaToEdit, metaForm } = reducerState;
const { formatMessage } = useIntl();
const modelName = get(mainLayout, ['info', isContentTypeView ? 'displayName' : 'name'], '');
@ -85,7 +95,60 @@ const EditSettingsView = ({ mainLayout, components, isContentTypeView, slug }) =
};
const handleToggleModal = () => {
setIsModalFormOpen(prevState => !prevState);
setIsModalFormOpen(prev => !prev);
};
const toggleConfirmDialog = () => {
setIsConfirmDialogOpen(prev => !prev);
};
const handleMetaChange = ({ target: { name, value } }) => {
dispatch({
type: 'ON_CHANGE_META',
keys: name.split('.'),
value,
});
};
const handleMetaSubmit = e => {
e.preventDefault();
dispatch({
type: 'SUBMIT_META_FORM',
});
handleToggleModal();
};
const handleSubmit = e => {
e.preventDefault();
toggleConfirmDialog();
};
const submitMutation = useMutation(
body => {
return putCMSettingsEV(body, slug, isContentTypeView);
},
{
onSuccess: ({ data }) => {
if (updateLayout) {
updateLayout(data.data);
}
dispatch({
type: 'SUBMIT_SUCCEEDED',
});
toggleConfirmDialog();
trackUsage('didEditEditSettings');
},
onError: () => {
toggleNotification({ type: 'warning', message: { id: 'notification.error' } });
},
}
);
const { isLoading: isSubmittingForm } = submitMutation;
const handleConfirm = () => {
const body = pick(cloneDeep(modifiedData), ['layouts', 'metadatas', 'settings']);
set(body, 'layouts.edit', unformatLayout(body.layouts.edit));
submitMutation.mutate(body);
};
return (
@ -115,135 +178,153 @@ const EditSettingsView = ({ mainLayout, components, isContentTypeView, slug }) =
{ name: upperFirst(modelName) }
)}
/>
<HeaderLayout
title={formatMessage(
{
id: getTrad('components.SettingsViewWrapper.pluginHeader.title'),
defaultMessage: `Configure the view - ${upperFirst(modelName)}`,
},
{ name: upperFirst(modelName) }
)}
subtitle={formatMessage({
id: getTrad('components.SettingsViewWrapper.pluginHeader.description.edit-settings'),
defaultMessage: 'Customize how the edit view will look like.',
})}
navigationAction={
<Link
startIcon={<ArrowLeft />}
onClick={e => {
e.preventDefault();
goBack();
}}
to="/"
>
{formatMessage({
id: 'app.components.go-back',
defaultMessage: 'Go back',
})}
</Link>
}
primaryAction={
<Button
disabled={isEqual(initialData, modifiedData)}
startIcon={<Check />}
type="submit"
>
{formatMessage({ id: 'form.button.save', defaultMessage: 'Save' })}
</Button>
}
/>
<ContentLayout>
<Box
background="neutral0"
hasRadius
shadow="filterShadow"
paddingTop={6}
paddingBottom={6}
paddingLeft={7}
paddingRight={7}
>
<Stack size={4}>
<H3 as="h2">
<form onSubmit={handleSubmit}>
<HeaderLayout
title={formatMessage(
{
id: getTrad('components.SettingsViewWrapper.pluginHeader.title'),
defaultMessage: `Configure the view - ${upperFirst(modelName)}`,
},
{ name: upperFirst(modelName) }
)}
subtitle={formatMessage({
id: getTrad('components.SettingsViewWrapper.pluginHeader.description.edit-settings'),
defaultMessage: 'Customize how the edit view will look like.',
})}
navigationAction={
<Link
startIcon={<ArrowLeft />}
onClick={e => {
e.preventDefault();
goBack();
}}
to="/"
>
{formatMessage({
id: getTrad('containers.SettingPage.settings'),
defaultMessage: 'Settings',
id: 'app.components.go-back',
defaultMessage: 'Go back',
})}
</H3>
<Grid>
<GridItem col={6} s={12}>
<Select
label={formatMessage({
id: getTrad('containers.SettingPage.editSettings.entry.title'),
defaultMessage: 'Entry title',
})}
hint={formatMessage({
id: getTrad('containers.SettingPage.editSettings.entry.title.description'),
defaultMessage: 'Set the display field of your entry',
})}
onChange={value => {
handleChange({
target: { name: 'settings.mainField', value: value === '' ? null : value },
});
}}
value={modifiedData.settings.mainField}
>
{entryTitleOptions.map(attribute => (
<Option key={attribute} value={attribute}>
{attribute}
</Option>
))}
</Select>
</GridItem>
</Grid>
<Box paddingTop={2} paddingBottom={2}>
<Divider />
</Box>
<H3>
{formatMessage({
id: getTrad('containers.SettingPage.view'),
defaultMessage: 'View',
})}
</H3>
<Grid gap={4}>
<GridItem col={isContentTypeView ? 8 : 12} s={12}>
<DisplayedFields
attributes={attributes}
editLayout={editLayout}
editLayoutRemainingFields={editLayoutRemainingFields}
onAddField={field => {
dispatch({
type: 'ON_ADD_FIELD',
name: field,
});
}}
onRemoveField={(rowId, index) => {
dispatch({
type: 'REMOVE_FIELD',
rowIndex: rowId,
fieldIndex: index,
});
}}
/>
</GridItem>
{isContentTypeView && (
<GridItem col={4} s={12}>
<RelationalFields
editRelationsLayoutRemainingFields={editRelationsLayoutRemainingFields}
relationsLayout={relationsLayout}
onAddField={name => dispatch({ type: 'ADD_RELATION', name })}
onRemoveField={index => dispatch({ type: 'REMOVE_RELATION', index })}
</Link>
}
primaryAction={
<Button
disabled={isEqual(initialData, modifiedData)}
startIcon={<Check />}
type="submit"
>
{formatMessage({ id: 'form.button.save', defaultMessage: 'Save' })}
</Button>
}
/>
<ContentLayout>
<Box
background="neutral0"
hasRadius
shadow="filterShadow"
paddingTop={6}
paddingBottom={6}
paddingLeft={7}
paddingRight={7}
>
<Stack size={4}>
<H3 as="h2">
{formatMessage({
id: getTrad('containers.SettingPage.settings'),
defaultMessage: 'Settings',
})}
</H3>
<Grid>
<GridItem col={6} s={12}>
<Select
label={formatMessage({
id: getTrad('containers.SettingPage.editSettings.entry.title'),
defaultMessage: 'Entry title',
})}
hint={formatMessage({
id: getTrad('containers.SettingPage.editSettings.entry.title.description'),
defaultMessage: 'Set the display field of your entry',
})}
onChange={value => {
handleChange({
target: {
name: 'settings.mainField',
value: value === '' ? null : value,
},
});
}}
value={modifiedData.settings.mainField}
>
{entryTitleOptions.map(attribute => (
<Option key={attribute} value={attribute}>
{attribute}
</Option>
))}
</Select>
</GridItem>
</Grid>
<Box paddingTop={2} paddingBottom={2}>
<Divider />
</Box>
<H3>
{formatMessage({
id: getTrad('containers.SettingPage.view'),
defaultMessage: 'View',
})}
</H3>
<Grid gap={4}>
<GridItem col={isContentTypeView ? 8 : 12} s={12}>
<DisplayedFields
attributes={attributes}
editLayout={editLayout}
editLayoutRemainingFields={editLayoutRemainingFields}
onAddField={field => {
dispatch({
type: 'ON_ADD_FIELD',
name: field,
});
}}
onRemoveField={(rowId, index) => {
dispatch({
type: 'REMOVE_FIELD',
rowIndex: rowId,
fieldIndex: index,
});
}}
/>
</GridItem>
)}
</Grid>
</Stack>
</Box>
</ContentLayout>
{isContentTypeView && (
<GridItem col={4} s={12}>
<RelationalFields
editRelationsLayoutRemainingFields={editRelationsLayoutRemainingFields}
relationsLayout={relationsLayout}
onAddField={name => dispatch({ type: 'ADD_RELATION', name })}
onRemoveField={index => dispatch({ type: 'REMOVE_RELATION', index })}
/>
</GridItem>
)}
</Grid>
</Stack>
</Box>
</ContentLayout>
<ConfirmDialog
bodyText={{
id: getTrad('popUpWarning.warning.updateAllSettings'),
defaultMessage: 'This will modify all your settings',
}}
iconRightButton={<Check />}
isConfirmButtonLoading={isSubmittingForm}
isOpen={isConfirmDialogOpen}
onToggleDialog={toggleConfirmDialog}
onConfirm={handleConfirm}
variantRightButton="success-light"
/>
</form>
{isModalFormOpen && (
<ModalForm
onSubmit={e => console.log(e)}
onSubmit={handleMetaSubmit}
onToggle={handleToggleModal}
type={get(attributes, [metaToEdit, 'type'], '')}
onChange={handleMetaChange}
/>
)}
</Main>
@ -253,6 +334,7 @@ const EditSettingsView = ({ mainLayout, components, isContentTypeView, slug }) =
EditSettingsView.defaultProps = {
isContentTypeView: false,
updateLayout: null,
};
EditSettingsView.propTypes = {
@ -270,6 +352,7 @@ EditSettingsView.propTypes = {
options: PropTypes.object.isRequired,
}).isRequired,
slug: PropTypes.string.isRequired,
updateLayout: PropTypes.func,
};
export default EditSettingsView;

View File

@ -0,0 +1,13 @@
import { axiosInstance } from '../../../../core/utils';
import { getRequestUrl } from '../../../utils';
const putCMSettingsEV = (body, slug, isContentTypeView) => {
return axiosInstance.put(
getRequestUrl(
isContentTypeView ? `content-types/${slug}/configuration` : `components/${slug}/configuration`
),
body
);
};
export default putCMSettingsEV;

View File

@ -15,39 +15,8 @@ import { Flex } from '@strapi/design-system/Flex';
import { Grid, GridItem } from '@strapi/design-system/Grid';
import { TextInput } from '@strapi/design-system/TextInput';
import { ToggleInput } from '@strapi/design-system/ToggleInput';
import Date from '@strapi/icons/Date';
import Boolean from '@strapi/icons/Boolean';
import Email from '@strapi/icons/Email';
import Enumeration from '@strapi/icons/Enumeration';
import Media from '@strapi/icons/Media';
import Relation from '@strapi/icons/Relation';
import Text from '@strapi/icons/Text';
import Uid from '@strapi/icons/Uid';
import Number from '@strapi/icons/Number';
import { getTrad } from '../../../utils';
const iconByTypes = {
biginteger: <Number />,
boolean: <Boolean />,
date: <Date />,
datetime: <Date />,
decimal: <Number />,
email: <Email />,
enum: <Enumeration />,
enumeration: <Enumeration />,
file: <Media />,
files: <Media />,
float: <Number />,
integer: <Number />,
media: <Media />,
number: <Number />,
relation: <Relation />,
string: <Text />,
text: <Text />,
time: <Date />,
timestamp: <Date />,
uid: <Uid />,
};
import FieldTypeIcon from '../../../components/FieldTypeIcon';
const HeaderContainer = styled(Flex)`
svg {
@ -81,7 +50,7 @@ const EditFieldForm = ({
<form onSubmit={onSubmit}>
<ModalHeader>
<HeaderContainer>
{iconByTypes[type]}
<FieldTypeIcon type={type} />
<ButtonText textColor="neutral800" as="h2" id="title">
{formatMessage(
{