Browse Source

Merge pull request #117 from Tumao727/feature/insert-data

add insert data modal stepper component
nameczz 4 years ago
parent
commit
add5ae65a3

+ 5 - 0
client/src/assets/icons/upload.svg

@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M14 6.66669C13.6318 6.66669 13.3333 6.36821 13.3333 6.00002L13.3333 3.33335C13.3333 3.15654 13.2631 2.98697 13.1381 2.86195C13.0131 2.73692 12.8435 2.66669 12.6667 2.66669L3.33334 2.66669C3.15653 2.66669 2.98696 2.73693 2.86193 2.86195C2.73691 2.98697 2.66667 3.15654 2.66667 3.33335L2.66667 6.00002C2.66667 6.36821 2.36819 6.66669 2 6.66669C1.63181 6.66669 1.33334 6.36821 1.33334 6.00002L1.33334 3.33335C1.33334 2.80292 1.54405 2.29421 1.91912 1.91914C2.2942 1.54407 2.8029 1.33335 3.33334 1.33335L12.6667 1.33335C13.1971 1.33335 13.7058 1.54407 14.0809 1.91914C14.456 2.29421 14.6667 2.80292 14.6667 3.33335L14.6667 6.00002C14.6667 6.36821 14.3682 6.66669 14 6.66669Z" fill="white"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M11.8047 9.80474C11.5444 10.0651 11.1223 10.0651 10.8619 9.80474L8 6.94281L5.13807 9.80474C4.87772 10.0651 4.45561 10.0651 4.19526 9.80474C3.93491 9.54439 3.93491 9.12228 4.19526 8.86193L7.5286 5.5286C7.78894 5.26825 8.21105 5.26825 8.4714 5.5286L11.8047 8.86193C12.0651 9.12228 12.0651 9.54439 11.8047 9.80474Z" fill="white"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M8.00001 14.6667C7.63182 14.6667 7.33334 14.3682 7.33334 14L7.33334 6.00002C7.33334 5.63183 7.63181 5.33335 8 5.33335C8.36819 5.33335 8.66667 5.63183 8.66667 6.00002L8.66667 14C8.66667 14.3682 8.36819 14.6667 8.00001 14.6667Z" fill="white"/>
+</svg>

+ 2 - 2
client/src/components/__test__/customDialog/DialogTemplate.spec.tsx

