mirror of
https://github.com/strapi/strapi.git
synced 2025-09-25 16:29:34 +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: [
|
||||
{
|
||||
autoFocus: true,
|
||||
type: 'enum',
|
||||
type: 'select-default-boolean',
|
||||
intlLabel: {
|
||||
id: getTrad('form.attribute.settings.default'),
|
||||
defaultMessage: 'Default value',
|
||||
},
|
||||
name: 'default',
|
||||
options: [],
|
||||
// options: [
|
||||
// { value: 'true', label: 'TRUE' },
|
||||
// { value: '', label: 'NULL' },
|
||||
// { value: 'false', label: 'FALSE' },
|
||||
// ],
|
||||
options: [
|
||||
{
|
||||
value: 'true',
|
||||
key: 'true',
|
||||
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: {},
|
||||
},
|
||||
],
|
||||
|
@ -1,12 +1,5 @@
|
||||
import React, { useCallback, useEffect, useState, useMemo } from 'react';
|
||||
import {
|
||||
// HeaderModal,
|
||||
// HeaderModalTitle,
|
||||
// Modal,
|
||||
// ModalBody,
|
||||
// ModalFooter,
|
||||
// ModalForm,
|
||||
|
||||
GenericInput,
|
||||
getYupInnerErrors,
|
||||
useTracking,
|
||||
@ -18,7 +11,6 @@ import { useIntl } from 'react-intl';
|
||||
import { useHistory, useLocation } from 'react-router-dom';
|
||||
import { get, has, isEmpty, set, toLower } from 'lodash';
|
||||
import upperFirst from 'lodash/upperFirst';
|
||||
import toString from 'lodash/toString';
|
||||
import { useSelector, useDispatch, shallowEqual } from 'react-redux';
|
||||
import AddIcon from '@strapi/icons/AddIcon';
|
||||
import { Box } from '@strapi/parts/Box';
|
||||
@ -37,6 +29,7 @@ import AttributeOptions from '../AttributeOptions';
|
||||
import DraftAndPublishToggle from '../DraftAndPublishToggle';
|
||||
import FormModalHeader from '../FormModalHeader';
|
||||
|
||||
import BooleanDefaultValueSelect from '../BooleanDefaultValueSelect';
|
||||
import CustomRadioGroup from '../CustomRadioGroup';
|
||||
import ContentTypeRadioGroup from '../ContentTypeRadioGroup';
|
||||
// import ComponentIconPicker from '../ComponentIconPicker';
|
||||
@ -65,8 +58,8 @@ import {
|
||||
SET_DATA_TO_EDIT,
|
||||
SET_DYNAMIC_ZONE_DATA_SCHEMA,
|
||||
SET_ATTRIBUTE_DATA_SCHEMA,
|
||||
ADD_COMPONENTS_TO_DYNAMIC_ZONE,
|
||||
ON_CHANGE_ALLOWED_TYPE,
|
||||
// ADD_COMPONENTS_TO_DYNAMIC_ZONE,
|
||||
// ON_CHANGE_ALLOWED_TYPE,
|
||||
SET_ERRORS,
|
||||
ON_CHANGE,
|
||||
RESET_PROPS_AND_SET_THE_FORM_FOR_ADDING_A_COMPO_TO_A_DZ,
|
||||
@ -561,24 +554,24 @@ const FormModal = () => {
|
||||
}, '');
|
||||
};
|
||||
|
||||
const handleClickAddComponentsToDynamicZone = ({
|
||||
target: { name, components, shouldAddComponents },
|
||||
}) => {
|
||||
dispatch({
|
||||
type: ADD_COMPONENTS_TO_DYNAMIC_ZONE,
|
||||
name,
|
||||
components,
|
||||
shouldAddComponents,
|
||||
});
|
||||
};
|
||||
// const handleClickAddComponentsToDynamicZone = ({
|
||||
// target: { name, components, shouldAddComponents },
|
||||
// }) => {
|
||||
// dispatch({
|
||||
// type: ADD_COMPONENTS_TO_DYNAMIC_ZONE,
|
||||
// name,
|
||||
// components,
|
||||
// shouldAddComponents,
|
||||
// });
|
||||
// };
|
||||
|
||||
const handleChangeMediaAllowedTypes = ({ target: { name, value } }) => {
|
||||
dispatch({
|
||||
type: ON_CHANGE_ALLOWED_TYPE,
|
||||
name,
|
||||
value,
|
||||
});
|
||||
};
|
||||
// const handleChangeMediaAllowedTypes = ({ target: { name, value } }) => {
|
||||
// dispatch({
|
||||
// type: ON_CHANGE_ALLOWED_TYPE,
|
||||
// name,
|
||||
// value,
|
||||
// });
|
||||
// };
|
||||
|
||||
const handleChange = useCallback(
|
||||
({ target: { name, value, type, ...rest } }) => {
|
||||
@ -589,11 +582,12 @@ const FormModal = () => {
|
||||
'maxLength',
|
||||
'minLength',
|
||||
'regex',
|
||||
'default',
|
||||
];
|
||||
|
||||
let val;
|
||||
|
||||
if (['default', ...namesThatCanResetToNullValue].includes(name) && value === '') {
|
||||
if (namesThatCanResetToNullValue.includes(name) && value === '') {
|
||||
val = null;
|
||||
} else if (
|
||||
type === 'radio' &&
|
||||
@ -607,17 +601,6 @@ const FormModal = () => {
|
||||
|
||||
// The boolean default accepts 3 different values
|
||||
// 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') {
|
||||
val = value.split('\n');
|
||||
} else {
|
||||
@ -1113,6 +1096,7 @@ const FormModal = () => {
|
||||
|
||||
const genericInputProps = {
|
||||
customInputs: {
|
||||
'select-default-boolean': BooleanDefaultValueSelect,
|
||||
'radio-group': CustomRadioGroup,
|
||||
'content-type-radio-group': ContentTypeRadioGroup,
|
||||
'toggle-draft-publish': DraftAndPublishToggle,
|
||||
@ -1233,21 +1217,7 @@ const FormModal = () => {
|
||||
|
||||
// FIXME
|
||||
|
||||
// Condition for the boolean default value
|
||||
// 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)
|
||||
) {
|
||||
if (input.name === 'enum' && Array.isArray(retrievedValue)) {
|
||||
value = retrievedValue.join('\n');
|
||||
} else if (input.name === 'uid') {
|
||||
value = input.value;
|
||||
@ -1319,16 +1289,7 @@ const FormModal = () => {
|
||||
// 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)
|
||||
) {
|
||||
if (input.name === 'enum' && Array.isArray(retrievedValue)) {
|
||||
value = retrievedValue.join('\n');
|
||||
} else if (input.name === 'uid') {
|
||||
value = input.value;
|
||||
|
Loading…
x
Reference in New Issue
Block a user