added the alerts to the bin details part of the bin page, also fixed bug in the new alert dialog
This commit is contained in:
parent
f72aeb802f
commit
6ccc1ba263
6 changed files with 167 additions and 14 deletions
|
|
@ -230,7 +230,7 @@ export default function OrbitCameraControls(props: Props) {
|
|||
window.removeEventListener("mouseup", handleMouseUp);
|
||||
canvas.removeEventListener("wheel", handleWheel);
|
||||
};
|
||||
}, [camera, gl, target, clampVerticalRotation, minPhi, maxPhi]);
|
||||
}, [camera, gl, target, clampVerticalRotation, minPhi, maxPhi, initialRadius, maxRadius]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
@ -27,14 +27,14 @@ interface Props {
|
|||
}
|
||||
export default function BinSummary(props: Props){
|
||||
const {bin, devices, fans, heaters, permissions, componentDevices, componentMap, binPrefs, updateBinCallback} = props
|
||||
const [currentDevice, setCurrentDevice] = useState<Device | undefined>(undefined)
|
||||
//const [currentDevice, setCurrentDevice] = useState<Device | undefined>(undefined)
|
||||
const isMobile = useMobile()
|
||||
|
||||
useEffect(() => {
|
||||
if(devices.length > 0){
|
||||
setCurrentDevice(devices[0])
|
||||
}
|
||||
},[devices])
|
||||
// useEffect(() => {
|
||||
// if(devices.length > 0){
|
||||
// setCurrentDevice(devices[0])
|
||||
// }
|
||||
// },[devices])
|
||||
|
||||
const activity = (reading: string) => {
|
||||
//if the device hasnt checked in in 6 hours = missing 12 hours = inactive within 6 hours = live
|
||||
|
|
@ -173,7 +173,13 @@ export default function BinSummary(props: Props){
|
|||
</Grid2>
|
||||
<Grid2 size={isMobile ? 12 : 5}>
|
||||
<Card raised sx={{height: 600}}>
|
||||
<BinDetails bin={bin} updateBinCallback={updateBinCallback}/>
|
||||
<BinDetails
|
||||
bin={bin}
|
||||
updateBinCallback={updateBinCallback}
|
||||
componentDevices={componentDevices}
|
||||
devices={devices}
|
||||
linkedComponents={componentMap}
|
||||
permissions={permissions}/>
|
||||
</Card>
|
||||
</Grid2>
|
||||
<Grid2 size={12}>
|
||||
|
|
|
|||
137
src/bin/binSummary/components/binAlerts.tsx
Normal file
137
src/bin/binSummary/components/binAlerts.tsx
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
import { LinearProgress } from "@mui/material";
|
||||
import { Bin, Component, Device, Interaction } from "models";
|
||||
import Alerts, { Alert } from "objects/objectInteractions/Alerts";
|
||||
import NewObjectInteraction from "objects/objectInteractions/NewObjectInteraction";
|
||||
import { extension } from "pbHelpers/ComponentType";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { useGlobalState, useInteractionsAPI } from "providers";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
|
||||
interface Props {
|
||||
linkedComponents: Map<string, Component>; //the component key to the component object
|
||||
componentDevices: Map<string, number>;
|
||||
bin: Bin
|
||||
devices: Device[];
|
||||
permissions: pond.Permission[]
|
||||
}
|
||||
|
||||
export default function BinAlerts(props: Props){
|
||||
const {linkedComponents, componentDevices, permissions} = props
|
||||
const [{as}] = useGlobalState();
|
||||
const interactionsAPI = useInteractionsAPI();
|
||||
|
||||
//list of alerts, each alert contains a list of interactions with matching conditions
|
||||
const [alerts, setAlerts] = useState<Alert[]>([]);
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [newAlert, setNewAlert] = useState(false)
|
||||
|
||||
const matchConditions = (interaction: Interaction, set: Alert) => {
|
||||
//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 load = useCallback(()=>{
|
||||
//load the interactions for the linked components
|
||||
setLoading(true)
|
||||
const newInteractions: Interaction[] = [];
|
||||
const interactionSourceMap = new Map<string, string>();
|
||||
const sinkOptions: Component[] = [];
|
||||
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 => {
|
||||
//alert and control are not mutally exclusive, it is possible to be both if the control is sending notifications
|
||||
if (interaction.isAlert()) {
|
||||
// Find matching alert
|
||||
let similarAlertIndex = alerts.findIndex(alert =>
|
||||
matchConditions(interaction, alert)
|
||||
);
|
||||
|
||||
const compKey = interactionSourceMap.get(interaction.key());
|
||||
const component = compKey ? linkedComponents.get(compKey) : undefined;
|
||||
|
||||
if (component) {
|
||||
if (similarAlertIndex === -1) {
|
||||
alerts.push({
|
||||
conditions: interaction.settings.conditions,
|
||||
sourceComponents: [component],
|
||||
});
|
||||
} else {
|
||||
alerts[similarAlertIndex].sourceComponents.push(component);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
setAlerts(alerts);
|
||||
}).catch(err => {
|
||||
console.error("Interaction fetch error:", err)
|
||||
}).finally(() => {
|
||||
setLoading(false)
|
||||
})
|
||||
},[linkedComponents, interactionsAPI, componentDevices, as])
|
||||
|
||||
useEffect(()=>{
|
||||
load()
|
||||
},[load])
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<NewObjectInteraction
|
||||
open={newAlert}
|
||||
onClose={(refresh) => {
|
||||
setNewAlert(false)
|
||||
if(refresh){
|
||||
load()
|
||||
}
|
||||
}}
|
||||
linkedComponents={linkedComponents}
|
||||
componentDevices={componentDevices}/>
|
||||
{loading ?
|
||||
<LinearProgress />
|
||||
:
|
||||
<Alerts alerts={alerts} permissions={permissions} addNew={() => {setNewAlert(true)}}/>
|
||||
}
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
|
|
@ -2,11 +2,18 @@ import { Box, Tab, Tabs } from "@mui/material";
|
|||
import React from "react";
|
||||
import { useState } from "react";
|
||||
import BinTableView from "./binTableView";
|
||||
import { Bin } from "models";
|
||||
import { Bin, Component, Device } from "models";
|
||||
import Alerts from "objects/objectInteractions/Alerts";
|
||||
import BinAlerts from "./binAlerts";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
|
||||
interface Props {
|
||||
bin: Bin
|
||||
updateBinCallback?: (bin: Bin) => void
|
||||
linkedComponents: Map<string, Component>; //the component key to the component object
|
||||
componentDevices: Map<string, number>;
|
||||
devices: Device[];
|
||||
permissions: pond.Permission[]
|
||||
}
|
||||
|
||||
interface TabPanelProps {
|
||||
|
|
@ -30,7 +37,7 @@ function TabPanelMine(props: TabPanelProps) {
|
|||
}
|
||||
|
||||
export default function BinDetails (props: Props) {
|
||||
const {bin, updateBinCallback} = props
|
||||
const {bin, updateBinCallback, linkedComponents, componentDevices, devices, permissions} = props
|
||||
const [currentTab, setCurrentTab] = useState(0)
|
||||
|
||||
//this is where we will have the tabs abd tab panels for the table view, alerts, interactions, and analysis
|
||||
|
|
@ -45,14 +52,14 @@ export default function BinDetails (props: Props) {
|
|||
variant="fullWidth">
|
||||
<Tab label={"Table View"} value={0} />
|
||||
<Tab label={"Alerts"} value={1} />
|
||||
<Tab label={"Interactions"} value={2} />
|
||||
<Tab label={"Controls"} value={2} />
|
||||
<Tab label={"Analysis"} value={3} />
|
||||
</Tabs>
|
||||
<TabPanelMine value={currentTab} index={0}>
|
||||
<BinTableView bin={bin} updateBinCallback={updateBinCallback}/>
|
||||
</TabPanelMine>
|
||||
<TabPanelMine value={currentTab} index={1}>
|
||||
|
||||
<BinAlerts bin={bin} componentDevices={componentDevices} devices={devices} linkedComponents={linkedComponents} permissions={permissions}/>
|
||||
</TabPanelMine>
|
||||
<TabPanelMine value={currentTab} index={2}>
|
||||
|
||||
|
|
|
|||
|
|
@ -179,7 +179,6 @@ export default function NewObjectInteraction(props: Props){
|
|||
setNewAlertComponentType(quack.ComponentType.COMPONENT_TYPE_INVALID);
|
||||
setConditions([]);
|
||||
setSelectedAlertComponents([]);
|
||||
setValidComponents([])
|
||||
setValStrings(["0", "0"]);
|
||||
setNumConditions(0)
|
||||
setNodeOptions([]);
|
||||
|
|
@ -190,7 +189,6 @@ export default function NewObjectInteraction(props: Props){
|
|||
setResultType(quack.InteractionResultType.INTERACTION_RESULT_TYPE_REPORT)
|
||||
setSinkMotor(false)
|
||||
setSelectedSink("")//the key of the component to be the sink
|
||||
setSinkOptions([])
|
||||
setResultMode(0)
|
||||
setResultValue("")
|
||||
setDutyCycleEnabled(false)
|
||||
|
|
@ -215,12 +213,15 @@ export default function NewObjectInteraction(props: Props){
|
|||
|
||||
//display the components that match the type that was selected for the new alert
|
||||
const listMatchingComponents = () => {
|
||||
console.log("listing")
|
||||
let matching: Component[] = [];
|
||||
console.log(validComponents)
|
||||
validComponents.forEach(comp => {
|
||||
if (comp.type() === newAlertComponentType) {
|
||||
matching.push(comp);
|
||||
}
|
||||
});
|
||||
console.log(matching)
|
||||
return (
|
||||
<List>
|
||||
{matching.map(comp => (
|
||||
|
|
@ -1018,6 +1019,7 @@ export default function NewObjectInteraction(props: Props){
|
|||
displayEmpty
|
||||
value={newAlertComponentType}
|
||||
onChange={e => {
|
||||
console.log("type change")
|
||||
setNewAlertComponentType(e.target.value as quack.ComponentType);
|
||||
setSelectedAlertComponents([]);
|
||||
setConditions(initialConditions(e.target.value as quack.ComponentType));
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ export default function BinV2(){
|
|||
attachedDevIds.push(resp.data.componentDevices[k]);
|
||||
}
|
||||
});
|
||||
|
||||
setComponentDevices(newComponentDevices);
|
||||
|
||||
let newInteractionDevices = new Map<string, number>();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue