diff --git a/src/models/Interaction.ts b/src/models/Interaction.ts
index 659ca70..f9edba9 100644
--- a/src/models/Interaction.ts
+++ b/src/models/Interaction.ts
@@ -1,6 +1,7 @@
import { pond } from "protobuf-ts/pond";
import { or } from "utils/types";
import { cloneDeep } from "lodash";
+import { Result } from "pbHelpers/Enums";
export class Interaction {
public settings: pond.InteractionSettings = pond.InteractionSettings.create();
@@ -53,6 +54,18 @@ export class Interaction {
return subtype;
}
+ //these two are not mutually exclusive, it is possible to be an alert and a control
+ public isAlert(): boolean {
+ if(this.settings.result?.type === Result.report) return true
+ if(this.settings.notifications?.reports && this.settings.notifications.notify) return true
+ return false
+ }
+
+ public isControl(): boolean {
+ if(this.settings.result?.type !== Result.report) return true //as of right now all interactions that are not report are some sort of control
+ return false
+ }
+
public static upToSubtype(nodeNumber: number): number {
let subtype = 0;
switch (nodeNumber) {
diff --git a/src/objects/objectInteractions/Alerts.tsx b/src/objects/objectInteractions/Alerts.tsx
new file mode 100644
index 0000000..0c1ab01
--- /dev/null
+++ b/src/objects/objectInteractions/Alerts.tsx
@@ -0,0 +1,74 @@
+import { ExpandMore } from "@mui/icons-material";
+import { Accordion, AccordionDetails, AccordionSummary, Box, Grid2, List, ListItem, ListSubheader, Typography } from "@mui/material";
+import { Component } from "models";
+import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
+import { pond, quack } from "protobuf-ts/pond";
+import React, { useState } from "react";
+import NewObjectInteraction from "./NewObjectInteraction";
+
+export interface Alert {
+ conditions: pond.InteractionCondition[];
+ sourceComponents: Component[];
+}
+
+interface Props {
+ alerts: Alert[]
+}
+
+export default function Alerts(props: Props){
+ const {alerts} = props
+ const [openNewAlert, setOpenNewAlert] = useState(false)
+
+ const readableCondition = (condition: pond.InteractionCondition) => {
+ let describer = describeMeasurement(condition.measurementType);
+ let type = describer.label();
+ let comparison =
+ condition.comparison === quack.RelationalOperator.RELATIONAL_OPERATOR_EQUAL_TO
+ ? "Exactly"
+ : condition.comparison === quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN
+ ? "Above"
+ : "Below";
+ let value = describer.toDisplay(condition.value);
+ return (
+
+ {type + " " + comparison + " " + value + describer.GetUnit()}
+
+ );
+ };
+
+ const alertAccordion = (alert: Alert) => {
+ return (
+
+ }>
+
+ {alert.conditions.map((condition, i) => (
+
+ {readableCondition(condition)}
+
+ ))}
+
+
+
+
+ Reporting Components
+ {alert.sourceComponents.map((comp, i) => (
+ {comp.name()}
+ ))}
+
+
+
+ );
+ };
+
+ return (
+
+ {}}/>
+
+ Alerts
+ {alerts.map((alert, i) => (
+ {alertAccordion(alert)}
+ ))}
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/objects/objectInteractions/Controls.tsx b/src/objects/objectInteractions/Controls.tsx
new file mode 100644
index 0000000..096c9ca
--- /dev/null
+++ b/src/objects/objectInteractions/Controls.tsx
@@ -0,0 +1,61 @@
+import { Accordion, AccordionDetails, AccordionSummary, List, ListItem, ListSubheader } from "@mui/material";
+import { Component, Device } from "models";
+import { pond } from "protobuf-ts/pond";
+import React, { useEffect, useState } from "react";
+
+export interface Control {
+ conditions: pond.InteractionCondition[];
+ sourceComponents: Component[];
+ result: pond.InteractionResult | null;
+ sinkComponent: Component
+ device: Device
+}
+
+interface Props {
+ controls: Control[]
+}
+
+export default function Controls(props: Props){
+ const { controls } = props
+ const [deviceControls, setDeviceControls] = useState