actually added device actions
This commit is contained in:
parent
aa3301ac35
commit
4b08791bc9
5 changed files with 726 additions and 6 deletions
537
src/common/DeviceActions.tsx
Normal file
537
src/common/DeviceActions.tsx
Normal file
|
|
@ -0,0 +1,537 @@
|
|||
import {
|
||||
Divider,
|
||||
IconButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Menu,
|
||||
MenuItem,
|
||||
Theme,
|
||||
Tooltip
|
||||
} from "@mui/material";
|
||||
// import { amber, blue, green } from "@mui/co";
|
||||
import {
|
||||
AddCircle as AddIcon,
|
||||
ExitToApp as RemoveSelfIcon,
|
||||
History as HistoryIcon,
|
||||
MoreVert as MoreIcon,
|
||||
PauseCircleFilled,
|
||||
PlayCircleFilled,
|
||||
Reorder as ComponentOrderIcon,
|
||||
Save as SaveDeviceProfileIcon,
|
||||
SaveAlt as LoadDeviceProfileIcon,
|
||||
Settings as DeviceSettingsIcon,
|
||||
Share as ShareObjectIcon,
|
||||
AccountCircle as ObjectUsersIcon,
|
||||
SupervisedUserCircle as ObjectTeamsIcon,
|
||||
Sync as SyncDeviceIcon,
|
||||
Wifi as WifiIcon
|
||||
} from "@mui/icons-material";
|
||||
import { Skeleton } from "@mui/material";
|
||||
import Datadog from "assets/external/datadog.png";
|
||||
import { ImgIcon } from "common/ImgIcon";
|
||||
import NotificationButton from "common/NotificationButton";
|
||||
// import ComponentOrder from "component/ComponentOrder";
|
||||
// import ComponentSettings from "component/ComponentSettings";
|
||||
// import DeviceSettings from "device/DeviceSettings";
|
||||
// import LoadDeviceProfile from "device/LoadDeviceProfile";
|
||||
// import { PauseData } from "device/PauseData";
|
||||
// import { ResumeData } from "device/ResumeData";
|
||||
// import SaveDeviceProfile from "device/SaveDeviceProfile";
|
||||
// import SyncDevice from "device/SyncDevice";
|
||||
// import UpgradeDevice from "device/UpgradeDevice";
|
||||
// import InteractionSettings from "interactions/InteractionSettings";
|
||||
import { cloneDeep } from "lodash";
|
||||
// import { Component, Device, deviceScope, Interaction } from "models";
|
||||
import { Device, deviceScope } from "models";
|
||||
// import { MatchParams } from "navigation/Routes";
|
||||
import { isShareableLink } from "pbHelpers/Device";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { useGlobalState } from "providers";
|
||||
import React, { useState } from "react";
|
||||
// import { useHistory, useRouteMatch } from "react-router";
|
||||
import { isOffline } from "utils/environment";
|
||||
import { or } from "utils/types";
|
||||
import ObjectUsers from "user/ObjectUsers";
|
||||
import RemoveSelfFromObject from "user/RemoveSelfFromObject";
|
||||
import ShareObject from "user/ShareObject";
|
||||
// import Connection from "./Connection";
|
||||
// import ObjectTeams from "teams/ObjectTeams";
|
||||
// import ArcGISDeviceData from "./ArcGISDeviceData";
|
||||
// import { DeviceAvailabilityMap, OffsetAvailabilityMap } from "pbHelpers/DeviceAvailability";
|
||||
import { amber, blue, green } from "@mui/material/colors";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => {
|
||||
// const isMobile = useMobile()
|
||||
return ({
|
||||
greenIcon: {
|
||||
color: green["500"],
|
||||
"&:hover": {
|
||||
color: green["600"]
|
||||
}
|
||||
},
|
||||
amberIcon: {
|
||||
color: amber["600"],
|
||||
"&:hover": {
|
||||
color: amber["700"]
|
||||
}
|
||||
},
|
||||
blueIcon: {
|
||||
color: blue["500"],
|
||||
"&:hover": {
|
||||
color: blue["600"]
|
||||
}
|
||||
},
|
||||
red: {
|
||||
color: "var(--status-alert)"
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
interface Props {
|
||||
device: Device;
|
||||
isPaused: boolean;
|
||||
// components: Component[];
|
||||
// interactions: Interaction[];
|
||||
refreshCallback: () => void;
|
||||
// availablePositions: DeviceAvailabilityMap;
|
||||
// availableOffsets: OffsetAvailabilityMap;
|
||||
permissions: Array<pond.Permission>;
|
||||
preferences: pond.DevicePreferences;
|
||||
isLoading: boolean;
|
||||
toggleNotificationPreference: Function;
|
||||
}
|
||||
|
||||
interface DialogState {
|
||||
isAddComponentDialogOpen: boolean;
|
||||
isDeviceSettingsDialogOpen: boolean;
|
||||
isShareObjectDialogOpen: boolean;
|
||||
isSyncDeviceDialogOpen: boolean;
|
||||
isPauseDialogOpen: boolean;
|
||||
isResumeDialogOpen: boolean;
|
||||
isInteractionSettingsOpen: boolean;
|
||||
isObjectUsersDialogOpen: boolean;
|
||||
isObjectTeamsDialogOpen: boolean;
|
||||
isRemoveSelfDialogOpen: boolean;
|
||||
isSaveDeviceProfileOpen: boolean;
|
||||
isLoadDeviceProfileOpen: boolean;
|
||||
isConnectionDialogOpen: boolean;
|
||||
isComponentOrderDialogOpen: boolean;
|
||||
isJsonDataDialogOpen: boolean;
|
||||
}
|
||||
|
||||
export default function DeviceActions(props: Props) {
|
||||
const {
|
||||
device,
|
||||
isPaused,
|
||||
// components,
|
||||
// interactions,
|
||||
refreshCallback,
|
||||
// availablePositions,
|
||||
// availableOffsets,
|
||||
permissions,
|
||||
preferences,
|
||||
isLoading,
|
||||
toggleNotificationPreference
|
||||
} = props;
|
||||
const classes = useStyles();
|
||||
const [{ user }] = useGlobalState();
|
||||
const canWrite = permissions.includes(pond.Permission.PERMISSION_WRITE);
|
||||
const navigate = useNavigate();
|
||||
// const match = useRouteMatch<MatchParams>();
|
||||
const [menuAnchorEl, setMenuAnchorEl] = useState<Element | null>(null);
|
||||
const [dialogState, setDialogState] = useState<DialogState>({
|
||||
isAddComponentDialogOpen: false,
|
||||
isDeviceSettingsDialogOpen: false,
|
||||
isShareObjectDialogOpen: false,
|
||||
isSyncDeviceDialogOpen: false,
|
||||
isPauseDialogOpen: false,
|
||||
isResumeDialogOpen: false,
|
||||
isInteractionSettingsOpen: false,
|
||||
isObjectUsersDialogOpen: false,
|
||||
isObjectTeamsDialogOpen: false,
|
||||
isRemoveSelfDialogOpen: false,
|
||||
isSaveDeviceProfileOpen: false,
|
||||
isLoadDeviceProfileOpen: false,
|
||||
isConnectionDialogOpen: false,
|
||||
isComponentOrderDialogOpen: false,
|
||||
isJsonDataDialogOpen: false
|
||||
});
|
||||
|
||||
const openDialog = (target: keyof DialogState) => {
|
||||
let updatedDialogState = cloneDeep(dialogState);
|
||||
updatedDialogState[target] = true;
|
||||
setDialogState(updatedDialogState);
|
||||
setMenuAnchorEl(null);
|
||||
};
|
||||
|
||||
const closeDialog = (target: keyof DialogState) => {
|
||||
let updatedDialogState = cloneDeep(dialogState);
|
||||
updatedDialogState[target] = false;
|
||||
setDialogState(updatedDialogState);
|
||||
};
|
||||
|
||||
const closeAndRefresh = (target: keyof DialogState) => (refresh: boolean) => {
|
||||
closeDialog(target);
|
||||
if (refresh) props.refreshCallback();
|
||||
};
|
||||
|
||||
const deviceMenu = () => {
|
||||
const canShare = permissions.includes(pond.Permission.PERMISSION_SHARE);
|
||||
const canManageUsers = permissions.includes(pond.Permission.PERMISSION_USERS);
|
||||
const canProvision = user.allowedTo("provision");
|
||||
const isCellular = device.settings.platform === pond.DevicePlatform.DEVICE_PLATFORM_ELECTRON;
|
||||
const canPause = canWrite && isCellular && user.allowedTo("pause-data");
|
||||
const isWifi = device.settings.platform === pond.DevicePlatform.DEVICE_PLATFORM_PHOTON;
|
||||
// const isShareLink = isShareableLink(match.params.deviceID);
|
||||
const isShareLink = false
|
||||
|
||||
return (
|
||||
<Menu
|
||||
id="deviceMenu"
|
||||
anchorEl={menuAnchorEl ? menuAnchorEl : null}
|
||||
open={menuAnchorEl !== null}
|
||||
onClose={() => setMenuAnchorEl(null)}
|
||||
disableAutoFocusItem>
|
||||
{canWrite && (
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
openDialog("isAddComponentDialogOpen");
|
||||
}}
|
||||
dense>
|
||||
<ListItemIcon>
|
||||
<AddIcon className={classes.greenIcon} />
|
||||
</ListItemIcon>
|
||||
<ListItemText secondary="Add Component" />
|
||||
</MenuItem>
|
||||
)}
|
||||
{canWrite && (
|
||||
<MenuItem onClick={() => openDialog("isInteractionSettingsOpen")} dense>
|
||||
<ListItemIcon>
|
||||
<AddIcon className={classes.greenIcon} />
|
||||
</ListItemIcon>
|
||||
<ListItemText secondary="Add Interaction" />
|
||||
</MenuItem>
|
||||
)}
|
||||
{canWrite && <Divider />}
|
||||
|
||||
{!isOffline() && canShare && (
|
||||
<MenuItem onClick={() => openDialog("isShareObjectDialogOpen")} dense>
|
||||
<ListItemIcon>
|
||||
<ShareObjectIcon className={classes.blueIcon} />
|
||||
</ListItemIcon>
|
||||
<ListItemText secondary="Share" />
|
||||
</MenuItem>
|
||||
)}
|
||||
{canWrite &&
|
||||
user.hasAdmin() && ( //TODO: once the resync issue has been resolved remove the admin check
|
||||
<MenuItem onClick={() => openDialog("isSyncDeviceDialogOpen")} dense>
|
||||
<ListItemIcon>
|
||||
<SyncDeviceIcon className={classes.amberIcon} />
|
||||
</ListItemIcon>
|
||||
<ListItemText secondary="Resync" />
|
||||
</MenuItem>
|
||||
)}
|
||||
{user.hasFeature("json") && (
|
||||
<MenuItem onClick={() => openDialog("isJsonDataDialogOpen")} dense>
|
||||
<ListItemIcon>
|
||||
<LoadDeviceProfileIcon className={classes.greenIcon} />
|
||||
</ListItemIcon>
|
||||
<ListItemText secondary="Export Json Data" />
|
||||
</MenuItem>
|
||||
)}
|
||||
<MenuItem onClick={() => openDialog("isComponentOrderDialogOpen")} dense>
|
||||
<ListItemIcon>
|
||||
<ComponentOrderIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText secondary="Component Order" />
|
||||
</MenuItem>
|
||||
<Divider />
|
||||
|
||||
{canPause && !isPaused && (
|
||||
<MenuItem onClick={() => openDialog("isPauseDialogOpen")} dense>
|
||||
<ListItemIcon>
|
||||
<PauseCircleFilled />
|
||||
</ListItemIcon>
|
||||
<ListItemText secondary="Pause Data" />
|
||||
</MenuItem>
|
||||
)}
|
||||
{canPause && isPaused && (
|
||||
<MenuItem onClick={() => openDialog("isResumeDialogOpen")} dense>
|
||||
<ListItemIcon>
|
||||
<PlayCircleFilled className={classes.greenIcon} />
|
||||
</ListItemIcon>
|
||||
<ListItemText secondary="Resume Data" />
|
||||
</MenuItem>
|
||||
)}
|
||||
{isWifi && canWrite && (
|
||||
<MenuItem onClick={() => openDialog("isConnectionDialogOpen")} dense>
|
||||
<ListItemIcon>
|
||||
<WifiIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText secondary="Connection" />
|
||||
</MenuItem>
|
||||
)}
|
||||
{(canPause || (isWifi && canWrite)) && <Divider />}
|
||||
{canProvision && (
|
||||
<MenuItem onClick={() => openDialog("isSaveDeviceProfileOpen")} dense>
|
||||
<ListItemIcon>
|
||||
<SaveDeviceProfileIcon className={classes.blueIcon} />
|
||||
</ListItemIcon>
|
||||
<ListItemText secondary="Save Profile" />
|
||||
</MenuItem>
|
||||
)}
|
||||
{canProvision && (
|
||||
<MenuItem onClick={() => openDialog("isLoadDeviceProfileOpen")} dense>
|
||||
<ListItemIcon>
|
||||
<LoadDeviceProfileIcon className={classes.greenIcon} />
|
||||
</ListItemIcon>
|
||||
<ListItemText secondary="Load Profile" />
|
||||
</MenuItem>
|
||||
)}
|
||||
{canProvision && <Divider />}
|
||||
{!isOffline() && canManageUsers && (
|
||||
<MenuItem onClick={() => openDialog("isObjectUsersDialogOpen")} dense>
|
||||
<ListItemIcon>
|
||||
<ObjectUsersIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText secondary="Users" />
|
||||
</MenuItem>
|
||||
)}
|
||||
{!isOffline() && canManageUsers && (
|
||||
<MenuItem onClick={() => openDialog("isObjectTeamsDialogOpen")} dense>
|
||||
<ListItemIcon>
|
||||
<ObjectTeamsIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText secondary="Teams" />
|
||||
</MenuItem>
|
||||
)}
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
// const groupID: number = parseInt(match.params.groupID, 10);
|
||||
// const groupPath: string = groupID > 0 ? "/groups/" + groupID.toString() : "";
|
||||
const devicePath: string = "/devices/" + device.id().toString();
|
||||
// let path = groupPath + devicePath + "/history";
|
||||
let path = devicePath + "/history";
|
||||
navigate(path);
|
||||
}}
|
||||
dense>
|
||||
<ListItemIcon>
|
||||
<HistoryIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText secondary="History" />
|
||||
</MenuItem>
|
||||
{/* {canProvision && (
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
window.open(
|
||||
"https://app.datadoghq.com/logs?cols=core_host%2Ccore_service&index=main&live=true&messageDisplay=inline&stream_sort=desc&query=%40device%3A" +
|
||||
device.id(),
|
||||
"_blank"
|
||||
);
|
||||
}}
|
||||
dense>
|
||||
<ListItemIcon>
|
||||
<ImgIcon src={Datadog} />
|
||||
</ListItemIcon>
|
||||
<ListItemText secondary="Datadog" />
|
||||
</MenuItem>
|
||||
)} */}
|
||||
<Divider />
|
||||
{!isShareLink && (
|
||||
<MenuItem onClick={() => openDialog("isRemoveSelfDialogOpen")} dense>
|
||||
<ListItemIcon>
|
||||
<RemoveSelfIcon className={classes.red} />
|
||||
</ListItemIcon>
|
||||
<ListItemText secondary="Leave" />
|
||||
</MenuItem>
|
||||
)}
|
||||
</Menu>
|
||||
);
|
||||
};
|
||||
|
||||
const dialogs = () => {
|
||||
const deviceName = device.name();
|
||||
const {
|
||||
isAddComponentDialogOpen,
|
||||
isDeviceSettingsDialogOpen,
|
||||
isShareObjectDialogOpen,
|
||||
isSyncDeviceDialogOpen,
|
||||
isPauseDialogOpen,
|
||||
isResumeDialogOpen,
|
||||
isInteractionSettingsOpen,
|
||||
isObjectUsersDialogOpen,
|
||||
isObjectTeamsDialogOpen,
|
||||
isRemoveSelfDialogOpen,
|
||||
isSaveDeviceProfileOpen,
|
||||
isLoadDeviceProfileOpen,
|
||||
isConnectionDialogOpen,
|
||||
isComponentOrderDialogOpen,
|
||||
isJsonDataDialogOpen
|
||||
} = dialogState;
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{/* <DeviceSettings
|
||||
device={device}
|
||||
isDialogOpen={or(isDeviceSettingsDialogOpen, false)}
|
||||
closeDialogCallback={() => closeDialog("isDeviceSettingsDialogOpen")}
|
||||
refreshCallback={refreshCallback}
|
||||
canEdit={canWrite}
|
||||
components={components}
|
||||
/> */}
|
||||
{/* <ComponentSettings
|
||||
mode="add"
|
||||
device={device}
|
||||
isDialogOpen={or(isAddComponentDialogOpen, false)}
|
||||
closeDialogCallback={() => closeDialog("isAddComponentDialogOpen")}
|
||||
availablePositions={availablePositions}
|
||||
availableOffsets={availableOffsets}
|
||||
refreshCallback={refreshCallback}
|
||||
canEdit={canWrite}
|
||||
/>
|
||||
<SyncDevice
|
||||
device={device}
|
||||
isDialogOpen={or(isSyncDeviceDialogOpen, false)}
|
||||
closeDialogCallback={() => closeDialog("isSyncDeviceDialogOpen")}
|
||||
refreshCallback={refreshCallback}
|
||||
/> */}
|
||||
<ShareObject
|
||||
scope={deviceScope(device.id().toString())}
|
||||
label={deviceName}
|
||||
permissions={permissions}
|
||||
isDialogOpen={or(isShareObjectDialogOpen, false)}
|
||||
closeDialogCallback={() => closeDialog("isShareObjectDialogOpen")}
|
||||
/>
|
||||
{/* <InteractionSettings
|
||||
device={device}
|
||||
components={cloneDeep(components)}
|
||||
mode="add"
|
||||
isDialogOpen={or(isInteractionSettingsOpen, false)}
|
||||
closeDialogCallback={() => closeDialog("isInteractionSettingsOpen")}
|
||||
refreshCallback={refreshCallback}
|
||||
canEdit={canWrite}
|
||||
/> */}
|
||||
<ObjectUsers
|
||||
scope={deviceScope(device.id().toString())}
|
||||
label={deviceName}
|
||||
permissions={permissions}
|
||||
isDialogOpen={or(isObjectUsersDialogOpen, false)}
|
||||
closeDialogCallback={() => closeDialog("isObjectUsersDialogOpen")}
|
||||
refreshCallback={refreshCallback}
|
||||
/>
|
||||
{/* <ObjectTeams
|
||||
scope={deviceScope(device.id().toString())}
|
||||
label={deviceName}
|
||||
permissions={permissions}
|
||||
isDialogOpen={or(isObjectTeamsDialogOpen, false)}
|
||||
closeDialogCallback={() => closeDialog("isObjectTeamsDialogOpen")}
|
||||
refreshCallback={refreshCallback}
|
||||
/> */}
|
||||
<RemoveSelfFromObject
|
||||
scope={deviceScope(device.id().toString())}
|
||||
label={deviceName}
|
||||
isDialogOpen={isRemoveSelfDialogOpen}
|
||||
closeDialogCallback={() => closeDialog("isRemoveSelfDialogOpen")}
|
||||
/>
|
||||
{/* <SaveDeviceProfile
|
||||
isDialogOpen={isSaveDeviceProfileOpen}
|
||||
closeDialogCallback={() => closeDialog("isSaveDeviceProfileOpen")}
|
||||
device={device}
|
||||
components={components}
|
||||
interactions={interactions}
|
||||
tagIds={device.status.tagKeys}
|
||||
refreshCallback={refreshCallback}
|
||||
/> */}
|
||||
{/* <LoadDeviceProfile
|
||||
isDialogOpen={isLoadDeviceProfileOpen}
|
||||
closeDialogCallback={() => closeDialog("isLoadDeviceProfileOpen")}
|
||||
device={device}
|
||||
refreshCallback={refreshCallback}
|
||||
/> */}
|
||||
{/* <PauseData
|
||||
id={device.id()}
|
||||
isOpen={isPauseDialogOpen}
|
||||
close={closeAndRefresh("isPauseDialogOpen")}
|
||||
/>
|
||||
<ResumeData
|
||||
id={device.id()}
|
||||
isOpen={isResumeDialogOpen}
|
||||
close={closeAndRefresh("isResumeDialogOpen")}
|
||||
/>
|
||||
<Connection
|
||||
deviceID={device.id()}
|
||||
open={isConnectionDialogOpen}
|
||||
close={closeAndRefresh("isConnectionDialogOpen")}
|
||||
deviceName={device.name()}
|
||||
/>
|
||||
<ComponentOrder
|
||||
device={device}
|
||||
devicePreferences={preferences}
|
||||
components={components}
|
||||
open={isComponentOrderDialogOpen}
|
||||
close={closeAndRefresh("isComponentOrderDialogOpen")}
|
||||
/>
|
||||
<ArcGISDeviceData
|
||||
open={isJsonDataDialogOpen}
|
||||
close={closeAndRefresh("isJsonDataDialogOpen")}
|
||||
device={device}
|
||||
components={components}
|
||||
/> */}
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const buttons = () => {
|
||||
return (
|
||||
<React.Fragment>
|
||||
{/* {canWrite && user.allowedTo("provision") && <UpgradeDevice device={device} />} */}
|
||||
{/* {!isShareableLink(match.params.deviceID) && ( */}
|
||||
<NotificationButton
|
||||
notify={preferences.notify}
|
||||
onChange={toggleNotificationPreference}
|
||||
tooltip={
|
||||
"Notifications for " +
|
||||
device.name() +
|
||||
" are " +
|
||||
(preferences.notify ? "enabled" : "disabled")
|
||||
}
|
||||
hidden={isLoading}
|
||||
/>
|
||||
{/* )} */}
|
||||
<Tooltip title="Settings">
|
||||
<IconButton onClick={() => openDialog("isDeviceSettingsDialogOpen")}>
|
||||
<DeviceSettingsIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="More">
|
||||
<IconButton
|
||||
aria-owns={"deviceMenu"}
|
||||
aria-haspopup="true"
|
||||
onClick={event => setMenuAnchorEl(event.currentTarget)}>
|
||||
<MoreIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
if (isLoading)
|
||||
return (
|
||||
<Skeleton>
|
||||
<IconButton />
|
||||
<IconButton />
|
||||
<IconButton />
|
||||
</Skeleton>
|
||||
);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{buttons()}
|
||||
|
||||
{deviceMenu()}
|
||||
{dialogs()}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ import { makeStyles } from "@mui/styles";
|
|||
import ResponsiveTable, { Column } from "common/ResponsiveTable";
|
||||
import ProvisionDevice from "device/ProvisionDevice";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { useDeviceAPI } from "providers";
|
||||
import { useDeviceAPI, useGroupAPI } from "providers";
|
||||
import { useEffect, useState } from "react";
|
||||
import PageContainer from "./PageContainer";
|
||||
import { useMobile } from "hooks";
|
||||
|
|
@ -34,6 +34,7 @@ export default function Devices() {
|
|||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const deviceAPI = useDeviceAPI();
|
||||
const groupAPI = useGroupAPI();
|
||||
const [limit, setLimit] = useState(10);
|
||||
const [page, setPage] = useState(0);
|
||||
const [order, ] = useState<"asc" | "desc">("asc");
|
||||
|
|
@ -43,6 +44,13 @@ 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 [orderGroup, ] = useState<"asc" | "desc">("asc");
|
||||
const [orderGroupBy, ] = useState("name");
|
||||
const [searchGroup, setGroupSearch] = useState("");
|
||||
const [totalGroups, setTotalGroups] = useState(0);
|
||||
|
||||
const openProvisionDialog = () => {
|
||||
setIsProvisionDialogOpen(true);
|
||||
};
|
||||
|
|
@ -51,6 +59,18 @@ export default function Devices() {
|
|||
setIsProvisionDialogOpen(false);
|
||||
};
|
||||
|
||||
const loadGroups = () => {
|
||||
groupAPI.listGroups(
|
||||
groupLimit,
|
||||
groupPage*groupLimit,
|
||||
orderGroup,
|
||||
orderGroupBy,
|
||||
searchGroup,
|
||||
).then(resp => {
|
||||
console.log(resp.data)
|
||||
})
|
||||
}
|
||||
|
||||
const loadDevices = () => {
|
||||
deviceAPI.list(
|
||||
limit,
|
||||
|
|
@ -76,12 +96,17 @@ export default function Devices() {
|
|||
loadDevices()
|
||||
}, [limit, page, order, orderBy, search])
|
||||
|
||||
useEffect(() => {
|
||||
loadDevices()
|
||||
}, [groupLimit, groupPage, orderGroup, orderGroupBy, searchGroup])
|
||||
|
||||
|
||||
const handleChange = (event: any) => {
|
||||
setLimit(event.target.value);
|
||||
};
|
||||
|
||||
const appendToUrl = (appendage: number | string) => {
|
||||
const basePath = location.pathname.replace(/\/$/, ""); // Ensure no trailing slash
|
||||
const basePath = location.pathname.replace(/\/$/, "");
|
||||
return(`${basePath}/${appendage}`);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ export {
|
|||
// useFieldAPI,
|
||||
// useFieldMarkerAPI,
|
||||
// useFirmwareAPI,
|
||||
// useGroupAPI,
|
||||
useGroupAPI,
|
||||
// useHarvestPlanAPI,
|
||||
// useHarvestYearAPI,
|
||||
// useHomeMarkerAPI,
|
||||
|
|
|
|||
154
src/providers/pond/groupAPI.tsx
Normal file
154
src/providers/pond/groupAPI.tsx
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
import { useHTTP, usePermissionAPI } from "hooks";
|
||||
import { createContext, PropsWithChildren, useContext } from "react";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { or } from "utils/types";
|
||||
import { User, groupScope } from "models";
|
||||
import { pondURL } from "./pond";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { useGlobalState } from "providers";
|
||||
import { getContextKeys, getContextTypes } from "pbHelpers/Context";
|
||||
|
||||
export interface IGroupAPIContext {
|
||||
addGroup: (group: pond.GroupSettings) => Promise<any>;
|
||||
addDevice: (group: number, device: number) => Promise<any>;
|
||||
removeDevice: (group: number, device: number) => Promise<any>;
|
||||
updateGroup: (id: number, group: pond.GroupSettings) => Promise<any>;
|
||||
removeGroup: (id: number) => Promise<any>;
|
||||
getGroup: (id: number) => Promise<any>;
|
||||
listGroups: (
|
||||
limit: number,
|
||||
offset: number,
|
||||
order?: "asc" | "desc",
|
||||
orderBy?: string,
|
||||
search?: string,
|
||||
asRoot?: boolean
|
||||
) => Promise<any>;
|
||||
listGroupDevices: (
|
||||
id: number,
|
||||
limit: number,
|
||||
offset: number,
|
||||
order: "asc" | "desc",
|
||||
search?: string,
|
||||
comprehensive?: boolean
|
||||
) => Promise<AxiosResponse<pond.GetMultiDeviceResponse>>;
|
||||
updateGroupPermissions: (id: number, users: User[]) => Promise<any>;
|
||||
}
|
||||
|
||||
export const GroupAPIContext = createContext<IGroupAPIContext>({} as IGroupAPIContext);
|
||||
|
||||
interface Props {}
|
||||
|
||||
export default function GroupProvider(props: PropsWithChildren<Props>) {
|
||||
const { children } = props;
|
||||
const { get, post, put, del } = useHTTP();
|
||||
const permissionAPI = usePermissionAPI();
|
||||
const [{ as }] = useGlobalState();
|
||||
|
||||
const addGroup = (group: pond.GroupSettings) => {
|
||||
if (as) return post(pondURL("/groups?as=" + as), group);
|
||||
return post(pondURL("/groups"), group);
|
||||
};
|
||||
|
||||
const addDevice = (group: number, device: number) => {
|
||||
let url = "/groups/" + group + "/devices/" + device + "/add";
|
||||
if (as) return post(pondURL(url + as), group);
|
||||
return post(pondURL(url), group);
|
||||
};
|
||||
|
||||
const removeDevice = (group: number, device: number) => {
|
||||
let url = "/groups/" + group + "/devices/" + device + "/remove";
|
||||
if (as) return post(pondURL(url + as), group);
|
||||
return post(pondURL(url), group);
|
||||
};
|
||||
|
||||
const updateGroup = (id: number, group: pond.GroupSettings) => {
|
||||
if (as) return put(pondURL("/groups/" + id + "?as=" + as), group);
|
||||
return put(pondURL("/groups/" + id), group);
|
||||
};
|
||||
|
||||
const removeGroup = (id: number) => {
|
||||
if (as) return del(pondURL("/groups/" + id + "?as=" + as));
|
||||
return del(pondURL("/groups/" + id));
|
||||
};
|
||||
|
||||
const getGroup = (id: number) => {
|
||||
if (as) return get(pondURL("/groups/" + id + "?as=" + as));
|
||||
return get(pondURL("/groups/" + id));
|
||||
};
|
||||
|
||||
const listGroups = (
|
||||
limit: number,
|
||||
offset: number,
|
||||
order?: "asc" | "desc",
|
||||
orderBy?: string,
|
||||
search?: string,
|
||||
asRoot?: boolean
|
||||
) => {
|
||||
let keys = getContextKeys()
|
||||
let types = getContextTypes()
|
||||
return get(
|
||||
pondURL(
|
||||
"/groups" +
|
||||
"?limit=" +
|
||||
limit +
|
||||
"&offset=" +
|
||||
offset +
|
||||
("&order=" + or(order, "asc")) +
|
||||
("&orderBy=" + or(orderBy, "id")) +
|
||||
(search ? "&search=" + search : "") +
|
||||
(asRoot ? "&asRoot=" + asRoot.toString() : "") +
|
||||
(as ? "&as=" + as.toString() : "") +
|
||||
(keys.length > 0 ? "&keys=" + keys : "") +
|
||||
(types.length > 0 ? "&types=" + types : "")
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
const listGroupDevices = (
|
||||
id: number,
|
||||
limit: number,
|
||||
offset: number,
|
||||
order: "asc" | "desc",
|
||||
search?: string,
|
||||
comprehensive: boolean = false
|
||||
) => {
|
||||
return get<pond.GetMultiDeviceResponse>(
|
||||
pondURL(
|
||||
"/groups/" +
|
||||
id +
|
||||
"/devices?limit=" +
|
||||
limit +
|
||||
"&offset=" +
|
||||
offset +
|
||||
"&order=" +
|
||||
order +
|
||||
(search ? "&search=" + search : "") +
|
||||
(comprehensive ? "&comprehensive=" + comprehensive.toString() : "") +
|
||||
(as ? "&as=" + as.toString() : "")
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
const updateGroupPermissions = (id: number, users: User[]) => {
|
||||
return permissionAPI.updatePermissions(groupScope(id.toString()), users);
|
||||
};
|
||||
|
||||
return (
|
||||
<GroupAPIContext.Provider
|
||||
value={{
|
||||
addGroup,
|
||||
addDevice,
|
||||
removeDevice,
|
||||
updateGroup,
|
||||
removeGroup,
|
||||
getGroup,
|
||||
listGroups,
|
||||
listGroupDevices,
|
||||
updateGroupPermissions
|
||||
}}>
|
||||
{children}
|
||||
</GroupAPIContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export const useGroupAPI = () => useContext(GroupAPIContext);
|
||||
|
|
@ -9,6 +9,7 @@ import GateProvider, { useGateAPI } from "./gateAPI";
|
|||
import NoteProvider, { useNoteAPI } from "./noteAPI";
|
||||
import DeviceProvider, { useDeviceAPI } from "./deviceAPI";
|
||||
import BackpackProvider, { useBackpackAPI } from "./backpackAPI";
|
||||
import GroupProvider, { useGroupAPI } from "./groupAPI";
|
||||
// import NoteProvider from "providers/noteAPI";
|
||||
|
||||
export const pondURL = (partial: string, demo: boolean = false): string => {
|
||||
|
|
@ -33,9 +34,11 @@ export default function PondProvider(props: PropsWithChildren<any>) {
|
|||
<GateProvider>
|
||||
<NoteProvider>
|
||||
<DeviceProvider>
|
||||
<BackpackProvider>
|
||||
{children}
|
||||
</BackpackProvider>
|
||||
<GroupProvider>
|
||||
<BackpackProvider>
|
||||
{children}
|
||||
</BackpackProvider>
|
||||
</GroupProvider>
|
||||
</DeviceProvider>
|
||||
</NoteProvider>
|
||||
</GateProvider>
|
||||
|
|
@ -55,5 +58,6 @@ export {
|
|||
usePermissionAPI,
|
||||
useBinAPI,
|
||||
useGateAPI,
|
||||
useGroupAPI,
|
||||
useNoteAPI,
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue