From 1b5d76712abf32920323eeb4be4635e6b67935f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Espino=20Garc=C3=ADa?= Date: Fri, 9 Jul 2021 11:16:06 +0200 Subject: [PATCH] MM-35935 Respect disabled for bool settings (#5405) * Respect disabled for bool settings * Fix test * Mirate to functional component * Fix test --- .../autocomplete_selector.js | 7 +- .../widgets/settings/bool_setting.js | 197 ------------------ ..._setting.test.js => bool_setting.test.tsx} | 7 +- .../widgets/settings/bool_setting.tsx | 195 +++++++++++++++++ app/screens/apps_form/apps_form_component.tsx | 13 +- app/screens/apps_form/apps_form_field.tsx | 4 +- .../interactive_dialog/dialog_element.js | 8 +- .../interactive_dialog/dialog_element.test.js | 6 +- 8 files changed, 215 insertions(+), 222 deletions(-) delete mode 100644 app/components/widgets/settings/bool_setting.js rename app/components/widgets/settings/{bool_setting.test.js => bool_setting.test.tsx} (82%) create mode 100644 app/components/widgets/settings/bool_setting.tsx diff --git a/app/components/autocomplete_selector/autocomplete_selector.js b/app/components/autocomplete_selector/autocomplete_selector.js index 13cb07d1c..4cfd716aa 100644 --- a/app/components/autocomplete_selector/autocomplete_selector.js +++ b/app/components/autocomplete_selector/autocomplete_selector.js @@ -198,16 +198,17 @@ export default class AutocompleteSelector extends PureComponent { ); } + const noediting = disabled ? style.disabled : null; + return ( {labelContent} - + { fontSize: 14, }, disabled: { - opacity: 0.5, + backgroundColor: changeOpacity(theme.centerChannelColor, 0.1), }, }; }); diff --git a/app/components/widgets/settings/bool_setting.js b/app/components/widgets/settings/bool_setting.js deleted file mode 100644 index 9e71f44f9..000000000 --- a/app/components/widgets/settings/bool_setting.js +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import React, {PureComponent} from 'react'; -import PropTypes from 'prop-types'; -import { - View, - Text, - Switch, -} from 'react-native'; - -import FormattedText from '@components/formatted_text'; -import Markdown from '@components/markdown'; -import {getMarkdownBlockStyles, getMarkdownTextStyles} from '@utils/markdown'; -import { - changeOpacity, - makeStyleSheetFromTheme, -} from '@utils/theme'; - -export default class BoolSetting extends PureComponent { - static propTypes = { - id: PropTypes.string.isRequired, - label: PropTypes.oneOfType([ - PropTypes.shape({ - id: PropTypes.string.isRequired, - defaultMessage: PropTypes.string.isRequired, - }), - PropTypes.string, - ]), - value: PropTypes.bool.isRequired, - placeholder: PropTypes.string, - helpText: PropTypes.node, - errorText: PropTypes.node, - optional: PropTypes.bool, - theme: PropTypes.object.isRequired, - onChange: PropTypes.func.isRequired, - }; - - handleChange = (value) => { - this.props.onChange(this.props.id, Boolean(value)); - }; - - render() { - const { - label, - value, - placeholder, - helpText, - errorText, - optional, - theme, - } = this.props; - const style = getStyleSheet(theme); - const textStyles = getMarkdownTextStyles(theme); - const blockStyles = getMarkdownBlockStyles(theme); - - let optionalContent; - let asterisk; - if (optional) { - optionalContent = ( - - ); - } else { - asterisk = {' *'}; - } - - let labelContent; - if (label) { - labelContent = ( - - - {label} - - {asterisk} - {optionalContent} - - - ); - } - - let helpTextContent; - if (helpText) { - helpTextContent = ( - - - - ); - } - - let errorTextContent; - if (errorText) { - errorTextContent = ( - - - - ); - } - - return ( - <> - - {labelContent} - - - - - {placeholder} - - - - - - {helpTextContent} - {errorTextContent} - - - ); - } -} - -const getStyleSheet = makeStyleSheetFromTheme((theme) => { - return { - labelContainer: { - flexDirection: 'row', - marginTop: 15, - marginBottom: 10, - }, - label: { - fontSize: 14, - color: theme.centerChannelColor, - marginLeft: 15, - }, - inputContainer: { - backgroundColor: theme.centerChannelBg, - flexDirection: 'row', - alignItems: 'center', - paddingHorizontal: 15, - height: 40, - }, - placeholderText: { - color: changeOpacity(theme.centerChannelColor, 0.5), - fontSize: 15, - }, - inputSwitch: { - position: 'absolute', - right: 12, - }, - separator: { - backgroundColor: changeOpacity(theme.centerChannelColor, 0.1), - height: 1, - width: '100%', - }, - optional: { - color: changeOpacity(theme.centerChannelColor, 0.5), - fontSize: 14, - marginLeft: 5, - }, - helpTextContainer: { - marginHorizontal: 15, - marginTop: 10, - }, - helpText: { - fontSize: 12, - color: changeOpacity(theme.centerChannelColor, 0.5), - }, - errorTextContainer: { - marginHorizontal: 15, - marginVertical: 10, - }, - errorText: { - fontSize: 12, - color: theme.errorTextColor, - }, - asterisk: { - color: theme.errorTextColor, - fontSize: 14, - }, - }; -}); diff --git a/app/components/widgets/settings/bool_setting.test.js b/app/components/widgets/settings/bool_setting.test.tsx similarity index 82% rename from app/components/widgets/settings/bool_setting.test.js rename to app/components/widgets/settings/bool_setting.test.tsx index 996c97b73..54f184ea3 100644 --- a/app/components/widgets/settings/bool_setting.test.js +++ b/app/components/widgets/settings/bool_setting.test.tsx @@ -1,11 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import React from 'react'; +import {Switch} from 'react-native'; import {shallow} from 'enzyme'; import Preferences from '@mm-redux/constants/preferences'; -import BoolSetting from './bool_setting.js'; +import BoolSetting from './bool_setting'; describe('components/widgets/settings/TextSetting', () => { const theme = Preferences.THEMES.default; @@ -23,11 +24,11 @@ describe('components/widgets/settings/TextSetting', () => { />, ); - wrapper.instance().handleChange(false); + wrapper.find(Switch).simulate('valueChange', false); expect(onChange).toHaveBeenCalledTimes(1); expect(onChange).toHaveBeenCalledWith('elementid', false); - wrapper.instance().handleChange(true); + wrapper.find(Switch).simulate('valueChange', true); expect(onChange).toHaveBeenCalledTimes(2); expect(onChange).toHaveBeenCalledWith('elementid', true); }); diff --git a/app/components/widgets/settings/bool_setting.tsx b/app/components/widgets/settings/bool_setting.tsx new file mode 100644 index 000000000..937428994 --- /dev/null +++ b/app/components/widgets/settings/bool_setting.tsx @@ -0,0 +1,195 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; +import { + View, + Text, + Switch, +} from 'react-native'; + +import FormattedText from '@components/formatted_text'; +import Markdown from '@components/markdown'; +import {getMarkdownBlockStyles, getMarkdownTextStyles} from '@utils/markdown'; +import { + changeOpacity, + makeStyleSheetFromTheme, +} from '@utils/theme'; +import {Theme} from '@mm-redux/types/preferences'; + +type Props = { + id: string; + label?: string | {id: string, defaultMessage: string}; + value: boolean; + placeholder?: string; + helpText?: string; + errorText?: string; + optional?: boolean; + disabled?: boolean; + theme: Theme; + onChange: (name: string, value: boolean) => void; +} + +export default function BoolSetting(props: Props) { + const { + id, + label, + value, + placeholder, + helpText, + errorText, + optional, + theme, + disabled, + onChange, + } = props; + const style = getStyleSheet(theme); + const textStyles = getMarkdownTextStyles(theme); + const blockStyles = getMarkdownBlockStyles(theme); + + let optionalContent; + let asterisk; + if (optional) { + optionalContent = ( + + ); + } else { + asterisk = {' *'}; + } + + let labelContent; + if (label) { + labelContent = ( + + + {label} + + {asterisk} + {optionalContent} + + + ); + } + + let helpTextContent; + if (helpText) { + helpTextContent = ( + + + + ); + } + + let errorTextContent; + if (errorText) { + errorTextContent = ( + + + + ); + } + + const noediting = disabled ? style.disabled : null; + + return ( + <> + + {labelContent} + + + + + {placeholder} + + onChange(id, newValue)} + value={value} + style={style.inputSwitch} + disabled={disabled} + /> + + + + {helpTextContent} + {errorTextContent} + + + ); +} + +const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { + return { + labelContainer: { + flexDirection: 'row', + marginTop: 15, + marginBottom: 10, + }, + label: { + fontSize: 14, + color: theme.centerChannelColor, + marginLeft: 15, + }, + inputContainer: { + backgroundColor: theme.centerChannelBg, + flexDirection: 'row', + alignItems: 'center', + paddingHorizontal: 15, + height: 40, + }, + disabled: { + backgroundColor: changeOpacity(theme.centerChannelColor, 0.1), + }, + placeholderText: { + color: changeOpacity(theme.centerChannelColor, 0.5), + fontSize: 15, + }, + inputSwitch: { + position: 'absolute', + right: 12, + }, + separator: { + backgroundColor: changeOpacity(theme.centerChannelColor, 0.1), + height: 1, + width: '100%', + }, + optional: { + color: changeOpacity(theme.centerChannelColor, 0.5), + fontSize: 14, + marginLeft: 5, + }, + helpTextContainer: { + marginHorizontal: 15, + marginTop: 10, + }, + helpText: { + fontSize: 12, + color: changeOpacity(theme.centerChannelColor, 0.5), + }, + errorTextContainer: { + marginHorizontal: 15, + marginVertical: 10, + }, + errorText: { + fontSize: 12, + color: theme.errorTextColor, + }, + asterisk: { + color: theme.errorTextColor, + fontSize: 14, + }, + }; +}); diff --git a/app/screens/apps_form/apps_form_component.tsx b/app/screens/apps_form/apps_form_component.tsx index 27c8496db..0e8c5bd72 100644 --- a/app/screens/apps_form/apps_form_component.tsx +++ b/app/screens/apps_form/apps_form_component.tsx @@ -15,7 +15,6 @@ import {Theme} from '@mm-redux/types/preferences'; import {checkDialogElementForError, checkIfErrorsMatchElements} from '@mm-redux/utils/integration_utils'; import StatusBar from '@components/status_bar'; -import FormattedText from '@components/formatted_text'; import Markdown from '@components/markdown'; import {dismissModal} from '@actions/navigation'; @@ -47,7 +46,7 @@ export type Props = { type State = { values: {[name: string]: string}; formError: string | null; - fieldErrors: {[name: string]: React.ReactNode}; + fieldErrors: {[name: string]: string}; form: AppForm; } @@ -119,7 +118,7 @@ export default class AppsFormComponent extends PureComponent { const {fields} = this.props.form; const values = this.state.values; - const fieldErrors: {[name: string]: React.ReactNode} = {}; + const fieldErrors: {[name: string]: string} = {}; const elements = fieldsAsElements(fields); elements?.forEach((element) => { @@ -128,13 +127,7 @@ export default class AppsFormComponent extends PureComponent { values[element.name], ); if (error) { - fieldErrors[element.name] = ( - - ); + fieldErrors[element.name] = this.context.intl.formatMessage(error.id, error.defaultMessage, error.values); } }); diff --git a/app/screens/apps_form/apps_form_field.tsx b/app/screens/apps_form/apps_form_field.tsx index 95a9faec0..213f0ac15 100644 --- a/app/screens/apps_form/apps_form_field.tsx +++ b/app/screens/apps_form/apps_form_field.tsx @@ -24,11 +24,11 @@ const TEXTAREA_DEFAULT_MAX_LENGTH = 3000; export type Props = { field: AppField; name: string; - errorText?: React.ReactNode; + errorText?: string; theme: Theme; value: AppFormValue; - onChange: (name: string, value: string | AppSelectOption) => void; + onChange: (name: string, value: string | AppSelectOption | boolean) => void; performLookup: (name: string, userInput: string) => Promise; } diff --git a/app/screens/interactive_dialog/dialog_element.js b/app/screens/interactive_dialog/dialog_element.js index daa322eff..c14a5617c 100644 --- a/app/screens/interactive_dialog/dialog_element.js +++ b/app/screens/interactive_dialog/dialog_element.js @@ -4,10 +4,10 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; -import BoolSetting from 'app/components/widgets/settings/bool_setting'; -import TextSetting from 'app/components/widgets/settings/text_setting'; -import AutocompleteSelector from 'app/components/autocomplete_selector'; -import RadioSetting from 'app/components/widgets/settings/radio_setting'; +import BoolSetting from '@components/widgets/settings/bool_setting'; +import TextSetting from '@components/widgets/settings/text_setting'; +import AutocompleteSelector from '@components/autocomplete_selector'; +import RadioSetting from '@components/widgets/settings/radio_setting'; const TEXT_DEFAULT_MAX_LENGTH = 150; const TEXTAREA_DEFAULT_MAX_LENGTH = 3000; diff --git a/app/screens/interactive_dialog/dialog_element.test.js b/app/screens/interactive_dialog/dialog_element.test.js index 42ff1fcff..f1e4ffc79 100644 --- a/app/screens/interactive_dialog/dialog_element.test.js +++ b/app/screens/interactive_dialog/dialog_element.test.js @@ -5,9 +5,9 @@ import React from 'react'; import {shallow} from 'enzyme'; import Preferences from '@mm-redux/constants/preferences'; -import RadioSetting from 'app/components/widgets/settings/radio_setting'; -import BoolSetting from 'app/components/widgets/settings/bool_setting'; -import AutocompleteSelector from 'app/components/autocomplete_selector'; +import RadioSetting from '@components/widgets/settings/radio_setting'; +import BoolSetting from '@components/widgets/settings/bool_setting'; +import AutocompleteSelector from '@components/autocomplete_selector'; import DialogElement from './dialog_element.js'; describe('DialogElement', () => {