diff --git a/pkgs/ui/public/clan-dark.png b/pkgs/ui/public/clan-dark.png new file mode 100644 index 0000000..dfeea5e Binary files /dev/null and b/pkgs/ui/public/clan-dark.png differ diff --git a/pkgs/ui/public/clan-white.png b/pkgs/ui/public/clan-white.png new file mode 100644 index 0000000..21735dd Binary files /dev/null and b/pkgs/ui/public/clan-white.png differ diff --git a/pkgs/ui/src/app/dashboard/page.tsx b/pkgs/ui/src/app/dashboard/page.tsx deleted file mode 100644 index c230c6a..0000000 --- a/pkgs/ui/src/app/dashboard/page.tsx +++ /dev/null @@ -1,61 +0,0 @@ -"use client"; -import { RecentActivity } from "@/components/dashboard/activity"; -import { AppOverview } from "@/components/dashboard/appOverview"; -import { NetworkOverview } from "@/components/dashboard/NetworkOverview"; -import { Notifications } from "@/components/dashboard/notifications"; -import { QuickActions } from "@/components/dashboard/quickActions"; -import { TaskQueue } from "@/components/dashboard/taskQueue"; -import { tw } from "@/utils/tailwind"; - -interface DashboardCardProps { - children?: React.ReactNode; - rowSpan?: number; - sx?: string; -} -const DashboardCard = (props: DashboardCardProps) => { - const { children, rowSpan, sx = "" } = props; - return ( -
- {children} -
- ); -}; - -interface DashboardPanelProps { - children?: React.ReactNode; -} -const DashboardPanel = (props: DashboardPanelProps) => { - const { children } = props; - return ( -
{children}
- ); -}; - -export default function Dashboard() { - return ( -
-
- - - - - - - - - - - - - - - - - - -
-
- ); -} diff --git a/pkgs/ui/src/app/join/page.tsx b/pkgs/ui/src/app/join/page.tsx new file mode 100644 index 0000000..a693cb7 --- /dev/null +++ b/pkgs/ui/src/app/join/page.tsx @@ -0,0 +1,5 @@ +import JoinPrequel from "@/views/joinPrequel"; + +export default function Page() { + return ; +} diff --git a/pkgs/ui/src/app/layout.tsx b/pkgs/ui/src/app/layout.tsx index ec03ba8..d3b210b 100644 --- a/pkgs/ui/src/app/layout.tsx +++ b/pkgs/ui/src/app/layout.tsx @@ -4,13 +4,14 @@ import "./globals.css"; import localFont from "next/font/local"; import * as React from "react"; import { + Button, CssBaseline, IconButton, ThemeProvider, useMediaQuery, useTheme, } from "@mui/material"; -import { ChangeEvent, useState } from "react"; +import { useState } from "react"; import { Toaster } from "react-hot-toast"; import { StyledEngineProvider } from "@mui/material/styles"; @@ -20,7 +21,14 @@ import MenuIcon from "@mui/icons-material/Menu"; import Image from "next/image"; import { tw } from "@/utils/tailwind"; import axios from "axios"; -import { MachineContextProvider } from "@/components/hooks/useMachines"; + +import { + AppContext, + WithAppState, + // useAppState, +} from "@/components/hooks/useAppContext"; +import Background from "@/components/background"; +// import { usePathname, redirect } from "next/navigation"; const roboto = localFont({ src: [ @@ -37,6 +45,17 @@ axios.defaults.baseURL = "http://localhost:2979"; // add negative margin for smooth transition to fill the space of the sidebar const translate = tw`lg:-ml-64 -ml-14`; +// const AutoRedirectEffect = () => { +// const { isLoading, data } = useAppState(); +// const pathname = usePathname(); +// React.useEffect(() => { +// if (!isLoading && !data.isJoined && pathname !== "/") { +// redirect("/"); +// } +// }, [isLoading, data, pathname]); +// return <>; +// }; + export default function RootLayout({ children, }: { @@ -65,9 +84,9 @@ export default function RootLayout({ } }, [userPrefersDarkmode, useDarkTheme, setUseDarkTheme]); - const changeThemeHandler = (target: ChangeEvent, currentValue: boolean) => { - setUseDarkTheme(currentValue); - }; + // const changeThemeHandler = (target: ChangeEvent, currentValue: boolean) => { + // setUseDarkTheme(currentValue); + // }; return ( @@ -82,47 +101,78 @@ export default function RootLayout({ - -
- setShowSidebar(false)} - /> -
-
-
-
- -
-
- Clan Logo + + {(appState) => { + const showSidebarDerived = Boolean( + showSidebar && + !appState.isLoading && + appState.data.isJoined, + ); + return ( + <> + +
+ setShowSidebar(false)} /> -
-
-
+
+
+
+
+ +
+
+ Clan Logo +
+
+
-
-
-
{children}
-
-
-
-
- +
+
+
+ {/* */} + + + {children} +
+
+
+
+
+ + ); + }} + + diff --git a/pkgs/ui/src/app/page.tsx b/pkgs/ui/src/app/page.tsx index 40b43ee..f3e1a47 100644 --- a/pkgs/ui/src/app/page.tsx +++ b/pkgs/ui/src/app/page.tsx @@ -1,79 +1,86 @@ "use client"; -import React, { useEffect, useState } from "react"; -import { - Button, - IconButton, - Input, - InputAdornment, - Paper, - TextField, - Typography, -} from "@mui/material"; -import { useSearchParams } from "next/navigation"; -import { useInspectFlake } from "@/api/default/default"; -import { ConfirmVM } from "@/components/join/confirmVM"; +import { RecentActivity } from "@/components/dashboard/activity"; +import { AppOverview } from "@/components/dashboard/appOverview"; +import { NetworkOverview } from "@/components/dashboard/NetworkOverview"; +import { Notifications } from "@/components/dashboard/notifications"; +import { QuickActions } from "@/components/dashboard/quickActions"; +import { TaskQueue } from "@/components/dashboard/taskQueue"; +import { useAppState } from "@/components/hooks/useAppContext"; +import { MachineContextProvider } from "@/components/hooks/useMachines"; import { LoadingOverlay } from "@/components/join/loadingOverlay"; -import { FlakeBadge } from "@/components/flakeBadge/flakeBadge"; -import { Log } from "@/components/join/log"; +import { tw } from "@/utils/tailwind"; +import JoinPrequel from "@/views/joinPrequel"; -import { useForm, SubmitHandler, Controller } from "react-hook-form"; -import { Confirm } from "@/components/join/confirm"; -import { Layout } from "@/components/join/layout"; -import { ChevronRight } from "@mui/icons-material"; - -type FormValues = { - flakeUrl: string; - flakeAttribute: string; +interface DashboardCardProps { + children?: React.ReactNode; + rowSpan?: number; + sx?: string; +} +const DashboardCard = (props: DashboardCardProps) => { + const { children, rowSpan, sx = "" } = props; + return ( +
+ {children} +
+ ); }; -export default function Page() { - const queryParams = useSearchParams(); - const flakeUrl = queryParams.get("flake") || ""; - const flakeAttribute = queryParams.get("attr") || "default"; - const { handleSubmit, control, formState, getValues, reset } = - useForm({ defaultValues: { flakeUrl: "" } }); - - const onSubmit: SubmitHandler = (data) => console.log(data); - - return ( - - {!formState.isSubmitted && !flakeUrl && ( -
- ( - Clan Url: - } - endAdornment={ - - - - - - } - // }} - /> - )} - /> - - )} - {(formState.isSubmitted || flakeUrl) && ( - reset()} - flakeUrl={formState.isSubmitted ? getValues("flakeUrl") : flakeUrl} - /> - )} -
- ); +interface DashboardPanelProps { + children?: React.ReactNode; +} +const DashboardPanel = (props: DashboardPanelProps) => { + const { children } = props; + return ( +
{children}
+ ); +}; + +export default function Dashboard() { + const { data, isLoading } = useAppState(); + if (isLoading) { + return ( +
+
+ +
+
+ ); + } + if (!data.isJoined) { + return ; + } + if (data.isJoined) { + return ( + +
+
+ + + + + + + + + + + + + + + + + + +
+
+
+ ); + } } diff --git a/pkgs/ui/src/app/templates/[id]/page.tsx b/pkgs/ui/src/app/templates/[id]/page.tsx index bfdbfa0..7793ce8 100644 --- a/pkgs/ui/src/app/templates/[id]/page.tsx +++ b/pkgs/ui/src/app/templates/[id]/page.tsx @@ -7,16 +7,12 @@ import { Edit, Group, Key, - MenuOpen, - NetworkCell, Settings, SettingsEthernet, - VisibilityOff, } from "@mui/icons-material"; import { Avatar, Button, - Divider, IconButton, List, ListItem, @@ -29,14 +25,13 @@ import { Typography, } from "@mui/material"; import { useState } from "react"; -import { useListMachines } from "@/api/default/default"; +// import { useListMachines } from "@/api/default/default"; export async function generateStaticParams() { return [{ id: "1" }, { id: "2" }]; } function getTemplate(params: { id: string }) { - console.log({ params }); // const res = await fetch(`https://.../posts/${params.id}`); return { short: `My Template ${params.id}`, @@ -47,8 +42,7 @@ interface TemplateDetailProps { params: { id: string }; } export default function TemplateDetail({ params }: TemplateDetailProps) { - const { data, isLoading } = useListMachines(); - console.log({ data, isLoading }); + // const { data, isLoading } = useListMachines(); const details = getTemplate(params); const [anchorEl, setAnchorEl] = useState(null); diff --git a/pkgs/ui/src/app/templates/page.tsx b/pkgs/ui/src/app/templates/page.tsx index ee7f06c..fc76ba1 100644 --- a/pkgs/ui/src/app/templates/page.tsx +++ b/pkgs/ui/src/app/templates/page.tsx @@ -2,7 +2,6 @@ import { ChevronRight } from "@mui/icons-material"; import { Avatar, Divider, - IconButton, List, ListItem, ListItemAvatar, diff --git a/pkgs/ui/src/components/background.tsx b/pkgs/ui/src/components/background.tsx new file mode 100644 index 0000000..1eb8174 --- /dev/null +++ b/pkgs/ui/src/components/background.tsx @@ -0,0 +1,45 @@ +import Image from "next/image"; +import clanLight from "../../public/clan-dark.png"; +import clanDark from "../../public/clan-dark.png"; +import { useAppState } from "./hooks/useAppContext"; + +export default function Background() { + const { data, isLoading } = useAppState(); + + return ( +
+ {(isLoading || !data.isJoined) && ( + <> + clan + clan + + )} +
+ ); +} diff --git a/pkgs/ui/src/components/createMachineForm/customConfig.tsx b/pkgs/ui/src/components/createMachineForm/customConfig.tsx index fd005fb..3a03aee 100644 --- a/pkgs/ui/src/components/createMachineForm/customConfig.tsx +++ b/pkgs/ui/src/components/createMachineForm/customConfig.tsx @@ -12,7 +12,7 @@ import { Paper, Typography, } from "@mui/material"; -import { IChangeEvent, FormProps } from "@rjsf/core"; +import { IChangeEvent } from "@rjsf/core"; import { Form } from "@rjsf/mui"; import validator from "@rjsf/validator-ajv8"; import toast from "react-hot-toast"; @@ -100,7 +100,7 @@ function ErrorList< } function PureCustomConfig(props: PureCustomConfigProps) { - const { schema, initialValues, formHooks } = props; + const { schema, formHooks } = props; const { setValue, watch } = formHooks; console.log({ schema }); diff --git a/pkgs/ui/src/components/createMachineForm/index.tsx b/pkgs/ui/src/components/createMachineForm/index.tsx index 3c5186a..7fbef8e 100644 --- a/pkgs/ui/src/components/createMachineForm/index.tsx +++ b/pkgs/ui/src/components/createMachineForm/index.tsx @@ -5,19 +5,14 @@ import { Step, StepLabel, Stepper, - Typography, useMediaQuery, useTheme, } from "@mui/material"; -import React, { ReactNode, useState } from "react"; -import { useForm, UseFormReturn } from "react-hook-form"; +import React, { useState } from "react"; +import { useForm } from "react-hook-form"; import { CustomConfig } from "./customConfig"; import { CreateMachineForm, FormStep } from "./interfaces"; -const SC = (props: { children: ReactNode }) => { - return <>{props.children}; -}; - export function CreateMachineForm() { const formHooks = useForm({ defaultValues: { @@ -25,7 +20,7 @@ export function CreateMachineForm() { config: {}, }, }); - const { handleSubmit, control, watch, reset, formState } = formHooks; + const { handleSubmit, reset } = formHooks; const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down("sm")); const [activeStep, setActiveStep] = useState(0); diff --git a/pkgs/ui/src/components/createMachineForm/interfaces.ts b/pkgs/ui/src/components/createMachineForm/interfaces.ts index e83c9a9..c9e14c2 100644 --- a/pkgs/ui/src/components/createMachineForm/interfaces.ts +++ b/pkgs/ui/src/components/createMachineForm/interfaces.ts @@ -1,4 +1,4 @@ -import { ReactElement, ReactNode } from "react"; +import { ReactElement } from "react"; import { UseFormReturn } from "react-hook-form"; export type StepId = "template" | "modules" | "config" | "save"; diff --git a/pkgs/ui/src/components/dashboard/NetworkOverview/index.tsx b/pkgs/ui/src/components/dashboard/NetworkOverview/index.tsx index ed7c108..245e8e6 100644 --- a/pkgs/ui/src/components/dashboard/NetworkOverview/index.tsx +++ b/pkgs/ui/src/components/dashboard/NetworkOverview/index.tsx @@ -8,7 +8,6 @@ import { ListItem, ListItemIcon, ListItemText, - Typography, } from "@mui/material"; import Link from "next/link"; import React from "react"; diff --git a/pkgs/ui/src/components/dashboard/appOverview/index.tsx b/pkgs/ui/src/components/dashboard/appOverview/index.tsx index 0e7acc8..5b576d5 100644 --- a/pkgs/ui/src/components/dashboard/appOverview/index.tsx +++ b/pkgs/ui/src/components/dashboard/appOverview/index.tsx @@ -1,7 +1,5 @@ import { DashboardCard } from "@/components/card"; import Image from "next/image"; -import { ReactNode } from "react"; - interface AppCardProps { name: string; icon?: string; @@ -32,11 +30,6 @@ const AppCard = (props: AppCardProps) => { ); }; -type App = { - name: string; - icon?: string; -}; - const apps = [ { name: "Firefox", diff --git a/pkgs/ui/src/components/dashboard/notifications/index.tsx b/pkgs/ui/src/components/dashboard/notifications/index.tsx index 7693114..dcc8017 100644 --- a/pkgs/ui/src/components/dashboard/notifications/index.tsx +++ b/pkgs/ui/src/components/dashboard/notifications/index.tsx @@ -1,17 +1,12 @@ import { DashboardCard } from "@/components/card"; import { notificationData } from "@/data/dashboardData"; -import { tw } from "@/utils/tailwind"; import { Avatar, - Chip, List, ListItem, ListItemAvatar, - ListItemButton, - ListItemIcon, ListItemText, } from "@mui/material"; -import { Label } from "recharts"; import CheckIcon from "@mui/icons-material/Check"; import InfoIcon from "@mui/icons-material/Info"; diff --git a/pkgs/ui/src/components/dashboard/quickActions/index.tsx b/pkgs/ui/src/components/dashboard/quickActions/index.tsx index 17e03c5..b11f590 100644 --- a/pkgs/ui/src/components/dashboard/quickActions/index.tsx +++ b/pkgs/ui/src/components/dashboard/quickActions/index.tsx @@ -1,6 +1,6 @@ "use client"; import { DashboardCard } from "@/components/card"; -import { Button, Fab } from "@mui/material"; +import { Fab } from "@mui/material"; import { MouseEventHandler, ReactNode } from "react"; import LanIcon from "@mui/icons-material/Lan"; diff --git a/pkgs/ui/src/components/dashboard/taskQueue/index.tsx b/pkgs/ui/src/components/dashboard/taskQueue/index.tsx index c55ab3d..eed11c5 100644 --- a/pkgs/ui/src/components/dashboard/taskQueue/index.tsx +++ b/pkgs/ui/src/components/dashboard/taskQueue/index.tsx @@ -19,7 +19,7 @@ interface TaskEntryProps { details?: string; } const TaskEntry = (props: TaskEntryProps) => { - const { result, task, details, status } = props; + const { result, task, status } = props; return ( <>
{status}
diff --git a/pkgs/ui/src/components/flakeBadge/flakeBadge.tsx b/pkgs/ui/src/components/flakeBadge/flakeBadge.tsx index 1b0b91a..8871de4 100644 --- a/pkgs/ui/src/components/flakeBadge/flakeBadge.tsx +++ b/pkgs/ui/src/components/flakeBadge/flakeBadge.tsx @@ -10,7 +10,10 @@ export const FlakeBadge = (props: FlakeBadgeProps) => ( label={`${props.flakeUrl}#${props.flakeAttr}`} sx={{ p: 2, - "& .MuiChip-label": { + "&.MuiChip-root": { + maxWidth: "unset", + }, + "&.MuiChip-label": { overflow: "unset", }, }} diff --git a/pkgs/ui/src/components/hooks/useAppContext.tsx b/pkgs/ui/src/components/hooks/useAppContext.tsx new file mode 100644 index 0000000..6f221d6 --- /dev/null +++ b/pkgs/ui/src/components/hooks/useAppContext.tsx @@ -0,0 +1,61 @@ +import { useListMachines } from "@/api/default/default"; +import { MachinesResponse } from "@/api/model"; +import { AxiosError, AxiosResponse } from "axios"; +import React, { + createContext, + Dispatch, + ReactNode, + SetStateAction, + useState, +} from "react"; +import { KeyedMutator } from "swr"; + +type AppContextType = { + // data: AxiosResponse<{}, any> | undefined; + data: AppState; + + isLoading: boolean; + error: AxiosError | undefined; + + setAppState: Dispatch>; + mutate: KeyedMutator>; + swrKey: string | false | Record; +}; + +// const initialState = { +// isLoading: true, +// } as const; + +export const AppContext = createContext({} as AppContextType); + +type AppState = { + isJoined?: boolean; + clanName?: string; +}; + +interface AppContextProviderProps { + children: ReactNode; +} +export const WithAppState = (props: AppContextProviderProps) => { + const { children } = props; + const { isLoading, error, mutate, swrKey } = useListMachines(); + + const [data, setAppState] = useState({ isJoined: false }); + + return ( + + {children} + + ); +}; + +export const useAppState = () => React.useContext(AppContext); diff --git a/pkgs/ui/src/components/hooks/useVms.tsx b/pkgs/ui/src/components/hooks/useVms.tsx index 212d290..bccfe77 100644 --- a/pkgs/ui/src/components/hooks/useVms.tsx +++ b/pkgs/ui/src/components/hooks/useVms.tsx @@ -33,7 +33,9 @@ export const useVms = (options: UseVmsOptions) => { } catch (e) { const err = e as AxiosError; setError(err); - toast.error(err.message); + toast( + "Could not find default configuration. Please select a machine preset", + ); return undefined; } finally { setIsLoading(false); diff --git a/pkgs/ui/src/components/join/configureVM.tsx b/pkgs/ui/src/components/join/configureVM.tsx index e1541f6..630cb5a 100644 --- a/pkgs/ui/src/components/join/configureVM.tsx +++ b/pkgs/ui/src/components/join/configureVM.tsx @@ -10,10 +10,11 @@ import { } from "@mui/material"; import { Controller, SubmitHandler, UseFormReturn } from "react-hook-form"; import { FlakeBadge } from "../flakeBadge/flakeBadge"; -import { createVm, useGetVmLogs } from "@/api/default/default"; +import { createVm, useInspectFlakeAttrs } from "@/api/default/default"; import { VmConfig } from "@/api/model"; -import { Dispatch, SetStateAction, useState } from "react"; +import { Dispatch, SetStateAction, useEffect, useState } from "react"; import { toast } from "react-hot-toast"; +import { useAppState } from "../hooks/useAppContext"; interface VmPropLabelProps { children: React.ReactNode; @@ -28,20 +29,26 @@ interface VmPropContentProps { children: React.ReactNode; } const VmPropContent = (props: VmPropContentProps) => ( -
{props.children}
+
{props.children}
); interface VmDetailsProps { - vmConfig: VmConfig; formHooks: UseFormReturn; setVmUuid: Dispatch>; } export const ConfigureVM = (props: VmDetailsProps) => { - const { vmConfig, formHooks, setVmUuid } = props; - const { control, handleSubmit } = formHooks; - const { cores, flake_attr, flake_url, graphics, memory_size } = vmConfig; + const { formHooks, setVmUuid } = props; + const { control, handleSubmit, watch, setValue } = formHooks; const [isStarting, setStarting] = useState(false); + const { setAppState } = useAppState(); + const { isLoading, data } = useInspectFlakeAttrs({ url: watch("flake_url") }); + + useEffect(() => { + if (!isLoading && data?.data) { + setValue("flake_attr", data.data.flake_attrs[0] || ""); + } + }, [isLoading, setValue, data]); const onSubmit: SubmitHandler = async (data) => { setStarting(true); @@ -53,6 +60,7 @@ export const ConfigureVM = (props: VmDetailsProps) => { setStarting(false); if (response.statusText === "OK") { toast.success(("Joined @ " + uuid) as string); + setAppState((s) => ({ ...s, isJoined: true })); } else { toast.error("Could not join"); } @@ -64,30 +72,44 @@ export const ConfigureVM = (props: VmDetailsProps) => { className="grid grid-cols-4 gap-y-10" >
- General + General
Flake - + Machine - ( - - )} - /> + {!isLoading && ( + ( + + )} + /> + )}
- VM + VM
CPU Cores @@ -103,7 +125,7 @@ export const ConfigureVM = (props: VmDetailsProps) => { name="graphics" control={control} render={({ field }) => ( - + )} /> @@ -129,7 +151,12 @@ export const ConfigureVM = (props: VmDetailsProps) => {
{isStarting && } -
diff --git a/pkgs/ui/src/components/join/confirm.tsx b/pkgs/ui/src/components/join/confirm.tsx index cf04bdf..5e8067ff 100644 --- a/pkgs/ui/src/components/join/confirm.tsx +++ b/pkgs/ui/src/components/join/confirm.tsx @@ -3,7 +3,7 @@ import { useState } from "react"; import { LoadingOverlay } from "./loadingOverlay"; import { FlakeBadge } from "../flakeBadge/flakeBadge"; import { Typography, Button } from "@mui/material"; -import { FlakeResponse } from "@/api/model"; +// import { FlakeResponse } from "@/api/model"; import { ConfirmVM } from "./confirmVM"; import { Log } from "./log"; import GppMaybeIcon from "@mui/icons-material/GppMaybe"; @@ -11,22 +11,29 @@ import { useInspectFlake } from "@/api/default/default"; interface ConfirmProps { flakeUrl: string; + flakeAttr: string; handleBack: () => void; } export const Confirm = (props: ConfirmProps) => { - const { flakeUrl, handleBack } = props; + const { flakeUrl, handleBack, flakeAttr } = props; const [userConfirmed, setUserConfirmed] = useState(false); - const { data, error, isLoading } = useInspectFlake({ url: flakeUrl }); + const { data, isLoading } = useInspectFlake({ + url: flakeUrl, + }); return userConfirmed ? ( - + ) : ( -
+
{isLoading && ( } + subtitle={} /> )} {data && ( diff --git a/pkgs/ui/src/components/join/confirmVM.tsx b/pkgs/ui/src/components/join/confirmVM.tsx index efad07e..8bda0ca 100644 --- a/pkgs/ui/src/components/join/confirmVM.tsx +++ b/pkgs/ui/src/components/join/confirmVM.tsx @@ -3,43 +3,36 @@ import React, { useEffect, useState } from "react"; import { VmConfig } from "@/api/model"; import { useVms } from "@/components/hooks/useVms"; -import { Alert, AlertTitle, Button } from "@mui/material"; - -import { useSearchParams } from "next/navigation"; - -import { createVm, inspectVm, useGetVmLogs } from "@/api/default/default"; - import { LoadingOverlay } from "./loadingOverlay"; -import { FlakeBadge } from "../flakeBadge/flakeBadge"; -import { Log } from "./log"; -import { SubmitHandler, useForm } from "react-hook-form"; +import { useForm } from "react-hook-form"; import { ConfigureVM } from "./configureVM"; import { VmBuildLogs } from "./vmBuildLogs"; interface ConfirmVMProps { url: string; handleBack: () => void; + defaultFlakeAttr: string; } export function ConfirmVM(props: ConfirmVMProps) { - const { url, handleBack } = props; + const { url, defaultFlakeAttr } = props; const formHooks = useForm({ defaultValues: { flake_url: url, - flake_attr: "vm1", - cores: 1, + flake_attr: defaultFlakeAttr, + cores: 4, graphics: true, - memory_size: 1024, + memory_size: 2048, }, }); const [vmUuid, setVmUuid] = useState(null); - const { setValue, watch, formState, handleSubmit } = formHooks; - const { config, error, isLoading } = useVms({ + const { setValue, watch, formState } = formHooks; + const { config, isLoading } = useVms({ url, - // TODO: FIXME - attr: watch("flake_attr"), + attr: watch("flake_attr") || defaultFlakeAttr, }); + useEffect(() => { if (config) { setValue("cores", config?.cores); @@ -52,48 +45,12 @@ export function ConfirmVM(props: ConfirmVMProps) {
{!formState.isSubmitted && ( <> - {error && ( - - Error - An Error occurred - See details below - - )}
{isLoading && ( - } - /> - )} - {config && ( - - )} - {error && ( - <> - - err.msg.split("\n")) - ?.flat() - .filter(Boolean) || [] - } - /> - + )} + +
)} diff --git a/pkgs/ui/src/components/join/loadingOverlay.tsx b/pkgs/ui/src/components/join/loadingOverlay.tsx index 63c5381..8ae22e3 100644 --- a/pkgs/ui/src/components/join/loadingOverlay.tsx +++ b/pkgs/ui/src/components/join/loadingOverlay.tsx @@ -1,18 +1,27 @@ "use client"; -import { LinearProgress, Typography } from "@mui/material"; +import { CircularProgress, LinearProgress, Typography } from "@mui/material"; interface LoadingOverlayProps { title: React.ReactNode; subtitle: React.ReactNode; + variant?: "linear" | "circle"; } export const LoadingOverlay = (props: LoadingOverlayProps) => { - const { title, subtitle } = props; + const { title, subtitle, variant = "linear" } = props; return (
- {title} - -
{subtitle}
- +
+ {title} +
+
+ {subtitle} +
+ {variant === "linear" && } + {variant === "circle" && ( +
+ +
+ )}
); }; diff --git a/pkgs/ui/src/components/join/vmBuildLogs.tsx b/pkgs/ui/src/components/join/vmBuildLogs.tsx index 72440bf..bad19cc 100644 --- a/pkgs/ui/src/components/join/vmBuildLogs.tsx +++ b/pkgs/ui/src/components/join/vmBuildLogs.tsx @@ -9,11 +9,7 @@ interface VmBuildLogsProps { export const VmBuildLogs = (props: VmBuildLogsProps) => { const { vmUuid } = props; - const { - data: logs, - isLoading, - error, - } = useGetVmLogs(vmUuid as string, { + const { data: logs, isLoading } = useGetVmLogs(vmUuid as string, { swr: { enabled: vmUuid !== null, }, diff --git a/pkgs/ui/src/components/sidebar/index.tsx b/pkgs/ui/src/components/sidebar/index.tsx index a89f59b..59eac48 100644 --- a/pkgs/ui/src/components/sidebar/index.tsx +++ b/pkgs/ui/src/components/sidebar/index.tsx @@ -1,17 +1,14 @@ import { - Alert, Divider, - Icon, IconButton, List, ListItem, ListItemButton, ListItemIcon, ListItemText, - Snackbar, } from "@mui/material"; import Image from "next/image"; -import { ReactNode, useState } from "react"; +import { ReactNode } from "react"; import DashboardIcon from "@mui/icons-material/Dashboard"; import DevicesIcon from "@mui/icons-material/Devices"; @@ -29,7 +26,7 @@ type MenuEntry = { icon: ReactNode; label: string; to: string; - missing: boolean; + disabled: boolean; } & { subMenuEntries?: MenuEntry[]; }; @@ -39,37 +36,37 @@ const menuEntries: MenuEntry[] = [ icon: , label: "Dashoard", to: "/", - missing: false, + disabled: false, }, { icon: , label: "Machines", to: "/machines", - missing: false, + disabled: false, }, { icon: , label: "Applications", to: "/applications", - missing: true, + disabled: true, }, { icon: , label: "Network", to: "/network", - missing: true, + disabled: true, }, { icon: , label: "Templates", to: "/templates", - missing: false, + disabled: false, }, { icon: , label: "Backups", to: "/backups", - missing: true, + disabled: true, }, ]; @@ -83,22 +80,6 @@ interface SidebarProps { export function Sidebar(props: SidebarProps) { const { show, onClose } = props; - const [open, setOpen] = React.useState(false); - const handleClick = () => { - setOpen(true); - }; - - const handleClose = ( - event?: React.SyntheticEvent | Event, - reason?: string, - ) => { - if (reason === "clickaway") { - return; - } - - setOpen(false); - }; - return (