MUI update
This commit is contained in:
194
frontend/src/Home.tsx
Normal file
194
frontend/src/Home.tsx
Normal file
@@ -0,0 +1,194 @@
|
||||
import { Backdrop, Button, CircularProgress, Container, Grid, Paper, Snackbar, TextField, } from "@mui/material";
|
||||
import React, { Fragment, useEffect, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { Socket } from "socket.io-client";
|
||||
import { StackableResult } from "./components/StackableResult";
|
||||
import { connected, disconnected, downloading, finished } from "./features/status/statusSlice";
|
||||
import { IDLInfo, IDLInfoBase, IMessage } from "./interfaces";
|
||||
import { RootState } from "./stores/store";
|
||||
import { updateInStateMap, } from "./utils";
|
||||
|
||||
type Props = {
|
||||
socket: Socket
|
||||
}
|
||||
|
||||
export default function Home({ socket }: Props) {
|
||||
// redux state
|
||||
const settings = useSelector((state: RootState) => state.settings)
|
||||
const status = useSelector((state: RootState) => state.status)
|
||||
const dispatch = useDispatch()
|
||||
|
||||
// ephemeral state
|
||||
const [progressMap, setProgressMap] = useState(new Map<number, number>());
|
||||
const [messageMap, setMessageMap] = useState(new Map<number, IMessage>());
|
||||
const [downloadInfoMap, setDownloadInfoMap] = useState(new Map<number, IDLInfoBase>());
|
||||
|
||||
const [url, setUrl] = useState('');
|
||||
const [showBackdrop, setShowBackdrop] = useState(false);
|
||||
|
||||
/* -------------------- Effects -------------------- */
|
||||
/* WebSocket connect event handler*/
|
||||
useEffect(() => {
|
||||
socket.on('connect', () => {
|
||||
dispatch(connected());
|
||||
socket.emit('fetch-jobs')
|
||||
socket.emit('disk-space')
|
||||
socket.emit('retrieve-jobs');
|
||||
})
|
||||
return () => {
|
||||
socket.disconnect()
|
||||
}
|
||||
}, [])
|
||||
|
||||
|
||||
/* Ask server for pending jobs / background jobs */
|
||||
useEffect(() => {
|
||||
socket.on('pending-jobs', (count: number) => {
|
||||
count === 0 ? setShowBackdrop(false) : setShowBackdrop(true)
|
||||
})
|
||||
}, [])
|
||||
|
||||
/* Handle download information sent by server */
|
||||
useEffect(() => {
|
||||
socket.on('info', (data: IDLInfo) => {
|
||||
setShowBackdrop(false)
|
||||
dispatch(downloading())
|
||||
updateInStateMap(data.pid, data.info, downloadInfoMap, setDownloadInfoMap);
|
||||
})
|
||||
}, [])
|
||||
|
||||
/* Handle per-download progress */
|
||||
useEffect(() => {
|
||||
socket.on('progress', (data: IMessage) => {
|
||||
if (showBackdrop) {
|
||||
setShowBackdrop(false)
|
||||
}
|
||||
if (!status.downloading) {
|
||||
dispatch(downloading())
|
||||
}
|
||||
if (data.status === 'Done!' || data.status === 'Aborted') {
|
||||
updateInStateMap(data.pid, 'Done!', messageMap, setMessageMap);
|
||||
updateInStateMap(data.pid, 0, progressMap, setProgressMap);
|
||||
socket.emit('disk-space')
|
||||
dispatch(finished())
|
||||
return;
|
||||
}
|
||||
updateInStateMap(data.pid, data, messageMap, setMessageMap);
|
||||
if (data.progress) {
|
||||
updateInStateMap(data.pid, Math.ceil(Number(data.progress.replace('%', ''))), progressMap, setProgressMap)
|
||||
}
|
||||
})
|
||||
}, [])
|
||||
|
||||
/* -------------------- component functions -------------------- */
|
||||
|
||||
/**
|
||||
* Retrive url from input, cli-arguments from checkboxes and emits via WebSocket
|
||||
*/
|
||||
const sendUrl = () => {
|
||||
socket.emit('send-url', {
|
||||
url: url,
|
||||
params: settings.cliArgs.toString(),
|
||||
})
|
||||
setUrl('')
|
||||
setTimeout(() => {
|
||||
const input = document.getElementById('urlInput') as HTMLInputElement;
|
||||
input.value = '';
|
||||
setShowBackdrop(true)
|
||||
}, 250);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the url state whenever the input value changes
|
||||
* @param e Input change event
|
||||
*/
|
||||
const handleUrlChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setUrl(e.target.value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Abort a specific download if id's provided, other wise abort all running ones.
|
||||
* @param id The download id / pid
|
||||
* @returns void
|
||||
*/
|
||||
const abort = (id?: number) => {
|
||||
if (id) {
|
||||
updateInStateMap(id, null, downloadInfoMap, setDownloadInfoMap, true)
|
||||
socket.emit('abort', { pid: id })
|
||||
return
|
||||
}
|
||||
socket.emit('abort-all')
|
||||
}
|
||||
|
||||
return (
|
||||
<Container maxWidth="lg" sx={{ mt: 4, mb: 4 }}>
|
||||
<Backdrop
|
||||
sx={{ color: '#fff', zIndex: (theme) => theme.zIndex.drawer + 1 }}
|
||||
open={showBackdrop}
|
||||
>
|
||||
<CircularProgress color="primary" />
|
||||
</Backdrop>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<Paper
|
||||
sx={{
|
||||
p: 2,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
<TextField
|
||||
id="urlInput"
|
||||
label={settings.i18n.t('urlInput')}
|
||||
variant="outlined"
|
||||
onChange={handleUrlChange}
|
||||
/>
|
||||
<Grid container spacing={1} pt={2}>
|
||||
<Grid item>
|
||||
<Button variant="contained" onClick={() => sendUrl()} disabled={false}>{settings.i18n.t('startButton')}</Button>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Button variant="contained" onClick={() => abort()}>{settings.i18n.t('abortAllButton')}</Button>
|
||||
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Paper>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container spacing={{ xs: 2, md: 2 }} columns={{ xs: 4, sm: 8, md: 12 }} pt={2}>
|
||||
{ /*Super big brain flatMap moment*/
|
||||
Array
|
||||
.from(messageMap)
|
||||
.filter(flattened => [...flattened][0])
|
||||
.filter(flattened => [...flattened][1].toString() !== 'Done!')
|
||||
.flatMap(message => (
|
||||
<Grid item xs={4} sm={8} md={6} key={message[0]}>
|
||||
{
|
||||
/*
|
||||
Message[0] => key, the pid which is shared with the progress and download Maps
|
||||
Message[1] => value, the actual formatted message sent from server
|
||||
*/
|
||||
}
|
||||
<Fragment>
|
||||
<StackableResult
|
||||
formattedLog={message[1]}
|
||||
title={downloadInfoMap.get(message[0])?.title}
|
||||
thumbnail={downloadInfoMap.get(message[0])?.thumbnail}
|
||||
resolution={downloadInfoMap.get(message[0])?.resolution}
|
||||
progress={progressMap.get(message[0])}
|
||||
stopCallback={() => abort(message[0])}
|
||||
/>
|
||||
</Fragment>
|
||||
</Grid>
|
||||
))
|
||||
}
|
||||
</Grid>
|
||||
<Snackbar
|
||||
open={status.connected}
|
||||
autoHideDuration={1500}
|
||||
message="Connected"
|
||||
onClose={() => dispatch(disconnected())}
|
||||
/>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user