formatted mobile devices list

This commit is contained in:
Carter 2025-02-25 13:48:19 -06:00
parent 8743cba65a
commit 80683e29e5
3 changed files with 79 additions and 9 deletions

View file

@ -4,6 +4,7 @@ import { ChevronRight, Close, Search, ViewColumn } from "@mui/icons-material"
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import React from "react"; import React from "react";
import { useMobile } from "hooks"; import { useMobile } from "hooks";
import classNames from "classnames";
const useStyles = makeStyles((theme: Theme) => { const useStyles = makeStyles((theme: Theme) => {
// const isMobile = useMobile() // const isMobile = useMobile()
@ -140,7 +141,8 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
return () => clearTimeout(handler); // Cleanup on change return () => clearTimeout(handler); // Cleanup on change
}, [inputSearchText]); }, [inputSearchText]);
const handleCollapse = (index: number) => { const handleCollapse = (index: number, event: React.MouseEvent<HTMLDivElement | HTMLButtonElement, MouseEvent>) => {
event.stopPropagation();
if (multiGutter) { if (multiGutter) {
if (openGutters.includes(index)) { if (openGutters.includes(index)) {
setOpenGutters(openGutters => openGutters.filter(num => num !== index)); setOpenGutters(openGutters => openGutters.filter(num => num !== index));
@ -285,11 +287,10 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
{renderTitle()} {renderTitle()}
{renderSubtitle()} {renderSubtitle()}
{setSearchText && searchBar()} {setSearchText && searchBar()}
</Box> </Box>
{rows.map((row, index) => { {rows.map((row, index) => {
return ( return (
<Card className={classes.card} key={"mobile-card-"+index}> <Card className={classNames(classes.card, onRowClick&&classes.rowHover)} key={"mobile-card-"+index} onClick={() => onRowClick&&onRowClick(row)}>
{renderMobileRow(row)} {renderMobileRow(row)}
{renderGutter && {renderGutter &&
<> <>
@ -304,7 +305,8 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
display: "flex", display: "flex",
justifyContent: "center" justifyContent: "center"
}} }}
onClick={() => handleCollapse(index)} onClick={(event) => handleCollapse(index, event)}
// style={{pre}}
> >
<IconButton <IconButton
sx={{ sx={{
@ -427,7 +429,7 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
transition: 'transform 0.3s ease', transition: 'transform 0.3s ease',
marginRight: isMobile ? -1 : 0 marginRight: isMobile ? -1 : 0
}} }}
onClick={() => handleCollapse(index)}> onClick={(event) => handleCollapse(index, event)}>
<ChevronRight/> <ChevronRight/>
</IconButton> </IconButton>
</TableCell> </TableCell>

View file

@ -18,6 +18,10 @@ import SmartBreadcrumb from "common/SmartBreadcrumb";
import GroupActions from "group/GroupActions"; import GroupActions from "group/GroupActions";
// import CircleGraphIcon from "common/CircleGraphIcon"; // import CircleGraphIcon from "common/CircleGraphIcon";
import DevicesSummary from "device/DevicesSummary"; import DevicesSummary from "device/DevicesSummary";
import { GetDeviceProductIcon } from "products/DeviceProduct";
import BindaptIcon from "products/Bindapt/BindaptIcon";
import { describePower } from "pbHelpers/Power";
import moment from "moment";
const useStyles = makeStyles((theme: Theme) => { const useStyles = makeStyles((theme: Theme) => {
return ({ return ({
@ -359,6 +363,64 @@ export default function Devices() {
return group return group
} }
const mobile = (row: Device) => {
return (
<Box sx={{ margin: 2 }}>
<Grid2 spacing={1} container direction={"row"} justifyContent="space-between" alignItems={"center"}>
<Grid2 >
{/* {GetDeviceProductIcon(row)} */}
{/* {icon} */}
<BindaptIcon />
</Grid2>
<Grid2 size={{ xs: 9}}>
<Grid2 container direction="column">
<Grid2>
{row.name()}
</Grid2>
<Grid2>
Last Active: {moment(row.status.lastActive).fromNow()}
</Grid2>
</Grid2>
</Grid2>
<Grid2 >
{describePower(row.status.power).icon}
</Grid2>
</Grid2>
</Box>
)
}
const gutter = (row: Device) => {
return (
<Box sx={{ margin: 1 }}>
<Grid2 container spacing={1} direction="column">
<Grid2>
{row.settings.description}
</Grid2>
{row.status.plenum &&
<Grid2 container direction="row" spacing={0}>
<Grid2>
<Typography color={orange[400]}>
{row.status.plenum.temperature}°C
</Typography>
</Grid2>
<Grid2 >
<Typography marginRight={1}>
{", "}
</Typography>
</Grid2>
<Grid2>
<Typography color={blue[300]}>
{row.status.plenum.humidity}%
</Typography>
</Grid2>
</Grid2>
}
</Grid2>
</Box>
)
}
return( return(
<PageContainer padding={isMobile ? 0 : 2}> <PageContainer padding={isMobile ? 0 : 2}>
<Box <Box
@ -392,7 +454,9 @@ export default function Devices() {
title={<SmartBreadcrumb prependPaths={getGroup() && ["groups", getGroup().id().toString()]} groupName={getGroup() && getGroup().name()} paddingBottom={1}/>} title={<SmartBreadcrumb prependPaths={getGroup() && ["groups", getGroup().id().toString()]} groupName={getGroup() && getGroup().name()} paddingBottom={1}/>}
subtitle={subtitle()} subtitle={subtitle()}
rows={devices} rows={devices}
renderGutter={gutter}
columns={columns()} columns={columns()}
renderMobile={mobile}
total={total} total={total}
pageSize={limit} pageSize={limit}
page={page} page={page}

View file

@ -16,6 +16,9 @@ import {
import { NexusST } from "./Nexus/NexusDescriber"; import { NexusST } from "./Nexus/NexusDescriber";
import { MiPCAV2, OmniAir } from "./OmniAir/OmniAirDescriber"; import { MiPCAV2, OmniAir } from "./OmniAir/OmniAirDescriber";
import { ConfigurablePin } from "pbHelpers/AddressTypes"; import { ConfigurablePin } from "pbHelpers/AddressTypes";
import { useTheme } from "@mui/material";
import { Device } from "models";
import { or } from "utils";
export type ProductTab = "components" | "presets"; export type ProductTab = "components" | "presets";
@ -101,11 +104,12 @@ export function GetDeviceProductLabel(product: pond.DeviceProduct): string {
} }
export function GetDeviceProductIcon( export function GetDeviceProductIcon(
product: pond.DeviceProduct, device: pond.Device | Device
platform: pond.DevicePlatform,
theme?: "dark" | "light"
): string | undefined { ): string | undefined {
return getDescriber(product).icon(platform, theme); const theme = useTheme()
const product = or(device.settings?.product, pond.DeviceProduct.DEVICE_PRODUCT_NONE)
const platform = or(device.settings?.platform, pond.DevicePlatform.DEVICE_PLATFORM_INVALID)
return getDescriber(product).icon(platform, theme.palette.mode);
} }
export function IsCardController(product?: pond.DeviceProduct): boolean { export function IsCardController(product?: pond.DeviceProduct): boolean {