update the upload

This commit is contained in:
proddy
2024-08-14 18:53:52 +02:00
parent d5fec4aec8
commit 5a058746bb
11 changed files with 466 additions and 720 deletions

View File

@@ -22,6 +22,11 @@ export const alovaInstance = createAlova({
method.config.headers.Authorization =
'Bearer ' + localStorage.getItem(ACCESS_TOKEN);
}
// for simualting vrey slow networks
// return new Promise((resolve) => {
// const random = 3000 + Math.random() * 2000;
// setTimeout(resolve, Math.floor(random));
// });
},
responded: {

View File

@@ -1,4 +1,3 @@
import { useState } from 'react';
import { toast } from 'react-toastify';
import DownloadIcon from '@mui/icons-material/GetApp';
@@ -24,28 +23,8 @@ import {
} from 'components';
import { useI18nContext } from 'i18n/i18n-react';
import RestartMonitor from '../status/RestartMonitor';
const UploadDownload = () => {
const { LL } = useI18nContext();
const [restarting, setRestarting] = useState<boolean>();
const [md5, setMd5] = useState<string>();
const {
loading: isUploading,
uploading: progress,
send: sendUpload,
abort: cancelUpload
} = useRequest(SystemApi.uploadFile, {
immediate: false
}).onSuccess(({ data }) => {
if (data) {
setMd5(data.md5 as string);
toast.success(LL.UPLOAD() + ' MD5 ' + LL.SUCCESSFUL());
} else {
setRestarting(true);
}
});
const { send: sendSettings } = useRequest(getSettings(), {
immediate: false
@@ -116,18 +95,6 @@ const UploadDownload = () => {
return data.esp_platform;
};
const startUpload = async (files: File[]) => {
await sendUpload(files[0]).catch((error: Error) => {
if (error.message === 'The user aborted a request') {
toast.warning(LL.UPLOAD() + ' ' + LL.ABORTED());
} else if (error.message === 'Network Error') {
toast.warning('Invalid file extension or incompatible bin file');
} else {
toast.error(error.message);
}
});
};
const saveFile = (json: unknown, endpoint: string) => {
const anchor = document.createElement('a');
anchor.href = URL.createObjectURL(
@@ -241,107 +208,93 @@ const UploadDownload = () => {
{LL.RESTART_TEXT(1)}.
</Typography>
</Box>
{md5 && (
<Box mb={2}>
<Typography variant="body2">{'MD5: ' + md5}</Typography>
</Box>
)}
<SingleUpload
onDrop={startUpload}
onCancel={cancelUpload}
isUploading={isUploading}
progress={progress}
/>
{!isUploading && (
<>
<Typography sx={{ pt: 4, pb: 2 }} variant="h6" color="primary">
{LL.DOWNLOAD(0)}
<SingleUpload />
<Typography sx={{ pt: 4, pb: 2 }} variant="h6" color="primary">
{LL.DOWNLOAD(0)}
</Typography>
<Box color="warning.main">
<Typography mb={1} variant="body2">
{LL.HELP_INFORMATION_4()}
</Typography>
<Button
sx={{ ml: 2 }}
startIcon={<DownloadIcon />}
variant="outlined"
color="primary"
onClick={() => callAPI('system', 'info')}
>
{LL.SUPPORT_INFORMATION(0)}
</Button>
<Button
sx={{ ml: 2 }}
startIcon={<DownloadIcon />}
variant="outlined"
color="primary"
onClick={() => callAPI('system', 'allvalues')}
>
All Values
</Button>
</Box>
<Box color="warning.main">
<Typography mt={2} mb={1} variant="body2">
{LL.DOWNLOAD_SETTINGS_TEXT()}
</Typography>
<Button
sx={{ ml: 2 }}
startIcon={<DownloadIcon />}
variant="outlined"
color="primary"
onClick={downloadSettings}
>
{LL.SETTINGS_OF('')}
</Button>
</Box>
<Box color="warning.main">
<Typography mt={2} mb={1} variant="body2">
{LL.DOWNLOAD_CUSTOMIZATION_TEXT()}
</Typography>
<Button
sx={{ ml: 2 }}
startIcon={<DownloadIcon />}
variant="outlined"
color="primary"
onClick={downloadCustomizations}
>
{LL.CUSTOMIZATIONS()}
</Button>
<Button
sx={{ ml: 2 }}
startIcon={<DownloadIcon />}
variant="outlined"
color="primary"
onClick={downloadEntities}
>
{LL.CUSTOM_ENTITIES(0)}
</Button>
<Box color="warning.main">
<Typography mt={2} mb={1} variant="body2">
{LL.DOWNLOAD_SCHEDULE_TEXT()}
</Typography>
<Box color="warning.main">
<Typography mb={1} variant="body2">
{LL.HELP_INFORMATION_4()}
</Typography>
<Button
sx={{ ml: 2 }}
startIcon={<DownloadIcon />}
variant="outlined"
color="primary"
onClick={() => callAPI('system', 'info')}
>
{LL.SUPPORT_INFORMATION(0)}
</Button>
<Button
sx={{ ml: 2 }}
startIcon={<DownloadIcon />}
variant="outlined"
color="primary"
onClick={() => callAPI('system', 'allvalues')}
>
All Values
</Button>
</Box>
<Box color="warning.main">
<Typography mt={2} mb={1} variant="body2">
{LL.DOWNLOAD_SETTINGS_TEXT()}
</Typography>
<Button
sx={{ ml: 2 }}
startIcon={<DownloadIcon />}
variant="outlined"
color="primary"
onClick={downloadSettings}
>
{LL.SETTINGS_OF('')}
</Button>
</Box>
<Box color="warning.main">
<Typography mt={2} mb={1} variant="body2">
{LL.DOWNLOAD_CUSTOMIZATION_TEXT()}
</Typography>
<Button
sx={{ ml: 2 }}
startIcon={<DownloadIcon />}
variant="outlined"
color="primary"
onClick={downloadCustomizations}
>
{LL.CUSTOMIZATIONS()}
</Button>
<Button
sx={{ ml: 2 }}
startIcon={<DownloadIcon />}
variant="outlined"
color="primary"
onClick={downloadEntities}
>
{LL.CUSTOM_ENTITIES(0)}
</Button>
<Box color="warning.main">
<Typography mt={2} mb={1} variant="body2">
{LL.DOWNLOAD_SCHEDULE_TEXT()}
</Typography>
</Box>
<Button
sx={{ ml: 2 }}
startIcon={<DownloadIcon />}
variant="outlined"
color="primary"
onClick={downloadSchedule}
>
{LL.SCHEDULE(0)}
</Button>
</Box>
</>
)}
</Box>
<Button
sx={{ ml: 2 }}
startIcon={<DownloadIcon />}
variant="outlined"
color="primary"
onClick={downloadSchedule}
>
{LL.SCHEDULE(0)}
</Button>
</Box>
</>
);
};
return (
<SectionContent>{restarting ? <RestartMonitor /> : content()}</SectionContent>
);
return <SectionContent>{content()}</SectionContent>;
};
export default UploadDownload;

View File

@@ -1,117 +1,119 @@
import { Fragment } from 'react';
import { useDropzone } from 'react-dropzone';
import type { DropzoneState } from 'react-dropzone';
import { ChangeEvent, useRef, useState } from 'react';
import { toast } from 'react-toastify';
import CancelIcon from '@mui/icons-material/Cancel';
import CloudUploadIcon from '@mui/icons-material/CloudUpload';
import { Box, Button, LinearProgress, Typography, useTheme } from '@mui/material';
import type { Theme } from '@mui/material';
import UploadIcon from '@mui/icons-material/Upload';
import { Box, Button, LinearProgress, Typography } from '@mui/material';
import type { Progress } from 'alova';
import * as SystemApi from 'api/system';
import { useRequest } from 'alova/client';
import RestartMonitor from 'app/status/RestartMonitor';
import { useI18nContext } from 'i18n/i18n-react';
const getBorderColor = (theme: Theme, props: DropzoneState) => {
if (props.isDragAccept) {
return theme.palette.success.main;
}
if (props.isDragReject) {
return theme.palette.error.main;
}
if (props.isDragActive) {
return theme.palette.info.main;
}
return theme.palette.grey[700];
};
const SingleUpload = () => {
const [md5, setMd5] = useState<string>();
const [restarting, setRestarting] = useState<boolean>();
export interface SingleUploadProps {
onDrop: (acceptedFiles: File[]) => void;
onCancel: () => void;
isUploading: boolean;
progress: Progress;
}
const SingleUpload = ({
onDrop,
onCancel,
isUploading,
progress
}: SingleUploadProps) => {
const uploading = isUploading && progress.total > 0;
const dropzoneState = useDropzone({
onDrop,
accept: {
'application/octet-stream': ['.bin'],
'application/json': ['.json'],
'text/plain': ['.md5']
},
disabled: isUploading,
multiple: false
const {
loading: isUploading,
uploading: progress,
send: sendUpload,
abort: cancelUpload
} = useRequest(SystemApi.uploadFile, {
immediate: false
}).onSuccess(({ data }) => {
if (data) {
setMd5(data.md5 as string);
toast.success(LL.UPLOAD() + ' MD5 ' + LL.SUCCESSFUL());
setFile(undefined);
} else {
setRestarting(true);
}
});
const { getRootProps, getInputProps } = dropzoneState;
const theme = useTheme();
const [file, setFile] = useState<File>();
const inputRef = useRef<HTMLInputElement | null>(null);
const { LL } = useI18nContext();
const progressText = () => {
if (uploading) {
return (
LL.UPLOADING() +
': ' +
Math.round((progress.loaded * 100) / progress.total) +
'%'
);
console.log(progress); // TODO remove
const handleUploadClick = () => {
inputRef.current?.click();
};
const handleFileChange = async (e: ChangeEvent<HTMLInputElement>) => {
if (!e.target.files) {
return;
}
return LL.UPLOAD_DROP_TEXT();
setFile(e.target.files[0]);
await sendUpload(e.target.files[0]).catch((error: Error) => {
if (error.message === 'The user aborted a request') {
toast.warning(LL.UPLOAD() + ' ' + LL.ABORTED());
} else if (error.message === 'Network Error') {
toast.warning('Invalid file extension or incompatible bin file');
} else {
toast.error(error.message);
}
});
};
return (
<Box
{...getRootProps({
sx: {
py: 4,
px: 2,
borderWidth: 2,
borderRadius: 2,
borderStyle: 'dashed',
color: theme.palette.grey[400],
transition: 'border .24s ease-in-out',
width: '100%',
cursor: uploading ? 'default' : 'pointer',
borderColor: getBorderColor(theme, dropzoneState)
}
})}
>
<input {...getInputProps()} />
<Box flexDirection="column" display="flex" alignItems="center">
<CloudUploadIcon fontSize="large" />
<Typography variant="h6">{progressText()}</Typography>
{uploading && (
<Fragment>
<Box width="100%" p={2}>
<LinearProgress
variant="determinate"
value={
progress.total === 0 || progress.loaded === 0
? 0
: progress.loaded <= progress.total
? Math.round((progress.loaded * 100) / progress.total)
: Math.round((progress.total * 100) / progress.loaded)
}
/>
</Box>
<Button
startIcon={<CancelIcon />}
variant="outlined"
color="secondary"
onClick={onCancel}
>
{LL.CANCEL()}
</Button>
</Fragment>
)}
</Box>
</Box>
<>
<input
type="file"
ref={inputRef}
style={{ display: 'none' }}
onChange={handleFileChange}
/>
<Button
sx={{ ml: 2 }}
startIcon={<UploadIcon />}
variant="outlined"
color="secondary"
onClick={handleUploadClick}
>
{file ? LL.UPLOADING() + ` ${file.name}` : LL.UPLOAD()}
</Button>
{isUploading && (
<>
<Box width="100%" p={2}>
<LinearProgress
variant="determinate"
value={
progress.total === 0 || progress.loaded === 0
? 0
: progress.loaded <= progress.total
? Math.round((progress.loaded * 100) / progress.total)
: Math.round((progress.total * 100) / progress.loaded)
}
/>
</Box>
<Button
startIcon={<CancelIcon />}
variant="outlined"
color="secondary"
onClick={cancelUpload}
>
{LL.CANCEL()}
</Button>
</>
)}
{md5 && (
<Box mt={2}>
<Typography variant="body2">{'MD5: ' + md5}</Typography>
</Box>
)}
{restarting && <RestartMonitor />}
</>
);
};