component cards imported

This commit is contained in:
Carter 2025-02-21 15:47:45 -06:00
parent 538c807766
commit af4cc08d87
4 changed files with 330 additions and 62 deletions

View file

@ -3,12 +3,10 @@ import {
DialogActions, DialogActions,
DialogContent, DialogContent,
DialogTitle, DialogTitle,
makeStyles,
Step, Step,
StepLabel, StepLabel,
Stepper, Stepper,
createStyles, Grid2 as Grid,
Grid,
FormControlLabel, FormControlLabel,
Switch, Switch,
Table, Table,
@ -19,19 +17,20 @@ import {
Box, Box,
Typography, Typography,
Checkbox Checkbox
} from "@material-ui/core"; } from "@mui/material";
import ResponsiveDialog from "common/ResponsiveDialog"; import ResponsiveDialog from "common/ResponsiveDialog";
import { Component, Device } from "models"; import { Component, Device } from "models";
import { pond, quack } from "protobuf-ts/pond"; import { pond, quack } from "protobuf-ts/pond";
import { useComponentAPI, useSnackbar } from "providers"; import { useComponentAPI, useSnackbar } from "providers";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { getThemeType } from "theme";
import { CableInfo } from "./ComponentDiagnostics"; import { CableInfo } from "./ComponentDiagnostics";
import ComponentForm from "./ComponentForm"; import ComponentForm from "./ComponentForm";
import { getThemeType } from "theme/themeType";
import { makeStyles } from "@mui/styles";
const useStyles = makeStyles(() => const useStyles = makeStyles(() => {
createStyles({ return ({
buttons: { buttons: {
marginLeft: 5, marginLeft: 5,
marginRight: 5 marginRight: 5
@ -48,7 +47,7 @@ const useStyles = makeStyles(() =>
padding: 0 padding: 0
} }
}) })
); });
interface Props { interface Props {
open: boolean; open: boolean;
@ -147,8 +146,8 @@ export default function AddCompsFromDiag(props: Props) {
const simpleActions = () => { const simpleActions = () => {
return ( return (
<DialogActions> <DialogActions>
<Grid container direction="row" justify="space-between"> <Grid container direction="row" justifyContent="space-between">
<Grid item> <Grid>
<Button <Button
variant="contained" variant="contained"
color="primary" color="primary"
@ -158,7 +157,7 @@ export default function AddCompsFromDiag(props: Props) {
Cancel Cancel
</Button> </Button>
</Grid> </Grid>
<Grid item> <Grid>
<Button <Button
className={classes.buttons} className={classes.buttons}
variant="contained" variant="contained"
@ -177,8 +176,8 @@ export default function AddCompsFromDiag(props: Props) {
const advancedActions = () => { const advancedActions = () => {
return ( return (
<DialogActions> <DialogActions>
<Grid container direction="row" justify="space-between"> <Grid container direction="row" justifyContent="space-between">
<Grid item> <Grid>
<Button <Button
variant="contained" variant="contained"
color="primary" color="primary"
@ -188,7 +187,7 @@ export default function AddCompsFromDiag(props: Props) {
Cancel Cancel
</Button> </Button>
</Grid> </Grid>
<Grid item> <Grid>
{currentStep !== 0 && ( {currentStep !== 0 && (
<Button <Button
className={classes.buttons} className={classes.buttons}
@ -328,9 +327,9 @@ export default function AddCompsFromDiag(props: Props) {
close(); close();
}}> }}>
<DialogTitle> <DialogTitle>
<Grid container direction="row" justify="space-between"> <Grid container direction="row" justifyContent="space-between">
<Grid item>Port {port} Components</Grid> <Grid >Port {port} Components</Grid>
<Grid item> <Grid >
<FormControlLabel <FormControlLabel
control={ control={
<Switch <Switch

View file

@ -1,17 +1,14 @@
import { import {
createStyles,
Divider, Divider,
IconButton, IconButton,
ListItemIcon, ListItemIcon,
ListItemText, ListItemText,
makeStyles,
Menu, Menu,
MenuItem, MenuItem,
Theme,
Tooltip Tooltip
} from "@material-ui/core"; } from "@mui/material";
import { green, teal } from "@material-ui/core/colors"; import { AddCircle, DeleteOutline, MoreVert, SaveAlt, Settings } from "@mui/icons-material";
import { Theme } from "@material-ui/core/styles/createMuiTheme";
import { AddCircle, DeleteOutline, MoreVert, SaveAlt, Settings } from "@material-ui/icons";
import ExportDataSettings from "component/ExportDataSettings"; import ExportDataSettings from "component/ExportDataSettings";
import InteractionSettings from "interactions/InteractionSettings"; import InteractionSettings from "interactions/InteractionSettings";
import { Component, Device } from "models"; import { Component, Device } from "models";
@ -23,9 +20,11 @@ import { useGlobalState } from "providers";
import React, { useState } from "react"; import React, { useState } from "react";
import { or } from "utils/types"; import { or } from "utils/types";
import ComponentSettings from "./ComponentSettings"; import ComponentSettings from "./ComponentSettings";
import { green, teal } from "@mui/material/colors";
import { makeStyles } from "@mui/styles";
const useStyles = makeStyles((theme: Theme) => const useStyles = makeStyles((_theme: Theme) => {
createStyles({ return ({
addIcon: { addIcon: {
color: green["500"], color: green["500"],
"&:hover": { "&:hover": {
@ -48,7 +47,7 @@ const useStyles = makeStyles((theme: Theme) =>
color: "var(--status-alert)" color: "var(--status-alert)"
} }
}) })
); });
interface Props { interface Props {
device: Device; device: Device;
@ -83,7 +82,7 @@ export default function ComponentActions(props: Props) {
const [anchorEl, setAnchorEl] = useState<Element | null>(null); const [anchorEl, setAnchorEl] = useState<Element | null>(null);
const [componentSettingsMode, setComponentSettingsMode] = useState<string>(""); const [componentSettingsMode, setComponentSettingsMode] = useState<string>("");
const [isJSON, setIsJSON] = useState(false); const [isJSON, setIsJSON] = useState(false);
const [{ user, newStructure }] = useGlobalState(); const [{ user }] = useGlobalState();
const openMoreMenu = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => { const openMoreMenu = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
setAnchorEl(event.currentTarget); setAnchorEl(event.currentTarget);
@ -115,7 +114,7 @@ export default function ComponentActions(props: Props) {
onClose={closeMoreMenu} onClose={closeMoreMenu}
disableAutoFocusItem> disableAutoFocusItem>
{canAddInteraction && ( {canAddInteraction && (
<MenuItem dense onClick={() => setIsAddInteractionOpen(true)} button divider> <MenuItem dense onClick={() => setIsAddInteractionOpen(true)} divider>
<ListItemIcon> <ListItemIcon>
<AddCircle className={classes.addIcon} /> <AddCircle className={classes.addIcon} />
</ListItemIcon> </ListItemIcon>
@ -129,7 +128,7 @@ export default function ComponentActions(props: Props) {
setIsExportDataOpen(true); setIsExportDataOpen(true);
}}> }}>
<ListItemIcon> <ListItemIcon>
<SaveAlt fontSize="default" className={classes.exportDataIcon} /> <SaveAlt className={classes.exportDataIcon} />
</ListItemIcon> </ListItemIcon>
<ListItemText primary="Export Data" /> <ListItemText primary="Export Data" />
</MenuItem> </MenuItem>
@ -137,7 +136,7 @@ export default function ComponentActions(props: Props) {
{canEdit && ( {canEdit && (
<MenuItem dense onClick={() => openComponentSettingsDialog("remove")}> <MenuItem dense onClick={() => openComponentSettingsDialog("remove")}>
<ListItemIcon> <ListItemIcon>
<DeleteOutline fontSize="default" className={classes.red} /> <DeleteOutline className={classes.red} />
</ListItemIcon> </ListItemIcon>
<ListItemText primary="Delete" /> <ListItemText primary="Delete" />
</MenuItem> </MenuItem>
@ -173,7 +172,7 @@ export default function ComponentActions(props: Props) {
refreshCallback={refreshCallback} refreshCallback={refreshCallback}
canEdit={canEdit} canEdit={canEdit}
/> />
<ExportDataSettings {/* <ExportDataSettings
device={device} device={device}
component={component} component={component}
isDialogOpen={isExportDataOpen} isDialogOpen={isExportDataOpen}
@ -181,9 +180,9 @@ export default function ComponentActions(props: Props) {
initialStartDate={initialStartDate} initialStartDate={initialStartDate}
initialEndDate={initialEndDate} initialEndDate={initialEndDate}
isJSON={isJSON} isJSON={isJSON}
newMeasurements={newStructure} // newMeasurements={newStructure}
user={user} user={user}
/> /> */}
</React.Fragment> </React.Fragment>
); );
}; };
@ -195,7 +194,7 @@ export default function ComponentActions(props: Props) {
aria-label="Component Settings" aria-label="Component Settings"
onOpen={event => event.stopPropagation()}> onOpen={event => event.stopPropagation()}>
<IconButton color="default" onClick={() => openComponentSettingsDialog("")}> <IconButton color="default" onClick={() => openComponentSettingsDialog("")}>
<Settings fontSize="default" /> <Settings />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<Tooltip title="More"> <Tooltip title="More">

View file

@ -1,15 +1,16 @@
import { Box, Grid, Typography, makeStyles, createStyles, Theme } from "@material-ui/core"; import { Box, Grid2 as Grid, Typography, Theme, Divider } from "@mui/material";
import GrainDescriber from "grain/GrainDescriber"; import GrainDescriber from "grain/GrainDescriber";
import { Component } from "models"; import { Component } from "models";
import { convertedUnitMeasurement } from "models/UnitMeasurement"; import { convertedUnitMeasurement } from "models/UnitMeasurement";
import moment from "moment"; import moment from "moment";
import { pond } from "protobuf-ts/pond"; import { pond } from "protobuf-ts/pond";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import Divider from "@material-ui/core/Divider"; // import Divider from "@material-ui/core/Divider";
import { Plenum } from "models/Plenum"; import { Plenum } from "models/Plenum";
import { Pressure } from "models/Pressure"; import { Pressure } from "models/Pressure";
import { GrainCable } from "models/GrainCable"; import { GrainCable } from "models/GrainCable";
import { extension, Summary } from "pbHelpers/ComponentType"; import { extension, Summary } from "pbHelpers/ComponentType";
import { makeStyles } from "@mui/styles";
interface Props { interface Props {
component: Component | Plenum | Pressure | GrainCable; component: Component | Plenum | Pressure | GrainCable;
@ -24,8 +25,8 @@ interface Props {
excludedNodes?: number[]; excludedNodes?: number[];
} }
const useStyles = makeStyles((theme: Theme) => const useStyles = makeStyles((theme: Theme) => {
createStyles({ return ({
"@keyframes ripple": { "@keyframes ripple": {
from: { from: {
transform: "scale(.8)", transform: "scale(.8)",
@ -50,7 +51,7 @@ const useStyles = makeStyles((theme: Theme) =>
margin: theme.spacing(1) margin: theme.spacing(1)
} }
}) })
); });
export default function UnitMeasurementSummary(props: Props) { export default function UnitMeasurementSummary(props: Props) {
const { const {
@ -112,7 +113,7 @@ export default function UnitMeasurementSummary(props: Props) {
let grain = GrainDescriber(component.settings.grainType); let grain = GrainDescriber(component.settings.grainType);
return ( return (
<Grid container> <Grid container>
<Grid item xs={12}> <Grid size={{ xs: 12 }}>
<Typography variant={largeText ? "body1" : "caption"} color="textPrimary"> <Typography variant={largeText ? "body1" : "caption"} color="textPrimary">
{summaries.map((summary: Summary, index: number) => { {summaries.map((summary: Summary, index: number) => {
let sumVal = summary.value; let sumVal = summary.value;
@ -133,7 +134,7 @@ export default function UnitMeasurementSummary(props: Props) {
if (found) { if (found) {
overlays.push( overlays.push(
<React.Fragment key={"overlay" + index}> <React.Fragment key={"overlay" + index}>
<Grid item> <Grid >
<Box <Box
width="20px" width="20px"
height="20px" height="20px"
@ -142,7 +143,7 @@ export default function UnitMeasurementSummary(props: Props) {
style={{ background: overlay.colour }} style={{ background: overlay.colour }}
/> />
</Grid> </Grid>
<Grid item> <Grid >
<Typography <Typography
variant={largeText ? "body1" : "caption"} variant={largeText ? "body1" : "caption"}
component="span" component="span"
@ -178,7 +179,7 @@ export default function UnitMeasurementSummary(props: Props) {
</Typography> </Typography>
)} )}
{!props.omitTime && ( {!props.omitTime && (
<Grid item xs={12}> <Grid size={{ xs: 12 }}>
<Typography color="textSecondary" variant={largeText ? "body1" : "caption"}> <Typography color="textSecondary" variant={largeText ? "body1" : "caption"}>
{moment(timestamp).fromNow()} {moment(timestamp).fromNow()}
</Typography> </Typography>
@ -186,7 +187,7 @@ export default function UnitMeasurementSummary(props: Props) {
)} )}
{overlays.length > 0 && ( {overlays.length > 0 && (
<React.Fragment> <React.Fragment>
<Grid item xs={12}> <Grid size={{ xs: 12 }}>
<Divider variant="middle" className={classes.divider} /> <Divider variant="middle" className={classes.divider} />
</Grid> </Grid>
<Grid container direction="row"> <Grid container direction="row">
@ -205,11 +206,11 @@ export default function UnitMeasurementSummary(props: Props) {
const blacklist: Array<any> = []; const blacklist: Array<any> = [];
const filteredSummaries = summaries.filter((item: any) => !blacklist.includes(item.label)); const filteredSummaries = summaries.filter((item: any) => !blacklist.includes(item.label));
return ( return (
<Grid container direction="row" justify={centered ? "center" : "flex-start"} spacing={1}> <Grid container direction="row" justifyContent={centered ? "center" : "flex-start"} spacing={1}>
{filteredSummaries.map((summary: Summary, i: number) => { {filteredSummaries.map((summary: Summary, i: number) => {
let sumVal = summary.value; let sumVal = summary.value;
return ( return (
<Grid item key={"summary-" + i}> <Grid key={"summary-" + i}>
{summary.label} {summary.label}
{summary.error && <span style={{ color: "red" }}>{" [error(s)]"}</span>} {summary.error && <span style={{ color: "red" }}>{" [error(s)]"}</span>}
{": "} {": "}
@ -257,7 +258,7 @@ export default function UnitMeasurementSummary(props: Props) {
if (found) { if (found) {
overlays.push( overlays.push(
<React.Fragment key={"overlay" + i}> <React.Fragment key={"overlay" + i}>
<Grid item> <Grid >
<Box <Box
width="20px" width="20px"
height="20px" height="20px"
@ -266,7 +267,7 @@ export default function UnitMeasurementSummary(props: Props) {
style={{ background: overlay.colour }} style={{ background: overlay.colour }}
/> />
</Grid> </Grid>
<Grid item> <Grid >
<Typography <Typography
variant={largeText ? "body1" : "caption"} variant={largeText ? "body1" : "caption"}
component="span" component="span"

View file

@ -1,5 +1,5 @@
import { Button, Grid2 } from "@mui/material"; import { Button, Checkbox, Divider, FormControlLabel, Grid2 as Grid, List, ListItem, Typography } from "@mui/material";
import { Component, Device, User } from "models"; import { Component, Device, Interaction, User } from "models";
import { getContextKeys, getContextTypes } from "pbHelpers/Context"; import { getContextKeys, getContextTypes } from "pbHelpers/Context";
import { useDeviceAPI, useGlobalState, useSnackbar } from "providers"; import { useDeviceAPI, useGlobalState, useSnackbar } from "providers";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
@ -9,11 +9,16 @@ import { useMobile } from "hooks";
import LoadingScreen from "app/LoadingScreen"; import LoadingScreen from "app/LoadingScreen";
import SmartBreadcrumb from "common/SmartBreadcrumb"; import SmartBreadcrumb from "common/SmartBreadcrumb";
import DeviceActions from "device/DeviceActions"; import DeviceActions from "device/DeviceActions";
import { pond } from "protobuf-ts/pond"; import { pond, quack } from "protobuf-ts/pond";
import { cloneDeep } from "lodash"; import { cloneDeep } from "lodash";
import DeviceOverview from "device/DeviceOverview"; import DeviceOverview from "device/DeviceOverview";
import { DeviceAvailabilityMap, FindAvailablePositions, OffsetAvailabilityMap } from "pbHelpers/DeviceAvailability"; import { DeviceAvailabilityMap, FindAvailablePositions, OffsetAvailabilityMap } from "pbHelpers/DeviceAvailability";
import AddComponentManualDialog from "component/AddComponentManualDialog"; import AddComponentManualDialog from "component/AddComponentManualDialog";
import ComponentCard from "component/ComponentCard";
import { sameComponentID, sortComponents } from "pbHelpers/Component";
import { isController } from "pbHelpers/ComponentType";
import { or } from "utils";
import ComponentDiagnostics from "component/ComponentDiagnostics";
export default function DevicePage() { export default function DevicePage() {
const deviceAPI = useDeviceAPI() const deviceAPI = useDeviceAPI()
@ -28,15 +33,19 @@ export default function DevicePage() {
const [permissions, setPermissions] = useState<pond.Permission[]>([]) const [permissions, setPermissions] = useState<pond.Permission[]>([])
const [preferences, setPreferences] = useState<pond.DevicePreferences>(pond.DevicePreferences.create()) const [preferences, setPreferences] = useState<pond.DevicePreferences>(pond.DevicePreferences.create())
const [tags, setTags] = useState<pond.Tag[]>([]); const [tags, setTags] = useState<pond.Tag[]>([]);
const [interactions, setInteractions] = useState<Interaction[]>([]);
const [prefsMap, setPrefsMap] = useState<Map<string, pond.DeviceComponentPreferences>>(new Map());
const [cellularUsage, _setCellularUsage] = useState<number>(0); const [cellularUsage, _setCellularUsage] = useState<number>(0);
const [cellularStatus, _setCellularStatus] = useState<string>(""); const [cellularStatus, _setCellularStatus] = useState<string>("");
const [availablePositions, setAvailablePositions] = useState<DeviceAvailabilityMap>(new Map()); const [availablePositions, setAvailablePositions] = useState<DeviceAvailabilityMap>(new Map());
const [availableOffsets, setAvailableOffsets] = useState<OffsetAvailabilityMap>(new Map()); const [availableOffsets, setAvailableOffsets] = useState<OffsetAvailabilityMap>(new Map());
const [displayOrder, setDisplayOrder] = useState<string[]>([]);
// const [components, setComponents] = useState<Map<string, Component>>(new Map()); const [components, setComponents] = useState<Map<string, Component>>(new Map());
const [components, setComponents] = useState<Component[]>([]); const [diagnosticComponents, setDiagnosticComponents] = useState<Component[]>([]);
// const [components, setComponents] = useState<Component[]>([]);
const [addComponentManualDialogOpen, setAddComponentManualDialogOpen] = useState(false) const [addComponentManualDialogOpen, setAddComponentManualDialogOpen] = useState(false)
@ -70,7 +79,42 @@ export default function DevicePage() {
device.settings.product device.settings.product
); );
setAvailablePositions(available.GetAvailability()); setAvailablePositions(available.GetAvailability());
setComponents(newComps) let rawComponents: Array<any> = or(resp.data.components, []);
let rComponents: Map<string, Component> = new Map();
let diagComponents: Component[] = [];
rawComponents.forEach((rawComponent: any) => {
let component = Component.any(rawComponent);
rComponents.set(component.key(), component);
//check if is a diagnostic component
switch (component.type()) {
case quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE:
if (component.subType() === quack.GrainCableSubtype.GRAIN_CABLE_SUBTYPE_OPI_DIAG) {
diagComponents.push(component);
}
}
});
setComponents(rComponents)
let interactions: Interaction[] = [];
resp.data.interactions.forEach((interaction: pond.Interaction) => {
if (
interaction.settings &&
interaction.settings.nodeOne > interaction.settings.nodeTwo &&
interaction.settings.nodeTwo !== 0
) {
//flip operator and send negative comparitor to save
interaction.settings.conditions.forEach(condition => {
//coming back from the backend as a string for some reason
if (condition.comparison.toString() === "RELATIONAL_OPERATOR_GREATER_THAN") {
condition.comparison = quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN;
} else {
condition.comparison = quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN;
}
condition.value = condition.value * -1;
});
}
interactions.push(Interaction.any(interaction));
});
setInteractions(interactions);
}).catch(err => { }).catch(err => {
setDevice(Device.create()); setDevice(Device.create());
// setComponents(new Map()); // setComponents(new Map());
@ -95,6 +139,10 @@ export default function DevicePage() {
.finally(() => setLoading(false)); .finally(() => setLoading(false));
} }
useEffect(() => {
console.log(components)
}, [components])
useEffect(() => { useEffect(() => {
loadDevice() loadDevice()
}, [deviceID]) }, [deviceID])
@ -126,13 +174,233 @@ export default function DevicePage() {
return usage; return usage;
}; };
const displayedComponentsBlacklist = [
quack.ComponentType.COMPONENT_TYPE_POWER,
quack.ComponentType.COMPONENT_TYPE_MODEM
];
const getOrderedComponents = () => {
let compsToOrder: Component[] = [];
Array.from(components.values()).forEach(comp => {
if (!displayedComponentsBlacklist.includes(comp.settings.type)) {
compsToOrder.push(comp);
}
});
if (displayOrder.length === compsToOrder.length) {
return compsToOrder.sort((a, b: Component) => sortComponents(a, b, displayOrder));
} else {
return compsToOrder;
}
};
const handleComponentChanged = (component: Component) => {
let updatedComponents = cloneDeep(components);
let updatedComponent = cloneDeep(component);
if (updatedComponents.has(updatedComponent.key())) {
updatedComponents.set(updatedComponent.key(), updatedComponent);
setComponents(updatedComponents);
}
};
const componentCards = () => {
let orderedComponents = getOrderedComponents();
let sensorComponents: JSX.Element[] = [];
let controllerComponents: JSX.Element[] = [];
//let componentCards = [];
//let hasGPS = false;
for (let i = 0; i < orderedComponents.length; i++) {
let c = orderedComponents[i];
if (displayedComponentsBlacklist.includes(c.settings.type)) {
continue;
}
let id: quack.IComponentID = quack.ComponentID.fromObject({
type: c.settings.type,
addressType: c.settings.addressType,
address: c.settings.address
});
let filteredInteractions = interactions.filter(interaction => {
let isSource = false;
let isSink = false;
if (interaction.settings) {
isSource = sameComponentID(interaction.settings.source, id);
isSink = sameComponentID(interaction.settings.sink, id);
}
return isSource || isSink;
});
// if (id.type === quack.ComponentType.COMPONENT_TYPE_GPS) {
// hasGPS = true;
// }
if (isController(c.settings.type)) {
controllerComponents.push(
<ComponentCard
device={device}
availablePositions={availablePositions}
availableOffsets={availableOffsets}
component={c}
components={orderedComponents}
interactions={filteredInteractions}
permissions={permissions}
deviceComponentPreferences={prefsMap.get(c.key())}
key={i}
refreshCallback={(updatedComponent?: Component) =>
updatedComponent ? handleComponentChanged(updatedComponent) : loadDevice()
}
/>
);
} else {
sensorComponents.push(
<ComponentCard
device={device}
availablePositions={availablePositions}
availableOffsets={availableOffsets}
component={c}
components={orderedComponents}
interactions={filteredInteractions}
permissions={permissions}
deviceComponentPreferences={prefsMap.get(c.key())}
key={i}
refreshCallback={(updatedComponent?: Component) =>
updatedComponent ? handleComponentChanged(updatedComponent) : loadDevice()
}
/>
);
}
}
return (
<List>
<li>
<Grid container direction="row" justifyContent="space-between">
<Grid >
<Typography display="block" variant="h6">
Sensors
</Typography>
</Grid>
<Grid >
{/* <FormControlLabel
label="Show Errors"
control={
<Checkbox
checked={showErrors}
onChange={() => {
//setShowErrors(!showErrors);
dispatch({ key: "showErrors", value: !showErrors });
}}
/>
}
/> */}
</Grid>
</Grid>
</li>
<Divider component="li" />
<ListItem>
<Grid container direction="row" justifyContent="flex-start" spacing={2}>
{sensorComponents}
</Grid>
</ListItem>
<li>
<Typography display="block" variant="h6">
Controls
</Typography>
</li>
<Divider component="li" />
<ListItem>
<Grid container direction="row" justifyContent="flex-start" spacing={2}>
{controllerComponents}
</Grid>
</ListItem>
{device.settings.mutations.length > 0 && (
<>
<li>
<Typography display="block" variant="h6">
Calculated Measurements
</Typography>
</li>
<Divider component="li" />
<ListItem>
<Grid container direction="row" justifyContent="flex-start" spacing={2}>
{/* {device.settings.mutations.map((mut, i) => (
<DeviceMutationCard
key={"mutation" + i}
deviceId={device.id()}
mutation={mut}
showMobile={isMobile}
/>
))} */}
</Grid>
</ListItem>
</>
)}
{device.settings.product !== pond.DeviceProduct.DEVICE_PRODUCT_NONE &&
permissions.includes(pond.Permission.PERMISSION_WRITE) && (
<>
<li>
<Typography display="block" variant="h6">
Setup
</Typography>
</li>
<Divider component="li" />
<ListItem>
<Grid container direction="row" spacing={2}>
{isMobile ? (
<>
<Grid size={{ xs: 12 }}>
{/* <DeviceWizard
device={device}
//permissions={permissions}
components={Array.from(components.values())}
refreshCallback={load}
/> */}
</Grid>
{diagnosticComponents.map(comp => (
<Grid size={{ xs: 12 }} key={comp.key()}>
<ComponentDiagnostics
component={comp}
device={device}
refreshCallback={loadDevice}
/>
</Grid>
))}
</>
) : (
<>
<Grid size={{ xs: 6, sm: 6, lg: 4, xl: 3 }} >
{/* <DeviceWizard
device={device}
//permissions={permissions}
components={Array.from(components.values())}
refreshCallback={load}
/> */}
</Grid>
<Grid size={{ xs: 6, sm: 6, lg: 8, xl: 9 }} >
<Grid container direction="row" spacing={2}>
{diagnosticComponents.map(comp => (
<Grid size={{ sm: 12, lg: 6, xl: 4 }} key={comp.key()}>
<ComponentDiagnostics
component={comp}
device={device}
refreshCallback={loadDevice}
/>
</Grid>
))}
</Grid>
</Grid>
</>
)}
</Grid>
</ListItem>
</>
)}
</List>
);
}
return ( return (
<PageContainer padding={isMobile ? 0 : 2}> <PageContainer padding={isMobile ? 0 : 2}>
<Grid2 container justifyContent={"space-between"}> <Grid container justifyContent={"space-between"}>
<Grid2> <Grid>
<SmartBreadcrumb /> <SmartBreadcrumb />
</Grid2> </Grid>
<Grid2> <Grid>
<AddComponentManualDialog <AddComponentManualDialog
device={device.id()} device={device.id()}
open={addComponentManualDialogOpen} open={addComponentManualDialogOpen}
@ -152,18 +420,19 @@ export default function DevicePage() {
availablePositions={availablePositions} availablePositions={availablePositions}
availableOffsets={availableOffsets} availableOffsets={availableOffsets}
/> />
</Grid2> </Grid>
</Grid2> </Grid>
<DeviceOverview <DeviceOverview
device={device} device={device}
// components={[...components.values()]} components={[...components.values()]}
// components={[]} // components={[]}
components={components} // components={components}
usage={getUsage()} usage={getUsage()}
loading={loading} loading={loading}
tags={tags} tags={tags}
groupID={parseInt(groupID)} groupID={parseInt(groupID)}
/> />
{componentCards()}
</PageContainer> </PageContainer>
); );
} }