|
@@ -1,63 +1,22 @@
|
|
|
-import { Theme, Typography, Chip } from '@mui/material';
|
|
|
+import { Typography, Chip, Autocomplete, TextField } from '@mui/material';
|
|
|
import { FC, useState, useContext } from 'react';
|
|
|
import { useTranslation } from 'react-i18next';
|
|
|
import { saveAs } from 'file-saver';
|
|
|
import DialogTemplate from '@/components/customDialog/DialogTemplate';
|
|
|
-import CustomSelector from '@/components/customSelector/CustomSelector';
|
|
|
import { rootContext } from '@/context';
|
|
|
import { InsertStatusEnum } from './insert/consts';
|
|
|
import { DataService } from '@/http';
|
|
|
import { LoadSampleParam } from './Types';
|
|
|
import icons from '@/components/icons/Icons';
|
|
|
-import { makeStyles } from '@mui/styles';
|
|
|
import type { CollectionObject } from '@server/types';
|
|
|
|
|
|
const DownloadIcon = icons.download;
|
|
|
|
|
|
-const getStyles = makeStyles((theme: Theme) => {
|
|
|
- return {
|
|
|
- icon: {
|
|
|
- fontSize: '16px',
|
|
|
- },
|
|
|
- downloadBtn: {
|
|
|
- maxWidth: '240px',
|
|
|
- margin: theme.spacing(1.5, 1.5, 0, 0),
|
|
|
- },
|
|
|
- selectors: {
|
|
|
- '& .selectorWrapper': {
|
|
|
- display: 'flex',
|
|
|
- flexDirection: 'column',
|
|
|
- marginBottom: theme.spacing(2),
|
|
|
-
|
|
|
- '& .selectLabel': {
|
|
|
- fontSize: '14px',
|
|
|
- lineHeight: '20px',
|
|
|
-
|
|
|
- color: theme.palette.text.secondary,
|
|
|
- },
|
|
|
-
|
|
|
- '& .description': {
|
|
|
- color: theme.palette.text.secondary,
|
|
|
- marginBottom: theme.spacing(2),
|
|
|
- fontSize: 13,
|
|
|
- lineHeight: 1.5,
|
|
|
- width: '35vw',
|
|
|
- },
|
|
|
- },
|
|
|
- '& .actions': {
|
|
|
- display: 'flex',
|
|
|
- flexDirection: 'column',
|
|
|
- },
|
|
|
- '& .download-actions': {
|
|
|
- display: 'flex',
|
|
|
- flexDirection: 'row',
|
|
|
- },
|
|
|
- '& .selector': {},
|
|
|
- },
|
|
|
- };
|
|
|
-});
|
|
|
-
|
|
|
const sizeOptions = [
|
|
|
+ {
|
|
|
+ label: '10',
|
|
|
+ value: '10',
|
|
|
+ },
|
|
|
{
|
|
|
label: '100',
|
|
|
value: '100',
|
|
@@ -76,178 +35,250 @@ const sizeOptions = [
|
|
|
},
|
|
|
];
|
|
|
|
|
|
-const ImportSampleDialog: FC<{ collection: CollectionObject; cb?: Function }> =
|
|
|
- props => {
|
|
|
- const classes = getStyles();
|
|
|
- const { collection } = props;
|
|
|
- const [size, setSize] = useState<string>(sizeOptions[0].value);
|
|
|
- const [csvFileName, setCsvFileName] = useState<string>(
|
|
|
- `${collection.collection_name}.sample.${size}.csv`
|
|
|
- );
|
|
|
- const [jsonFileName, setJsonFileName] = useState<string>(
|
|
|
- `${collection.collection_name}.sample.${size}.json`
|
|
|
- );
|
|
|
- const [insertStatus, setInsertStatus] = useState<InsertStatusEnum>(
|
|
|
- InsertStatusEnum.init
|
|
|
- );
|
|
|
-
|
|
|
- const { t: insertTrans } = useTranslation('insert');
|
|
|
- const { t: btnTrans } = useTranslation('btn');
|
|
|
- const { handleCloseDialog, openSnackBar } = useContext(rootContext);
|
|
|
- // selected collection name
|
|
|
+const ImportSampleDialog: FC<{
|
|
|
+ collection: CollectionObject;
|
|
|
+ cb?: Function;
|
|
|
+}> = props => {
|
|
|
+ const { collection } = props;
|
|
|
+ const [size, setSize] = useState<string>(sizeOptions[0].value);
|
|
|
+ const [csvFileName, setCsvFileName] = useState<string>(
|
|
|
+ `${collection.collection_name}.sample.${size}.csv`
|
|
|
+ );
|
|
|
+ const [jsonFileName, setJsonFileName] = useState<string>(
|
|
|
+ `${collection.collection_name}.sample.${size}.json`
|
|
|
+ );
|
|
|
+ const [insertStatus, setInsertStatus] = useState<InsertStatusEnum>(
|
|
|
+ InsertStatusEnum.init
|
|
|
+ );
|
|
|
|
|
|
- const handleImportSample = async (
|
|
|
- collectionName: string,
|
|
|
- size: string,
|
|
|
- download: boolean = false,
|
|
|
- format: 'csv' | 'json' = 'csv'
|
|
|
- ): Promise<{ result: string | boolean; msg: string }> => {
|
|
|
- const param: LoadSampleParam = {
|
|
|
- collection_name: collectionName,
|
|
|
- size: size,
|
|
|
- download,
|
|
|
- format: format,
|
|
|
- };
|
|
|
- try {
|
|
|
- const res = await DataService.importSample(collectionName, param);
|
|
|
- if (download) {
|
|
|
- const fileName = format === 'csv' ? csvFileName : jsonFileName;
|
|
|
- const type =
|
|
|
- format === 'csv' ? 'text/csv;charset=utf-8;' : 'application/json';
|
|
|
- const blob = new Blob([res.sampleFile], { type });
|
|
|
- saveAs(blob, fileName);
|
|
|
- return { result: res.sampleFile, msg: '' };
|
|
|
- }
|
|
|
- await DataService.flush(collectionName);
|
|
|
- if (props.cb) {
|
|
|
- await props.cb(collectionName);
|
|
|
- }
|
|
|
- return { result: true, msg: '' };
|
|
|
- } catch (err: any) {
|
|
|
- const {
|
|
|
- response: {
|
|
|
- data: { message },
|
|
|
- },
|
|
|
- } = err;
|
|
|
- return { result: false, msg: message || '' };
|
|
|
- }
|
|
|
- };
|
|
|
+ const { t: insertTrans } = useTranslation('insert');
|
|
|
+ const { t: btnTrans } = useTranslation('btn');
|
|
|
+ const { handleCloseDialog, openSnackBar } = useContext(rootContext);
|
|
|
|
|
|
- const onDownloadCSVClicked = async () => {
|
|
|
- return await handleImportSample(
|
|
|
- collection.collection_name,
|
|
|
- size,
|
|
|
- true,
|
|
|
- 'csv'
|
|
|
- );
|
|
|
+ const handleImportSample = async (
|
|
|
+ collectionName: string,
|
|
|
+ size: string,
|
|
|
+ download: boolean = false,
|
|
|
+ format: 'csv' | 'json' = 'csv'
|
|
|
+ ): Promise<{ result: string | boolean; msg: string }> => {
|
|
|
+ const param: LoadSampleParam = {
|
|
|
+ collection_name: collectionName,
|
|
|
+ size: size,
|
|
|
+ download,
|
|
|
+ format: format,
|
|
|
};
|
|
|
+ try {
|
|
|
+ const res = await DataService.importSample(collectionName, param);
|
|
|
+ if (download) {
|
|
|
+ const fileName = format === 'csv' ? csvFileName : jsonFileName;
|
|
|
+ const type =
|
|
|
+ format === 'csv' ? 'text/csv;charset=utf-8;' : 'application/json';
|
|
|
+ const blob = new Blob([res.sampleFile], { type });
|
|
|
+ saveAs(blob, fileName);
|
|
|
+ return { result: res.sampleFile, msg: '' };
|
|
|
+ }
|
|
|
+ await DataService.flush(collectionName);
|
|
|
+ if (props.cb) {
|
|
|
+ await props.cb(collectionName);
|
|
|
+ }
|
|
|
+ return { result: true, msg: '' };
|
|
|
+ } catch (err: any) {
|
|
|
+ const {
|
|
|
+ response: {
|
|
|
+ data: { message },
|
|
|
+ },
|
|
|
+ } = err;
|
|
|
+ return { result: false, msg: message || '' };
|
|
|
+ }
|
|
|
+ };
|
|
|
|
|
|
- const onDownloadJSONClicked = async () => {
|
|
|
- return await handleImportSample(
|
|
|
- collection.collection_name,
|
|
|
- size,
|
|
|
- true,
|
|
|
- 'json'
|
|
|
- );
|
|
|
- };
|
|
|
+ const onDownloadCSVClicked = async () => {
|
|
|
+ return await handleImportSample(
|
|
|
+ collection.collection_name,
|
|
|
+ size,
|
|
|
+ true,
|
|
|
+ 'csv'
|
|
|
+ );
|
|
|
+ };
|
|
|
|
|
|
- const importData = async () => {
|
|
|
- if (insertStatus === InsertStatusEnum.success) {
|
|
|
- handleCloseDialog();
|
|
|
- return;
|
|
|
- }
|
|
|
- // start loading
|
|
|
- setInsertStatus(InsertStatusEnum.loading);
|
|
|
- const { result, msg } = await handleImportSample(
|
|
|
- collection.collection_name,
|
|
|
- size
|
|
|
- );
|
|
|
+ const onDownloadJSONClicked = async () => {
|
|
|
+ return await handleImportSample(
|
|
|
+ collection.collection_name,
|
|
|
+ size,
|
|
|
+ true,
|
|
|
+ 'json'
|
|
|
+ );
|
|
|
+ };
|
|
|
|
|
|
- if (!result) {
|
|
|
- openSnackBar(msg, 'error');
|
|
|
- setInsertStatus(InsertStatusEnum.init);
|
|
|
- return;
|
|
|
- }
|
|
|
- setInsertStatus(InsertStatusEnum.success);
|
|
|
- // hide dialog
|
|
|
+ const importData = async () => {
|
|
|
+ if (insertStatus === InsertStatusEnum.success) {
|
|
|
handleCloseDialog();
|
|
|
- };
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // start loading
|
|
|
+ setInsertStatus(InsertStatusEnum.loading);
|
|
|
+ const { result, msg } = await handleImportSample(
|
|
|
+ collection.collection_name,
|
|
|
+ size
|
|
|
+ );
|
|
|
+
|
|
|
+ if (!result) {
|
|
|
+ openSnackBar(msg, 'error');
|
|
|
+ setInsertStatus(InsertStatusEnum.init);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ setInsertStatus(InsertStatusEnum.success);
|
|
|
+ // hide dialog
|
|
|
+ handleCloseDialog();
|
|
|
+ };
|
|
|
|
|
|
- return (
|
|
|
- <DialogTemplate
|
|
|
- title={insertTrans('importSampleData', {
|
|
|
- collection: collection.collection_name,
|
|
|
- })}
|
|
|
- handleClose={handleCloseDialog}
|
|
|
- confirmLabel={
|
|
|
- insertStatus === InsertStatusEnum.init
|
|
|
- ? btnTrans('import')
|
|
|
- : insertStatus === InsertStatusEnum.loading
|
|
|
+ return (
|
|
|
+ <DialogTemplate
|
|
|
+ title={insertTrans('importSampleData', {
|
|
|
+ collection: collection.collection_name,
|
|
|
+ })}
|
|
|
+ handleClose={handleCloseDialog}
|
|
|
+ confirmLabel={
|
|
|
+ insertStatus === InsertStatusEnum.init
|
|
|
+ ? btnTrans('import')
|
|
|
+ : insertStatus === InsertStatusEnum.loading
|
|
|
? btnTrans('importing')
|
|
|
: insertStatus === InsertStatusEnum.success
|
|
|
- ? btnTrans('done')
|
|
|
- : insertStatus
|
|
|
- }
|
|
|
- handleConfirm={importData}
|
|
|
- confirmDisabled={insertStatus === InsertStatusEnum.loading}
|
|
|
- showActions={true}
|
|
|
- showCancel={false}
|
|
|
- // don't show close icon when insert not finish
|
|
|
- // showCloseIcon={insertStatus !== InsertStatusEnum.loading}
|
|
|
- >
|
|
|
- <section className={classes.selectors}>
|
|
|
- <div className="selectorWrapper">
|
|
|
- <div className="description">
|
|
|
- <Typography variant="inherit" component="p">
|
|
|
- {insertTrans('importSampleDataDesc')}
|
|
|
- </Typography>
|
|
|
- </div>
|
|
|
+ ? btnTrans('done')
|
|
|
+ : insertStatus
|
|
|
+ }
|
|
|
+ handleConfirm={importData}
|
|
|
+ confirmDisabled={insertStatus === InsertStatusEnum.loading}
|
|
|
+ showActions={true}
|
|
|
+ showCancel={false}
|
|
|
+ >
|
|
|
+ <section style={{}}>
|
|
|
+ <div
|
|
|
+ className="selectorWrapper"
|
|
|
+ style={{
|
|
|
+ display: 'flex',
|
|
|
+ flexDirection: 'column',
|
|
|
+ marginBottom: 16,
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ className="description"
|
|
|
+ style={{
|
|
|
+ color: '#6b7280', // theme.palette.text.secondary
|
|
|
+ marginBottom: 16,
|
|
|
+ fontSize: 13,
|
|
|
+ lineHeight: 1.5,
|
|
|
+ width: '35vw',
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <Typography variant="inherit" component="p">
|
|
|
+ {insertTrans('importSampleDataDesc')}
|
|
|
+ </Typography>
|
|
|
+ </div>
|
|
|
|
|
|
- <div className="actions">
|
|
|
- <CustomSelector
|
|
|
- label={insertTrans('sampleDataSize')}
|
|
|
- options={sizeOptions}
|
|
|
- wrapperClass="selector"
|
|
|
- labelClass="selectLabel"
|
|
|
- value={size}
|
|
|
- variant="filled"
|
|
|
- onChange={(e: { target: { value: unknown } }) => {
|
|
|
- const size = e.target.value;
|
|
|
- setSize(size as string);
|
|
|
+ <div
|
|
|
+ className="actions"
|
|
|
+ style={{
|
|
|
+ display: 'flex',
|
|
|
+ flexDirection: 'column',
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <Autocomplete
|
|
|
+ freeSolo
|
|
|
+ options={sizeOptions.map(option => option.value)}
|
|
|
+ value={size}
|
|
|
+ onChange={(event: any, newValue: string | null) => {
|
|
|
+ if (newValue && /^\d+$/.test(newValue)) {
|
|
|
+ const val = Math.min(Number(newValue), 10000).toString();
|
|
|
+ setSize(val);
|
|
|
setCsvFileName(
|
|
|
- `${collection.collection_name}.sample.${size}.csv`
|
|
|
+ `${collection.collection_name}.sample.${val}.csv`
|
|
|
);
|
|
|
setJsonFileName(
|
|
|
- `${collection.collection_name}.sample.${size}.json`
|
|
|
+ `${collection.collection_name}.sample.${val}.json`
|
|
|
);
|
|
|
- }}
|
|
|
- />
|
|
|
- </div>
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ onInputChange={(event, newInputValue) => {
|
|
|
+ if (/^\d*$/.test(newInputValue)) {
|
|
|
+ let val = newInputValue;
|
|
|
+ if (val) {
|
|
|
+ val = Math.min(Number(val), 10000).toString();
|
|
|
+ }
|
|
|
+ setSize(val);
|
|
|
+ setCsvFileName(
|
|
|
+ `${collection.collection_name}.sample.${val}.csv`
|
|
|
+ );
|
|
|
+ setJsonFileName(
|
|
|
+ `${collection.collection_name}.sample.${val}.json`
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ renderInput={params => (
|
|
|
+ <TextField
|
|
|
+ {...params}
|
|
|
+ label={insertTrans('sampleDataSize')}
|
|
|
+ variant="filled"
|
|
|
+ inputProps={{
|
|
|
+ ...params.inputProps,
|
|
|
+ inputMode: 'numeric',
|
|
|
+ pattern: '[0-9]*',
|
|
|
+ max: 10000,
|
|
|
+ }}
|
|
|
+ onInput={e => {
|
|
|
+ const input = e.target as HTMLInputElement;
|
|
|
+ let val = input.value.replace(/[^0-9]/g, '');
|
|
|
+ if (val) {
|
|
|
+ val = Math.min(Number(val), 10000).toString();
|
|
|
+ }
|
|
|
+ input.value = val;
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ )}
|
|
|
+ sx={{ marginBottom: 2 }}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
|
|
|
- <div className="download-actions">
|
|
|
- <Chip
|
|
|
- className={classes.downloadBtn}
|
|
|
- icon={<DownloadIcon />}
|
|
|
- label={csvFileName}
|
|
|
- title={csvFileName}
|
|
|
- variant="outlined"
|
|
|
- size="small"
|
|
|
- onClick={onDownloadCSVClicked}
|
|
|
- />
|
|
|
- <Chip
|
|
|
- className={classes.downloadBtn}
|
|
|
- icon={<DownloadIcon />}
|
|
|
- label={jsonFileName}
|
|
|
- title={jsonFileName}
|
|
|
- variant="outlined"
|
|
|
- size="small"
|
|
|
- onClick={onDownloadJSONClicked}
|
|
|
- />
|
|
|
- </div>
|
|
|
+ <div
|
|
|
+ className="download-actions"
|
|
|
+ style={{
|
|
|
+ display: 'flex',
|
|
|
+ flexDirection: 'row',
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <Chip
|
|
|
+ // className={classes.downloadBtn}
|
|
|
+ sx={{
|
|
|
+ maxWidth: '240px',
|
|
|
+ margin: theme => theme.spacing(1.5, 1.5, 0, 0),
|
|
|
+ fontSize: '14px',
|
|
|
+ }}
|
|
|
+ icon={<DownloadIcon sx={{ fontSize: '16px' }} />}
|
|
|
+ label={csvFileName}
|
|
|
+ title={csvFileName}
|
|
|
+ variant="outlined"
|
|
|
+ size="small"
|
|
|
+ onClick={onDownloadCSVClicked}
|
|
|
+ />
|
|
|
+ <Chip
|
|
|
+ // className={classes.downloadBtn}
|
|
|
+ sx={{
|
|
|
+ maxWidth: '240px',
|
|
|
+ margin: theme => theme.spacing(1.5, 1.5, 0, 0),
|
|
|
+ fontSize: '14px',
|
|
|
+ }}
|
|
|
+ icon={<DownloadIcon sx={{ fontSize: '16px' }} />}
|
|
|
+ label={jsonFileName}
|
|
|
+ title={jsonFileName}
|
|
|
+ variant="outlined"
|
|
|
+ size="small"
|
|
|
+ onClick={onDownloadJSONClicked}
|
|
|
+ />
|
|
|
</div>
|
|
|
- </section>
|
|
|
- </DialogTemplate>
|
|
|
- );
|
|
|
- };
|
|
|
+ </div>
|
|
|
+ </section>
|
|
|
+ </DialogTemplate>
|
|
|
+ );
|
|
|
+};
|
|
|
|
|
|
export default ImportSampleDialog;
|