mirror of
https://github.com/strapi/strapi.git
synced 2025-09-22 14:59:07 +00:00
Merge branch 'v4/ds-migration' of github.com:strapi/strapi into v4/ds-migration
This commit is contained in:
commit
e0184b62b1
@ -304,6 +304,14 @@ const EditViewDataManagerProvider = ({
|
|||||||
console.error(err);
|
console.error(err);
|
||||||
|
|
||||||
errors = getYupInnerErrors(err);
|
errors = getYupInnerErrors(err);
|
||||||
|
|
||||||
|
toggleNotification({
|
||||||
|
type: 'warning',
|
||||||
|
message: {
|
||||||
|
id: getTrad('containers.EditView.notification.errors'),
|
||||||
|
defaultMessage: 'The form contains some errors',
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
@ -311,7 +319,16 @@ const EditViewDataManagerProvider = ({
|
|||||||
errors,
|
errors,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[createFormData, isCreatingEntry, modifiedData, onPost, onPut, trackerProperty, yupSchema]
|
[
|
||||||
|
createFormData,
|
||||||
|
isCreatingEntry,
|
||||||
|
modifiedData,
|
||||||
|
onPost,
|
||||||
|
onPut,
|
||||||
|
toggleNotification,
|
||||||
|
trackerProperty,
|
||||||
|
yupSchema,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handlePublish = useCallback(async () => {
|
const handlePublish = useCallback(async () => {
|
||||||
|
@ -295,6 +295,14 @@ const createYupSchemaAttribute = (type, validations, options) => {
|
|||||||
return value !== null;
|
return value !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type === 'date' || type === 'datetime') {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
return !isEmpty(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return !isEmpty(value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
return !isEmpty(value);
|
return !isEmpty(value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ const Label = ({ intlLabel, id, labelAction, name, numberOfEntries, showNumberOf
|
|||||||
const label = intlLabel?.id ? formatMessage(intlLabel) : '';
|
const label = intlLabel?.id ? formatMessage(intlLabel) : '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<Box paddingBottom={1}>
|
||||||
<Row>
|
<Row>
|
||||||
<Text textColor="neutral800" htmlFor={id || name} small bold as="label">
|
<Text textColor="neutral800" htmlFor={id || name} small bold as="label">
|
||||||
{label}
|
{label}
|
||||||
@ -24,6 +25,7 @@ const Label = ({ intlLabel, id, labelAction, name, numberOfEntries, showNumberOf
|
|||||||
</Text>
|
</Text>
|
||||||
{labelAction && <LabelAction paddingLeft={1}>{labelAction}</LabelAction>}
|
{labelAction && <LabelAction paddingLeft={1}>{labelAction}</LabelAction>}
|
||||||
</Row>
|
</Row>
|
||||||
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -59,7 +59,6 @@ const FieldComponent = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Stack size={1}>
|
|
||||||
<Row justifyContent="space-between">
|
<Row justifyContent="space-between">
|
||||||
{intlLabel && (
|
{intlLabel && (
|
||||||
<Label
|
<Label
|
||||||
@ -78,12 +77,14 @@ const FieldComponent = ({
|
|||||||
defaultMessage: 'Reset Entry',
|
defaultMessage: 'Reset Entry',
|
||||||
})}
|
})}
|
||||||
icon={<DeleteIcon />}
|
icon={<DeleteIcon />}
|
||||||
|
noBorder
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
removeComponentFromField(name, componentUid);
|
removeComponentFromField(name, componentUid);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Row>
|
</Row>
|
||||||
|
<Stack size={1}>
|
||||||
{!isRepeatable && !isInitialized && (
|
{!isRepeatable && !isInitialized && (
|
||||||
<ComponentInitializer
|
<ComponentInitializer
|
||||||
isReadOnly={isReadOnly}
|
isReadOnly={isReadOnly}
|
||||||
@ -94,6 +95,7 @@ const FieldComponent = ({
|
|||||||
<NonRepeatableComponent
|
<NonRepeatableComponent
|
||||||
componentUid={componentUid}
|
componentUid={componentUid}
|
||||||
isFromDynamicZone={isFromDynamicZone}
|
isFromDynamicZone={isFromDynamicZone}
|
||||||
|
isNested={isNested}
|
||||||
name={name}
|
name={name}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -18,7 +18,7 @@ const CominSoonInput = ({ description, intlLabel, labelAction, error, name }) =>
|
|||||||
)
|
)
|
||||||
: name;
|
: name;
|
||||||
|
|
||||||
const hint = description
|
const hint = description?.id
|
||||||
? formatMessage(
|
? formatMessage(
|
||||||
{ id: description.id, defaultMessage: description.defaultMessage },
|
{ id: description.id, defaultMessage: description.defaultMessage },
|
||||||
{ ...description.values }
|
{ ...description.values }
|
||||||
|
@ -10,7 +10,7 @@ import { useContentTypeLayout } from '../../hooks';
|
|||||||
import FieldComponent from '../FieldComponent';
|
import FieldComponent from '../FieldComponent';
|
||||||
import Inputs from '../Inputs';
|
import Inputs from '../Inputs';
|
||||||
|
|
||||||
const NonRepeatableComponent = ({ componentUid, name }) => {
|
const NonRepeatableComponent = ({ componentUid, isFromDynamicZone, isNested, name }) => {
|
||||||
const { getComponentLayout } = useContentTypeLayout();
|
const { getComponentLayout } = useContentTypeLayout();
|
||||||
const componentLayoutData = useMemo(() => getComponentLayout(componentUid), [
|
const componentLayoutData = useMemo(() => getComponentLayout(componentUid), [
|
||||||
componentUid,
|
componentUid,
|
||||||
@ -19,7 +19,15 @@ const NonRepeatableComponent = ({ componentUid, name }) => {
|
|||||||
const fields = componentLayoutData.layouts.edit;
|
const fields = componentLayoutData.layouts.edit;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box background="neutral100" paddingLeft={6} paddingRight={6} paddingTop={6} paddingBottom={6}>
|
<Box
|
||||||
|
background={isFromDynamicZone ? 'neutral0' : 'neutral100'}
|
||||||
|
paddingLeft={6}
|
||||||
|
paddingRight={6}
|
||||||
|
paddingTop={6}
|
||||||
|
paddingBottom={6}
|
||||||
|
hasRadius={isNested}
|
||||||
|
borderColor={isNested ? 'neutral200' : ''}
|
||||||
|
>
|
||||||
<Stack size={6}>
|
<Stack size={6}>
|
||||||
{fields.map((fieldRow, key) => {
|
{fields.map((fieldRow, key) => {
|
||||||
return (
|
return (
|
||||||
@ -39,6 +47,7 @@ const NonRepeatableComponent = ({ componentUid, name }) => {
|
|||||||
id: metadatas.label,
|
id: metadatas.label,
|
||||||
defaultMessage: metadatas.label,
|
defaultMessage: metadatas.label,
|
||||||
}}
|
}}
|
||||||
|
isNested
|
||||||
isRepeatable={fieldSchema.repeatable}
|
isRepeatable={fieldSchema.repeatable}
|
||||||
max={fieldSchema.max}
|
max={fieldSchema.max}
|
||||||
min={fieldSchema.min}
|
min={fieldSchema.min}
|
||||||
@ -67,8 +76,15 @@ const NonRepeatableComponent = ({ componentUid, name }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
NonRepeatableComponent.defaultProps = {
|
||||||
|
isFromDynamicZone: false,
|
||||||
|
isNested: false,
|
||||||
|
};
|
||||||
|
|
||||||
NonRepeatableComponent.propTypes = {
|
NonRepeatableComponent.propTypes = {
|
||||||
componentUid: PropTypes.string.isRequired,
|
componentUid: PropTypes.string.isRequired,
|
||||||
|
isFromDynamicZone: PropTypes.bool,
|
||||||
|
isNested: PropTypes.bool,
|
||||||
name: PropTypes.string.isRequired,
|
name: PropTypes.string.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,27 +1,37 @@
|
|||||||
import React, { useCallback, useState, useEffect, useMemo, memo } from 'react';
|
import React, { useCallback, useState, useEffect, useMemo, memo } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { FormattedMessage, useIntl } from 'react-intl';
|
|
||||||
import { Link, useLocation } from 'react-router-dom';
|
|
||||||
import { findIndex, get, isArray, isEmpty, set } from 'lodash';
|
|
||||||
import {
|
import {
|
||||||
DropdownIndicator,
|
// FormattedMessage,
|
||||||
LabelIconWrapper,
|
useIntl,
|
||||||
|
} from 'react-intl';
|
||||||
|
// import { Link, useLocation } from 'react-router-dom';
|
||||||
|
// import { findIndex, get, isArray, isEmpty, set } from 'lodash';
|
||||||
|
import get from 'lodash/get';
|
||||||
|
import isArray from 'lodash/isArray';
|
||||||
|
import {
|
||||||
|
// DropdownIndicator,
|
||||||
|
|
||||||
NotAllowedInput,
|
NotAllowedInput,
|
||||||
useCMEditViewDataManager,
|
useCMEditViewDataManager,
|
||||||
useQueryParams,
|
// useQueryParams,
|
||||||
} from '@strapi/helper-plugin';
|
} from '@strapi/helper-plugin';
|
||||||
import { Flex, Text, Padded } from '@buffetjs/core';
|
// import { Flex, Text, Padded } from '@buffetjs/core';
|
||||||
import { stringify } from 'qs';
|
// import { stringify } from 'qs';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { axiosInstance } from '../../../core/utils';
|
import { axiosInstance } from '../../../core/utils';
|
||||||
import { getTrad } from '../../utils';
|
// import { getTrad } from '../../utils';
|
||||||
import SelectOne from '../SelectOne';
|
import ComingSoonInput from '../Inputs/ComingSoonInput';
|
||||||
import SelectMany from '../SelectMany';
|
// import SelectOne from '../SelectOne';
|
||||||
import ClearIndicator from './ClearIndicator';
|
// import SelectMany from '../SelectMany';
|
||||||
import IndicatorSeparator from './IndicatorSeparator';
|
// import ClearIndicator from './ClearIndicator';
|
||||||
import Option from './Option';
|
// import IndicatorSeparator from './IndicatorSeparator';
|
||||||
import { A, BaselineAlignment } from './components';
|
// import Option from './Option';
|
||||||
import { connect, select, styles } from './utils';
|
// import { A, BaselineAlignment } from './components';
|
||||||
|
import {
|
||||||
|
connect,
|
||||||
|
select,
|
||||||
|
// styles
|
||||||
|
} from './utils';
|
||||||
|
|
||||||
const initialPaginationState = {
|
const initialPaginationState = {
|
||||||
_contains: '',
|
_contains: '',
|
||||||
@ -29,77 +39,89 @@ const initialPaginationState = {
|
|||||||
_start: 0,
|
_start: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildParams = (query, paramsToKeep) => {
|
// const buildParams = (query, paramsToKeep) => {
|
||||||
if (!paramsToKeep) {
|
// if (!paramsToKeep) {
|
||||||
return {};
|
// return {};
|
||||||
}
|
// }
|
||||||
|
|
||||||
return paramsToKeep.reduce((acc, current) => {
|
// return paramsToKeep.reduce((acc, current) => {
|
||||||
const value = get(query, current, null);
|
// const value = get(query, current, null);
|
||||||
|
|
||||||
if (value) {
|
// if (value) {
|
||||||
set(acc, current, value);
|
// set(acc, current, value);
|
||||||
}
|
// }
|
||||||
|
|
||||||
return acc;
|
// return acc;
|
||||||
}, {});
|
// }, {});
|
||||||
};
|
// };
|
||||||
function SelectWrapper({
|
function SelectWrapper({
|
||||||
description,
|
description,
|
||||||
editable,
|
// editable,
|
||||||
label,
|
labelAction,
|
||||||
labelIcon,
|
intlLabel,
|
||||||
isCreatingEntry,
|
isCreatingEntry,
|
||||||
isFieldAllowed,
|
isFieldAllowed,
|
||||||
isFieldReadable,
|
isFieldReadable,
|
||||||
mainField,
|
mainField,
|
||||||
name,
|
name,
|
||||||
relationType,
|
relationType,
|
||||||
targetModel,
|
// targetModel,
|
||||||
placeholder,
|
// placeholder,
|
||||||
queryInfos,
|
queryInfos,
|
||||||
}) {
|
}) {
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
const [{ query }] = useQueryParams();
|
// const [{ query }] = useQueryParams();
|
||||||
// Disable the input in case of a polymorphic relation
|
// Disable the input in case of a polymorphic relation
|
||||||
const isMorph = useMemo(() => relationType.toLowerCase().includes('morph'), [relationType]);
|
const isMorph = useMemo(() => relationType.toLowerCase().includes('morph'), [relationType]);
|
||||||
const {
|
const {
|
||||||
addRelation,
|
// addRelation,
|
||||||
modifiedData,
|
modifiedData,
|
||||||
moveRelation,
|
// moveRelation,
|
||||||
onChange,
|
// onChange,
|
||||||
onRemoveRelation,
|
// onRemoveRelation,
|
||||||
} = useCMEditViewDataManager();
|
} = useCMEditViewDataManager();
|
||||||
const { pathname } = useLocation();
|
// const { pathname } = useLocation();
|
||||||
|
|
||||||
const value = get(modifiedData, name, null);
|
const value = get(modifiedData, name, null);
|
||||||
const [state, setState] = useState(initialPaginationState);
|
const [
|
||||||
const [options, setOptions] = useState([]);
|
state,
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
// setState
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
] = useState(initialPaginationState);
|
||||||
|
const [
|
||||||
|
// options,
|
||||||
|
setOptions,
|
||||||
|
] = useState([]);
|
||||||
|
const [
|
||||||
|
// isLoading,
|
||||||
|
setIsLoading,
|
||||||
|
] = useState(false);
|
||||||
|
const [
|
||||||
|
isOpen,
|
||||||
|
// setIsOpen
|
||||||
|
] = useState(false);
|
||||||
|
|
||||||
const filteredOptions = useMemo(() => {
|
// const filteredOptions = useMemo(() => {
|
||||||
return options.filter(option => {
|
// return options.filter(option => {
|
||||||
if (!isEmpty(value)) {
|
// if (!isEmpty(value)) {
|
||||||
// SelectMany
|
// // SelectMany
|
||||||
if (Array.isArray(value)) {
|
// if (Array.isArray(value)) {
|
||||||
return findIndex(value, o => o.id === option.value.id) === -1;
|
// return findIndex(value, o => o.id === option.value.id) === -1;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// SelectOne
|
// // SelectOne
|
||||||
return get(value, 'id', '') !== option.value.id;
|
// return get(value, 'id', '') !== option.value.id;
|
||||||
}
|
// }
|
||||||
|
|
||||||
return true;
|
// return true;
|
||||||
});
|
// });
|
||||||
}, [options, value]);
|
// }, [options, value]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
endPoint,
|
endPoint,
|
||||||
containsKey,
|
containsKey,
|
||||||
defaultParams,
|
defaultParams,
|
||||||
shouldDisplayRelationLink,
|
// shouldDisplayRelationLink,
|
||||||
paramsToKeep,
|
// paramsToKeep,
|
||||||
} = queryInfos;
|
} = queryInfos;
|
||||||
|
|
||||||
const isSingle = ['oneWay', 'oneToOne', 'manyToOne', 'oneToManyMorph', 'oneToOneMorph'].includes(
|
const isSingle = ['oneWay', 'oneToOne', 'manyToOne', 'oneToManyMorph', 'oneToOneMorph'].includes(
|
||||||
@ -170,15 +192,17 @@ function SelectWrapper({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
isMorph,
|
|
||||||
isFieldAllowed,
|
|
||||||
state._limit,
|
|
||||||
state._contains,
|
|
||||||
defaultParams,
|
|
||||||
containsKey,
|
containsKey,
|
||||||
|
defaultParams,
|
||||||
endPoint,
|
endPoint,
|
||||||
idsToOmit,
|
idsToOmit,
|
||||||
|
isFieldAllowed,
|
||||||
|
isMorph,
|
||||||
mainField.name,
|
mainField.name,
|
||||||
|
setIsLoading,
|
||||||
|
setOptions,
|
||||||
|
state._contains,
|
||||||
|
state._limit,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -193,180 +217,198 @@ function SelectWrapper({
|
|||||||
return () => source.cancel('Operation canceled by the user.');
|
return () => source.cancel('Operation canceled by the user.');
|
||||||
}, [getData, isOpen]);
|
}, [getData, isOpen]);
|
||||||
|
|
||||||
const handleInputChange = (inputValue, { action }) => {
|
// const handleInputChange = (inputValue, { action }) => {
|
||||||
if (action === 'input-change') {
|
// if (action === 'input-change') {
|
||||||
setState(prevState => {
|
// setState(prevState => {
|
||||||
if (prevState._contains === inputValue) {
|
// if (prevState._contains === inputValue) {
|
||||||
return prevState;
|
// return prevState;
|
||||||
}
|
// }
|
||||||
|
|
||||||
return { ...prevState, _contains: inputValue, _start: 0 };
|
// return { ...prevState, _contains: inputValue, _start: 0 };
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
return inputValue;
|
// return inputValue;
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleMenuScrollToBottom = () => {
|
// const handleMenuScrollToBottom = () => {
|
||||||
setState(prevState => ({ ...prevState, _limit: prevState._limit + 20 }));
|
// setState(prevState => ({ ...prevState, _limit: prevState._limit + 20 }));
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleMenuClose = () => {
|
// const handleMenuClose = () => {
|
||||||
setState(initialPaginationState);
|
// setState(initialPaginationState);
|
||||||
setIsOpen(false);
|
// setIsOpen(false);
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleChange = value => {
|
// const handleChange = value => {
|
||||||
onChange({ target: { name, value: value ? value.value : value } });
|
// onChange({ target: { name, value: value ? value.value : value } });
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleAddRelation = value => {
|
// const handleAddRelation = value => {
|
||||||
if (!isEmpty(value)) {
|
// if (!isEmpty(value)) {
|
||||||
addRelation({ target: { name, value } });
|
// addRelation({ target: { name, value } });
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleMenuOpen = () => {
|
// const handleMenuOpen = () => {
|
||||||
setIsOpen(true);
|
// setIsOpen(true);
|
||||||
};
|
// };
|
||||||
|
|
||||||
const to = `/content-manager/collectionType/${targetModel}/${value ? value.id : null}`;
|
// const to = `/content-manager/collectionType/${targetModel}/${value ? value.id : null}`;
|
||||||
|
|
||||||
const searchToPersist = stringify(buildParams(query, paramsToKeep), { encode: false });
|
// const searchToPersist = stringify(buildParams(query, paramsToKeep), { encode: false });
|
||||||
|
|
||||||
const link = useMemo(() => {
|
// const link = useMemo(() => {
|
||||||
if (!value) {
|
// if (!value) {
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (!shouldDisplayRelationLink) {
|
// if (!shouldDisplayRelationLink) {
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
|
|
||||||
return (
|
// return (
|
||||||
<Link to={{ pathname: to, state: { from: pathname }, search: searchToPersist }}>
|
// <Link to={{ pathname: to, state: { from: pathname }, search: searchToPersist }}>
|
||||||
<FormattedMessage id="content-manager.containers.Edit.seeDetails">
|
// <FormattedMessage id="content-manager.containers.Edit.seeDetails">
|
||||||
{msg => <A color="mediumBlue">{msg}</A>}
|
// {msg => <A color="mediumBlue">{msg}</A>}
|
||||||
</FormattedMessage>
|
// </FormattedMessage>
|
||||||
</Link>
|
// </Link>
|
||||||
);
|
// );
|
||||||
}, [shouldDisplayRelationLink, pathname, to, value, searchToPersist]);
|
// }, [shouldDisplayRelationLink, pathname, to, value, searchToPersist]);
|
||||||
|
|
||||||
const Component = isSingle ? SelectOne : SelectMany;
|
// const Component = isSingle ? SelectOne : SelectMany;
|
||||||
const associationsLength = isArray(value) ? value.length : 0;
|
const associationsLength = isArray(value) ? value.length : 0;
|
||||||
|
|
||||||
const isDisabled = useMemo(() => {
|
// const isDisabled = useMemo(() => {
|
||||||
if (isMorph) {
|
// if (isMorph) {
|
||||||
return true;
|
// return true;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (!isCreatingEntry) {
|
// if (!isCreatingEntry) {
|
||||||
return (!isFieldAllowed && isFieldReadable) || !editable;
|
// return (!isFieldAllowed && isFieldReadable) || !editable;
|
||||||
}
|
// }
|
||||||
|
|
||||||
return !editable;
|
// return !editable;
|
||||||
}, [isMorph, isCreatingEntry, editable, isFieldAllowed, isFieldReadable]);
|
// }, [isMorph, isCreatingEntry, editable, isFieldAllowed, isFieldReadable]);
|
||||||
|
|
||||||
const labelIconformatted = labelIcon
|
const multipleLabel = intlLabel.id
|
||||||
? { icon: labelIcon.icon, title: formatMessage(labelIcon.title) }
|
? formatMessage({ id: intlLabel.id, defaultMessage: intlLabel.defaultMessage })
|
||||||
: labelIcon;
|
: name;
|
||||||
|
const formattedLabel = isSingle
|
||||||
|
? intlLabel
|
||||||
|
: {
|
||||||
|
// Custom trad id in order to add the label count
|
||||||
|
id: 'relations-label',
|
||||||
|
defaultMessage: '{label} ({count})',
|
||||||
|
values: { label: multipleLabel, count: associationsLength },
|
||||||
|
};
|
||||||
|
|
||||||
if (!isFieldAllowed && isCreatingEntry) {
|
if (!isFieldAllowed && isCreatingEntry) {
|
||||||
return <NotAllowedInput label={label} labelIcon={labelIconformatted} />;
|
return <NotAllowedInput intlLabel={intlLabel} labelAction={labelAction} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isCreatingEntry && !isFieldAllowed && !isFieldReadable) {
|
if (!isCreatingEntry && !isFieldAllowed && !isFieldReadable) {
|
||||||
return <NotAllowedInput label={label} labelIcon={labelIconformatted} />;
|
return <NotAllowedInput intlLabel={intlLabel} labelAction={labelAction} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Padded>
|
<ComingSoonInput
|
||||||
<BaselineAlignment />
|
intlLabel={formattedLabel}
|
||||||
<Flex justifyContent="space-between">
|
labelAction={labelAction}
|
||||||
<Flex>
|
description={description}
|
||||||
<Text fontWeight="semiBold">
|
|
||||||
<span>
|
|
||||||
{label}
|
|
||||||
{!isSingle && ` (${associationsLength})`}
|
|
||||||
</span>
|
|
||||||
</Text>
|
|
||||||
{labelIconformatted && (
|
|
||||||
<div style={{ lineHeight: '13px' }}>
|
|
||||||
<LabelIconWrapper title={labelIconformatted.title}>
|
|
||||||
{labelIconformatted.icon}
|
|
||||||
</LabelIconWrapper>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Flex>
|
|
||||||
{isSingle && link}
|
|
||||||
</Flex>
|
|
||||||
{!isEmpty(description) && (
|
|
||||||
<Padded top size="xs">
|
|
||||||
<BaselineAlignment />
|
|
||||||
<Text fontSize="sm" color="grey" lineHeight="12px" ellipsis>
|
|
||||||
{description}
|
|
||||||
</Text>
|
|
||||||
</Padded>
|
|
||||||
)}
|
|
||||||
<Padded top size="sm">
|
|
||||||
<BaselineAlignment />
|
|
||||||
|
|
||||||
<Component
|
|
||||||
addRelation={handleAddRelation}
|
|
||||||
components={{ ClearIndicator, DropdownIndicator, IndicatorSeparator, Option }}
|
|
||||||
displayNavigationLink={shouldDisplayRelationLink}
|
|
||||||
id={name}
|
|
||||||
isDisabled={isDisabled}
|
|
||||||
isLoading={isLoading}
|
|
||||||
isClearable
|
|
||||||
mainField={mainField}
|
|
||||||
move={moveRelation}
|
|
||||||
name={name}
|
name={name}
|
||||||
options={filteredOptions}
|
|
||||||
onChange={handleChange}
|
|
||||||
onInputChange={handleInputChange}
|
|
||||||
onMenuClose={handleMenuClose}
|
|
||||||
onMenuOpen={handleMenuOpen}
|
|
||||||
onMenuScrollToBottom={handleMenuScrollToBottom}
|
|
||||||
onRemove={onRemoveRelation}
|
|
||||||
placeholder={
|
|
||||||
isEmpty(placeholder) ? (
|
|
||||||
<FormattedMessage id={getTrad('containers.Edit.addAnItem')} />
|
|
||||||
) : (
|
|
||||||
placeholder
|
|
||||||
)
|
|
||||||
}
|
|
||||||
searchToPersist={searchToPersist}
|
|
||||||
styles={styles}
|
|
||||||
targetModel={targetModel}
|
|
||||||
value={value}
|
|
||||||
/>
|
/>
|
||||||
</Padded>
|
|
||||||
<div style={{ marginBottom: 28 }} />
|
|
||||||
</Padded>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// return (
|
||||||
|
// <Padded>
|
||||||
|
// <BaselineAlignment />
|
||||||
|
// <Flex justifyContent="space-between">
|
||||||
|
// <Flex>
|
||||||
|
// <Text fontWeight="semiBold">
|
||||||
|
// <span>
|
||||||
|
// {label}
|
||||||
|
// {!isSingle && ` (${associationsLength})`}
|
||||||
|
// </span>
|
||||||
|
// </Text>
|
||||||
|
// {labelIconformatted && (
|
||||||
|
// <div style={{ lineHeight: '13px' }}>
|
||||||
|
// <LabelIconWrapper title={labelIconformatted.title}>
|
||||||
|
// {labelIconformatted.icon}
|
||||||
|
// </LabelIconWrapper>
|
||||||
|
// </div>
|
||||||
|
// )}
|
||||||
|
// </Flex>
|
||||||
|
// {isSingle && link}
|
||||||
|
// </Flex>
|
||||||
|
// {!isEmpty(description) && (
|
||||||
|
// <Padded top size="xs">
|
||||||
|
// <BaselineAlignment />
|
||||||
|
// <Text fontSize="sm" color="grey" lineHeight="12px" ellipsis>
|
||||||
|
// {description}
|
||||||
|
// </Text>
|
||||||
|
// </Padded>
|
||||||
|
// )}
|
||||||
|
// <Padded top size="sm">
|
||||||
|
// <BaselineAlignment />
|
||||||
|
|
||||||
|
// <Component
|
||||||
|
// addRelation={handleAddRelation}
|
||||||
|
// components={{ ClearIndicator, DropdownIndicator, IndicatorSeparator, Option }}
|
||||||
|
// displayNavigationLink={shouldDisplayRelationLink}
|
||||||
|
// id={name}
|
||||||
|
// isDisabled={isDisabled}
|
||||||
|
// isLoading={isLoading}
|
||||||
|
// isClearable
|
||||||
|
// mainField={mainField}
|
||||||
|
// move={moveRelation}
|
||||||
|
// name={name}
|
||||||
|
// options={filteredOptions}
|
||||||
|
// onChange={handleChange}
|
||||||
|
// onInputChange={handleInputChange}
|
||||||
|
// onMenuClose={handleMenuClose}
|
||||||
|
// onMenuOpen={handleMenuOpen}
|
||||||
|
// onMenuScrollToBottom={handleMenuScrollToBottom}
|
||||||
|
// onRemove={onRemoveRelation}
|
||||||
|
// placeholder={
|
||||||
|
// isEmpty(placeholder) ? (
|
||||||
|
// <FormattedMessage id={getTrad('containers.Edit.addAnItem')} />
|
||||||
|
// ) : (
|
||||||
|
// placeholder
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// searchToPersist={searchToPersist}
|
||||||
|
// styles={styles}
|
||||||
|
// targetModel={targetModel}
|
||||||
|
// value={value}
|
||||||
|
// />
|
||||||
|
// </Padded>
|
||||||
|
// <div style={{ marginBottom: 28 }} />
|
||||||
|
// </Padded>
|
||||||
|
// );
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectWrapper.defaultProps = {
|
SelectWrapper.defaultProps = {
|
||||||
editable: true,
|
// editable: true,
|
||||||
description: '',
|
description: '',
|
||||||
label: '',
|
labelAction: null,
|
||||||
labelIcon: null,
|
|
||||||
isFieldAllowed: true,
|
isFieldAllowed: true,
|
||||||
placeholder: '',
|
// placeholder: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
SelectWrapper.propTypes = {
|
SelectWrapper.propTypes = {
|
||||||
editable: PropTypes.bool,
|
// editable: PropTypes.bool,
|
||||||
description: PropTypes.string,
|
description: PropTypes.shape({
|
||||||
label: PropTypes.string,
|
|
||||||
labelIcon: PropTypes.shape({
|
|
||||||
icon: PropTypes.node.isRequired,
|
|
||||||
title: PropTypes.shape({
|
|
||||||
id: PropTypes.string.isRequired,
|
id: PropTypes.string.isRequired,
|
||||||
defaultMessage: PropTypes.string,
|
defaultMessage: PropTypes.string.isRequired,
|
||||||
}),
|
values: PropTypes.object,
|
||||||
}),
|
}),
|
||||||
|
intlLabel: PropTypes.shape({
|
||||||
|
id: PropTypes.string.isRequired,
|
||||||
|
defaultMessage: PropTypes.string.isRequired,
|
||||||
|
values: PropTypes.object,
|
||||||
|
}).isRequired,
|
||||||
|
labelAction: PropTypes.element,
|
||||||
isCreatingEntry: PropTypes.bool.isRequired,
|
isCreatingEntry: PropTypes.bool.isRequired,
|
||||||
isFieldAllowed: PropTypes.bool,
|
isFieldAllowed: PropTypes.bool,
|
||||||
isFieldReadable: PropTypes.bool.isRequired,
|
isFieldReadable: PropTypes.bool.isRequired,
|
||||||
@ -377,9 +419,13 @@ SelectWrapper.propTypes = {
|
|||||||
}).isRequired,
|
}).isRequired,
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
name: PropTypes.string.isRequired,
|
name: PropTypes.string.isRequired,
|
||||||
placeholder: PropTypes.string,
|
// placeholder: PropTypes.shape({
|
||||||
|
// id: PropTypes.string.isRequired,
|
||||||
|
// defaultMessage: PropTypes.string.isRequired,
|
||||||
|
// values: PropTypes.object,
|
||||||
|
// }),
|
||||||
relationType: PropTypes.string.isRequired,
|
relationType: PropTypes.string.isRequired,
|
||||||
targetModel: PropTypes.string.isRequired,
|
// targetModel: PropTypes.string.isRequired,
|
||||||
queryInfos: PropTypes.shape({
|
queryInfos: PropTypes.shape({
|
||||||
containsKey: PropTypes.string.isRequired,
|
containsKey: PropTypes.string.isRequired,
|
||||||
defaultParams: PropTypes.object,
|
defaultParams: PropTypes.object,
|
||||||
|
@ -5,10 +5,12 @@ import { CheckPermissions, useTracking } from '@strapi/helper-plugin';
|
|||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
import { ContentLayout } from '@strapi/parts/Layout';
|
import { ContentLayout } from '@strapi/parts/Layout';
|
||||||
import { Box } from '@strapi/parts/Box';
|
import { Box } from '@strapi/parts/Box';
|
||||||
|
import { Divider } from '@strapi/parts/Divider';
|
||||||
import { Grid, GridItem } from '@strapi/parts/Grid';
|
import { Grid, GridItem } from '@strapi/parts/Grid';
|
||||||
import { LinkButton } from '@strapi/parts/LinkButton';
|
import { LinkButton } from '@strapi/parts/LinkButton';
|
||||||
import { Main } from '@strapi/parts/Main';
|
import { Main } from '@strapi/parts/Main';
|
||||||
import { Stack } from '@strapi/parts/Stack';
|
import { Stack } from '@strapi/parts/Stack';
|
||||||
|
import { TableLabel } from '@strapi/parts/Text';
|
||||||
import ConfigureIcon from '@strapi/icons/ConfigureIcon';
|
import ConfigureIcon from '@strapi/icons/ConfigureIcon';
|
||||||
import EditIcon from '@strapi/icons/EditIcon';
|
import EditIcon from '@strapi/icons/EditIcon';
|
||||||
import { InjectionZone } from '../../../shared/components';
|
import { InjectionZone } from '../../../shared/components';
|
||||||
@ -18,7 +20,7 @@ import DynamicZone from '../../components/DynamicZone';
|
|||||||
// import FormWrapper from '../../components/FormWrapper';
|
// import FormWrapper from '../../components/FormWrapper';
|
||||||
import FieldComponent from '../../components/FieldComponent';
|
import FieldComponent from '../../components/FieldComponent';
|
||||||
import Inputs from '../../components/Inputs';
|
import Inputs from '../../components/Inputs';
|
||||||
// import SelectWrapper from '../../components/SelectWrapper';
|
import SelectWrapper from '../../components/SelectWrapper';
|
||||||
import CollectionTypeFormWrapper from '../../components/CollectionTypeFormWrapper';
|
import CollectionTypeFormWrapper from '../../components/CollectionTypeFormWrapper';
|
||||||
import EditViewDataManagerProvider from '../../components/EditViewDataManagerProvider';
|
import EditViewDataManagerProvider from '../../components/EditViewDataManagerProvider';
|
||||||
import SingleTypeFormWrapper from '../../components/SingleTypeFormWrapper';
|
import SingleTypeFormWrapper from '../../components/SingleTypeFormWrapper';
|
||||||
@ -88,6 +90,9 @@ const EditView = ({
|
|||||||
);
|
);
|
||||||
}, [currentContentTypeLayoutData]);
|
}, [currentContentTypeLayoutData]);
|
||||||
|
|
||||||
|
const relationsLayout = currentContentTypeLayoutData.layouts.editRelations;
|
||||||
|
const displayedRelationsLength = relationsLayout.length;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DataManagementWrapper allLayoutData={layout} slug={slug} id={id} origin={origin}>
|
<DataManagementWrapper allLayoutData={layout} slug={slug} id={id} origin={origin}>
|
||||||
{({
|
{({
|
||||||
@ -241,6 +246,66 @@ const EditView = ({
|
|||||||
<Informations />
|
<Informations />
|
||||||
<InjectionZone area="contentManager.editView.informations" />
|
<InjectionZone area="contentManager.editView.informations" />
|
||||||
</Box>
|
</Box>
|
||||||
|
{displayedRelationsLength > 0 && (
|
||||||
|
<Box
|
||||||
|
as="aside"
|
||||||
|
aria-labelledby="additional-informations"
|
||||||
|
background="neutral0"
|
||||||
|
borderColor="neutral150"
|
||||||
|
hasRadius
|
||||||
|
paddingBottom={4}
|
||||||
|
paddingLeft={4}
|
||||||
|
paddingRight={4}
|
||||||
|
paddingTop={6}
|
||||||
|
>
|
||||||
|
<TableLabel textColor="neutral600">
|
||||||
|
{formatMessage(
|
||||||
|
{
|
||||||
|
id: getTrad('containers.Edit.relations'),
|
||||||
|
defaultMessage:
|
||||||
|
'{number, plural, =0 {relations} one {relation} other {relations}}',
|
||||||
|
},
|
||||||
|
{ number: displayedRelationsLength }
|
||||||
|
)}
|
||||||
|
</TableLabel>
|
||||||
|
<Box paddingTop={2} paddingBottom={6}>
|
||||||
|
<Divider />
|
||||||
|
</Box>
|
||||||
|
<Stack size={4}>
|
||||||
|
{relationsLayout.map(
|
||||||
|
({ name, fieldSchema, labelAction, metadatas, queryInfos }) => {
|
||||||
|
return (
|
||||||
|
<SelectWrapper
|
||||||
|
{...fieldSchema}
|
||||||
|
{...metadatas}
|
||||||
|
key={name}
|
||||||
|
description={{
|
||||||
|
id: metadatas.description,
|
||||||
|
defaultMessage: metadatas.description,
|
||||||
|
}}
|
||||||
|
intlLabel={{
|
||||||
|
id: metadatas.label,
|
||||||
|
defaultMessage: metadatas.label,
|
||||||
|
}}
|
||||||
|
labelAction={labelAction}
|
||||||
|
name={name}
|
||||||
|
relationsType={fieldSchema.relationType}
|
||||||
|
queryInfos={queryInfos}
|
||||||
|
placeholder={
|
||||||
|
metadatas.placeholder
|
||||||
|
? {
|
||||||
|
id: metadatas.placeholder,
|
||||||
|
defaultMessage: metadatas.placeholder,
|
||||||
|
}
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
<Box as="aside" aria-labelledby="links">
|
<Box as="aside" aria-labelledby="links">
|
||||||
<Stack size={2}>
|
<Stack size={2}>
|
||||||
{slug !== 'strapi::administrator' && (
|
{slug !== 'strapi::administrator' && (
|
||||||
|
@ -110,7 +110,6 @@ const CMEditViewLocalePicker = ({
|
|||||||
<Option
|
<Option
|
||||||
value={value.value}
|
value={value.value}
|
||||||
disabled
|
disabled
|
||||||
hidden
|
|
||||||
startIcon={hasDraftAndPublishEnabled ? <Bullet status={currentLocaleStatus} /> : null}
|
startIcon={hasDraftAndPublishEnabled ? <Bullet status={currentLocaleStatus} /> : null}
|
||||||
>
|
>
|
||||||
{value.label}
|
{value.label}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import I18N from '@strapi/icons/I18N';
|
import I18N from '@strapi/icons/I18N';
|
||||||
// FIXME
|
import StrikedWorld from '@strapi/icons/StrikedWorld';
|
||||||
import HelpIcon from '@strapi/icons/HelpIcon';
|
|
||||||
import LabelAction from '../components/LabelAction';
|
import LabelAction from '../components/LabelAction';
|
||||||
import { getTrad } from '../utils';
|
import { getTrad } from '../utils';
|
||||||
|
|
||||||
@ -45,7 +44,7 @@ const enhanceEditLayout = layout =>
|
|||||||
? 'This value is unique for the selected locale'
|
? 'This value is unique for the selected locale'
|
||||||
: 'This value is common to all locales',
|
: 'This value is common to all locales',
|
||||||
},
|
},
|
||||||
icon: hasI18nEnabled ? <I18N aria-hidden /> : <HelpIcon aria-hidden />,
|
icon: hasI18nEnabled ? <I18N aria-hidden /> : <StrikedWorld aria-hidden />,
|
||||||
};
|
};
|
||||||
|
|
||||||
acc.push({ ...field, labelAction: <LabelAction {...labelActionProps} /> });
|
acc.push({ ...field, labelAction: <LabelAction {...labelActionProps} /> });
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import I18N from '@strapi/icons/I18N';
|
import I18N from '@strapi/icons/I18N';
|
||||||
// FIXME
|
|
||||||
import HelpIcon from '@strapi/icons/HelpIcon';
|
import StrikedWorld from '@strapi/icons/StrikedWorld';
|
||||||
import LabelAction from '../../components/LabelAction';
|
import LabelAction from '../../components/LabelAction';
|
||||||
import { getTrad } from '../../utils';
|
import { getTrad } from '../../utils';
|
||||||
import mutateEditViewLayout, {
|
import mutateEditViewLayout, {
|
||||||
@ -450,7 +450,7 @@ describe('i18n | contentManagerHooks | mutateEditViewLayout', () => {
|
|||||||
labelAction: (
|
labelAction: (
|
||||||
<LabelAction
|
<LabelAction
|
||||||
title={{ id: notLocalizedTrad, defaultMessage: notLocalizedTradDefaultMessage }}
|
title={{ id: notLocalizedTrad, defaultMessage: notLocalizedTradDefaultMessage }}
|
||||||
icon={<HelpIcon aria-hidden />}
|
icon={<StrikedWorld aria-hidden />}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user