Browse Source

Merge pull request #32 from Tumao727/feature/load-partition

add load partition
nameczz 4 years ago
parent
commit
9167be822a

+ 71 - 0
client/src/hooks/Dialog.tsx

@@ -0,0 +1,71 @@
+import { useContext } from 'react';
+import { useTranslation } from 'react-i18next';
+import { Typography } from '@material-ui/core';
+import { rootContext } from '../context/Root';
+import { CollectionView } from '../pages/collections/Types';
+import { PartitionView } from '../pages/partitions/Types';
+import { StatusEnum } from '../components/status/Types';
+
+// handle release and load dialog
+export interface DialogHookProps {
+  type: 'partition' | 'collection';
+}
+
+export const useDialogHook = (props: DialogHookProps) => {
+  const { type } = props;
+  const { setDialog } = useContext(rootContext);
+  const { t: dialogTrans } = useTranslation('dialog');
+  const { t: btnTrans } = useTranslation('btn');
+  const { t: partitionTrans } = useTranslation('partition');
+  const { t: collectionTrans } = useTranslation('collection');
+
+  const name =
+    type === 'collection'
+      ? collectionTrans('collection')
+      : partitionTrans('partition');
+
+  const actionsMap = {
+    release: {
+      title: dialogTrans('releaseTitle', { type: name }),
+      component: (
+        <Typography className="dialog-content">
+          {dialogTrans('releaseContent', { type: name })}
+        </Typography>
+      ),
+      confirmLabel: btnTrans('release'),
+    },
+    load: {
+      title: dialogTrans('loadTitle', { type: name }),
+      component: (
+        <Typography className="dialog-content">
+          {dialogTrans('loadContent', { type: name })}
+        </Typography>
+      ),
+      confirmLabel: btnTrans('load'),
+    },
+  };
+
+  const handleAction = (
+    data: PartitionView | CollectionView,
+    cb: (data: any) => Promise<any>
+  ) => {
+    const actionType: 'release' | 'load' =
+      data._status === StatusEnum.loaded ? 'release' : 'load';
+    const { title, component, confirmLabel } = actionsMap[actionType];
+
+    setDialog({
+      open: true,
+      type: 'notice',
+      params: {
+        title,
+        component,
+        confirmLabel,
+        confirm: () => cb(data),
+      },
+    });
+  };
+
+  return {
+    handleAction,
+  };
+};

+ 25 - 5
client/src/http/Partition.ts

@@ -1,13 +1,17 @@
 import { StatusEnum } from '../components/status/Types';
 import { StatusEnum } from '../components/status/Types';
-import { PartitionManageParam, PartitionView } from '../pages/partitions/Types';
+import {
+  PartitionManageParam,
+  PartitionParam,
+  PartitionView,
+} from '../pages/partitions/Types';
 import { formatNumber } from '../utils/Common';
 import { formatNumber } from '../utils/Common';
 import BaseModel from './BaseModel';
 import BaseModel from './BaseModel';
 
 
 export class PartitionHttp extends BaseModel implements PartitionView {
 export class PartitionHttp extends BaseModel implements PartitionView {
-  id!: string;
-  name!: string;
-  rowCount!: string;
-  status!: StatusEnum;
+  private id!: string;
+  private name!: string;
+  private rowCount!: string;
+  private status!: StatusEnum;
 
 
   constructor(props: {}) {
   constructor(props: {}) {
     super(props);
     super(props);
@@ -35,11 +39,27 @@ export class PartitionHttp extends BaseModel implements PartitionView {
     });
     });
   }
   }
 
 
+  static loadPartition(param: PartitionParam) {
+    const { collectionName, partitionNames } = param;
+    const path = `${this.URL_BASE}/load`;
+    return super.update({
+      path,
+      data: {
+        collection_name: collectionName,
+        partition_names: partitionNames,
+      },
+    });
+  }
+
   get _id() {
   get _id() {
     return this.id;
     return this.id;
   }
   }
 
 
   get _name() {
   get _name() {
+    return this.name;
+  }
+
+  get _formatName() {
     return this.name === '_default' ? 'Default partition' : this.name;
     return this.name === '_default' ? 'Default partition' : this.name;
   }
   }
 
 

+ 1 - 0
client/src/i18n/cn/button.ts