@@ -14,7 +14,7 @@ describe('test dialog template component', () => {
         <I18nextProvider i18n={i18n}>
         <I18nextProvider i18n={i18n}>
           <DialogTemplate
           <DialogTemplate
             title="dialog template"
             title="dialog template"
-            handleCancel={mockCancelFn}
+            handleClose={mockCancelFn}
             handleConfirm={mockConfirmFn}
             handleConfirm={mockConfirmFn}
           >
           >
             dialog content
             dialog content
@@ -38,7 +38,7 @@ describe('test dialog template component', () => {
         <I18nextProvider i18n={i18n}>
         <I18nextProvider i18n={i18n}>
           <DialogTemplate
           <DialogTemplate
             title="dialog template"
             title="dialog template"
-            handleCancel={mockCancelFn}
+            handleClose={mockCancelFn}
             handleConfirm={mockConfirmFn}
             handleConfirm={mockConfirmFn}
             confirmDisabled={true}
             confirmDisabled={true}
           >
           >

+ 23 - 15
client/src/components/customDialog/DialogTemplate.tsx

@@ -19,35 +19,43 @@ const useStyles = makeStyles((theme: Theme) => ({
 const DialogTemplate: FC<DialogContainerProps> = ({
 const DialogTemplate: FC<DialogContainerProps> = ({
   title,
   title,
   cancelLabel,
   cancelLabel,
+  handleClose,
   handleCancel,
   handleCancel,
   confirmLabel,
   confirmLabel,
   handleConfirm,
   handleConfirm,
   confirmDisabled,
   confirmDisabled,
   children,
   children,
+  showActions = true,
+  showCancel = true,
 }) => {
 }) => {
   const { t } = useTranslation('btn');
   const { t } = useTranslation('btn');
   const cancel = cancelLabel || t('cancel');
   const cancel = cancelLabel || t('cancel');
   const confirm = confirmLabel || t('confirm');
   const confirm = confirmLabel || t('confirm');
   const classes = useStyles();
   const classes = useStyles();
+  const onCancel = handleCancel || handleClose;
 
 
   return (
   return (
     <>
     <>
-      <CustomDialogTitle onClose={handleCancel}>{title}</CustomDialogTitle>
+      <CustomDialogTitle onClose={handleClose}>{title}</CustomDialogTitle>
       <DialogContent>{children}</DialogContent>
       <DialogContent>{children}</DialogContent>
-      <DialogActions className={classes.actions}>
-        <CustomButton onClick={handleCancel} color="default" name="cancel">
-          {cancel}
-        </CustomButton>
-        <CustomButton
-          variant="contained"
-          onClick={handleConfirm}
-          color="primary"
-          disabled={confirmDisabled}
-          name="confirm"
-        >
-          {confirm}
-        </CustomButton>
-      </DialogActions>
+      {showActions && (
+        <DialogActions className={classes.actions}>
+          {showCancel && (
+            <CustomButton onClick={onCancel} color="default" name="cancel">
+              {cancel}
+            </CustomButton>
+          )}
+          <CustomButton
+            variant="contained"
+            onClick={handleConfirm}
+            color="primary"
+            disabled={confirmDisabled}
+            name="confirm"
+          >
+            {confirm}
+          </CustomButton>
+        </DialogActions>
+      )}
     </>
     </>
   );
   );
 };
 };

+ 7 - 3
client/src/components/customDialog/Types.ts

@@ -1,3 +1,4 @@
+import { ReactElement } from 'react';
 import { DialogType } from '../../context/Types';
 import { DialogType } from '../../context/Types';
 export type CustomDialogType = DialogType & {
 export type CustomDialogType = DialogType & {
   onClose: () => void;
   onClose: () => void;
@@ -21,9 +22,12 @@ export type DeleteDialogContentType = {
 
 
 export type DialogContainerProps = {
 export type DialogContainerProps = {
   title: string;
   title: string;
-  cancelLabel?: string;
-  confirmLabel?: string;
-  handleCancel: () => void;
+  cancelLabel?: string | ReactElement;
+  confirmLabel?: string | ReactElement;
+  handleClose: () => void;
+  handleCancel?: () => void;
   handleConfirm: (param: any) => void;
   handleConfirm: (param: any) => void;
   confirmDisabled?: boolean;
   confirmDisabled?: boolean;
+  showActions?: boolean;
+  showCancel?: boolean;
 };
 };

+ 4 - 0
client/src/components/icons/Icons.tsx

@@ -27,6 +27,7 @@ import { ReactComponent as InfoIcon } from '../../assets/icons/info.svg';
 import { ReactComponent as ReleaseIcon } from '../../assets/icons/release.svg';
 import { ReactComponent as ReleaseIcon } from '../../assets/icons/release.svg';
 import { ReactComponent as LoadIcon } from '../../assets/icons/load.svg';
 import { ReactComponent as LoadIcon } from '../../assets/icons/load.svg';
 import { ReactComponent as KeyIcon } from '../../assets/icons/key.svg';
 import { ReactComponent as KeyIcon } from '../../assets/icons/key.svg';
+import { ReactComponent as UploadIcon } from '../../assets/icons/upload.svg';
 
 
 const icons: { [x in IconsType]: (props?: any) => React.ReactElement } = {
 const icons: { [x in IconsType]: (props?: any) => React.ReactElement } = {
   search: (props = {}) => <SearchIcon {...props} />,
   search: (props = {}) => <SearchIcon {...props} />,
@@ -72,6 +73,9 @@ const icons: { [x in IconsType]: (props?: any) => React.ReactElement } = {
   key: (props = {}) => (
   key: (props = {}) => (
     <SvgIcon viewBox="0 0 16 16" component={KeyIcon} {...props} />
     <SvgIcon viewBox="0 0 16 16" component={KeyIcon} {...props} />
   ),
   ),
+  upload: (props = {}) => (
+    <SvgIcon viewBox="0 0 16 16" component={UploadIcon} {...props} />
+  ),
 };
 };
 
 
 export default icons;
 export default icons;

+ 2 - 1
client/src/components/icons/Types.ts

@@ -24,4 +24,5 @@ export type IconsType =
   | 'release'
   | 'release'
   | 'load'
   | 'load'
   | 'remove'
   | 'remove'
-  | 'key';
+  | 'key'
+  | 'upload';

+ 177 - 0
client/src/components/insert/Container.tsx

@@ -0,0 +1,177 @@
+import { makeStyles, Theme } from '@material-ui/core';
+import { FC, useContext, useMemo, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import DialogTemplate from '../customDialog/DialogTemplate';
+import icons from '../icons/Icons';
+import { rootContext } from '../../context/Root';
+import InsertImport from './Import';
+import InsertPreview from './Preview';
+import InsertStatus from './Status';
+import {
+  InsertContentProps,
+  InsertStatusEnum,
+  InsertStepperEnum,
+} from './Types';
+import { Option } from '../customSelector/Types';
+
+const getStyles = makeStyles((theme: Theme) => ({
+  icon: {
+    fontSize: '16px',
+  },
+}));
+
+/**
+ * this component contains processes during insert
+ * all datas and methods passed in as props, no interactions with server done in it
+ */
+
+const InsertContainer: FC<InsertContentProps> = ({
+  collections,
+  selectedCollection,
+  partitions,
+  selectedPartition,
+  schema,
+  handleInsert,
+}) => {
+  const classes = getStyles();
+
+  // props children component needed:
+  const collectionOptions: Option[] = collections.map(c => ({
+    label: c._name,
+    value: c._name,
+  }));
+  const partitionOptions: Option[] = partitions.map(p => ({
+    label: p._name,
+    value: p._name,
+  }));
+  const schemaOptions: Option[] = schema.map(s => ({
+    label: s._fieldName,
+    value: s._fieldId,
+  }));
+
+  const { t: insertTrans } = useTranslation('insert');
+  const { t: btnTrans } = useTranslation('btn');
+  const { handleCloseDialog } = useContext(rootContext);
+  const [activeStep, setActiveStep] = useState<InsertStepperEnum>(
+    InsertStepperEnum.import
+  );
+  const [insertStatus, setInsertStauts] = useState<InsertStatusEnum>(
+    InsertStatusEnum.init
+  );
+  // const [nextDisabled, setNextDisabled] = useState<boolean>(false);
+
+  const BackIcon = icons.back;
+
+  const { confirm, cancel } = useMemo(() => {
+    /**
+     * activeStep type is InsertStepperEnum
+     * so index 0 represents import,
+     * index 1 represents preview,
+     * index 2 represents status
+     */
+    const labelList = [
+      {
+        confirm: btnTrans('next'),
+        cancel: btnTrans('cancel'),
+      },
+      {
+        confirm: btnTrans('insert'),
+        cancel: (
+          <>
+            <BackIcon classes={{ root: classes.icon }} />
+            {btnTrans('previous')}
+          </>
+        ),
+      },
+      {
+        confirm: btnTrans('done'),
+        cancel: '',
+      },
+    ];
+    return labelList[activeStep];
+  }, [activeStep, btnTrans, BackIcon, classes.icon]);
+
+  const { showActions, showCancel } = useMemo(() => {
+    return {
+      showActions: insertStatus !== InsertStatusEnum.loading,
+      showCancel: insertStatus === InsertStatusEnum.init,
+    };
+  }, [insertStatus]);
+
+  const handleInsertData = () => {
+    // mock status change
+    setInsertStauts(InsertStatusEnum.loading);
+    handleInsert();
+    setTimeout(() => {
+      setInsertStauts(InsertStatusEnum.success);
+    }, 500);
+  };
+
+  const handleNext = () => {
+    switch (activeStep) {
+      case InsertStepperEnum.import:
+        setActiveStep(activeStep => activeStep + 1);
+        break;
+      case InsertStepperEnum.preview:
+        setActiveStep(activeStep => activeStep + 1);
+        handleInsertData();
+        break;
+      // default represent InsertStepperEnum.status
+      default:
+        handleCloseDialog();
+        break;
+    }
+  };
+
+  const handleBack = () => {
+    switch (activeStep) {
+      case InsertStepperEnum.import:
+        handleCloseDialog();
+        break;
+      case InsertStepperEnum.preview:
+        setActiveStep(activeStep => activeStep - 1);
+        break;
+      // default represent InsertStepperEnum.status
+      // status don't have cancel button
+      default:
+        break;
+    }
+  };
+
+  const generateContent = (activeStep: InsertStepperEnum) => {
+    switch (activeStep) {
+      case InsertStepperEnum.import:
+        return (
+          <InsertImport
+            collectionOptions={collectionOptions}
+            selectedCollection={selectedCollection}
+            partitionOptions={partitionOptions}
+            selectedPartition={selectedPartition}
+          />
+        );
+      case InsertStepperEnum.preview:
+        return <InsertPreview schemaOptions={schemaOptions} />;
+      // default represents InsertStepperEnum.status
+      default:
+        return <InsertStatus status={insertStatus} />;
+    }
+  };
+
+  return (
+    <DialogTemplate
+      title={insertTrans('import')}
+      handleClose={handleCloseDialog}
+      confirmLabel={confirm}
+      cancelLabel={cancel}
+      handleCancel={handleBack}
+      handleConfirm={handleNext}
+      confirmDisabled={false}
+      showActions={showActions}
+      showCancel={showCancel}
+    >
+      {generateContent(activeStep)}
+    </DialogTemplate>
+  );
+};
+
+export default InsertContainer;

+ 79 - 0
client/src/components/insert/Import.tsx

@@ -0,0 +1,79 @@
+import { useTranslation } from 'react-i18next';
+import Typography from '@material-ui/core/Typography';
+import { makeStyles, Theme, Divider } from '@material-ui/core';
+import CustomSelector from '../customSelector/CustomSelector';
+import { FC } from 'react';
+import { InsertImportProps } from './Types';
+
+const getStyles = makeStyles((theme: Theme) => ({
+  tip: {
+    color: theme.palette.milvusGrey.dark,
+  },
+  selectorWrapper: {
+    display: 'flex',
+    justifyContent: 'space-between',
+    alignItems: 'center',
+
+    '& .selector': {
+      flexBasis: '40%',
+      minWidth: '256px',
+    },
+
+    '& .divider': {
+      width: '20px',
+      margin: theme.spacing(0, 4),
+      color: theme.palette.milvusGrey.dark,
+    },
+  },
+  uploadWrapper: {
+    backgroundColor: '#f9f9f9',
+    padding: theme.spacing(1),
+  },
+}));
+
+const InsertImport: FC<InsertImportProps> = ({
+  collectionOptions,
+  partitionOptions,
+  selectedCollection,
+  selectedPartition,
+}) => {
+  const { t: insertTrans } = useTranslation('insert');
+  const { t: collectionTrans } = useTranslation('collection');
+  const { t: partitionTrans } = useTranslation('partition');
+  const classes = getStyles();
+
+  const handleCollectionChange = () => {};
+  const handlePartitionChange = () => {};
+
+  return (
+    <section>
+      <Typography className={classes.tip}>
+        {insertTrans('targetTip')}
+      </Typography>
+
+      <form className={classes.selectorWrapper}>
+        <CustomSelector
+          options={collectionOptions}
+          classes={{ root: 'selector' }}
+          value={selectedCollection}
+          variant="filled"
+          label={collectionTrans('collection')}
+          onChange={handleCollectionChange}
+        />
+        <Divider classes={{ root: 'divider' }} />
+        <CustomSelector
+          options={partitionOptions}
+          classes={{ root: 'selector' }}
+          value={selectedPartition}
+          variant="filled"
+          label={partitionTrans('partition')}
+          onChange={handlePartitionChange}
+        />
+      </form>
+
+      <div className={classes.uploadWrapper}>uploader</div>
+    </section>
+  );
+};
+
+export default InsertImport;

+ 8 - 0
client/src/components/insert/Preview.tsx

@@ -0,0 +1,8 @@
+import { FC } from 'react';
+import { InsertPreviewProps } from './Types';
+
+const InsertPreview: FC<InsertPreviewProps> = ({ schemaOptions }) => {
+  return <div>preview</div>;
+};
+
+export default InsertPreview;

+ 8 - 0
client/src/components/insert/Status.tsx

@@ -0,0 +1,8 @@
+import { FC } from 'react';
+import { InsertStatusProps } from './Types';
+
+const InsertStatus: FC<InsertStatusProps> = ({ status }) => {
+  return <div>status</div>;
+};
+
+export default InsertStatus;

+ 42 - 0
client/src/components/insert/Types.ts

@@ -0,0 +1,42 @@
+import { CollectionData } from '../../pages/collections/Types';
+import { PartitionData } from '../../pages/partitions/Types';
+import { FieldData } from '../../pages/schema/Types';
+import { Option } from '../customSelector/Types';
+
+export interface InsertContentProps {
+  collections: CollectionData[];
+  selectedCollection: string;
+  partitions: PartitionData[];
+  selectedPartition: string;
+  schema: FieldData[];
+  handleInsert: () => void;
+}
+
+export enum InsertStepperEnum {
+  import,
+  preview,
+  status,
+}
+
+export enum InsertStatusEnum {
+  // init means not begin yet
+  init = 'init',
+  loading = 'loading',
+  success = 'success',
+  error = 'error',
+}
+
+export interface InsertImportProps {
+  collectionOptions: Option[];
+  partitionOptions: Option[];
+  selectedCollection: string;
+  selectedPartition: string;
+}
+
+export interface InsertPreviewProps {
+  schemaOptions: Option[];
+}
+
+export interface InsertStatusProps {
+  status: InsertStatusEnum;
+}

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

@@ -0,0 +1,5 @@
+export interface UploaderProps {
+  label: string;
+  accept: string;
+  btnClass?: string;
+}

+ 30 - 0
client/src/components/uploader/Uploader.tsx

@@ -0,0 +1,30 @@
+import { makeStyles, Theme } from '@material-ui/core';
+import { FC, useRef } from 'react';
+import CustomButton from '../customButton/CustomButton';
+import { UploaderProps } from './Types';
+
+const getStyles = makeStyles((theme: Theme) => ({
+  btn: {},
+}));
+
+const Uploader: FC<UploaderProps> = ({ label, accept, btnClass = '' }) => {
+  const inputRef = useRef(null);
+  const classes = getStyles();
+
+  return (
+    <form>
+      <CustomButton variant="text" className={`${classes.btn} ${btnClass}`}>
+        {label}
+      </CustomButton>
+      <input
+        ref={inputRef}
+        id="fileId"
+        type="file"
+        accept={accept}
+        style={{ display: 'none' }}
+      />
+    </form>
+  );
+};
+
+export default Uploader;

+ 26 - 3
client/src/hooks/Dialog.tsx

@@ -1,4 +1,4 @@
-import { useContext } from 'react';
+import { ReactElement, useContext } from 'react';
 import { useTranslation } from 'react-i18next';
 import { useTranslation } from 'react-i18next';
 import { Typography } from '@material-ui/core';
 import { Typography } from '@material-ui/core';
 import { rootContext } from '../context/Root';
 import { rootContext } from '../context/Root';
@@ -8,11 +8,13 @@ import { StatusEnum } from '../components/status/Types';
 import { CollectionData } from '../pages/overview/collectionCard/Types';
 import { CollectionData } from '../pages/overview/collectionCard/Types';
 
 
 // handle release and load dialog
 // handle release and load dialog
-export interface DialogHookProps {
+export interface LoadAndReleaseDialogHookProps {
   type: 'partition' | 'collection';
   type: 'partition' | 'collection';
 }
 }
 
 
-export const useDialogHook = (props: DialogHookProps) => {
+export const useLoadAndReleaseDialogHook = (
+  props: LoadAndReleaseDialogHookProps
+) => {
   const { type } = props;
   const { type } = props;
   const { setDialog } = useContext(rootContext);
   const { setDialog } = useContext(rootContext);
   const { t: dialogTrans } = useTranslation('dialog');
   const { t: dialogTrans } = useTranslation('dialog');
@@ -70,3 +72,24 @@ export const useDialogHook = (props: DialogHookProps) => {
     handleAction,
     handleAction,
   };
   };
 };
 };
+
+export const useInsertDialogHook = () => {
+  const { setDialog } = useContext(rootContext);
+
+  const handleInsertDialog = (
+    // stepper container, contains all contents
+    component: ReactElement
+  ) => {
+    setDialog({
+      open: true,
+      type: 'custom',
+      params: {
+        component,
+      },
+    });
+  };
+
+  return {
+    handleInsertDialog,
+  };
+};

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

@@ -11,6 +11,10 @@ const btnTrans = {
   release: 'Release',
   release: 'Release',
   create: 'Create',
   create: 'Create',
   load: 'Load',
   load: 'Load',
+  insert: 'Import Data',
+  next: 'Next',
+  previous: 'Previous',
+  done: 'Done',
 };
 };
 
 
 export default btnTrans;
 export default btnTrans;

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

@@ -0,0 +1,6 @@
+const insertTrans = {
+  import: 'Import Data',
+  targetTip: 'Where to put your data',
+};
+
+export default insertTrans;

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

@@ -11,6 +11,10 @@ const btnTrans = {
   delete: 'Delete',
   delete: 'Delete',
   release: 'Release',
   release: 'Release',
   load: 'Load',
   load: 'Load',
+  insert: 'Import Data',
+  next: 'Next',
+  previous: 'Previous',
+  done: 'Done',
 };
 };
 
 
 export default btnTrans;
 export default btnTrans;

+ 6 - 0
client/src/i18n/en/insert.ts

@@ -0,0 +1,6 @@
+const insertTrans = {
+  import: 'Import Data',
+  targetTip: 'Where to put your data',
+};
+
+export default insertTrans;

+ 4 - 0
client/src/i18n/index.ts

@@ -21,6 +21,8 @@ import successEn from './en/success';
 import successCn from './cn/success';
 import successCn from './cn/success';
 import indexEn from './en/index';
 import indexEn from './en/index';
 import indexCn from './cn/index';
 import indexCn from './cn/index';
+import insertEn from './en/insert';
+import insertCn from './cn/insert';
 
 
 export const resources = {
 export const resources = {
   cn: {
   cn: {
@@ -34,6 +36,7 @@ export const resources = {
     partition: partitionCn,
     partition: partitionCn,
     success: successCn,
     success: successCn,
     index: indexCn,
     index: indexCn,
+    insert: insertCn,
   },
   },
   en: {
   en: {
     translation: commonEn,
     translation: commonEn,
@@ -46,6 +49,7 @@ export const resources = {
     partition: partitionEn,
     partition: partitionEn,
     success: successEn,
     success: successEn,
     index: indexEn,
     index: indexEn,
+    insert: insertEn,
   },
   },
 };
 };
 
 

+ 31 - 2
client/src/pages/collections/Collections.tsx

@@ -19,9 +19,13 @@ 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';
+import {
+  useInsertDialogHook,
+  useLoadAndReleaseDialogHook,
+} from '../../hooks/Dialog';
 import Highlighter from 'react-highlight-words';
 import Highlighter from 'react-highlight-words';
 import { parseLocationSearch } from '../../utils/Format';
 import { parseLocationSearch } from '../../utils/Format';
+import InsertContainer from '../../components/insert/Container';
 
 
 const useStyles = makeStyles((theme: Theme) => ({
 const useStyles = makeStyles((theme: Theme) => ({
   emptyWrapper: {
   emptyWrapper: {
@@ -52,7 +56,8 @@ const { search = '' } = parseLocationSearch(window.location.search);
 
 
 const Collections = () => {
 const Collections = () => {
   useNavigationHook(ALL_ROUTER_TYPES.COLLECTIONS);
   useNavigationHook(ALL_ROUTER_TYPES.COLLECTIONS);
-  const { handleAction } = useDialogHook({ type: 'collection' });
+  const { handleAction } = useLoadAndReleaseDialogHook({ type: 'collection' });
+  const { handleInsertDialog } = useInsertDialogHook();
   const [collections, setCollections] = useState<CollectionView[]>([]);
   const [collections, setCollections] = useState<CollectionView[]>([]);
   const [searchedCollections, setSearchedCollections] = useState<
   const [searchedCollections, setSearchedCollections] = useState<
     CollectionView[]
     CollectionView[]
@@ -224,6 +229,30 @@ const Collections = () => {
       },
       },
       icon: 'add',
       icon: 'add',
     },
     },
+    // {
+    //   label: btnTrans('insert'),
+    //   onClick: () => {
+    //     const component = (
+    //       <InsertContainer
+    //         collections={[]}
+    //         selectedCollection={''}
+    //         partitions={[]}
+    //         selectedPartition={''}
+    //         schema={[]}
+    //         handleInsert={() => {}}
+    //       />
+    //     );
+    //     handleInsertDialog(component);
+    //   },
+    //   /**
+    //    * insert validation:
+    //    * 1. At least 1 available collection
+    //    * 2. selected collections quantity shouldn't over 1
+    //    */
+    //   disabled: () =>
+    //     collectionList.length === 0 || selectedCollections.length > 1,
+    //   icon: 'upload',
+    // },
     {
     {
       type: 'iconBtn',
       type: 'iconBtn',
       onClick: () => {
       onClick: () => {

+ 1 - 1
client/src/pages/collections/Create.tsx

@@ -175,7 +175,7 @@ const CreateCollection: FC<CollectionCreateProps> = ({ handleCreate }) => {
   return (
   return (
     <DialogTemplate
     <DialogTemplate
       title={collectionTrans('createTitle')}
       title={collectionTrans('createTitle')}
-      handleCancel={handleCloseDialog}
+      handleClose={handleCloseDialog}
       confirmLabel={btnTrans('create')}
       confirmLabel={btnTrans('create')}
       handleConfirm={handleCreateCollection}
       handleConfirm={handleCreateCollection}
       confirmDisabled={disabled || !allFieldsValid}
       confirmDisabled={disabled || !allFieldsValid}

+ 2 - 2
client/src/pages/overview/Overview.tsx

@@ -5,7 +5,7 @@ import EmptyCard from '../../components/cards/EmptyCard';
 import icons from '../../components/icons/Icons';
 import icons from '../../components/icons/Icons';
 import { StatusEnum } from '../../components/status/Types';
 import { StatusEnum } from '../../components/status/Types';
 import { rootContext } from '../../context/Root';
 import { rootContext } from '../../context/Root';
-import { useDialogHook } from '../../hooks/Dialog';
+import { useLoadAndReleaseDialogHook } from '../../hooks/Dialog';
 import { useNavigationHook } from '../../hooks/Navigation';
 import { useNavigationHook } from '../../hooks/Navigation';
 import { CollectionHttp } from '../../http/Collection';
 import { CollectionHttp } from '../../http/Collection';
 import { ALL_ROUTER_TYPES } from '../../router/Types';
 import { ALL_ROUTER_TYPES } from '../../router/Types';
@@ -31,7 +31,7 @@ const useStyles = makeStyles((theme: Theme) => ({
 
 
 const Overview = () => {
 const Overview = () => {
   useNavigationHook(ALL_ROUTER_TYPES.OVERVIEW);
   useNavigationHook(ALL_ROUTER_TYPES.OVERVIEW);
-  const { handleAction } = useDialogHook({ type: 'collection' });
+  const { handleAction } = useLoadAndReleaseDialogHook({ type: 'collection' });
   const classes = useStyles();
   const classes = useStyles();
   const { t: overviewTrans } = useTranslation('overview');
   const { t: overviewTrans } = useTranslation('overview');
   const { t: collectionTrans } = useTranslation('collection');
   const { t: collectionTrans } = useTranslation('collection');

+ 1 - 1
client/src/pages/partitions/Create.tsx

@@ -63,7 +63,7 @@ const CreatePartition: FC<PartitionCreateProps> = ({
   return (
   return (
     <DialogTemplate
     <DialogTemplate
       title={partitionTrans('createTitle')}
       title={partitionTrans('createTitle')}
-      handleCancel={handleClose}
+      handleClose={handleClose}
       confirmLabel={btnTrans('create')}
       confirmLabel={btnTrans('create')}
       handleConfirm={handleCreatePartition}
       handleConfirm={handleCreatePartition}
       confirmDisabled={disabled}
       confirmDisabled={disabled}

+ 1 - 1
client/src/pages/schema/Create.tsx

@@ -138,7 +138,7 @@ const CreateIndex = (props: {
         type: indexTrans('index'),
         type: indexTrans('index'),
         name: collectionName,
         name: collectionName,
       })}
       })}
-      handleCancel={handleCancel}
+      handleClose={handleCancel}
       confirmLabel={btnTrans('create')}
       confirmLabel={btnTrans('create')}
       handleConfirm={handleCreateIndex}
       handleConfirm={handleCreateIndex}
       confirmDisabled={disabled}
       confirmDisabled={disabled}

+ 0 - 1
client/src/pages/schema/Types.ts

@@ -1,5 +1,4 @@
 import { ReactElement } from 'react';
 import { ReactElement } from 'react';
-import { ManageRequestMethods } from '../../types/Common';
 import { DataType } from '../collections/Types';
 import { DataType } from '../collections/Types';
 
 
 export enum INDEX_TYPES_ENUM {
 export enum INDEX_TYPES_ENUM {

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

@@ -1,3 +1,8 @@
+/**
+ * we usually use Material makeStyles to write component and page style
+ * this file is used for some global scope reusable style
+ */
+
 /* reset some elements styles */
 /* reset some elements styles */
 fieldset {
 fieldset {
   border: 0;
   border: 0;