Files
SolarEnergy/central_frontend/src/dialogs/DeployOTAUpdateDialogProvider.tsx
2024-10-09 18:46:51 +02:00

149 lines
4.5 KiB
TypeScript

import {
Button,
Checkbox,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
FormControl,
FormControlLabel,
FormGroup,
FormLabel,
Radio,
RadioGroup,
Typography,
} from "@mui/material";
import React from "react";
import { Device, DeviceApi } from "../api/DeviceApi";
import { OTAAPI, OTAUpdate } from "../api/OTAApi";
import { useAlert } from "../hooks/context_providers/AlertDialogProvider";
import { useConfirm } from "../hooks/context_providers/ConfirmDialogProvider";
import { useLoadingMessage } from "../hooks/context_providers/LoadingMessageProvider";
import { useSnackbar } from "../hooks/context_providers/SnackbarProvider";
import { AsyncWidget } from "../widgets/AsyncWidget";
export function DeployOTAUpdateDialogProvider(p: {
update: OTAUpdate;
onClose: () => void;
}): React.ReactElement {
const loadingMessage = useLoadingMessage();
const alert = useAlert();
const confirm = useConfirm();
const snackbar = useSnackbar();
const [devicesList, setDevicesList] = React.useState<Device[] | undefined>();
const loadDevicesList = async () => {
let list = await DeviceApi.ValidatedList();
list = list.filter((e) => e.info.reference == p.update.platform);
setDevicesList(list);
};
const [allDevices, setAllDevices] = React.useState(false);
const [selectedDevices, setSelectedDevices] = React.useState<string[]>([]);
const startDeployment = async () => {
if (
allDevices &&
!(await confirm(
"Do you really want to deploy the update to all devices?"
))
)
return;
try {
loadingMessage.show("Applying OTA update...");
await OTAAPI.SetDesiredVersion(p.update, allDevices, selectedDevices);
snackbar("The update was successfully applied!");
p.onClose();
} catch (e) {
console.error("Failed to deploy the udpate!", e);
alert(`Failed to deploy the udpate! ${e}`);
} finally {
loadingMessage.hide();
}
};
return (
<Dialog open={true} onClose={p.onClose}>
<DialogTitle>
Deploy update <i>{p.update.version}</i> for platform{" "}
<i>{p.update.platform}</i>
</DialogTitle>
<AsyncWidget
loadKey={1}
load={loadDevicesList}
errMsg="Failed to load the list of devices!"
build={() => (
<DialogContent>
<DialogContentText>
You can choose to deploy update to all device or to target only a
part of devices:
</DialogContentText>
<FormControl>
<FormLabel>Gender</FormLabel>
<RadioGroup
name="radio-buttons-group"
value={allDevices}
onChange={(v) => setAllDevices(v.target.value == "true")}
>
<FormControlLabel
value={true}
control={<Radio />}
label="Deploy the update to all the devices of the platform"
/>
<FormControlLabel
value={false}
control={<Radio />}
label="Deploy the update to a limited range of devices"
/>
</RadioGroup>
</FormControl>
{!allDevices && (
<Typography>
There are no devices to which the update can be deployed.
</Typography>
)}
{!allDevices && (
<FormGroup>
{devicesList?.map((d) => (
<FormControlLabel
control={
<Checkbox
checked={selectedDevices.includes(d.id)}
onChange={(_e, v) => {
if (v) {
selectedDevices.push(d.id);
setSelectedDevices([...selectedDevices]);
} else
setSelectedDevices(
selectedDevices.filter((e) => e != d.id)
);
}}
/>
}
label={d.name}
/>
))}
</FormGroup>
)}
</DialogContent>
)}
/>
<DialogActions>
<Button onClick={p.onClose}>Cancel</Button>
<Button
onClick={startDeployment}
autoFocus
disabled={!allDevices && selectedDevices.length == 0}
>
Start deployment
</Button>
</DialogActions>
</Dialog>
);
}