145 lines
4.3 KiB
TypeScript
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>
|
|
);
|
|
}
|