Browse Source

refactor: advancedSearch component

Signed-off-by: ryjiang <jiangruiyi@gmail.com>
ryjiang 3 months ago
parent
commit
55ae614a37

+ 34 - 35
client/src/components/advancedSearch/Condition.tsx

@@ -1,4 +1,4 @@
-import React, { useState, useEffect, useMemo } from 'react';
+import React, { useState, useEffect, useMemo, useCallback } from 'react';
 import { Theme, IconButton, TextField, SelectChangeEvent } from '@mui/material';
 import { makeStyles } from '@mui/styles';
 import CloseIcon from '@mui/icons-material/Close';
@@ -33,8 +33,6 @@ const Condition: FC<ConditionProps> = props => {
     initData?.isCorrect || false
   );
 
-  const [isKeyLegal, setIsKeyLegal] = useState(initData?.isCorrect || false);
-
   /**
    * Check condition's value by field's and operator's type.
    * Trigger condition change event.
@@ -42,19 +40,13 @@ const Condition: FC<ConditionProps> = props => {
   useEffect(() => {
     const type = conditionField?.data_type;
     const conditionValueWithNoSpace = conditionValue.replaceAll(' ', '');
-    let isKeyLegal = false;
     let isLegal = checkValue({
       value: conditionValueWithNoSpace,
       type,
       operator,
     });
-
-    // if type is json, check the json key is valid
-    if (type === DataTypeStringEnum.JSON) {
-      isKeyLegal = jsonKeyValue.trim() !== '';
-    }
-
-    setIsKeyLegal(isKeyLegal);
+    const isKeyLegal =
+      type === DataTypeStringEnum.JSON ? jsonKeyValue.trim() !== '' : true;
     setIsValueLegal(isLegal);
     triggerChange(id, {
       field: conditionField,
@@ -68,7 +60,6 @@ const Condition: FC<ConditionProps> = props => {
           type !== DataTypeStringEnum.JSON),
       id,
     });
-    // No need for 'id' and 'triggerChange'.
     // eslint-disable-next-line react-hooks/exhaustive-deps
   }, [conditionField, operator, conditionValue, jsonKeyValue]);
 
@@ -78,33 +69,42 @@ const Condition: FC<ConditionProps> = props => {
     if (conditionField.data_type === DataTypeStringEnum.Bool) {
       const data = LOGICAL_OPERATORS.filter(v => v.value === '==');
       setOperator(data[0].value);
-      // bool only support ==
       return data;
     }
     return LOGICAL_OPERATORS;
   }, [conditionField]);
 
-  // Logic operator input change.
-  const handleOpChange = (event: SelectChangeEvent<unknown>) => {
+  const handleOpChange = useCallback((event: SelectChangeEvent<unknown>) => {
     setOperator(event.target.value);
-  };
-  // Field Name input change.
-  const handleFieldNameChange = (event: SelectChangeEvent<unknown>) => {
-    const value = event.target.value;
-    const target = fields.find(field => field.name === value);
-    target && setConditionField(target);
-  };
-  // Value input change.
-  const handleValueChange = (event: React.ChangeEvent<HTMLInputElement>) => {
-    const value = event.target.value;
-    setConditionValue(value);
-  };
+  }, []);
+
+  const handleFieldNameChange = useCallback(
+    (event: SelectChangeEvent<unknown>) => {
+      const value = event.target.value;
+      const target = fields.find(field => field.name === value);
+      if (target) setConditionField(target);
+    },
+    [fields]
+  );
+
+  const handleValueChange = useCallback(
+    (event: React.ChangeEvent<HTMLInputElement>) => {
+      setConditionValue(event.target.value);
+    },
+    []
+  );
+
+  const handleJSONKeyChange = useCallback(
+    (event: React.ChangeEvent<HTMLInputElement>) => {
+      setJsonKeyValue(event.target.value);
+    },
+    []
+  );
 
-  // Value JSON change.
-  const handleJSONKeyChange = (event: React.ChangeEvent<HTMLInputElement>) => {
-    const value = event.target.value;
-    setJsonKeyValue(value);
-  };
+  const isKeyLegal =
+    conditionField?.data_type === DataTypeStringEnum.JSON
+      ? jsonKeyValue.trim() !== ''
+      : true;
 
   return (
     <div className={`${classes.wrapper} ${className}`} {...others}>
@@ -116,17 +116,16 @@ const Condition: FC<ConditionProps> = props => {
         variant="filled"
         wrapperClass={classes.fieldName}
       />
-      {conditionField?.data_type === DataTypeStringEnum.JSON ? (
+      {conditionField?.data_type === DataTypeStringEnum.JSON && (
         <TextField
           className={classes.key}
           label="key"
           variant="filled"
           value={jsonKeyValue}
-          // size="small"
           onChange={handleJSONKeyChange}
           error={!isKeyLegal}
         />
-      ) : null}
+      )}
       <CustomSelector
         label="Logic"
         value={operator}

+ 29 - 28
client/src/components/advancedSearch/ConditionGroup.tsx

@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import React, { useState, useCallback } from 'react';
 import { useTranslation } from 'react-i18next';
 import { Theme } from '@mui/material';
 import { makeStyles } from '@mui/styles';
@@ -17,34 +17,35 @@ import type {
 const BinaryLogicalOp: FC<BinaryLogicalOpProps> = props => {
   const { onChange, className, initValue = 'and' } = props;
   const [operator, setOperator] = useState(initValue);
-  const handleChange = (
-    event: React.MouseEvent<HTMLElement>,
-    newOp: string
-  ) => {
-    if (newOp !== null) {
-      setOperator(newOp);
-      onChange(newOp);
-    }
-  };
+  const handleChange = useCallback(
+    (
+      event: React.MouseEvent<HTMLElement>,
+      newOp: string
+    ) => {
+      if (newOp !== null) {
+        setOperator(newOp);
+        onChange(newOp);
+      }
+    },
+    [onChange]
+  );
   return (
-    <>
-      <div className={`${className} op-${operator}`}>
-        <ToggleButtonGroup
-          value={operator}
-          exclusive
-          onChange={handleChange}
-          aria-label="Binary Logical Operator"
-        >
-          <ToggleButton value="and" aria-label="And">
-            AND
-          </ToggleButton>
-          <ToggleButton value="or" aria-label="Or">
-            OR
-          </ToggleButton>
-        </ToggleButtonGroup>
-        <div className="op-split" />
-      </div>
-    </>
+    <div className={`${className} op-${operator}`}>
+      <ToggleButtonGroup
+        value={operator}
+        exclusive
+        onChange={handleChange}
+        aria-label="Binary Logical Operator"
+      >
+        <ToggleButton value="and" aria-label="And">
+          AND
+        </ToggleButton>
+        <ToggleButton value="or" aria-label="Or">
+          OR
+        </ToggleButton>
+      </ToggleButtonGroup>
+      <div className="op-split" />
+    </div>
   );
 };
 

+ 21 - 16
client/src/components/advancedSearch/CopyButton.tsx

@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import React, { useState, useCallback } from 'react';
 import { Theme } from '@mui/material';
 import { makeStyles } from '@mui/styles';
 import icons from '../icons/Icons';
@@ -15,7 +15,7 @@ const CopyButton: FC<CopyButtonProps> = props => {
   const { t: commonTrans } = useTranslation();
   const [tooltipTitle, setTooltipTitle] = useState('Copy');
 
-  const unsecuredCopyToClipboard = (v: string) => {
+  const unsecuredCopyToClipboard = useCallback((v: string) => {
     const textArea = document.createElement('textarea');
     textArea.style.position = 'fixed';
     textArea.style.opacity = '0';
@@ -30,21 +30,26 @@ const CopyButton: FC<CopyButtonProps> = props => {
       console.error('Unable to copy to clipboard', err);
     }
     document.body.removeChild(textArea);
-  };
+  }, []);
 
-  const handleClick = (event: React.MouseEvent<HTMLElement>, v: string) => {
-    event.stopPropagation();
-
-    if (typeof v === 'object') {
-      v = JSON.stringify(v);
-    }
-
-    setTooltipTitle(commonTrans('copy.copied'));
-    navigator.clipboard?.writeText(v) ?? unsecuredCopyToClipboard(v);
-    setTimeout(() => {
-      setTooltipTitle(commonTrans('copy.copy'));
-    }, 1000);
-  };
+  const handleClick = useCallback(
+    (event: React.MouseEvent<HTMLElement>, v: string) => {
+      event.stopPropagation();
+      if (typeof v === 'object') {
+        v = JSON.stringify(v);
+      }
+      setTooltipTitle(commonTrans('copy.copied'));
+      if (navigator.clipboard && navigator.clipboard.writeText) {
+        navigator.clipboard.writeText(v);
+      } else {
+        unsecuredCopyToClipboard(v);
+      }
+      setTimeout(() => {
+        setTooltipTitle(commonTrans('copy.copy'));
+      }, 1000);
+    },
+    [commonTrans, unsecuredCopyToClipboard]
+  );
 
   return (
     <CustomIconButton

+ 26 - 58
client/src/components/advancedSearch/utils.ts

@@ -1,19 +1,12 @@
 import { DataTypeStringEnum } from '@/consts';
 
 export const formatValue = (value: string, type: string, operator: string) => {
-  let conditionValue: string = ''; //
   switch (type) {
     case DataTypeStringEnum.VarChar:
-      switch (operator) {
-        case 'in':
-        case 'not in':
-          conditionValue = `${value}`;
-          break;
-        default:
-          conditionValue = `"${value}"`;
-          break;
+      if (operator === 'in' || operator === 'not in') {
+        return `${value}`;
       }
-      break;
+      return `"${value}"`;
     case DataTypeStringEnum.JSON:
       switch (operator) {
         case '<':
@@ -21,39 +14,25 @@ export const formatValue = (value: string, type: string, operator: string) => {
         case '==':
         case '>=':
         case '<=':
-          conditionValue = value;
-          break;
-        case 'in':
-        case 'not in':
-          conditionValue = `[${value}]`;
-          break;
         case 'JSON_CONTAINS':
         case 'ARRAY_CONTAINS':
-          conditionValue = `${value}`;
-          break;
+          return `${value}`;
+        case 'in':
+        case 'not in':
         case 'ARRAY_CONTAINS_ALL':
         case 'ARRAY_CONTAINS_ANY':
-          conditionValue = `[${value}]`;
-          break;
         case 'JSON_CONTAINS_ALL':
         case 'JSON_CONTAINS_ANY':
-          conditionValue = `[${value}]`;
-          break;
+          return `[${value}]`;
         default:
-          conditionValue = `"${value}"`;
-          break;
+          return `"${value}"`;
       }
-      break;
     default:
-      conditionValue = value;
+      return value;
   }
-
-  return conditionValue;
 };
 
 export const checkValue = (data: any): boolean => {
-  let isLegal = false;
-
   const regInt = /^-?\d+$/;
   const regNumber = /^-?\d+(\.\d+)?$/;
   const regNumberInterval = /^\[(-?\d+(\.\d+)?)(,(-?\d+(\.\d+)?))*\]$/;
@@ -65,48 +44,37 @@ export const checkValue = (data: any): boolean => {
     case DataTypeStringEnum.Int16:
     case DataTypeStringEnum.Int32:
     case DataTypeStringEnum.Int64:
-      // case DataTypeStringEnum:
-      isLegal = isIn
+      return isIn
         ? regIntInterval.test(data.value)
         : regInt.test(data.value);
-      break;
     case DataTypeStringEnum.Float:
     case DataTypeStringEnum.Double:
     case DataTypeStringEnum.FloatVector:
-      isLegal = isIn
+      return isIn
         ? regNumberInterval.test(data.value)
         : regNumber.test(data.value);
-      break;
     case DataTypeStringEnum.Bool:
-      const legalValues = ['false', 'true'];
-      isLegal = legalValues.includes(data.value);
-      break;
+      return ['false', 'true'].includes(data.value);
     case DataTypeStringEnum.VarChar:
-      isLegal = data.value !== '';
-      break;
-    case DataTypeStringEnum.JSON:
+    case DataTypeStringEnum.Array:
+      return data.value !== '';
+    case DataTypeStringEnum.JSON: {
       let type = DataTypeStringEnum.VarChar;
-      switch (data.operator) {
-        case '>':
-        case '<':
-        case '>=':
-        case '<=':
-          type = DataTypeStringEnum.Int64;
+      if (
+        data.operator === '>' ||
+        data.operator === '<' ||
+        data.operator === '>=' ||
+        data.operator === '<='
+      ) {
+        type = DataTypeStringEnum.Int64;
       }
-
-      isLegal = checkValue({
+      return checkValue({
         value: data.value,
-        type: type,
+        type,
         operator: data.operator,
       });
-      break;
-    case DataTypeStringEnum.Array:
-      isLegal = data.value !== '';
-      break;
+    }
     default:
-      isLegal = false;
-      break;
+      return false;
   }
-
-  return isLegal;
 };

+ 1 - 3
client/src/components/code/CodeBlock.tsx

@@ -36,9 +36,7 @@ const CodeBlock: FC<CodeBlockProps> = ({
 }) => {
   const theme = useTheme();
   const classes = getStyles();
-
   const { t: commonTrans } = useTranslation();
-
   const highlightTheme = theme.palette.mode === 'dark' ? vs2015 : github;
 
   return (
@@ -52,7 +50,7 @@ const CodeBlock: FC<CodeBlockProps> = ({
         language={language}
         style={{ ...highlightTheme, ...style }}
         customStyle={CodeStyle}
-        showLineNumbers={true}
+        showLineNumbers
       >
         {code}
       </SyntaxHighlighter>

+ 2 - 4
client/src/components/customButton/CustomButton.tsx

@@ -26,13 +26,11 @@ const CustomButton = ({
   ...props
 }: CustomButtonProps) => {
   const button = <Button disabled={disabled} {...props} />;
-
-  return tooltip ? (
+  if (!tooltip) return button;
+  return (
     <Tooltip title={tooltip} placement={tooltipPlacement}>
       {disabled ? <span>{button}</span> : button}
     </Tooltip>
-  ) : (
-    button
   );
 };
 

+ 3 - 3
client/src/components/customDialog/CustomDialog.tsx

@@ -42,15 +42,15 @@ const CustomDialog: FC<CustomDialogType> = props => {
     cancelLabel = t('cancel'),
     confirmClass = '',
     handleClose,
+    component: CustomComponent,
   } = params;
-  const { component: CustomComponent } = params;
 
   const handleConfirm = async (event: React.FormEvent<HTMLFormElement>) => {
     if (confirm) {
       const res = await confirm();
       if (!res) return;
     }
-    handleClose ? handleClose() : onClose();
+    (handleClose || onClose)();
     event.preventDefault();
   };
 
@@ -59,7 +59,7 @@ const CustomDialog: FC<CustomDialogType> = props => {
       const res = await cancel();
       if (!res) return;
     }
-    handleClose ? handleClose() : onClose();
+    (handleClose || onClose)();
   };
 
   return (