From f6e3ba8399f0941b2529d24dc13df274623b1808 Mon Sep 17 00:00:00 2001 From: soupette Date: Mon, 11 Oct 2021 18:24:12 +0200 Subject: [PATCH] Add custom select for default boolean Signed-off-by: soupette --- .../BooleanDefaultValueSelect/index.js | 84 +++++++++++++++++ .../tests/index.test.js | 24 +++++ .../FormModal/attributes/advancedForm.js | 25 ++++-- .../admin/src/components/FormModal/index.js | 89 ++++++------------- 4 files changed, 151 insertions(+), 71 deletions(-) create mode 100644 packages/core/content-type-builder/admin/src/components/BooleanDefaultValueSelect/index.js create mode 100644 packages/core/content-type-builder/admin/src/components/BooleanDefaultValueSelect/tests/index.test.js diff --git a/packages/core/content-type-builder/admin/src/components/BooleanDefaultValueSelect/index.js b/packages/core/content-type-builder/admin/src/components/BooleanDefaultValueSelect/index.js new file mode 100644 index 0000000000..3f52cc1634 --- /dev/null +++ b/packages/core/content-type-builder/admin/src/components/BooleanDefaultValueSelect/index.js @@ -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 ( + + ); +}; + +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; diff --git a/packages/core/content-type-builder/admin/src/components/BooleanDefaultValueSelect/tests/index.test.js b/packages/core/content-type-builder/admin/src/components/BooleanDefaultValueSelect/tests/index.test.js new file mode 100644 index 0000000000..2dd11df938 --- /dev/null +++ b/packages/core/content-type-builder/admin/src/components/BooleanDefaultValueSelect/tests/index.test.js @@ -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('', () => { + it('renders and matches the snapshot', () => { + const { + container: { firstChild }, + } = render( + + + + ); + + expect(firstChild).toMatchInlineSnapshot(); + }); +}); diff --git a/packages/core/content-type-builder/admin/src/components/FormModal/attributes/advancedForm.js b/packages/core/content-type-builder/admin/src/components/FormModal/attributes/advancedForm.js index 7a0f81ede2..242703f66f 100644 --- a/packages/core/content-type-builder/admin/src/components/FormModal/attributes/advancedForm.js +++ b/packages/core/content-type-builder/admin/src/components/FormModal/attributes/advancedForm.js @@ -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: {}, }, ], diff --git a/packages/core/content-type-builder/admin/src/components/FormModal/index.js b/packages/core/content-type-builder/admin/src/components/FormModal/index.js index 0667297c60..078731dc85 100644 --- a/packages/core/content-type-builder/admin/src/components/FormModal/index.js +++ b/packages/core/content-type-builder/admin/src/components/FormModal/index.js @@ -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;