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 renderOperatorFields = ({ getFieldValue }: GetFieldValue) =>
+ isOperatorNone(getFieldValue('operator')) ? (
+
+ {operatorField}
+
+ ) : isOperatorMultiValue(getFieldValue('operator')) ? (
+
+
+
+
+
+
+ {operatorField}
+
+
+
+
+
+
+ ) : (
+
+ {operatorField}
+
+
+
+
+
+
+ );
+
export const FormattingPopoverContent = ({
config,
onChange,
@@ -65,167 +186,44 @@ export const FormattingPopoverContent = ({
config?: ConditionalFormattingConfig;
onChange: (config: ConditionalFormattingConfig) => void;
columns: { label: string; value: string }[];
-}) => {
- const isOperatorMultiValue = (operator?: COMPARATOR) =>
- operator && MULTIPLE_VALUE_COMPARATORS.includes(operator);
-
- const isOperatorNone = (operator?: COMPARATOR) =>
- !operator || operator === COMPARATOR.NONE;
-
- const operatorField = useMemo(
- () => (
-
-
-
- ),
- [],
- );
-
- 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 (
-
- );
-};
+}) => (
+
+);