@@ -10,6 +10,7 @@ const btnTrans = {
   delete: '删除',
   delete: '删除',
   release: 'Release',
   release: 'Release',
   create: 'Create',
   create: 'Create',
+  load: 'Load',
 };
 };
 
 
 export default btnTrans;
 export default btnTrans;

+ 6 - 0
client/src/i18n/cn/dialog.ts

@@ -2,6 +2,12 @@ const dialogTrans = {
   deleteTipAction: 'Type',
   deleteTipAction: 'Type',
   deleteTipPurpose: 'to confirm.',
   deleteTipPurpose: 'to confirm.',
   deleteTitle: `Delete {{type}}`,
   deleteTitle: `Delete {{type}}`,
+
+  releaseTitle: `Release {{type}}`,
+  loadTitle: `Load {{type}}`,
+
+  loadContent: `You are trying to load a {{type}} with data. Only loaded {{type}} can be searched.`,
+  releaseContent: `You are trying to release a {{type}} with data. Please be aware that the data will no longer be available for search.`,
 };
 };
 
 
 export default dialogTrans;
 export default dialogTrans;

+ 1 - 0
client/src/i18n/cn/success.ts

@@ -1,6 +1,7 @@
 const successTrans = {
 const successTrans = {
   connect: 'Connet milvus success',
   connect: 'Connet milvus success',
   create: `{{name}} has been created`,
   create: `{{name}} has been created`,
+  load: `{{name}} has been loaded`,
   delete: `{{name}} has been deleted`,
   delete: `{{name}} has been deleted`,
 };
 };
 
 

+ 1 - 0
client/src/i18n/en/button.ts

@@ -10,6 +10,7 @@ const btnTrans = {
   import: 'Import',
   import: 'Import',
   delete: 'Delete',
   delete: 'Delete',
   release: 'Release',
   release: 'Release',
+  load: 'Load',
 };
 };
 
 
 export default btnTrans;
 export default btnTrans;

+ 5 - 0
client/src/i18n/en/dialog.ts

@@ -2,6 +2,11 @@ const dialogTrans = {
   deleteTipAction: 'Type',
   deleteTipAction: 'Type',
   deleteTipPurpose: 'to confirm.',
   deleteTipPurpose: 'to confirm.',
   deleteTitle: `Delete {{type}}`,
   deleteTitle: `Delete {{type}}`,
+  releaseTitle: `Release {{type}}`,
+  loadTitle: `Load {{type}}`,
+
+  loadContent: `You are trying to load a {{type}} with data. Only loaded {{type}} can be searched.`,
+  releaseContent: `You are trying to release a {{type}} with data. Please be aware that the data will no longer be available for search.`,
 };
 };
 
 
 export default dialogTrans;
 export default dialogTrans;

+ 1 - 0
client/src/i18n/en/success.ts

@@ -1,6 +1,7 @@
 const successTrans = {
 const successTrans = {
   connect: 'Connet milvus success',
   connect: 'Connet milvus success',
   create: `{{name}} has been created`,
   create: `{{name}} has been created`,
+  load: `{{name}} has been loaded`,
   delete: `{{name}} has been deleted`,
   delete: `{{name}} has been deleted`,
 };
 };
 
 

+ 6 - 44
client/src/pages/collections/Collections.tsx

@@ -12,13 +12,14 @@ import EmptyCard from '../../components/cards/EmptyCard';
 import Status from '../../components/status/Status';
 import Status from '../../components/status/Status';
 import { useTranslation } from 'react-i18next';
 import { useTranslation } from 'react-i18next';
 import { ChildrenStatusType, StatusEnum } from '../../components/status/Types';
 import { ChildrenStatusType, StatusEnum } from '../../components/status/Types';
-import { makeStyles, Theme, Typography } from '@material-ui/core';
+import { makeStyles, Theme } from '@material-ui/core';
 import StatusIcon from '../../components/status/StatusIcon';
 import StatusIcon from '../../components/status/StatusIcon';
 import CustomToolTip from '../../components/customToolTip/CustomToolTip';
 import CustomToolTip from '../../components/customToolTip/CustomToolTip';
 import { rootContext } from '../../context/Root';
 import { rootContext } from '../../context/Root';
 import CreateCollection from './Create';
 import CreateCollection from './Create';
 import DeleteTemplate from '../../components/customDialog/DeleteDialogTemplate';
 import DeleteTemplate from '../../components/customDialog/DeleteDialogTemplate';
 import { CollectionHttp } from '../../http/Collection';
 import { CollectionHttp } from '../../http/Collection';
