diff --git a/superset-frontend/src/components/Form/Form.tsx b/superset-frontend/src/components/Form/Form.tsx index 946324549ad33..1fc25e6c498b7 100644 --- a/superset-frontend/src/components/Form/Form.tsx +++ b/superset-frontend/src/components/Form/Form.tsx @@ -32,3 +32,5 @@ const StyledForm = styled(AntDForm)` export default function Form(props: FormProps) { return ; } + +export { FormProps }; diff --git a/superset-frontend/src/components/Form/index.tsx b/superset-frontend/src/components/Form/index.tsx index 7d7a60745df8b..1aa62ae567088 100644 --- a/superset-frontend/src/components/Form/index.tsx +++ b/superset-frontend/src/components/Form/index.tsx @@ -16,9 +16,9 @@ * specific language governing permissions and limitations * under the License. */ -import Form from './Form'; +import Form, { FormProps } from './Form'; import FormItem from './FormItem'; import FormLabel from './FormLabel'; import LabeledErrorBoundInput from './LabeledErrorBoundInput'; -export { Form, FormItem, FormLabel, LabeledErrorBoundInput }; +export { Form, FormItem, FormLabel, LabeledErrorBoundInput, FormProps }; diff --git a/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx b/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx index b23b456c4cd65..85f406c08d189 100644 --- a/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx +++ b/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx @@ -16,9 +16,9 @@ * specific language governing permissions and limitations * under the License. */ -import React, { useCallback, useMemo } from 'react'; +import React from 'react'; import { styled, t } from '@superset-ui/core'; -import { Form, FormItem } from 'src/components/Form'; +import { Form, FormItem, FormProps } from 'src/components/Form'; import { Select } from 'src/components'; import { Col, InputNumber, Row } from 'src/common/components'; import Button from 'src/components/Button'; @@ -57,6 +57,127 @@ const operatorOptions = [ { value: COMPARATOR.BETWEEN_OR_RIGHT_EQUAL, label: '< x ≤' }, ]; +const targetValueValidator = ( + compare: (targetValue: number, compareValue: number) => boolean, + rejectMessage: string, +) => (targetValue: number | string) => ( + _: any, + compareValue: number | string, +) => { + if ( + !targetValue || + !compareValue || + compare(Number(targetValue), Number(compareValue)) + ) { + return Promise.resolve(); + } + return Promise.reject(new Error(rejectMessage)); +}; + +const targetValueLeftValidator = targetValueValidator( + (target: number, val: number) => target > val, + t('This value should be smaller than the right target value'), +); + +const targetValueRightValidator = targetValueValidator( + (target: number, val: number) => target < val, + t('This value should be greater than the left target value'), +); + +const isOperatorMultiValue = (operator?: COMPARATOR) => + operator && MULTIPLE_VALUE_COMPARATORS.includes(operator); + +const isOperatorNone = (operator?: COMPARATOR) => + !operator || operator === COMPARATOR.NONE; + +const rulesRequired = [{ required: true, message: t('Required') }]; + +type GetFieldValue = Pick['form'], 'getFieldValue'>; +const rulesTargetValueLeft = [ + { required: true, message: t('Required') }, + ({ getFieldValue }: GetFieldValue) => ({ + validator: targetValueLeftValidator(getFieldValue('targetValueRight')), + }), +]; + +const rulesTargetValueRight = [ + { required: true, message: t('Required') }, + ({ getFieldValue }: GetFieldValue) => ({ + validator: targetValueRightValidator(getFieldValue('targetValueLeft')), + }), +]; + +const targetValueLeftDeps = ['targetValueRight']; +const targetValueRightDeps = ['targetValueLeft']; + +const shouldFormItemUpdate = ( + prevValues: ConditionalFormattingConfig, + currentValues: ConditionalFormattingConfig, +) => + isOperatorNone(prevValues.operator) !== + isOperatorNone(currentValues.operator) || + isOperatorMultiValue(prevValues.operator) !== + isOperatorMultiValue(currentValues.operator); + +const operatorField = ( + + - - ), - [], - ); - - const targetValueLeftValidator = useCallback( - (rightValue?: number) => (_: any, value?: number) => { - if (!value || !rightValue || rightValue > value) { - return Promise.resolve(); - } - return Promise.reject( - new Error( - t('This value should be smaller than the right target value'), - ), - ); - }, - [], - ); - - const targetValueRightValidator = useCallback( - (leftValue?: number) => (_: any, value?: number) => { - if (!value || !leftValue || leftValue < value) { - return Promise.resolve(); - } - return Promise.reject( - new Error(t('This value should be greater than the left target value')), - ); - }, - [], - ); - - return ( -
- - - - - - - - - isOperatorNone(prevValues.operator) !== - isOperatorNone(currentValues.operator) || - isOperatorMultiValue(prevValues.operator) !== - isOperatorMultiValue(currentValues.operator) - } - > - {({ getFieldValue }) => - isOperatorNone(getFieldValue('operator')) ? ( - - {operatorField} - - ) : isOperatorMultiValue(getFieldValue('operator')) ? ( - - - ({ - validator: targetValueLeftValidator( - getFieldValue('targetValueRight'), - ), - }), - ]} - dependencies={['targetValueRight']} - validateTrigger="onBlur" - trigger="onBlur" - > - - - - {operatorField} - - ({ - validator: targetValueRightValidator( - getFieldValue('targetValueLeft'), - ), - }), - ]} - dependencies={['targetValueLeft']} - validateTrigger="onBlur" - trigger="onBlur" - > - - - - - ) : ( - - {operatorField} - - - - - - - ) - } - - - - - - -
- ); -}; +}) => ( +
+ + + + + + + + + {renderOperatorFields} + + + + + + +
+);