Browse Source

rm search from src/pages

czhen 3 years ago
parent
commit
49c5914da1

+ 1 - 1
client/src/http/Collection.ts

@@ -1,7 +1,7 @@
 import { ChildrenStatusType } from '../components/status/Types';
 import { CollectionView, InsertDataParam } from '../pages/collections/Types';
 import { Field } from '../pages/schema/Types';
-import { VectorSearchParam } from '../pages/search/Types';
+import { VectorSearchParam } from '../types/SearchTypes';
 import { QueryParam } from '../pages/query/Types';
 import { IndexState, ShowCollectionsType } from '../types/Milvus';
 import { formatNumber } from '../utils/Common';

+ 0 - 1
client/src/pages/search/Constants.ts

@@ -1 +0,0 @@
-export const TOP_K_OPTIONS = [50, 100, 150, 200, 250];

+ 0 - 289
client/src/pages/search/SearchParams.tsx

@@ -1,289 +0,0 @@
-import { makeStyles, Theme } from '@material-ui/core';
-import { FC, useCallback, useEffect, useMemo } from 'react';
-import { useTranslation } from 'react-i18next';
-import CustomInput from '../../components/customInput/CustomInput';
-import { ITextfieldConfig } from '../../components/customInput/Types';
-import CustomSelector from '../../components/customSelector/CustomSelector';
-import { Option } from '../../components/customSelector/Types';
-import {
-  DEFAULT_NLIST_VALUE,
-  DEFAULT_SEARCH_PARAM_VALUE_MAP,
-  INDEX_CONFIG,
-  METRIC_OPTIONS_MAP,
-  searchKeywordsType,
-} from '../../consts/Milvus';
-import { useFormValidation } from '../../hooks/Form';
-import { formatForm } from '../../utils/Form';
-import { SearchParamInputConfig, SearchParamsProps } from './Types';
-
-const getStyles = makeStyles((theme: Theme) => ({
-  selector: {
-    width: '100%',
-    marginTop: theme.spacing(2),
-  },
-  input: {
-    marginTop: theme.spacing(2),
-  },
-  inlineInput: {
-    marginTop: theme.spacing(2),
-    width: '48%',
-  },
-  inlineInputWrapper: {
-    display: 'flex',
-    justifyContent: 'space-between',
-  },
-}));
-
-const SearchParams: FC<SearchParamsProps> = ({
-  indexType,
-  indexParams,
-  searchParamsForm,
-  handleFormChange,
-  embeddingType,
-  metricType,
-  topK,
-  setParamsDisabled,
-  wrapperClass = '',
-}) => {
-  const { t: indexTrans } = useTranslation('index');
-  const { t: warningTrans } = useTranslation('warning');
-  const classes = getStyles();
-
-  const metricOptions: Option[] = METRIC_OPTIONS_MAP[embeddingType];
-
-  // search params key list, depends on index type
-  // e.g. ['nprobe']
-  const searchParams = useMemo(
-    (): searchKeywordsType[] =>
-      indexType !== ''
-        ? [...INDEX_CONFIG[indexType].search, 'round_decimal']
-        : ['round_decimal'],
-    [indexType]
-  );
-
-  const handleInputChange = useCallback(
-    (key: string, value: number) => {
-      const form = { ...searchParamsForm, [key]: value };
-      handleFormChange(form);
-    },
-    [handleFormChange, searchParamsForm]
-  );
-
-  /**
-   * function to transfer search params to CustomInput need config type
-   */
-  const getNumberInputConfig = useCallback(
-    (params: SearchParamInputConfig): ITextfieldConfig => {
-      const {
-        label,
-        key,
-        min,
-        max,
-        value,
-        handleChange,
-        isInt = true,
-      } = params;
-
-      // search_k range is special compared to others,need to be handled separately
-      // range: {-1} ∪ [top_k, n × n_trees]
-      const isSearchK = label === 'search_k';
-
-      const config: ITextfieldConfig = {
-        label,
-        key,
-        onChange: value => {
-          handleChange(value);
-        },
-        className: classes.inlineInput,
-        variant: 'filled',
-        type: 'number',
-        value,
-        validations: [
-          {
-            rule: 'require',
-            errorText: warningTrans('required', { name: label }),
-          },
-        ],
-      };
-      if (!isSearchK && min && max) {
-        config.validations?.push({
-          rule: 'range',
-          errorText: warningTrans('range', { min, max }),
-          extraParam: {
-            min,
-            max,
-            type: 'number',
-          },
-        });
-      }
-
-      if (isInt) {
-        config.validations?.push({
-          rule: 'integer',
-          errorText: warningTrans('integer', { name: label }),
-        });
-      }
-
-      // search_k
-      if (isSearchK) {
-        config.validations?.push({
-          rule: 'specValueOrRange',
-          errorText: warningTrans('specValueOrRange', {
-            name: label,
-            min,
-            max,
-            specValue: -1,
-          }),
-          extraParam: {
-            min,
-            max,
-            compareValue: -1,
-            type: 'number',
-          },
-        });
-      }
-      return config;
-    },
-    [classes.inlineInput, warningTrans]
-  );
-
-  const getSearchInputConfig = useCallback(
-    (paramKey: searchKeywordsType): ITextfieldConfig => {
-      const nlist = Number(
-        // nlist range is [1, 65536], if user didn't create index, we set 1024 as default nlist value
-        indexParams.find(p => p.key === 'nlist')?.value || DEFAULT_NLIST_VALUE
-      );
-
-      const configParamMap: {
-        [key in searchKeywordsType]: SearchParamInputConfig;
-      } = {
-        round_decimal: {
-          label: 'Round Decimals',
-          key: 'round_decimal',
-          value: searchParamsForm['round_decimal'] || '',
-          min: -1,
-          max: 10,
-          isInt: true,
-          handleChange: value => {
-            handleInputChange('round_decimal', value);
-          },
-          className: classes.inlineInput,
-        },
-        nprobe: {
-          label: 'nprobe',
-          key: 'nprobe',
-          value: searchParamsForm['nprobe'] || '',
-          min: 1,
-          max: nlist,
-          isInt: true,
-          handleChange: value => {
-            handleInputChange('nprobe', value);
-          },
-          className: classes.inlineInput,
-        },
-
-        ef: {
-          label: 'ef',
-          key: 'ef',
-          value: searchParamsForm['ef'] || '',
-          min: topK,
-          max: 32768,
-          isInt: true,
-          handleChange: value => {
-            handleInputChange('ef', value);
-          },
-        },
-        search_k: {
-          label: 'search_k',
-          key: 'search_k',
-          value: searchParamsForm['search_k'] || '',
-          min: topK,
-          // n * n_trees can be infinity
-          max: Infinity,
-          isInt: true,
-          handleChange: value => {
-            handleInputChange('search_k', value);
-          },
-        },
-        search_length: {
-          label: 'search_length',
-          key: 'search_length',
-          value: searchParamsForm['search_length'] || '',
-          min: 10,
-          max: 300,
-          isInt: true,
-          handleChange: value => {
-            handleInputChange('search_length', value);
-          },
-        },
-      };
-
-      const param = configParamMap[paramKey];
-      return getNumberInputConfig(param);
-    },
-    [
-      indexParams,
-      searchParamsForm,
-      classes.inlineInput,
-      topK,
-      getNumberInputConfig,
-      handleInputChange,
-    ]
-  );
-
-  useEffect(() => {
-    // generate different form according to search params
-    const form = searchParams.reduce(
-      (paramsForm, param) => ({
-        ...paramsForm,
-        [param]: DEFAULT_SEARCH_PARAM_VALUE_MAP[param],
-      }),
-      {}
-    );
-    handleFormChange(form);
-  }, [searchParams, handleFormChange]);
-
-  const checkedForm = useMemo(() => {
-    const { ...needCheckItems } = searchParamsForm;
-    return formatForm(needCheckItems);
-  }, [searchParamsForm]);
-
-  const { validation, checkIsValid, disabled } = useFormValidation(checkedForm);
-
-  useEffect(() => {
-    setParamsDisabled(disabled);
-  }, [disabled, setParamsDisabled]);
-
-  return (
-    <div className={wrapperClass}>
-      {/* metric type */}
-      <CustomSelector
-        options={metricOptions}
-        value={metricType}
-        label={indexTrans('metric')}
-        wrapperClass={classes.selector}
-        variant="filled"
-        onChange={(e: { target: { value: unknown } }) => {
-          // not selectable now, so not set onChange event
-        }}
-        // not selectable now
-        // readOnly can't avoid all events, so we use disabled instead
-        disabled={true}
-      />
-      <div className={classes.inlineInputWrapper}>
-        {/* dynamic params, now every type only has one param except metric type */}
-        {searchParams.map(param => (
-          <CustomInput
-            key={param}
-            type="text"
-            textConfig={getSearchInputConfig(param)}
-            checkValid={checkIsValid}
-            validInfo={validation}
-          />
-        ))}
-      </div>
-    </div>
-  );
-};
-
-export default SearchParams;

