308 lines
10 KiB
TypeScript
308 lines
10 KiB
TypeScript
import {
|
|
Accordion,
|
|
AccordionDetails,
|
|
AccordionSummary,
|
|
Button,
|
|
DialogActions,
|
|
DialogContent,
|
|
DialogTitle,
|
|
Grid2 as Grid,
|
|
List,
|
|
ListItem,
|
|
MenuItem,
|
|
TextField
|
|
} from "@mui/material";
|
|
import { ExpandMore } from "@mui/icons-material";
|
|
import { Component } from "models";
|
|
import { pond, quack } from "protobuf-ts/pond";
|
|
import React, { useCallback, useState, useEffect } from "react";
|
|
import ResponsiveDialog from "./ResponsiveDialog";
|
|
|
|
interface Props {
|
|
open: boolean;
|
|
existingMutation?: pond.LinearMutation;
|
|
componentsByDevice: Map<string, Component[]>; //string being device id and component array of that devices components
|
|
onClose: () => void;
|
|
onSubmit: (mutation: pond.LinearMutation) => void;
|
|
}
|
|
|
|
export default function LinearMutationBuilder(props: Props) {
|
|
const { open, onClose, componentsByDevice, onSubmit, existingMutation } = props;
|
|
const [coefficientSets, setCoefficientSets] = useState<pond.ComponentCoefficients[]>([]);
|
|
const [devOptions, setDevOptions] = useState<string[]>([]);
|
|
const [compOptions, setCompOptions] = useState<Component[][]>([]);
|
|
const [selectedDevices, setSelectedDevices] = useState<string[]>([]);
|
|
const [selectedComponents, setSelectedComponents] = useState<string[]>([]);
|
|
const [selectedMutation, setSelectedMutation] = useState(pond.Mutator.MUTATOR_NONE);
|
|
const [mutationConstant, setMutationConstant] = useState(0);
|
|
const [mutationName, setMutationName] = useState("");
|
|
|
|
useEffect(() => {
|
|
setDevOptions(Array.from(componentsByDevice.keys()));
|
|
setMutationName("");
|
|
setSelectedMutation(pond.Mutator.MUTATOR_NONE);
|
|
setCoefficientSets([]);
|
|
setMutationConstant(0);
|
|
setSelectedComponents([]);
|
|
setSelectedDevices([]);
|
|
setCompOptions([]);
|
|
if (existingMutation) {
|
|
setMutationName(existingMutation.mutationName);
|
|
setSelectedMutation(existingMutation.mutation);
|
|
setCoefficientSets(existingMutation.componentCoefficients);
|
|
setMutationConstant(existingMutation.constant);
|
|
let co: Component[][] = [];
|
|
let sc: string[] = [];
|
|
let sd: string[] = [];
|
|
existingMutation.componentCoefficients.forEach(compCo => {
|
|
let splitString = compCo.componentKey.split(":", 2);
|
|
if (splitString.length > 1) {
|
|
sd.push(splitString[0]);
|
|
sc.push(splitString[1]);
|
|
let c = componentsByDevice.get(splitString[0]);
|
|
if (c) {
|
|
co.push(c);
|
|
}
|
|
}
|
|
});
|
|
setSelectedComponents(sc);
|
|
setSelectedDevices(sd);
|
|
setCompOptions(co);
|
|
}
|
|
}, [componentsByDevice, existingMutation]);
|
|
|
|
const addNewSet = () => {
|
|
let cs = coefficientSets;
|
|
let sd = selectedDevices;
|
|
let co = compOptions;
|
|
let sc = selectedComponents;
|
|
|
|
cs.push(pond.ComponentCoefficients.create());
|
|
sd.push("");
|
|
co.push([]);
|
|
sc.push("");
|
|
|
|
setCoefficientSets([...cs]);
|
|
setSelectedDevices([...sd]);
|
|
setCompOptions([...co]);
|
|
setSelectedComponents([...sc]);
|
|
};
|
|
|
|
const setOptionsFor = (pos: number, dev: string) => {
|
|
let co = compOptions;
|
|
let components = componentsByDevice.get(dev);
|
|
if (components) {
|
|
co[pos] = components;
|
|
}
|
|
setCompOptions([...co]);
|
|
};
|
|
|
|
const nodeCoefficientDisplay = (
|
|
deviceID: string,
|
|
componentKey: string,
|
|
set: pond.ComponentCoefficients
|
|
) => {
|
|
set.componentKey = deviceID + ":" + componentKey; //note: changing the set that is passed in is changing the state variable
|
|
let componentList = componentsByDevice.get(deviceID);
|
|
let component: Component = Component.create();
|
|
if (componentList) {
|
|
componentList.forEach(comp => {
|
|
if (comp.key() === componentKey) {
|
|
component = comp;
|
|
}
|
|
});
|
|
}
|
|
let nodeList: JSX.Element[] = [];
|
|
component.lastMeasurement.forEach((um, k) => {
|
|
if (um.values[0]) {
|
|
if (set.measurementCoefficients[k] === undefined) {
|
|
set.measurementCoefficients[k] = pond.MeasurementCoefficients.create({
|
|
coefficients: [],
|
|
measurementType: um.type
|
|
});
|
|
}
|
|
for (let i = 0; i < um.values[0].values.length; i++) {
|
|
//default to 0 if it isn't set
|
|
if (!set.measurementCoefficients[k].coefficients[i]) {
|
|
set.measurementCoefficients[k].coefficients[i] = 0;
|
|
}
|
|
nodeList.push(
|
|
<ListItem key={componentKey + "node" + i + um.type}>
|
|
<Grid container direction="row" alignContent="center" alignItems="center">
|
|
<Grid size={{ xs: 12 }}>
|
|
Node {i + 1} ({quack.MeasurementType[um.type]})
|
|
</Grid>
|
|
<Grid size={{ xs: 12 }}>
|
|
<TextField
|
|
fullWidth
|
|
value={set.measurementCoefficients[k].coefficients[i]}
|
|
type="number"
|
|
onChange={e => {
|
|
set.measurementCoefficients[k].coefficients[i] = +e.target.value;
|
|
setCoefficientSets([...coefficientSets]);
|
|
}}
|
|
/>
|
|
</Grid>
|
|
</Grid>
|
|
</ListItem>
|
|
);
|
|
}
|
|
}
|
|
});
|
|
|
|
return <List>{nodeList}</List>;
|
|
};
|
|
|
|
const displaySets = useCallback(() => {
|
|
let setDisplay: JSX.Element[] = [];
|
|
coefficientSets.forEach((set, i) => {
|
|
setDisplay.push(
|
|
<ListItem key={i} style={{ width: 450 }}>
|
|
<Grid container direction="column">
|
|
<Grid
|
|
container
|
|
direction="row"
|
|
alignContent="center"
|
|
alignItems="center"
|
|
justifyContent="space-between">
|
|
<Grid size={{ xs: 5 }}>
|
|
<TextField
|
|
fullWidth
|
|
label={"Device"}
|
|
select
|
|
value={selectedDevices[i]}
|
|
onChange={event => {
|
|
let sd = selectedDevices;
|
|
sd[i] = event.target.value as string;
|
|
setSelectedDevices([...sd]);
|
|
setOptionsFor(i, event.target.value as string);
|
|
}}>
|
|
{devOptions.map(dev => (
|
|
<MenuItem key={dev} value={dev}>
|
|
{dev}
|
|
</MenuItem>
|
|
))}
|
|
</TextField>
|
|
</Grid>
|
|
<Grid size={{ xs: 5 }}>
|
|
<TextField
|
|
fullWidth
|
|
label={"Component"}
|
|
select
|
|
value={selectedComponents[i]}
|
|
onChange={event => {
|
|
let sc = selectedComponents;
|
|
sc[i] = event.target.value as string;
|
|
setSelectedComponents([...sc]);
|
|
set.measurementCoefficients = [];
|
|
}}>
|
|
{compOptions[i] &&
|
|
compOptions[i].map(comp => (
|
|
<MenuItem key={comp.key()} value={comp.key()}>
|
|
{comp.name()}
|
|
</MenuItem>
|
|
))}
|
|
</TextField>
|
|
</Grid>
|
|
</Grid>
|
|
{selectedComponents[i] !== "" && (
|
|
<Grid>
|
|
<Accordion>
|
|
<AccordionSummary expandIcon={<ExpandMore />}>Node Coefficients</AccordionSummary>
|
|
<AccordionDetails>
|
|
{nodeCoefficientDisplay(selectedDevices[i], selectedComponents[i], set)}
|
|
</AccordionDetails>
|
|
</Accordion>
|
|
</Grid>
|
|
)}
|
|
</Grid>
|
|
</ListItem>
|
|
);
|
|
});
|
|
return <List>{setDisplay}</List>;
|
|
}, [coefficientSets, selectedDevices, compOptions, devOptions, selectedComponents]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
|
|
return (
|
|
<ResponsiveDialog open={open} onClose={() => onClose()}>
|
|
<DialogTitle>Build New Mutation</DialogTitle>
|
|
<DialogContent>
|
|
<TextField
|
|
style={{ marginBottom: 10 }}
|
|
value={mutationName}
|
|
fullWidth
|
|
label={"Mutation Name"}
|
|
onChange={e => {
|
|
setMutationName(e.target.value as string);
|
|
}}
|
|
/>
|
|
<TextField
|
|
style={{ marginBottom: 10 }}
|
|
value={selectedMutation}
|
|
fullWidth
|
|
select
|
|
label={"Mutation Type"}
|
|
onChange={e => {
|
|
setSelectedMutation(+e.target.value);
|
|
}}>
|
|
<MenuItem key={pond.Mutator.MUTATOR_NONE} value={pond.Mutator.MUTATOR_NONE}>
|
|
Select Type of Calculated Measurement
|
|
</MenuItem>
|
|
<MenuItem key={pond.Mutator.MUTATOR_FUEL_LEVEL} value={pond.Mutator.MUTATOR_FUEL_LEVEL}>
|
|
Fuel Level
|
|
</MenuItem>
|
|
</TextField>
|
|
<TextField
|
|
style={{ marginBottom: 10 }}
|
|
value={mutationConstant}
|
|
fullWidth
|
|
type="number"
|
|
label={"Mutation Constant"}
|
|
onChange={e => {
|
|
setMutationConstant(+e.target.value);
|
|
}}
|
|
/>
|
|
{displaySets()}
|
|
<Button variant="contained" color="primary" onClick={addNewSet}>
|
|
Add Component
|
|
</Button>
|
|
</DialogContent>
|
|
<DialogActions>
|
|
{existingMutation ? (
|
|
<React.Fragment>
|
|
<Button
|
|
color="primary"
|
|
onClick={() => {
|
|
existingMutation.mutationName = mutationName;
|
|
existingMutation.constant = mutationConstant;
|
|
existingMutation.mutation = selectedMutation;
|
|
existingMutation.componentCoefficients = coefficientSets;
|
|
onClose();
|
|
}}>
|
|
Finish
|
|
</Button>
|
|
</React.Fragment>
|
|
) : (
|
|
<React.Fragment>
|
|
<Button color="primary" onClick={onClose}>
|
|
Close
|
|
</Button>
|
|
<Button
|
|
color="primary"
|
|
disabled={selectedMutation === pond.Mutator.MUTATOR_NONE}
|
|
onClick={() => {
|
|
let newMutation = pond.LinearMutation.create();
|
|
newMutation.mutation = selectedMutation;
|
|
newMutation.componentCoefficients = coefficientSets;
|
|
newMutation.constant = mutationConstant;
|
|
newMutation.mutationName = mutationName;
|
|
onSubmit(newMutation);
|
|
onClose();
|
|
}}>
|
|
Add Mutation
|
|
</Button>
|
|
</React.Fragment>
|
|
)}
|
|
</DialogActions>
|
|
</ResponsiveDialog>
|
|
);
|
|
}
|