Merge branch 'node_exclusion_update' into dev_environment

This commit is contained in:
csawatzky 2025-07-31 15:18:45 -06:00
commit 163f4dc288
54 changed files with 351 additions and 409 deletions

View file

@ -285,7 +285,7 @@ export default function ComponentCard(props: Props) {
// ) : (
<UnitMeasurementSummary
component={component}
excludedNodes={deviceComponentPreferences?.excludedNodes}
excludedNodes={component.settings.excludedNodes}
reading={UnitMeasurement.convertLastMeasurement(measurements)}
//dense
/>

View file

@ -11,30 +11,31 @@ import {
FormControl,
FormControlLabel,
FormGroup,
FormLabel,
//FormLabel,
Grid2 as Grid,
Theme,
Tooltip,
Typography
} from "@mui/material";
import { lightGreen } from "@mui/material/colors";
import { ExpandMore } from "@mui/icons-material";
import { ExpandMore, Warning } from "@mui/icons-material";
import MeasurementsChart from "charts/MeasurementsChart";
//import { GraphOrientation } from "common/Graph";
import RangeInput, { Range } from "common/RangeInput";
//import RangeInput, { Range } from "common/RangeInput";
import { GetDefaultDateRange } from "common/time/DateRange";
import DateSelect from "common/time/DateSelect";
import MeasurementSummary from "component/MeasurementSummary";
//import DateSelect from "common/time/DateSelect";
//import MeasurementSummary from "component/MeasurementSummary";
import { grainName } from "grain";
import { useMobile, usePrevious } from "hooks";
import { useMobile } from "hooks";
import { cloneDeep } from "lodash";
import { Component, Interaction } from "models";
import { UnitMeasurement } from "models/UnitMeasurement";
import moment from "moment";
import { deviceComponentID } from "pbHelpers/Component";
//import { deviceComponentID } from "pbHelpers/Component";
import {
extension,
//getComponentVisual,
GetNumNodes,
//GetNumNodes,
GetNumNodesFromUnitMeasurement,
GraphFilters
} from "pbHelpers/ComponentType";
@ -43,9 +44,9 @@ import { findInteractionsAsSource } from "pbHelpers/Interaction";
import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
import { pond } from "protobuf-ts/pond";
import { quack } from "protobuf-ts/quack";
import { useGlobalState } from "providers";
import React, { useEffect, useState } from "react";
import { or } from "utils/types";
//import { useGlobalState } from "providers";
import React, { useState } from "react";
//import { or } from "utils/types";
import UnitMeasurementSummary from "./UnitMeasurementSummary";
import { makeStyles } from "@mui/styles";
@ -82,34 +83,34 @@ interface Props {
component: Component;
interactions: Interaction[];
sampling: boolean;
samples?: pond.Measurement[]; //deprecated: old measurement structure
//samples?: pond.Measurement[]; //deprecated: old measurement structure
unitMeasurements?: UnitMeasurement[];
sampleLimit?: number;
updateDate?: (startDate: any, endDate: any, live?: boolean) => void;
allowLive?: boolean;
recentMeasurement?: pond.Measurement;
//recentMeasurement?: pond.Measurement;
recentUnitMeasurement?: UnitMeasurement[];
deviceComponentPreferences?: pond.DeviceComponentPreferences;
}
function setComponentGraphRanges(device: number | string, component: string, ranges: Range[]) {
const key: string = "graphRanges-" + deviceComponentID(device, component);
localStorage.setItem(key, JSON.stringify(or(ranges, [])));
}
// function setComponentGraphRanges(device: number | string, component: string, ranges: Range[]) {
// const key: string = "graphRanges-" + deviceComponentID(device, component);
// localStorage.setItem(key, JSON.stringify(or(ranges, [])));
// }
function getComponentGraphRanges(device: number | string, component: string): Range[] {
const key: string = "graphRanges-" + deviceComponentID(device, component);
return JSON.parse(or(localStorage.getItem(key), "[]"));
}
// function getComponentGraphRanges(device: number | string, component: string): Range[] {
// const key: string = "graphRanges-" + deviceComponentID(device, component);
// return JSON.parse(or(localStorage.getItem(key), "[]"));
// }
export default function ComponentChart(props: Props) {
const { component, deviceComponentPreferences } = props;
//const { component, deviceComponentPreferences } = props;
const classes = useStyles();
const isMobile = useMobile();
const { deviceKey, componentKey } = props;
const prevDevice = usePrevious(props.deviceKey);
const prevComponentKey = usePrevious(props.componentKey);
const prevComponent = usePrevious(props.component);
// const { deviceKey, componentKey } = props;
// const prevDevice = usePrevious(props.deviceKey);
// const prevComponentKey = usePrevious(props.componentKey);
// const prevComponent = usePrevious(props.component);
const defaultDateRange = GetDefaultDateRange();
const [startDate, setStartDate] = useState(defaultDateRange.start);
const [endDate, setEndDate] = useState(defaultDateRange.end);
@ -126,46 +127,47 @@ export default function ComponentChart(props: Props) {
const [expandData, setExpandData] = useState(false);
const [showOriginal, setShowOriginal] = useState(true);
const [showAveraged, setShowAveraged] = useState(false);
const [showAllNodes, setShowAllNodes] = useState(false);
useEffect(() => {
if (prevComponent !== props.component) {
let updatedFilters = cloneDeep(graphFilters);
let filledTo = props.component.settings.grainFilledTo;
updatedFilters.grainFilledTo = filledTo > 0 ? filledTo : undefined;
updatedFilters.grainType = props.component.settings.grainType;
setGraphFilters(updatedFilters);
}
}, [prevComponent, graphFilters, props.component]);
// useEffect(() => {
// if (prevComponent !== props.component) {
// let updatedFilters = cloneDeep(graphFilters);
// let filledTo = props.component.settings.grainFilledTo;
// updatedFilters.grainFilledTo = filledTo > 0 ? filledTo : undefined;
// updatedFilters.grainType = props.component.settings.grainType;
// setGraphFilters(updatedFilters);
// }
// }, [prevComponent, graphFilters, props.component]);
useEffect(() => {
if (prevDevice !== deviceKey || prevComponentKey !== componentKey) {
const ranges = getComponentGraphRanges(deviceKey, componentKey);
let updatedFilters = cloneDeep(graphFilters);
updatedFilters.ranges = ranges;
setGraphFilters(updatedFilters);
}
}, [deviceKey, prevDevice, prevComponentKey, componentKey, graphFilters]);
// useEffect(() => {
// if (prevDevice !== deviceKey || prevComponentKey !== componentKey) {
// const ranges = getComponentGraphRanges(deviceKey, componentKey);
// let updatedFilters = cloneDeep(graphFilters);
// updatedFilters.ranges = ranges;
// setGraphFilters(updatedFilters);
// }
// }, [deviceKey, prevDevice, prevComponentKey, componentKey, graphFilters]);
//use the excluded nodes to set the default for the graph filters
useEffect(() => {
let excludedNodes = deviceComponentPreferences?.excludedNodes;
if (excludedNodes === undefined || excludedNodes.length === 0) return;
let updatedFilters = cloneDeep(graphFilters);
if (excludedNodes && component.lastMeasurement[0]) {
let includedNodes: string[] = [];
let numNodes = GetNumNodesFromUnitMeasurement(
UnitMeasurement.any(component.lastMeasurement[0])
);
// useEffect(() => {
// let excludedNodes = component.settings.excludedNodes;
// if (excludedNodes === undefined || excludedNodes.length === 0) return;
// let updatedFilters = cloneDeep(graphFilters);
// if (excludedNodes && component.lastMeasurement[0]) {
// let includedNodes: string[] = [];
// let numNodes = GetNumNodesFromUnitMeasurement(
// UnitMeasurement.any(component.lastMeasurement[0])
// );
for (let i = 0; i < numNodes; i++) {
if (!excludedNodes.includes(i)) {
includedNodes.push(i.toString());
}
}
updatedFilters.selectedNodes = includedNodes;
}
setGraphFilters(updatedFilters);
}, [deviceComponentPreferences, component]); //eslint-disable-line react-hooks/exhaustive-deps
// for (let i = 0; i < numNodes; i++) {
// if (!excludedNodes.includes(i)) {
// includedNodes.push(i.toString());
// }
// }
// updatedFilters.selectedNodes = includedNodes;
// }
// setGraphFilters(updatedFilters);
// }, [component]); //eslint-disable-line react-hooks/exhaustive-deps
const updateDateRange = (newStartDate: any, newEndDate: any, live: boolean) => {
setStartDate(newStartDate);
@ -176,14 +178,14 @@ export default function ComponentChart(props: Props) {
}
};
const changeRange = (index: number, range: Range) => {
let updatedFilters = cloneDeep(graphFilters);
let ranges = updatedFilters.ranges ? updatedFilters.ranges : [];
ranges[index] = range;
updatedFilters.ranges = ranges;
setComponentGraphRanges(deviceKey, componentKey, ranges);
setGraphFilters(updatedFilters);
};
// const changeRange = (index: number, range: Range) => {
// let updatedFilters = cloneDeep(graphFilters);
// let ranges = updatedFilters.ranges ? updatedFilters.ranges : [];
// ranges[index] = range;
// updatedFilters.ranges = ranges;
// setComponentGraphRanges(deviceKey, componentKey, ranges);
// setGraphFilters(updatedFilters);
// };
const handleGrainCableControlsChange = (name: string) => (event: any) => {
let updatedFilters = cloneDeep(graphFilters);
@ -211,23 +213,22 @@ export default function ComponentChart(props: Props) {
};
const cableControls = () => {
const { component, samples, deviceComponentPreferences } = props;
const excludedNodes = deviceComponentPreferences?.excludedNodes ?? [];
const { recentUnitMeasurement } = props;
//const excludedNodes = component.settings.excludedNodes ?? [];
const selectedNodes = graphFilters.selectedNodes ? graphFilters.selectedNodes : ["all"];
const lastMeasurement = component.status.lastMeasurement;
let numNodes = 0;
if (samples) {
numNodes = GetNumNodes(
component.settings.type,
lastMeasurement && lastMeasurement.measurement
);
} else {
if (component.lastMeasurement && component.lastMeasurement[0]) {
// if (samples) {
// numNodes = GetNumNodes(
// component.settings.type,
// recentUnitMeasurement
// );
// } else {
if (recentUnitMeasurement && recentUnitMeasurement.length > 0) {
numNodes = GetNumNodesFromUnitMeasurement(
UnitMeasurement.any(component.lastMeasurement[0])
recentUnitMeasurement[0]
);
}
}
//}
if (numNodes <= 1) {
return null;
@ -301,17 +302,17 @@ export default function ComponentChart(props: Props) {
}
//TODO-DRAGER: this mey not be necessary to do anymore with them being split up
if (component.type() === quack.ComponentType.COMPONENT_TYPE_DRAGER_GAS_DONGLE) {
let describer = describeMeasurement(
component.lastMeasurement[0].type,
component.type(),
component.subType()
);
let details = describer.nodeDetails();
if (details) {
nodeLabel = details.labels[i - 1];
}
}
// if (component.type() === quack.ComponentType.COMPONENT_TYPE_DRAGER_GAS_DONGLE) {
// let describer = describeMeasurement(
// component.lastMeasurement[0].type,
// component.type(),
// component.subType()
// );
// let details = describer.nodeDetails();
// if (details) {
// nodeLabel = details.labels[i - 1];
// }
// }
grainCableControls.push(
<Grid size={{ xs: 6 }} key={"node-" + (i - 1).toString()}>
@ -322,7 +323,7 @@ export default function ComponentChart(props: Props) {
checked={selectedNodes.includes((i - 1).toString()) ? true : false}
onChange={handleGrainCableControlsChange((i - 1).toString())}
value={(i - 1).toString()}
disabled={excludedNodes.includes(i - 1)}
//disabled={excludedNodes.includes(i - 1)}
/>
}
label={<Typography variant="body2">{nodeLabel}</Typography>}
@ -695,19 +696,27 @@ export default function ComponentChart(props: Props) {
}
};
const displayExcludedNodes = () => {
const {component} = props
let nodes: number[] = []
component.settings.excludedNodes.forEach(node => {
nodes.push(node+1)
})
return nodes
}
const content = () => {
const {
component,
sampling,
samples,
recentMeasurement,
recentUnitMeasurement,
deviceComponentPreferences
recentUnitMeasurement
} = props;
const ext = extension(component.settings.type, component.settings.subtype);
const ranges = graphFilters.ranges ? graphFilters.ranges : [];
//const ext = extension(component.settings.type, component.settings.subtype);
//const ranges = graphFilters.ranges ? graphFilters.ranges : [];
let convertedLastMeasurement;
//console.log(recentUnitMeasurement)
if (recentUnitMeasurement && recentUnitMeasurement.length > 0) {
let measurements = recentUnitMeasurement;
convertedLastMeasurement = UnitMeasurement.convertLastMeasurement(measurements);
@ -716,18 +725,17 @@ export default function ComponentChart(props: Props) {
<Grid container spacing={2} direction={isMobile ? "column" : "row-reverse"}>
{isMobile && (
<Grid className={classes.borderedContainer}>
{samples ? (
{/* {samples ? (
<MeasurementSummary component={component} reading={recentMeasurement} />
) : (
) : ( */}
<Card raised className={classes.container}>
<Typography style={{ fontWeight: 650 }}>Latest Measurements:</Typography>
<UnitMeasurementSummary
component={component}
reading={convertedLastMeasurement}
excludedNodes={deviceComponentPreferences?.excludedNodes}
/>
</Card>
)}
{/* )} */}
</Grid>
)}
<Grid
@ -749,14 +757,29 @@ export default function ComponentChart(props: Props) {
<React.Fragment>
{/* {newStructure && ( */}
<Grid size={{ xs: 12 }}>
<Typography style={{ fontWeight: 650, fontSize: 20 }}>Status</Typography>
<Box display="flex" justifyContent="space-between">
<Box>
<Typography style={{ fontWeight: 650, fontSize: 20 }}>Status</Typography>
</Box>
{component.settings.excludedNodes.length > 0 &&
<Box display="flex" alignContent="center" margin="auto" marginX={0}>
<Typography textAlign="center" marginX={1}>
Excluded Nodes
</Typography>
<Tooltip
title={"You have excluded nodes (" + displayExcludedNodes().toLocaleString() + ") and they will not show up on this page, you can reveal them temporarily by selecting show errors"}>
<Warning color="warning"/>
</Tooltip>
</Box>
}
</Box>
<Divider variant="middle" className={classes.divider} />
</Grid>
{/* )} */}
<Grid size={{ xs: 12 }} className={classes.borderedContainer}>
{samples ? (
{/* {samples ? (
<MeasurementSummary component={component} reading={recentMeasurement} />
) : (
) : ( */}
<Card raised style={{ padding: 25, marginBottom: 20 }}>
<Typography style={{ fontWeight: 650 }}>Latest Measurements:</Typography>
<UnitMeasurementSummary
@ -764,10 +787,9 @@ export default function ComponentChart(props: Props) {
reading={convertedLastMeasurement}
largeText
boldMeasurements
excludedNodes={deviceComponentPreferences?.excludedNodes}
/>
</Card>
)}
{/* )} */}
</Grid>
</React.Fragment>
)}
@ -792,7 +814,7 @@ export default function ComponentChart(props: Props) {
</Grid>
)}
{!sampling &&
{/* {!sampling &&
ext.measurements.map((m, i) => {
const range = ranges[i] ? ranges[i] : ({} as Range);
if (m.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_BOOLEAN) {
@ -810,7 +832,7 @@ export default function ComponentChart(props: Props) {
);
}
return null;
})}
})} */}
</Grid>
</Grid>
);

View file

@ -97,6 +97,7 @@ export default function ComponentDiagnostics(props: Props) {
undefined,
undefined,
undefined,
undefined,
as
)
.then(resp => {

View file

@ -181,11 +181,11 @@ export default function ComponentSettings(props: Props) {
setTabVal(newValue);
};
useEffect(() => {
if (deviceComponentPrefs) {
setExcludedNodes(deviceComponentPrefs.excludedNodes);
}
}, [deviceComponentPrefs]);
// useEffect(() => {
// if (deviceComponentPrefs) {
// setExcludedNodes(deviceComponentPrefs.excludedNodes);
// }
// }, [deviceComponentPrefs]);
const init = useCallback(() => {
let component = props.component;
@ -208,6 +208,7 @@ export default function ComponentSettings(props: Props) {
)
);
setFormComponent(initComponent);
setExcludedNodes(initComponent.settings.excludedNodes)
}, [props.component, componentTypeOptions]);
useEffect(() => {
@ -324,20 +325,21 @@ export default function ComponentSettings(props: Props) {
const updateComponent = () => {
const component = formComponent;
component.settings.excludedNodes = excludedNodes
componentAPI
.update(device.id(), component.settings, getContextKeys(), getContextTypes(), as)
.then((_response: any) => {
success(component.name() + " was successfully updated!");
let updatedPrefs = pond.DeviceComponentPreferences.create();
updatedPrefs.excludedNodes = excludedNodes;
deviceAPI
.updateComponentPreferences(device.id(), component.key(), updatedPrefs, undefined, undefined, as)
.then(_resp => {
console.log("Preferences updated");
})
.catch(_err => {
console.log("Preferences failed to update");
});
// let updatedPrefs = pond.DeviceComponentPreferences.create();
// updatedPrefs.excludedNodes = excludedNodes;
// deviceAPI
// .updateComponentPreferences(device.id(), component.key(), updatedPrefs, undefined, undefined, as)
// .then(_resp => {
// console.log("Preferences updated");
// })
// .catch(_err => {
// console.log("Preferences failed to update");
// });
refresh();
})
.catch((_err: any) => {
@ -929,11 +931,11 @@ export default function ComponentSettings(props: Props) {
let nodes;
if (
prevComponent &&
prevComponent.lastMeasurement[0] &&
prevComponent.lastMeasurement[0].values[0] &&
prevComponent.lastMeasurement[0].values[0].values
prevComponent.status.measurement[0] &&
prevComponent.status.measurement[0].values[0] &&
prevComponent.status.measurement[0].values[0].values
) {
nodes = prevComponent.lastMeasurement[0].values[0].values;
nodes = prevComponent.status.measurement[0].values[0].values;
}
return (
@ -1018,24 +1020,6 @@ export default function ComponentSettings(props: Props) {
}}>
Clear Excluded Nodes
</Button>
{/* button for testing the pref update */}
{/* {prevComponent && (
<Button
onClick={() => {
let pref = pond.DeviceComponentPreferences.create();
pref.excludedNodes = excludedNodes;
deviceAPI
.updateComponentPreferences(device.id(), prevComponent.key(), pref)
.then(resp => {
console.log("no errors");
})
.catch(err => {
console.log("errors");
});
}}>
Update Prefs
</Button>
)} */}
</Box>
);
};
@ -1061,7 +1045,7 @@ export default function ComponentSettings(props: Props) {
onChange={handleChange}>
<Tab label="General" />
<Tab label="Overlays" />
<Tab label="Preferences" disabled={!prevComponent} />
<Tab label="Nodes" disabled={!prevComponent} />
</Tabs>
)}
<TabPanelMine value={tabVal} index={0}>

View file

@ -109,7 +109,8 @@ class ExportDataSettings extends React.Component<Props, State> {
undefined,
[device.id().toString()],
["device"],
undefined,
undefined,
undefined,
as
)
.then(resp => {

View file

@ -21,7 +21,6 @@ interface Props {
onlyRecent?: boolean;
largeText?: boolean;
boldMeasurements?: boolean;
excludedNodes?: number[];
}
const useStyles = makeStyles((theme: Theme) => {
@ -61,8 +60,7 @@ export default function UnitMeasurementSummary(props: Props) {
dense,
onlyRecent,
largeText,
boldMeasurements,
excludedNodes
boldMeasurements
} = props;
const [summaries, setSummaries] = useState<Summary[]>([]);
const [timestamp, setTimestamp] = useState("");
@ -80,12 +78,11 @@ export default function UnitMeasurementSummary(props: Props) {
setTimestamp(reading.timestamp);
setSummaries(
extension(component.type(), component.subType()).unitMeasurementSummary(
reading,
excludedNodes
reading
)
);
}
}, [component, reading, excludedNodes]); // eslint-disable-line react-hooks/exhaustive-deps
}, [component, reading]); // eslint-disable-line react-hooks/exhaustive-deps
const noSummary = () => {
return (