+ 0 - 129
client/src/pages/search/Styles.ts

@@ -1,129 +0,0 @@
-import { makeStyles, Theme } from '@material-ui/core';
-
-export const getVectorSearchStyles = makeStyles((theme: Theme) => ({
-  form: {
-    display: 'flex',
-    justifyContent: 'space-between',
-
-    '& .field': {
-      display: 'flex',
-      flexDirection: 'column',
-      flexBasis: '33%',
-
-      padding: theme.spacing(2, 3, 4),
-      backgroundColor: '#fff',
-      borderRadius: theme.spacing(0.5),
-      boxShadow: '3px 3px 10px rgba(0, 0, 0, 0.05)',
-
-      '& .textarea': {
-        border: `1px solid ${theme.palette.milvusGrey.main}`,
-        borderRadius: theme.spacing(0.5),
-        padding: theme.spacing(1),
-        paddingBottom: '18px',
-        marginTop: theme.spacing(2),
-      },
-
-      // reset default style
-      '& .textfield': {
-        padding: 0,
-        fontSize: '14px',
-        lineHeight: '20px',
-        fontWeight: 400,
-
-        '&::before': {
-          borderBottom: 'none',
-        },
-
-        '&::after': {
-          borderBottom: 'none',
-        },
-      },
-
-      '& .multiline': {
-        '& textarea': {
-          overflow: 'auto',
-          // change scrollbar style
-          '&::-webkit-scrollbar': {
-            width: '8px',
-          },
-
-          '&::-webkit-scrollbar-track': {
-            backgroundColor: '#f9f9f9',
-          },
-
-          '&::-webkit-scrollbar-thumb': {
-            borderRadius: '8px',
-            backgroundColor: '#eee',
-          },
-        },
-      },
-    },
-
-    '& .field-second': {
-      flexGrow: 1,
-      margin: theme.spacing(0, 1),
-    },
-
-    // Textfield component has more bottom space to show error msg when validation
-    // if still set padding-bottom, the whole form space will be stretched
-    '& .field-params': {
-      paddingBottom: 0,
-    },
-
-    '& .text': {
-      color: theme.palette.milvusGrey.dark,
-      fontWeight: 500,
-    },
-  },
-  selector: {
-    width: '100%',
-    marginTop: theme.spacing(2),
-  },
-  paramsWrapper: {
-    display: 'flex',
-    flexDirection: 'column',
-  },
-  toolbar: {
-    display: 'flex',
-    justifyContent: 'space-between',
-    alignItems: 'center',
-
-    padding: theme.spacing(2, 0),
-
-    '& .left': {
-      display: 'flex',
-      alignItems: 'center',
-
-      '& .text': {
-        color: theme.palette.milvusGrey.main,
-      },
-    },
-    '& .right': {
-      '& .btn': {
-        marginRight: theme.spacing(1),
-      },
-      '& .icon': {
-        fontSize: '16px',
-      },
-    },
-  },
-  menuLabel: {
-    minWidth: '108px',
-
-    padding: theme.spacing(0, 1),
-    margin: theme.spacing(0, 1),
-
-    backgroundColor: '#fff',
-    color: theme.palette.milvusGrey.dark,
-  },
-  menuItem: {
-    fontWeight: 500,
-    fontSize: '12px',
-    lineHeight: '16px',
-    color: theme.palette.milvusGrey.dark,
-  },
-  error: {
-    marginTop: theme.spacing(1),
-    color: theme.palette.error.main,
-  },
-}));

