WIP ESLint fixes
This commit is contained in:
		@@ -38,6 +38,7 @@ export default tseslint.config(
 | 
				
			|||||||
      ],
 | 
					      ],
 | 
				
			||||||
      ...reactX.configs["recommended-typescript"].rules,
 | 
					      ...reactX.configs["recommended-typescript"].rules,
 | 
				
			||||||
      ...reactDom.configs.recommended.rules,
 | 
					      ...reactDom.configs.recommended.rules,
 | 
				
			||||||
 | 
					      "@typescript-eslint/no-non-null-assertion": "off"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -51,7 +51,7 @@ export function App() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  const context: AuthContext = {
 | 
					  const context: AuthContext = {
 | 
				
			||||||
    signedIn: signedIn,
 | 
					    signedIn: signedIn,
 | 
				
			||||||
    setSignedIn: (s) => setSignedIn(s),
 | 
					    setSignedIn: (s) => { setSignedIn(s); },
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const router = createBrowserRouter(
 | 
					  const router = createBrowserRouter(
 | 
				
			||||||
@@ -97,12 +97,12 @@ export function App() {
 | 
				
			|||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <AuthContextK.Provider value={context}>
 | 
					    <AuthContextK value={context}>
 | 
				
			||||||
      <RouterProvider router={router} />
 | 
					      <RouterProvider router={router} />
 | 
				
			||||||
    </AuthContextK.Provider>
 | 
					    </AuthContextK>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function useAuth(): AuthContext {
 | 
					export function useAuth(): AuthContext {
 | 
				
			||||||
  return React.useContext(AuthContextK)!;
 | 
					  return React.use(AuthContextK)!;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,7 +44,7 @@ export class APIClient {
 | 
				
			|||||||
   */
 | 
					   */
 | 
				
			||||||
  static async exec(args: RequestParams): Promise<APIResponse> {
 | 
					  static async exec(args: RequestParams): Promise<APIResponse> {
 | 
				
			||||||
    let body: string | undefined | FormData = undefined;
 | 
					    let body: string | undefined | FormData = undefined;
 | 
				
			||||||
    let headers: any = {};
 | 
					    const headers: any = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // JSON request
 | 
					    // JSON request
 | 
				
			||||||
    if (args.jsonData) {
 | 
					    if (args.jsonData) {
 | 
				
			||||||
@@ -67,17 +67,17 @@ export class APIClient {
 | 
				
			|||||||
      const res: XMLHttpRequest = await new Promise((resolve, reject) => {
 | 
					      const res: XMLHttpRequest = await new Promise((resolve, reject) => {
 | 
				
			||||||
        const xhr = new XMLHttpRequest();
 | 
					        const xhr = new XMLHttpRequest();
 | 
				
			||||||
        xhr.upload.addEventListener("progress", (e) =>
 | 
					        xhr.upload.addEventListener("progress", (e) =>
 | 
				
			||||||
          args.upProgress!(e.loaded / e.total)
 | 
					          { args.upProgress!(e.loaded / e.total); }
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        xhr.addEventListener("load", () => resolve(xhr));
 | 
					        xhr.addEventListener("load", () => { resolve(xhr); });
 | 
				
			||||||
        xhr.addEventListener("error", () =>
 | 
					        xhr.addEventListener("error", () =>
 | 
				
			||||||
          reject(new Error("File upload failed"))
 | 
					          { reject(new Error("File upload failed")); }
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        xhr.addEventListener("abort", () =>
 | 
					        xhr.addEventListener("abort", () =>
 | 
				
			||||||
          reject(new Error("File upload aborted"))
 | 
					          { reject(new Error("File upload aborted")); }
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        xhr.addEventListener("timeout", () =>
 | 
					        xhr.addEventListener("timeout", () =>
 | 
				
			||||||
          reject(new Error("File upload timeout"))
 | 
					          { reject(new Error("File upload timeout")); }
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        xhr.open(args.method, url, true);
 | 
					        xhr.open(args.method, url, true);
 | 
				
			||||||
        xhr.withCredentials = true;
 | 
					        xhr.withCredentials = true;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -140,7 +140,7 @@ export interface NWFilter {
 | 
				
			|||||||
  rules: NWFilterRule[];
 | 
					  rules: NWFilterRule[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function NWFilterURL(n: NWFilter, edit: boolean = false): string {
 | 
					export function NWFilterURL(n: NWFilter, edit = false): string {
 | 
				
			||||||
  return `/nwfilter/${n.uuid}${edit ? "/edit" : ""}`;
 | 
					  return `/nwfilter/${n.uuid}${edit ? "/edit" : ""}`;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -221,7 +221,7 @@ export class NWFilterApi {
 | 
				
			|||||||
  static async Delete(n: NWFilter): Promise<void> {
 | 
					  static async Delete(n: NWFilter): Promise<void> {
 | 
				
			||||||
    await APIClient.exec({
 | 
					    await APIClient.exec({
 | 
				
			||||||
      method: "DELETE",
 | 
					      method: "DELETE",
 | 
				
			||||||
      uri: `/nwfilter/${n.uuid}`,
 | 
					      uri: `/nwfilter/${n.uuid!}`,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -53,7 +53,7 @@ export interface NetworkInfo {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export type NetworkStatus = "Started" | "Stopped";
 | 
					export type NetworkStatus = "Started" | "Stopped";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function NetworkURL(n: NetworkInfo, edit: boolean = false): string {
 | 
					export function NetworkURL(n: NetworkInfo, edit = false): string {
 | 
				
			||||||
  return `/net/${n.uuid}${edit ? "/edit" : ""}`;
 | 
					  return `/net/${n.uuid}${edit ? "/edit" : ""}`;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,7 @@ export interface APIToken {
 | 
				
			|||||||
  max_inactivity?: number;
 | 
					  max_inactivity?: number;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function APITokenURL(t: APIToken, edit: boolean = false): string {
 | 
					export function APITokenURL(t: APIToken, edit = false): string {
 | 
				
			||||||
  return `/token/${t.id}${edit ? "/edit" : ""}`;
 | 
					  return `/token/${t.id}${edit ? "/edit" : ""}`;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,7 +39,7 @@ export function AlertDialogProvider(p: PropsWithChildren): React.ReactElement {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <>
 | 
				
			||||||
      <AlertContextK.Provider value={hook}>{p.children}</AlertContextK.Provider>
 | 
					      <AlertContextK value={hook}>{p.children}</AlertContextK>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <Dialog
 | 
					      <Dialog
 | 
				
			||||||
        open={open}
 | 
					        open={open}
 | 
				
			||||||
@@ -67,5 +67,5 @@ export function AlertDialogProvider(p: PropsWithChildren): React.ReactElement {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function useAlert(): AlertContext {
 | 
					export function useAlert(): AlertContext {
 | 
				
			||||||
  return React.useContext(AlertContextK)!;
 | 
					  return React.use(AlertContextK)!;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -59,13 +59,13 @@ export function ConfirmDialogProvider(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <>
 | 
				
			||||||
      <ConfirmContextK.Provider value={hook}>
 | 
					      <ConfirmContextK value={hook}>
 | 
				
			||||||
        {p.children}
 | 
					        {p.children}
 | 
				
			||||||
      </ConfirmContextK.Provider>
 | 
					      </ConfirmContextK>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <Dialog
 | 
					      <Dialog
 | 
				
			||||||
        open={open}
 | 
					        open={open}
 | 
				
			||||||
        onClose={() => handleClose(false)}
 | 
					        onClose={() => { handleClose(false); }}
 | 
				
			||||||
        aria-labelledby="alert-dialog-title"
 | 
					        aria-labelledby="alert-dialog-title"
 | 
				
			||||||
        aria-describedby="alert-dialog-description"
 | 
					        aria-describedby="alert-dialog-description"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
@@ -76,10 +76,10 @@ export function ConfirmDialogProvider(
 | 
				
			|||||||
          </DialogContentText>
 | 
					          </DialogContentText>
 | 
				
			||||||
        </DialogContent>
 | 
					        </DialogContent>
 | 
				
			||||||
        <DialogActions>
 | 
					        <DialogActions>
 | 
				
			||||||
          <Button onClick={() => handleClose(false)} autoFocus>
 | 
					          <Button onClick={() => { handleClose(false); }} autoFocus>
 | 
				
			||||||
            {cancelButton ?? "Cancel"}
 | 
					            {cancelButton ?? "Cancel"}
 | 
				
			||||||
          </Button>
 | 
					          </Button>
 | 
				
			||||||
          <Button onClick={() => handleClose(true)} color="error">
 | 
					          <Button onClick={() => { handleClose(true); }} color="error">
 | 
				
			||||||
            {confirmButton ?? "Confirm"}
 | 
					            {confirmButton ?? "Confirm"}
 | 
				
			||||||
          </Button>
 | 
					          </Button>
 | 
				
			||||||
        </DialogActions>
 | 
					        </DialogActions>
 | 
				
			||||||
@@ -89,5 +89,5 @@ export function ConfirmDialogProvider(
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function useConfirm(): ConfirmContext {
 | 
					export function useConfirm(): ConfirmContext {
 | 
				
			||||||
  return React.useContext(ConfirmContextK)!;
 | 
					  return React.use(ConfirmContextK)!;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,10 +6,10 @@ import {
 | 
				
			|||||||
} from "@mui/material";
 | 
					} from "@mui/material";
 | 
				
			||||||
import React, { PropsWithChildren } from "react";
 | 
					import React, { PropsWithChildren } from "react";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type LoadingMessageContext = {
 | 
					interface LoadingMessageContext {
 | 
				
			||||||
  show: (message: string) => void;
 | 
					  show: (message: string) => void;
 | 
				
			||||||
  hide: () => void;
 | 
					  hide: () => void;
 | 
				
			||||||
};
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const LoadingMessageContextK =
 | 
					const LoadingMessageContextK =
 | 
				
			||||||
  React.createContext<LoadingMessageContext | null>(null);
 | 
					  React.createContext<LoadingMessageContext | null>(null);
 | 
				
			||||||
@@ -34,9 +34,9 @@ export function LoadingMessageProvider(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <>
 | 
				
			||||||
      <LoadingMessageContextK.Provider value={hook}>
 | 
					      <LoadingMessageContextK value={hook}>
 | 
				
			||||||
        {p.children}
 | 
					        {p.children}
 | 
				
			||||||
      </LoadingMessageContextK.Provider>
 | 
					      </LoadingMessageContextK>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <Dialog open={open}>
 | 
					      <Dialog open={open}>
 | 
				
			||||||
        <DialogContent>
 | 
					        <DialogContent>
 | 
				
			||||||
@@ -60,5 +60,5 @@ export function LoadingMessageProvider(
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function useLoadingMessage(): LoadingMessageContext {
 | 
					export function useLoadingMessage(): LoadingMessageContext {
 | 
				
			||||||
  return React.useContext(LoadingMessageContextK)!;
 | 
					  return React.use(LoadingMessageContextK)!;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,9 +24,9 @@ export function SnackbarProvider(p: PropsWithChildren): React.ReactElement {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <>
 | 
				
			||||||
      <SnackbarContextK.Provider value={hook}>
 | 
					      <SnackbarContextK value={hook}>
 | 
				
			||||||
        {p.children}
 | 
					        {p.children}
 | 
				
			||||||
      </SnackbarContextK.Provider>
 | 
					      </SnackbarContextK>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <Snackbar
 | 
					      <Snackbar
 | 
				
			||||||
        open={open}
 | 
					        open={open}
 | 
				
			||||||
@@ -39,5 +39,5 @@ export function SnackbarProvider(p: PropsWithChildren): React.ReactElement {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function useSnackbar(): SnackbarContext {
 | 
					export function useSnackbar(): SnackbarContext {
 | 
				
			||||||
  return React.useContext(SnackbarContextK)!;
 | 
					  return React.use(SnackbarContextK)!;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,7 +21,7 @@ const darkTheme = createTheme({
 | 
				
			|||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const root = ReactDOM.createRoot(
 | 
					const root = ReactDOM.createRoot(
 | 
				
			||||||
  document.getElementById("root") as HTMLElement
 | 
					  document.getElementById("root")!
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
root.render(
 | 
					root.render(
 | 
				
			||||||
  <React.StrictMode>
 | 
					  <React.StrictMode>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -116,7 +116,7 @@ function EditApiTokenRouteInner(p: {
 | 
				
			|||||||
  const [changed, setChanged] = React.useState(false);
 | 
					  const [changed, setChanged] = React.useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [, updateState] = React.useState<any>();
 | 
					  const [, updateState] = React.useState<any>();
 | 
				
			||||||
  const forceUpdate = React.useCallback(() => updateState({}), []);
 | 
					  const forceUpdate = React.useCallback(() => { updateState({}); }, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const valueChanged = () => {
 | 
					  const valueChanged = () => {
 | 
				
			||||||
    setChanged(true);
 | 
					    setChanged(true);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -99,7 +99,7 @@ function EditNetworkFilterRouteInner(p: {
 | 
				
			|||||||
  const [changed, setChanged] = React.useState(false);
 | 
					  const [changed, setChanged] = React.useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [, updateState] = React.useState<any>();
 | 
					  const [, updateState] = React.useState<any>();
 | 
				
			||||||
  const forceUpdate = React.useCallback(() => updateState({}), []);
 | 
					  const forceUpdate = React.useCallback(() => { updateState({}); }, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const valueChanged = () => {
 | 
					  const valueChanged = () => {
 | 
				
			||||||
    setChanged(true);
 | 
					    setChanged(true);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -97,7 +97,7 @@ function EditNetworkRouteInner(p: {
 | 
				
			|||||||
  const [changed, setChanged] = React.useState(false);
 | 
					  const [changed, setChanged] = React.useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [, updateState] = React.useState<any>();
 | 
					  const [, updateState] = React.useState<any>();
 | 
				
			||||||
  const forceUpdate = React.useCallback(() => updateState({}), []);
 | 
					  const forceUpdate = React.useCallback(() => { updateState({}); }, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const valueChanged = () => {
 | 
					  const valueChanged = () => {
 | 
				
			||||||
    setChanged(true);
 | 
					    setChanged(true);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -103,7 +103,7 @@ function EditVMInner(p: {
 | 
				
			|||||||
  const [changed, setChanged] = React.useState(false);
 | 
					  const [changed, setChanged] = React.useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [, updateState] = React.useState<any>();
 | 
					  const [, updateState] = React.useState<any>();
 | 
				
			||||||
  const forceUpdate = React.useCallback(() => updateState({}), []);
 | 
					  const forceUpdate = React.useCallback(() => { updateState({}); }, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const valueChanged = () => {
 | 
					  const valueChanged = () => {
 | 
				
			||||||
    setChanged(true);
 | 
					    setChanged(true);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -166,14 +166,14 @@ function UploadIsoFileFromUrlCard(p: {
 | 
				
			|||||||
          label="URL"
 | 
					          label="URL"
 | 
				
			||||||
          value={url}
 | 
					          value={url}
 | 
				
			||||||
          style={{ flex: 3 }}
 | 
					          style={{ flex: 3 }}
 | 
				
			||||||
          onChange={(e) => setURL(e.target.value)}
 | 
					          onChange={(e) => { setURL(e.target.value); }}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
        <span style={{ width: "10px" }}></span>
 | 
					        <span style={{ width: "10px" }}></span>
 | 
				
			||||||
        <TextField
 | 
					        <TextField
 | 
				
			||||||
          label="Filename"
 | 
					          label="Filename"
 | 
				
			||||||
          value={actualFileName}
 | 
					          value={actualFileName}
 | 
				
			||||||
          style={{ flex: 2 }}
 | 
					          style={{ flex: 2 }}
 | 
				
			||||||
          onChange={(e) => setFilename(e.target.value)}
 | 
					          onChange={(e) => { setFilename(e.target.value); }}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
        {url !== "" && actualFileName !== "" && (
 | 
					        {url !== "" && actualFileName !== "" && (
 | 
				
			||||||
          <Button onClick={upload}>Upload file</Button>
 | 
					          <Button onClick={upload}>Upload file</Button>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -78,7 +78,7 @@ function NetworkFiltersListRouteInner(p: {
 | 
				
			|||||||
            size="small"
 | 
					            size="small"
 | 
				
			||||||
            value={visibleFilters}
 | 
					            value={visibleFilters}
 | 
				
			||||||
            exclusive
 | 
					            exclusive
 | 
				
			||||||
            onChange={(_ev, v) => setVisibleFilters(v)}
 | 
					            onChange={(_ev, v) => { setVisibleFilters(v); }}
 | 
				
			||||||
            aria-label="visible filters"
 | 
					            aria-label="visible filters"
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            <ToggleButton value={VisibleFilters.All}>All</ToggleButton>
 | 
					            <ToggleButton value={VisibleFilters.All}>All</ToggleButton>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -236,7 +236,7 @@ export function SysInfoRouteInner(p: {
 | 
				
			|||||||
function SysInfoDetailsTable(p: {
 | 
					function SysInfoDetailsTable(p: {
 | 
				
			||||||
  label: string;
 | 
					  label: string;
 | 
				
			||||||
  icon: React.ReactElement;
 | 
					  icon: React.ReactElement;
 | 
				
			||||||
  entries: Array<{ label: string; value: string | number }>;
 | 
					  entries: { label: string; value: string | number }[];
 | 
				
			||||||
}): React.ReactElement {
 | 
					}): React.ReactElement {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <VirtWebPaper
 | 
					    <VirtWebPaper
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,13 +25,13 @@ import { VirtWebRouteContainer } from "../widgets/VirtWebRouteContainer";
 | 
				
			|||||||
import { VMStatusWidget } from "../widgets/vms/VMStatusWidget";
 | 
					import { VMStatusWidget } from "../widgets/vms/VMStatusWidget";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function VMListRoute(): React.ReactElement {
 | 
					export function VMListRoute(): React.ReactElement {
 | 
				
			||||||
  const [groups, setGroups] = React.useState<Array<string | undefined>>();
 | 
					  const [groups, setGroups] = React.useState<(string | undefined)[]>();
 | 
				
			||||||
  const [list, setList] = React.useState<VMInfo[] | undefined>();
 | 
					  const [list, setList] = React.useState<VMInfo[] | undefined>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const loadKey = React.useRef(1);
 | 
					  const loadKey = React.useRef(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const load = async () => {
 | 
					  const load = async () => {
 | 
				
			||||||
    const groups: Array<string | undefined> = await GroupApi.GetList();
 | 
					    const groups: (string | undefined)[] = await GroupApi.GetList();
 | 
				
			||||||
    const list = await VMApi.GetList();
 | 
					    const list = await VMApi.GetList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (list.find((v) => !v.group) !== undefined) groups.push(undefined);
 | 
					    if (list.find((v) => !v.group) !== undefined) groups.push(undefined);
 | 
				
			||||||
@@ -70,7 +70,7 @@ export function VMListRoute(): React.ReactElement {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function VMListWidget(p: {
 | 
					function VMListWidget(p: {
 | 
				
			||||||
  groups: Array<string | undefined>;
 | 
					  groups: (string | undefined)[];
 | 
				
			||||||
  list: VMInfo[];
 | 
					  list: VMInfo[];
 | 
				
			||||||
  onReload: () => void;
 | 
					  onReload: () => void;
 | 
				
			||||||
}): React.ReactElement {
 | 
					}): React.ReactElement {
 | 
				
			||||||
@@ -125,9 +125,9 @@ function VMListWidget(p: {
 | 
				
			|||||||
                  >
 | 
					                  >
 | 
				
			||||||
                    <IconButton
 | 
					                    <IconButton
 | 
				
			||||||
                      size="small"
 | 
					                      size="small"
 | 
				
			||||||
                      onClick={() => toggleHiddenGroup(g)}
 | 
					                      onClick={() => { toggleHiddenGroup(g); }}
 | 
				
			||||||
                    >
 | 
					                    >
 | 
				
			||||||
                      {!hiddenGroups?.has(g) ? (
 | 
					                      {!hiddenGroups.has(g) ? (
 | 
				
			||||||
                        <KeyboardArrowUpIcon />
 | 
					                        <KeyboardArrowUpIcon />
 | 
				
			||||||
                      ) : (
 | 
					                      ) : (
 | 
				
			||||||
                        <KeyboardArrowDownIcon />
 | 
					                        <KeyboardArrowDownIcon />
 | 
				
			||||||
@@ -157,7 +157,7 @@ function VMListWidget(p: {
 | 
				
			|||||||
                      <TableCell>
 | 
					                      <TableCell>
 | 
				
			||||||
                        <VMStatusWidget
 | 
					                        <VMStatusWidget
 | 
				
			||||||
                          vm={row}
 | 
					                          vm={row}
 | 
				
			||||||
                          onChange={(s) => updateVMState(row, s)}
 | 
					                          onChange={(s) => { updateVMState(row, s); }}
 | 
				
			||||||
                        />
 | 
					                        />
 | 
				
			||||||
                      </TableCell>
 | 
					                      </TableCell>
 | 
				
			||||||
                      <TableCell>
 | 
					                      <TableCell>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -91,7 +91,7 @@ function VNCInner(p: { vm: VMInfo }): React.ReactElement {
 | 
				
			|||||||
    connect(false);
 | 
					    connect(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (vncRef.current) {
 | 
					    if (vncRef.current) {
 | 
				
			||||||
      vncRef.current.onfullscreenchange = () => setCounter(counter + 1);
 | 
					      vncRef.current.onfullscreenchange = () => { setCounter(counter + 1); };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -140,10 +140,10 @@ function VNCInner(p: { vm: VMInfo }): React.ReactElement {
 | 
				
			|||||||
          ref={vncScreenRef}
 | 
					          ref={vncScreenRef}
 | 
				
			||||||
          url={token.url}
 | 
					          url={token.url}
 | 
				
			||||||
          onDisconnect={() => {
 | 
					          onDisconnect={() => {
 | 
				
			||||||
            console.info("VNC disconnected " + token?.url);
 | 
					            console.info("VNC disconnected " + token.url);
 | 
				
			||||||
            disconnected();
 | 
					            disconnected();
 | 
				
			||||||
          }}
 | 
					          }}
 | 
				
			||||||
          onConnect={() => setConnected(true)}
 | 
					          onConnect={() => { setConnected(true); }}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,7 +36,7 @@ export function LoginRoute(): React.ReactElement {
 | 
				
			|||||||
  const canSubmit = username.length > 0 && password.length > 0;
 | 
					  const canSubmit = username.length > 0 && password.length > 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [showPassword, setShowPassword] = React.useState(false);
 | 
					  const [showPassword, setShowPassword] = React.useState(false);
 | 
				
			||||||
  const handleClickShowPassword = () => setShowPassword((show) => !show);
 | 
					  const handleClickShowPassword = () => { setShowPassword((show) => !show); };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const handleMouseDownPassword = (
 | 
					  const handleMouseDownPassword = (
 | 
				
			||||||
    event: React.MouseEvent<HTMLButtonElement>
 | 
					    event: React.MouseEvent<HTMLButtonElement>
 | 
				
			||||||
@@ -105,7 +105,7 @@ export function LoginRoute(): React.ReactElement {
 | 
				
			|||||||
              label="Username"
 | 
					              label="Username"
 | 
				
			||||||
              name="username"
 | 
					              name="username"
 | 
				
			||||||
              value={username}
 | 
					              value={username}
 | 
				
			||||||
              onChange={(e) => setUsername(e.target.value)}
 | 
					              onChange={(e) => { setUsername(e.target.value); }}
 | 
				
			||||||
              autoComplete="username"
 | 
					              autoComplete="username"
 | 
				
			||||||
              autoFocus
 | 
					              autoFocus
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
@@ -120,7 +120,7 @@ export function LoginRoute(): React.ReactElement {
 | 
				
			|||||||
                type={showPassword ? "text" : "password"}
 | 
					                type={showPassword ? "text" : "password"}
 | 
				
			||||||
                id="password"
 | 
					                id="password"
 | 
				
			||||||
                value={password}
 | 
					                value={password}
 | 
				
			||||||
                onChange={(e) => setPassword(e.target.value)}
 | 
					                onChange={(e) => { setPassword(e.target.value); }}
 | 
				
			||||||
                autoComplete="current-password"
 | 
					                autoComplete="current-password"
 | 
				
			||||||
                endAdornment={
 | 
					                endAdornment={
 | 
				
			||||||
                  <InputAdornment position="end">
 | 
					                  <InputAdornment position="end">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -67,7 +67,7 @@ export function AsyncWidget(p: {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
          <Button onClick={load}>Try again</Button>
 | 
					          <Button onClick={load}>Try again</Button>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          {p.errAdditionalElement && p.errAdditionalElement()}
 | 
					          {p.errAdditionalElement?.()}
 | 
				
			||||||
        </Box>
 | 
					        </Box>
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,13 +32,13 @@ export function ConfigImportExportButtons(p: {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      // Wait for a file to be chosen
 | 
					      // Wait for a file to be chosen
 | 
				
			||||||
      await new Promise((res, _rej) =>
 | 
					      await new Promise((res, _rej) =>
 | 
				
			||||||
        fileEl.addEventListener("change", () => res(null))
 | 
					        { fileEl.addEventListener("change", () => { res(null); }); }
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if ((fileEl.files?.length ?? 0) === 0) return null;
 | 
					      if ((fileEl.files?.length ?? 0) === 0) return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Import conf
 | 
					      // Import conf
 | 
				
			||||||
      let file = fileEl.files![0];
 | 
					      const file = fileEl.files![0];
 | 
				
			||||||
      const content = await file.text();
 | 
					      const content = await file.text();
 | 
				
			||||||
      p.importConf?.(JSON.parse(content));
 | 
					      p.importConf?.(JSON.parse(content));
 | 
				
			||||||
    } catch (e) {
 | 
					    } catch (e) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,7 @@ export function TabsWidget<E>(p: {
 | 
				
			|||||||
    <Box sx={{ borderBottom: 1, borderColor: "divider" }}>
 | 
					    <Box sx={{ borderBottom: 1, borderColor: "divider" }}>
 | 
				
			||||||
      <Tabs
 | 
					      <Tabs
 | 
				
			||||||
        value={currTabIndex}
 | 
					        value={currTabIndex}
 | 
				
			||||||
        onChange={(_ev, newVal) => updateActiveTab(newVal)}
 | 
					        onChange={(_ev, newVal) => { updateActiveTab(newVal); }}
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        {activeOptions.map((o, index) => (
 | 
					        {activeOptions.map((o, index) => (
 | 
				
			||||||
          <Tab key={index} label={o.label} style={{ color: o.color }} />
 | 
					          <Tab key={index} label={o.label} style={{ color: o.color }} />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,7 +17,7 @@ export function CheckboxInput(p: {
 | 
				
			|||||||
        <Checkbox
 | 
					        <Checkbox
 | 
				
			||||||
          disabled={!p.editable}
 | 
					          disabled={!p.editable}
 | 
				
			||||||
          checked={p.checked}
 | 
					          checked={p.checked}
 | 
				
			||||||
          onChange={(e) => p.onValueChange(e.target.checked)}
 | 
					          onChange={(e) => { p.onValueChange(e.target.checked); }}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      label={p.label}
 | 
					      label={p.label}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,7 +44,7 @@ export function IPInputWithMask(p: {
 | 
				
			|||||||
          return;
 | 
					          return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const split = v?.split("/");
 | 
					        const split = v.split("/");
 | 
				
			||||||
        const ip =
 | 
					        const ip =
 | 
				
			||||||
          p.version === 4 ? sanitizeIpV4(split[0]) : sanitizeIpV6(split[0]);
 | 
					          p.version === 4 ? sanitizeIpV4(split[0]) : sanitizeIpV6(split[0]);
 | 
				
			||||||
        let mask = undefined;
 | 
					        let mask = undefined;
 | 
				
			||||||
@@ -69,7 +69,7 @@ export function IPInputWithMask(p: {
 | 
				
			|||||||
function sanitizeIpV4(s: string | undefined): string | undefined {
 | 
					function sanitizeIpV4(s: string | undefined): string | undefined {
 | 
				
			||||||
  if (s === "" || s === undefined) return s;
 | 
					  if (s === "" || s === undefined) return s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let split = s.split(".");
 | 
					  const split = s.split(".");
 | 
				
			||||||
  if (split.length > 4) split.splice(4);
 | 
					  if (split.length > 4) split.splice(4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let needAnotherIteration = false;
 | 
					  let needAnotherIteration = false;
 | 
				
			||||||
@@ -106,7 +106,7 @@ function sanitizeIpV6(s: string | undefined): string | undefined {
 | 
				
			|||||||
      const num = parseInt(e, 16);
 | 
					      const num = parseInt(e, 16);
 | 
				
			||||||
      if (isNaN(num)) return "0";
 | 
					      if (isNaN(num)) return "0";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      let s = num.toString(16);
 | 
					      const s = num.toString(16);
 | 
				
			||||||
      if (num > 0xffff) {
 | 
					      if (num > 0xffff) {
 | 
				
			||||||
        needAnotherIteration = true;
 | 
					        needAnotherIteration = true;
 | 
				
			||||||
        return s.slice(0, 4) + ":" + s.slice(4);
 | 
					        return s.slice(0, 4) + ":" + s.slice(4);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,7 +32,7 @@ function sanitizeMacAddress(s: string | undefined): string | undefined {
 | 
				
			|||||||
      const num = parseInt(e, 16);
 | 
					      const num = parseInt(e, 16);
 | 
				
			||||||
      if (isNaN(num)) return "0";
 | 
					      if (isNaN(num)) return "0";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      let s = num.toString(16).padStart(2, "0");
 | 
					      const s = num.toString(16).padStart(2, "0");
 | 
				
			||||||
      if (num > 0xff) {
 | 
					      if (num > 0xff) {
 | 
				
			||||||
        needAnotherIteration = true;
 | 
					        needAnotherIteration = true;
 | 
				
			||||||
        return s.slice(0, 2) + ":" + s.slice(2);
 | 
					        return s.slice(0, 2) + ":" + s.slice(2);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,7 @@ export function NWFConnStateInput(p: {
 | 
				
			|||||||
      label="Connection state"
 | 
					      label="Connection state"
 | 
				
			||||||
      value={p.value}
 | 
					      value={p.value}
 | 
				
			||||||
      onValueChange={(s) => {
 | 
					      onValueChange={(s) => {
 | 
				
			||||||
        p.onChange?.(s as any);
 | 
					        p.onChange(s as any);
 | 
				
			||||||
      }}
 | 
					      }}
 | 
				
			||||||
      options={[
 | 
					      options={[
 | 
				
			||||||
        { label: "None", value: undefined },
 | 
					        { label: "None", value: undefined },
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,7 +13,7 @@ export function NWFilterPriorityInput(p: {
 | 
				
			|||||||
      value={p.value?.toString()}
 | 
					      value={p.value?.toString()}
 | 
				
			||||||
      type="number"
 | 
					      type="number"
 | 
				
			||||||
      onValueChange={(v) => {
 | 
					      onValueChange={(v) => {
 | 
				
			||||||
        p.onChange?.(v && v !== "" ? Number(v) : undefined);
 | 
					        p.onChange(v && v !== "" ? Number(v) : undefined);
 | 
				
			||||||
      }}
 | 
					      }}
 | 
				
			||||||
      size={ServerApi.Config.constraints.nwfilter_priority}
 | 
					      size={ServerApi.Config.constraints.nwfilter_priority}
 | 
				
			||||||
      helperText="A lower priority value is accessed before one with a higher value"
 | 
					      helperText="A lower priority value is accessed before one with a higher value"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -66,9 +66,9 @@ export function NWFilterRules(p: {
 | 
				
			|||||||
            deleteRule(n);
 | 
					            deleteRule(n);
 | 
				
			||||||
          }}
 | 
					          }}
 | 
				
			||||||
          onGoDown={
 | 
					          onGoDown={
 | 
				
			||||||
            n < p.rules.length - 1 ? () => swapRules(n, n + 1) : undefined
 | 
					            n < p.rules.length - 1 ? () => { swapRules(n, n + 1); } : undefined
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          onGoUp={n > 0 ? () => swapRules(n, n - 1) : undefined}
 | 
					          onGoUp={n > 0 ? () => { swapRules(n, n - 1); } : undefined}
 | 
				
			||||||
          {...p}
 | 
					          {...p}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      ))}
 | 
					      ))}
 | 
				
			||||||
@@ -153,7 +153,7 @@ function NWRuleEdit(p: {
 | 
				
			|||||||
            editable={p.editable}
 | 
					            editable={p.editable}
 | 
				
			||||||
            onChange={p.onChange}
 | 
					            onChange={p.onChange}
 | 
				
			||||||
            selector={s}
 | 
					            selector={s}
 | 
				
			||||||
            onDelete={() => deleteSelector(n)}
 | 
					            onDelete={() => { deleteSelector(n); }}
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
        ))}
 | 
					        ))}
 | 
				
			||||||
      </CardContent>
 | 
					      </CardContent>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -130,7 +130,7 @@ function HostReservationWidget(p: {
 | 
				
			|||||||
            value={p.host.mac}
 | 
					            value={p.host.mac}
 | 
				
			||||||
            onValueChange={(v) => {
 | 
					            onValueChange={(v) => {
 | 
				
			||||||
              p.host.mac = v!;
 | 
					              p.host.mac = v!;
 | 
				
			||||||
              p.onChange?.();
 | 
					              p.onChange();
 | 
				
			||||||
            }}
 | 
					            }}
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
        )}
 | 
					        )}
 | 
				
			||||||
@@ -142,7 +142,7 @@ function HostReservationWidget(p: {
 | 
				
			|||||||
          value={p.host.ip}
 | 
					          value={p.host.ip}
 | 
				
			||||||
          onValueChange={(v) => {
 | 
					          onValueChange={(v) => {
 | 
				
			||||||
            p.host.ip = v!;
 | 
					            p.host.ip = v!;
 | 
				
			||||||
            p.onChange?.();
 | 
					            p.onChange();
 | 
				
			||||||
          }}
 | 
					          }}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,7 @@ export function PortInput(p: {
 | 
				
			|||||||
      value={p.value?.toString() ?? ""}
 | 
					      value={p.value?.toString() ?? ""}
 | 
				
			||||||
      type="number"
 | 
					      type="number"
 | 
				
			||||||
      onValueChange={(v) => {
 | 
					      onValueChange={(v) => {
 | 
				
			||||||
        p.onChange?.(sanitizePort(v));
 | 
					        p.onChange(sanitizePort(v));
 | 
				
			||||||
      }}
 | 
					      }}
 | 
				
			||||||
      checkValue={(v) => Number(v) <= 65535}
 | 
					      checkValue={(v) => Number(v) <= 65535}
 | 
				
			||||||
    />
 | 
					    />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,7 @@ export function RadioGroupInput(p: {
 | 
				
			|||||||
      <RadioGroup
 | 
					      <RadioGroup
 | 
				
			||||||
        row
 | 
					        row
 | 
				
			||||||
        value={p.value}
 | 
					        value={p.value}
 | 
				
			||||||
        onChange={(_ev, v) => p.onValueChange?.(v)}
 | 
					        onChange={(_ev, v) => { p.onValueChange(v); }}
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        {p.options.map((o) => (
 | 
					        {p.options.map((o) => (
 | 
				
			||||||
          <FormControlLabel
 | 
					          <FormControlLabel
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,7 +33,7 @@ export function SelectInput(p: {
 | 
				
			|||||||
      <Select
 | 
					      <Select
 | 
				
			||||||
        value={p.value ?? ""}
 | 
					        value={p.value ?? ""}
 | 
				
			||||||
        label={p.label}
 | 
					        label={p.label}
 | 
				
			||||||
        onChange={(e) => p.onValueChange(e.target.value)}
 | 
					        onChange={(e) => { p.onValueChange(e.target.value); }}
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        {p.options.map((e) => (
 | 
					        {p.options.map((e) => (
 | 
				
			||||||
          <MenuItem
 | 
					          <MenuItem
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -260,7 +260,7 @@ function IPSection(p: {
 | 
				
			|||||||
  const confirm = useConfirm();
 | 
					  const confirm = useConfirm();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const toggleNetwork = async () => {
 | 
					  const toggleNetwork = async () => {
 | 
				
			||||||
    if (!!p.config) {
 | 
					    if (p.config) {
 | 
				
			||||||
      if (
 | 
					      if (
 | 
				
			||||||
        !(await confirm(
 | 
					        !(await confirm(
 | 
				
			||||||
          `Do you really want to disable IPv${p.version} on this network? Specific configuration will be deleted!`
 | 
					          `Do you really want to disable IPv${p.version} on this network? Specific configuration will be deleted!`
 | 
				
			||||||
@@ -268,11 +268,11 @@ function IPSection(p: {
 | 
				
			|||||||
      )
 | 
					      )
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      p.onChange?.(undefined);
 | 
					      p.onChange(undefined);
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    p.onChange?.({
 | 
					    p.onChange({
 | 
				
			||||||
      bridge_address: p.version === 4 ? "192.168.1.1" : "fd00::1",
 | 
					      bridge_address: p.version === 4 ? "192.168.1.1" : "fd00::1",
 | 
				
			||||||
      prefix: p.version === 4 ? 24 : 8,
 | 
					      prefix: p.version === 4 ? 24 : 8,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
@@ -298,7 +298,7 @@ function IPSection(p: {
 | 
				
			|||||||
      p.config!.dhcp = undefined;
 | 
					      p.config!.dhcp = undefined;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    p.onChange?.(p.config);
 | 
					    p.onChange(p.config);
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const toggleNAT = async (v: boolean) => {
 | 
					  const toggleNAT = async (v: boolean) => {
 | 
				
			||||||
@@ -315,7 +315,7 @@ function IPSection(p: {
 | 
				
			|||||||
      p.config!.nat = undefined;
 | 
					      p.config!.nat = undefined;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    p.onChange?.(p.config);
 | 
					    p.onChange(p.config);
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!p.config && !p.editable) return <></>;
 | 
					  if (!p.config && !p.editable) return <></>;
 | 
				
			||||||
@@ -338,10 +338,10 @@ function IPSection(p: {
 | 
				
			|||||||
              editable={p.editable}
 | 
					              editable={p.editable}
 | 
				
			||||||
              label="Bridge address"
 | 
					              label="Bridge address"
 | 
				
			||||||
              version={p.version}
 | 
					              version={p.version}
 | 
				
			||||||
              value={p.config?.bridge_address}
 | 
					              value={p.config.bridge_address}
 | 
				
			||||||
              onValueChange={(v) => {
 | 
					              onValueChange={(v) => {
 | 
				
			||||||
                p.config!.bridge_address = v ?? "";
 | 
					                p.config!.bridge_address = v ?? "";
 | 
				
			||||||
                p.onChange?.(p.config);
 | 
					                p.onChange(p.config);
 | 
				
			||||||
              }}
 | 
					              }}
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -352,7 +352,7 @@ function IPSection(p: {
 | 
				
			|||||||
              type="number"
 | 
					              type="number"
 | 
				
			||||||
              onValueChange={(v) => {
 | 
					              onValueChange={(v) => {
 | 
				
			||||||
                p.config!.prefix = Number(v);
 | 
					                p.config!.prefix = Number(v);
 | 
				
			||||||
                p.onChange?.(p.config);
 | 
					                p.onChange(p.config);
 | 
				
			||||||
              }}
 | 
					              }}
 | 
				
			||||||
              size={
 | 
					              size={
 | 
				
			||||||
                p.version === 4 ? { min: 0, max: 32 } : { min: 0, max: 128 }
 | 
					                p.version === 4 ? { min: 0, max: 32 } : { min: 0, max: 128 }
 | 
				
			||||||
@@ -407,7 +407,7 @@ function IPSection(p: {
 | 
				
			|||||||
            dhcp={p.config.dhcp}
 | 
					            dhcp={p.config.dhcp}
 | 
				
			||||||
            onChange={(d) => {
 | 
					            onChange={(d) => {
 | 
				
			||||||
              p.config!.dhcp = d;
 | 
					              p.config!.dhcp = d;
 | 
				
			||||||
              p.onChange?.(p.config);
 | 
					              p.onChange(p.config);
 | 
				
			||||||
            }}
 | 
					            }}
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
        </EditSection>
 | 
					        </EditSection>
 | 
				
			||||||
@@ -431,7 +431,7 @@ function IPSection(p: {
 | 
				
			|||||||
              nat={p.config.nat}
 | 
					              nat={p.config.nat}
 | 
				
			||||||
              onChange={(n) => {
 | 
					              onChange={(n) => {
 | 
				
			||||||
                p.config!.nat = n;
 | 
					                p.config!.nat = n;
 | 
				
			||||||
                p.onChange?.(p.config);
 | 
					                p.onChange(p.config);
 | 
				
			||||||
              }}
 | 
					              }}
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
          )}
 | 
					          )}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,13 +29,13 @@ export function NetworkStatusWidget(p: {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const changedAction = () => setState(undefined);
 | 
					  const changedAction = () => { setState(undefined); };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  React.useEffect(() => {
 | 
					  React.useEffect(() => {
 | 
				
			||||||
    refresh();
 | 
					    refresh();
 | 
				
			||||||
    const i = setInterval(() => refresh(), 3000);
 | 
					    const i = setInterval(() => refresh(), 3000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return () => clearInterval(i);
 | 
					    return () => { clearInterval(i); };
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (state === undefined)
 | 
					  if (state === undefined)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -95,7 +95,7 @@ export function TokenRawRightsEditor(p: {
 | 
				
			|||||||
              </TableCell>
 | 
					              </TableCell>
 | 
				
			||||||
              {p.editable && (
 | 
					              {p.editable && (
 | 
				
			||||||
                <TableCell style={{ width: "100px" }}>
 | 
					                <TableCell style={{ width: "100px" }}>
 | 
				
			||||||
                  <IconButton onClick={() => deleteRule(num)}>
 | 
					                  <IconButton onClick={() => { deleteRule(num); }}>
 | 
				
			||||||
                    <Tooltip title="Remove the rule">
 | 
					                    <Tooltip title="Remove the rule">
 | 
				
			||||||
                      <DeleteIcon />
 | 
					                      <DeleteIcon />
 | 
				
			||||||
                    </Tooltip>
 | 
					                    </Tooltip>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -576,7 +576,7 @@ export function TokenRightsEditor(p: {
 | 
				
			|||||||
                  right={{ verb: "GET", path: `/api/nwfilter/${v.uuid}` }}
 | 
					                  right={{ verb: "GET", path: `/api/nwfilter/${v.uuid}` }}
 | 
				
			||||||
                  parent={{ verb: "GET", path: "/api/nwfilter/*" }}
 | 
					                  parent={{ verb: "GET", path: "/api/nwfilter/*" }}
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
                {ServerApi.Config.builtin_nwfilter_rules.includes(v.name!) ? (
 | 
					                {ServerApi.Config.builtin_nwfilter_rules.includes(v.name) ? (
 | 
				
			||||||
                  <TableCell></TableCell>
 | 
					                  <TableCell></TableCell>
 | 
				
			||||||
                ) : (
 | 
					                ) : (
 | 
				
			||||||
                  <CellRight
 | 
					                  <CellRight
 | 
				
			||||||
@@ -585,7 +585,7 @@ export function TokenRightsEditor(p: {
 | 
				
			|||||||
                    parent={{ verb: "PUT", path: "/api/nwfilter/*" }}
 | 
					                    parent={{ verb: "PUT", path: "/api/nwfilter/*" }}
 | 
				
			||||||
                  />
 | 
					                  />
 | 
				
			||||||
                )}
 | 
					                )}
 | 
				
			||||||
                {ServerApi.Config.builtin_nwfilter_rules.includes(v.name!) ? (
 | 
					                {ServerApi.Config.builtin_nwfilter_rules.includes(v.name) ? (
 | 
				
			||||||
                  <TableCell></TableCell>
 | 
					                  <TableCell></TableCell>
 | 
				
			||||||
                ) : (
 | 
					                ) : (
 | 
				
			||||||
                  <CellRight
 | 
					                  <CellRight
 | 
				
			||||||
@@ -767,7 +767,7 @@ function RouteRight(p: RightOpts): React.ReactElement {
 | 
				
			|||||||
  const parentActivated =
 | 
					  const parentActivated =
 | 
				
			||||||
    !!p.parent &&
 | 
					    !!p.parent &&
 | 
				
			||||||
    p.token.rights.findIndex(
 | 
					    p.token.rights.findIndex(
 | 
				
			||||||
      (r) => r.verb === p.parent?.verb && r.path === p.parent?.path
 | 
					      (r) => r.verb === p.parent?.verb && r.path === p.parent.path
 | 
				
			||||||
    ) !== -1;
 | 
					    ) !== -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const toggle = (a: boolean) => {
 | 
					  const toggle = (a: boolean) => {
 | 
				
			||||||
@@ -804,7 +804,7 @@ function RouteRight(p: RightOpts): React.ReactElement {
 | 
				
			|||||||
              <Checkbox
 | 
					              <Checkbox
 | 
				
			||||||
                checked={activated || parentActivated}
 | 
					                checked={activated || parentActivated}
 | 
				
			||||||
                disabled={!p.editable || parentActivated}
 | 
					                disabled={!p.editable || parentActivated}
 | 
				
			||||||
                onChange={(_e, a) => toggle(a)}
 | 
					                onChange={(_e, a) => { toggle(a); }}
 | 
				
			||||||
              />
 | 
					              />
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            label={p.label}
 | 
					            label={p.label}
 | 
				
			||||||
@@ -814,7 +814,7 @@ function RouteRight(p: RightOpts): React.ReactElement {
 | 
				
			|||||||
            <Checkbox
 | 
					            <Checkbox
 | 
				
			||||||
              checked={activated || parentActivated}
 | 
					              checked={activated || parentActivated}
 | 
				
			||||||
              disabled={!p.editable || parentActivated}
 | 
					              disabled={!p.editable || parentActivated}
 | 
				
			||||||
              onChange={(_e, a) => toggle(a)}
 | 
					              onChange={(_e, a) => { toggle(a); }}
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
          </span>
 | 
					          </span>
 | 
				
			||||||
        )}
 | 
					        )}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -222,7 +222,7 @@ function VMDetailsTabGeneral(p: DetailsInnerProps): React.ReactElement {
 | 
				
			|||||||
                  : "Add a new group instead of using existing one"
 | 
					                  : "Add a new group instead of using existing one"
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
              <IconButton onClick={() => setAddGroup(!addGroup)}>
 | 
					              <IconButton onClick={() => { setAddGroup(!addGroup); }}>
 | 
				
			||||||
                {addGroup ? <ListIcon /> : <AddIcon />}
 | 
					                {addGroup ? <ListIcon /> : <AddIcon />}
 | 
				
			||||||
              </IconButton>
 | 
					              </IconButton>
 | 
				
			||||||
            </Tooltip>
 | 
					            </Tooltip>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,13 +31,13 @@ export function VMStatusWidget(p: {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const changedAction = () => setState(undefined);
 | 
					  const changedAction = () => { setState(undefined); };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  React.useEffect(() => {
 | 
					  React.useEffect(() => {
 | 
				
			||||||
    refresh();
 | 
					    refresh();
 | 
				
			||||||
    const i = setInterval(() => refresh(), 3000);
 | 
					    const i = setInterval(() => refresh(), 3000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return () => clearInterval(i);
 | 
					    return () => { clearInterval(i); };
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (state === undefined)
 | 
					  if (state === undefined)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user