This commit is contained in:
		@@ -36,6 +36,7 @@ export interface BaseFileVMDisk {
 | 
			
		||||
 | 
			
		||||
  // application attributes
 | 
			
		||||
  new?: boolean;
 | 
			
		||||
  originalSize?: number;
 | 
			
		||||
  deleteType?: "keepfile" | "deletefile";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										24
									
								
								virtweb_frontend/src/widgets/forms/DiskSizeInput.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								virtweb_frontend/src/widgets/forms/DiskSizeInput.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
import { ServerApi } from "../../api/ServerApi";
 | 
			
		||||
import { TextInput } from "./TextInput";
 | 
			
		||||
 | 
			
		||||
export function DiskSizeInput(p: {
 | 
			
		||||
  label?: string;
 | 
			
		||||
  value: number;
 | 
			
		||||
  onChange: (size: number) => void;
 | 
			
		||||
}): React.ReactElement {
 | 
			
		||||
  return (
 | 
			
		||||
    <TextInput
 | 
			
		||||
      editable={true}
 | 
			
		||||
      label={p.label ?? "Disk size (GB)"}
 | 
			
		||||
      size={{
 | 
			
		||||
        min: ServerApi.Config.constraints.disk_size.min / (1000 * 1000 * 1000),
 | 
			
		||||
        max: ServerApi.Config.constraints.disk_size.max / (1000 * 1000 * 1000),
 | 
			
		||||
      }}
 | 
			
		||||
      value={(p.value / (1000 * 1000 * 1000)).toString()}
 | 
			
		||||
      onValueChange={(v) => {
 | 
			
		||||
        p.onChange?.(Number(v ?? "0") * 1000 * 1000 * 1000);
 | 
			
		||||
      }}
 | 
			
		||||
      type="number"
 | 
			
		||||
    />
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
import { mdiHarddiskPlus } from "@mdi/js";
 | 
			
		||||
import Icon from "@mdi/react";
 | 
			
		||||
import ExpandIcon from "@mui/icons-material/Expand";
 | 
			
		||||
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
 | 
			
		||||
import DeleteIcon from "@mui/icons-material/Delete";
 | 
			
		||||
import { Button, IconButton, Paper, Tooltip, Typography } from "@mui/material";
 | 
			
		||||
@@ -15,6 +16,7 @@ import { DiskBusSelect } from "./DiskBusSelect";
 | 
			
		||||
import { DiskImageSelect } from "./DiskImageSelect";
 | 
			
		||||
import { SelectInput } from "./SelectInput";
 | 
			
		||||
import { TextInput } from "./TextInput";
 | 
			
		||||
import { DiskSizeInput } from "./DiskSizeInput";
 | 
			
		||||
 | 
			
		||||
export function VMDisksList(p: {
 | 
			
		||||
  vm: VMInfo;
 | 
			
		||||
@@ -99,6 +101,19 @@ function DiskInfo(p: {
 | 
			
		||||
  diskImagesList: DiskImage[];
 | 
			
		||||
}): React.ReactElement {
 | 
			
		||||
  const confirm = useConfirm();
 | 
			
		||||
 | 
			
		||||
  const expandDisk = () => {
 | 
			
		||||
    if (p.disk.resize === true) {
 | 
			
		||||
      p.disk.resize = false;
 | 
			
		||||
      p.disk.size = p.disk.originalSize!;
 | 
			
		||||
    } else {
 | 
			
		||||
      p.disk.resize = true;
 | 
			
		||||
      p.disk.originalSize = p.disk.size!;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    p.onChange?.();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const deleteDisk = async () => {
 | 
			
		||||
    if (p.disk.deleteType) {
 | 
			
		||||
      p.disk.deleteType = undefined;
 | 
			
		||||
@@ -121,42 +136,74 @@ function DiskInfo(p: {
 | 
			
		||||
 | 
			
		||||
  if (!p.editable || !p.disk.new)
 | 
			
		||||
    return (
 | 
			
		||||
      <VMDiskFileWidget
 | 
			
		||||
        {...p}
 | 
			
		||||
        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.canBackup && (
 | 
			
		||||
              <Tooltip title="Backup this disk">
 | 
			
		||||
      <>
 | 
			
		||||
        <VMDiskFileWidget
 | 
			
		||||
          {...p}
 | 
			
		||||
          secondaryAction={
 | 
			
		||||
            <>
 | 
			
		||||
              {p.editable && (
 | 
			
		||||
                <IconButton
 | 
			
		||||
                  onClick={() => {
 | 
			
		||||
                    p.onRequestBackup(p.disk);
 | 
			
		||||
                  }}
 | 
			
		||||
                  edge="end"
 | 
			
		||||
                  aria-label="expand disk"
 | 
			
		||||
                  onClick={expandDisk}
 | 
			
		||||
                >
 | 
			
		||||
                  <Icon path={mdiHarddiskPlus} size={1} />
 | 
			
		||||
                  {p.disk.resize === true ? (
 | 
			
		||||
                    <Tooltip title="Cancel disk expansion">
 | 
			
		||||
                      <ExpandIcon color="error" />
 | 
			
		||||
                    </Tooltip>
 | 
			
		||||
                  ) : (
 | 
			
		||||
                    <Tooltip title="Increase disk size">
 | 
			
		||||
                      <ExpandIcon />
 | 
			
		||||
                    </Tooltip>
 | 
			
		||||
                  )}
 | 
			
		||||
                </IconButton>
 | 
			
		||||
              </Tooltip>
 | 
			
		||||
            )}
 | 
			
		||||
          </>
 | 
			
		||||
        }
 | 
			
		||||
      />
 | 
			
		||||
              )}
 | 
			
		||||
 | 
			
		||||
              {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>
 | 
			
		||||
              )}
 | 
			
		||||
            </>
 | 
			
		||||
          }
 | 
			
		||||
        />
 | 
			
		||||
 | 
			
		||||
        {/* New disk size*/}
 | 
			
		||||
        {p.disk.resize && (
 | 
			
		||||
          <DiskSizeInput
 | 
			
		||||
            label="New disk size (GB)"
 | 
			
		||||
            value={p.disk.size}
 | 
			
		||||
            onChange={(v) => {
 | 
			
		||||
              p.disk.size = v;
 | 
			
		||||
              p.onChange?.();
 | 
			
		||||
            }}
 | 
			
		||||
          />
 | 
			
		||||
        )}
 | 
			
		||||
      </>
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
@@ -233,21 +280,12 @@ function DiskInfo(p: {
 | 
			
		||||
 | 
			
		||||
      {/* Disk size */}
 | 
			
		||||
      {(!p.disk.from_image || p.disk.resize === true) && (
 | 
			
		||||
        <TextInput
 | 
			
		||||
          editable={true}
 | 
			
		||||
          label="Disk size (GB)"
 | 
			
		||||
          size={{
 | 
			
		||||
            min:
 | 
			
		||||
              ServerApi.Config.constraints.disk_size.min / (1000 * 1000 * 1000),
 | 
			
		||||
            max:
 | 
			
		||||
              ServerApi.Config.constraints.disk_size.max / (1000 * 1000 * 1000),
 | 
			
		||||
          }}
 | 
			
		||||
          value={(p.disk.size / (1000 * 1000 * 1000)).toString()}
 | 
			
		||||
          onValueChange={(v) => {
 | 
			
		||||
            p.disk.size = Number(v ?? "0") * 1000 * 1000 * 1000;
 | 
			
		||||
        <DiskSizeInput
 | 
			
		||||
          value={p.disk.size}
 | 
			
		||||
          onChange={(v) => {
 | 
			
		||||
            p.disk.size = v;
 | 
			
		||||
            p.onChange?.();
 | 
			
		||||
          }}
 | 
			
		||||
          type="number"
 | 
			
		||||
        />
 | 
			
		||||
      )}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user