+ 0 - 509
client/src/pages/search/VectorSearch.tsx

@@ -1,509 +0,0 @@
-import { TextField, Typography } from '@material-ui/core';
-import { useTranslation } from 'react-i18next';
-import { useNavigationHook } from '../../hooks/Navigation';
-import { ALL_ROUTER_TYPES } from '../../router/Types';
-import CustomSelector from '../../components/customSelector/CustomSelector';
-import { useCallback, useEffect, useMemo, useState } from 'react';
-import SearchParams from './SearchParams';
-import { DEFAULT_METRIC_VALUE_MAP } from '../../consts/Milvus';
-import { FieldOption, SearchResultView, VectorSearchParam } from './Types';
-import MilvusGrid from '../../components/grid/Grid';
-import EmptyCard from '../../components/cards/EmptyCard';
-import icons from '../../components/icons/Icons';
-import { usePaginationHook } from '../../hooks/Pagination';
-import CustomButton from '../../components/customButton/CustomButton';
-import SimpleMenu from '../../components/menu/SimpleMenu';
-import { TOP_K_OPTIONS } from './Constants';
-import { Option } from '../../components/customSelector/Types';
-import { CollectionHttp } from '../../http/Collection';
-import { CollectionData, DataTypeEnum } from '../collections/Types';
-import { IndexHttp } from '../../http/Index';
-import { getVectorSearchStyles } from './Styles';
-import { parseValue } from '../../utils/Insert';
-import {
-  classifyFields,
-  getDefaultIndexType,
-  getEmbeddingType,
-  getNonVectorFieldsForFilter,
-  getVectorFieldOptions,
-  transferSearchResult,
-} from '../../utils/search';
-import { ColDefinitionsType } from '../../components/grid/Types';
-import Filter from '../../components/advancedSearch';
-import { Field } from '../../components/advancedSearch/Types';
-import { useLocation } from 'react-router-dom';
-import { parseLocationSearch } from '../../utils/Format';
-
-const VectorSearch = () => {
-  useNavigationHook(ALL_ROUTER_TYPES.SEARCH);
-  const location = useLocation();
-
-  // i18n
-  const { t: searchTrans } = useTranslation('search');
-  const { t: btnTrans } = useTranslation('btn');
-  const classes = getVectorSearchStyles();
-
-  // data stored inside the component
-  const [tableLoading, setTableLoading] = useState<boolean>(false);
-  const [collections, setCollections] = useState<CollectionData[]>([]);
-  const [selectedCollection, setSelectedCollection] = useState<string>('');
-  const [fieldOptions, setFieldOptions] = useState<FieldOption[]>([]);
-  // fields for advanced filter
-  const [filterFields, setFilterFields] = useState<Field[]>([]);
-  const [selectedField, setSelectedField] = useState<string>('');
-  // search params form
-  const [searchParam, setSearchParam] = useState<{ [key in string]: number }>(
-    {}
-  );
-  // search params disable state
-  const [paramDisabled, setParamDisabled] = useState<boolean>(true);
-  // use null as init value before search, empty array means no results
-  const [searchResult, setSearchResult] = useState<SearchResultView[] | null>(
-    null
-  );
-  // default topK is 100
-  const [topK, setTopK] = useState<number>(100);
-  const [expression, setExpression] = useState<string>('');
-  const [vectors, setVectors] = useState<string>('');
-
-  const {
-    pageSize,
-    handlePageSize,
-    currentPage,
-    handleCurrentPage,
-    total,
-    data: result,
-    order,
-    orderBy,
-    handleGridSort,
-  } = usePaginationHook(searchResult || []);
-
-  const collectionOptions: Option[] = useMemo(
-    () =>
-      collections.map(c => ({
-        label: c._name,
-        value: c._name,
-      })),
-    [collections]
-  );
-
-  const outputFields: string[] = useMemo(() => {
-    const fields =
-      collections.find(c => c._name === selectedCollection)?._fields || [];
-    // vector field can't be output fields
-    const invalidTypes = ['BinaryVector', 'FloatVector'];
-    const nonVectorFields = fields.filter(
-      field => !invalidTypes.includes(field._fieldType)
-    );
-    return nonVectorFields.map(f => f._fieldName);
-  }, [selectedCollection, collections]);
-
-  const primaryKeyField = useMemo(() => {
-    const selectedCollectionInfo = collections.find(
-      c => c._name === selectedCollection
-    );
-    const fields = selectedCollectionInfo?._fields || [];
-    return fields.find(f => f._isPrimaryKey)?._fieldName;
-  }, [selectedCollection, collections]);
-
-  const colDefinitions: ColDefinitionsType[] = useMemo(() => {
-    /**
-     * id represents primary key, score represents distance
-     * since we transfer score to distance in the view, and original field which is primary key has already in the table
-     * we filter 'id' and 'score' to avoid redundant data
-     */
-    return searchResult && searchResult.length > 0
-      ? Object.keys(searchResult[0])
-          .filter(item => {
-            // if primary key field name is id, don't filter it
-            const invalidItems =
-              primaryKeyField === 'id' ? ['score'] : ['id', 'score'];
-            return !invalidItems.includes(item);
-          })
-          .map(key => ({
-            id: key,
-            align: 'left',
-            disablePadding: false,
-            label: key,
-          }))
-      : [];
-  }, [searchResult, primaryKeyField]);
-
-  const {
-    metricType,
-    indexType,
-    indexParams,
-    fieldType,
-    embeddingType,
-    selectedFieldDimension,
-  } = useMemo(() => {
-    if (selectedField !== '') {
-      // field options must contain selected field, so selectedFieldInfo will never undefined
-      const selectedFieldInfo = fieldOptions.find(
-        f => f.value === selectedField
-      );
-      const index = selectedFieldInfo?.indexInfo;
-      const embeddingType = getEmbeddingType(selectedFieldInfo!.fieldType);
-      const metric =
-        index?._metricType || DEFAULT_METRIC_VALUE_MAP[embeddingType];
-      const indexParams = index?._indexParameterPairs || [];
-      const dim = selectedFieldInfo?.dimension || 0;
-
-      return {
-        metricType: metric,
-        indexType: index?._indexType || getDefaultIndexType(embeddingType),
-        indexParams,
-        fieldType: DataTypeEnum[selectedFieldInfo?.fieldType!],
-        embeddingType,
-        selectedFieldDimension: dim,
-      };
-    }
-
-    return {
-      metricType: '',
-      indexType: '',
-      indexParams: [],
-      fieldType: 0,
-      embeddingType: DataTypeEnum.FloatVector,
-      selectedFieldDimension: 0,
-    };
-  }, [selectedField, fieldOptions]);
-
-  /**
-   * vector value validation
-   * @return whether is valid
-   */
-  const vectorValueValid = useMemo(() => {
-    // if user hasn't input value or not select field, don't trigger validation check
-    if (vectors === '' || selectedFieldDimension === 0) {
-      return true;
-    }
-    const value = parseValue(vectors);
-    const isArray = Array.isArray(value);
-    return isArray && value.length === selectedFieldDimension;
-  }, [vectors, selectedFieldDimension]);
-
-  const searchDisabled = useMemo(() => {
-    /**
-     * before search, user must:
-     * 1. enter vector value, it should be an array and length should be equal to selected field dimension
-     * 2. choose collection and field
-     * 3. set extra search params
-     */
-    const isInvalid =
-      vectors === '' ||
-      selectedCollection === '' ||
-      selectedField === '' ||
-      paramDisabled ||
-      !vectorValueValid;
-    return isInvalid;
-  }, [
-    paramDisabled,
-    selectedField,
-    selectedCollection,
-    vectors,
-    vectorValueValid,
-  ]);
-
-  // fetch data
-  const fetchCollections = useCallback(async () => {
-    const collections = await CollectionHttp.getCollections();
-    setCollections(collections);
-  }, []);
-
-  const fetchFieldsWithIndex = useCallback(
-    async (collectionName: string, collections: CollectionData[]) => {
-      const fields =
-        collections.find(c => c._name === collectionName)?._fields || [];
-      const indexes = await IndexHttp.getIndexInfo(collectionName);
-
-      const { vectorFields, nonVectorFields } = classifyFields(fields);
-
-      // only vector type fields can be select
-      const fieldOptions = getVectorFieldOptions(vectorFields, indexes);
-      setFieldOptions(fieldOptions);
-      if (fieldOptions.length > 0) {
-        // set first option value as default field value
-        const [{ value: defaultFieldValue }] = fieldOptions;
-        setSelectedField(defaultFieldValue as string);
-      }
-
-      // only non vector type fields can be advanced filter
-      const filterFields = getNonVectorFieldsForFilter(nonVectorFields);
-      setFilterFields(filterFields);
-    },
-    []
-  );
-
-  useEffect(() => {
-    fetchCollections();
-  }, [fetchCollections]);
-
-  // get field options with index when selected collection changed
-  useEffect(() => {
-    if (selectedCollection !== '') {
-      fetchFieldsWithIndex(selectedCollection, collections);
-    }
-  }, [selectedCollection, collections, fetchFieldsWithIndex]);
-
-  // set default collection value if is from overview page
-  useEffect(() => {
-    if (location.search && collections.length > 0) {
-      const { collectionName } = parseLocationSearch(location.search);
-      // collection name validation
-      const isNameValid = collections
-        .map(c => c._name)
-        .includes(collectionName);
-      isNameValid && setSelectedCollection(collectionName);
-    }
-  }, [location, collections]);
-
-  // icons
-  const VectorSearchIcon = icons.vectorSearch;
-  const ResetIcon = icons.refresh;
-  const ArrowIcon = icons.dropdown;
-
-  // methods
-  const handlePageChange = (e: any, page: number) => {
-    handleCurrentPage(page);
-  };
-  const handleReset = () => {
-    /**
-     * reset search includes:
-     * 1. reset vectors
-     * 2. reset selected collection and field
-     * 3. reset search params
-     * 4. reset advanced filter expression
-     * 5. clear search result
-     */
-    setVectors('');
-    setSelectedField('');
-    setSelectedCollection('');
-    setSearchResult(null);
-    setFilterFields([]);
-    setExpression('');
-  };
-  const handleSearch = async (topK: number, expr = expression) => {
-    const searhParamPairs = {
-      params: JSON.stringify(searchParam),
-      anns_field: selectedField,
-      topk: topK,
-      metric_type: metricType,
-      round_decimal: searchParam.round_decimal,
-    };
-
-    const params: VectorSearchParam = {
-      output_fields: outputFields,
-      expr,
-      search_params: searhParamPairs,
-      vectors: [parseValue(vectors)],
-      vector_type: fieldType,
-    };
-
-    setTableLoading(true);
-    try {
-      const res = await CollectionHttp.vectorSearchData(
-        selectedCollection,
-        params
-      );
-      setTableLoading(false);
-
-      const result = transferSearchResult(res.results);
-      setSearchResult(result);
-    } catch (err) {
-      setTableLoading(false);
-    }
-  };
-  const handleAdvancedFilterChange = (expression: string) => {
-    setExpression(expression);
-    if (!searchDisabled) {
-      handleSearch(topK, expression);
-    }
-  };
-
-  const handleVectorChange = (value: string) => {
-    setVectors(value);
-  };
-
-  return (
-    <section className="page-wrapper">
-      {/* form section */}
-      <form className={classes.form}>
-        {/**
-         * vector value textarea
-         * use field-params class because it also has error msg if invalid
-         */}
-        <fieldset className="field field-params">
-          <Typography className="text">
-            {searchTrans('firstTip', {
-              dimensionTip:
-                selectedFieldDimension !== 0
-                  ? `(dimension: ${selectedFieldDimension})`
-                  : '',
-            })}
-          </Typography>
-          <TextField
-            className="textarea"
-            InputProps={{
-              classes: {
-                root: 'textfield',
-                multiline: 'multiline',
-              },
-            }}
-            multiline
-            rows={5}
-            placeholder={searchTrans('vectorPlaceholder')}
-            value={vectors}
-            onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
-              handleVectorChange(e.target.value as string);
-            }}
-          />
-          {/* validation */}
-          {!vectorValueValid && (
-            <Typography variant="caption" className={classes.error}>
-              {searchTrans('vectorValueWarning', {
-                dimension: selectedFieldDimension,
-              })}
-            </Typography>
-          )}
-        </fieldset>
-        {/* collection and field selectors */}
-        <fieldset className="field field-second">
-          <Typography className="text">{searchTrans('secondTip')}</Typography>
-          <CustomSelector
-            options={collectionOptions}
-            wrapperClass={classes.selector}
-            variant="filled"
-            label={searchTrans(
-              collectionOptions.length === 0 ? 'noCollection' : 'collection'
-            )}
-            disabled={collectionOptions.length === 0}
-            value={selectedCollection}
-            onChange={(e: { target: { value: unknown } }) => {
-              const collection = e.target.value;
-
-              setSelectedCollection(collection as string);
-              // every time selected collection changed, reset field
-              setSelectedField('');
-            }}
-          />
-          <CustomSelector
-            options={fieldOptions}
-            // readOnly can't avoid all events, so we use disabled instead
-            disabled={selectedCollection === ''}
-            wrapperClass={classes.selector}
-            variant="filled"
-            label={searchTrans('field')}
-            value={selectedField}
-            onChange={(e: { target: { value: unknown } }) => {
-              const field = e.target.value;
-              setSelectedField(field as string);
-            }}
-          />
-        </fieldset>
-        {/* search params selectors */}
-        <fieldset className="field field-params">
-          <Typography className="text">{searchTrans('thirdTip')}</Typography>
-          <SearchParams
-            wrapperClass={classes.paramsWrapper}
-            metricType={metricType!}
-            embeddingType={
-              embeddingType as
-                | DataTypeEnum.BinaryVector
-                | DataTypeEnum.FloatVector
-            }
-            indexType={indexType}
-            indexParams={indexParams!}
-            searchParamsForm={searchParam}
-            handleFormChange={setSearchParam}
-            topK={topK}
-            setParamsDisabled={setParamDisabled}
-          />
-        </fieldset>
-      </form>
-
-      {/**
-       * search toolbar section
-       * including topK selector, advanced filter, search and reset btn
-       */}
-      <section className={classes.toolbar}>
-        <div className="left">
-          <Typography variant="h5" className="text">
-            {`${searchTrans('result')}: `}
-          </Typography>
-          {/* topK selector */}
-          <SimpleMenu
-            label={searchTrans('topK', { number: topK })}
-            menuItems={TOP_K_OPTIONS.map(item => ({
-              label: item.toString(),
-              callback: () => {
-                setTopK(item);
-                if (!searchDisabled) {
-                  handleSearch(item);
-                }
-              },
-              wrapperClass: classes.menuItem,
-            }))}
-            buttonProps={{
-              className: classes.menuLabel,
-              endIcon: <ArrowIcon />,
-            }}
-            menuItemWidth="108px"
-          />
-
-          <Filter
-            title="Advanced Filter"
-            fields={filterFields}
-            filterDisabled={selectedField === '' || selectedCollection === ''}
-            onSubmit={handleAdvancedFilterChange}
-          />
-        </div>
-        <div className="right">
-          <CustomButton className="btn" onClick={handleReset}>
-            <ResetIcon classes={{ root: 'icon' }} />
-            {btnTrans('reset')}
-          </CustomButton>
-          <CustomButton
-            variant="contained"
-            disabled={searchDisabled}
-            onClick={() => handleSearch(topK)}
-          >
-            {btnTrans('search')}
-          </CustomButton>
-        </div>
-      </section>
-
-      {/* search result table section */}
-      {(searchResult && searchResult.length > 0) || tableLoading ? (
-        <MilvusGrid
-          toolbarConfigs={[]}
-          colDefinitions={colDefinitions}
-          rows={result}
-          rowCount={total}
-          primaryKey="rank"
-          page={currentPage}
-          onChangePage={handlePageChange}
-          rowsPerPage={pageSize}
-          setRowsPerPage={handlePageSize}
-          openCheckBox={false}
-          isLoading={tableLoading}
-          orderBy={orderBy}
-          order={order}
-          handleSort={handleGridSort}
-        />
-      ) : (
-        <EmptyCard
-          wrapperClass={`page-empty-card`}
-          icon={<VectorSearchIcon />}
-          text={
-            searchResult !== null
-              ? searchTrans('empty')
-              : searchTrans('startTip')
-          }
-        />
-      )}
-    </section>
-  );
-};
-
-export default VectorSearch;

+ 4 - 4
client/src/pages/search/Types.ts → client/src/types/SearchTypes.ts

@@ -1,7 +1,7 @@
-import { Option } from '../../components/customSelector/Types';
-import { searchKeywordsType } from '../../consts/Milvus';
-import { DataType, DataTypeEnum } from '../collections/Types';
-import { IndexView } from '../schema/Types';
+import { Option } from '../components/customSelector/Types';
+import { searchKeywordsType } from '../consts/Milvus';
+import { DataType, DataTypeEnum } from '../pages/collections/Types';
+import { IndexView } from '../pages/schema/Types';
 
 export interface SearchParamsProps {
   // if user created index, pass metric type choosed when creating

+ 1 - 1
client/src/utils/search.ts

@@ -10,7 +10,7 @@ import {
   FieldOption,
   SearchResult,
   SearchResultView,
-} from '../pages/search/Types';
+} from '../types/SearchTypes';
 
 /**
  * Do not change  vector search result default sort  by ourself.