Use tabs to organize UI
This commit is contained in:
		@@ -1,15 +1,34 @@
 | 
			
		||||
import { makeStyles, typographyStyles } from "@fluentui/react-components";
 | 
			
		||||
import {
 | 
			
		||||
  Tab,
 | 
			
		||||
  TabList,
 | 
			
		||||
  makeStyles,
 | 
			
		||||
  typographyStyles,
 | 
			
		||||
} from "@fluentui/react-components";
 | 
			
		||||
import { ServerApi } from "./api/ServerApi";
 | 
			
		||||
import { AuthRouteWidget } from "./routes/AuthRouteWidget";
 | 
			
		||||
import { AsyncWidget } from "./widgets/AsyncWidget";
 | 
			
		||||
import { MainMenu } from "./widgets/MainMenu";
 | 
			
		||||
import { SystemInfoWidget } from "./widgets/SystemInfoWidget";
 | 
			
		||||
import { VirtualMachinesWidget } from "./widgets/VirtualMachinesWidget";
 | 
			
		||||
import {
 | 
			
		||||
  DesktopFilled,
 | 
			
		||||
  DesktopRegular,
 | 
			
		||||
  Info12Filled,
 | 
			
		||||
  Info12Regular,
 | 
			
		||||
  InfoFilled,
 | 
			
		||||
  InfoRegular,
 | 
			
		||||
  bundleIcon,
 | 
			
		||||
} from "@fluentui/react-icons";
 | 
			
		||||
import React from "react";
 | 
			
		||||
 | 
			
		||||
