defined device change data, and started working on storage

This commit is contained in:
csawatzky 2026-07-08 10:57:23 -06:00
parent bced38d454
commit 7e6b41273b
7 changed files with 118 additions and 66 deletions

View file

@ -60,14 +60,6 @@ export default function bin3dVisualizer(props: Props){
setBinMode(bin.settings.mode) setBinMode(bin.settings.mode)
},[bin]) },[bin])
const updateBin = (newMode: pond.BinMode) => {
if(updateBinCallback){
let clone = cloneDeep(bin)
clone.settings.mode = newMode
updateBinCallback(clone)
}
};
const binModeControl = () => { const binModeControl = () => {
return ( return (
<Box> <Box>
@ -374,9 +366,6 @@ export default function bin3dVisualizer(props: Props){
componentMap={componentMap} componentMap={componentMap}
newMode={newMode} newMode={newMode}
open={openModeChange} open={openModeChange}
updateMode={(newMode) => {
updateBin(newMode)
}}
onClose={()=>{setOpenModeChange(false)}} onClose={()=>{setOpenModeChange(false)}}
/> />
<Box position={"relative"} height={600}> <Box position={"relative"} height={600}>

View file

@ -1,15 +1,23 @@
import { Box, Button, DialogActions, DialogContent, DialogTitle, Typography } from "@mui/material"; import { Box, Button, DialogActions, DialogContent, DialogTitle } from "@mui/material";
import ResponsiveDialog from "common/ResponsiveDialog"; import ResponsiveDialog from "common/ResponsiveDialog";
import { Bin, Component, Device, Interaction } from "models"; import { Bin, Component, Device, Interaction } from "models";
import { pond } from "protobuf-ts/pond"; import { pond } from "protobuf-ts/pond";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import StorageMode from "./StorageMode"; import StorageMode from "./StorageMode";
import DryingMode, { DryingBaseStepCount } from "./DryingMode"; import DryingMode from "./DryingMode";
import HydratingMode from "./HydratingMode"; import HydratingMode from "./HydratingMode";
import CooldownMode from "./CooldownMode"; import CooldownMode from "./CooldownMode";
import { PromiseProgress, Stage, Step } from "common/PromiseProgress"; import { PromiseProgress, Stage, Step } from "common/PromiseProgress";
import { useComponentAPI, useInteractionsAPI } from "providers"; import { useBinAPI, useComponentAPI, useInteractionsAPI } from "providers";
import { ComponentSet } from "bin/conditioning/pickComponentSet"; import { ComponentSet } from "bin/conditioning/pickComponentSet";
import { cloneDeep } from "lodash";
export interface DeviceChangeData {
deviceId: number
toRemove: Interaction[]
toAdd?: pond.MultiInteractionSettings
componentSets: ComponentSet[]
}
interface Props { interface Props {
newMode: pond.BinMode //used to control which dialog to open newMode: pond.BinMode //used to control which dialog to open
@ -20,16 +28,17 @@ interface Props {
devices: Device[] devices: Device[]
componentDevices: Map<string, number> componentDevices: Map<string, number>
componentMap: Map<string, Component> componentMap: Map<string, Component>
updateMode: (newMode: pond.BinMode) => void modeUpdated?: (mode: pond.BinMode) => void
} }
export default function BinModeController(props: Props) { export default function BinModeController(props: Props) {
const {open, onClose, newMode, updateMode, devices, componentDevices, componentMap, binPrefs, bin} = props const {open, onClose, newMode, devices, componentDevices, componentMap, binPrefs, bin, modeUpdated} = props
const [showProgress, setShowProgress] = useState(false) const [showProgress, setShowProgress] = useState(false)
const [deviceComponents, setDeviceComponents] = useState<Map<number, Component[]>>(new Map()) const [deviceComponents, setDeviceComponents] = useState<Map<number, Component[]>>(new Map())
const [promiseStages, setPromiseStages] = useState<Stage[]>([]) const [promiseStages, setPromiseStages] = useState<Stage[]>([])
const interactionAPI = useInteractionsAPI() const interactionAPI = useInteractionsAPI()
const componentAPI = useComponentAPI() const componentAPI = useComponentAPI()
const binAPI = useBinAPI();
//the use effects for the initial setup of what will be needed //the use effects for the initial setup of what will be needed
useEffect(()=>{ useEffect(()=>{
@ -59,55 +68,79 @@ export default function BinModeController(props: Props) {
onClose() onClose()
} }
const buildStages = (conflictingInteractions: Interaction[], deviceId: number, newInteractions: pond.MultiInteractionSettings, componentSets: ComponentSet[]) => { const buildStages = (deviceData: DeviceChangeData[]) => {
//build the stages to pass into the PromiseProgress //build the stages to pass into the PromiseProgress
//stage one is to remove conflicting interactions //stage one is to remove conflicting interactions
let stages: Stage[] = [] let stages: Stage[] = []
let stage1: Stage = { let stage1: Stage = {
title: "Remove Conflicting Interactions", title: "Remove Interactions",
steps: [] steps: []
} }
conflictingInteractions.forEach(i => {
let newStep: Step = {
title: "Removing Interaction",
promise: interactionAPI.removeInteraction(deviceId, i.key())
}
stage1.steps.push(newStep);
});
if(stage1.steps.length > 0){
stages.push(stage1)
}
//stage two is to add the new interactions
let stage2: Stage = { let stage2: Stage = {
title: "Add New Interactions", title: "Add New Interactions",
steps: [ steps: []
{
title: "Adding Interactions",
promise: interactionAPI.addMultiInteractions(deviceId, newInteractions)
} }
]
}
if(stage2.steps.length > 0){
stages.push(stage2)
}
//stage three is to update the controller components
let stage3: Stage = { let stage3: Stage = {
title: "Update Controllers", title: "Update Controllers",
steps: [] steps: []
} }
componentSets.forEach(set => { deviceData.forEach(data => {
data.toRemove.forEach(interaction => {
let newStep: Step = {
title: "Removing Interaction",
promise: () => interactionAPI.removeInteraction(data.deviceId, interaction.key())
}
stage1.steps.push(newStep);
})
let newInteractions = data.toAdd
if(newInteractions){
stage2.steps.push({
title: "Adding Interactions",
promise: () => interactionAPI.addMultiInteractions(data.deviceId, newInteractions)
})
}
data.componentSets.forEach(set => {
set.controllers.forEach(controller => { set.controllers.forEach(controller => {
let newStep: Step = { let newStep: Step = {
title: "Updating " + controller.name(), title: "Updating " + controller.name(),
promise: componentAPI.update(deviceId, controller.settings) promise: () => componentAPI.update(data.deviceId, controller.settings)
} }
stage3.steps.push(newStep) stage3.steps.push(newStep)
}) })
}) })
})
if(stage1.steps.length > 0){
stages.push(stage1)
}
if(stage2.steps.length > 0){
stages.push(stage2)
}
if(stage3.steps.length > 0){ if(stage3.steps.length > 0){
stages.push(stage3) stages.push(stage3)
} }
//stage 4 is to update the bin with the new mode
let stage4: Stage = {
title: "Update Bin With New Mode",
steps: [
{
title: "Update " + bin.name(),
promise: () => {
let clone = cloneDeep(bin.settings)
clone.mode = newMode
//this will set the bin to use the auto top nodes for cables when the bin is going into storage mode, and turn them off if the bin is being conditioned
if(newMode === pond.BinMode.BIN_MODE_STORAGE){
clone.autoGrainNode = true
}else{
clone.autoGrainNode = false
}
return binAPI.updateBin(bin.key(), clone)
},
onComplete: () => modeUpdated?.(newMode)
}
]
}
stages.push(stage4)
//set those stages to a state variable //set those stages to a state variable
setPromiseStages(stages) setPromiseStages(stages)
} }
@ -136,7 +169,7 @@ export default function BinModeController(props: Props) {
/> />
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={closeDialog}>Cancel</Button> <Button onClick={closeDialog}>Close</Button>
</DialogActions> </DialogActions>
</React.Fragment> </React.Fragment>
) )
@ -152,8 +185,8 @@ export default function BinModeController(props: Props) {
binPrefs={binPrefs} binPrefs={binPrefs}
deviceComponents={deviceComponents} deviceComponents={deviceComponents}
cancel={closeDialog} cancel={closeDialog}
confirm={(conflicting, device, newInteractions, components) => { confirm={(deviceData) => {
buildStages(conflicting, device, newInteractions, components) buildStages(deviceData)
setShowProgress(true) setShowProgress(true)
}} }}
/> />
@ -162,7 +195,7 @@ export default function BinModeController(props: Props) {
case pond.BinMode.BIN_MODE_COOLDOWN: case pond.BinMode.BIN_MODE_COOLDOWN:
return <CooldownMode /> return <CooldownMode />
default: default:
return <StorageMode /> return <StorageMode devices={devices} confirm={()=>{}}/>
} }
} }

View file

@ -18,6 +18,7 @@ import { useGlobalState, useInteractionsAPI } from "providers";
import BinConditioningInteraction from "bin/BinConditioningInteraction"; import BinConditioningInteraction from "bin/BinConditioningInteraction";
import ConditionDisplay from "./conditionDisplay"; import ConditionDisplay from "./conditionDisplay";
import React from "react"; import React from "react";
import { DeviceChangeData } from "./BinModeController";
const useStyles = makeStyles((theme: Theme) => { const useStyles = makeStyles((theme: Theme) => {
@ -33,8 +34,6 @@ interface Step {
completed?: boolean; completed?: boolean;
} }
export const DryingBaseStepCount = 3
interface Option { interface Option {
label: string; label: string;
device: Device; device: Device;
@ -47,7 +46,7 @@ interface Props {
binPrefs?: Map<string, pond.BinComponentPreferences> binPrefs?: Map<string, pond.BinComponentPreferences>
grain?: pond.Grain grain?: pond.Grain
cancel: () => void cancel: () => void
confirm: (conflictingInteractions: Interaction[], deviceId: number, newInteractions: pond.MultiInteractionSettings, componentSets: ComponentSet[]) => void confirm: (deviceData: DeviceChangeData[]) => void
} }
const steps = [{label: "Style"}, {label: "Device"}, {label: "Interaction"}] const steps = [{label: "Style"}, {label: "Device"}, {label: "Interaction"}]
@ -419,6 +418,7 @@ export default function DryingMode(props: Props){
} }
const deviceStep = () => { const deviceStep = () => {
return ( return (
<Box> <Box>
<Typography>Devices</Typography> <Typography>Devices</Typography>
@ -497,7 +497,7 @@ export default function DryingMode(props: Props){
{/* next - goes to the next step, hidden on the last step */} {/* next - goes to the next step, hidden on the last step */}
{currentStep !== steps.length - 1 && <Button onClick={() => {setCurrentStep(currentStep+1)}}>Next</Button>} {currentStep !== steps.length - 1 && <Button onClick={() => {setCurrentStep(currentStep+1)}}>Next</Button>}
{/* confirm - tells the parent to build the stages using the data, only visible on the last step */} {/* confirm - tells the parent to build the stages using the data, only visible on the last step */}
{currentStep === steps.length - 1 && interactionsToAdd && selectedDevice && <Button onClick={() => {confirm(conflictingInteractions, selectedDevice.id(), interactionsToAdd, componentSets)}}>Confirm</Button>} {currentStep === steps.length - 1 && interactionsToAdd && selectedDevice && <Button onClick={() => {confirm([{ toRemove: conflictingInteractions, deviceId: selectedDevice.id(), toAdd: interactionsToAdd, componentSets}])}}>Confirm</Button>}
</React.Fragment> </React.Fragment>
) )
} }

View file

@ -1,9 +1,38 @@
import { Box } from "@mui/material"; import { Box, DialogContent, DialogTitle, DialogActions } from "@mui/material";
import { ComponentSet } from "bin/conditioning/pickComponentSet";
import { Device, Interaction } from "models";
import { pond } from "protobuf-ts/pond";
import React from "react";
interface InteractionToRemove {
deviceID: number,
//interactions:
}
interface Props {
// the devices connected to the bin
devices: Device[]
confirm: (conflictingInteractions: Interaction[], deviceId: number, newInteractions: pond.MultiInteractionSettings, componentSets: ComponentSet[]) => void
}
/**
* when a bin goes into storage mode then the auto top node needs to be set, should be handled in the controller actually
* interactions with connected controllers as sink should be deleted, and controllers should be set to off
* @returns
*/
export default function StorageMode(props: Props){
//load the interactions for all of the bins connected devices
//
export default function StorageMode(){
return ( return (
<Box> <React.Fragment>
<DialogTitle>Storage Mode</DialogTitle>
</Box> <DialogContent>
{/* could have the explanation of what changing to storage mode does here */}
</DialogContent>
<DialogActions></DialogActions>
</React.Fragment>
) )
} }

View file

@ -439,7 +439,7 @@ if (!selectedDevice) return;
conflictingSetInteractions.forEach(i => { conflictingSetInteractions.forEach(i => {
let newStep: PromiseStep = { let newStep: PromiseStep = {
title: "Removing Interaction", title: "Removing Interaction",
promise: interactionAPI.removeInteraction(selectedDevice.id(), i.key(), as) promise: () => interactionAPI.removeInteraction(selectedDevice.id(), i.key(), as)
} }
stage1.steps.push(newStep); stage1.steps.push(newStep);
}); });
@ -452,7 +452,7 @@ if (!selectedDevice) return;
steps: [ steps: [
{ {
title: "Adding Interactions", title: "Adding Interactions",
promise: interactionAPI.addMultiInteractions(selectedDevice.id(), interactionsToAdd) promise: () => interactionAPI.addMultiInteractions(selectedDevice.id(), interactionsToAdd)
} }
] ]
} }
@ -469,7 +469,7 @@ if (!selectedDevice) return;
set.controllers.forEach(controller => { set.controllers.forEach(controller => {
let newStep: PromiseStep = { let newStep: PromiseStep = {
title: "Updating " + controller.name(), title: "Updating " + controller.name(),
promise: componentAPI.update(selectedDevice.id(), controller.settings) promise: () => componentAPI.update(selectedDevice.id(), controller.settings)
} }
stage3.steps.push(newStep) stage3.steps.push(newStep)
}) })

View file

@ -11,7 +11,7 @@ export interface Stage {
export interface Step { export interface Step {
title: string title: string
promise: Promise<AxiosResponse> promise: () => Promise<AxiosResponse>
onComplete?: () => void onComplete?: () => void
onError?: () => void onError?: () => void
} }
@ -52,7 +52,7 @@ export function PromiseProgress(props: Props){
// mark step as in progress // mark step as in progress
progMap.set(i+"-"+k, progress.InProgress); progMap.set(i+"-"+k, progress.InProgress);
setCompletion(new Map(progMap)); setCompletion(new Map(progMap));
return step.promise return step.promise()
.then(() => { .then(() => {
// mark step as completed // mark step as completed
progMap.set(i+"-"+k, progress.Complete); progMap.set(i+"-"+k, progress.Complete);

View file

@ -417,7 +417,8 @@ export default function ComponentProvider(props: PropsWithChildren<Props>) {
"&end=" + "&end=" +
end + end +
(keys ? "&keys=" + keys : "&keys=" + [deviceId.toString()]) + (keys ? "&keys=" + keys : "&keys=" + [deviceId.toString()]) +
(types ? "&types=" + types : "&types=" + ["device"]) (types ? "&types=" + types : "&types=" + ["device"]) +
(as ? "&as=" + as : "")
) )
return new Promise<AxiosResponse<pond.ListComponentHistoryBetweenResponse>>((resolve,reject) => { return new Promise<AxiosResponse<pond.ListComponentHistoryBetweenResponse>>((resolve,reject) => {
get<pond.ListComponentHistoryBetweenResponse>(url).then(resp => { get<pond.ListComponentHistoryBetweenResponse>(url).then(resp => {