+import { useDialogHook } from '../../hooks/Dialog';
 
 
 const useStyles = makeStyles((theme: Theme) => ({
 const useStyles = makeStyles((theme: Theme) => ({
   emptyWrapper: {
   emptyWrapper: {
@@ -41,7 +42,7 @@ const useStyles = makeStyles((theme: Theme) => ({
 
 
 const Collections = () => {
 const Collections = () => {
   useNavigationHook(ALL_ROUTER_TYPES.COLLECTIONS);
   useNavigationHook(ALL_ROUTER_TYPES.COLLECTIONS);
-
+  const { handleAction } = useDialogHook({ type: 'partition' });
   const [collections, setCollections] = useState<CollectionView[]>([]);
   const [collections, setCollections] = useState<CollectionView[]>([]);
   const {
   const {
     pageSize,
     pageSize,
@@ -129,47 +130,6 @@ const Collections = () => {
     setSelectedCollections([]);
     setSelectedCollections([]);
   };
   };
 
 
-  const handleAction = (data: CollectionView) => {
-    const actionType: 'release' | 'load' =
-      data._status === StatusEnum.loaded ? 'release' : 'load';
-
-    const actionsMap = {
-      release: {
-        title: t('releaseTitle'),
-        component: (
-          <Typography className={classes.dialogContent}>
-            {t('releaseContent')}
-          </Typography>
-        ),
-        confirmLabel: t('releaseConfirmLabel'),
-        confirm: () => handleRelease(data),
-      },
-      load: {
-        title: t('loadTitle'),
-        component: (
-          <Typography className={classes.dialogContent}>
-            {t('loadContent')}
-          </Typography>
-        ),
-        confirmLabel: t('loadConfirmLabel'),
-        confirm: () => handleLoad(data),
-      },
-    };
-
-    const { title, component, confirmLabel, confirm } = actionsMap[actionType];
-
-    setDialog({
-      open: true,
-      type: 'notice',
-      params: {
-        title,
-        component,
-        confirmLabel,
-        confirm,
-      },
-    });
-  };
-
   const toolbarConfigs: ToolBarConfig[] = [
   const toolbarConfigs: ToolBarConfig[] = [
     {
     {
       label: t('create'),
       label: t('create'),
@@ -264,7 +224,9 @@ const Collections = () => {
       actionBarConfigs: [
       actionBarConfigs: [
         {
         {
           onClick: (e: React.MouseEvent, row: CollectionView) => {
           onClick: (e: React.MouseEvent, row: CollectionView) => {
-            handleAction(row);
+            const cb =
+              row._status === StatusEnum.unloaded ? handleLoad : handleRelease;
+            handleAction(row, cb);
           },
           },
           icon: 'load',
           icon: 'load',
           label: 'load',
           label: 'load',

+ 8 - 0
client/src/pages/partitions/Types.ts

@@ -8,14 +8,22 @@ export interface PartitionView {
   _status: StatusEnum;
   _status: StatusEnum;
   _statusElement?: ReactElement;
   _statusElement?: ReactElement;
   _rowCount: string;
   _rowCount: string;
+  _formatName: string;
 }
 }
 
 
+// delete and create
 export interface PartitionManageParam {
 export interface PartitionManageParam {
   collectionName: string;
   collectionName: string;
   partitionName: string;
   partitionName: string;
   type: ManageRequestMethods;
   type: ManageRequestMethods;
 }
 }
 
 
+// load and release
+export interface PartitionParam {
+  collectionName: string;
+  partitionNames: string[];
+}
+
 export interface PartitionCreateProps {
 export interface PartitionCreateProps {
   handleCreate: (name: string) => void;
   handleCreate: (name: string) => void;
   handleClose: () => void;
   handleClose: () => void;

+ 44 - 2
client/src/pages/partitions/partitions.tsx

@@ -1,6 +1,6 @@
 import { makeStyles, Theme } from '@material-ui/core';
 import { makeStyles, Theme } from '@material-ui/core';
 import { FC, useContext, useEffect, useState } from 'react';
 import { FC, useContext, useEffect, useState } from 'react';
-import { PartitionManageParam, PartitionView } from './Types';
+import { PartitionManageParam, PartitionParam, PartitionView } from './Types';
 import MilvusGrid from '../../components/grid';
 import MilvusGrid from '../../components/grid';
 import { ColDefinitionsType, ToolBarConfig } from '../../components/grid/Types';
 import { ColDefinitionsType, ToolBarConfig } from '../../components/grid/Types';
 import { useTranslation } from 'react-i18next';
 import { useTranslation } from 'react-i18next';
@@ -12,6 +12,8 @@ import CreatePartition from './Create';
 import { PartitionHttp } from '../../http/Partition';
 import { PartitionHttp } from '../../http/Partition';
 import Status from '../../components/status/Status';
 import Status from '../../components/status/Status';
 import { ManageRequestMethods } from '../../types/Common';
 import { ManageRequestMethods } from '../../types/Common';
+import { StatusEnum } from '../../components/status/Types';
+import { useDialogHook } from '../../hooks/Dialog';
 
 
 const useStyles = makeStyles((theme: Theme) => ({
 const useStyles = makeStyles((theme: Theme) => ({
   wrapper: {
   wrapper: {
@@ -30,7 +32,10 @@ const Partitions: FC<{
   const { t } = useTranslation('partition');
   const { t } = useTranslation('partition');
   const { t: successTrans } = useTranslation('success');
   const { t: successTrans } = useTranslation('success');
   const InfoIcon = icons.info;
   const InfoIcon = icons.info;
+  const LoadIcon = icons.load;
+  const ReleaseIcon = icons.release;
 
 
+  const { handleAction } = useDialogHook({ type: 'partition' });
   const [selectedPartitions, setSelectedPartitions] = useState<PartitionView[]>(
   const [selectedPartitions, setSelectedPartitions] = useState<PartitionView[]>(
     []
     []
   );
   );
@@ -64,6 +69,19 @@ const Partitions: FC<{
     }
     }
   };
   };
 
 
+  const handleRelease = async (data: PartitionView) => {};
+
+  const handleLoad = async (data: PartitionView) => {
+    const param: PartitionParam = {
+      collectionName,
+      partitionNames: [data._name!],
+    };
+    const res = await PartitionHttp.loadPartition(param);
+    openSnackBar(successTrans('load', { name: t('partition') }));
+    fetchPartitions(collectionName);
+    return res;
+  };
+
   const toolbarConfigs: ToolBarConfig[] = [
   const toolbarConfigs: ToolBarConfig[] = [
     {
     {
       label: t('create'),
       label: t('create'),
@@ -99,7 +117,7 @@ const Partitions: FC<{
       label: t('id'),
       label: t('id'),
     },
     },
     {
     {
-      id: '_name',
+      id: '_formatName',
       align: 'left',
       align: 'left',
       disablePadding: false,
       disablePadding: false,
       label: t('name'),
       label: t('name'),
@@ -123,6 +141,30 @@ const Partitions: FC<{
         </span>
         </span>
       ),
       ),
     },
     },
+    {
+      id: 'action',
+      align: 'center',
+      disablePadding: false,
+      label: '',
+      showActionCell: true,
+      isHoverAction: true,
+      actionBarConfigs: [
+        {
+          onClick: (e: React.MouseEvent, row: PartitionView) => {
+            const cb =
+              row._status === StatusEnum.unloaded ? handleLoad : handleRelease;
+            handleAction(row, cb);
+          },
+          icon: 'load',
+          label: 'load',
+          showIconMethod: 'renderFn',
+          getLabel: (row: PartitionView) =>
+            row._status === StatusEnum.loaded ? 'release' : 'load',
+          renderIconFn: (row: PartitionView) =>
+            row._status === StatusEnum.loaded ? <ReleaseIcon /> : <LoadIcon />,
+        },
+      ],
+    },
   ];
   ];
 
 
   const handleSelectChange = (value: PartitionView[]) => {
   const handleSelectChange = (value: PartitionView[]) => {

+ 11 - 0
client/src/styles/common.css

@@ -42,3 +42,14 @@ fieldset {
 .page-empty-card .MuiSvgIcon-root path {
 .page-empty-card .MuiSvgIcon-root path {
   stroke: #aeaebb;
   stroke: #aeaebb;
 }
 }
+
+/* used for release or load dialog content */
+.dialog-content {
+  line-height: 24px;
+  font-size: 16px;
+  text-transform: lowercase;
+}
+
+.dialog-content::first-letter {
+  text-transform: uppercase;
+}