const useStyles = makeStyles({
 | 
			
		||||
  title: typographyStyles.title2,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const InfoIcon = bundleIcon(InfoFilled, InfoRegular);
 | 
			
		||||
 | 
			
		||||
const DesktopIcon = bundleIcon(DesktopFilled, DesktopRegular);
 | 
			
		||||
 | 
			
		||||
export function App() {
 | 
			
		||||
  return (
 | 
			
		||||
    <AsyncWidget
 | 
			
		||||
@@ -24,6 +43,7 @@ export function App() {
 | 
			
		||||
 | 
			
		||||
function AppInner(): React.ReactElement {
 | 
			
		||||
  const styles = useStyles();
 | 
			
		||||
  const [tab, setTab] = React.useState<"vm" | "info">("vm");
 | 
			
		||||
 | 
			
		||||
  if (!ServerApi.Config.authenticated && !ServerApi.Config.disable_auth)
 | 
			
		||||
    return <AuthRouteWidget />;
 | 
			
		||||
@@ -36,12 +56,31 @@ function AppInner(): React.ReactElement {
 | 
			
		||||
        margin: "50px auto",
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
      <div style={{ display: "flex", justifyContent: "space-between" }}>
 | 
			
		||||
        <span className={styles.title}>VirtWebRemote</span>
 | 
			
		||||
        <MainMenu />
 | 
			
		||||
      <span className={styles.title}>VirtWebRemote</span>
 | 
			
		||||
      <div
 | 
			
		||||
        style={{
 | 
			
		||||
          display: "flex",
 | 
			
		||||
          justifyContent: "space-between",
 | 
			
		||||
          marginTop: "30px",
 | 
			
		||||
        }}
 | 
			
		||||
      >
 | 
			
		||||
        <TabList
 | 
			
		||||
          selectedValue={tab}
 | 
			
		||||
          onTabSelect={(_, d) => setTab(d.value as any)}
 | 
			
		||||
        >
 | 
			
		||||
          <Tab value="vm" icon={<DesktopIcon />}>
 | 
			
		||||
            Virtual machines
 | 
			
		||||
          </Tab>
 | 
			
		||||
          <Tab value="info" icon={<InfoIcon />}>
 | 
			
		||||
            System info
 | 
			
		||||
          </Tab>
 | 
			
		||||
        </TabList>
 | 
			
		||||
        <div>
 | 
			
		||||
          <MainMenu />
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <VirtualMachinesWidget />
 | 
			
		||||
      <SystemInfoWidget />
 | 
			
		||||
      {tab === "vm" && <VirtualMachinesWidget />}
 | 
			
		||||
      {tab === "info" && <SystemInfoWidget />}
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										27
									
								
								remote_frontend/src/api/VMApi.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								remote_frontend/src/api/VMApi.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
import { APIClient } from "./ApiClient";
 | 
			
		||||
 | 
			
		||||
export interface VMInfo {
 | 
			
		||||
  uiid: string;
 | 
			
		||||
  name: string;
 | 
			
		||||
  description?: string;
 | 
			
		||||
  architecture: string;
 | 
			
		||||
  memory: number;
 | 
			
		||||
  number_vcpu: number;
 | 
			
		||||
  can_get_state: boolean;
 | 
			
		||||
  can_start: boolean;
 | 
			
		||||
  can_shutdown: boolean;
 | 
			
		||||
  can_kill: boolean;
 | 
			
		||||
  can_reset: boolean;
 | 
			
		||||
  can_suspend: boolean;
 | 
			
		||||
  can_resume: boolean;
 | 
			
		||||
  can_screenshot: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class VMApi {
 | 
			
		||||
  /**
 | 
			
		||||
   * Get the list of VM that can be managed by this console
 | 
			
		||||
   */
 | 
			
		||||
  static async GetList(): Promise<VMInfo[]> {
 | 
			
		||||
    return (await APIClient.exec({ method: "GET", uri: "/vm/list" })).data;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,17 +1,10 @@
 | 
			
		||||
import { makeStyles, typographyStyles } from "@fluentui/react-components";
 | 
			
		||||
import React from "react";
 | 
			
		||||
 | 
			
		||||
const useStyles = makeStyles({
 | 
			
		||||
  title: typographyStyles.title3,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export function SectionContainer(
 | 
			
		||||
  p: React.PropsWithChildren<{ title: string }>
 | 
			
		||||
  p: React.PropsWithChildren
 | 
			
		||||
): React.ReactElement {
 | 
			
		||||
  const styles = useStyles();
 | 
			
		||||
  return (
 | 
			
		||||
    <div style={{ margin: "100px 0px" }}>
 | 
			
		||||
      <span className={styles.title}>{p.title}</span>
 | 
			
		||||
    <div style={{ margin: "50px 15px" }}>
 | 
			
		||||
      <div style={{ height: "20px" }}></div>
 | 
			
		||||
      {p.children}
 | 
			
		||||
    </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ export function SystemInfoWidget(): React.ReactElement {
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <SectionContainer title="System info">
 | 
			
		||||
    <SectionContainer>
 | 
			
		||||
      <AsyncWidget
 | 
			
		||||
        loadKey={1}
 | 
			
		||||
        load={load}
 | 
			
		||||
@@ -84,7 +84,7 @@ function SystemInfoWidgetInner(): React.ReactElement {
 | 
			
		||||
              status!.system.available_memory + status!.system.used_memory
 | 
			
		||||
            )}`}
 | 
			
		||||
            validationState="none"
 | 
			
		||||
            style={{ flex: 1 }}
 | 
			
		||||
            style={{ flex: 2 }}
 | 
			
		||||
          >
 | 
			
		||||
            <ProgressBar
 | 
			
		||||
              value={
 | 
			
		||||
@@ -93,6 +93,7 @@ function SystemInfoWidgetInner(): React.ReactElement {
 | 
			
		||||
              }
 | 
			
		||||
            />
 | 
			
		||||
          </Field>
 | 
			
		||||
          <div style={{ width: "20px" }}></div>
 | 
			
		||||
          <div style={{ flex: 1 }}>
 | 
			
		||||
            <p>
 | 
			
		||||
              Load average: {status!.system.load_average.one}{" "}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,27 @@
 | 
			
		||||
import React from "react";
 | 
			
		||||
import { VMApi, VMInfo } from "../api/VMApi";
 | 
			
		||||
import { SectionContainer } from "./SectionContainer";
 | 
			
		||||
import { AsyncWidget } from "./AsyncWidget";
 | 
			
		||||
 | 
			
		||||
export function VirtualMachinesWidget(): React.ReactElement {
 | 
			
		||||
  return <SectionContainer title="Virtual machines">TODO</SectionContainer>;
 | 
			
		||||
  const [list, setList] = React.useState<VMInfo[] | undefined>();
 | 
			
		||||
  const load = async () => {
 | 
			
		||||
    setList(await VMApi.GetList());
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <SectionContainer>
 | 
			
		||||
      <AsyncWidget
 | 
			
		||||
        loadKey={1}
 | 
			
		||||
        load={load}
 | 
			
		||||
        loadingMessage="Loading the list virtual machines..."
 | 
			
		||||
        errMsg="Failed to load the list of virtual machines!"
 | 
			
		||||
        build={() => <VirtualMachinesWidgetInner list={list!} />}
 | 
			
		||||
      />
 | 
			
		||||
    </SectionContainer>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function VirtualMachinesWidgetInner(p: { list: VMInfo[] }): React.ReactElement {
 | 
			
		||||
  return <>build list of vms</>;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user