Prepare UI for disks backups

This commit is contained in:
2025-05-30 10:28:54 +02:00
parent a18310e04a
commit 83df7e1b20
7 changed files with 145 additions and 43 deletions

View File

@ -1,4 +1,4 @@
import { mdiHarddisk } from "@mdi/js";
import { mdiHarddisk, mdiHarddiskPlus } from "@mdi/js";
import Icon from "@mdi/react";
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
import DeleteIcon from "@mui/icons-material/Delete";
@ -14,16 +14,23 @@ import {
} from "@mui/material";
import { filesize } from "filesize";
import { ServerApi } from "../../api/ServerApi";
import { VMFileDisk, VMInfo } from "../../api/VMApi";
import { VMFileDisk, VMInfo, VMState } from "../../api/VMApi";
import { useConfirm } from "../../hooks/providers/ConfirmDialogProvider";
import { SelectInput } from "./SelectInput";
import { TextInput } from "./TextInput";
import React from "react";
import { ConvertDiskImageDialog } from "../../dialogs/ConvertDiskImageDialog";
export function VMDisksList(p: {
vm: VMInfo;
state?: VMState;
onChange?: () => void;
editable: boolean;
}): React.ReactElement {
const [currBackupRequest, setCurrBackupRequest] = React.useState<
VMFileDisk | undefined
>();
const addNewDisk = () => {
p.vm.file_disks.push({
format: "QCow2",
@ -35,6 +42,14 @@ export function VMDisksList(p: {
p.onChange?.();
};
const handleBackupRequest = (disk: VMFileDisk) => {
setCurrBackupRequest(disk);
};
const handleFinishBackup = () => {
setCurrBackupRequest(undefined);
};
return (
<>
{/* disks list */}
@ -43,25 +58,40 @@ export function VMDisksList(p: {
// eslint-disable-next-line react-x/no-array-index-key
key={num}
editable={p.editable}
canBackup={!p.editable && !d.new && p.state !== "Running"}
disk={d}
onChange={p.onChange}
removeFromList={() => {
p.vm.file_disks.splice(num, 1);
p.onChange?.();
}}
onRequestBackup={handleBackupRequest}
/>
))}
{p.editable && <Button onClick={addNewDisk}>Add new disk</Button>}
{/* Disk backup */}
{currBackupRequest && (
<ConvertDiskImageDialog
backup
onCancel={handleFinishBackup}
onFinished={handleFinishBackup}
vm={p.vm}
disk={currBackupRequest}
/>
)}
</>
);
}
function DiskInfo(p: {
editable: boolean;
canBackup: boolean;
disk: VMFileDisk;
onChange?: () => void;
removeFromList: () => void;
onRequestBackup: (disk: VMFileDisk) => void;
}): React.ReactElement {
const confirm = useConfirm();
const deleteDisk = async () => {
@ -88,23 +118,33 @@ function DiskInfo(p: {
return (
<ListItem
secondaryAction={
p.editable && (
<IconButton
edge="end"
aria-label="delete disk"
onClick={deleteDisk}
>
{p.disk.deleteType ? (
<Tooltip title="Cancel disk removal">
<CheckCircleIcon />
</Tooltip>
) : (
<Tooltip title="Remove disk">
<DeleteIcon />
</Tooltip>
)}
</IconButton>
)
<>
{p.editable && (
<IconButton
edge="end"
aria-label="delete disk"
onClick={deleteDisk}
>
{p.disk.deleteType ? (
<Tooltip title="Cancel disk removal">
<CheckCircleIcon />
</Tooltip>
) : (
<Tooltip title="Remove disk">
<DeleteIcon />
</Tooltip>
)}
</IconButton>
)}
{p.canBackup && (
<Tooltip title="Backup this disk">
<IconButton onClick={() => p.onRequestBackup(p.disk)}>
<Icon path={mdiHarddiskPlus} size={1} />
</IconButton>
</Tooltip>
)}
</>
}
>
<ListItemAvatar>

View File

@ -10,7 +10,7 @@ import { IsoFile, IsoFilesApi } from "../../api/IsoFilesApi";
import { NWFilter, NWFilterApi } from "../../api/NWFilterApi";
import { NetworkApi, NetworkInfo } from "../../api/NetworksApi";
import { ServerApi } from "../../api/ServerApi";
import { VMApi, VMInfo } from "../../api/VMApi";
import { VMApi, VMInfo, VMState } from "../../api/VMApi";
import { useAlert } from "../../hooks/providers/AlertDialogProvider";
import { useConfirm } from "../../hooks/providers/ConfirmDialogProvider";
import { useSnackbar } from "../../hooks/providers/SnackbarProvider";
@ -33,6 +33,7 @@ interface DetailsProps {
editable: boolean;
onChange?: () => void;
screenshot?: boolean;
state?: VMState | undefined;
}
export function VMDetails(p: DetailsProps): React.ReactElement {

View File

@ -0,0 +1,21 @@
import { mdiHarddisk } from "@mdi/js";
import { Icon } from "@mdi/react";
import { Avatar, ListItem, ListItemAvatar, ListItemText } from "@mui/material";
import { filesize } from "filesize";
import { VMFileDisk } from "../../api/VMApi";
export function VMDiskFileWidget(p: { disk: VMFileDisk }): React.ReactElement {
return (
<ListItem>
<ListItemAvatar>
<Avatar>
<Icon path={mdiHarddisk} />
</Avatar>
</ListItemAvatar>
<ListItemText
primary={p.disk.name}
secondary={`${p.disk.format} - ${filesize(p.disk.size)}`}
/>
</ListItem>
);
}