added status plenum to display plenum data, added pulseBox to extend the mui box and give it a pulsing animation of a given color

This commit is contained in:
Carter 2025-03-31 13:57:54 -06:00
parent 6d21ec0fc6
commit 14c1acd17c
6 changed files with 121 additions and 20 deletions

8
package-lock.json generated
View file

@ -10770,7 +10770,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#6cbc16a8de336d72e2e65619327e4462d26ce05d", "resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#9074fe327f799b1faef10374bd7ede55f3eb6a17",
"dependencies": { "dependencies": {
"protobufjs": "^6.8.8" "protobufjs": "^6.8.8"
} }
@ -13551,9 +13551,9 @@
} }
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "6.2.0", "version": "6.2.3",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.2.0.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.3.tgz",
"integrity": "sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==", "integrity": "sha512-IzwM54g4y9JA/xAeBPNaDXiBF8Jsgl3VBQ2YQ/wOY6fyW3xMdSoltIV3Bo59DErdqdE6RxUfv8W69DvUorE4Eg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {

View file

@ -1,4 +1,4 @@
import { darken, Tabs, TabsProps } from "@mui/material"; import { Tabs, TabsProps } from "@mui/material";
import React, { useEffect, useState, useRef } from "react"; import React, { useEffect, useState, useRef } from "react";
// import AnimatedTabs from "./AnimatedTabs"; // import AnimatedTabs from "./AnimatedTabs";

56
src/common/PulseBox.tsx Normal file
View file

@ -0,0 +1,56 @@
import { Box, BoxProps, Theme } from "@mui/material";
import { makeStyles } from "@mui/styles";
import classNames from "classnames";
import { ReactNode } from "react";
const useStyles = makeStyles((_theme: Theme) => ({
pulseWrapper: {
position: 'relative',
display: 'block', // Changed to block to respect Box margins
width: 'fit-content', // Shrinks to child width
'&::after': {
content: '""',
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
border: '2px solid var(--pulse-color)',
borderRadius: 'inherit', // Should inherit from Box
animation: '$pulse 1.5s infinite ease-in-out',
pointerEvents: 'none',
boxSizing: 'border-box',
},
},
'@keyframes pulse': {
from: {
transform: "scale(1)",
opacity: 1
},
to: {
transform: "scale(1.25)",
opacity: 0
}
},
}));
interface Props extends BoxProps {
color: string;
children: ReactNode;
className?: string;
}
export default function PulseBox(props: Props) {
const { color, children, className, ...boxProps } = props;
const classes = useStyles()
return (
<Box
{...boxProps}
className={classNames([classes.pulseWrapper, className])}
style={{ '--pulse-color': color } as React.CSSProperties}
>
{children}
</Box>
);
};

View file

@ -10,7 +10,7 @@ const useStyles = makeStyles((theme: Theme) => {
// const isMobile = useMobile() // const isMobile = useMobile()
return ({ return ({
gutter: { gutter: {
backgroundColor: darken(theme.palette.background.paper, 0.03), backgroundColor: darken(theme.palette.background.paper, 0.05),
border: "none" border: "none"
}, },
tableContainer: { tableContainer: {
@ -55,7 +55,7 @@ const useStyles = makeStyles((theme: Theme) => {
rowHover: { rowHover: {
cursor: "pointer", cursor: "pointer",
"&:hover": { "&:hover": {
backgroundColor: "rgba(150, 150, 150, 0.05)" backgroundColor: "rgba(150, 150, 150, 0.15)"
} }
} }
})}, })},
@ -323,7 +323,7 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
sx={{ sx={{
width: "100%", width: "100%",
display: "flex", display: "flex",
justifyContent: "center" justifyContent: "center",
}} }}
onClick={(event) => handleCollapse(index, event)} onClick={(event) => handleCollapse(index, event)}
// style={{pre}} // style={{pre}}

View file

@ -0,0 +1,51 @@
import { Grid2, Theme, Typography } from "@mui/material";
import { blue, orange } from "@mui/material/colors";
import { makeStyles } from "@mui/styles";
import { Device } from "models";
import PulseBox from "./PulseBox";
interface Props {
device: Device
}
const useStyles = makeStyles((theme: Theme) => {
const lightMode = theme.palette?.mode === "light";
return ({
box: {
display: "inline-block",
borderRadius: "6px",
backgroundColor: lightMode ? "rgb(170, 170, 170)" : "rgb(34, 34, 34)",
padding: theme.spacing(0.5),
marginRight: "auto",
margin: theme.spacing(1),
},
pulse: {
// padding: theme.spacing(2)
paddingLeft: theme.spacing(-6)
}
})
})
export default function StatusPlenum(props: Props) {
const { device } = props;
const classes = useStyles()
return (
<PulseBox color="blue" className={classes.box} >
{/* <Box className={classes.box}> */}
<Grid2 container direction="column" >
<Grid2>
<Typography variant="body2" style={{ color: orange[500]}}>
{device.status.plenum?.temperature.toFixed(1)}°C
</Typography>
</Grid2>
<Grid2>
<Typography variant="body2" style={{ color: blue[800]}}>
{device.status.plenum?.humidity.toFixed(1)}%
</Typography>
</Grid2>
</Grid2>
{/* </Box> */}
</PulseBox>
)
}

View file

@ -22,6 +22,7 @@ import BindaptIcon from "products/Bindapt/BindaptIcon";
import { describePower } from "pbHelpers/Power"; import { describePower } from "pbHelpers/Power";
import { Tag as TagUI } from "common/Tag"; import { Tag as TagUI } from "common/Tag";
import moment from "moment"; import moment from "moment";
import StatusPlenum from "common/StatusPlenum";
const useStyles = makeStyles((theme: Theme) => { const useStyles = makeStyles((theme: Theme) => {
return ({ return ({
@ -214,6 +215,8 @@ export default function Devices() {
).then(resp => { ).then(resp => {
let newDevices: Device[] = [] let newDevices: Device[] = []
resp.data.devices.forEach(device => { resp.data.devices.forEach(device => {
console.log(device.status)
console.log(device.status?.plenum?.overlays)
if (device.status?.plenum?.temperature) { if (device.status?.plenum?.temperature) {
setHasPlenums(true) setHasPlenums(true)
} }
@ -325,18 +328,9 @@ export default function Devices() {
render: (device: Device) => { render: (device: Device) => {
if (device.status.plenum?.temperature) { if (device.status.plenum?.temperature) {
return ( return (
<Grid2 container direction="column" marginLeft={2}> <Box sx={{ marginLeft: 1 }}>
<Grid2> <StatusPlenum device={device} />
<Typography variant="body2" style={{ color: orange[300]}}> </Box>
{device.status.plenum.temperature.toFixed(1)}°C
</Typography>
</Grid2>
<Grid2>
<Typography variant="body2" color="info">
{device.status.plenum.humidity.toFixed(1)}%
</Typography>
</Grid2>
</Grid2>
) )
} else { } else {
return ( return (