Merge branch 'multi_plenum_drying' into staging_environment

This commit is contained in:
csawatzky 2025-11-20 16:03:44 -06:00
commit f228e1a574
8 changed files with 1463 additions and 238 deletions

View file

@ -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={() => {

View 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>
)
}