add loading status to block user action when doing api call; add error message when fail to do api call

This commit is contained in:
Songyi Huang 2020-09-22 22:41:59 -07:00
parent 882e0d0289
commit b6711547b0
2 changed files with 67 additions and 25 deletions

View File

@ -15,11 +15,10 @@ import Button from "@material-ui/core/Button";
import Dialog from "@material-ui/core/Dialog";
import DialogTitle from "@material-ui/core/DialogTitle";
import DialogContent from "@material-ui/core/DialogContent";
import DialogContentText from "@material-ui/core/DialogContentText";
import TextField from "@material-ui/core/TextField";
import DialogActions from "@material-ui/core/DialogActions";
import {Message, Upload} from 'element-react';
import {Message, Upload, Loading} from 'element-react';
import {apiUrl} from "../utils/config";
const drawerWidth = 250;
@ -78,6 +77,7 @@ const useStyles = makeStyles((theme) => ({
function MenuBar (props) {
const classes = useStyles();
const [uploadDialogLoading, setUploadDialogLoading] = React.useState(false);
const [open, setOpen] = React.useState({game: true, agent: true});
@ -114,9 +114,10 @@ function MenuBar (props) {
bodyFormData.append('entry', uploadForm.entry);
bodyFormData.append('game', uploadForm.game);
bodyFormData.append('model', uploadRef.current.state.fileList[0].raw);
setUploadDialogLoading(true);
axios.post(`${apiUrl}/tournament/upload_agent`, bodyFormData, {headers: {'Content-Type': 'multipart/form-data'}})
.then(res => {
setTimeout(() => {setUploadDialogLoading(false)}, 250);
Message({
message: "Successfully uploaded model",
type: "success",
@ -126,6 +127,15 @@ function MenuBar (props) {
setUploadDialogOpen(false);
setUploadForm({...uploadFormInitValue});
})
.catch(err => {
setTimeout(() => {setUploadDialogLoading(false)}, 250);
Message({
message: "Failed to upload model",
type: "error",
showClose: true,
});
console.log(err);
})
};
const history = useHistory();
@ -196,7 +206,13 @@ function MenuBar (props) {
<Button variant="contained" color="primary" onClick={openUploadDialog} className={classes.button}>
Upload Model
</Button>
<Dialog open={uploadDialogOpen} onClose={handleUploadDialogClose} aria-labelledby="form-dialog-title">
<Dialog
open={uploadDialogOpen}
onClose={handleUploadDialogClose}
aria-labelledby="form-dialog-title"
disableBackdropClick={true}
>
<Loading loading={uploadDialogLoading}>
<DialogTitle id="form-dialog-title">Upload Model</DialogTitle>
<DialogContent>
<Upload
@ -247,6 +263,7 @@ function MenuBar (props) {
Upload
</Button>
</DialogActions>
</Loading>
</Dialog>
</Drawer>
)

View File

@ -21,7 +21,7 @@ import withStyles from "@material-ui/core/styles/withStyles";
import PlayCircleOutlineIcon from '@material-ui/icons/PlayCircleOutline';
import Button from "@material-ui/core/Button";
import {useHistory} from "react-router-dom";
import {Message} from "element-react";
import {Message, Loading} from "element-react";
const gameList = [
{game: 'leduc-holdem', dispName: 'Leduc Hold\'em'},
@ -224,33 +224,48 @@ const EnhancedTableToolbar = (props) => {
const history = useHistory();
const functionalButton = () => {
const FunctionalButton = () => {
const [buttonLoading, setButtonLoading] = React.useState(false);
if (routeInfo.type === 'game'){
const handleLaunchTournament = (gameName) => {
// todo: customize eval num
// todo: add global loading when waiting for API response
axios.get(`${apiUrl}/tournament/launch?eval_num=200&name=${gameName}`)
.then(res => {
Message({
message: "Successfully launched tournament",
type: "success",
showClose: true
});
})
}
const handleLaunchTournament = (gameName) => {
// todo: customize eval num
setButtonLoading(true);
axios.get(`${apiUrl}/tournament/launch?eval_num=200&name=${gameName}`)
.then(res => {
setTimeout(() => {setButtonLoading(false)}, 250);
Message({
message: "Successfully launched tournament",
type: "success",
showClose: true
});
})
.catch(err => {
console.log(err);
Message({
message: "Failed to launch tournament",
type: "error",
showClose: true,
});
setTimeout(() => {setButtonLoading(false)}, 250);
})
}
return (
<div className={classes.button}>
<Button variant="contained" color="primary" onClick={() => handleLaunchTournament(routeInfo.name)}>
Launch Tournament
</Button>
<Loading loading={buttonLoading}>
<Button variant="contained" color="primary" onClick={() => handleLaunchTournament(routeInfo.name)}>
Launch Tournament
</Button>
</Loading>
</div>
)
}
else if (routeInfo.type ==='agent') {
const delButtonDisabled = defaultModelList.includes(routeInfo.name);
const handleDelModel = (agentName) => {
setButtonLoading(true);
axios.get(`${apiUrl}/tournament/delete_agent?name=${agentName}`)
.then(res => {
setTimeout(() => {setButtonLoading(false)}, 250);
Message({
message: "Successfully deleted model",
type: "success",
@ -259,12 +274,22 @@ const EnhancedTableToolbar = (props) => {
setReloadMenu(reloadMenu+1);
history.push(`/leaderboard?type=game&name=leduc-holdem`);
})
.catch(err => {
Message({
message: "Failed to delete model",
type: "error",
showClose: true,
});
setTimeout(() => {setButtonLoading(false)}, 250);
})
};
return (
<div className={classes.button}>
<Button variant="contained" onClick={() => handleDelModel(routeInfo.name)} color="primary" disabled={delButtonDisabled}>
Delete Model
</Button>
<Loading loading={buttonLoading}>
<Button variant="contained" onClick={() => handleDelModel(routeInfo.name)} color="primary" disabled={delButtonDisabled}>
Delete Model
</Button>
</Loading>
</div>
)
}
@ -284,7 +309,7 @@ const EnhancedTableToolbar = (props) => {
<Typography color="textPrimary">{name}</Typography>
</Breadcrumbs>
<div className={classes.button}>
{functionalButton()}
<FunctionalButton />
</div>
</Toolbar>
);