added graphs to the bin details section on the new page and started working on the sensors
This commit is contained in:
parent
acdc18ce28
commit
67b251d865
13 changed files with 897 additions and 93 deletions
186
src/bin/binSummary/components/binControls.tsx
Normal file
186
src/bin/binSummary/components/binControls.tsx
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
import { LinearProgress } from "@mui/material";
|
||||
import { Bin, Component, Device, Interaction } from "models";
|
||||
import Controls, { Control } from "objects/objectInteractions/Controls";
|
||||
import NewObjectInteraction from "objects/objectInteractions/NewObjectInteraction";
|
||||
import { sameComponentID } from "pbHelpers/Component";
|
||||
import { extension } from "pbHelpers/ComponentType";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { quack } from "protobuf-ts/quack";
|
||||
import { useGlobalState } from "providers";
|
||||
import interactionsAPI, { useInteractionsAPI } from "providers/pond/interactionsAPI";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
|
||||
interface Props {
|
||||
linkedComponents: Map<string, Component>; //the component key to the component object
|
||||
componentDevices: Map<string, number>;
|
||||
devices: Device[];
|
||||
permissions: pond.Permission[]
|
||||
}
|
||||
|
||||
export default function BinControls(props: Props) {
|
||||
const {linkedComponents, componentDevices, devices, permissions} = props
|
||||
const [{as}] = useGlobalState()
|
||||
const interactionsAPI = useInteractionsAPI()
|
||||
const [controls, setControls] = useState<Control[]>([]);
|
||||
const [selectedDevice, setSelectedDevice] = useState<Device | undefined>(undefined)
|
||||
const [openNewInteraction, setOpenNewInteraction] = useState(false)
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
|
||||
const findDevice = (deviceID: number) => {
|
||||
for (let device of devices) {
|
||||
if (device.id() === deviceID) return device
|
||||
}
|
||||
}
|
||||
const findSinkComponent = (sinks: Component[], interactionSink: quack.ComponentID, sourceDevice: number) => {
|
||||
for (let component of sinks) {
|
||||
if (sameComponentID(component.location(), interactionSink) && sourceDevice === componentDevices.get(component.key())){
|
||||
return component
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const matchConditions = (interaction: Interaction, set: Control) => {
|
||||
//if the number of conditions are not the same they are different
|
||||
if (interaction.settings.conditions.length !== set.conditions.length) {
|
||||
return false;
|
||||
}
|
||||
//continue with the comparison
|
||||
let matching = true;
|
||||
interaction.settings.conditions.forEach((condition, i) => {
|
||||
if (
|
||||
condition.comparison !== set.conditions[i].comparison ||
|
||||
condition.measurementType !== set.conditions[i].measurementType ||
|
||||
condition.value !== set.conditions[i].value
|
||||
) {
|
||||
matching = false;
|
||||
}
|
||||
});
|
||||
return matching;
|
||||
};
|
||||
|
||||
const matchResult = (interaction: Interaction, set: Control) => {
|
||||
let interactionResult = interaction.settings.result
|
||||
let setResult = set.result
|
||||
let matching = true
|
||||
// if anything in the result for the interaction is different from the set make matching false
|
||||
if(interactionResult?.type !== setResult?.type ||
|
||||
interactionResult?.mode !== setResult?.mode ||
|
||||
interactionResult?.value !== setResult?.value ||
|
||||
interactionResult?.dutyCycle !== setResult?.dutyCycle
|
||||
){
|
||||
matching = false
|
||||
}
|
||||
return matching
|
||||
}
|
||||
const load = useCallback(()=>{
|
||||
if(!loading){
|
||||
setLoading(true)
|
||||
const newInteractions: Interaction[] = [];
|
||||
const interactionSourceMap = new Map<string, string>();
|
||||
const sinkOptions: Component[] = [];
|
||||
const controls: Control[] = [];
|
||||
|
||||
const run = async () => {
|
||||
// Run all component API fetches in parallel
|
||||
await Promise.all(
|
||||
[...linkedComponents].map(async ([key, comp]) => {
|
||||
const device = componentDevices.get(key);
|
||||
|
||||
if (device) {
|
||||
const resp = await interactionsAPI.listInteractionsByComponent(
|
||||
device,
|
||||
comp.location(),
|
||||
undefined,
|
||||
as
|
||||
);
|
||||
|
||||
resp.forEach(interaction => interactionSourceMap.set(interaction.key(), key));
|
||||
newInteractions.push(...resp);
|
||||
}
|
||||
|
||||
// Collect controller components
|
||||
if (extension(comp.type()).isController) {
|
||||
sinkOptions.push(comp);
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
run().then(() => {
|
||||
newInteractions.forEach(interaction => {
|
||||
if (interaction.isControl()) {
|
||||
if (!interaction.settings.sink) return //if there is no sink it cant be a control so move on to the next
|
||||
const compKey = interactionSourceMap.get(interaction.key());
|
||||
if (!compKey) return //we have to have a valid component key
|
||||
const component = linkedComponents.get(compKey);
|
||||
const deviceID = componentDevices.get(compKey);
|
||||
if (!deviceID) return //we have to know which device it is for
|
||||
const controlDevice = findDevice(deviceID)
|
||||
if (!controlDevice) return //failed to get the device from the array
|
||||
const sinkComponent = findSinkComponent(sinkOptions, interaction.settings.sink, deviceID)
|
||||
if (!sinkComponent) return //failed to get the correct sink component
|
||||
|
||||
let similarControlIndex = controls.findIndex(control =>
|
||||
matchConditions(interaction, control) &&
|
||||
matchResult(interaction, control) &&
|
||||
sameComponentID(interaction.settings.sink, control.sinkComponent.location()) && //if the sink for the interaction is the same address as the existing control
|
||||
deviceID === control.device.id() //if the device id for source component is the same as the device id in the control
|
||||
);
|
||||
|
||||
if (component && interaction.settings.result) {
|
||||
if (similarControlIndex === -1) {
|
||||
controls.push({
|
||||
conditions: interaction.settings.conditions,
|
||||
result: interaction.settings.result,
|
||||
sourceComponents: [component],
|
||||
sinkComponent: sinkComponent,
|
||||
device: controlDevice
|
||||
});
|
||||
} else {
|
||||
controls[similarControlIndex].sourceComponents.push(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
setControls(controls);
|
||||
}).catch(err => {
|
||||
console.error("Interaction fetch error:", err)
|
||||
})
|
||||
}
|
||||
},[linkedComponents, interactionsAPI, componentDevices, as])
|
||||
|
||||
useEffect(() => {
|
||||
load()
|
||||
}, [load]);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<NewObjectInteraction
|
||||
open={openNewInteraction}
|
||||
onClose={(refresh) => {
|
||||
setOpenNewInteraction(false)
|
||||
if(refresh){
|
||||
load()
|
||||
}
|
||||
}}
|
||||
linkedComponents={linkedComponents}
|
||||
componentDevices={componentDevices}
|
||||
device={selectedDevice}/>
|
||||
{loading ?
|
||||
<LinearProgress />
|
||||
:
|
||||
<Controls
|
||||
controls={controls}
|
||||
devices={devices}
|
||||
permissions={permissions}
|
||||
addNew={(device) => {
|
||||
console.log("new control")
|
||||
setSelectedDevice(device)
|
||||
setOpenNewInteraction(true)
|
||||
}}
|
||||
/>
|
||||
}
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue