merged gas status, pulled, updated staging proto

This commit is contained in:
Carter 2025-05-23 13:24:32 -06:00
commit a1a4851fd9
8 changed files with 593 additions and 67 deletions

View file

@ -1,5 +1,5 @@
import { DeveloperBoard as ProvisionIcon, LibraryAdd as CreateGroupIcon } from "@mui/icons-material";
import { Box, Chip, Grid2, IconButton, Skeleton, Tab, Tabs, Theme, Tooltip, Typography, useTheme } from "@mui/material";
import { DeveloperBoard as ProvisionIcon, LibraryAdd as CreateGroupIcon, Tune } from "@mui/icons-material";
import { Box, Checkbox, Chip, Grid2, IconButton, ListItemIcon, ListItemText, Menu, MenuItem, Skeleton, Tab, Tabs, Theme, Tooltip, Typography, useTheme } from "@mui/material";
import { blue, green, orange } from "@mui/material/colors";
import { makeStyles } from "@mui/styles";
import ResponsiveTable, { Column } from "common/ResponsiveTable";
@ -24,6 +24,8 @@ import { Tag as TagUI } from "common/Tag";
import moment from "moment";
import StatusPlenum from "common/StatusPlenum";
import StatusSen5x from "common/StatusSen5x";
import StatusDust from "common/StatusDust";
import StatusGas from "common/StatusGas";
const useStyles = makeStyles((theme: Theme) => {
return ({
@ -100,6 +102,10 @@ export default function Devices() {
const [isProvisionDialogOpen, setIsProvisionDialogOpen] = useState<boolean>(false);
const [hasPlenums, setHasPlenums] = useState(false)
const [hasSen5x, setHasSen5x] = useState(false)
const [hasCo, setHasCo] = useState(false)
const [hasCo2, setHasCo2] = useState(false)
const [hasNo2, setHasNo2] = useState(false)
const [hasO2, setHasO2] = useState(false)
const [groupsLoading, setGroupsLoading] = useState(false)
const [groups, setGroups] = useState<Group[]>([]);
@ -122,6 +128,26 @@ export default function Devices() {
const [groupSettingsIsOpen, setGroupSettingsIsOpen] = useState<boolean>(false);
const [fieldContains, setFieldContains] = useState<Map<string, string>>(new Map<string, string>())
const [separateDust, setSeparateDust] = useState(() => {
const stored = localStorage.getItem('separateDust');
return stored !== null ? stored === 'true' : false;
});
useEffect(() => {
localStorage.setItem('separateDust', separateDust.toString());
}, [separateDust]);
const [groupGas, setGroupGas] = useState(() => {
const stored = localStorage.getItem('groupGas');
return stored !== null ? stored === 'true' : false;
});
useEffect(() => {
localStorage.setItem('groupGas', groupGas.toString());
}, [groupGas]);
const [preferencesAnchor, setPreferencesAnchor] = useState<any>(null)
const [{ as }] = useGlobalState()
@ -250,12 +276,12 @@ export default function Devices() {
).then(resp => {
let newDevices: Device[] = []
resp.data.devices.forEach(device => {
if (device.status?.plenum?.temperature) {
setHasPlenums(true)
}
if (device.status?.sen5x?.temperature) {
setHasSen5x(true)
}
if (device.status?.plenum?.temperature) setHasPlenums(true)
if (device.status?.sen5x?.temperature) setHasSen5x(true)
if (device.status?.o2) setHasO2(true)
if (device.status?.co) setHasCo(true)
if (device.status?.co2) setHasCo2(true)
if (device.status?.no2) setHasNo2(true)
newDevices.push(Device.create(device))
})
setDevices(newDevices)
@ -277,15 +303,40 @@ export default function Devices() {
setLimit(event.target.value);
};
const prependToUrl = (prependage: number | string) => {
const basePath = location.pathname.replace(/\/$/, "");
return(`/${prependage}/${basePath}`.replace(/\/{2,}/g, "/").replace(/(\/[^/]+)\/\1+/g, "$1"));
};
// const prependToUrl = (prependage: number | string) => {
// const basePath = location.pathname.replace(/\/$/, "");
// return(`/${prependage}/${basePath}`.replace(/\/{2,}/g, "/").replace(/(\/[^/]+)\/\1+/g, "$1"));
// };
function insertGroupContext(groupID: string, deviceID: string): string {
const path = location.pathname
const segments = path.split('/').filter(Boolean);
const deviceIndex = segments.findIndex(segment => segment === 'devices');
if (deviceIndex === -1) {
throw new Error('Path does not contain "devices"');
}
// Build the new segments
const newSegments = [
...segments.slice(0, deviceIndex),
'groups',
groupID,
...segments.slice(deviceIndex),
deviceID
];
return '/' + newSegments.join('/');
}
// useEffect(() => {
// console.log(devices)
// }, [devices])
const toDevice = (device: Device) => {
let url = prependToUrl(getGroup() ? "groups/" + getGroup().id() : "")
url = url + "/" + device.id()
navigate(url, { replace: true, state: {device: device} })
let url = getGroup() ? insertGroupContext(getGroup().id().toString(), device.id().toString()) : ""
if (url.length < 1) url = device.id().toString()
navigate(url, { state: {device: device} })
};
const handleTabChange = (_event: React.SyntheticEvent, newValue: string) => {
@ -396,7 +447,95 @@ export default function Devices() {
if (device.status.sen5x?.temperature) {
return (
<Box sx={{ marginLeft: 1 }}>
<StatusSen5x device={device} />
<StatusSen5x device={device} noDust={separateDust} />
</Box>
)
} else {
return (
<></>
)
}
}
})
if (separateDust) columns.push({
title: "Dust",
render: (device: Device) => {
if (device.status.sen5x?.temperature) {
return (
<Box sx={{ marginLeft: 1 }}>
<StatusDust device={device} />
</Box>
)
} else {
return (
<></>
)
}
}
})
}
if (hasCo) {
columns.push({
title: groupGas ? "Gas" : "CO",
render: (device: Device) => {
if (device.status.co) {
return (
<Box sx={{ marginLeft: 1 }}>
<StatusGas device={device} gasType={groupGas ? "all" : "co"}/>
</Box>
)
} else {
return (
<></>
)
}
}
})
}
if (hasCo2 && !groupGas) {
columns.push({
title: "CO2",
render: (device: Device) => {
if (device.status.co2) {
return (
<Box sx={{ marginLeft: 1 }}>
<StatusGas device={device} gasType={"co2"}/>
</Box>
)
} else {
return (
<></>
)
}
}
})
}
if (hasNo2 && !groupGas) {
columns.push({
title: "NO2",
render: (device: Device) => {
if (device.status.no2) {
return (
<Box sx={{ marginLeft: 1 }}>
<StatusGas device={device} gasType={"no2"}/>
</Box>
)
} else {
return (
<></>
)
}
}
})
}
if (hasO2 && !groupGas) {
columns.push({
title: "O2",
render: (device: Device) => {
if (device.status.o2) {
return (
<Box sx={{ marginLeft: 1 }}>
<StatusGas device={device} gasType={"o2"}/>
</Box>
)
} else {
@ -499,6 +638,51 @@ export default function Devices() {
)
}
const preferencesButton = () => {
return (
<IconButton onClick={(event) => setPreferencesAnchor(event.currentTarget)}>
<Tune />
</IconButton>
)
}
const preferencesMenu = () => {
return (
<Menu
id="userMenu"
anchorEl={preferencesAnchor}
open={preferencesAnchor !== null}
onClose={() => setPreferencesAnchor(null)}
disableAutoFocusItem>
<MenuItem
onClick={() => setSeparateDust(!separateDust)}
sx={{ marginLeft: -0.75 }}
dense
>
<ListItemIcon>
<Checkbox
checked={!separateDust}
/>
</ListItemIcon>
<ListItemText primary={"Group Dust"} />
</MenuItem>
<MenuItem
onClick={() => setGroupGas(!groupGas)}
sx={{ marginLeft: -0.75 }}
dense
>
<ListItemIcon>
<Checkbox
checked={groupGas}
/>
</ListItemIcon>
<ListItemText primary={"Group Gas"} />
</MenuItem>
</Menu>
)
}
return(
<PageContainer padding={isMobile ? 0 : 2}>
<Box
@ -548,6 +732,7 @@ export default function Devices() {
setOrder={setOrder}
orderBy={orderBy}
setOrderBy={setOrderBy}
endTitleElement={preferencesButton}
/>
<ProvisionDevice
isOpen={isProvisionDialogOpen}
@ -566,6 +751,7 @@ export default function Devices() {
removeGroupCallback={removeGroupCallback}
addGroupCallback={addGroupCallback}
/>
{preferencesMenu()}
</PageContainer>
)
}