Files
VirtWeb/virtweb_frontend/src/dialogs/ConvertDiskImageDialog.tsx
Pierre HUBERT 794d16bdaa
Some checks failed
continuous-integration/drone/push Build is failing
Simplify raw disks definition
2025-05-30 11:15:21 +02:00

145 lines
4.3 KiB
TypeScript

import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
} from "@mui/material";
import React from "react";
import { DiskImage, DiskImageApi, DiskImageFormat } from "../api/DiskImageApi";
import { ServerApi } from "../api/ServerApi";
import { VMFileDisk, VMInfo } from "../api/VMApi";
import { useAlert } from "../hooks/providers/AlertDialogProvider";
import { useLoadingMessage } from "../hooks/providers/LoadingMessageProvider";
import { FileDiskImageWidget } from "../widgets/FileDiskImageWidget";
import { CheckboxInput } from "../widgets/forms/CheckboxInput";
import { SelectInput } from "../widgets/forms/SelectInput";
import { TextInput } from "../widgets/forms/TextInput";
import { VMDiskFileWidget } from "../widgets/vms/VMDiskFileWidget";
export function ConvertDiskImageDialog(
p: {
onCancel: () => void;
onFinished: () => void;
} & (
| { backup?: false; image: DiskImage }
| { backup: true; disk: VMFileDisk; vm: VMInfo }
)
): React.ReactElement {
const alert = useAlert();
const loadingMessage = useLoadingMessage();
const [format, setFormat] = React.useState<DiskImageFormat>({
format: "QCow2",
});
const origFilename = p.backup ? p.disk.name : p.image.file_name;
const [filename, setFilename] = React.useState(origFilename + ".qcow2");
const handleFormatChange = (value?: string) => {
setFormat({ format: value ?? ("QCow2" as any) });
if (value === "QCow2") setFilename(`${origFilename}.qcow2`);
if (value === "CompressedQCow2") setFilename(`${origFilename}.qcow2.gz`);
if (value === "Raw") {
setFilename(`${origFilename}.raw`);
// Check sparse checkbox by default
setFormat({ format: "Raw", is_sparse: true });
}
if (value === "CompressedRaw") setFilename(`${origFilename}.raw.gz`);
};
const handleSubmit = async () => {
try {
loadingMessage.show(
p.backup ? "Performing backup..." : "Converting image..."
);
// Perform the conversion / backup operation
if (p.backup)
await DiskImageApi.BackupVMDisk(p.vm, p.disk, filename, format);
else await DiskImageApi.Convert(p.image, filename, format);
p.onFinished();
alert(p.backup ? "Backup successful!" : "Conversion successful!");
} catch (e) {
console.error("Failed to perform backup/conversion!", e);
alert(
p.backup
? `Failed to perform backup! ${e}`
: `Failed to convert image! ${e}`
);
} finally {
loadingMessage.hide();
}
};
return (
<Dialog open onClose={p.onCancel}>
<DialogTitle>
{p.backup ? `Backup disk ${p.disk.name}` : "Convert disk image"}
</DialogTitle>
<DialogContent>
<DialogContentText>
Select the destination format for this image:
</DialogContentText>
{/* Show details of of the image */}
{p.backup ? (
<VMDiskFileWidget {...p} />
) : (
<FileDiskImageWidget {...p} />
)}
{/* New image format */}
<SelectInput
editable
label="Target format"
value={format.format}
onValueChange={handleFormatChange}
options={[
{ value: "QCow2" },
{ value: "Raw" },
{ value: "CompressedRaw" },
{ value: "CompressedQCow2" },
]}
/>
{/* Check for sparse file */}
{format.format === "Raw" && (
<CheckboxInput
editable
label="Sparse file"
checked={format.is_sparse}
onValueChange={(c) => {
setFormat({ format: "Raw", is_sparse: c });
}}
/>
)}
{/* New image name */}
<TextInput
editable
label="New image name"
value={filename}
onValueChange={(s) => {
setFilename(s ?? "");
}}
size={ServerApi.Config.constraints.disk_image_name_size}
helperText="The image name shall contain the proper file extension for the selected target format"
/>
</DialogContent>
<DialogActions>
<Button onClick={p.onCancel}>Cancel</Button>
<Button onClick={handleSubmit} autoFocus>
{p.backup ? "Perform backup" : "Convert image"}
</Button>
</DialogActions>
</Dialog>
);
}