groupd now generate tabs
This commit is contained in:
parent
c1ff72025a
commit
916d0f9132
4 changed files with 609 additions and 8 deletions
484
src/group/GroupSettings.tsx
Normal file
484
src/group/GroupSettings.tsx
Normal file
|
|
@ -0,0 +1,484 @@
|
|||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
darken,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
Divider,
|
||||
Grid,
|
||||
Grid2,
|
||||
lighten,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemSecondaryAction,
|
||||
ListItemText,
|
||||
Paper,
|
||||
Step,
|
||||
StepLabel,
|
||||
Stepper,
|
||||
Tab,
|
||||
Tabs,
|
||||
TextField,
|
||||
Theme,
|
||||
Typography
|
||||
} from "@mui/material";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
// import { darken, lighten } from "@material-ui/core/styles/colorManipulator";
|
||||
// import { Theme } from "@material-ui/core/styles/createMuiTheme";
|
||||
import DeleteButton from "common/DeleteButton";
|
||||
import Loader from "common/Loader";
|
||||
import ResponsiveDialog from "common/ResponsiveDialog";
|
||||
import SearchBar from "common/SearchBar";
|
||||
// import SearchBar from "common/SearchBar";
|
||||
// import RemoveGroup from "group/RemoveGroup";
|
||||
import { useDeviceAPI, useGroupAPI, usePrevious, useSnackbar } from "hooks";
|
||||
import { Device, Group } from "models";
|
||||
import { filterDevices } from "pbHelpers/Device";
|
||||
import { groupsAreEqual } from "pbHelpers/Group";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import RemoveGroup from "./RemoveGroup";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => {
|
||||
return ({
|
||||
deviceListContainer: {
|
||||
marginBottom: theme.spacing(1)
|
||||
},
|
||||
devicesList: {
|
||||
overflow: "auto",
|
||||
minHeight: "25vh",
|
||||
maxHeight: "35vh",
|
||||
height: "auto",
|
||||
background:
|
||||
theme.palette.mode === "dark"
|
||||
? lighten(theme.palette.background.paper, 0.04)
|
||||
: darken(theme.palette.background.paper, 0.04)
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
interface Props {
|
||||
initialGroup?: Group;
|
||||
mode?: "add" | "update" | "remove" | undefined;
|
||||
isDialogOpen: boolean;
|
||||
closeDialogCallback: Function;
|
||||
refreshCallback: Function;
|
||||
canEdit?: boolean;
|
||||
groupDevices?: Device[];
|
||||
}
|
||||
|
||||
export default function GroupSettings(props: Props) {
|
||||
const classes = useStyles();
|
||||
const { success, error, warning } = useSnackbar();
|
||||
const {
|
||||
initialGroup,
|
||||
mode,
|
||||
isDialogOpen,
|
||||
closeDialogCallback,
|
||||
refreshCallback,
|
||||
canEdit,
|
||||
groupDevices
|
||||
} = props;
|
||||
const prevInitialGroup = usePrevious(initialGroup);
|
||||
const groupAPI = useGroupAPI();
|
||||
const deviceAPI = useDeviceAPI();
|
||||
const [devices, setDevices] = useState<Device[]>([]);
|
||||
const [group, setGroup] = useState<Group>(initialGroup ? Group.clone(initialGroup) : new Group());
|
||||
const [isRemoveGroupOpen, setIsRemoveGroupOpen] = useState<boolean>(
|
||||
mode === "remove" ? true : false
|
||||
);
|
||||
const [tabIndex, setTabIndex] = useState<number>(0);
|
||||
const prevTabIndex = usePrevious(tabIndex);
|
||||
const [steps] = useState<string[]>(["General group information", "Select devices for the group"]);
|
||||
const [deviceSearch, setDeviceSearch] = useState<string>("");
|
||||
const [loadingDevices, setLoadingDevices] = useState<boolean>(false);
|
||||
|
||||
const loadDevices = useCallback(() => {
|
||||
setLoadingDevices(true);
|
||||
deviceAPI
|
||||
.list(1000000, 0, "asc")
|
||||
.then((response: any) => {
|
||||
let rDevices: Device[] = response.data.devices
|
||||
? response.data.devices.map((device: any) => Device.any(device))
|
||||
: [];
|
||||
|
||||
setDevices(rDevices);
|
||||
})
|
||||
.catch((error: any) => {
|
||||
setDevices([]);
|
||||
})
|
||||
.finally(() => setLoadingDevices(false));
|
||||
}, [deviceAPI]);
|
||||
|
||||
useEffect(() => {
|
||||
if (prevInitialGroup !== initialGroup) {
|
||||
setGroup(initialGroup ? Group.clone(initialGroup) : new Group());
|
||||
//setDevices([]);
|
||||
}
|
||||
|
||||
if (prevTabIndex !== 1 && tabIndex === 1) {
|
||||
loadDevices();
|
||||
}
|
||||
}, [initialGroup, loadDevices, prevInitialGroup, prevTabIndex, props, tabIndex, groupDevices]);
|
||||
|
||||
const close = () => {
|
||||
closeDialogCallback();
|
||||
setGroup(initialGroup ? Group.clone(initialGroup) : new Group());
|
||||
setDevices([]);
|
||||
setTabIndex(0);
|
||||
};
|
||||
|
||||
const submit = () => {
|
||||
const groupName = group.name();
|
||||
switch (mode) {
|
||||
case "add":
|
||||
groupAPI
|
||||
.addGroup(group.settings)
|
||||
.then((response: any) => {
|
||||
success(groupName + " was successfully created");
|
||||
close();
|
||||
refreshCallback();
|
||||
})
|
||||
.catch((err: any) => {
|
||||
err.response.data.error
|
||||
? warning(err.response.data.error)
|
||||
: error("Error occured when creating a group");
|
||||
close();
|
||||
})
|
||||
.finally(() => setTabIndex(0));
|
||||
break;
|
||||
default:
|
||||
groupAPI
|
||||
.updateGroup(group.id(), group.settings)
|
||||
.then((response: any) => {
|
||||
success(groupName + " was successfully updated");
|
||||
close();
|
||||
refreshCallback();
|
||||
})
|
||||
.catch((err: any) => {
|
||||
err.response.data.error
|
||||
? warning(err.response.data.error)
|
||||
: error("Error occured when updating " + groupName);
|
||||
close();
|
||||
});
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const openRemoveGroup = () => {
|
||||
setIsRemoveGroupOpen(true);
|
||||
};
|
||||
|
||||
const closeRemoveGroup = () => {
|
||||
setIsRemoveGroupOpen(false);
|
||||
if (mode === "remove") {
|
||||
close();
|
||||
}
|
||||
};
|
||||
|
||||
const isFormValid = () => {
|
||||
const validGroup: boolean = group !== undefined && group !== null;
|
||||
const validUpdate: boolean =
|
||||
mode !== "update" || !groupsAreEqual(Group.clone(initialGroup), group);
|
||||
|
||||
return validGroup && validUpdate;
|
||||
};
|
||||
|
||||
const changeTab = (value: number) => {
|
||||
setTabIndex(value);
|
||||
};
|
||||
|
||||
const nextStep = () => {
|
||||
let nextStepIndex = tabIndex + 1;
|
||||
setTabIndex(nextStepIndex);
|
||||
};
|
||||
|
||||
const backStep = () => {
|
||||
let backStepIndex = tabIndex - 1;
|
||||
setTabIndex(backStepIndex);
|
||||
};
|
||||
|
||||
const changeDeviceSearch = (value: string) => {
|
||||
setDeviceSearch(value);
|
||||
};
|
||||
|
||||
const changeName = (event: any) => {
|
||||
let updatedGroup = Group.clone(group);
|
||||
updatedGroup.settings.name = event.target.value;
|
||||
setGroup(updatedGroup);
|
||||
};
|
||||
|
||||
const changeDescription = (event: any) => {
|
||||
let updatedGroup = Group.clone(group);
|
||||
updatedGroup.settings.description = event.target.value;
|
||||
setGroup(updatedGroup);
|
||||
};
|
||||
|
||||
const changeDevices = (device: number) => {
|
||||
let updatedGroup = Group.clone(group);
|
||||
const exists = updatedGroup.settings.devices.includes(device);
|
||||
if (exists) {
|
||||
updatedGroup.settings.devices = updatedGroup.settings.devices.filter(
|
||||
groupDevice => groupDevice !== device
|
||||
);
|
||||
} else {
|
||||
updatedGroup.settings.devices.push(device);
|
||||
}
|
||||
setGroup(updatedGroup);
|
||||
};
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ UI BEGINS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
const title = () => {
|
||||
switch (mode) {
|
||||
case "add":
|
||||
return (
|
||||
<React.Fragment>
|
||||
Group Creation
|
||||
<Typography variant="body2" color="textSecondary" gutterBottom>
|
||||
Groups are a great way to organize your devices
|
||||
</Typography>
|
||||
</React.Fragment>
|
||||
);
|
||||
case "update":
|
||||
return (
|
||||
<React.Fragment>
|
||||
Group Settings
|
||||
<Typography variant="body2" color="textSecondary">
|
||||
{group.name()}
|
||||
</Typography>
|
||||
</React.Fragment>
|
||||
);
|
||||
default:
|
||||
return <React.Fragment />;
|
||||
}
|
||||
};
|
||||
|
||||
const generalGroupContent = () => {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TextField
|
||||
id="group-name"
|
||||
label="Name"
|
||||
value={group.settings.name}
|
||||
onChange={changeName}
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
disabled={!canEdit}
|
||||
fullWidth
|
||||
/>
|
||||
|
||||
<TextField
|
||||
id="group-description"
|
||||
label="Description"
|
||||
multiline
|
||||
rows={4}
|
||||
// rowsMax="4"
|
||||
value={group.settings.description}
|
||||
onChange={changeDescription}
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
disabled={!canEdit}
|
||||
fullWidth
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const devicesGroupContent = () => {
|
||||
if (mode !== "add") return devicesTab();
|
||||
return (
|
||||
<Paper elevation={0} className={classes.deviceListContainer}>
|
||||
<SearchBar value={deviceSearch} onChange={changeDeviceSearch} shape="square" />
|
||||
{loadingDevices ? (
|
||||
<List className={classes.devicesList}>
|
||||
<ListItem>
|
||||
<Grid2 container justifyContent="center">
|
||||
<Loader size="small" />
|
||||
</Grid2>
|
||||
</ListItem>
|
||||
</List>
|
||||
) : (
|
||||
<List dense className={classes.devicesList}>
|
||||
{filterDevices(deviceSearch, devices, [])
|
||||
.sort((a, b: Device) => a.name().localeCompare(b.name()))
|
||||
.map(device => {
|
||||
const label = `checkbox-list-secondary-label-${device.id()}`;
|
||||
return (
|
||||
<ListItem key={device.id()} onClick={() => changeDevices(device.id())}>
|
||||
<ListItemText id={label} primary={device.name()} />
|
||||
<ListItemSecondaryAction>
|
||||
<Checkbox
|
||||
edge="end"
|
||||
onChange={() => changeDevices(device.id())}
|
||||
checked={group.settings.devices.includes(device.id())}
|
||||
inputProps={{ "aria-labelledby": label }}
|
||||
disabled={!canEdit}
|
||||
/>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
);
|
||||
})}
|
||||
</List>
|
||||
)}
|
||||
</Paper>
|
||||
);
|
||||
};
|
||||
|
||||
//useEffect(() => {
|
||||
// if (tabIndex === 1) loadDevices()
|
||||
//}, [groupDevices])
|
||||
|
||||
const addDevice = (device: number) => {
|
||||
groupAPI.addDevice(group.id(), device).then(() => {
|
||||
refreshCallback();
|
||||
});
|
||||
};
|
||||
|
||||
const removeDevice = (device: number) => {
|
||||
groupAPI.removeDevice(group.id(), device).then(() => {
|
||||
refreshCallback();
|
||||
});
|
||||
};
|
||||
|
||||
const devicesTab = () => {
|
||||
return (
|
||||
<Paper elevation={0} className={classes.deviceListContainer}>
|
||||
<SearchBar value={deviceSearch} onChange={changeDeviceSearch} shape="square" />
|
||||
{loadingDevices ? (
|
||||
<List className={classes.devicesList}>
|
||||
<ListItem>
|
||||
<Grid2 container justifyContent="center">
|
||||
<Loader size="small" />
|
||||
</Grid2>
|
||||
</ListItem>
|
||||
</List>
|
||||
) : (
|
||||
<List dense className={classes.devicesList}>
|
||||
{filterDevices(deviceSearch, devices, [])
|
||||
.sort((a, b: Device) => a.name().localeCompare(b.name()))
|
||||
.map(device => {
|
||||
const label = `checkbox-list-secondary-label-${device.id()}`;
|
||||
return (
|
||||
<ListItem key={device.id()} onClick={() => changeDevices(device.id())}>
|
||||
<ListItemText id={label} primary={device.name()} />
|
||||
<ListItemSecondaryAction>
|
||||
<Checkbox
|
||||
edge="end"
|
||||
onChange={(_, checked) => {
|
||||
if (checked) addDevice(device.id());
|
||||
else removeDevice(device.id());
|
||||
}}
|
||||
checked={Boolean(groupDevices?.find(dev => dev.id() === device.id()))}
|
||||
inputProps={{ "aria-labelledby": label }}
|
||||
disabled={!canEdit}
|
||||
/>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
);
|
||||
})}
|
||||
</List>
|
||||
)}
|
||||
</Paper>
|
||||
);
|
||||
};
|
||||
|
||||
const content = () => {
|
||||
if (mode === "add") {
|
||||
return (
|
||||
<React.Fragment>
|
||||
{tabIndex === 0 && generalGroupContent()}
|
||||
{tabIndex === 1 && devicesGroupContent()}
|
||||
<Stepper activeStep={tabIndex} alternativeLabel>
|
||||
{steps.map(label => (
|
||||
<Step key={label}>
|
||||
<StepLabel>{label}</StepLabel>
|
||||
</Step>
|
||||
))}
|
||||
</Stepper>
|
||||
<Divider />
|
||||
</React.Fragment>
|
||||
);
|
||||
} else if (mode === "update") {
|
||||
return (
|
||||
<React.Fragment>
|
||||
{tabIndex === 0 && generalGroupContent()}
|
||||
{tabIndex === 1 && devicesGroupContent()}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
return <React.Fragment />;
|
||||
};
|
||||
|
||||
const actions = () => {
|
||||
return (
|
||||
<Grid2 container justifyContent="space-between" direction="row">
|
||||
<Grid2 size={{ xs: 5 }}>
|
||||
{mode === "add" ? (
|
||||
<Button onClick={backStep} color="primary" disabled={tabIndex === 0}>
|
||||
Back
|
||||
</Button>
|
||||
) : (
|
||||
mode === "update" &&
|
||||
canEdit && <DeleteButton onClick={openRemoveGroup}>Delete</DeleteButton>
|
||||
)}
|
||||
</Grid2>
|
||||
<Grid2 size={{ xs: 7 }} container justifyContent="flex-end">
|
||||
<Button onClick={close} color="primary">
|
||||
Cancel
|
||||
</Button>
|
||||
{(mode === "add" && tabIndex === steps.length - 1) || mode === "update"
|
||||
? canEdit && (
|
||||
<Button onClick={submit} color="primary" disabled={!isFormValid()}>
|
||||
Submit
|
||||
</Button>
|
||||
)
|
||||
: mode === "add" && (
|
||||
<Button onClick={nextStep} color="primary">
|
||||
Next
|
||||
</Button>
|
||||
)}
|
||||
</Grid2>
|
||||
</Grid2>
|
||||
);
|
||||
};
|
||||
|
||||
const dialogs = () => {
|
||||
return (
|
||||
<RemoveGroup
|
||||
group={group}
|
||||
isDialogOpen={isRemoveGroupOpen}
|
||||
closeDialogCallback={closeRemoveGroup}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<ResponsiveDialog
|
||||
open={isDialogOpen}
|
||||
onClose={close}
|
||||
aria-labelledby="group-settings-dialog"
|
||||
maxWidth="sm"
|
||||
fullWidth>
|
||||
<DialogTitle id="group-settings-title">{title()}</DialogTitle>
|
||||
{mode === "update" && (
|
||||
<Tabs
|
||||
value={tabIndex}
|
||||
onChange={(event, value) => {
|
||||
changeTab(value);
|
||||
}}
|
||||
indicatorColor="secondary"
|
||||
textColor="inherit"
|
||||
variant="fullWidth">
|
||||
<Tab label="General" />
|
||||
<Tab label="Devices" />
|
||||
</Tabs>
|
||||
)}
|
||||
<Divider />
|
||||
<DialogContent>{content()}</DialogContent>
|
||||
<DialogActions>{actions()}</DialogActions>
|
||||
{dialogs()}
|
||||
</ResponsiveDialog>
|
||||
);
|
||||
}
|
||||
84
src/group/RemoveGroup.tsx
Normal file
84
src/group/RemoveGroup.tsx
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
Theme,
|
||||
Typography
|
||||
} from "@mui/material";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
import { useGroupAPI, useSnackbar } from "hooks";
|
||||
import { Group } from "models";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => {
|
||||
return ({
|
||||
contentPadding: {
|
||||
paddingTop: theme.spacing(2),
|
||||
paddingBottom: theme.spacing(2)
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
interface Props {
|
||||
group: Group;
|
||||
isDialogOpen: boolean;
|
||||
closeDialogCallback: Function;
|
||||
}
|
||||
|
||||
export default function RemoveGroup(props: Props) {
|
||||
const classes = useStyles();
|
||||
const navigate = useNavigate();
|
||||
const groupAPI = useGroupAPI();
|
||||
const { success, error, warning } = useSnackbar();
|
||||
const { group, isDialogOpen, closeDialogCallback } = props;
|
||||
let groupName = group.name();
|
||||
|
||||
const closeDialog = () => {
|
||||
closeDialogCallback();
|
||||
};
|
||||
|
||||
const submit = () => {
|
||||
groupAPI
|
||||
.removeGroup(group.id())
|
||||
.then((response: any) => {
|
||||
success(groupName + " was successfully removed");
|
||||
// navigate("/groups");
|
||||
})
|
||||
.catch((err: any) => {
|
||||
err ? warning(err) : error("Error occured while removing " + groupName);
|
||||
closeDialog();
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={isDialogOpen}
|
||||
fullWidth
|
||||
onClose={closeDialog}
|
||||
aria-labelledby="remove-group-label"
|
||||
aria-describedby="remove-group-description">
|
||||
<DialogTitle id="remove-group-title">Delete {groupName}?</DialogTitle>
|
||||
<DialogContent className={classes.contentPadding}>
|
||||
<Typography color="error" align="left" variant="subtitle1">
|
||||
WARNING:
|
||||
</Typography>
|
||||
<Typography color="textPrimary" align="left" variant="body1">
|
||||
Clicking 'Accept' will delete {groupName} for you and all other users.
|
||||
</Typography>
|
||||
<Typography color="textSecondary" align="left" variant="body2">
|
||||
Devices will NOT be deleted in this process.
|
||||
</Typography>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={closeDialog} color="primary">
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={submit} color="primary">
|
||||
Accept
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
|
@ -12,6 +12,8 @@ export class Group {
|
|||
my.settings = pond.GroupSettings.fromObject(cloneDeep(or(pb.settings, {})));
|
||||
my.status = pond.GroupStatus.fromObject(cloneDeep(or(pb.status, {})));
|
||||
}
|
||||
my.id = my.id.bind(my);
|
||||
my.name = my.name.bind(my);
|
||||
return my;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { DeveloperBoard as ProvisionIcon, LibraryAdd as CreateGroupIcon } from "@mui/icons-material";
|
||||
import { Box, Chip, IconButton, Theme, Tooltip, Typography } from "@mui/material";
|
||||
import { Box, Chip, IconButton, Tab, Tabs, Theme, Tooltip, Typography } from "@mui/material";
|
||||
import { blue, green } from "@mui/material/colors";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
import ResponsiveTable, { Column } from "common/ResponsiveTable";
|
||||
|
|
@ -15,6 +15,7 @@ import { getContextKeys, getContextTypes } from "pbHelpers/Context";
|
|||
import { getDeviceStateHelper } from "pbHelpers/DeviceState";
|
||||
import { Group } from "models";
|
||||
import GroupSettings from "group/GroupSettings";
|
||||
import SmartBreadcrumb from "common/SmartBreadcrumb";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => {
|
||||
return ({
|
||||
|
|
@ -49,11 +50,12 @@ export default function Devices() {
|
|||
const [devices, setDevices] = useState<pond.Device[]>([])
|
||||
const [isProvisionDialogOpen, setIsProvisionDialogOpen] = useState<boolean>(false);
|
||||
|
||||
const [groupLimit, setGroupLimit] = useState(10);
|
||||
const [groupPage, setGroupPage] = useState(0);
|
||||
const [groups, setGroups] = useState<Group[]>([])
|
||||
const [groupLimit, ] = useState(10);
|
||||
const [groupPage, ] = useState(0);
|
||||
const [orderGroup, ] = useState<"asc" | "desc">("asc");
|
||||
const [orderGroupBy, ] = useState("name");
|
||||
const [searchGroup, setGroupSearch] = useState("");
|
||||
const [searchGroup, ] = useState("");
|
||||
const [totalGroups, setTotalGroups] = useState(0);
|
||||
|
||||
const [selectedGroup, setSelectedGroup] = useState<Group | undefined>(undefined);
|
||||
|
|
@ -62,6 +64,8 @@ export default function Devices() {
|
|||
>(undefined);
|
||||
const [groupSettingsIsOpen, setGroupSettingsIsOpen] = useState<boolean>(false);
|
||||
|
||||
const [tab, setTab] = useState("all");
|
||||
|
||||
const openProvisionDialog = () => {
|
||||
setIsProvisionDialogOpen(true);
|
||||
};
|
||||
|
|
@ -79,7 +83,7 @@ export default function Devices() {
|
|||
setSelectedGroup(group);
|
||||
};
|
||||
|
||||
const closeGroupSettings = (event: any) => {
|
||||
const closeGroupSettings = (_event: any) => {
|
||||
setGroupSettingsIsOpen(false);
|
||||
setGroupSettingsMode(undefined);
|
||||
setSelectedGroup(undefined);
|
||||
|
|
@ -93,10 +97,20 @@ export default function Devices() {
|
|||
orderGroupBy,
|
||||
searchGroup,
|
||||
).then(resp => {
|
||||
console.log(resp.data)
|
||||
// console.log(resp.data)
|
||||
let newGroups: Group[] = []
|
||||
resp.data.groups.forEach((group: pond.Group) => {
|
||||
newGroups.push(Group.create(group))
|
||||
})
|
||||
setGroups(newGroups)
|
||||
setTotalGroups(resp.data.total)
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
console.log(groups)
|
||||
}, [groups])
|
||||
|
||||
const loadDevices = () => {
|
||||
deviceAPI.list(
|
||||
limit,
|
||||
|
|
@ -140,6 +154,11 @@ export default function Devices() {
|
|||
navigate(appendToUrl(or(device.settings?.deviceId, "")), { state: {device: device} })
|
||||
};
|
||||
|
||||
const handleTabChange = (_event: React.SyntheticEvent, newValue: string) => {
|
||||
if (newValue !== "never") setTab(newValue);
|
||||
if (newValue === "never") openGroupSettings(undefined, "add");
|
||||
};
|
||||
|
||||
const columns = (): Column<pond.Device>[] => {
|
||||
return [
|
||||
{
|
||||
|
|
@ -170,7 +189,6 @@ export default function Devices() {
|
|||
label={device.settings?.name ? device.settings.name : "Device " + device.settings?.deviceId}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
)
|
||||
}
|
||||
},
|
||||
|
|
@ -227,6 +245,19 @@ export default function Devices() {
|
|||
|
||||
return(
|
||||
<PageContainer padding={isMobile ? 0 : 2}>
|
||||
<SmartBreadcrumb />
|
||||
<Tabs
|
||||
value={tab}
|
||||
onChange={handleTabChange}
|
||||
>
|
||||
<Tab value={"all"} label="All" />
|
||||
{groups.map((group, index) => {
|
||||
if (group.id()) return (
|
||||
<Tab value={group.id()} label={group.name()} key={"group-tab-"+index}/>
|
||||
)
|
||||
})}
|
||||
<Tab value={"never"} label={groupButton()} />
|
||||
</Tabs>
|
||||
<ResponsiveTable<pond.Device>
|
||||
title="Devices"
|
||||
subtitle={subtitle()}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue