import { Button, Card, Dialog, DialogActions, DialogBody, DialogContent, DialogSurface, DialogTitle, DialogTrigger, Table, TableBody, TableCell, TableCellActions, TableCellLayout, TableHeader, TableHeaderCell, TableRow, Title3, Tooltip, } from "@fluentui/react-components"; import { Desktop24Regular, ScreenshotRegular } from "@fluentui/react-icons"; import { filesize } from "filesize"; import React from "react"; import { GroupApi, GroupVMState } from "../api/GroupApi"; import { Rights, VMGroup } from "../api/ServerApi"; import { VMInfo } from "../api/VMApi"; import { useToast } from "../hooks/providers/ToastProvider"; import { GroupVMAction } from "./GroupVMAction"; import { VMLiveScreenshot } from "./VMLiveScreenshot"; export function GroupsWidget(p: { rights: Rights }): React.ReactElement { return ( <> {p.rights.groups.map((g) => ( <GroupInfo group={g} /> ))} </> ); } function GroupInfo(p: { group: VMGroup }): React.ReactElement { const toast = useToast(); const [state, setState] = React.useState<GroupVMState | undefined>(); const [screenshotVM, setScreenshotVM] = React.useState<VMInfo | undefined>(); const load = async () => { const newState = await GroupApi.State(p.group); if (state !== newState) setState(newState); }; const screenshot = (vm: VMInfo) => { setScreenshotVM(vm); }; React.useEffect(() => { const interval = setInterval(async () => { try { if (p.group.can_get_state) await load(); } catch (e) { console.error(e); toast( "Error", `Failed to refresh group ${p.group.id} VMs status!`, "error" ); } }, 1000); return () => clearInterval(interval); }); return ( <> <Card style={{ margin: "50px 10px", display: "flex", flexDirection: "column", }} > <div style={{ display: "flex", justifyContent: "space-between" }}> <Title3 style={{ marginLeft: "10px" }}>{p.group.id}</Title3> <GroupVMAction group={p.group} /> </div> <Table sortable> <TableHeader> <TableRow> <TableHeaderCell>VM</TableHeaderCell> <TableHeaderCell>Resources</TableHeaderCell> <TableHeaderCell>State</TableHeaderCell> <TableHeaderCell>Actions</TableHeaderCell> </TableRow> </TableHeader> <TableBody> {p.group.vms.map((item) => ( <TableRow key={item.uuid}> <TableCell> <TableCellLayout media={<Desktop24Regular />} appearance="primary" description={item.description} > {item.name} </TableCellLayout> <TableCellActions> {state?.[item.uuid] === "Running" && ( <Tooltip relationship="description" content={"Take a screenshot of the VM screen"} withArrow > <Button icon={<ScreenshotRegular />} appearance="subtle" aria-label="Edit" disabled={!p.group.can_screenshot} onClick={() => screenshot(item)} /> </Tooltip> )} </TableCellActions> </TableCell> <TableCell> {item.architecture} • RAM :{" "} {filesize(item.memory)} •{" "} {item.number_vcpu} vCPU </TableCell> <TableCell>{state?.[item.uuid] ?? ""}</TableCell> <TableCell> <GroupVMAction group={p.group} state={state?.[item.uuid]} vm={item} /> </TableCell> </TableRow> ))} </TableBody> </Table> </Card> <Dialog open={!!screenshotVM} onOpenChange={(_event, _data) => { if (!screenshotVM) setScreenshotVM(undefined); }} > <DialogSurface> <DialogBody> <DialogTitle> <em>{screenshotVM?.name}</em> screen </DialogTitle> <DialogContent> <VMLiveScreenshot vm={screenshotVM!} group={p.group} /> </DialogContent> <DialogActions> <DialogTrigger disableButtonEnhancement> <Button appearance="secondary" onClick={() => setScreenshotVM(undefined)} > Close </Button> </DialogTrigger> </DialogActions> </DialogBody> </DialogSurface> </Dialog> </> ); }