From 767d2015df4150f2c32b5f06e66efa0a96407abc Mon Sep 17 00:00:00 2001 From: Pierre Hubert Date: Tue, 2 Jan 2024 19:52:59 +0100 Subject: [PATCH] Improve VM screen --- virtweb_frontend/src/routes/VMListRoute.tsx | 42 +------ .../src/widgets/vms/VMDetails.tsx | 119 ++++++++++++++++-- 2 files changed, 111 insertions(+), 50 deletions(-) diff --git a/virtweb_frontend/src/routes/VMListRoute.tsx b/virtweb_frontend/src/routes/VMListRoute.tsx index 792abdd..9174740 100644 --- a/virtweb_frontend/src/routes/VMListRoute.tsx +++ b/virtweb_frontend/src/routes/VMListRoute.tsx @@ -1,4 +1,3 @@ -import DeleteIcon from "@mui/icons-material/Delete"; import VisibilityIcon from "@mui/icons-material/Visibility"; import { Button, @@ -14,15 +13,12 @@ import { } from "@mui/material"; import { filesize } from "filesize"; import React from "react"; +import { useNavigate } from "react-router-dom"; import { VMApi, VMInfo } from "../api/VMApi"; import { AsyncWidget } from "../widgets/AsyncWidget"; import { RouterLink } from "../widgets/RouterLink"; import { VirtWebRouteContainer } from "../widgets/VirtWebRouteContainer"; 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 { const [list, setList] = React.useState(); @@ -66,39 +62,8 @@ function VMListWidget(p: { list: VMInfo[]; onReload: () => void; }): React.ReactElement { - const confirm = useConfirm(); - const alert = useAlert(); - const snackbar = useSnackbar(); 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 ( @@ -135,11 +100,6 @@ function VMListWidget(p: { - - deleteVM(row)}> - - - ))} diff --git a/virtweb_frontend/src/widgets/vms/VMDetails.tsx b/virtweb_frontend/src/widgets/vms/VMDetails.tsx index 3904b90..3c6dd20 100644 --- a/virtweb_frontend/src/widgets/vms/VMDetails.tsx +++ b/virtweb_frontend/src/widgets/vms/VMDetails.tsx @@ -1,4 +1,4 @@ -import { Grid } from "@mui/material"; +import { Box, Button, Grid, Tab, Tabs } from "@mui/material"; import React from "react"; import { validate as validateUUID } from "uuid"; import { IsoFile, IsoFilesApi } from "../../api/IsoFilesApi"; @@ -16,6 +16,10 @@ import { ResAutostartInput } from "../forms/ResAutostartInput"; import { VMNetworksList } from "../forms/VMNetworksList"; import { NetworkApi, NetworkInfo } from "../../api/NetworksApi"; 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 { vm: VMInfo; @@ -59,14 +63,49 @@ export function VMDetails(p: DetailsProps): React.ReactElement { ); } -function VMDetailsInner( - p: DetailsProps & { - isoList: IsoFile[]; - vcpuCombinations: number[]; - networksList: NetworkInfo[]; - networkFiltersList: NWFilter[]; - } -): React.ReactElement { +enum VMTab { + General = 0, + Storage, + Network, + Danger, +} + +type DetailsInnerProps = DetailsProps & { + isoList: IsoFile[]; + vcpuCombinations: number[]; + networksList: NetworkInfo[]; + networkFiltersList: NWFilter[]; +}; + +function VMDetailsInner(p: DetailsInnerProps): React.ReactElement { + const [currTab, setCurrTab] = React.useState(VMTab.General); + + return ( + <> + + setCurrTab(newVal)}> + + + + {!p.editable && ( + + )} + + + + {currTab === VMTab.General && } + {currTab === VMTab.Storage && } + {currTab === VMTab.Network && } + {currTab === VMTab.Danger && } + + ); +} + +function VMDetailsTabGeneral(p: DetailsInnerProps): React.ReactElement { return ( { @@ -215,7 +254,13 @@ function VMDetailsInner( /> )} + + ); +} +function VMDetailsTabStorage(p: DetailsInnerProps): React.ReactElement { + return ( + {/* Storage section */} + + ); +} +function VMDetailsTabNetwork(p: DetailsInnerProps): React.ReactElement { + return ( + {/* Networks section */} @@ -237,3 +288,53 @@ function VMDetailsInner( ); } + +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 ( + + ); +}