displaying status information on the gates dashboard now

This commit is contained in:
csawatzky 2026-01-15 14:32:39 -06:00
parent f06bcf9535
commit 65e70265fb
6 changed files with 66 additions and 15 deletions

4
package-lock.json generated
View file

@ -42,7 +42,7 @@
"mui-tel-input": "^7.0.0", "mui-tel-input": "^7.0.0",
"notistack": "^3.0.1", "notistack": "^3.0.1",
"openweathermap-ts": "^1.2.10", "openweathermap-ts": "^1.2.10",
"protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#staging", "protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#object_status",
"query-string": "^9.2.1", "query-string": "^9.2.1",
"react": "^18.3.1", "react": "^18.3.1",
"react-beautiful-dnd": "^13.1.1", "react-beautiful-dnd": "^13.1.1",
@ -10953,7 +10953,7 @@
}, },
"node_modules/protobuf-ts": { "node_modules/protobuf-ts": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#3f647071f211c4552c2acc23a8ecabb6904a4156", "resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#580cb59c08f9895384b5adc4853c480bf3bf3165",
"dependencies": { "dependencies": {
"protobufjs": "^6.8.8" "protobufjs": "^6.8.8"
} }

View file

@ -54,7 +54,7 @@
"mui-tel-input": "^7.0.0", "mui-tel-input": "^7.0.0",
"notistack": "^3.0.1", "notistack": "^3.0.1",
"openweathermap-ts": "^1.2.10", "openweathermap-ts": "^1.2.10",
"protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#staging", "protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#object_status",
"query-string": "^9.2.1", "query-string": "^9.2.1",
"react": "^18.3.1", "react": "^18.3.1",
"react-beautiful-dnd": "^13.1.1", "react-beautiful-dnd": "^13.1.1",

View file

@ -11,8 +11,10 @@ import ResponsiveTable, { Column } from "common/ResponsiveTable";
import AddGateFab from "./AddGateFab"; import AddGateFab from "./AddGateFab";
import GateSettings from "./GateSettings"; import GateSettings from "./GateSettings";
import { useGateAPI, useGlobalState } from "providers"; import { useGateAPI, useGlobalState } from "providers";
import { Settings } from "@mui/icons-material"; import { CheckCircleOutline, DoNotDisturb, ErrorOutline, RemoveCircleOutline, Settings } from "@mui/icons-material";
import { cloneDeep } from "lodash"; import { cloneDeep } from "lodash";
import moment from "moment";
import { pond } from "protobuf-ts/pond";
interface Props { interface Props {
//gates: Gate[]; //gates: Gate[];
@ -89,6 +91,19 @@ export default function GateList(props: Props) {
setPageSize(event.target.value); setPageSize(event.target.value);
}; };
const displayPCAStatus = (state: pond.PCAState) => {
switch(state){
case pond.PCAState.PCA_STATE_IN_BOUNDS:
return <CheckCircleOutline sx={{color: "green"}}/>
case pond.PCAState.PCA_STATE_OUT_BOUNDS:
return <ErrorOutline sx={{color: "red"}} />
case pond.PCAState.PCA_STATE_OFF:
return <RemoveCircleOutline />
default:
return <DoNotDisturb />
}
}
const desktopCols = (): Column<Gate>[] => { const desktopCols = (): Column<Gate>[] => {
return [ return [
{ {
@ -151,6 +166,29 @@ export default function GateList(props: Props) {
</Box> </Box>
) )
}, },
{
title: "PCA Status",
render: gate => (
<Box padding={2}>
{displayPCAStatus(gate.status.pcaState)}
</Box>
)
},
{
title: "Last FLow",
render: gate => (
<Box padding={2}>
<Box display="flex" justifyContent="space-between">
<Typography>Last Flow:</Typography>
<Typography>{gate.status.lastMassAirflow.toFixed(2)}</Typography>
</Box>
<Box display="flex" justifyContent="space-between">
<Typography>Last Reading:</Typography>
<Typography>{gate.status.lastUpdate !== "" ? moment(gate.status.lastUpdate).fromNow() : "No Reading Yet"}</Typography>
</Box>
</Box>
)
}
] ]
} }
const mobileCols = (): Column<Gate>[] => { const mobileCols = (): Column<Gate>[] => {
@ -162,13 +200,16 @@ export default function GateList(props: Props) {
<Typography margin="auto" marginLeft={0} fontWeight={650} fontSize={20}> <Typography margin="auto" marginLeft={0} fontWeight={650} fontSize={20}>
{gate.name} {gate.name}
</Typography> </Typography>
<IconButton onClick={(event) => { <Box display="flex" alignItems="center" gap={1}>
event.stopPropagation() {displayPCAStatus(gate.status.pcaState)}
setSelectedGate(gate) <IconButton onClick={(event) => {
setGateDialog(true) event.stopPropagation()
}}> setSelectedGate(gate)
<Settings /> setGateDialog(true)
</IconButton> }}>
<Settings />
</IconButton>
</Box>
</Box> </Box>
) )
} }
@ -198,6 +239,14 @@ export default function GateList(props: Props) {
<Typography>PCA Unit:</Typography> <Typography>PCA Unit:</Typography>
<Typography>{gate.settings.pcaType !== "" ? gate.settings.pcaType : "None"}</Typography> <Typography>{gate.settings.pcaType !== "" ? gate.settings.pcaType : "None"}</Typography>
</Box> </Box>
<Box padding={2} display="flex" flexDirection="row" justifyContent="space-between">
<Typography>Last Flow:</Typography>
<Typography>{gate.status.lastMassAirflow}</Typography>
</Box>
<Box padding={2} display="flex" flexDirection="row" justifyContent="space-between">
<Typography>Last Reading:</Typography>
<Typography>{gate.status.lastUpdate !== "" ? moment(gate.status.lastUpdate).fromNow() : "No PCA reading yet"}</Typography>
</Box>
</Box> </Box>
// <Typography variant="body2" color="textSecondary" sx={{ padding: 1 }}> // <Typography variant="body2" color="textSecondary" sx={{ padding: 1 }}>

View file

@ -5,22 +5,24 @@ import { or } from "utils/types";
export class Gate { export class Gate {
public settings: pond.GateSettings = pond.GateSettings.create(); public settings: pond.GateSettings = pond.GateSettings.create();
public status: pond.GateStatus = pond.GateStatus.create();
public name: string = "Gate"; public name: string = "Gate";
public key: string = ""; public key: string = "";
public preferences: any = {}; public preferences: any = {};
public gateMutations: any = {}; public gateMutations: any = {};
public pcaState: pond.PCAState = pond.PCAState.PCA_STATE_UNKNOWN; // public pcaState: pond.PCAState = pond.PCAState.PCA_STATE_UNKNOWN;
public static create(pb?: pond.Gate): Gate { public static create(pb?: pond.Gate): Gate {
let my = new Gate(); let my = new Gate();
if (pb) { if (pb) {
let g = pond.Gate.fromObject(pb); let g = pond.Gate.fromObject(pb);
my.settings = pond.GateSettings.fromObject(cloneDeep(or(g.settings, {}))); my.settings = pond.GateSettings.fromObject(cloneDeep(or(g.settings, {})));
my.status = pond.GateStatus.fromObject(cloneDeep(or(g.status, {})));
my.name = g.name; my.name = g.name;
my.key = g.key; my.key = g.key;
my.preferences = g.componentPreferences; my.preferences = g.componentPreferences;
my.gateMutations = g.gateMutations; my.gateMutations = g.gateMutations;
my.pcaState = g.pcaState; // my.pcaState = g.pcaState;
} }
return my; return my;
} }
@ -77,7 +79,7 @@ export class Gate {
} }
public gateMarkerColour(): string { public gateMarkerColour(): string {
switch (this.pcaState) { switch (this.status.pcaState) {
case pond.PCAState.PCA_STATE_OFF: case pond.PCAState.PCA_STATE_OFF:
return "grey"; return "grey";
case pond.PCAState.PCA_STATE_IN_BOUNDS: case pond.PCAState.PCA_STATE_IN_BOUNDS:

View file

@ -182,7 +182,6 @@ export default function Terminals(props: Props) {
if(loading) return if(loading) return
setLoading(true) setLoading(true)
terminalAPI.listTerminals(200, 0, "asc", "name", undefined, as).then(resp => { terminalAPI.listTerminals(200, 0, "asc", "name", undefined, as).then(resp => {
console.log(resp.data)
if(resp.data.terminals){ if(resp.data.terminals){
setTerminals(resp.data.terminals.map(a => Terminal.any(a))); setTerminals(resp.data.terminals.map(a => Terminal.any(a)));
} }

View file

@ -138,6 +138,7 @@ export default function GateProvider(props: PropsWithChildren<Props>) {
return new Promise<AxiosResponse<pond.ListGatesResponse>>((resolve, reject) => { return new Promise<AxiosResponse<pond.ListGatesResponse>>((resolve, reject) => {
get<pond.ListGatesResponse>(url).then(resp => { get<pond.ListGatesResponse>(url).then(resp => {
resp.data = pond.ListGatesResponse.fromObject(resp.data) resp.data = pond.ListGatesResponse.fromObject(resp.data)
console.log(resp)
return resolve(resp) return resolve(resp)
}).catch(err => { }).catch(err => {
return reject(err) return reject(err)