getting the new object interaction dialog filtering the components properly regarding devices being passed in, finished the display part for alert and notification
This commit is contained in:
parent
3cdddb928f
commit
ce7c90f384
6 changed files with 314 additions and 101 deletions
|
|
@ -1,10 +1,11 @@
|
||||||
import { ExpandMore } from "@mui/icons-material";
|
import { Add, ExpandMore } from "@mui/icons-material";
|
||||||
import { Accordion, AccordionDetails, AccordionSummary, Box, Grid2, List, ListItem, ListSubheader, Typography } from "@mui/material";
|
import { Accordion, AccordionDetails, AccordionSummary, Box, Grid2, IconButton, List, ListItem, ListSubheader, Typography } from "@mui/material";
|
||||||
import { Component } from "models";
|
import { Component } from "models";
|
||||||
import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
|
import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
|
||||||
import { pond, quack } from "protobuf-ts/pond";
|
import { pond, quack } from "protobuf-ts/pond";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import NewObjectInteraction from "./NewObjectInteraction";
|
import NewObjectInteraction from "./NewObjectInteraction";
|
||||||
|
import { Option } from "common/SearchSelect";
|
||||||
|
|
||||||
export interface Alert {
|
export interface Alert {
|
||||||
conditions: pond.InteractionCondition[];
|
conditions: pond.InteractionCondition[];
|
||||||
|
|
@ -13,11 +14,12 @@ export interface Alert {
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
alerts: Alert[]
|
alerts: Alert[]
|
||||||
|
addNew?: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Alerts(props: Props){
|
export default function Alerts(props: Props){
|
||||||
const {alerts} = props
|
const {alerts, addNew} = props
|
||||||
const [openNewAlert, setOpenNewAlert] = useState(false)
|
// const [openNewAlert, setOpenNewAlert] = useState(false)
|
||||||
|
|
||||||
const readableCondition = (condition: pond.InteractionCondition) => {
|
const readableCondition = (condition: pond.InteractionCondition) => {
|
||||||
let describer = describeMeasurement(condition.measurementType);
|
let describer = describeMeasurement(condition.measurementType);
|
||||||
|
|
@ -62,9 +64,19 @@ export default function Alerts(props: Props){
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<NewObjectInteraction open={openNewAlert} onClose={()=>{}}/>
|
{/* <NewObjectInteraction open={openNewAlert} onClose={(refresh)=>{
|
||||||
|
setOpenNewAlert(false)
|
||||||
|
if(refresh && refreshCallback) refreshCallback()
|
||||||
|
}} typeOptions={typeOptions} linkedComponents={linkedComponents}/> */}
|
||||||
<List style={{ margin: 5 }}>
|
<List style={{ margin: 5 }}>
|
||||||
<ListSubheader>Alerts</ListSubheader>
|
<ListSubheader sx={{paddingY: 1, display: "flex", justifyContent: "space-between", alignItems: "center"}}>
|
||||||
|
<Typography>
|
||||||
|
Alerts
|
||||||
|
</Typography>
|
||||||
|
{addNew &&
|
||||||
|
<IconButton onClick={()=>{addNew()}} color="primary"><Add /></IconButton>
|
||||||
|
}
|
||||||
|
</ListSubheader>
|
||||||
{alerts.map((alert, i) => (
|
{alerts.map((alert, i) => (
|
||||||
<ListItem key={i}>{alertAccordion(alert)}</ListItem>
|
<ListItem key={i}>{alertAccordion(alert)}</ListItem>
|
||||||
))}
|
))}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { Accordion, AccordionDetails, AccordionSummary, List, ListItem, ListSubheader } from "@mui/material";
|
import { Add } from "@mui/icons-material";
|
||||||
|
import { Accordion, AccordionDetails, AccordionSummary, Divider, IconButton, List, ListItem, ListSubheader, Menu, MenuItem, Typography } from "@mui/material";
|
||||||
import { Component, Device } from "models";
|
import { Component, Device } 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";
|
||||||
|
|
@ -12,17 +13,20 @@ export interface Control {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
devices: Device[]
|
||||||
controls: Control[]
|
controls: Control[]
|
||||||
|
addNew?: (deviceID: number) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Controls(props: Props){
|
export default function Controls(props: Props){
|
||||||
const { controls } = props
|
const { devices, controls, addNew } = props
|
||||||
const [deviceControls, setDeviceControls] = useState<Map<number, Control[]>>(new Map())
|
const [deviceControls, setDeviceControls] = useState<Map<number, Control[]>>(new Map())
|
||||||
const [deviceNameMap, setDeviceNameMap] = useState<Map<number, string>>(new Map())
|
const [openDeviceMenu, setOpenDeviceMenu] = useState(false)
|
||||||
|
const [anchor, setAnchor] = useState<null | HTMLElement>(null)
|
||||||
|
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
let map: Map<number, Control[]> = new Map()
|
let map: Map<number, Control[]> = new Map()
|
||||||
let nameMap: Map<number, string> = new Map()
|
|
||||||
controls.forEach(control => {
|
controls.forEach(control => {
|
||||||
let mappedControls = map.get(control.device.id())
|
let mappedControls = map.get(control.device.id())
|
||||||
if(mappedControls){
|
if(mappedControls){
|
||||||
|
|
@ -30,30 +34,72 @@ export default function Controls(props: Props){
|
||||||
}else{
|
}else{
|
||||||
map.set(control.device.id(), [control])
|
map.set(control.device.id(), [control])
|
||||||
}
|
}
|
||||||
if(!nameMap.get(control.device.id())){
|
|
||||||
nameMap.set(control.device.id(), control.device.name())
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
setDeviceControls(map)
|
setDeviceControls(map)
|
||||||
setDeviceNameMap(nameMap)
|
|
||||||
},[controls])
|
},[controls])
|
||||||
|
|
||||||
const controlAccordion = (control: Control) => {
|
const controlAccordion = (control: Control) => {
|
||||||
return (
|
return (
|
||||||
<Accordion>
|
<Accordion>
|
||||||
<AccordionSummary>{control.device.name()}</AccordionSummary>
|
<AccordionSummary>Show what the control does</AccordionSummary>
|
||||||
<AccordionDetails></AccordionDetails>
|
<AccordionDetails>show the components that are doing it</AccordionDetails>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const deviceMenu = () => {
|
||||||
|
return (
|
||||||
|
<Menu
|
||||||
|
open={openDeviceMenu}
|
||||||
|
anchorEl={anchor}
|
||||||
|
onClose={() => {
|
||||||
|
setAnchor(null)
|
||||||
|
setOpenDeviceMenu(false)
|
||||||
|
}}>
|
||||||
|
{devices.map(dev => (
|
||||||
|
<MenuItem
|
||||||
|
key={dev.id()}
|
||||||
|
onClick={() => {
|
||||||
|
setAnchor(null)
|
||||||
|
setOpenDeviceMenu(false)
|
||||||
|
if (addNew) addNew(dev.id())
|
||||||
|
|
||||||
|
}}>
|
||||||
|
{dev.name()}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Menu>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
|
{deviceMenu()}
|
||||||
<List style={{ margin: 5 }}>
|
<List style={{ margin: 5 }}>
|
||||||
<ListSubheader>Controls</ListSubheader>
|
<ListSubheader sx={{paddingY: 1, display: "flex", justifyContent: "space-between", alignItems: "center"}}>
|
||||||
{controls.map((control, i) => (
|
<Typography>
|
||||||
|
Alerts
|
||||||
|
</Typography>
|
||||||
|
<IconButton
|
||||||
|
onClick={(e)=>{
|
||||||
|
setOpenDeviceMenu(true)
|
||||||
|
setAnchor(e.currentTarget)
|
||||||
|
}}
|
||||||
|
color="primary">
|
||||||
|
<Add />
|
||||||
|
</IconButton>
|
||||||
|
</ListSubheader>
|
||||||
|
{devices.map(device => (
|
||||||
|
<React.Fragment key={device.id()}>
|
||||||
|
<Typography sx={{paddingY: 1, paddingX: 2}}>{device.name()}</Typography>
|
||||||
|
<Divider />
|
||||||
|
{deviceControls.get(device.id()) ? deviceControls.get(device.id())?.map((control, i) => (
|
||||||
<ListItem key={i}>{controlAccordion(control)}</ListItem>
|
<ListItem key={i}>{controlAccordion(control)}</ListItem>
|
||||||
|
))
|
||||||
|
:
|
||||||
|
<Typography sx={{paddingY: 1, paddingX: 2}}>No Control Interactions For Device</Typography>
|
||||||
|
}
|
||||||
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
</List>
|
</List>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import { Button, DialogActions, DialogContent, DialogTitle, MenuItem, Select } from "@mui/material";
|
import { Button, Checkbox, DialogActions, DialogContent, DialogTitle, List, ListItem, ListItemIcon, ListItemText, MenuItem, Select } from "@mui/material";
|
||||||
import ResponsiveDialog from "common/ResponsiveDialog";
|
import ResponsiveDialog from "common/ResponsiveDialog";
|
||||||
import { getMeasurements } from "pbHelpers/ComponentType";
|
import { Option } from "common/SearchSelect";
|
||||||
|
import { Component } from "models";
|
||||||
|
import { extension, getMeasurements } from "pbHelpers/ComponentType";
|
||||||
import { Measurement, Operator } from "pbHelpers/Enums";
|
import { Measurement, Operator } from "pbHelpers/Enums";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { quack } from "protobuf-ts/quack";
|
import { quack } from "protobuf-ts/quack";
|
||||||
|
|
@ -9,19 +11,58 @@ import { useEffect, useState } from "react";
|
||||||
interface Props {
|
interface Props {
|
||||||
open: boolean
|
open: boolean
|
||||||
onClose: (refreshCallback: boolean) => void
|
onClose: (refreshCallback: boolean) => void
|
||||||
|
linkedComponents: Map<string, Component>
|
||||||
|
componentDevices: Map<string, number>
|
||||||
//if we pass in a device id we could filter the components to only be for that device, this could be used for the control part
|
//if we pass in a device id we could filter the components to only be for that device, this could be used for the control part
|
||||||
device?: number
|
device?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function NewObjectInteraction(props: Props){
|
export default function NewObjectInteraction(props: Props){
|
||||||
const { open, onClose } = props
|
const { open, onClose, device, linkedComponents, componentDevices } = props
|
||||||
const [newAlertComponentType, setNewAlertComponentType] = useState<quack.ComponentType>(
|
const [newAlertComponentType, setNewAlertComponentType] = useState<quack.ComponentType>(
|
||||||
quack.ComponentType.COMPONENT_TYPE_INVALID
|
quack.ComponentType.COMPONENT_TYPE_INVALID
|
||||||
);
|
);
|
||||||
const [conditions, setConditions] = useState<pond.InteractionCondition[]>([]);
|
const [conditions, setConditions] = useState<pond.InteractionCondition[]>([]);
|
||||||
const [selectedAlertComponents, setSelectedAlertComponents] = useState<string[]>([]);
|
const [selectedAlertComponents, setSelectedAlertComponents] = useState<string[]>([]);
|
||||||
|
const [validOptions, setValidOptions] = useState<Option[]>([])
|
||||||
|
const [validComponents, setValidComponents] = useState<Component[]>([])
|
||||||
|
|
||||||
useEffect(() => {},[])
|
useEffect(() => {
|
||||||
|
//if the device is passed in need to filter out possible components
|
||||||
|
let validCompList: Component[] = []
|
||||||
|
let validOptions: Option[] = []
|
||||||
|
|
||||||
|
linkedComponents.forEach((comp, key) => {
|
||||||
|
if(componentDevices.get(key) === device || !device){
|
||||||
|
validCompList.push(comp)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
let included: quack.ComponentType[] = []
|
||||||
|
validCompList.forEach(comp => {
|
||||||
|
if(included.includes(comp.type())) return
|
||||||
|
let ext = extension(comp.type(), comp.subType())
|
||||||
|
if(device){
|
||||||
|
if(!ext.isController){
|
||||||
|
included.push(comp.type())
|
||||||
|
validOptions.push({
|
||||||
|
label: ext.friendlyName,
|
||||||
|
value: comp.type()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
included.push(comp.type())
|
||||||
|
validOptions.push({
|
||||||
|
label: ext.friendlyName,
|
||||||
|
value: comp.type()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
setValidOptions(validOptions)
|
||||||
|
setValidComponents(validCompList)
|
||||||
|
},[device, linkedComponents, componentDevices])
|
||||||
|
|
||||||
|
|
||||||
const close = (refresh: boolean) => {
|
const close = (refresh: boolean) => {
|
||||||
|
|
@ -41,6 +82,39 @@ export default function NewObjectInteraction(props: Props){
|
||||||
return [condition];
|
return [condition];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//display the components that match the type that was selected for the new alert
|
||||||
|
const listMatchingComponents = () => {
|
||||||
|
let matching: Component[] = [];
|
||||||
|
validComponents.forEach(comp => {
|
||||||
|
if (comp.type() === newAlertComponentType) {
|
||||||
|
matching.push(comp);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<List>
|
||||||
|
{matching.map(comp => (
|
||||||
|
<ListItem key={comp.key()}>
|
||||||
|
<ListItemIcon>
|
||||||
|
<Checkbox
|
||||||
|
checked={selectedAlertComponents.includes(comp.key())}
|
||||||
|
onChange={(_, checked) => {
|
||||||
|
let selected = selectedAlertComponents;
|
||||||
|
if (checked) {
|
||||||
|
selected.push(comp.key());
|
||||||
|
} else {
|
||||||
|
selected.splice(selected.indexOf(comp.key()), 1);
|
||||||
|
}
|
||||||
|
setSelectedAlertComponents([...selected]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText>{comp.name()}</ListItemText>
|
||||||
|
</ListItem>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ResponsiveDialog
|
<ResponsiveDialog
|
||||||
open={open}
|
open={open}
|
||||||
|
|
@ -64,7 +138,7 @@ export default function NewObjectInteraction(props: Props){
|
||||||
<MenuItem key={0} value={0}>
|
<MenuItem key={0} value={0}>
|
||||||
Select Component Type
|
Select Component Type
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
{typeOptions.map(option => (
|
{validOptions.map(option => (
|
||||||
<MenuItem key={option.value} value={option.value}>
|
<MenuItem key={option.value} value={option.value}>
|
||||||
{option.label}
|
{option.label}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|
@ -73,21 +147,21 @@ export default function NewObjectInteraction(props: Props){
|
||||||
{/* list of checkboxes for the components that match that type */}
|
{/* list of checkboxes for the components that match that type */}
|
||||||
{listMatchingComponents()}
|
{listMatchingComponents()}
|
||||||
{/* have the conditions set here */}
|
{/* have the conditions set here */}
|
||||||
{conditionInput()}
|
{/* {conditionInput()} */}
|
||||||
{/* have the schedule set here */}
|
{/* have the schedule set here */}
|
||||||
{scheduler()}
|
{/* {scheduler()} */}
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button onClick={() => close(false)} variant="contained">
|
<Button onClick={() => close(false)} variant="contained">
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
{/* <Button
|
||||||
disabled={selectedAlertComponents.length === 0}
|
disabled={selectedAlertComponents.length === 0}
|
||||||
onClick={addInteractionToComponents}
|
onClick={addInteractionToComponents}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary">
|
color="primary">
|
||||||
Confirm
|
Confirm
|
||||||
</Button>
|
</Button> */}
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</ResponsiveDialog>
|
</ResponsiveDialog>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
import { Button, List, ListItem, ListSubheader, Typography } from "@mui/material";
|
||||||
|
import { makeStyles } from "@mui/styles";
|
||||||
|
import moment from "moment";
|
||||||
|
import { pond } from "protobuf-ts/pond";
|
||||||
|
import { useGlobalState, useNotificationAPI } from "providers";
|
||||||
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
|
import { getThemeType } from "theme/themeType";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
objectKey: string
|
||||||
|
objectType: pond.ObjectType
|
||||||
|
}
|
||||||
|
|
||||||
|
const useStyles = makeStyles(() => {
|
||||||
|
return ({
|
||||||
|
dark: {
|
||||||
|
backgroundColor: getThemeType() === "light" ? "rgb(245, 245, 245)" : "rgb(50, 50, 50)",
|
||||||
|
padding: 5
|
||||||
|
},
|
||||||
|
light: {
|
||||||
|
backgroundColor: getThemeType() === "light" ? "rgb(235, 235, 235)" : "rgb(60, 60, 60)",
|
||||||
|
padding: 5
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
export default function Notifications(props: Props){
|
||||||
|
const {objectKey, objectType} = props
|
||||||
|
const classes = useStyles();
|
||||||
|
const [recentNotifications, setRecentNotifications] = useState<pond.Notification[]>([]);
|
||||||
|
const [notificationsLoading, setNotificationsLoading] = useState(false)
|
||||||
|
const loadingRef = useRef(false)
|
||||||
|
const [{as}] = useGlobalState();
|
||||||
|
const notificationAPI = useNotificationAPI();
|
||||||
|
const [totalNotifications, setTotalNotifications] = useState(0)
|
||||||
|
|
||||||
|
|
||||||
|
//get the notifications for the components on an object
|
||||||
|
useEffect(() => {
|
||||||
|
if (loadingRef.current) return
|
||||||
|
loadingRef.current = true
|
||||||
|
notificationAPI
|
||||||
|
.listObjectNotifications(objectKey, objectType, 10, 0, undefined, undefined, undefined, as)
|
||||||
|
.then(resp => {
|
||||||
|
setRecentNotifications(resp.data.notifications);
|
||||||
|
setTotalNotifications(resp.data.total);
|
||||||
|
})
|
||||||
|
.catch(_err => {})
|
||||||
|
.finally(() => {
|
||||||
|
loadingRef.current = true;
|
||||||
|
});
|
||||||
|
}, [objectKey, objectType, notificationAPI]);
|
||||||
|
|
||||||
|
const loadMoreNotifications = () => {
|
||||||
|
let current = recentNotifications;
|
||||||
|
setNotificationsLoading(true);
|
||||||
|
notificationAPI
|
||||||
|
.listObjectNotifications(
|
||||||
|
objectKey,
|
||||||
|
objectType,
|
||||||
|
10,
|
||||||
|
current.length,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
as
|
||||||
|
)
|
||||||
|
.then(resp => {
|
||||||
|
if (resp.data.notifications.length > 0) {
|
||||||
|
let c = current.concat(resp.data.notifications);
|
||||||
|
setRecentNotifications([...c]);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(_err => {})
|
||||||
|
.finally(() => {
|
||||||
|
setNotificationsLoading(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<List style={{ margin: 5 }}>
|
||||||
|
<ListSubheader>Notifications</ListSubheader>
|
||||||
|
{recentNotifications && (
|
||||||
|
<React.Fragment>
|
||||||
|
{recentNotifications.map((notification, i) => (
|
||||||
|
<ListItem key={i} className={i % 2 === 0 ? classes.dark : classes.light}>
|
||||||
|
<Typography style={{ fontWeight: 650 }}>
|
||||||
|
{moment(notification.status?.timestamp).format("MMMM DD, YYYY - h:mm a")}
|
||||||
|
</Typography>{" "}
|
||||||
|
:{" "}
|
||||||
|
<Typography>
|
||||||
|
{notification.settings?.title + " - " + notification.settings?.subtitle}
|
||||||
|
</Typography>
|
||||||
|
</ListItem>
|
||||||
|
))}
|
||||||
|
{recentNotifications.length < totalNotifications && (
|
||||||
|
<ListItem key={"button"}>
|
||||||
|
<Button onClick={loadMoreNotifications} disabled={notificationsLoading}>
|
||||||
|
Get More
|
||||||
|
</Button>
|
||||||
|
</ListItem>
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
|
)}
|
||||||
|
</List>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -9,23 +9,32 @@ import { useInteractionsAPI } from "hooks";
|
||||||
import { useGlobalState } from "providers";
|
import { useGlobalState } from "providers";
|
||||||
import { extension, getFriendlyName } from "pbHelpers/ComponentType";
|
import { extension, getFriendlyName } from "pbHelpers/ComponentType";
|
||||||
import { sameComponentID } from "pbHelpers/Component";
|
import { sameComponentID } from "pbHelpers/Component";
|
||||||
|
import Notifications from "./Notifications";
|
||||||
|
import { pond } from "protobuf-ts/pond";
|
||||||
|
import React from "react";
|
||||||
|
import NewObjectInteraction from "./NewObjectInteraction";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
linkedComponents: Map<string, Component>; //the component key to the component object
|
linkedComponents: Map<string, Component>; //the component key to the component object
|
||||||
componentDevices: Map<string, number>;
|
componentDevices: Map<string, number>;
|
||||||
|
objectKey: string
|
||||||
|
objectType: pond.ObjectType
|
||||||
devices: Device[];
|
devices: Device[];
|
||||||
|
refreshCallback?: () => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ObjectInteractions(props: Props) {
|
export default function ObjectInteractions(props: Props) {
|
||||||
const { linkedComponents, componentDevices, devices } = props
|
const { linkedComponents, componentDevices, devices, objectKey, objectType, refreshCallback } = props
|
||||||
const [{as}] = useGlobalState()
|
const [{as}] = useGlobalState()
|
||||||
//list of alerts, each alert contains a list of interactions with matching conditions
|
//list of alerts, each alert contains a list of interactions with matching conditions
|
||||||
const [alerts, setAlerts] = useState<Alert[]>([]);
|
const [alerts, setAlerts] = useState<Alert[]>([]);
|
||||||
//list of interactions relating to a controller
|
//list of interactions relating to a controller
|
||||||
const [controls, setControls] = useState<Control[]>([]);
|
const [controls, setControls] = useState<Control[]>([]);
|
||||||
const interactionsAPI = useInteractionsAPI();
|
const interactionsAPI = useInteractionsAPI();
|
||||||
const [sinkOptions, setSinkOptions] = useState<Component[]>([])
|
const [openNewInteraction, setOpenNewInteraction] = useState(false)
|
||||||
const [typeOptions, setTypeOptions] = useState<Option[]>([]);
|
const [allSinks, setAllSinks] = useState<Component[]>([]);
|
||||||
|
// const [typeOptions, setTypeOptions] = useState<Option[]>([]);
|
||||||
|
const [selectedDevice, setSelectedDevice] = useState<number | undefined>(undefined)
|
||||||
|
|
||||||
|
|
||||||
const matchConditions = (interaction: Interaction, set: Alert | Control) => {
|
const matchConditions = (interaction: Interaction, set: Alert | Control) => {
|
||||||
|
|
@ -79,8 +88,6 @@ export default function ObjectInteractions(props: Props) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const newInteractions: Interaction[] = [];
|
const newInteractions: Interaction[] = [];
|
||||||
const interactionSourceMap = new Map<string, string>();
|
const interactionSourceMap = new Map<string, string>();
|
||||||
const includedOps: quack.ComponentType[] = [];
|
|
||||||
const typeOps: Option[] = [];
|
|
||||||
const sinkOptions: Component[] = [];
|
const sinkOptions: Component[] = [];
|
||||||
const alerts: Alert[] = [];
|
const alerts: Alert[] = [];
|
||||||
const controls: Control[] = [];
|
const controls: Control[] = [];
|
||||||
|
|
@ -103,15 +110,6 @@ export default function ObjectInteractions(props: Props) {
|
||||||
newInteractions.push(...resp);
|
newInteractions.push(...resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect component types
|
|
||||||
if (!includedOps.includes(comp.type())) {
|
|
||||||
includedOps.push(comp.type());
|
|
||||||
typeOps.push({
|
|
||||||
label: getFriendlyName(comp.type()),
|
|
||||||
value: comp.type(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect controller components
|
// Collect controller components
|
||||||
if (extension(comp.type()).isController) {
|
if (extension(comp.type()).isController) {
|
||||||
sinkOptions.push(comp);
|
sinkOptions.push(comp);
|
||||||
|
|
@ -178,8 +176,7 @@ export default function ObjectInteractions(props: Props) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
setTypeOptions(typeOps);
|
setAllSinks(sinkOptions);
|
||||||
setSinkOptions(sinkOptions);
|
|
||||||
setAlerts(alerts);
|
setAlerts(alerts);
|
||||||
console.log(alerts)
|
console.log(alerts)
|
||||||
setControls(controls);
|
setControls(controls);
|
||||||
|
|
@ -192,13 +189,35 @@ export default function ObjectInteractions(props: Props) {
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<NewObjectInteraction
|
||||||
|
open={openNewInteraction}
|
||||||
|
onClose={(refresh) => {
|
||||||
|
setOpenNewInteraction(false)
|
||||||
|
if(refresh && refreshCallback){
|
||||||
|
refreshCallback()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
linkedComponents={linkedComponents}
|
||||||
|
componentDevices={componentDevices}
|
||||||
|
device={selectedDevice}/>
|
||||||
<Card raised style={{ margin: 5 }}>
|
<Card raised style={{ margin: 5 }}>
|
||||||
<Box padding={1}>
|
<Box padding={1}>
|
||||||
<Typography style={{ fontWeight: 650, fontSize: 25 }}>Interactions</Typography>
|
<Typography style={{ fontWeight: 650, fontSize: 25 }}>Interactions</Typography>
|
||||||
<Controls controls={controls}/>
|
<Controls
|
||||||
<Alerts alerts={alerts}/>
|
controls={controls}
|
||||||
{/* <Notifications /> */}
|
devices={devices}
|
||||||
|
addNew={(deviceID) => {
|
||||||
|
setSelectedDevice(deviceID)
|
||||||
|
setOpenNewInteraction(true)
|
||||||
|
}}/>
|
||||||
|
<Alerts alerts={alerts} addNew={() => {
|
||||||
|
setSelectedDevice(undefined)
|
||||||
|
setOpenNewInteraction(true)
|
||||||
|
}}/>
|
||||||
|
<Notifications objectKey={objectKey} objectType={objectType}/>
|
||||||
</Box>
|
</Box>
|
||||||
</Card>
|
</Card>
|
||||||
|
</React.Fragment>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -857,56 +857,15 @@ export default function Bin(props: Props) {
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
{/* <StyledToggleButtonGroup
|
|
||||||
id="tour-graph-tabs"
|
|
||||||
value={detail}
|
|
||||||
exclusive
|
|
||||||
size="small"
|
|
||||||
aria-label="detail">
|
|
||||||
<StyledToggle
|
|
||||||
value={"inventory"}
|
|
||||||
aria-label="Inventory Details"
|
|
||||||
onClick={() => setDetail("inventory")}>
|
|
||||||
Inventory
|
|
||||||
</StyledToggle>
|
|
||||||
<StyledToggle
|
|
||||||
onClick={() => setDetail("sensors")}
|
|
||||||
value={"sensors"}
|
|
||||||
aria-label="Bin Sensor Graphs">
|
|
||||||
Sensors
|
|
||||||
</StyledToggle>
|
|
||||||
<StyledToggle
|
|
||||||
onClick={() => setDetail("analytics")}
|
|
||||||
value={"analytics"}
|
|
||||||
aria-label="Bin Analysis Graphs">
|
|
||||||
Analysis
|
|
||||||
</StyledToggle>
|
|
||||||
<StyledToggle
|
|
||||||
onClick={() => setDetail("alerts")}
|
|
||||||
value={"alerts"}
|
|
||||||
aria-label="Device Alerts">
|
|
||||||
Alerts
|
|
||||||
</StyledToggle>
|
|
||||||
<StyledToggle
|
|
||||||
onClick={() => setDetail("presets")}
|
|
||||||
value={"presets"}
|
|
||||||
aria-label="Bin Mode Presets">
|
|
||||||
Presets
|
|
||||||
</StyledToggle>
|
|
||||||
</StyledToggleButtonGroup> */}
|
|
||||||
</Box>
|
</Box>
|
||||||
{detail === "alerts" && (
|
{detail === "alerts" && (
|
||||||
<Box>
|
<Box>
|
||||||
{/* <ObjectAlerts
|
|
||||||
linkedComponents={components}
|
|
||||||
componentDevices={componentDevices}
|
|
||||||
objectType={pond.ObjectType.OBJECT_TYPE_BIN}
|
|
||||||
objectKey={bin.key()}
|
|
||||||
/> */}
|
|
||||||
<ObjectInteractions
|
<ObjectInteractions
|
||||||
linkedComponents={components}
|
linkedComponents={components}
|
||||||
componentDevices={componentDevices}
|
componentDevices={componentDevices}
|
||||||
devices={devices}
|
devices={devices}
|
||||||
|
objectKey={bin.key()}
|
||||||
|
objectType={pond.ObjectType.OBJECT_TYPE_BIN}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|
@ -1039,16 +998,12 @@ export default function Bin(props: Props) {
|
||||||
</TabPanelMine>
|
</TabPanelMine>
|
||||||
<TabPanelMine value={mobileTab} index={4}>
|
<TabPanelMine value={mobileTab} index={4}>
|
||||||
<Box>
|
<Box>
|
||||||
{/* <ObjectAlerts
|
|
||||||
linkedComponents={components}
|
|
||||||
componentDevices={componentDevices}
|
|
||||||
objectType={pond.ObjectType.OBJECT_TYPE_BIN}
|
|
||||||
objectKey={bin.key()}
|
|
||||||
/> */}
|
|
||||||
<ObjectInteractions
|
<ObjectInteractions
|
||||||
linkedComponents={components}
|
linkedComponents={components}
|
||||||
componentDevices={componentDevices}
|
componentDevices={componentDevices}
|
||||||
devices={devices}
|
devices={devices}
|
||||||
|
objectKey={bin.key()}
|
||||||
|
objectType={pond.ObjectType.OBJECT_TYPE_BIN}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</TabPanelMine>
|
</TabPanelMine>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue