From 89f8af1e5c8a427b06a4e213d1fdade77ae090b8 Mon Sep 17 00:00:00 2001 From: Iván Ávalos Date: Thu, 18 Apr 2024 23:30:49 -0600 Subject: Show position attributes in device list --- src/main/DeviceList.jsx | 17 ++++++++--- src/main/DeviceRow.jsx | 81 +++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 88 insertions(+), 10 deletions(-) diff --git a/src/main/DeviceList.jsx b/src/main/DeviceList.jsx index eb51232f..3bb5f5e1 100644 --- a/src/main/DeviceList.jsx +++ b/src/main/DeviceList.jsx @@ -1,11 +1,12 @@ import React, { useEffect, useRef, useState } from 'react'; import { useDispatch } from 'react-redux'; import makeStyles from '@mui/styles/makeStyles'; -import { FixedSizeList } from 'react-window'; +import { VariableSizeList } from 'react-window'; import AutoSizer from 'react-virtualized-auto-sizer'; import { devicesActions } from '../store'; import { useEffectAsync } from '../reactHelper'; import DeviceRow from './DeviceRow'; +import { useAttributePreference } from '../common/util/preferences'; const useStyles = makeStyles((theme) => ({ list: { @@ -28,6 +29,8 @@ const DeviceList = ({ devices }) => { const [, setTime] = useState(Date.now()); + const positionItems = useAttributePreference('positionItems', 'speed,address,totalDistance,course'); + useEffect(() => { const interval = setInterval(() => setTime(Date.now()), 60000); return () => { @@ -44,20 +47,26 @@ const DeviceList = ({ devices }) => { } }, []); + // RATIONALE: calculate row height to fit position attributes + const getItemSize = (index) => { + const item = devices[index]; + return 72 + (item.positionId && (positionItems.split(',').length * 20) || 0); + }; + return ( {({ height, width }) => ( - {DeviceRow} - + )} ); diff --git a/src/main/DeviceRow.jsx b/src/main/DeviceRow.jsx index d9c1a189..8399da22 100644 --- a/src/main/DeviceRow.jsx +++ b/src/main/DeviceRow.jsx @@ -2,14 +2,20 @@ import React from 'react'; import { useDispatch, useSelector } from 'react-redux'; import makeStyles from '@mui/styles/makeStyles'; import { - IconButton, Tooltip, Avatar, ListItemAvatar, ListItemText, ListItemButton, + IconButton, Tooltip, Avatar, ListItemAvatar, ListItemText, ListItemButton, Stack, } from '@mui/material'; +import LockIcon from '@mui/icons-material/Lock'; +import LockOpenIcon from '@mui/icons-material/LockOpen'; import BatteryFullIcon from '@mui/icons-material/BatteryFull'; import BatteryChargingFullIcon from '@mui/icons-material/BatteryChargingFull'; import Battery60Icon from '@mui/icons-material/Battery60'; import BatteryCharging60Icon from '@mui/icons-material/BatteryCharging60'; import Battery20Icon from '@mui/icons-material/Battery20'; import BatteryCharging20Icon from '@mui/icons-material/BatteryCharging20'; +import SpeedIcon from '@mui/icons-material/Speed'; +import ScheduleIcon from '@mui/icons-material/Schedule'; +import PlaceIcon from '@mui/icons-material/Place'; +import AvTimerIcon from '@mui/icons-material/AvTimer'; import ErrorIcon from '@mui/icons-material/Error'; import dayjs from 'dayjs'; import relativeTime from 'dayjs/plugin/relativeTime'; @@ -22,6 +28,8 @@ import { mapIconKey, mapIcons } from '../map/core/preloadImages'; import { useAdministrator } from '../common/util/permissions'; import EngineIcon from '../resources/images/data/engine.svg?react'; import { useAttributePreference } from '../common/util/preferences'; +import usePositionAttributes from '../common/attributes/usePositionAttributes'; +import PositionValue from '../common/components/PositionValue'; dayjs.extend(relativeTime); @@ -63,6 +71,9 @@ const DeviceRow = ({ data, index, style }) => { const devicePrimary = useAttributePreference('devicePrimary', 'name'); const deviceSecondary = useAttributePreference('deviceSecondary', ''); + const positionAttributes = usePositionAttributes(t); + const positionItems = useAttributePreference('positionItems', 'speed,address,totalDistance,course'); + const secondaryText = () => { let status; if (item.status === 'online' || !item.lastUpdate) { @@ -74,10 +85,45 @@ const DeviceRow = ({ data, index, style }) => { <> {deviceSecondary && item[deviceSecondary] && `${item[deviceSecondary]} • `} {status} + {/* RATIONALE: clients want more info in the list */} + {position && positionItems.split(',').filter((key) => position.hasOwnProperty(key) || position.attributes.hasOwnProperty(key)).map((key) => ( + + )} + /> + ))} ); }; + // RATIONALE: we connect output/out1 to engine lock + const positionLock = () => { + let lock = false; + if (position.attributes.output !== undefined) { + lock = position.attributes.output === 1; + } else if (position.attributes.out1 !== undefined) { + lock = position.attributes.out1; + } else { + return <>; + } + + return ( + { + (lock) + ? + : + } + ) + }; + return (
{ + primary={item[devicePrimary]} + primaryTypographyProps={{ noWrap: true }} + secondary={secondaryText()} + secondaryTypographyProps={{ noWrap: true }} + /> {position && ( <> {position.attributes.hasOwnProperty('alarm') && ( @@ -105,6 +151,8 @@ const DeviceRow = ({ data, index, style }) => { )} + {/* RATIONALE: clients want engine lock at a glance */} + {positionLock()} {position.attributes.hasOwnProperty('ignition') && ( @@ -142,4 +190,25 @@ const DeviceRow = ({ data, index, style }) => { ); }; +const AttrItem = ({ attr, name, content }) => { + const attrIcon = () => { + switch(attr) { + case "address": return ; + case "deviceTime": return ; + case "fixTime": return ; + case "hours": return ; + case "serverTime": return ; + case "speed": return ; + default: return {name}; + } + }; + + return ( + <> +

+ {attrIcon()} {content} + + ); +}; + export default DeviceRow; -- cgit v1.2.3