Browse Source

add import dialog ui

tumao 4 years ago
parent
commit
9866c1a14f

+ 12 - 21
client/src/components/customSelector/CustomSelector.tsx

@@ -1,36 +1,27 @@
 import { FC } from 'react';
-import {
-  createStyles,
-  FormControl,
-  InputLabel,
-  makeStyles,
-  MenuItem,
-  Select,
-  Theme,
-} from '@material-ui/core';
+import { FormControl, InputLabel, MenuItem, Select } from '@material-ui/core';
 import { CustomSelectorType } from './Types';
 import { generateId } from '../../utils/Common';
 
-const useStyles = makeStyles((theme: Theme) =>
-  createStyles({
-    label: {
-      // textTransform: 'capitalize',
-    },
-  })
-);
-
 /**
  *  label: We may need label lowecase or capitalize, so we cant control css inside.
  * */
 const CustomSelector: FC<CustomSelectorType> = props => {
-  const { label, value, onChange, options, classes, variant, ...others } =
-    props;
+  const {
+    label,
+    value,
+    onChange,
+    options,
+    classes,
+    variant,
+    labelClass = '',
+    ...others
+  } = props;
   const id = generateId('selector');
-  const selectorClasses = useStyles();
 
   return (
     <FormControl variant={variant} classes={classes}>
-      <InputLabel htmlFor={id} className={selectorClasses.label}>
+      <InputLabel classes={{ root: labelClass }} htmlFor={id}>
         {label}
       </InputLabel>
       <Select

+ 1 - 0
client/src/components/customSelector/Types.ts

@@ -18,6 +18,7 @@ export type CustomSelectorType = SelectProps & {
   onChange: (e: React.ChangeEvent<{ value: unknown }>) => void;
   classes?: Partial<ClassNameMap<FormControlClassKey>>;
   variant?: 'filled' | 'outlined' | 'standard';
+  labelClass?: string;
 };
 
 export interface ICustomGroupSelect {

+ 93 - 3
client/src/components/insert/Import.tsx

@@ -4,10 +4,13 @@ import { makeStyles, Theme, Divider } from '@material-ui/core';
 import CustomSelector from '../customSelector/CustomSelector';
 import { FC } from 'react';
 import { InsertImportProps } from './Types';
+import Uploader from '../uploader/Uploader';
+import { INSERT_CSV_SAMPLE } from '../../consts/Insert';
 
 const getStyles = makeStyles((theme: Theme) => ({
   tip: {
     color: theme.palette.milvusGrey.dark,
+    marginBottom: theme.spacing(1),
   },
   selectorWrapper: {
     display: 'flex',
@@ -19,15 +22,66 @@ const getStyles = makeStyles((theme: Theme) => ({
       minWidth: '256px',
     },
 
+    '& .selectLabel': {
+      fontSize: '14px',
+      lineHeight: '20px',
+      color: '#010e29',
+    },
+
     '& .divider': {
       width: '20px',
       margin: theme.spacing(0, 4),
-      color: theme.palette.milvusGrey.dark,
+      backgroundColor: theme.palette.milvusGrey.dark,
     },
   },
   uploadWrapper: {
-    backgroundColor: '#f9f9f9',
+    marginTop: theme.spacing(3),
     padding: theme.spacing(1),
+    backgroundColor: '#f9f9f9',
+
+    '& .text': {
+      color: theme.palette.milvusGrey.dark,
+    },
+
+    '& .file': {
+      marginBottom: theme.spacing(1),
+    },
+
+    '& .uploaderWrapper': {
+      display: 'flex',
+      alignItems: 'center',
+
+      border: '1px solid #e9e9ed',
+      borderRadius: '4px',
+      padding: theme.spacing(1),
+
+      backgroundColor: '#fff',
+
+      '& .uploader': {
+        marginRight: theme.spacing(1),
+      },
+    },
+
+    '& .sampleWrapper': {
+      '& .sample': {
+        backgroundColor: '#fff',
+        padding: theme.spacing(2),
+        margin: theme.spacing(1, 0),
+      },
+    },
+
+    '& .title': {
+      marginTop: theme.spacing(1),
+    },
+
+    '& .noteList': {
+      marginTop: theme.spacing(1),
+      paddingLeft: theme.spacing(3),
+    },
+
+    '& .noteItem': {
+      maxWidth: '560px',
+    },
   },
 }));
 
@@ -45,6 +99,8 @@ const InsertImport: FC<InsertImportProps> = ({
   const handleCollectionChange = () => {};
   const handlePartitionChange = () => {};
 
+  const fileName = '';
+
   return (
     <section>
       <Typography className={classes.tip}>
@@ -55,6 +111,7 @@ const InsertImport: FC<InsertImportProps> = ({
         <CustomSelector
           options={collectionOptions}
           classes={{ root: 'selector' }}
+          labelClass="selectLabel"
           value={selectedCollection}
           variant="filled"
           label={collectionTrans('collection')}
@@ -64,6 +121,7 @@ const InsertImport: FC<InsertImportProps> = ({
         <CustomSelector
           options={partitionOptions}
           classes={{ root: 'selector' }}
+          labelClass="selectLabel"
           value={selectedPartition}
           variant="filled"
           label={partitionTrans('partition')}
@@ -71,7 +129,39 @@ const InsertImport: FC<InsertImportProps> = ({
         />
       </form>
 
-      <div className={classes.uploadWrapper}>uploader</div>
+      <div className={classes.uploadWrapper}>
+        <Typography className="text file" variant="body1">
+          {insertTrans('file')}
+        </Typography>
+        <div className="uploaderWrapper">
+          <Uploader
+            btnClass="uploader"
+            label={insertTrans('uploaderLabel')}
+            accept=".csv"
+          />
+          <Typography className="text">
+            {fileName || insertTrans('fileNamePlaceHolder')}
+          </Typography>
+        </div>
+
+        <div className="sampleWrapper">
+          <Typography variant="body2" className="text title">
+            {insertTrans('sample')}
+          </Typography>
+          <pre className="sample">{INSERT_CSV_SAMPLE}</pre>
+        </div>
+
+        <Typography variant="body2" className="text title">
+          {insertTrans('noteTitle')}
+        </Typography>
+        <ul className="noteList">
+          {insertTrans('notes', { returnObjects: true }).map(note => (
+            <li className="text noteItem">
+              <Typography>{note}</Typography>
+            </li>
+          ))}
+        </ul>
+      </div>
     </section>
   );
 };

+ 4 - 1
client/src/components/uploader/Uploader.tsx

@@ -13,7 +13,10 @@ const Uploader: FC<UploaderProps> = ({ label, accept, btnClass = '' }) => {
 
   return (
     <form>
-      <CustomButton variant="text" className={`${classes.btn} ${btnClass}`}>
+      <CustomButton
+        variant="contained"
+        className={`${classes.btn} ${btnClass}`}
+      >
         {label}
       </CustomButton>
       <input

+ 4 - 0
client/src/consts/Insert.ts

@@ -0,0 +1,4 @@
+export const INSERT_CSV_SAMPLE = `Date, Country, Units, Revenue,\n
+1, 183, [13848...], [318998...]\n
+909,3898,[3898...], [84981...]\n
+...`;

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

@@ -1,6 +1,16 @@
 const insertTrans = {
   import: 'Import Data',
   targetTip: 'Where to put your data',
+  file: 'File',
+  uploaderLabel: 'Choose CSV File',
+  fileNamePlaceHolder: 'No file selected',
+  sample: 'CSV Sample',
+  noteTitle: 'Note',
+  notes: [
+    `Make sure column names in the data are same as the field label names in Schema.`,
+    `Data size should be less than 5MB and the number of rows should be less than 100000, for the data to be imported properly.`,
+    `The "Import Data" option will only append new records. You cannot update existing records using this option.`,
+  ],
 };
 
 export default insertTrans;

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

@@ -1,6 +1,16 @@
 const insertTrans = {
   import: 'Import Data',
   targetTip: 'Where to put your data',
+  file: 'File',
+  uploaderLabel: 'Choose CSV File',
+  fileNamePlaceHolder: 'No file selected',
+  sample: 'CSV Sample',
+  noteTitle: 'Note',
+  notes: [
+    `Make sure column names in the data are same as the field label names in Schema.`,
+    `Data size should be less than 5MB and the number of rows should be less than 100000, for the data to be imported properly.`,
+    `The "Import Data" option will only append new records. You cannot update existing records using this option.`,
+  ],
 };
 
 export default insertTrans;

+ 24 - 24
client/src/pages/collections/Collections.tsx

@@ -229,30 +229,30 @@ const Collections = () => {
       },
       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',
-    // },
+    {
+      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',
       onClick: () => {

+ 9 - 0
client/src/styles/theme.ts

@@ -158,5 +158,14 @@ export const theme = createMuiTheme({
         marginLeft: 0,
       },
     },
+    MuiFilledInput: {
+      root: {
+        backgroundColor: '#f9f9f9',
+
+        '&:hover': {
+          backgroundColor: '#f9f9f9',
+        },
+      },
+    },
   },
 });