mirror of
https://github.com/strapi/strapi.git
synced 2025-09-27 01:09:49 +00:00
Add custom select for default boolean
Signed-off-by: soupette <cyril@strapi.io>
This commit is contained in:
parent
c2c5af77c4
commit
f6e3ba8399
@ -0,0 +1,84 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* BooleanDefaultValueSelect
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { useIntl } from 'react-intl';
|
||||||
|
import { Select, Option } from '@strapi/parts/Select';
|
||||||
|
|
||||||
|
const BooleanDefaultValueSelect = ({ intlLabel, name, options, onChange, value }) => {
|
||||||
|
const { formatMessage } = useIntl();
|
||||||
|
const label = intlLabel.id
|
||||||
|
? formatMessage(
|
||||||
|
{ id: intlLabel.id, defaultMessage: intlLabel.defaultMessage },
|
||||||
|
{ ...intlLabel.values }
|
||||||
|
)
|
||||||
|
: name;
|
||||||
|
|
||||||
|
const handleChange = value => {
|
||||||
|
let nextValue = '';
|
||||||
|
|
||||||
|
if (value === 'true') {
|
||||||
|
nextValue = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value === 'false') {
|
||||||
|
nextValue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
onChange({ target: { name, value: nextValue, type: 'select-default-boolean' } });
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
label={label}
|
||||||
|
id={name}
|
||||||
|
name={name}
|
||||||
|
onChange={handleChange}
|
||||||
|
value={(value === null ? '' : value).toString()}
|
||||||
|
>
|
||||||
|
{options.map(({ metadatas: { intlLabel, disabled, hidden }, key, value }) => {
|
||||||
|
return (
|
||||||
|
<Option key={key} value={value} disabled={disabled} hidden={hidden}>
|
||||||
|
{/* No need to translate the options */}
|
||||||
|
{intlLabel.defaultMessage}
|
||||||
|
</Option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
BooleanDefaultValueSelect.defaultProps = {
|
||||||
|
value: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
BooleanDefaultValueSelect.propTypes = {
|
||||||
|
intlLabel: PropTypes.shape({
|
||||||
|
id: PropTypes.string.isRequired,
|
||||||
|
defaultMessage: PropTypes.string.isRequired,
|
||||||
|
values: PropTypes.object,
|
||||||
|
}).isRequired,
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
onChange: PropTypes.func.isRequired,
|
||||||
|
options: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
metadatas: PropTypes.shape({
|
||||||
|
intlLabel: PropTypes.shape({
|
||||||
|
id: PropTypes.string.isRequired,
|
||||||
|
defaultMessage: PropTypes.string.isRequired,
|
||||||
|
}).isRequired,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
hidden: PropTypes.bool,
|
||||||
|
}).isRequired,
|
||||||
|
key: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
||||||
|
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
||||||
|
}).isRequired
|
||||||
|
).isRequired,
|
||||||
|
value: PropTypes.any,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BooleanDefaultValueSelect;
|
@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* Tests for BooleanDefaultValueSelect
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { render } from '@testing-library/react';
|
||||||
|
import { ThemeProvider, lightTheme } from '@strapi/parts';
|
||||||
|
import BooleanDefaultValueSelect from '../index';
|
||||||
|
|
||||||
|
describe('<BooleanDefaultValueSelect />', () => {
|
||||||
|
it('renders and matches the snapshot', () => {
|
||||||
|
const {
|
||||||
|
container: { firstChild },
|
||||||
|
} = render(
|
||||||
|
<ThemeProvider theme={lightTheme}>
|
||||||
|
<BooleanDefaultValueSelect />
|
||||||
|
</ThemeProvider>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(firstChild).toMatchInlineSnapshot();
|
||||||
|
});
|
||||||
|
});
|
@ -14,18 +14,29 @@ const advancedForm = {
|
|||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
type: 'enum',
|
type: 'select-default-boolean',
|
||||||
intlLabel: {
|
intlLabel: {
|
||||||
id: getTrad('form.attribute.settings.default'),
|
id: getTrad('form.attribute.settings.default'),
|
||||||
defaultMessage: 'Default value',
|
defaultMessage: 'Default value',
|
||||||
},
|
},
|
||||||
name: 'default',
|
name: 'default',
|
||||||
options: [],
|
options: [
|
||||||
// options: [
|
{
|
||||||
// { value: 'true', label: 'TRUE' },
|
value: 'true',
|
||||||
// { value: '', label: 'NULL' },
|
key: 'true',
|
||||||
// { value: 'false', label: 'FALSE' },
|
metadatas: { intlLabel: { id: 'true', defaultMessage: 'true' } },
|
||||||
// ],
|
},
|
||||||
|
{
|
||||||
|
value: '',
|
||||||
|
key: 'null',
|
||||||
|
metadatas: { intlLabel: { id: 'null', defaultMessage: 'null' } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'false',
|
||||||
|
key: 'false',
|
||||||
|
metadatas: { intlLabel: { id: 'false', defaultMessage: 'false' } },
|
||||||
|
},
|
||||||
|
],
|
||||||
// validations: {},
|
// validations: {},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -1,12 +1,5 @@
|
|||||||
import React, { useCallback, useEffect, useState, useMemo } from 'react';
|
import React, { useCallback, useEffect, useState, useMemo } from 'react';
|
||||||
import {
|
import {
|
||||||
// HeaderModal,
|
|
||||||
// HeaderModalTitle,
|
|
||||||
// Modal,
|
|
||||||
// ModalBody,
|
|
||||||
// ModalFooter,
|
|
||||||
// ModalForm,
|
|
||||||
|
|
||||||
GenericInput,
|
GenericInput,
|
||||||
getYupInnerErrors,
|
getYupInnerErrors,
|
||||||
useTracking,
|
useTracking,
|
||||||
@ -18,7 +11,6 @@ import { useIntl } from 'react-intl';
|
|||||||
import { useHistory, useLocation } from 'react-router-dom';
|
import { useHistory, useLocation } from 'react-router-dom';
|
||||||
import { get, has, isEmpty, set, toLower } from 'lodash';
|
import { get, has, isEmpty, set, toLower } from 'lodash';
|
||||||
import upperFirst from 'lodash/upperFirst';
|
import upperFirst from 'lodash/upperFirst';
|
||||||
import toString from 'lodash/toString';
|
|
||||||
import { useSelector, useDispatch, shallowEqual } from 'react-redux';
|
import { useSelector, useDispatch, shallowEqual } from 'react-redux';
|
||||||
import AddIcon from '@strapi/icons/AddIcon';
|
import AddIcon from '@strapi/icons/AddIcon';
|
||||||
import { Box } from '@strapi/parts/Box';
|
import { Box } from '@strapi/parts/Box';
|
||||||
@ -37,6 +29,7 @@ import AttributeOptions from '../AttributeOptions';
|
|||||||
import DraftAndPublishToggle from '../DraftAndPublishToggle';
|
import DraftAndPublishToggle from '../DraftAndPublishToggle';
|
||||||
import FormModalHeader from '../FormModalHeader';
|
import FormModalHeader from '../FormModalHeader';
|
||||||
|
|
||||||
|
import BooleanDefaultValueSelect from '../BooleanDefaultValueSelect';
|
||||||
import CustomRadioGroup from '../CustomRadioGroup';
|
import CustomRadioGroup from '../CustomRadioGroup';
|
||||||
import ContentTypeRadioGroup from '../ContentTypeRadioGroup';
|
import ContentTypeRadioGroup from '../ContentTypeRadioGroup';
|
||||||
// import ComponentIconPicker from '../ComponentIconPicker';
|
// import ComponentIconPicker from '../ComponentIconPicker';
|
||||||
@ -65,8 +58,8 @@ import {
|
|||||||
SET_DATA_TO_EDIT,
|
SET_DATA_TO_EDIT,
|
||||||
SET_DYNAMIC_ZONE_DATA_SCHEMA,
|
SET_DYNAMIC_ZONE_DATA_SCHEMA,
|
||||||
SET_ATTRIBUTE_DATA_SCHEMA,
|
SET_ATTRIBUTE_DATA_SCHEMA,
|
||||||
ADD_COMPONENTS_TO_DYNAMIC_ZONE,
|
// ADD_COMPONENTS_TO_DYNAMIC_ZONE,
|
||||||
ON_CHANGE_ALLOWED_TYPE,
|
// ON_CHANGE_ALLOWED_TYPE,
|
||||||
SET_ERRORS,
|
SET_ERRORS,
|
||||||
ON_CHANGE,
|
ON_CHANGE,
|
||||||
RESET_PROPS_AND_SET_THE_FORM_FOR_ADDING_A_COMPO_TO_A_DZ,
|
RESET_PROPS_AND_SET_THE_FORM_FOR_ADDING_A_COMPO_TO_A_DZ,
|
||||||
@ -561,24 +554,24 @@ const FormModal = () => {
|
|||||||
}, '');
|
}, '');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClickAddComponentsToDynamicZone = ({
|
// const handleClickAddComponentsToDynamicZone = ({
|
||||||
target: { name, components, shouldAddComponents },
|
// target: { name, components, shouldAddComponents },
|
||||||
}) => {
|
// }) => {
|
||||||
dispatch({
|
// dispatch({
|
||||||
type: ADD_COMPONENTS_TO_DYNAMIC_ZONE,
|
// type: ADD_COMPONENTS_TO_DYNAMIC_ZONE,
|
||||||
name,
|
// name,
|
||||||
components,
|
// components,
|
||||||
shouldAddComponents,
|
// shouldAddComponents,
|
||||||
});
|
// });
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleChangeMediaAllowedTypes = ({ target: { name, value } }) => {
|
// const handleChangeMediaAllowedTypes = ({ target: { name, value } }) => {
|
||||||
dispatch({
|
// dispatch({
|
||||||
type: ON_CHANGE_ALLOWED_TYPE,
|
// type: ON_CHANGE_ALLOWED_TYPE,
|
||||||
name,
|
// name,
|
||||||
value,
|
// value,
|
||||||
});
|
// });
|
||||||
};
|
// };
|
||||||
|
|
||||||
const handleChange = useCallback(
|
const handleChange = useCallback(
|
||||||
({ target: { name, value, type, ...rest } }) => {
|
({ target: { name, value, type, ...rest } }) => {
|
||||||
@ -589,11 +582,12 @@ const FormModal = () => {
|
|||||||
'maxLength',
|
'maxLength',
|
||||||
'minLength',
|
'minLength',
|
||||||
'regex',
|
'regex',
|
||||||
|
'default',
|
||||||
];
|
];
|
||||||
|
|
||||||
let val;
|
let val;
|
||||||
|
|
||||||
if (['default', ...namesThatCanResetToNullValue].includes(name) && value === '') {
|
if (namesThatCanResetToNullValue.includes(name) && value === '') {
|
||||||
val = null;
|
val = null;
|
||||||
} else if (
|
} else if (
|
||||||
type === 'radio' &&
|
type === 'radio' &&
|
||||||
@ -607,17 +601,6 @@ const FormModal = () => {
|
|||||||
|
|
||||||
// The boolean default accepts 3 different values
|
// The boolean default accepts 3 different values
|
||||||
// This check has been added to allow a reset to null for the bool
|
// This check has been added to allow a reset to null for the bool
|
||||||
} else if (type === 'radio' && name === 'default') {
|
|
||||||
if (value === 'false') {
|
|
||||||
val = false;
|
|
||||||
} else if (value === 'true') {
|
|
||||||
val = true;
|
|
||||||
} else {
|
|
||||||
val = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We store an array for the enum
|
|
||||||
// FIXME
|
|
||||||
} else if (name === 'enum') {
|
} else if (name === 'enum') {
|
||||||
val = value.split('\n');
|
val = value.split('\n');
|
||||||
} else {
|
} else {
|
||||||
@ -1113,6 +1096,7 @@ const FormModal = () => {
|
|||||||
|
|
||||||
const genericInputProps = {
|
const genericInputProps = {
|
||||||
customInputs: {
|
customInputs: {
|
||||||
|
'select-default-boolean': BooleanDefaultValueSelect,
|
||||||
'radio-group': CustomRadioGroup,
|
'radio-group': CustomRadioGroup,
|
||||||
'content-type-radio-group': ContentTypeRadioGroup,
|
'content-type-radio-group': ContentTypeRadioGroup,
|
||||||
'toggle-draft-publish': DraftAndPublishToggle,
|
'toggle-draft-publish': DraftAndPublishToggle,
|
||||||
@ -1233,21 +1217,7 @@ const FormModal = () => {
|
|||||||
|
|
||||||
// FIXME
|
// FIXME
|
||||||
|
|
||||||
// Condition for the boolean default value
|
if (input.name === 'enum' && Array.isArray(retrievedValue)) {
|
||||||
// The radio input doesn't accept false, true or null as value
|
|
||||||
// So we pass them as string
|
|
||||||
// This way the data stays accurate and we don't have to operate
|
|
||||||
// any data mutation
|
|
||||||
if (
|
|
||||||
input.name === 'default' &&
|
|
||||||
state.attributeType === 'boolean'
|
|
||||||
) {
|
|
||||||
value = toString(retrievedValue);
|
|
||||||
// Same here for the enum
|
|
||||||
} else if (
|
|
||||||
input.name === 'enum' &&
|
|
||||||
Array.isArray(retrievedValue)
|
|
||||||
) {
|
|
||||||
value = retrievedValue.join('\n');
|
value = retrievedValue.join('\n');
|
||||||
} else if (input.name === 'uid') {
|
} else if (input.name === 'uid') {
|
||||||
value = input.value;
|
value = input.value;
|
||||||
@ -1319,16 +1289,7 @@ const FormModal = () => {
|
|||||||
// So we pass them as string
|
// So we pass them as string
|
||||||
// This way the data stays accurate and we don't have to operate
|
// This way the data stays accurate and we don't have to operate
|
||||||
// any data mutation
|
// any data mutation
|
||||||
if (
|
if (input.name === 'enum' && Array.isArray(retrievedValue)) {
|
||||||
input.name === 'default' &&
|
|
||||||
state.attributeType === 'boolean'
|
|
||||||
) {
|
|
||||||
value = toString(retrievedValue);
|
|
||||||
// Same here for the enum
|
|
||||||
} else if (
|
|
||||||
input.name === 'enum' &&
|
|
||||||
Array.isArray(retrievedValue)
|
|
||||||
) {
|
|
||||||
value = retrievedValue.join('\n');
|
value = retrievedValue.join('\n');
|
||||||
} else if (input.name === 'uid') {
|
} else if (input.name === 'uid') {
|
||||||
value = input.value;
|
value = input.value;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user