Browse Source

Add refresh btn on collection page (#439)

* adjust refresh button

Signed-off-by: ryjiang <jiangruiyi@gmail.com>

* finish refreshbtn

Signed-off-by: ruiyi.jiang <ruiyi.jiang@zilliz.com>

---------

Signed-off-by: ryjiang <jiangruiyi@gmail.com>
Signed-off-by: ruiyi.jiang <ruiyi.jiang@zilliz.com>
ryjiang 1 year ago
parent
commit
0ffa0be949

+ 3 - 10
client/src/components/cards/EmptyCard.tsx

@@ -1,13 +1,6 @@
 import { FC } from 'react';
-import {
-  makeStyles,
-  Theme,
-  Typography,
-  Card,
-  CardContent,
-} from '@material-ui/core';
-import StatusIcon from '../status/StatusIcon';
-import { ChildrenStatusType } from '../status/Types';
+import { makeStyles, Theme, Typography, CardContent } from '@material-ui/core';
+import StatusIcon, { LoadingType } from '@/components/status/StatusIcon';
 import { EmptyCardProps } from './Types';
 
 const useStyles = makeStyles((theme: Theme) => ({
@@ -43,7 +36,7 @@ const EmptyCard: FC<EmptyCardProps> = ({
   return (
     <section className={`flex-center ${classes.wrapper} ${wrapperClass}`}>
       <CardContent>
-        {loading && <StatusIcon type={ChildrenStatusType.CREATING} size={40} />}
+        {loading && <StatusIcon type={LoadingType.CREATING} size={40} />}
         {icon}
         <Typography className={classes.text}>{text}</Typography>
         <Typography className={classes.subText}>{subText}</Typography>

+ 1 - 1
client/src/components/customToolTip/CustomToolTip.tsx

@@ -20,7 +20,7 @@ const CustomToolTip: FC<CustomToolTipType> = props => {
       placement={placement}
       arrow
     >
-      <span className="flex-center">{children}</span>
+      <span>{children}</span>
     </Tooltip>
   );
 };

+ 2 - 2
client/src/components/layout/Header.tsx

@@ -12,7 +12,6 @@ import { navContext, dataContext, authContext } from '@/context';
 import { MilvusService } from '@/http';
 import CustomSelector from '@/components/customSelector/CustomSelector';
 import icons from '../icons/Icons';
-import { HeaderType } from './Types';
 
 const useStyles = makeStyles((theme: Theme) =>
   createStyles({
@@ -69,7 +68,7 @@ const useStyles = makeStyles((theme: Theme) =>
   })
 );
 
-const Header: FC<HeaderType> = props => {
+const Header: FC = () => {
   const classes = useStyles();
   const { navInfo } = useContext(navContext);
   const { database, databases, setDatabase, loading } = useContext(dataContext);
@@ -130,6 +129,7 @@ const Header: FC<HeaderType> = props => {
           <Typography variant="h5" color="textPrimary">
             {navInfo.navTitle}
           </Typography>
+          {navInfo.extra}
         </div>
 
         <div className={classes.addressWrapper}>

+ 0 - 5
client/src/components/layout/Types.ts

@@ -1,5 +0,0 @@
-export type HeaderType = {
-  onlyLogo?: boolean;
-};
-
-export type GlobalCreateType = 'database' | 'query';

+ 7 - 6
client/src/components/status/Status.tsx

@@ -1,5 +1,5 @@
 import { FC, useMemo } from 'react';
-import { ChildrenStatusType, StatusType } from './Types';
+import StatusIcon, { LoadingType } from '@/components/status/StatusIcon';
 import { useTranslation } from 'react-i18next';
 import {
   makeStyles,
@@ -9,7 +9,11 @@ import {
   useTheme,
 } from '@material-ui/core';
 import { LOADING_STATE } from '@/consts';
-import StatusIcon from './StatusIcon';
+
+export type StatusType = {
+  status: LOADING_STATE;
+  percentage?: number;
+};
 
 const useStyles = makeStyles((theme: Theme) =>
   createStyles({
@@ -91,10 +95,7 @@ const Status: FC<StatusType> = props => {
         <div className={classes.circle}></div>
       )}
       {status === LOADING_STATE.LOADING && (
-        <StatusIcon
-          type={ChildrenStatusType.CREATING}
-          className={classes.loading}
-        />
+        <StatusIcon type={LoadingType.CREATING} className={classes.loading} />
       )}
 
       <Typography variant="body2" className={classes.label}>

+ 13 - 2
client/src/components/status/StatusIcon.tsx

@@ -1,6 +1,17 @@
 import { CircularProgress, makeStyles, Theme } from '@material-ui/core';
 import { FC, ReactElement } from 'react';
-import { ChildrenStatusType, StatusIconType } from './Types';
+
+export enum LoadingType {
+  CREATING = 'creating',
+  FINISH = 'finish',
+  ERROR = 'error',
+}
+
+export type StatusIconType = {
+  type: LoadingType;
+  className?: string;
+  size?: number;
+};
 
 const useStyles = makeStyles((theme: Theme) => ({
   wrapper: {
@@ -18,7 +29,7 @@ const StatusIcon: FC<StatusIconType> = props => {
   const classes = useStyles();
   const { type, className = '', size = 16 } = props;
 
-  const getElement = (type: ChildrenStatusType): ReactElement => {
+  const getElement = (type: LoadingType): ReactElement => {
     switch (type) {
       case 'creating':
         return (

+ 0 - 16
client/src/components/status/Types.ts

@@ -1,11 +1,6 @@
 import { LOADING_STATE } from '@/consts';
 import { SchemaObject } from '@server/types';
 
-export type StatusType = {
-  status: LOADING_STATE;
-  percentage?: number;
-};
-
 export type StatusActionType = {
   status: LOADING_STATE;
   percentage?: string | number;
@@ -15,14 +10,3 @@ export type StatusActionType = {
 };
 
 // @todo need rename
-export enum ChildrenStatusType {
-  CREATING = 'creating',
-  FINISH = 'finish',
-  ERROR = 'error',
-}
-
-export type StatusIconType = {
-  type: ChildrenStatusType;
-  className?: string;
-  size?: number;
-};

+ 14 - 20
client/src/hooks/Navigation.ts → client/src/hooks/Navigation.tsx

@@ -6,14 +6,21 @@ import { ALL_ROUTER_TYPES, NavInfo } from '@/router/Types';
 export const useNavigationHook = (
   type: ALL_ROUTER_TYPES,
   extraParam?: {
+    databaseName?: string;
     collectionName?: string;
     title?: string;
+    extra?: React.ReactNode;
   }
 ) => {
   const { t: navTrans } = useTranslation('nav');
   const { setNavInfo } = useContext(navContext);
-  const { collectionName = '', title = 'PLUGIN TITLE' } = extraParam || {
+  const {
+    databaseName = '',
+    collectionName = '',
+    extra,
+  } = extraParam || {
     collectionName: '',
+    databaseName: '',
   };
 
   useEffect(() => {
@@ -27,30 +34,17 @@ export const useNavigationHook = (
         setNavInfo(navInfo);
         break;
       }
-      case ALL_ROUTER_TYPES.DB_ADMIN: {
-        const navInfo: NavInfo = {
-          navTitle: navTrans('dbAdmin'),
-          backPath: '',
-          showDatabaseSelector: false,
-        };
-        setNavInfo(navInfo);
-        break;
-      }
       case ALL_ROUTER_TYPES.DATABASES: {
-        const navInfo: NavInfo = {
-          navTitle: navTrans('database'),
-          backPath: '',
-          showDatabaseSelector: true,
-        };
-        setNavInfo(navInfo);
-        break;
-      }
-      case ALL_ROUTER_TYPES.COLLECTION_DETAIL: {
         const navInfo: NavInfo = {
           navTitle: collectionName,
           backPath: '',
           showDatabaseSelector: true,
         };
+
+        if (collectionName) {
+          navInfo.extra = extra;
+        }
+
         setNavInfo(navInfo);
         break;
       }
@@ -84,5 +78,5 @@ export const useNavigationHook = (
       default:
         break;
     }
-  }, [type, navTrans, setNavInfo, collectionName, title]);
+  }, [type, navTrans, setNavInfo, databaseName, collectionName]);
 };

+ 17 - 6
client/src/pages/databases/Databases.tsx

@@ -13,8 +13,8 @@ import Data from './collections/data/Data';
 import Segments from './collections/segments/Segments';
 import { dataContext, authContext } from '@/context';
 import Collections from './collections/Collections';
-import StatusIcon from '@/components/status/StatusIcon';
-import { ChildrenStatusType } from '@/components/status/Types';
+import StatusIcon, { LoadingType } from '@/components/status/StatusIcon';
+import RefreshButton from './RefreshButton';
 
 const useStyles = makeStyles((theme: Theme) => ({
   wrapper: {
@@ -42,7 +42,8 @@ const useStyles = makeStyles((theme: Theme) => ({
 const Databases = () => {
   // context
   const { isManaged } = useContext(authContext);
-  const { database, collections, loading } = useContext(dataContext);
+  const { database, collections, loading, fetchCollection } =
+    useContext(dataContext);
 
   // get current collection from url
   const params = useParams();
@@ -52,11 +53,21 @@ const Databases = () => {
     collectionPage = '',
   } = params;
 
-  // update navigation
-  useNavigationHook(ALL_ROUTER_TYPES.COLLECTION_DETAIL, { collectionName });
+  // refresh collection
+  const refreshCollection = async () => {
+    await fetchCollection(collectionName);
+  };
+
   // get style
   const classes = useStyles();
 
+  // update navigation
+  useNavigationHook(ALL_ROUTER_TYPES.DATABASES, {
+    collectionName,
+    databaseName,
+    extra: <RefreshButton onClick={refreshCollection} />,
+  });
+
   // i18n
   const { t: collectionTrans } = useTranslation('collection');
 
@@ -104,7 +115,7 @@ const Databases = () => {
     <section className={`page-wrapper ${classes.wrapper}`}>
       <section className={classes.tree}>
         {loading ? (
-          <StatusIcon type={ChildrenStatusType.CREATING} />
+          <StatusIcon type={LoadingType.CREATING} />
         ) : (
           <DatabaseTree
             key="collections"

+ 50 - 0
client/src/pages/databases/RefreshButton.tsx

@@ -0,0 +1,50 @@
+import { useState, MouseEvent } from 'react';
+import CustomIconButton from '@/components/customButton/CustomIconButton';
+import StatusIcon, { LoadingType } from '@/components/status/StatusIcon';
+
+import { IconButtonProps, makeStyles, Theme } from '@material-ui/core';
+import icons from '@/components/icons/Icons';
+
+const useStyles = makeStyles((theme: Theme) => ({
+  rotatingRefreshButton: {
+    ' & svg': {
+      color: theme.palette.primary.main,
+    },
+    marginLeft: 4,
+  },
+}));
+
+const RefreshButton = (props: IconButtonProps & { tooltip?: string }) => {
+  // props
+  const { onClick, ...otherProps } = props;
+  // UI states
+  const [isLoading, setIsLoading] = useState(false);
+
+  // icon
+  const RefreshIcon = icons.refresh;
+  const classes = useStyles();
+
+  const onBtnClicked = async (event: MouseEvent<HTMLButtonElement>) => {
+    setIsLoading(true);
+    onClick && (await onClick(event));
+    setIsLoading(false);
+  };
+
+  if (isLoading) {
+    return <StatusIcon type={LoadingType.CREATING} size={20} />;
+  }
+
+  return (
+    <CustomIconButton
+      className={classes.rotatingRefreshButton}
+      {...otherProps}
+      onClick={onBtnClicked}
+      style={{}}
+      disabled={isLoading}
+    >
+      <RefreshIcon />
+    </CustomIconButton>
+  );
+};
+
+export default RefreshButton;

+ 1 - 3
client/src/pages/databases/collections/Collections.tsx

@@ -5,8 +5,7 @@ import { useTranslation } from 'react-i18next';
 import Highlighter from 'react-highlight-words';
 import { rootContext, authContext, dataContext } from '@/context';
 import { CollectionService } from '@/http';
-import { useNavigationHook, usePaginationHook } from '@/hooks';
-import { ALL_ROUTER_TYPES } from '@/router/Types';
+import { usePaginationHook } from '@/hooks';
 import AttuGrid from '@/components/grid/Grid';
 import CustomToolBar from '@/components/grid/ToolBar';
 import { ColDefinitionsType, ToolBarConfig } from '@/components/grid/Types';
@@ -69,7 +68,6 @@ const useStyles = makeStyles((theme: Theme) => ({
 }));
 
 const Collections = () => {
-  useNavigationHook(ALL_ROUTER_TYPES.COLLECTIONS);
   const { isManaged } = useContext(authContext);
   const { collections, database, loading, fetchCollections, fetchCollection } =
     useContext(dataContext);

+ 3 - 6
client/src/pages/databases/collections/StatusAction.tsx

@@ -1,8 +1,5 @@
 import { FC, useMemo, MouseEvent } from 'react';
-import {
-  ChildrenStatusType,
-  StatusActionType,
-} from '@/components/status/Types';
+import { StatusActionType } from '@/components/status/Types';
 import { useTranslation } from 'react-i18next';
 import {
   makeStyles,
@@ -13,7 +10,7 @@ import {
   Chip,
 } from '@material-ui/core';
 import { LOADING_STATE } from '@/consts';
-import StatusIcon from '@/components/status/StatusIcon';
+import StatusIcon, { LoadingType } from '@/components/status/StatusIcon';
 import icons from '@/components/icons/Icons';
 import CustomToolTip from '@/components/customToolTip/CustomToolTip';
 
@@ -111,7 +108,7 @@ const StatusAction: FC<StatusActionType> = props => {
           tooltip: collectionTrans('collectionIsLoading'),
           icon: (
             <StatusIcon
-              type={ChildrenStatusType.CREATING}
+              type={LoadingType.CREATING}
               className={classes.loading}
             />
           ),

+ 2 - 3
client/src/pages/databases/collections/overview/IndexTypeElement.tsx

@@ -6,8 +6,7 @@ import { IndexCreateParam, IndexExtraParam, IndexManageParam } from './Types';
 import { rootContext, dataContext } from '@/context';
 import icons from '@/components/icons/Icons';
 import DeleteTemplate from '@/components/customDialog/DeleteDialogTemplate';
-import StatusIcon from '@/components/status/StatusIcon';
-import { ChildrenStatusType } from '@/components/status/Types';
+import StatusIcon, { LoadingType } from '@/components/status/StatusIcon';
 import { IndexState } from '@/types/Milvus';
 import { NONE_INDEXABLE_DATA_TYPES, DataTypeStringEnum } from '@/consts';
 import CreateIndex from './Create';
@@ -169,7 +168,7 @@ const IndexTypeElement: FC<{
     switch (field.index.indexType) {
       default: {
         if (field.index.state === IndexState.InProgress) {
-          return <StatusIcon type={ChildrenStatusType.CREATING} />;
+          return <StatusIcon type={LoadingType.CREATING} />;
         }
 
         const chipComp = () => (

+ 11 - 22
client/src/pages/databases/collections/overview/Overview.tsx

@@ -19,7 +19,7 @@ import { LOADING_STATE } from '@/consts';
 import LoadCollectionDialog from '@/pages/dialogs/LoadCollectionDialog';
 import ReleaseCollectionDialog from '@/pages/dialogs/ReleaseCollectionDialog';
 import StatusAction from '@/pages/databases/collections/StatusAction';
-import CustomButton from '@/components/customButton/CustomButton';
+import CustomToolTip from '@/components/customToolTip/CustomToolTip';
 
 const useStyles = makeStyles((theme: Theme) => ({
   wrapper: {
@@ -50,6 +50,11 @@ const useStyles = makeStyles((theme: Theme) => ({
     fontSize: '20px',
     marginLeft: theme.spacing(0.5),
   },
+  questionIcon: {
+    position: 'relative',
+    top: '2px',
+    right: '-2px',
+  },
   primaryKeyChip: {
     fontSize: '8px',
     position: 'relative',
@@ -77,17 +82,6 @@ const useStyles = makeStyles((theme: Theme) => ({
       marginLeft: theme.spacing(0.5),
     },
   },
-  refreshBtn: {
-    color: theme.palette.attuGrey.main,
-    cursor: 'pointer',
-    minWidth: 0,
-    minHeight: 0,
-    padding: theme.spacing(0.5),
-    alignSelf: 'center',
-    '& svg': {
-      width: 15,
-    },
-  },
 
   paramWrapper: {
     // set min width to prevent other table cell stretching
@@ -140,12 +134,7 @@ const Overview = () => {
 
   const KeyIcon = icons.key;
   const EnabledIcon = icons.check;
-  const RefreshIcon = icons.refresh;
-
-  // refresh collection
-  const refreshCollection = async () => {
-    await fetchCollection(collectionName);
-  };
+  const QuestionIcon = icons.question;
 
   const colDefinitions: ColDefinitionsType[] = [
     {
@@ -296,11 +285,11 @@ const Overview = () => {
           <div className={classes.block}>
             <Typography variant="h5">
               {collectionTrans('rowCount')}
-              <CustomButton className={classes.refreshBtn} onClick={refreshCollection}>
-                <RefreshIcon />
-              </CustomButton>
+              <CustomToolTip title={collectionTrans('entityCountInfo')}>
+                <QuestionIcon classes={{ root: classes.questionIcon }} />
+              </CustomToolTip>
             </Typography>
-            <Typography variant="h6">{collection?.rowCount || '--'}</Typography>
+            <Typography variant="h6">{collection?.rowCount || '0'}</Typography>
           </div>
 
           <div className={classes.block}>

+ 2 - 3
client/src/pages/home/Overview.tsx

@@ -8,8 +8,7 @@ import { useNavigationHook } from '@/hooks';
 import { ALL_ROUTER_TYPES } from '@/router/Types';
 import DatabaseCard from './DatabaseCard';
 import SysCard from './SysCard';
-import StatusIcon from '@/components/status/StatusIcon';
-import { ChildrenStatusType } from '@/components/status/Types';
+import StatusIcon, { LoadingType } from '@/components/status/StatusIcon';
 
 const useStyles = makeStyles((theme: Theme) => ({
   overviewContainer: {
@@ -84,7 +83,7 @@ const Overview = () => {
       <section className={classes.section}>
         <Typography variant="h4">{databaseTrans('databases')}</Typography>
         {loadingDatabases ? (
-          <StatusIcon type={ChildrenStatusType.CREATING} />
+          <StatusIcon type={LoadingType.CREATING} />
         ) : (
           <div className={classes.cardWrapper}>
             {databases.map(db => {

+ 1 - 0
client/src/router/Types.ts

@@ -20,4 +20,5 @@ export type NavInfo = {
   navTitle: string;
   backPath: string;
   showDatabaseSelector: boolean;
+  extra?: React.ReactNode;
 };

+ 0 - 1
client/src/utils/Validation.ts

@@ -1,4 +1,3 @@
-import { ChildrenStatusType } from '@/components/status/Types';
 import { MetricType, METRIC_TYPES_VALUES } from '@/consts';
 import { CollectionObject } from '@server/types';