Show guidelines on UI on how to setup network hook
This commit is contained in:
		@@ -148,6 +148,12 @@ interface SysLoadAverage {
 | 
			
		||||
  fifteen: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface NetworkHookStatus {
 | 
			
		||||
  installed: boolean;
 | 
			
		||||
  content: string;
 | 
			
		||||
  path: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class ServerApi {
 | 
			
		||||
  /**
 | 
			
		||||
   * Get server configuration
 | 
			
		||||
@@ -181,6 +187,18 @@ export class ServerApi {
 | 
			
		||||
    ).data;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Get network hook status
 | 
			
		||||
   */
 | 
			
		||||
  static async NetworkHookStatus(): Promise<NetworkHookStatus> {
 | 
			
		||||
    return (
 | 
			
		||||
      await APIClient.exec({
 | 
			
		||||
        method: "GET",
 | 
			
		||||
        uri: "/server/network_hook_status",
 | 
			
		||||
      })
 | 
			
		||||
    ).data;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Get host supported vCPUs configurations
 | 
			
		||||
   */
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@ import { RouterLink } from "../widgets/RouterLink";
 | 
			
		||||
import { VirtWebRouteContainer } from "../widgets/VirtWebRouteContainer";
 | 
			
		||||
import { NetworkStatusWidget } from "../widgets/net/NetworkStatusWidget";
 | 
			
		||||
import { useNavigate } from "react-router-dom";
 | 
			
		||||
import { NetworkHookStatusWidget } from "../widgets/net/NetworkHookStatusWidget";
 | 
			
		||||
 | 
			
		||||
export function NetworksListRoute(): React.ReactElement {
 | 
			
		||||
  const [list, setList] = React.useState<NetworkInfo[] | undefined>();
 | 
			
		||||
@@ -54,6 +55,8 @@ function NetworksListRouteInner(p: {
 | 
			
		||||
        </RouterLink>
 | 
			
		||||
      }
 | 
			
		||||
    >
 | 
			
		||||
      <NetworkHookStatusWidget hiddenIfInstalled />
 | 
			
		||||
 | 
			
		||||
      <TableContainer component={Paper}>
 | 
			
		||||
        <Table>
 | 
			
		||||
          <TableHead>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										30
									
								
								virtweb_frontend/src/widgets/CopyToClipboard.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								virtweb_frontend/src/widgets/CopyToClipboard.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
import { ButtonBase } from "@mui/material";
 | 
			
		||||
import { PropsWithChildren } from "react";
 | 
			
		||||
import { useSnackbar } from "../hooks/providers/SnackbarProvider";
 | 
			
		||||
 | 
			
		||||
export function CopyToClipboard(
 | 
			
		||||
  p: PropsWithChildren<{ content: string }>
 | 
			
		||||
): React.ReactElement {
 | 
			
		||||
  const snackbar = useSnackbar();
 | 
			
		||||
 | 
			
		||||
  const copy = () => {
 | 
			
		||||
    navigator.clipboard.writeText(p.content);
 | 
			
		||||
    snackbar(`${p.content} copied to clipboard.`);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <ButtonBase
 | 
			
		||||
      onClick={copy}
 | 
			
		||||
      style={{
 | 
			
		||||
        display: "inline-block",
 | 
			
		||||
        alignItems: "unset",
 | 
			
		||||
        textAlign: "unset",
 | 
			
		||||
        position: "relative",
 | 
			
		||||
        padding: "0px",
 | 
			
		||||
      }}
 | 
			
		||||
      disableRipple
 | 
			
		||||
    >
 | 
			
		||||
      {p.children}
 | 
			
		||||
    </ButtonBase>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										102
									
								
								virtweb_frontend/src/widgets/net/NetworkHookStatusWidget.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								virtweb_frontend/src/widgets/net/NetworkHookStatusWidget.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,102 @@
 | 
			
		||||
import React, { PropsWithChildren } from "react";
 | 
			
		||||
import { AsyncWidget } from "../AsyncWidget";
 | 
			
		||||
import { NetworkHookStatus, ServerApi } from "../../api/ServerApi";
 | 
			
		||||
import { Alert, Typography } from "@mui/material";
 | 
			
		||||
import { CopyToClipboard } from "../CopyToClipboard";
 | 
			
		||||
 | 
			
		||||
export function NetworkHookStatusWidget(p: {
 | 
			
		||||
  hiddenIfInstalled: boolean;
 | 
			
		||||
}): React.ReactElement {
 | 
			
		||||
  const [status, setStatus] = React.useState<NetworkHookStatus | undefined>();
 | 
			
		||||
 | 
			
		||||
  const load = async () => {
 | 
			
		||||
    setStatus(await ServerApi.NetworkHookStatus());
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <AsyncWidget
 | 
			
		||||
      loadKey={1}
 | 
			
		||||
      errMsg="Failed to get network status!"
 | 
			
		||||
      ready={!!status}
 | 
			
		||||
      load={load}
 | 
			
		||||
      build={() => <NetworkHookStatusWidgetInner {...p} status={status!} />}
 | 
			
		||||
    />
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function NetworkHookStatusWidgetInner(p: {
 | 
			
		||||
  status: NetworkHookStatus;
 | 
			
		||||
  hiddenIfInstalled: boolean;
 | 
			
		||||
}): React.ReactElement {
 | 
			
		||||
  if (p.status.installed && p.hiddenIfInstalled) return <></>;
 | 
			
		||||
  if (p.status.installed)
 | 
			
		||||
    return (
 | 
			
		||||
      <Alert
 | 
			
		||||
        variant="outlined"
 | 
			
		||||
        severity="success"
 | 
			
		||||
        style={{ margin: "20px 0px" }}
 | 
			
		||||
      >
 | 
			
		||||
        The network hook has been installed on this system.
 | 
			
		||||
      </Alert>
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <Alert variant="outlined" severity="warning" style={{ margin: "20px 0px" }}>
 | 
			
		||||
      The network hook has not been detected on this system. It must be
 | 
			
		||||
      installed in order to expose ports from virtual machines through NAT on
 | 
			
		||||
      the network.
 | 
			
		||||
      <br />
 | 
			
		||||
      <br />
 | 
			
		||||
      In order to install it, please create a file named  
 | 
			
		||||
      <CopyToClipboard content={p.status.path}>
 | 
			
		||||
        <InlineCode>{p.status.path}</InlineCode>   with the following
 | 
			
		||||
      </CopyToClipboard>
 | 
			
		||||
      content:
 | 
			
		||||
      <br />
 | 
			
		||||
      <CopyToClipboard content={p.status.content}>
 | 
			
		||||
        <CodeBlock>{p.status.content}</CodeBlock>
 | 
			
		||||
      </CopyToClipboard>
 | 
			
		||||
      <br />
 | 
			
		||||
      You will need then to restart both <InlineCode>
 | 
			
		||||
        libvirtd
 | 
			
		||||
      </InlineCode> and <InlineCode>VirtWeb</InlineCode>.
 | 
			
		||||
    </Alert>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function InlineCode(p: PropsWithChildren): React.ReactElement {
 | 
			
		||||
  return (
 | 
			
		||||
    <code
 | 
			
		||||
      style={{
 | 
			
		||||
        display: "inline-block",
 | 
			
		||||
        backgroundColor: "black",
 | 
			
		||||
        color: "white",
 | 
			
		||||
        wordBreak: "break-all",
 | 
			
		||||
        wordWrap: "break-word",
 | 
			
		||||
        whiteSpace: "pre-wrap",
 | 
			
		||||
        padding: "0px 7px",
 | 
			
		||||
        borderRadius: "5px",
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      {p.children}
 | 
			
		||||
    </code>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function CodeBlock(p: PropsWithChildren): React.ReactElement {
 | 
			
		||||
  return (
 | 
			
		||||
    <pre
 | 
			
		||||
      style={{
 | 
			
		||||
        backgroundColor: "black",
 | 
			
		||||
        color: "white",
 | 
			
		||||
        wordBreak: "break-all",
 | 
			
		||||
        wordWrap: "break-word",
 | 
			
		||||
        whiteSpace: "pre-wrap",
 | 
			
		||||
        padding: "10px",
 | 
			
		||||
        borderRadius: "5px",
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      {p.children}
 | 
			
		||||
    </pre>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user