Sort VM by groups in VM list
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is passing
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	continuous-integration/drone/push Build is passing
				
			This commit is contained in:
		@@ -1,3 +1,5 @@
 | 
			
		||||
import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
 | 
			
		||||
import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp";
 | 
			
		||||
import VisibilityIcon from "@mui/icons-material/Visibility";
 | 
			
		||||
import {
 | 
			
		||||
  Button,
 | 
			
		||||
@@ -15,6 +17,7 @@ import {
 | 
			
		||||
import { filesize } from "filesize";
 | 
			
		||||
import React from "react";
 | 
			
		||||
import { useNavigate } from "react-router-dom";
 | 
			
		||||
import { GroupApi } from "../api/GroupApi";
 | 
			
		||||
import { VMApi, VMInfo, VMState } from "../api/VMApi";
 | 
			
		||||
import { AsyncWidget } from "../widgets/AsyncWidget";
 | 
			
		||||
import { RouterLink } from "../widgets/RouterLink";
 | 
			
		||||
@@ -22,11 +25,13 @@ import { VirtWebRouteContainer } from "../widgets/VirtWebRouteContainer";
 | 
			
		||||
import { VMStatusWidget } from "../widgets/vms/VMStatusWidget";
 | 
			
		||||
 | 
			
		||||
export function VMListRoute(): React.ReactElement {
 | 
			
		||||
  const [groups, setGroups] = React.useState<Array<string | undefined>>();
 | 
			
		||||
  const [list, setList] = React.useState<VMInfo[] | undefined>();
 | 
			
		||||
 | 
			
		||||
  const loadKey = React.useRef(1);
 | 
			
		||||
 | 
			
		||||
  const load = async () => {
 | 
			
		||||
    setGroups([undefined, ...(await GroupApi.GetList())]);
 | 
			
		||||
    setList(await VMApi.GetList());
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
@@ -52,7 +57,7 @@ export function VMListRoute(): React.ReactElement {
 | 
			
		||||
            </>
 | 
			
		||||
          }
 | 
			
		||||
        >
 | 
			
		||||
          <VMListWidget list={list!} onReload={reload} />
 | 
			
		||||
          <VMListWidget list={list!} groups={groups!} onReload={reload} />
 | 
			
		||||
        </VirtWebRouteContainer>
 | 
			
		||||
      )}
 | 
			
		||||
    />
 | 
			
		||||
@@ -60,13 +65,25 @@ export function VMListRoute(): React.ReactElement {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function VMListWidget(p: {
 | 
			
		||||
  groups: Array<string | undefined>;
 | 
			
		||||
  list: VMInfo[];
 | 
			
		||||
  onReload: () => void;
 | 
			
		||||
}): React.ReactElement {
 | 
			
		||||
  const navigate = useNavigate();
 | 
			
		||||
 | 
			
		||||
  const [hiddenGroups, setHiddenGroups] = React.useState<
 | 
			
		||||
    Set<string | undefined>
 | 
			
		||||
  >(new Set());
 | 
			
		||||
 | 
			
		||||
  const [runningVMs, setRunningVMs] = React.useState<Set<string>>(new Set());
 | 
			
		||||
 | 
			
		||||
  const toggleHiddenGroup = (g: string | undefined) => {
 | 
			
		||||
    if (hiddenGroups.has(g)) hiddenGroups.delete(g);
 | 
			
		||||
    else hiddenGroups.add(g);
 | 
			
		||||
 | 
			
		||||
    setHiddenGroups(new Set([...hiddenGroups]));
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const updateVMState = (v: VMInfo, s: VMState) => {
 | 
			
		||||
    const running = s !== "Shutoff";
 | 
			
		||||
    if (runningVMs.has(v.name) === running) {
 | 
			
		||||
@@ -93,35 +110,58 @@ function VMListWidget(p: {
 | 
			
		||||
          </TableRow>
 | 
			
		||||
        </TableHead>
 | 
			
		||||
        <TableBody>
 | 
			
		||||
          {p.list.map((row) => (
 | 
			
		||||
            <TableRow
 | 
			
		||||
              hover
 | 
			
		||||
              key={row.name}
 | 
			
		||||
              sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
 | 
			
		||||
              onDoubleClick={() => navigate(row.ViewURL)}
 | 
			
		||||
            >
 | 
			
		||||
              <TableCell component="th" scope="row">
 | 
			
		||||
                {row.name}
 | 
			
		||||
              </TableCell>
 | 
			
		||||
              <TableCell>{row.description ?? ""}</TableCell>
 | 
			
		||||
              <TableCell>{vmMemoryToHuman(row.memory)}</TableCell>
 | 
			
		||||
              <TableCell>{row.number_vcpu}</TableCell>
 | 
			
		||||
              <TableCell>
 | 
			
		||||
                <VMStatusWidget
 | 
			
		||||
                  vm={row}
 | 
			
		||||
                  onChange={(s) => updateVMState(row, s)}
 | 
			
		||||
                />
 | 
			
		||||
              </TableCell>
 | 
			
		||||
              <TableCell>
 | 
			
		||||
                <Tooltip title="View this VM">
 | 
			
		||||
                  <RouterLink to={row.ViewURL}>
 | 
			
		||||
                    <IconButton>
 | 
			
		||||
                      <VisibilityIcon />
 | 
			
		||||
                    </IconButton>
 | 
			
		||||
                  </RouterLink>
 | 
			
		||||
                </Tooltip>
 | 
			
		||||
              </TableCell>
 | 
			
		||||
            </TableRow>
 | 
			
		||||
          {p.groups.map((g, num) => (
 | 
			
		||||
            <React.Fragment key={num}>
 | 
			
		||||
              <TableRow>
 | 
			
		||||
                <TableCell
 | 
			
		||||
                  style={{ paddingBottom: 2, paddingTop: 2 }}
 | 
			
		||||
                  colSpan={6}
 | 
			
		||||
                >
 | 
			
		||||
                  <IconButton size="small" onClick={() => toggleHiddenGroup(g)}>
 | 
			
		||||
                    {!hiddenGroups?.has(g) ? (
 | 
			
		||||
                      <KeyboardArrowUpIcon />
 | 
			
		||||
                    ) : (
 | 
			
		||||
                      <KeyboardArrowDownIcon />
 | 
			
		||||
                    )}
 | 
			
		||||
                  </IconButton>
 | 
			
		||||
                  {g ?? "default"}
 | 
			
		||||
                </TableCell>
 | 
			
		||||
              </TableRow>
 | 
			
		||||
 | 
			
		||||
              {!hiddenGroups.has(g) &&
 | 
			
		||||
                p.list
 | 
			
		||||
                  .filter((row) => row.group === g)
 | 
			
		||||
                  .map((row) => (
 | 
			
		||||
                    <TableRow
 | 
			
		||||
                      hover
 | 
			
		||||
                      key={row.name}
 | 
			
		||||
                      sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
 | 
			
		||||
                      onDoubleClick={() => navigate(row.ViewURL)}
 | 
			
		||||
                    >
 | 
			
		||||
                      <TableCell component="th" scope="row">
 | 
			
		||||
                        {row.name}
 | 
			
		||||
                      </TableCell>
 | 
			
		||||
                      <TableCell>{row.description ?? ""}</TableCell>
 | 
			
		||||
                      <TableCell>{vmMemoryToHuman(row.memory)}</TableCell>
 | 
			
		||||
                      <TableCell>{row.number_vcpu}</TableCell>
 | 
			
		||||
                      <TableCell>
 | 
			
		||||
                        <VMStatusWidget
 | 
			
		||||
                          vm={row}
 | 
			
		||||
                          onChange={(s) => updateVMState(row, s)}
 | 
			
		||||
                        />
 | 
			
		||||
                      </TableCell>
 | 
			
		||||
                      <TableCell>
 | 
			
		||||
                        <Tooltip title="View this VM">
 | 
			
		||||
                          <RouterLink to={row.ViewURL}>
 | 
			
		||||
                            <IconButton>
 | 
			
		||||
                              <VisibilityIcon />
 | 
			
		||||
                            </IconButton>
 | 
			
		||||
                          </RouterLink>
 | 
			
		||||
                        </Tooltip>
 | 
			
		||||
                      </TableCell>
 | 
			
		||||
                    </TableRow>
 | 
			
		||||
                  ))}
 | 
			
		||||
            </React.Fragment>
 | 
			
		||||
          ))}
 | 
			
		||||
        </TableBody>
 | 
			
		||||
        <TableFooter>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user