Improve VM screen
This commit is contained in:
parent
d4ef389852
commit
767d2015df
@ -1,4 +1,3 @@
|
|||||||
import DeleteIcon from "@mui/icons-material/Delete";
|
|
||||||
import VisibilityIcon from "@mui/icons-material/Visibility";
|
import VisibilityIcon from "@mui/icons-material/Visibility";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
@ -14,15 +13,12 @@ import {
|
|||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { filesize } from "filesize";
|
import { filesize } from "filesize";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
import { VMApi, VMInfo } from "../api/VMApi";
|
import { VMApi, VMInfo } from "../api/VMApi";
|
||||||
import { AsyncWidget } from "../widgets/AsyncWidget";
|
import { AsyncWidget } from "../widgets/AsyncWidget";
|
||||||
import { RouterLink } from "../widgets/RouterLink";
|
import { RouterLink } from "../widgets/RouterLink";
|
||||||
import { VirtWebRouteContainer } from "../widgets/VirtWebRouteContainer";
|
import { VirtWebRouteContainer } from "../widgets/VirtWebRouteContainer";
|
||||||
import { VMStatusWidget } from "../widgets/vms/VMStatusWidget";
|
import { VMStatusWidget } from "../widgets/vms/VMStatusWidget";
|
||||||
import { useSnackbar } from "../hooks/providers/SnackbarProvider";
|
|
||||||
import { useConfirm } from "../hooks/providers/ConfirmDialogProvider";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
import { useAlert } from "../hooks/providers/AlertDialogProvider";
|
|
||||||
|
|
||||||
export function VMListRoute(): React.ReactElement {
|
export function VMListRoute(): React.ReactElement {
|
||||||
const [list, setList] = React.useState<VMInfo[] | undefined>();
|
const [list, setList] = React.useState<VMInfo[] | undefined>();
|
||||||
@ -66,39 +62,8 @@ function VMListWidget(p: {
|
|||||||
list: VMInfo[];
|
list: VMInfo[];
|
||||||
onReload: () => void;
|
onReload: () => void;
|
||||||
}): React.ReactElement {
|
}): React.ReactElement {
|
||||||
const confirm = useConfirm();
|
|
||||||
const alert = useAlert();
|
|
||||||
const snackbar = useSnackbar();
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const deleteVM = async (v: VMInfo) => {
|
|
||||||
try {
|
|
||||||
if (
|
|
||||||
!(await confirm(
|
|
||||||
`Do you really want to delete the vm ${v.name}? The operation CANNOT be undone!`,
|
|
||||||
"Delete a VM",
|
|
||||||
"DELETE"
|
|
||||||
))
|
|
||||||
)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const keepData = !(await confirm(
|
|
||||||
"Do you want to delete the files of the VM?",
|
|
||||||
"Delete a VM",
|
|
||||||
"Delete the data",
|
|
||||||
"keep the data"
|
|
||||||
));
|
|
||||||
|
|
||||||
await VMApi.Delete(v, keepData);
|
|
||||||
snackbar("The VM was successfully deleted!");
|
|
||||||
|
|
||||||
p.onReload();
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
alert(`Failed to delete VM!\n${e}`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableContainer component={Paper}>
|
<TableContainer component={Paper}>
|
||||||
<Table>
|
<Table>
|
||||||
@ -135,11 +100,6 @@ function VMListWidget(p: {
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="Delete this VM">
|
|
||||||
<IconButton onClick={() => deleteVM(row)}>
|
|
||||||
<DeleteIcon />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}
|
))}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Grid } from "@mui/material";
|
import { Box, Button, Grid, Tab, Tabs } from "@mui/material";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { validate as validateUUID } from "uuid";
|
import { validate as validateUUID } from "uuid";
|
||||||
import { IsoFile, IsoFilesApi } from "../../api/IsoFilesApi";
|
import { IsoFile, IsoFilesApi } from "../../api/IsoFilesApi";
|
||||||
@ -16,6 +16,10 @@ import { ResAutostartInput } from "../forms/ResAutostartInput";
|
|||||||
import { VMNetworksList } from "../forms/VMNetworksList";
|
import { VMNetworksList } from "../forms/VMNetworksList";
|
||||||
import { NetworkApi, NetworkInfo } from "../../api/NetworksApi";
|
import { NetworkApi, NetworkInfo } from "../../api/NetworksApi";
|
||||||
import { NWFilterApi, NWFilter } from "../../api/NWFilterApi";
|
import { NWFilterApi, NWFilter } from "../../api/NWFilterApi";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { useAlert } from "../../hooks/providers/AlertDialogProvider";
|
||||||
|
import { useConfirm } from "../../hooks/providers/ConfirmDialogProvider";
|
||||||
|
import { useSnackbar } from "../../hooks/providers/SnackbarProvider";
|
||||||
|
|
||||||
interface DetailsProps {
|
interface DetailsProps {
|
||||||
vm: VMInfo;
|
vm: VMInfo;
|
||||||
@ -59,14 +63,49 @@ export function VMDetails(p: DetailsProps): React.ReactElement {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function VMDetailsInner(
|
enum VMTab {
|
||||||
p: DetailsProps & {
|
General = 0,
|
||||||
|
Storage,
|
||||||
|
Network,
|
||||||
|
Danger,
|
||||||
|
}
|
||||||
|
|
||||||
|
type DetailsInnerProps = DetailsProps & {
|
||||||
isoList: IsoFile[];
|
isoList: IsoFile[];
|
||||||
vcpuCombinations: number[];
|
vcpuCombinations: number[];
|
||||||
networksList: NetworkInfo[];
|
networksList: NetworkInfo[];
|
||||||
networkFiltersList: NWFilter[];
|
networkFiltersList: NWFilter[];
|
||||||
|
};
|
||||||
|
|
||||||
|
function VMDetailsInner(p: DetailsInnerProps): React.ReactElement {
|
||||||
|
const [currTab, setCurrTab] = React.useState(VMTab.General);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Box sx={{ borderBottom: 1, borderColor: "divider" }}>
|
||||||
|
<Tabs value={currTab} onChange={(_ev, newVal) => setCurrTab(newVal)}>
|
||||||
|
<Tab label="General" tabIndex={VMTab.General} />
|
||||||
|
<Tab label="Storage" tabIndex={VMTab.Storage} />
|
||||||
|
<Tab label="Network" tabIndex={VMTab.Network} />
|
||||||
|
{!p.editable && (
|
||||||
|
<Tab
|
||||||
|
label="Danger zone"
|
||||||
|
style={{ color: "red" }}
|
||||||
|
tabIndex={VMTab.Danger}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Tabs>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{currTab === VMTab.General && <VMDetailsTabGeneral {...p} />}
|
||||||
|
{currTab === VMTab.Storage && <VMDetailsTabStorage {...p} />}
|
||||||
|
{currTab === VMTab.Network && <VMDetailsTabNetwork {...p} />}
|
||||||
|
{currTab === VMTab.Danger && <VMDetailsTabDanger {...p} />}
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
): React.ReactElement {
|
|
||||||
|
function VMDetailsTabGeneral(p: DetailsInnerProps): React.ReactElement {
|
||||||
return (
|
return (
|
||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
{
|
{
|
||||||
@ -215,7 +254,13 @@ function VMDetailsInner(
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</EditSection>
|
</EditSection>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function VMDetailsTabStorage(p: DetailsInnerProps): React.ReactElement {
|
||||||
|
return (
|
||||||
|
<Grid container spacing={2}>
|
||||||
{/* Storage section */}
|
{/* Storage section */}
|
||||||
<EditSection title="Storage">
|
<EditSection title="Storage">
|
||||||
<VMSelectIsoInput
|
<VMSelectIsoInput
|
||||||
@ -229,7 +274,13 @@ function VMDetailsInner(
|
|||||||
/>
|
/>
|
||||||
<VMDisksList {...p} />
|
<VMDisksList {...p} />
|
||||||
</EditSection>
|
</EditSection>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function VMDetailsTabNetwork(p: DetailsInnerProps): React.ReactElement {
|
||||||
|
return (
|
||||||
|
<Grid container spacing={2}>
|
||||||
{/* Networks section */}
|
{/* Networks section */}
|
||||||
<EditSection title="Networks">
|
<EditSection title="Networks">
|
||||||
<VMNetworksList {...p} />
|
<VMNetworksList {...p} />
|
||||||
@ -237,3 +288,53 @@ function VMDetailsInner(
|
|||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function VMDetailsTabDanger(p: DetailsInnerProps): React.ReactElement {
|
||||||
|
const confirm = useConfirm();
|
||||||
|
const alert = useAlert();
|
||||||
|
const snackbar = useSnackbar();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const deleteVM = async () => {
|
||||||
|
try {
|
||||||
|
if (
|
||||||
|
!(await confirm(
|
||||||
|
`Do you really want to delete the vm ${p.vm.name}? The operation CANNOT be undone!`,
|
||||||
|
"Delete a VM",
|
||||||
|
"DELETE"
|
||||||
|
))
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const keepData = !(await confirm(
|
||||||
|
"Do you want to delete the files of the VM?",
|
||||||
|
"Delete a VM",
|
||||||
|
"Delete the data",
|
||||||
|
"keep the data"
|
||||||
|
));
|
||||||
|
|
||||||
|
if (
|
||||||
|
!(await confirm(
|
||||||
|
`[LAST CALL] Do you really want to procede with removal? Again, the operation CANNOT be undone!`,
|
||||||
|
"Delete a VM",
|
||||||
|
"DELETE"
|
||||||
|
))
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
|
||||||
|
await VMApi.Delete(p.vm, keepData);
|
||||||
|
snackbar("The VM was successfully deleted!");
|
||||||
|
|
||||||
|
navigate("/vms");
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
alert(`Failed to delete VM!\n${e}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button color="error" onClick={deleteVM}>
|
||||||
|
Delete the VM
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user