loading device page with relative pathing
This commit is contained in:
parent
05f7765f82
commit
438451690b
8 changed files with 235 additions and 21 deletions
|
|
@ -12,6 +12,7 @@ import TeamPage from "pages/Team";
|
|||
import Header from "app/Header";
|
||||
import Logout from "pages/Logout";
|
||||
import Devices from "pages/Devices";
|
||||
import DevicePage from "pages/Device";
|
||||
|
||||
interface Props {
|
||||
open: boolean,
|
||||
|
|
@ -31,7 +32,7 @@ export default function Router(props: Props) {
|
|||
return (
|
||||
<Routes>
|
||||
<Route path="teams/*" element={<TeamsRoute/>} />
|
||||
<Route path="devices" element={<DevicesRoute/>} />
|
||||
<Route path="devices/*" element={<DevicesRoute/>} />
|
||||
</Routes>
|
||||
)
|
||||
}
|
||||
|
|
@ -65,10 +66,10 @@ export default function Router(props: Props) {
|
|||
path="" // "/settings/basic"
|
||||
element={<Devices />}
|
||||
/>
|
||||
{/* <Route
|
||||
<Route
|
||||
path="/:deviceID" // "/settings/basic"
|
||||
element={<TeamPage />}
|
||||
/> */}
|
||||
element={<DevicePage />}
|
||||
/>
|
||||
</Routes>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
60
src/pages/Device.tsx
Normal file
60
src/pages/Device.tsx
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
import { Theme, Typography } from "@mui/material";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
import { Device } from "models";
|
||||
import { getContextKeys, getContextTypes } from "pbHelpers/Context";
|
||||
import { useDeviceAPI, useSnackbar } from "providers";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useLocation, useParams } from "react-router-dom";
|
||||
import PageContainer from "./PageContainer";
|
||||
import { useMobile } from "hooks";
|
||||
import LoadingScreen from "app/LoadingScreen";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => {
|
||||
// const isMobile = useMobile()
|
||||
return ({
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
export default function DevicePage() {
|
||||
|
||||
const deviceAPI = useDeviceAPI()
|
||||
const snackbar = useSnackbar()
|
||||
const isMobile = useMobile()
|
||||
const deviceID = useParams<{ deviceID: string }>()?.deviceID ?? "";
|
||||
const { state } = useLocation();
|
||||
const [device, setDevice] = useState<Device>(state?.device ? Device.create(state.device) : Device.create())
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const loadDevice = () => {
|
||||
if (loading) return
|
||||
if (state?.device && parseInt(state.device.settings.deviceId) === device.id()) return
|
||||
deviceAPI.get(deviceID, false, getContextKeys(), getContextTypes()).then(resp => {
|
||||
setDevice(Device.create(resp.data))
|
||||
}).catch(() => {
|
||||
snackbar.error("Error loading device.")
|
||||
}).finally(() => {
|
||||
setLoading(false)
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
console.log(device)
|
||||
}, [device])
|
||||
|
||||
useEffect(() => {
|
||||
loadDevice()
|
||||
}, [])
|
||||
|
||||
if (loading) return (
|
||||
<LoadingScreen message="Loading device"/>
|
||||
)
|
||||
|
||||
return (
|
||||
<PageContainer padding={isMobile ? 0 : 2}>
|
||||
<Typography>
|
||||
{device.name()}
|
||||
</Typography>
|
||||
</PageContainer>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { DeveloperBoard as ProvisionIcon } from "@mui/icons-material";
|
||||
import { IconButton, Theme, Tooltip, Typography } from "@mui/material";
|
||||
import { Box, Chip, IconButton, Theme, Tooltip, Typography } from "@mui/material";
|
||||
import { blue } from "@mui/material/colors";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
import ResponsiveTable, { Column } from "common/ResponsiveTable";
|
||||
|
|
@ -12,6 +12,7 @@ import { useMobile } from "hooks";
|
|||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import { or } from "utils/types";
|
||||
import { getContextKeys, getContextTypes } from "pbHelpers/Context";
|
||||
import { getDeviceStateHelper } from "pbHelpers/DeviceState";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => {
|
||||
return ({
|
||||
|
|
@ -19,7 +20,10 @@ const useStyles = makeStyles((theme: Theme) => {
|
|||
color: blue["700"]
|
||||
},
|
||||
cellContainer: {
|
||||
padding: theme.spacing(1)
|
||||
margin: theme.spacing(1),
|
||||
marginLeft: theme.spacing(2),
|
||||
display: "flex",
|
||||
// justifyContent: "center",
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -82,20 +86,61 @@ export default function Devices() {
|
|||
};
|
||||
|
||||
const toDevice = (device: pond.Device) => {
|
||||
navigate(appendToUrl(or(device.settings?.deviceId, "")))
|
||||
navigate(appendToUrl(or(device.settings?.deviceId, "")), { state: {device: device} })
|
||||
};
|
||||
|
||||
const columns = (): Column<pond.Device>[] => {
|
||||
return [{
|
||||
title: "Device",
|
||||
render: (device) => {
|
||||
return (
|
||||
<Typography className={classes.cellContainer}>
|
||||
{device.settings?.name ? device.settings.name : "Device " + device.settings?.deviceId}
|
||||
</Typography>
|
||||
)
|
||||
}
|
||||
}]
|
||||
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 > 10
|
||||
? description.substring(0, 10) + "..."
|
||||
: description}
|
||||
</span>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
const provisionButton= () => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { useMobile } from "hooks";
|
||||
import PageContainer from "pages/PageContainer";
|
||||
import { Outlet } from "react-router-dom";
|
||||
import TeamList from "teams/TeamList";
|
||||
|
||||
export default function Teams() {
|
||||
|
|
@ -8,7 +7,6 @@ export default function Teams() {
|
|||
return (
|
||||
<PageContainer padding={isMobile ? 0 : 2}>
|
||||
<TeamList />
|
||||
<Outlet/>
|
||||
</PageContainer>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
101
src/pbHelpers/DeviceState.tsx
Normal file
101
src/pbHelpers/DeviceState.tsx
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
import {
|
||||
CheckCircle as OKIcon,
|
||||
Error as AlarmingIcon,
|
||||
Help as UnknownIcon,
|
||||
Warning as WarningIcon
|
||||
} from "@mui/icons-material";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { getTextSecondary } from "theme/text";
|
||||
|
||||
export interface DeviceStateHelper {
|
||||
description: string;
|
||||
icon: any;
|
||||
colour: string;
|
||||
}
|
||||
|
||||
const Unknown: DeviceStateHelper = {
|
||||
description: "Unknown",
|
||||
icon: <UnknownIcon style={{ color: "var(--status-unknown)" }} />,
|
||||
colour: "var(--status-unknown)"
|
||||
};
|
||||
|
||||
const OK: DeviceStateHelper = {
|
||||
description: "OK",
|
||||
icon: <OKIcon style={{ color: "var(--status-ok)" }} />,
|
||||
colour: "var(--status-ok)"
|
||||
};
|
||||
|
||||
const LowPower: DeviceStateHelper = {
|
||||
description: "Low Power",
|
||||
icon: <WarningIcon style={{ color: "var(--status-warning)" }} />,
|
||||
colour: "var(--status-warning)"
|
||||
};
|
||||
|
||||
const Missing: DeviceStateHelper = {
|
||||
description: "Missing",
|
||||
icon: <AlarmingIcon style={{ color: getTextSecondary() }} />,
|
||||
colour: getTextSecondary()
|
||||
};
|
||||
|
||||
const DEVICE_STATE_MAP = new Map<pond.DeviceState, DeviceStateHelper>([
|
||||
[pond.DeviceState.DEVICE_STATE_UNKNOWN, Unknown],
|
||||
[pond.DeviceState.DEVICE_STATE_OK, OK],
|
||||
[pond.DeviceState.DEVICE_STATE_LOW_POWER, LowPower],
|
||||
[pond.DeviceState.DEVICE_STATE_MISSING, Missing]
|
||||
]);
|
||||
|
||||
export function compareEnum<T>(value: string | number, enumMember: T): boolean {
|
||||
// Get the enum object from the enum member
|
||||
const enumObj = Object.freeze(enumMember as any).constructor;
|
||||
|
||||
// Check if the value matches either the key or the value of the enum member
|
||||
return Object.keys(enumObj).some(
|
||||
key => enumObj[key] === value || key === value
|
||||
);
|
||||
}
|
||||
|
||||
export function getDeviceStateHelper(state: pond.DeviceState): DeviceStateHelper {
|
||||
if (compareEnum(state, pond.DeviceState.DEVICE_STATE_OK)) {
|
||||
return OK;
|
||||
}
|
||||
const deviceStates = Array.from(DEVICE_STATE_MAP.keys());
|
||||
for (var i = 0; i < deviceStates.length; i++) {
|
||||
let key = deviceStates[i];
|
||||
if (state === key) {
|
||||
return DEVICE_STATE_MAP.get(key) as DeviceStateHelper;
|
||||
}
|
||||
}
|
||||
return Unknown;
|
||||
}
|
||||
|
||||
export function getDeviceStateDescription(state: pond.DeviceState): string {
|
||||
return getDeviceStateHelper(state).description;
|
||||
}
|
||||
|
||||
export function getDeviceStateIcon(state: pond.DeviceState): any {
|
||||
return getDeviceStateHelper(state).icon;
|
||||
}
|
||||
|
||||
export function getDeviceStateColour(state: pond.DeviceState): any {
|
||||
return getDeviceStateHelper(state).colour;
|
||||
}
|
||||
|
||||
export function filterByDeviceState(searchValue: string, state: pond.DeviceState) {
|
||||
let matches: string[] = [];
|
||||
switch (state) {
|
||||
case pond.DeviceState.DEVICE_STATE_OK:
|
||||
matches = ["okay", "good", "safe", "stable"];
|
||||
break;
|
||||
case pond.DeviceState.DEVICE_STATE_MISSING:
|
||||
matches = ["alarming", "alarmed", "bad", "error", "alert"];
|
||||
break;
|
||||
case pond.DeviceState.DEVICE_STATE_LOW_POWER:
|
||||
matches = ["warning", "caution", "low power"];
|
||||
break;
|
||||
default:
|
||||
matches = ["unknown", "?"];
|
||||
break;
|
||||
}
|
||||
|
||||
return matches.some(match => match.indexOf(searchValue.replace("state:", "").trim()) > -1);
|
||||
}
|
||||
|
|
@ -6,7 +6,6 @@ import { createContext, PropsWithChildren, useContext } from "react";
|
|||
import { pondURL } from "./pond";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { useGlobalState } from "providers";
|
||||
import { dateRange } from "providers/http";
|
||||
import moment from "moment";
|
||||
|
||||
export interface IDeviceAPIContext {
|
||||
|
|
|
|||
|
|
@ -138,7 +138,6 @@ export default function TeamList() {
|
|||
if (preferences) {
|
||||
let newTeamPrefs = cloneDeep(teamPrefs);
|
||||
let prefs = newTeamPrefs.get(team.id()) ?? pond.TeamPreferences.create()
|
||||
console.log(prefs)
|
||||
prefs.notify = !newTeamPrefs.get(team.id())?.notify
|
||||
newTeamPrefs.set(team.id(), prefs)
|
||||
teamAPI
|
||||
|
|
|
|||
11
src/theme/text.ts
Normal file
11
src/theme/text.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { getThemeType } from "./themeType";
|
||||
|
||||
export function getTextPrimary() {
|
||||
let themeType = getThemeType();
|
||||
return themeType === "light" ? "rgba(0, 0, 0, 0.87)" : "#FFF";
|
||||
}
|
||||
|
||||
export function getTextSecondary() {
|
||||
let themeType = getThemeType();
|
||||
return themeType === "light" ? "rgba(0, 0, 0, 0.54)" : "rgba(255, 255, 255, 0.7)";
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue