device settings and actions made functional
This commit is contained in:
parent
3ce00facd1
commit
4e7c68401b
19 changed files with 3042 additions and 41 deletions
|
|
@ -1,537 +0,0 @@
|
|||
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>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue