can provision devices
This commit is contained in:
parent
0ae37f1370
commit
03f8ed20ca
18 changed files with 1467 additions and 17 deletions
|
|
@ -25,7 +25,7 @@ html, body, #root {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* styles.css or a CSS module */
|
/* styles.css or a CSS module */
|
||||||
.MuiDialog-root {
|
/* .MuiDialog-root {
|
||||||
z-index: 1500 !important;
|
z-index: 1500 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -34,5 +34,5 @@ html, body, #root {
|
||||||
}
|
}
|
||||||
|
|
||||||
.MuiMenu-root {
|
.MuiMenu-root {
|
||||||
z-index: 1400 !important; /* Ensure it's above the drawer */
|
z-index: 1400 !important;
|
||||||
}
|
} */
|
||||||
|
|
@ -120,6 +120,11 @@ export default function ChatInput(props: Props) {
|
||||||
clearEntry();
|
clearEntry();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getPlaceholder = () => {
|
||||||
|
if (type === pond.NoteType.NOTE_TYPE_TEAM) return "Message team..."
|
||||||
|
return "Type to chat..."
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Grid
|
<Grid
|
||||||
|
|
@ -139,6 +144,7 @@ export default function ChatInput(props: Props) {
|
||||||
onChange={e => setMessage(e.target.value)}
|
onChange={e => setMessage(e.target.value)}
|
||||||
onKeyDown={onKeyDown}
|
onKeyDown={onKeyDown}
|
||||||
onKeyUp={onKeyUp}
|
onKeyUp={onKeyUp}
|
||||||
|
placeholder={getPlaceholder()}
|
||||||
/>
|
/>
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import { pond } from "protobuf-ts/pond";
|
||||||
import { red } from "@mui/material/colors";
|
import { red } from "@mui/material/colors";
|
||||||
import { makeStyles } from "@mui/styles";
|
import { makeStyles } from "@mui/styles";
|
||||||
import CancelSubmit from "common/CancelSubmit";
|
import CancelSubmit from "common/CancelSubmit";
|
||||||
|
import { getThemeType } from "theme/themeType";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
index: number;
|
index: number;
|
||||||
|
|
@ -35,12 +36,10 @@ const useStyles = makeStyles((theme: Theme) => ({
|
||||||
},
|
},
|
||||||
oddGrid: {
|
oddGrid: {
|
||||||
backgroundColor: theme.palette.background.paper,
|
backgroundColor: theme.palette.background.paper,
|
||||||
// padding: 4,
|
|
||||||
padding: theme.spacing(1)
|
padding: theme.spacing(1)
|
||||||
},
|
},
|
||||||
evenGrid: {
|
evenGrid: {
|
||||||
// backgroundColor: theme.palette.background.default,
|
backgroundColor: getThemeType() === "light" ? theme.palette.background.default : undefined,
|
||||||
// padding: 4
|
|
||||||
padding: theme.spacing(1)
|
padding: theme.spacing(1)
|
||||||
},
|
},
|
||||||
userAvatar: {
|
userAvatar: {
|
||||||
|
|
@ -51,8 +50,6 @@ const useStyles = makeStyles((theme: Theme) => ({
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes in a note and renders it
|
* Takes in a note and renders it
|
||||||
* handles deleting of the note
|
* handles deleting of the note
|
||||||
|
|
@ -132,7 +129,6 @@ export default function ChatMessage(props: Props) {
|
||||||
<Dialog open={dialog} onClose={closeDialog}>
|
<Dialog open={dialog} onClose={closeDialog}>
|
||||||
<DialogTitle>Delete Message?</DialogTitle>
|
<DialogTitle>Delete Message?</DialogTitle>
|
||||||
<DialogContent>Are you sure you wish to delete this message</DialogContent>
|
<DialogContent>Are you sure you wish to delete this message</DialogContent>
|
||||||
|
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<CancelSubmit
|
<CancelSubmit
|
||||||
onCancel={closeDialog}
|
onCancel={closeDialog}
|
||||||
|
|
|
||||||
403
src/device/ProvisionDevice.tsx
Normal file
403
src/device/ProvisionDevice.tsx
Normal file
|
|
@ -0,0 +1,403 @@
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
CircularProgress,
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
|
DialogTitle,
|
||||||
|
Divider,
|
||||||
|
Grid2 as Grid,
|
||||||
|
IconButton,
|
||||||
|
List,
|
||||||
|
ListItem,
|
||||||
|
TextField,
|
||||||
|
Tooltip,
|
||||||
|
Typography
|
||||||
|
} from "@mui/material";
|
||||||
|
import { FileCopy } from "@mui/icons-material";
|
||||||
|
import ResponsiveDialog from "common/ResponsiveDialog";
|
||||||
|
import SearchSelect, { Option } from "common/SearchSelect";
|
||||||
|
import SelectDevicePlatform from "device/SelectDevicePlatform";
|
||||||
|
import { useBackpackAPI, useDeviceAPI, usePrevious, useSnackbar } from "hooks";
|
||||||
|
import { cloneDeep } from "lodash";
|
||||||
|
import { Backpack, Device } from "models";
|
||||||
|
import { backpackOptions, genericBackpacks } from "pbHelpers/Backpack";
|
||||||
|
import { pond } from "protobuf-ts/pond";
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
isOpen: boolean;
|
||||||
|
refreshCallback: Function;
|
||||||
|
closeDialogCallback: Function;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ProvisionDevice(props: Props) {
|
||||||
|
const deviceAPI = useDeviceAPI();
|
||||||
|
const backpackAPI = useBackpackAPI();
|
||||||
|
const { error, success, warning, info } = useSnackbar();
|
||||||
|
const { isOpen, closeDialogCallback, refreshCallback } = props;
|
||||||
|
const [provisioned, setProvisioned] = useState<boolean>(false);
|
||||||
|
const [idHex, setIdHex] = useState<string>("");
|
||||||
|
const [keyHex, setKeyHex] = useState<string>("");
|
||||||
|
const [backpack, setBackpack] = useState<Backpack | undefined>(undefined);
|
||||||
|
const [name, setName] = useState<string>("");
|
||||||
|
const [description, setDescription] = useState<string>("");
|
||||||
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
|
const [backpacks, setBackpacks] = useState<Backpack[]>([]);
|
||||||
|
const [command, setCommand] = useState<string>("");
|
||||||
|
const [deviceLoading, setDeviceLoading] = useState<boolean>(false);
|
||||||
|
const [platform, setPlatform] = useState<pond.DevicePlatform>(
|
||||||
|
pond.DevicePlatform.DEVICE_PLATFORM_PHOTON
|
||||||
|
);
|
||||||
|
const [device, setDevice] = useState<Device | undefined>(undefined);
|
||||||
|
const prevIsOpen = usePrevious(isOpen);
|
||||||
|
const deviceID: number = parseInt(idHex, 16);
|
||||||
|
|
||||||
|
const setDefaultState = () => {
|
||||||
|
setProvisioned(false);
|
||||||
|
setIdHex("");
|
||||||
|
setKeyHex("");
|
||||||
|
setBackpack(undefined);
|
||||||
|
setName("");
|
||||||
|
setDescription("");
|
||||||
|
setLoading(false);
|
||||||
|
setBackpacks([]);
|
||||||
|
setCommand("");
|
||||||
|
setDeviceLoading(false);
|
||||||
|
setDevice(undefined);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isOpen && !prevIsOpen) {
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
backpackAPI
|
||||||
|
.listBackpacks()
|
||||||
|
.then((response: any) => {
|
||||||
|
const rawBackpacks = response.data.backpacks;
|
||||||
|
let updatedBackpacks: Backpack[] = genericBackpacks();
|
||||||
|
if (rawBackpacks && rawBackpacks.length > 0) {
|
||||||
|
rawBackpacks.forEach((backpack: any) => {
|
||||||
|
updatedBackpacks.push(Backpack.any(backpack));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(false);
|
||||||
|
setBackpacks(updatedBackpacks.sort((a, b) => (a.name() > b.name() ? 1 : -1)));
|
||||||
|
setBackpack(undefined);
|
||||||
|
})
|
||||||
|
.catch((err: any) => {
|
||||||
|
setDefaultState();
|
||||||
|
error(err ? err : "Error occured while loading device profiles");
|
||||||
|
})
|
||||||
|
.finally(() => setLoading(false));
|
||||||
|
}
|
||||||
|
}, [backpackAPI, isOpen, prevIsOpen, error]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isOpen && provisioned && !device && !deviceLoading) {
|
||||||
|
setDeviceLoading(true);
|
||||||
|
const deviceID = parseInt(idHex, 16);
|
||||||
|
deviceAPI
|
||||||
|
.get(deviceID)
|
||||||
|
.then(response => {
|
||||||
|
let rDevice = Device.any(response.data);
|
||||||
|
setDevice(rDevice);
|
||||||
|
setName(rDevice.name());
|
||||||
|
setDescription(rDevice.settings.description);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error(error);
|
||||||
|
setDevice(
|
||||||
|
Device.create(
|
||||||
|
pond.Device.create({ settings: pond.DeviceSettings.create({ deviceId: deviceID }) })
|
||||||
|
)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.finally(() => setDeviceLoading(false));
|
||||||
|
}
|
||||||
|
}, [device, deviceAPI, deviceLoading, idHex, isOpen, provisioned]);
|
||||||
|
|
||||||
|
const close = () => {
|
||||||
|
if (provisioned) {
|
||||||
|
refreshCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
closeDialogCallback();
|
||||||
|
setDefaultState();
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateCommand = (idHex: any, keyHex: any): string => {
|
||||||
|
if (!idHex || !keyHex) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return "set creds " + idHex + ":" + keyHex;
|
||||||
|
};
|
||||||
|
|
||||||
|
const assembleBackpack = (): pond.BackpackSettings => {
|
||||||
|
let assembledBackpack = backpack ? cloneDeep(backpack) : Backpack.create();
|
||||||
|
let agnosticDevice = assembledBackpack.settings.device
|
||||||
|
? cloneDeep(assembledBackpack.settings.device)
|
||||||
|
: ({} as pond.DeviceSettings);
|
||||||
|
agnosticDevice.deviceId = 0;
|
||||||
|
agnosticDevice.platform = platform;
|
||||||
|
agnosticDevice.product = assembledBackpack.settings.product;
|
||||||
|
assembledBackpack.settings.device = agnosticDevice;
|
||||||
|
|
||||||
|
return assembledBackpack.settings;
|
||||||
|
};
|
||||||
|
|
||||||
|
const submitProvision = () => {
|
||||||
|
setProvisioned(false);
|
||||||
|
deviceAPI
|
||||||
|
.add("", "", assembleBackpack())
|
||||||
|
.then((response: any) => {
|
||||||
|
let updatedIdHex = response.data.idHex;
|
||||||
|
let updatedKeyHex = response.data.keyHex;
|
||||||
|
setIdHex(updatedIdHex);
|
||||||
|
setKeyHex(updatedKeyHex);
|
||||||
|
success("Successfully provisioned a new device (id: " + parseInt(updatedIdHex, 16) + ")");
|
||||||
|
setProvisioned(true);
|
||||||
|
setCommand(generateCommand(updatedIdHex, updatedKeyHex));
|
||||||
|
})
|
||||||
|
.catch((error: any) => {
|
||||||
|
error.response.data.error
|
||||||
|
? warning(error.response.data.error)
|
||||||
|
: error("Error occured while provisioning a new device.");
|
||||||
|
close();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const submitDeviceUpdate = () => {
|
||||||
|
const deviceID = parseInt(idHex, 16);
|
||||||
|
let settings = pond.DeviceSettings.create(device ? device.settings : { deviceId: deviceID });
|
||||||
|
settings.name = name;
|
||||||
|
settings.description = description;
|
||||||
|
deviceAPI
|
||||||
|
.update(deviceID, settings)
|
||||||
|
.then(() => {
|
||||||
|
success("Device " + deviceID.toString() + " was successfully updated");
|
||||||
|
})
|
||||||
|
.catch((error: any) => {
|
||||||
|
error.response.data.error
|
||||||
|
? warning(error.response.data.error)
|
||||||
|
: error("Error occured while updating device " + deviceID.toString() + ".");
|
||||||
|
close();
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setDevice(undefined);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const copyID = () => {
|
||||||
|
navigator.clipboard.writeText(idHex);
|
||||||
|
info("ID copied to clipboard");
|
||||||
|
};
|
||||||
|
|
||||||
|
const copyKey = () => {
|
||||||
|
navigator.clipboard.writeText(keyHex);
|
||||||
|
info("Key copied to clipboard");
|
||||||
|
};
|
||||||
|
|
||||||
|
const copyCommand = () => {
|
||||||
|
navigator.clipboard.writeText(command + "\n");
|
||||||
|
info("Command copied to clipboard");
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeBackpack = (option: Option | null) => {
|
||||||
|
let selectedBackpack = undefined;
|
||||||
|
if (option) {
|
||||||
|
const value = Number(option.value);
|
||||||
|
selectedBackpack = backpacks.find(backpack => {
|
||||||
|
let idMatch: boolean = backpack.id() === value;
|
||||||
|
return idMatch && (value === 0 ? backpack.name() === option.label : true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setBackpack(selectedBackpack);
|
||||||
|
};
|
||||||
|
|
||||||
|
const content = () => {
|
||||||
|
if (provisioned) {
|
||||||
|
return (
|
||||||
|
<Grid container spacing={1}>
|
||||||
|
<Grid size={{xs:12}} container justifyContent="center" alignItems="center">
|
||||||
|
<Grid size={{xs: 11}}>
|
||||||
|
<TextField
|
||||||
|
id="id"
|
||||||
|
name="ID"
|
||||||
|
label="ID Hex"
|
||||||
|
disabled
|
||||||
|
value={idHex}
|
||||||
|
margin="normal"
|
||||||
|
variant="outlined"
|
||||||
|
type="text"
|
||||||
|
fullWidth
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid size={{xs:1}}>
|
||||||
|
<Tooltip title="Copy ID">
|
||||||
|
<IconButton onClick={copyID}>
|
||||||
|
<FileCopy />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<Grid size={{xs:12}} container justifyContent="center" alignItems="center">
|
||||||
|
<Grid size={{xs:11}}>
|
||||||
|
<TextField
|
||||||
|
id="key"
|
||||||
|
name="Key"
|
||||||
|
label="Key Hex"
|
||||||
|
disabled
|
||||||
|
value={keyHex}
|
||||||
|
margin="normal"
|
||||||
|
variant="outlined"
|
||||||
|
type="text"
|
||||||
|
fullWidth
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid size={{xs:1}}>
|
||||||
|
<Tooltip title="Copy Key">
|
||||||
|
<IconButton onClick={copyKey}>
|
||||||
|
<FileCopy />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<Grid size={{xs:12}} container justifyContent="center" alignItems="center">
|
||||||
|
<Grid size={{xs:11}}>
|
||||||
|
<TextField
|
||||||
|
id="command"
|
||||||
|
name="command"
|
||||||
|
label="Command"
|
||||||
|
variant="outlined"
|
||||||
|
value={command}
|
||||||
|
disabled
|
||||||
|
fullWidth
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid size={{xs:1}}>
|
||||||
|
<Tooltip title="Copy Command">
|
||||||
|
<IconButton onClick={copyCommand}>
|
||||||
|
<FileCopy />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
{/* {window.NDEFReader && (
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
onClick={() => {
|
||||||
|
const ndef = new NDEFReader();
|
||||||
|
ndef
|
||||||
|
.write({
|
||||||
|
records: [{ recordType: "text", data: command }]
|
||||||
|
})
|
||||||
|
.then(resp => {
|
||||||
|
success("Comand sent");
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
error("Failed to send command");
|
||||||
|
});
|
||||||
|
}}>
|
||||||
|
Write to Device
|
||||||
|
</Button>
|
||||||
|
)} */}
|
||||||
|
<Grid size={{xs:12}}>
|
||||||
|
<Divider />
|
||||||
|
</Grid>
|
||||||
|
{deviceLoading ? (
|
||||||
|
<CircularProgress />
|
||||||
|
) : (
|
||||||
|
<Grid size={{xs:12}}>
|
||||||
|
<Typography color="textPrimary" variant="body1" gutterBottom>
|
||||||
|
Update device name/description
|
||||||
|
</Typography>
|
||||||
|
<TextField
|
||||||
|
margin="normal"
|
||||||
|
id="deviceName"
|
||||||
|
label="Name"
|
||||||
|
type="text"
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
value={name}
|
||||||
|
onChange={(event: any) => setName(event.target.value)}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
margin="normal"
|
||||||
|
id="deviceDescription"
|
||||||
|
label="Description"
|
||||||
|
type="text"
|
||||||
|
multiline
|
||||||
|
rows="4"
|
||||||
|
// rowsMax="4"
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
value={description}
|
||||||
|
onChange={(event: any) => setDescription(event.target.value)}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedBackpack = backpack
|
||||||
|
? ({ label: backpack.name(), value: backpack.id() } as Option)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<List>
|
||||||
|
<ListItem>
|
||||||
|
<SelectDevicePlatform value={platform} onChange={platform => setPlatform(platform)} />
|
||||||
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
<SearchSelect
|
||||||
|
label="Select a profile to provision with"
|
||||||
|
selected={selectedBackpack}
|
||||||
|
options={backpackOptions(backpacks)}
|
||||||
|
changeSelection={changeBackpack}
|
||||||
|
loading={loading}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
</List>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const actions = () => {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<Button onClick={close} color="primary">
|
||||||
|
Close
|
||||||
|
</Button>
|
||||||
|
{!provisioned ? (
|
||||||
|
<Button onClick={submitProvision} color="primary" disabled={!backpack}>
|
||||||
|
Provision
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<Button onClick={submitDeviceUpdate} color="primary" disabled={!backpack}>
|
||||||
|
Update
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ResponsiveDialog open={isOpen} onClose={close} aria-labelledby="form-dialog-title" fullWidth>
|
||||||
|
<DialogTitle id="form-dialog-title">
|
||||||
|
Provision Device
|
||||||
|
{provisioned && (
|
||||||
|
<Typography variant="body2" color="textSecondary">
|
||||||
|
Device ID: {deviceID}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent>{content()}</DialogContent>
|
||||||
|
<DialogActions>{actions()}</DialogActions>
|
||||||
|
</ResponsiveDialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
31
src/device/SelectDevicePlatform.tsx
Normal file
31
src/device/SelectDevicePlatform.tsx
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
import { MenuItem, TextField } from "@mui/material";
|
||||||
|
import { GetAllDevicePlatformDescribers } from "pbHelpers/DevicePlatform";
|
||||||
|
import { pond } from "protobuf-ts/pond";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
value: pond.DevicePlatform;
|
||||||
|
onChange: (platform: pond.DevicePlatform) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function SelectDevicePlatform(props: Props) {
|
||||||
|
const { value, onChange } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TextField
|
||||||
|
id="select-device-platform"
|
||||||
|
select
|
||||||
|
label="Device Platform"
|
||||||
|
value={pond.DevicePlatform[value]}
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
onChange={event =>
|
||||||
|
onChange(pond.DevicePlatform[event.target.value as keyof typeof pond.DevicePlatform])
|
||||||
|
}>
|
||||||
|
{GetAllDevicePlatformDescribers().map(p => (
|
||||||
|
<MenuItem key={pond.DevicePlatform[p.platform]} value={pond.DevicePlatform[p.platform]}>
|
||||||
|
{p.label}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</TextField>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
export {
|
export {
|
||||||
// useAuth,
|
// useAuth,
|
||||||
// useBackpackAPI,
|
useBackpackAPI,
|
||||||
// useBilling,
|
// useBilling,
|
||||||
// useComponentAPI,
|
// useComponentAPI,
|
||||||
// useComponentsWebsocket,
|
// useComponentsWebsocket,
|
||||||
// useComponentWebsocket,
|
// useComponentWebsocket,
|
||||||
// useDeviceAPI,
|
useDeviceAPI,
|
||||||
// useDeviceWebsocket,
|
// useDeviceWebsocket,
|
||||||
// useFirmwareAPI,
|
// useFirmwareAPI,
|
||||||
// useGitlab,
|
// useGitlab,
|
||||||
|
|
|
||||||
26
src/models/Backpack.ts
Normal file
26
src/models/Backpack.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { pond } from "protobuf-ts/pond";
|
||||||
|
import { or } from "utils/types";
|
||||||
|
import { cloneDeep } from "lodash";
|
||||||
|
|
||||||
|
export class Backpack {
|
||||||
|
public settings: pond.BackpackSettings = pond.BackpackSettings.create();
|
||||||
|
public static create(pb?: pond.Backpack): Backpack {
|
||||||
|
let my = new Backpack();
|
||||||
|
if (pb) {
|
||||||
|
my.settings = pond.BackpackSettings.fromObject(cloneDeep(or(pb.settings, {})));
|
||||||
|
}
|
||||||
|
return my;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static any(data: any): Backpack {
|
||||||
|
return Backpack.create(pond.Backpack.fromObject(cloneDeep(data)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public id(): number {
|
||||||
|
return Number(this.settings.backpackId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public name(): string {
|
||||||
|
return this.settings.name !== "" ? this.settings.name : "Device Profile " + this.id();
|
||||||
|
}
|
||||||
|
}
|
||||||
64
src/models/Device.ts
Normal file
64
src/models/Device.ts
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
import { pond } from "protobuf-ts/pond";
|
||||||
|
import { or } from "utils/types";
|
||||||
|
import { cloneDeep } from "lodash";
|
||||||
|
import { MarkerData } from "Maps/mapMarkers/Markers";
|
||||||
|
|
||||||
|
export class Device {
|
||||||
|
public settings: pond.DeviceSettings = pond.DeviceSettings.create();
|
||||||
|
public status: pond.DeviceStatus = pond.DeviceStatus.create();
|
||||||
|
|
||||||
|
public static create(pb?: pond.Device): Device {
|
||||||
|
let my = new Device();
|
||||||
|
if (pb) {
|
||||||
|
my.settings = pond.DeviceSettings.fromObject(or(pb.settings, {}));
|
||||||
|
my.status = pond.DeviceStatus.fromObject(or(pb.status, {}));
|
||||||
|
}
|
||||||
|
return my;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static any(data: any): Device {
|
||||||
|
if (data.device) return Device.create(pond.Device.fromObject(cloneDeep(data.device)));
|
||||||
|
return Device.create(pond.Device.fromObject(cloneDeep(data)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static clone(other: Device): Device {
|
||||||
|
let my = new Device();
|
||||||
|
my.settings = pond.DeviceSettings.fromObject(cloneDeep(other.settings));
|
||||||
|
my.status = pond.DeviceStatus.fromObject(cloneDeep(other.status));
|
||||||
|
return my;
|
||||||
|
}
|
||||||
|
|
||||||
|
public id(): number {
|
||||||
|
return Number(this.settings.deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public name(): string {
|
||||||
|
return this.settings.name !== ""
|
||||||
|
? this.settings.name
|
||||||
|
: this.id() > 0
|
||||||
|
? "Device " + this.id()
|
||||||
|
: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public location(): pond.Location {
|
||||||
|
let loc = pond.Location.create();
|
||||||
|
loc.longitude = this.settings.longitude;
|
||||||
|
loc.latitude = this.settings.latitude;
|
||||||
|
return loc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMarkerData(
|
||||||
|
clickFunc?: (event: React.PointerEvent<HTMLElement>, index: number, isMobile: boolean) => void,
|
||||||
|
updateFunc?: (location: pond.Location) => void
|
||||||
|
): MarkerData {
|
||||||
|
let m: MarkerData = {
|
||||||
|
longitude: this.location()?.longitude ?? 0,
|
||||||
|
latitude: this.location()?.latitude ?? 0,
|
||||||
|
title: this.name(),
|
||||||
|
colour: this.settings.theme?.color ?? "blue",
|
||||||
|
clickFunc: clickFunc,
|
||||||
|
updateFunc: updateFunc
|
||||||
|
};
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
// export * from "./Backpack";
|
export * from "./Backpack";
|
||||||
// export * from "./Bin";
|
// export * from "./Bin";
|
||||||
// export * from "./BinYard";
|
// export * from "./BinYard";
|
||||||
// export * from "./Component";
|
// export * from "./Component";
|
||||||
// export * from "./Device";
|
export * from "./Device";
|
||||||
// export * from "./Firmware";
|
// export * from "./Firmware";
|
||||||
// export * from "./Group";
|
// export * from "./Group";
|
||||||
// export * from "./Interaction";
|
// export * from "./Interaction";
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import BottomNavigator from "./BottomNavigator";
|
||||||
import TeamPage from "pages/Team";
|
import TeamPage from "pages/Team";
|
||||||
import Header from "app/Header";
|
import Header from "app/Header";
|
||||||
import Logout from "pages/Logout";
|
import Logout from "pages/Logout";
|
||||||
|
import Devices from "pages/Devices";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
open: boolean,
|
open: boolean,
|
||||||
|
|
@ -70,6 +71,7 @@ export default function Router(props: Props) {
|
||||||
<Route path="/teams" element={<Teams/>} />
|
<Route path="/teams" element={<Teams/>} />
|
||||||
<Route path="/teams/:teamID" element={<TeamPage/>} />
|
<Route path="/teams/:teamID" element={<TeamPage/>} />
|
||||||
<Route path="/users" element={<Users/>} />
|
<Route path="/users" element={<Users/>} />
|
||||||
|
<Route path="/devices" element={<Devices/>} />
|
||||||
{/* <Route
|
{/* <Route
|
||||||
path="/teams/:teamID"
|
path="/teams/:teamID"
|
||||||
element={<Team />}
|
element={<Team />}
|
||||||
|
|
|
||||||
42
src/pages/Devices.tsx
Normal file
42
src/pages/Devices.tsx
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
import { DeveloperBoard as ProvisionIcon } from "@mui/icons-material";
|
||||||
|
import { IconButton, Theme, Tooltip } from "@mui/material";
|
||||||
|
import { blue } from "@mui/material/colors";
|
||||||
|
import { makeStyles } from "@mui/styles";
|
||||||
|
import ProvisionDevice from "device/ProvisionDevice";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme: Theme) => {
|
||||||
|
return ({
|
||||||
|
provisionIcon: {
|
||||||
|
color: blue["700"]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
export default function Devices() {
|
||||||
|
const classes = useStyles();
|
||||||
|
const [isProvisionDialogOpen, setIsProvisionDialogOpen] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const openProvisionDialog = () => {
|
||||||
|
setIsProvisionDialogOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeProvisionDialog = () => {
|
||||||
|
setIsProvisionDialogOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return(
|
||||||
|
<>
|
||||||
|
<Tooltip title="Provision Device">
|
||||||
|
<IconButton onClick={openProvisionDialog} aria-label="Provision Device">
|
||||||
|
<ProvisionIcon className={classes.provisionIcon} />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
<ProvisionDevice
|
||||||
|
isOpen={isProvisionDialogOpen}
|
||||||
|
refreshCallback={/*load*/()=>{}}
|
||||||
|
closeDialogCallback={closeProvisionDialog}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
25
src/pbHelpers/Backpack.ts
Normal file
25
src/pbHelpers/Backpack.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { Backpack } from "models";
|
||||||
|
import { pond } from "protobuf-ts/pond";
|
||||||
|
import { Option } from "common/SearchSelect";
|
||||||
|
|
||||||
|
export function backpackOptions(backpacks: Backpack[]): Option[] {
|
||||||
|
return backpacks.map(b => {
|
||||||
|
return { value: b.settings.backpackId, label: b.name() } as Option;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function genericBackpacks(): Backpack[] {
|
||||||
|
let basic = pond.Backpack.fromObject({
|
||||||
|
settings: {
|
||||||
|
backpackId: 0,
|
||||||
|
name: "Basic",
|
||||||
|
device: pond.DeviceSettings.fromObject({
|
||||||
|
name: "Basic",
|
||||||
|
pondCheckPeriodS: 60,
|
||||||
|
upgradeChannel: pond.UpgradeChannel.UPGRADE_CHANNEL_STABLE,
|
||||||
|
automaticallyUpgrade: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return [Backpack.create(basic)];
|
||||||
|
}
|
||||||
116
src/pbHelpers/DevicePlatform.tsx
Normal file
116
src/pbHelpers/DevicePlatform.tsx
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
import React from "react";
|
||||||
|
import {
|
||||||
|
DeviceUnknown,
|
||||||
|
SignalCellular4Bar,
|
||||||
|
SignalWifi4Bar,
|
||||||
|
SignalCellularOff,
|
||||||
|
SignalWifiOff
|
||||||
|
} from "@mui/icons-material";
|
||||||
|
import { pond } from "protobuf-ts/pond";
|
||||||
|
|
||||||
|
export interface DevicePlatformDescriber {
|
||||||
|
platform: pond.DevicePlatform;
|
||||||
|
label: string;
|
||||||
|
description: string;
|
||||||
|
icon: any;
|
||||||
|
offlineIcon: any;
|
||||||
|
platformName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Default: DevicePlatformDescriber = {
|
||||||
|
platform: pond.DevicePlatform.DEVICE_PLATFORM_INVALID,
|
||||||
|
label: "Unknown",
|
||||||
|
description: "Unknown communication platform",
|
||||||
|
icon: <DeviceUnknown style={{ color: "#fff" }} />,
|
||||||
|
offlineIcon: <DeviceUnknown style={{ color: "#fff" }} />,
|
||||||
|
platformName: "unknown"
|
||||||
|
};
|
||||||
|
|
||||||
|
const Photon: DevicePlatformDescriber = {
|
||||||
|
platform: pond.DevicePlatform.DEVICE_PLATFORM_PHOTON,
|
||||||
|
label: "Wi-Fi",
|
||||||
|
description: "Communicates via Wi-Fi",
|
||||||
|
icon: <SignalWifi4Bar style={{ color: "#fff" }} />,
|
||||||
|
offlineIcon: <SignalWifiOff style={{ color: "#fff" }} />,
|
||||||
|
platformName: "photon"
|
||||||
|
};
|
||||||
|
|
||||||
|
const Electron: DevicePlatformDescriber = {
|
||||||
|
platform: pond.DevicePlatform.DEVICE_PLATFORM_ELECTRON,
|
||||||
|
label: "Cellular",
|
||||||
|
description: "Communicates via cellular",
|
||||||
|
icon: <SignalCellular4Bar style={{ color: "#fff" }} />,
|
||||||
|
offlineIcon: <SignalCellularOff style={{ color: "#fff" }} />,
|
||||||
|
platformName: "electron"
|
||||||
|
};
|
||||||
|
|
||||||
|
const V2_Cellular: DevicePlatformDescriber = {
|
||||||
|
platform: pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR,
|
||||||
|
label: "V2 Cellular",
|
||||||
|
description: "Communicates via cellular",
|
||||||
|
icon: <SignalCellular4Bar style={{ color: "#fff" }} />,
|
||||||
|
offlineIcon: <SignalCellularOff style={{ color: "#fff" }} />,
|
||||||
|
platformName: "v2cellular"
|
||||||
|
};
|
||||||
|
|
||||||
|
const V2_Wifi_S3: DevicePlatformDescriber = {
|
||||||
|
platform: pond.DevicePlatform.DEVICE_PLATFORM_V2_WIFI_S3,
|
||||||
|
label: "V2 Wifi S3",
|
||||||
|
description: "Communicates via cellular",
|
||||||
|
icon: <SignalCellular4Bar style={{ color: "#fff" }} />,
|
||||||
|
offlineIcon: <SignalCellularOff style={{ color: "#fff" }} />,
|
||||||
|
platformName: "v2wifis3"
|
||||||
|
};
|
||||||
|
|
||||||
|
const V2_Cell_Black: DevicePlatformDescriber = {
|
||||||
|
platform: pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR_BLACK,
|
||||||
|
label: "V2 Cellular Black",
|
||||||
|
description: "Communicates via cellular",
|
||||||
|
icon: <SignalCellular4Bar style={{ color: "#fff" }} />,
|
||||||
|
offlineIcon: <SignalCellularOff style={{ color: "#fff" }} />,
|
||||||
|
platformName: "v2cellblack"
|
||||||
|
};
|
||||||
|
|
||||||
|
const V2_Cell_Green: DevicePlatformDescriber = {
|
||||||
|
platform: pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR_GREEN,
|
||||||
|
label: "V2 Cellular Green",
|
||||||
|
description: "Communicates via cellular",
|
||||||
|
icon: <SignalCellular4Bar style={{ color: "#fff" }} />,
|
||||||
|
offlineIcon: <SignalCellularOff style={{ color: "#fff" }} />,
|
||||||
|
platformName: "v2cellgreen"
|
||||||
|
};
|
||||||
|
|
||||||
|
const map = new Map<pond.DevicePlatform, DevicePlatformDescriber>([
|
||||||
|
[pond.DevicePlatform.DEVICE_PLATFORM_INVALID, Default],
|
||||||
|
[pond.DevicePlatform.DEVICE_PLATFORM_PHOTON, Photon],
|
||||||
|
[pond.DevicePlatform.DEVICE_PLATFORM_ELECTRON, Electron],
|
||||||
|
[pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR, V2_Cellular],
|
||||||
|
[pond.DevicePlatform.DEVICE_PLATFORM_V2_WIFI_S3, V2_Wifi_S3],
|
||||||
|
[pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR_BLACK, V2_Cell_Black],
|
||||||
|
[pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR_GREEN, V2_Cell_Green]
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function getDevicePlatformDescriber(platform: pond.DevicePlatform): DevicePlatformDescriber {
|
||||||
|
const describer = map.get(platform);
|
||||||
|
return describer ? describer : Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getDevicePlatformLabel(platform: pond.DevicePlatform): string {
|
||||||
|
return getDevicePlatformDescriber(platform).label;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getDevicePlatformDescription(platform: pond.DevicePlatform): string {
|
||||||
|
return getDevicePlatformDescriber(platform).description;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getDevicePlatformIcon(platform: pond.DevicePlatform): any {
|
||||||
|
return getDevicePlatformDescriber(platform).icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getDevicePlatformName(platform: pond.DevicePlatform): string {
|
||||||
|
return getDevicePlatformDescriber(platform).platformName;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GetAllDevicePlatformDescribers(): DevicePlatformDescriber[] {
|
||||||
|
return [...map.values()].filter(p => p.platform !== pond.DevicePlatform.DEVICE_PLATFORM_INVALID);
|
||||||
|
}
|
||||||
|
|
@ -3,14 +3,14 @@
|
||||||
// export { GitlabContext, useGitlab } from "./gitlab";
|
// export { GitlabContext, useGitlab } from "./gitlab";
|
||||||
export { HTTPContext, useHTTP } from "./http";
|
export { HTTPContext, useHTTP } from "./http";
|
||||||
export {
|
export {
|
||||||
// useBackpackAPI,
|
useBackpackAPI,
|
||||||
useBinAPI,
|
useBinAPI,
|
||||||
// useBinYardAPI,
|
// useBinYardAPI,
|
||||||
useNoteAPI,
|
useNoteAPI,
|
||||||
// useComponentAPI,
|
// useComponentAPI,
|
||||||
// useComponentsWebsocket,
|
// useComponentsWebsocket,
|
||||||
// useComponentWebsocket,
|
// useComponentWebsocket,
|
||||||
// useDeviceAPI,
|
useDeviceAPI,
|
||||||
// useDeviceWebsocket,
|
// useDeviceWebsocket,
|
||||||
// useFieldAPI,
|
// useFieldAPI,
|
||||||
// useFieldMarkerAPI,
|
// useFieldMarkerAPI,
|
||||||
|
|
|
||||||
59
src/providers/pond/backpackAPI.tsx
Normal file
59
src/providers/pond/backpackAPI.tsx
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
import { useHTTP } from "hooks";
|
||||||
|
import { pond } from "protobuf-ts/pond";
|
||||||
|
import { createContext, PropsWithChildren, useContext } from "react";
|
||||||
|
import { pondURL } from "./pond";
|
||||||
|
|
||||||
|
export interface IBackpackAPI {
|
||||||
|
addBackpack: (backpack: pond.Backpack) => Promise<any>;
|
||||||
|
updateBackpack: (backpackID: number | Long, backpack: pond.Backpack) => Promise<any>;
|
||||||
|
removeBackpack: (backpackID: number | Long) => Promise<any>;
|
||||||
|
getBackpack: (backpackID: number | Long) => Promise<any>;
|
||||||
|
listBackpacks: () => Promise<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const BackpackAPIContext = createContext<IBackpackAPI>({} as IBackpackAPI);
|
||||||
|
|
||||||
|
export default function BackpackProvider(props: PropsWithChildren<any>) {
|
||||||
|
const { children } = props;
|
||||||
|
const { get, post, put, del } = useHTTP();
|
||||||
|
|
||||||
|
const addBackpack = (backpack: pond.Backpack) => {
|
||||||
|
const url = pondURL("/backpacks");
|
||||||
|
return post(url, backpack);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateBackpack = (backpackID: number | Long, backpack: pond.Backpack) => {
|
||||||
|
const url = pondURL("/backpacks/" + backpackID);
|
||||||
|
return put(url, backpack);
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeBackpack = (backpackID: number | Long) => {
|
||||||
|
const url = pondURL("/backpacks/" + backpackID);
|
||||||
|
return del(url);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getBackpack = (backpackID: number | Long) => {
|
||||||
|
const url = pondURL("/backpacks/" + backpackID);
|
||||||
|
return get(url);
|
||||||
|
};
|
||||||
|
|
||||||
|
const listBackpacks = () => {
|
||||||
|
const url = pondURL("/backpacks");
|
||||||
|
return get(url);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BackpackAPIContext.Provider
|
||||||
|
value={{
|
||||||
|
addBackpack,
|
||||||
|
updateBackpack,
|
||||||
|
removeBackpack,
|
||||||
|
getBackpack,
|
||||||
|
listBackpacks
|
||||||
|
}}>
|
||||||
|
{children}
|
||||||
|
</BackpackAPIContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useBackpackAPI = () => useContext(BackpackAPIContext);
|
||||||
668
src/providers/pond/deviceAPI.tsx
Normal file
668
src/providers/pond/deviceAPI.tsx
Normal file
|
|
@ -0,0 +1,668 @@
|
||||||
|
import { useHTTP, usePermissionAPI } from "hooks";
|
||||||
|
// import { useWebsocket } from "websocket";
|
||||||
|
import { /*Component,*/ deviceScope, User } from "models";
|
||||||
|
import { pond } from "protobuf-ts/pond";
|
||||||
|
import { createContext, PropsWithChildren, useContext } from "react";
|
||||||
|
import { pondURL } from "./pond";
|
||||||
|
import { AxiosResponse } from "axios";
|
||||||
|
import { useGlobalState } from "providers";
|
||||||
|
import { dateRange } from "providers/http";
|
||||||
|
import moment from "moment";
|
||||||
|
|
||||||
|
export interface IDeviceAPIContext {
|
||||||
|
add: (name: string, description: string, backpack: pond.BackpackSettings) => Promise<any>;
|
||||||
|
update: (id: number, settings: pond.DeviceSettings) => Promise<any>;
|
||||||
|
remove: (id: number) => Promise<any>;
|
||||||
|
get: (id: number | string, demo?: boolean, keys?: string[], types?: string[]) => Promise<any>;
|
||||||
|
getPageData: (
|
||||||
|
id: number | string,
|
||||||
|
keys?: string[],
|
||||||
|
types?: string[]
|
||||||
|
) => Promise<AxiosResponse<pond.GetDevicePageDataResponse>>;
|
||||||
|
getMulti: (ids: number[] | string[]) => Promise<any>;
|
||||||
|
getGeoJson: (id: number | string, demo?: boolean) => Promise<any>;
|
||||||
|
getMultiGeoJson: (ids: number[] | string[]) => Promise<any>;
|
||||||
|
list: (
|
||||||
|
limit: number,
|
||||||
|
offset: number,
|
||||||
|
order?: "asc" | "desc",
|
||||||
|
orderBy?: string,
|
||||||
|
search?: string,
|
||||||
|
settings?: string,
|
||||||
|
status?: string,
|
||||||
|
ids?: number[] | string[] | Long[],
|
||||||
|
asRoot?: boolean,
|
||||||
|
comprehensive?: boolean,
|
||||||
|
withMeasurements?: boolean,
|
||||||
|
keys?: string[],
|
||||||
|
types?: string[]
|
||||||
|
) => Promise<AxiosResponse<pond.ListDevicesResponse>>;
|
||||||
|
listForUser: (
|
||||||
|
asRoot: boolean,
|
||||||
|
user?: string,
|
||||||
|
search?: string,
|
||||||
|
hologram?: boolean,
|
||||||
|
keys?: string[],
|
||||||
|
types?: string[]
|
||||||
|
) => Promise<AxiosResponse<pond.ListDevicesResponse>>;
|
||||||
|
claim: (id: number | Long, body: any) => Promise<any>;
|
||||||
|
listHistory: (id: number, limit: number, offset: number) => Promise<any>;
|
||||||
|
listCompleteHistory: (
|
||||||
|
id: number,
|
||||||
|
limit: number,
|
||||||
|
offset: number,
|
||||||
|
filters?: pond.ObjectType[]
|
||||||
|
) => Promise<AxiosResponse<pond.ListCompleteHistoryResponse>>;
|
||||||
|
updatePermissions: (id: number | string, users: User[]) => Promise<any>;
|
||||||
|
updatePreferences: (
|
||||||
|
id: number | string,
|
||||||
|
preferences: pond.UserPreferences,
|
||||||
|
keys?: string[],
|
||||||
|
types?: string[]
|
||||||
|
) => Promise<any>;
|
||||||
|
updateComponentPreferences: (
|
||||||
|
id: number | string,
|
||||||
|
component: string,
|
||||||
|
preferences: pond.DeviceComponentPreferences,
|
||||||
|
keys?: string[],
|
||||||
|
types?: string[]
|
||||||
|
) => Promise<any>;
|
||||||
|
listDeviceComponentPreferences: (
|
||||||
|
id: number | string,
|
||||||
|
keys?: string[],
|
||||||
|
types?: string[]
|
||||||
|
) => Promise<AxiosResponse<pond.ListDeviceComponentPreferencesResponse>>;
|
||||||
|
updateStatus: (
|
||||||
|
id: number | string,
|
||||||
|
status: pond.DeviceStatus,
|
||||||
|
keys?: string[],
|
||||||
|
types?: string[]
|
||||||
|
) => Promise<any>;
|
||||||
|
sync: (id: number) => Promise<any>;
|
||||||
|
clearPending: (id: number) => Promise<any>;
|
||||||
|
pause: (id: number) => Promise<any>;
|
||||||
|
bulkPause: (
|
||||||
|
ids: number[],
|
||||||
|
setPaused: boolean
|
||||||
|
) => Promise<AxiosResponse<pond.BulkPauseDeviceResponse>>;
|
||||||
|
bulkChangeDataCaps: (
|
||||||
|
ids: number[],
|
||||||
|
newCap: number
|
||||||
|
) => Promise<AxiosResponse<pond.BulkChangeDataCapsResponse>>;
|
||||||
|
resume: (id: number) => Promise<any>;
|
||||||
|
getUpgradeStatus: (id: number, keys?: string[], types?: string[]) => Promise<any>;
|
||||||
|
loadBackpack: (id: number, backpack: number) => Promise<any>;
|
||||||
|
setTags: (id: number, tags: string[]) => Promise<any>;
|
||||||
|
setWifi: (
|
||||||
|
id: number,
|
||||||
|
gateway: string,
|
||||||
|
password: string,
|
||||||
|
keys?: string[],
|
||||||
|
types?: string[]
|
||||||
|
) => Promise<any>;
|
||||||
|
tag: (id: number, tag: string) => Promise<any>;
|
||||||
|
untag: (id: number, tag: string) => Promise<any>;
|
||||||
|
getDatacap: (id: number) => Promise<any>;
|
||||||
|
isOverLimit: (id: number) => Promise<any>;
|
||||||
|
isPaused: (id: number) => Promise<any>;
|
||||||
|
setDatacap: (id: number, newCap: number) => Promise<any>;
|
||||||
|
// listJSONMeasurements: (
|
||||||
|
// id: number,
|
||||||
|
// components: Component[],
|
||||||
|
// startDate: any,
|
||||||
|
// endDate: any,
|
||||||
|
// limit: number,
|
||||||
|
// offset: number,
|
||||||
|
// order: string,
|
||||||
|
// orderBy: string
|
||||||
|
// ) => Promise<AxiosResponse<pond.ListDeviceExportedMeasurementsResponse>>;
|
||||||
|
listSimpleJSON: (device: number) => Promise<any>;
|
||||||
|
resetQuackCount: (id: number) => Promise<any>;
|
||||||
|
resetQuackCountTx: (id: number) => Promise<any>;
|
||||||
|
resetQuackCountTx1000: (id: number) => Promise<any>;
|
||||||
|
linearMutation: (
|
||||||
|
id: number,
|
||||||
|
mutation: pond.LinearMutation
|
||||||
|
) => Promise<AxiosResponse<pond.DeviceLinearMutationResponse>>;
|
||||||
|
getDataUsage: (id: number, start?: any) => Promise<any>;
|
||||||
|
buyData: (
|
||||||
|
id: number | string,
|
||||||
|
MB: number,
|
||||||
|
source?: string,
|
||||||
|
keys?: string[],
|
||||||
|
types?: string[]
|
||||||
|
) => Promise<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DeviceAPIContext = createContext<IDeviceAPIContext>({} as IDeviceAPIContext);
|
||||||
|
|
||||||
|
interface Props {}
|
||||||
|
|
||||||
|
export default function DeviceProvider(props: PropsWithChildren<Props>) {
|
||||||
|
const { children } = props;
|
||||||
|
const { get, post, put, del } = useHTTP();
|
||||||
|
const permissionAPI = usePermissionAPI();
|
||||||
|
const [{ as, team }] = useGlobalState();
|
||||||
|
|
||||||
|
const add = (name: string, description: string, backpack: pond.BackpackSettings) => {
|
||||||
|
if (as) return post(pondURL("/devices?as=" + as), { name, description, backpack });
|
||||||
|
return post(pondURL("/devices"), { name, description, backpack });
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDevice = (
|
||||||
|
id: number | string,
|
||||||
|
demo: boolean = false,
|
||||||
|
keys?: string[],
|
||||||
|
types?: string[]
|
||||||
|
) => {
|
||||||
|
if (as && !(types && types.length > 0 && types[0] === "team"))
|
||||||
|
return get(
|
||||||
|
pondURL(
|
||||||
|
"/devices/" +
|
||||||
|
id +
|
||||||
|
"?as=" +
|
||||||
|
as +
|
||||||
|
(keys ? "&keys=" + keys.toString() : "") +
|
||||||
|
(types ? "&types=" + types.toString() : ""),
|
||||||
|
demo
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const url = pondURL(
|
||||||
|
"/devices/" +
|
||||||
|
id +
|
||||||
|
(keys ? "?keys=" + keys.toString() : "") +
|
||||||
|
(types ? "&types=" + types.toString() : ""),
|
||||||
|
demo
|
||||||
|
);
|
||||||
|
return get(url);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDevicePageData = (
|
||||||
|
id: number | string,
|
||||||
|
keys?: string[],
|
||||||
|
types?: string[]
|
||||||
|
): Promise<AxiosResponse<pond.GetDevicePageDataResponse>> => {
|
||||||
|
if (as && !(types && types.length > 0 && types[0] === "team"))
|
||||||
|
return get(
|
||||||
|
pondURL(
|
||||||
|
"/devicePageData/" +
|
||||||
|
id +
|
||||||
|
"?as=" +
|
||||||
|
as +
|
||||||
|
(keys ? "&keys=" + keys.toString() : "") +
|
||||||
|
(types ? "&types=" + types.toString() : "")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const url = pondURL(
|
||||||
|
"/devicePageData/" +
|
||||||
|
id +
|
||||||
|
(keys ? "?keys=" + keys.toString() : "") +
|
||||||
|
(types ? "&types=" + types.toString() : "")
|
||||||
|
);
|
||||||
|
return get<pond.GetDevicePageDataResponse>(url);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDeviceGeoJSON = (id: number | string, demo: boolean = false) => {
|
||||||
|
if (as) return get(pondURL("/devices/" + id + "/geojson?as=" + as, demo));
|
||||||
|
const url = pondURL("/devices/" + id + "/geojson", demo);
|
||||||
|
return get(url);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getMulti = (ids: number[] | string[]) => {
|
||||||
|
let idString = "";
|
||||||
|
ids.forEach((id: number | string, i: number) => {
|
||||||
|
if (i === 0) {
|
||||||
|
idString = idString + id;
|
||||||
|
} else {
|
||||||
|
idString = idString + "," + id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (as) return get(pondURL("/multidevices?devices=" + idString + "&as=" + as));
|
||||||
|
return get(pondURL("/multidevices?devices=" + idString));
|
||||||
|
};
|
||||||
|
|
||||||
|
const getMultiDevicesGeoJSON = (ids: number[] | string[]) => {
|
||||||
|
let idString = "";
|
||||||
|
ids.forEach((id: number | string, i: number) => {
|
||||||
|
if (i === 0) {
|
||||||
|
idString = idString + id;
|
||||||
|
} else {
|
||||||
|
idString = idString + "," + id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (as) return get(pondURL("/geojson/devices?devices=" + idString + "&as=" + as));
|
||||||
|
return get(pondURL("/geojson/devices?devices=" + idString));
|
||||||
|
};
|
||||||
|
|
||||||
|
const list = (
|
||||||
|
limit: number,
|
||||||
|
offset: number,
|
||||||
|
order?: "asc" | "desc",
|
||||||
|
orderBy?: string,
|
||||||
|
search?: string,
|
||||||
|
settings?: string,
|
||||||
|
status?: string,
|
||||||
|
ids?: number[] | string[] | Long[],
|
||||||
|
asRoot?: boolean,
|
||||||
|
comprehensive?: boolean,
|
||||||
|
withMeasurements?: boolean,
|
||||||
|
keys?: string[],
|
||||||
|
types?: string[]
|
||||||
|
) => {
|
||||||
|
const url = pondURL(
|
||||||
|
"/devices" +
|
||||||
|
"?limit=" +
|
||||||
|
limit +
|
||||||
|
"&offset=" +
|
||||||
|
offset +
|
||||||
|
("&order=" + (order ? order : "asc")) +
|
||||||
|
("&by=" + (orderBy ? orderBy : "deviceId")) +
|
||||||
|
(search ? "&search=" + search : "") +
|
||||||
|
(settings ? "&settings=" + settings : "") +
|
||||||
|
(status ? "&status=" + status : "") +
|
||||||
|
(ids ? "&ids=" + ids.join(",") : "") +
|
||||||
|
(asRoot ? "&asRoot=" + asRoot.toString() : "") +
|
||||||
|
(as && !(types && types.length > 0 && types[0] === "team") ? "&as=" + as : "") +
|
||||||
|
(comprehensive ? "&comprehensive=" + comprehensive.toString() : "") +
|
||||||
|
(withMeasurements ? "&measurements=" + withMeasurements.toString() : "") +
|
||||||
|
(keys ? "&keys=" + keys.toString() : "") +
|
||||||
|
(types ? "&types=" + types.toString() : "")
|
||||||
|
);
|
||||||
|
return get<pond.ListDevicesResponse>(url);
|
||||||
|
};
|
||||||
|
|
||||||
|
const listForUser = (
|
||||||
|
asRoot: boolean,
|
||||||
|
user?: string,
|
||||||
|
search?: string,
|
||||||
|
hologram?: boolean,
|
||||||
|
keys?: string[],
|
||||||
|
types?: string[]
|
||||||
|
) => {
|
||||||
|
const url = pondURL(
|
||||||
|
"/devices" +
|
||||||
|
(user ? "?as=" + user : "?asRoot=" + asRoot.toString()) +
|
||||||
|
(search ? "&search=" + search : "") +
|
||||||
|
(hologram ? "&hologram=" + hologram.toString() : "") +
|
||||||
|
(keys ? "&keys=" + keys.toString() : "") +
|
||||||
|
(types ? "&types=" + types.toString() : "")
|
||||||
|
);
|
||||||
|
return get<pond.ListDevicesResponse>(url);
|
||||||
|
};
|
||||||
|
|
||||||
|
const remove = (id: number) => {
|
||||||
|
if (as) return del(pondURL("/devices/" + id + "?as=" + as));
|
||||||
|
const url = pondURL("/devices/" + id);
|
||||||
|
return del(url);
|
||||||
|
};
|
||||||
|
|
||||||
|
const update = (id: number, settings: pond.DeviceSettings) => {
|
||||||
|
if (as) return put(pondURL(`/devices/${id}/update?as=${as}`), settings);
|
||||||
|
const url = pondURL("/devices/" + id + "/update");
|
||||||
|
return put(url, settings);
|
||||||
|
};
|
||||||
|
|
||||||
|
const claim = (id: number | Long, body: any) => {
|
||||||
|
return put(pondURL("/devices/" + id), body);
|
||||||
|
};
|
||||||
|
|
||||||
|
const listHistory = (id: number, limit: number, offset: number) => {
|
||||||
|
return get(pondURL("/devices/" + id + "/history?limit=" + limit + "&offset=" + offset));
|
||||||
|
};
|
||||||
|
const listCompleteHistory = (
|
||||||
|
id: number,
|
||||||
|
limit: number,
|
||||||
|
offset: number,
|
||||||
|
filters?: pond.ObjectType[]
|
||||||
|
) => {
|
||||||
|
return get<pond.ListCompleteHistoryResponse>(
|
||||||
|
pondURL(
|
||||||
|
"/devices/" +
|
||||||
|
id +
|
||||||
|
"/completehistory?limit=" +
|
||||||
|
limit +
|
||||||
|
"&offset=" +
|
||||||
|
offset +
|
||||||
|
(filters ? "&sources=" + filters.toString() : "")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateDevicePermissions = (id: number | string, users: User[]) => {
|
||||||
|
return permissionAPI.updatePermissions(deviceScope(id.toString()), users);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updatePreferences = (
|
||||||
|
id: number | string,
|
||||||
|
preferences: pond.UserPreferences,
|
||||||
|
keys?: string[],
|
||||||
|
types?: string[]
|
||||||
|
) => {
|
||||||
|
return put(
|
||||||
|
pondURL(
|
||||||
|
"/devices/" +
|
||||||
|
id +
|
||||||
|
"/preferences" +
|
||||||
|
"?as=" +
|
||||||
|
as +
|
||||||
|
(keys ? "&keys=" + keys.toString() : "") +
|
||||||
|
(types ? "&types=" + types.toString() : "")
|
||||||
|
),
|
||||||
|
preferences
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateComponentPreferences = (
|
||||||
|
id: number | string,
|
||||||
|
component: string,
|
||||||
|
preferences: pond.DeviceComponentPreferences,
|
||||||
|
keys?: string[],
|
||||||
|
types?: string[]
|
||||||
|
) => {
|
||||||
|
return put(
|
||||||
|
pondURL(
|
||||||
|
"/devices/" +
|
||||||
|
id +
|
||||||
|
"/components/" +
|
||||||
|
component +
|
||||||
|
"/componentPreferences" +
|
||||||
|
"?as=" +
|
||||||
|
as +
|
||||||
|
(keys ? "&keys=" + keys.toString() : "") +
|
||||||
|
(types ? "&types=" + types.toString() : "")
|
||||||
|
),
|
||||||
|
preferences
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const listDeviceComponentPreferences = (
|
||||||
|
id: number | string,
|
||||||
|
keys?: string[],
|
||||||
|
types?: string[]
|
||||||
|
) => {
|
||||||
|
return get<pond.ListDeviceComponentPreferencesResponse>(
|
||||||
|
pondURL(
|
||||||
|
"/devices/" +
|
||||||
|
id +
|
||||||
|
"/componentPreferences?as=" +
|
||||||
|
as +
|
||||||
|
(keys ? "&keys=" + keys.toString() : "") +
|
||||||
|
(types ? "&types=" + types.toString() : "")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateStatus = (
|
||||||
|
id: number | string,
|
||||||
|
status: pond.DeviceStatus,
|
||||||
|
keys?: string[],
|
||||||
|
types?: string[]
|
||||||
|
) => {
|
||||||
|
return put(
|
||||||
|
pondURL(
|
||||||
|
"/devices/" +
|
||||||
|
id +
|
||||||
|
"/updateStatus" +
|
||||||
|
"?as=" +
|
||||||
|
as +
|
||||||
|
(keys ? "&keys=" + keys.toString() : "") +
|
||||||
|
(types ? "&types=" + types.toString() : "")
|
||||||
|
),
|
||||||
|
status
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const sync = (id: number) => {
|
||||||
|
return post(pondURL("/devices/" + id + "/sync"), {});
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearPending = (id: number) => {
|
||||||
|
return post(pondURL("/devices/" + id + "/clearPending"), {});
|
||||||
|
};
|
||||||
|
|
||||||
|
const pause = (id: number) => {
|
||||||
|
return post(pondURL("/devices/" + id + "/pause"), {});
|
||||||
|
};
|
||||||
|
|
||||||
|
const bulkPause = (ids: number[], setPaused: boolean) => {
|
||||||
|
return post<pond.BulkPauseDeviceResponse>(
|
||||||
|
pondURL(
|
||||||
|
"/bulkPauseDevices?ids=" +
|
||||||
|
ids.toString() +
|
||||||
|
(setPaused ? "&pause=" + setPaused.toString() : "")
|
||||||
|
),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const bulkChangeDataCaps = (ids: number[], newCap: number) => {
|
||||||
|
return post<pond.BulkChangeDataCapsResponse>(
|
||||||
|
pondURL("/bulkChangeDataCap?ids=" + ids.toString() + "&dataCap=" + newCap),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const resume = (id: number) => {
|
||||||
|
return post(pondURL("/devices/" + id + "/resume"), {});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getUpgradeStatus = (id: number, keys?: string[], types?: string[]) => {
|
||||||
|
let a = as ? "?as=" + as : "";
|
||||||
|
if (keys && keys.length > 0 && types && types.length > 0) {
|
||||||
|
a = as ? a + "&keys=" + keys + "&types=" + types : "?keys=" + keys + "&types=" + types;
|
||||||
|
}
|
||||||
|
let url = pondURL("/devices/" + id + "/firmware" + a);
|
||||||
|
return get(url);
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadBackpack = (id: number, backpack: number) => {
|
||||||
|
return put(pondURL("/devices/" + id + "/load/" + backpack), {});
|
||||||
|
};
|
||||||
|
|
||||||
|
const setTags = (id: number, tags: string[]) => {
|
||||||
|
return put(pondURL("/devices/" + id + "/tags"), { tags });
|
||||||
|
};
|
||||||
|
|
||||||
|
const setWifi = (
|
||||||
|
id: number,
|
||||||
|
gateway: string,
|
||||||
|
password: string,
|
||||||
|
keys?: string[],
|
||||||
|
types?: string[]
|
||||||
|
) => {
|
||||||
|
let a = as ? "?as=" + as : "";
|
||||||
|
if (keys && keys.length > 0 && types && types.length > 0) {
|
||||||
|
a = as ? a + "&keys=" + keys + "&types=" + types : "?keys=" + keys + "&types=" + types;
|
||||||
|
}
|
||||||
|
return put(pondURL("/devices/" + id + "/wifi" + a), { gateway, password });
|
||||||
|
};
|
||||||
|
|
||||||
|
const tag = (id: number, tag: string) => {
|
||||||
|
return put(pondURL("/devices/" + id + "/tags/" + tag), {});
|
||||||
|
};
|
||||||
|
|
||||||
|
const untag = (id: number, tag: string) => {
|
||||||
|
return del(pondURL("/devices/" + id + "/tags/" + tag));
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDatacap = (id: number) => {
|
||||||
|
return get(pondURL("/devices/" + id + "/datacap/"));
|
||||||
|
};
|
||||||
|
|
||||||
|
const isOverLimit = (id: number) => {
|
||||||
|
return get(pondURL("/devices/" + id + "/overlimit/"));
|
||||||
|
};
|
||||||
|
|
||||||
|
const isPaused = (id: number) => {
|
||||||
|
return get(pondURL("/devices/" + id + "/paused/"));
|
||||||
|
};
|
||||||
|
|
||||||
|
const setDatacap = (id: number, newCap: number) => {
|
||||||
|
return post(pondURL("/devices/" + id + "/datacap?limit=" + newCap));
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDataUsage = (id: number, start?: any) => {
|
||||||
|
if (start) {
|
||||||
|
start = "?start=" + moment(start).toISOString();
|
||||||
|
} else {
|
||||||
|
start = "";
|
||||||
|
}
|
||||||
|
return get(pondURL("/devices/" + id + "/usage/" + start));
|
||||||
|
};
|
||||||
|
|
||||||
|
// const listJSONMeasurements = (
|
||||||
|
// id: number,
|
||||||
|
// components: Component[],
|
||||||
|
// startDate: any,
|
||||||
|
// endDate: any,
|
||||||
|
// limit: number,
|
||||||
|
// offset: number,
|
||||||
|
// order: string,
|
||||||
|
// orderBy: string
|
||||||
|
// ) => {
|
||||||
|
// let keyString = "";
|
||||||
|
// components.forEach((comp, i) => {
|
||||||
|
// if (i === 0) {
|
||||||
|
// keyString = keyString + comp.key();
|
||||||
|
// } else {
|
||||||
|
// keyString = keyString + "," + comp.key();
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// if (as) {
|
||||||
|
// return get<pond.ListDeviceExportedMeasurementsResponse>(
|
||||||
|
// pondURL(
|
||||||
|
// "/devices/" +
|
||||||
|
// id +
|
||||||
|
// "/measurements/exportComplex" +
|
||||||
|
// dateRange(startDate, endDate) +
|
||||||
|
// "&components=" +
|
||||||
|
// keyString +
|
||||||
|
// "&limit=" +
|
||||||
|
// limit +
|
||||||
|
// "&offset=" +
|
||||||
|
// offset +
|
||||||
|
// "&order=" +
|
||||||
|
// order +
|
||||||
|
// "&orderBy=" +
|
||||||
|
// orderBy +
|
||||||
|
// "&as=" +
|
||||||
|
// as
|
||||||
|
// )
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// return get<pond.ListDeviceExportedMeasurementsResponse>(
|
||||||
|
// pondURL(
|
||||||
|
// "/devices/" +
|
||||||
|
// id +
|
||||||
|
// "/measurements/exportComplex" +
|
||||||
|
// dateRange(startDate, endDate) +
|
||||||
|
// "&components=" +
|
||||||
|
// keyString +
|
||||||
|
// "&limit=" +
|
||||||
|
// limit +
|
||||||
|
// "&offset=" +
|
||||||
|
// offset +
|
||||||
|
// "&order=" +
|
||||||
|
// order +
|
||||||
|
// "&orderBy=" +
|
||||||
|
// orderBy
|
||||||
|
// )
|
||||||
|
// );
|
||||||
|
// };
|
||||||
|
|
||||||
|
const listSimpleJSON = (device: number) => {
|
||||||
|
return get(pondURL("/devices/" + device + "/measurements/exportSimple"));
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetQuackCount = (id: number) => {
|
||||||
|
return post(pondURL("/devices/" + id + "/resetCounts"));
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetQuackCountTx = (id: number) => {
|
||||||
|
return post(pondURL("/devices/" + id + "/resetCountTx"));
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetQuackCountTx1000 = (id: number) => {
|
||||||
|
return post(pondURL("/devices/" + id + "/partialResetCountTx"));
|
||||||
|
};
|
||||||
|
|
||||||
|
const linearMutation = (id: number, mutation: pond.LinearMutation) => {
|
||||||
|
return post<pond.DeviceLinearMutationResponse>(
|
||||||
|
pondURL("/devices/" + id + "/linearMutation"),
|
||||||
|
mutation
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const buyData = (
|
||||||
|
id: number | string,
|
||||||
|
MB: number,
|
||||||
|
source?: string,
|
||||||
|
keys?: string[],
|
||||||
|
types?: string[]
|
||||||
|
) => {
|
||||||
|
let url = "/devices/" + id + "/buyData?MB=" + MB;
|
||||||
|
if (as === team.key()) url = url + "&team=" + team.key();
|
||||||
|
if (source) url = url + "&source=" + source;
|
||||||
|
if (keys) url = url + "&keys=" + keys;
|
||||||
|
if (types) url = url + "&types=" + types;
|
||||||
|
return put(pondURL(url));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DeviceAPIContext.Provider
|
||||||
|
value={{
|
||||||
|
add,
|
||||||
|
update,
|
||||||
|
remove,
|
||||||
|
get: getDevice,
|
||||||
|
getPageData: getDevicePageData,
|
||||||
|
getMulti,
|
||||||
|
getGeoJson: getDeviceGeoJSON,
|
||||||
|
getMultiGeoJson: getMultiDevicesGeoJSON,
|
||||||
|
list,
|
||||||
|
claim,
|
||||||
|
listHistory,
|
||||||
|
listCompleteHistory,
|
||||||
|
updatePermissions: updateDevicePermissions,
|
||||||
|
updateStatus,
|
||||||
|
updatePreferences,
|
||||||
|
clearPending,
|
||||||
|
sync,
|
||||||
|
pause,
|
||||||
|
bulkPause,
|
||||||
|
bulkChangeDataCaps,
|
||||||
|
resume,
|
||||||
|
getUpgradeStatus,
|
||||||
|
loadBackpack,
|
||||||
|
setTags,
|
||||||
|
setWifi,
|
||||||
|
tag,
|
||||||
|
untag,
|
||||||
|
getDatacap,
|
||||||
|
isOverLimit,
|
||||||
|
isPaused,
|
||||||
|
setDatacap,
|
||||||
|
// listJSONMeasurements,
|
||||||
|
listSimpleJSON,
|
||||||
|
resetQuackCount,
|
||||||
|
resetQuackCountTx,
|
||||||
|
resetQuackCountTx1000,
|
||||||
|
listForUser,
|
||||||
|
linearMutation,
|
||||||
|
getDataUsage,
|
||||||
|
buyData,
|
||||||
|
updateComponentPreferences,
|
||||||
|
listDeviceComponentPreferences
|
||||||
|
}}>
|
||||||
|
{children}
|
||||||
|
</DeviceAPIContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useDeviceAPI = () => useContext(DeviceAPIContext);
|
||||||
|
|
||||||
|
// export const useDeviceWebsocket = (
|
||||||
|
// id: number | string,
|
||||||
|
// emitter: (m: any) => void,
|
||||||
|
// rate: number = 0
|
||||||
|
// ) => useWebsocket("/devices/" + id, m => Device.any(JSON.parse(m.data)), emitter, rate);
|
||||||
|
|
@ -7,6 +7,8 @@ import { Scope } from "models";
|
||||||
import BinProvider, { useBinAPI } from "./binAPI";
|
import BinProvider, { useBinAPI } from "./binAPI";
|
||||||
import GateProvider, { useGateAPI } from "./gateAPI";
|
import GateProvider, { useGateAPI } from "./gateAPI";
|
||||||
import NoteProvider, { useNoteAPI } from "./noteAPI";
|
import NoteProvider, { useNoteAPI } from "./noteAPI";
|
||||||
|
import DeviceProvider, { useDeviceAPI } from "./deviceAPI";
|
||||||
|
import BackpackProvider, { useBackpackAPI } from "./backpackAPI";
|
||||||
// import NoteProvider from "providers/noteAPI";
|
// import NoteProvider from "providers/noteAPI";
|
||||||
|
|
||||||
export const pondURL = (partial: string, demo: boolean = false): string => {
|
export const pondURL = (partial: string, demo: boolean = false): string => {
|
||||||
|
|
@ -30,7 +32,11 @@ export default function PondProvider(props: PropsWithChildren<any>) {
|
||||||
<BinProvider>
|
<BinProvider>
|
||||||
<GateProvider>
|
<GateProvider>
|
||||||
<NoteProvider>
|
<NoteProvider>
|
||||||
{children}
|
<DeviceProvider>
|
||||||
|
<BackpackProvider>
|
||||||
|
{children}
|
||||||
|
</BackpackProvider>
|
||||||
|
</DeviceProvider>
|
||||||
</NoteProvider>
|
</NoteProvider>
|
||||||
</GateProvider>
|
</GateProvider>
|
||||||
</BinProvider>
|
</BinProvider>
|
||||||
|
|
@ -41,6 +47,8 @@ export default function PondProvider(props: PropsWithChildren<any>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
useBackpackAPI,
|
||||||
|
useDeviceAPI,
|
||||||
useUserAPI,
|
useUserAPI,
|
||||||
useTeamAPI,
|
useTeamAPI,
|
||||||
useImagekitAPI,
|
useImagekitAPI,
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,10 @@ function options(themeType: "light" | "dark"): ThemeOptions {
|
||||||
const highlight = themeType === "light" ? "black" : "white";
|
const highlight = themeType === "light" ? "black" : "white";
|
||||||
const bg = generateBackgroundShades(themeType)
|
const bg = generateBackgroundShades(themeType)
|
||||||
return {
|
return {
|
||||||
|
zIndex: {
|
||||||
|
modal: 1300,
|
||||||
|
popover: 1350
|
||||||
|
},
|
||||||
palette: {
|
palette: {
|
||||||
primary: Colours[getPrimaryColour() as keyof typeof Colours],
|
primary: Colours[getPrimaryColour() as keyof typeof Colours],
|
||||||
secondary: Colours[getSecondaryColour() as keyof typeof Colours],
|
secondary: Colours[getSecondaryColour() as keyof typeof Colours],
|
||||||
|
|
@ -122,7 +126,7 @@ function options(themeType: "light" | "dark"): ThemeOptions {
|
||||||
overflowX: "hidden"
|
overflowX: "hidden"
|
||||||
},
|
},
|
||||||
root: {
|
root: {
|
||||||
zIndex: 1500
|
// zIndex: 1500
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue