committing all group related code

This commit is contained in:
Carter 2025-01-07 10:34:18 -06:00
parent 0ec54b2d31
commit 2d98917322
14 changed files with 541 additions and 102 deletions

View file

@ -1,25 +1,230 @@
import { Grid2 } from "@mui/material";
import { Box, Chip, Grid2, Theme, Tooltip, Typography } from "@mui/material";
import SmartBreadcrumb from "common/SmartBreadcrumb";
import { Group } from "models"
import { useState } from "react"
import { useLocation, useParams } from "react-router-dom";
import { Device, Group } from "models"
import { useEffect, useState } from "react"
import { useLocation, useNavigate, useParams } from "react-router-dom";
import PageContainer from "./PageContainer";
import { useDeviceAPI, useGroupAPI } from "providers";
import GroupActions from "group/GroupActions";
import { pond } from "protobuf-ts/pond";
import { getContextKeys, getContextTypes } from "pbHelpers/Context";
import ResponsiveTable, { Column } from "common/ResponsiveTable";
import { or } from "utils/types";
import { appendToUrl } from "navigation/Router";
import { getDeviceStateHelper } from "pbHelpers/DeviceState";
import { makeStyles } from "@mui/styles";
import { blue, green } from "@mui/material/colors";
import { permissionToString } from "pbHelpers/Permission";
const useStyles = makeStyles((theme: Theme) => {
return ({
buttonBox: {
position: "absolute",
zIndex: 1,
right: theme.spacing(4),
transform: "translateY(-50%)", // Move it up by half its height
transition: "opacity 0.2s ease-in-out",
opacity: 1,
// top: 0,
},
fadeBox: {
opacity: 0, // Fully transparent by default
transition: "opacity 0.2s ease-in-out", // Smooth transition
"&:hover": {
opacity: 1, // Fully opaque on hover
},
},
provisionIcon: {
color: blue["700"]
},
cellContainer: {
margin: theme.spacing(1),
marginLeft: theme.spacing(2),
display: "flex",
// justifyContent: "center",
},
green: {
color: green["600"]
},
tab: {
display: "block",
overflow: "hidden",
textOverflow: "ellipsis",
maxWidth: theme.spacing(26),
whiteSpace: "nowrap",
padding: theme.spacing(1.5)
}
});
});
export default function GroupPage() {
const groupAPI = useGroupAPI()
const deviceAPI = useDeviceAPI()
const navigate = useNavigate()
const classes = useStyles()
const groupID = useParams<{ groupID: string }>()?.groupID ?? "";
const groupID = parseInt(useParams<{ groupID: string }>()?.groupID ?? "0");
const { state } = useLocation();
const [group, setGroup] = useState<Group>(state?.device ? Group.create(state.device) : Group.create())
const [group, setGroup] = useState<Group>(state?.group ? Group.create(state.group) : Group.create())
const [loadingGroup, setLoadingGroup] = useState(false)
const [loadingDevices, setLoadingDevices] = useState(false)
const [devices, setDevices] = useState<Device[]>([])
const [permissions, setPermissions] = useState<pond.Permission[]>([])
const [limit, setLimit] = useState(0)
const [total, setTotal] = useState(0)
const [page, setPage] = useState(1)
const [order, setOrder] = useState<"asc" | "desc">("asc")
const [orderBy, setOrderBy] = useState("")
const [search, setSearch] = useState("")
const loadGroup = () => {
setLoadingGroup(true)
groupAPI.getGroupAndPermissions(groupID).then(resp => {
if (resp.data.group) setGroup(Group.create(resp.data.group))
let newPerms: pond.Permission[] = []
resp.data.permissions.forEach(perm => {
if (typeof(perm) === "string") {
const permNumber = pond.Permission[perm as keyof typeof pond.Permission]
newPerms.push(permNumber)
} else {
newPerms.push(perm)
}
})
setPermissions(newPerms)
}).finally(() => {
setLoadingGroup(false)
})
}
useEffect(() => {
if (group.id() === groupID) return;
loadGroup()
}, [group, groupID])
const loadDevices = () => {
setLoadingDevices(true)
deviceAPI.list(
limit,
page*limit,
order,
orderBy,
search,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
getContextKeys(),
getContextTypes()
).then(resp => {
let newDevices: Device[] = [];
resp.data.devices.forEach(device => {
newDevices.push(Device.create(device))
})
setDevices(newDevices)
setTotal(resp.data.total)
}).finally(() => {
setLoadingDevices(false)
})
}
useEffect(() => {
loadDevices()
}, [group, limit, page, order, orderBy, search])
const toDevice = (device: Device) => {
navigate(appendToUrl(or(device.settings?.deviceId, "")), { state: {device: device} })
};
const columns = (): Column<Device>[] => {
return [
{
title: "State",
render: (device) => {
const status = device.status ?? pond.DeviceStatus.create()
const deviceStateHelper = getDeviceStateHelper(status.state);
return (
<Box className={classes.cellContainer}>
<Tooltip title={deviceStateHelper.description}>{deviceStateHelper.icon}</Tooltip>
</Box>
)
}
},
{
title: "ID",
render: device => <span className={classes.cellContainer}>
{device.settings?.deviceId}
</span>
},
{
title: "Device",
render: (device) => {
return (
<Box className={classes.cellContainer} >
<Chip
variant="outlined"
label={device.settings?.name ? device.settings.name : "Device " + device.settings?.deviceId}
/>
</Box>
)
}
},
{
title: "Description",
render: device => {
const description = device.settings?.description ?? ""
return (
<Box className={classes.cellContainer}>
<Tooltip title={device.settings?.description}>
<span>
{description.length > 20
? description.substring(0, 20) + "..."
: description}
</span>
</Tooltip>
</Box>
)
}
},
]
}
const handleChange = (event: any) => {
setLimit(event.target.value);
};
return (
<Grid2 container justifyContent={"space-between"}>
<Grid2>
<SmartBreadcrumb groupName={group.name()} />
<PageContainer>
<Grid2 container justifyContent={"space-between"} alignItems={"center"} paddingBottom={2}>
<Grid2 >
<SmartBreadcrumb groupName={group.name()} loading={loadingGroup} />
</Grid2>
<Grid2 marginTop={"auto"} marginBottom="auto">
<GroupActions
group={group}
permissions={permissions ? permissions : []}
devices={devices}
refreshCallback={() => {}}
/>
</Grid2>
</Grid2>
<Grid2>
{/* <GroupActions /> */}
</Grid2>
</Grid2>
<ResponsiveTable<Device>
title={group.name()}
subtitle={group.settings.description}
rows={devices}
columns={columns()}
total={total}
pageSize={limit}
page={page}
setPage={setPage}
handleRowsPerPageChange={handleChange}
onRowClick={toDevice}
setSearchText={setSearch}
isLoading={loadingDevices}
/>
</PageContainer>
)
}