Merge branch 'multi_plenum_drying' into staging_environment
This commit is contained in:
commit
f228e1a574
8 changed files with 1463 additions and 238 deletions
|
|
@ -19,6 +19,10 @@ export interface ButtonData {
|
|||
* The function to run when the button is clicked or toggled on when toggle is true
|
||||
*/
|
||||
function: () => void
|
||||
/**
|
||||
* whether the button is disabled or not
|
||||
*/
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
interface Props {
|
||||
|
|
@ -49,6 +53,10 @@ interface Props {
|
|||
* Numerical value for the size of the text for buttons that dont use the icon
|
||||
*/
|
||||
textSize?: number
|
||||
/**
|
||||
* When true will disable all of the buttons in the group, will be overridded by individual buttons disabled state in the button data
|
||||
*/
|
||||
disableAll?: boolean
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => {
|
||||
|
|
@ -88,7 +96,7 @@ const useStyles = makeStyles((theme: Theme) => {
|
|||
})
|
||||
|
||||
export default function ButtonGroup(props: Props){
|
||||
const { buttons, toggle, toggledButtons, multiToggle, textSize } = props
|
||||
const { buttons, toggle, toggledButtons, multiToggle, textSize, disableAll } = props
|
||||
const classes = useStyles()
|
||||
const [currentToggle, setCurrentToggle] = useState<number[]>([])
|
||||
|
||||
|
|
@ -135,6 +143,7 @@ export default function ButtonGroup(props: Props){
|
|||
<Box className={classes.container} display="flex" flexDirection="row">
|
||||
{buttons.map((b, i) => (
|
||||
<Button
|
||||
disabled={disableAll ?? b.disabled}
|
||||
key={i}
|
||||
className={checkToggled(i) ? classes.buttonToggled : classes.button}
|
||||
onClick={() => {
|
||||
|
|
|
|||
140
src/common/PromiseProgress.tsx
Normal file
140
src/common/PromiseProgress.tsx
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
import { AxiosResponse } from "axios"
|
||||
import { Box, Button, CircularProgress, DialogActions, DialogContent, DialogTitle, Typography } from "@mui/material"
|
||||
import { useEffect, useState } from "react"
|
||||
import { CheckCircle, Error, Pending } from "@mui/icons-material"
|
||||
import React from "react"
|
||||
|
||||
export interface Stage {
|
||||
title: string
|
||||
steps: Step[]
|
||||
}
|
||||
|
||||
export interface Step {
|
||||
title: string
|
||||
promise: Promise<AxiosResponse>
|
||||
onComplete?: () => void
|
||||
onError?: () => void
|
||||
}
|
||||
|
||||
interface Props {
|
||||
stages: Stage[]
|
||||
automaticStart: boolean
|
||||
failFast?: boolean
|
||||
onStart?: () => void
|
||||
onComplete?: () => void
|
||||
}
|
||||
|
||||
enum progress {
|
||||
Waiting = 1,
|
||||
InProgress = 2,
|
||||
Complete = 3,
|
||||
Failed = 4
|
||||
}
|
||||
|
||||
export function PromiseProgress(props: Props){
|
||||
const {stages, failFast, onStart, onComplete, automaticStart} = props
|
||||
const [completion, setCompletion] = useState<Map<string, progress>>(new Map())
|
||||
|
||||
const execute = () => {
|
||||
let completionMap: Map<string, progress> = new Map()
|
||||
stages.forEach((stage, i) => {
|
||||
stage.steps.forEach((_, k) => {
|
||||
completionMap.set(i + "-" + k, progress.Waiting)
|
||||
})
|
||||
})
|
||||
setCompletion(completionMap)
|
||||
|
||||
const runStages = async () => {
|
||||
let progMap = new Map(completionMap)
|
||||
for (const [i, stage] of stages.entries()) {
|
||||
// For each stage, map the steps into their own promise chains
|
||||
const stepPromises = stage.steps.map((step, k) => {
|
||||
// mark step as in progress
|
||||
progMap.set(i+"-"+k, progress.InProgress);
|
||||
setCompletion(new Map(progMap));
|
||||
return step.promise
|
||||
.then(() => {
|
||||
// mark step as completed
|
||||
progMap.set(i+"-"+k, progress.Complete);
|
||||
setCompletion(new Map(progMap));
|
||||
if (step.onComplete) step.onComplete();
|
||||
})
|
||||
.catch(err => {
|
||||
// mark step as failed
|
||||
progMap.set(i+"-"+k, progress.Failed);
|
||||
setCompletion(new Map(progMap));
|
||||
if(failFast){
|
||||
throw err; // this rejects this step promise
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// Wait for all steps in the current stage to finish
|
||||
// (they run in parallel)
|
||||
await Promise.all(stepPromises);
|
||||
}
|
||||
};
|
||||
if(onStart){
|
||||
onStart()
|
||||
}
|
||||
runStages().catch(err => {
|
||||
console.error("Execution stopped due to error:", err);
|
||||
}).finally(() => {
|
||||
if(onComplete) onComplete()
|
||||
});
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if(automaticStart){
|
||||
execute()
|
||||
}
|
||||
},[automaticStart, execute])
|
||||
|
||||
const getCompletion = (completion?: progress) => {
|
||||
switch(completion){
|
||||
case progress.InProgress:
|
||||
return <CircularProgress />
|
||||
case progress.Complete:
|
||||
return <CheckCircle />
|
||||
case progress.Failed:
|
||||
return <Error />
|
||||
default://default will run if it is waiting or there was no completion
|
||||
return <Pending />
|
||||
}
|
||||
}
|
||||
|
||||
const displayStage = (stage: Stage, number: number) => {
|
||||
return (
|
||||
<Box key={number}>
|
||||
<Typography>Stage {stage.title}</Typography>
|
||||
{stage.steps.map((step, i) => (
|
||||
<Box key={number+"-"+i} display="flex" flexDirection="row" justifyContent="space-between" margin={2} alignContent="center" alignItems="center">
|
||||
<Typography>{step.title}</Typography>
|
||||
{getCompletion(completion.get(number + "-" + i))}
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<DialogTitle>
|
||||
Progress
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
{stages.map((stage, number) => displayStage(stage, number))}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
{!automaticStart &&
|
||||
<Button onClick={() => {
|
||||
execute()
|
||||
}}>
|
||||
Start
|
||||
</Button>
|
||||
}
|
||||
</DialogActions>
|
||||
</React.Fragment>
|
||||
)
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue