diff --git a/pkgs/clan-cli/clan_cli/machines/hardware.py b/pkgs/clan-cli/clan_cli/machines/hardware.py index c9f47272b..f3e152532 100644 --- a/pkgs/clan-cli/clan_cli/machines/hardware.py +++ b/pkgs/clan-cli/clan_cli/machines/hardware.py @@ -122,11 +122,15 @@ def generate_machine_hardware_info( # Disable known hosts file "-o", "UserKnownHostsFile=/dev/null", - "-p", - str(machine.target_host.port), + # Disable strict host key checking. The GUI user cannot type "yes" into the ssh terminal. + "-o", + "StrictHostKeyChecking=no", + *( + ["-p", str(machine.target_host.port)] + if machine.target_host.port + else [] + ), target_host, - "-o UserKnownHostsFile=/dev/null", - f"{hostname}", "nixos-generate-config", # Filesystems are managed by disko "--no-filesystems", diff --git a/pkgs/webview-ui/app/src/index.tsx b/pkgs/webview-ui/app/src/index.tsx index 6a2ebe1a2..5c09a5148 100644 --- a/pkgs/webview-ui/app/src/index.tsx +++ b/pkgs/webview-ui/app/src/index.tsx @@ -1,5 +1,5 @@ /* @refresh reload */ -import { render } from "solid-js/web"; +import { Portal, render } from "solid-js/web"; import { RouteDefinition, Router } from "@solidjs/router"; import "./index.css"; @@ -14,6 +14,7 @@ import { Flash } from "./routes/flash/view"; import { CreateMachine } from "./routes/machines/create"; import { HostList } from "./routes/hosts/view"; import { Welcome } from "./routes/welcome"; +import { Toaster } from "solid-toast"; const client = new QueryClient(); @@ -113,9 +114,14 @@ export const routes: AppRoute[] = [ render( () => ( - - {routes} - + <> + + + + + {routes} + + ), // eslint-disable-next-line @typescript-eslint/no-non-null-assertion root!, diff --git a/pkgs/webview-ui/app/src/layout/layout.tsx b/pkgs/webview-ui/app/src/layout/layout.tsx index 741576916..bd9ff86bc 100644 --- a/pkgs/webview-ui/app/src/layout/layout.tsx +++ b/pkgs/webview-ui/app/src/layout/layout.tsx @@ -3,7 +3,6 @@ import { Header } from "./header"; import { Sidebar } from "../Sidebar"; import { activeURI, clanList } from "../App"; import { redirect, RouteSectionProps, useNavigate } from "@solidjs/router"; -import { Toaster } from "solid-toast"; export const Layout: Component = (props) => { const navigate = useNavigate(); @@ -19,7 +18,6 @@ export const Layout: Component = (props) => { }); return (
-
{ const [confirmDisk, setConfirmDisk] = createSignal(!hasDisk()); + const hwInfoQuery = createQuery(() => ({ + queryKey: [ + activeURI(), + "machine", + props.name, + "show_machine_hardware_info", + ], + queryFn: async () => { + const curr = activeURI(); + if (curr && props.name) { + const result = await callApi("show_machine_hardware_info", { + clan_dir: curr, + machine_name: props.name, + }); + if (result.status === "error") throw new Error("Failed to fetch data"); + return result.data || null; + } + return null; + }, + })); + const handleInstall = async (values: InstallForm) => { console.log("Installing", values); const curr_uri = activeURI(); @@ -72,6 +93,9 @@ const InstallMachine = (props: InstallMachineProps) => { return; } + const loading_toast = toast.loading( + "Installing machine. Grab coffee (15min)...", + ); const r = await callApi("install_machine", { opts: { flake: { @@ -82,6 +106,7 @@ const InstallMachine = (props: InstallMachineProps) => { }, password: "", }); + toast.dismiss(loading_toast); if (r.status === "error") { toast.error("Failed to install machine"); @@ -91,7 +116,8 @@ const InstallMachine = (props: InstallMachineProps) => { } }; - const handleDiskConfirm = async () => { + const handleDiskConfirm = async (e: Event) => { + e.preventDefault(); const curr_uri = activeURI(); const disk = getValue(formStore, "disk"); const disk_id = props.disks.find((d) => d.name === disk)?.id_link; @@ -112,14 +138,86 @@ const InstallMachine = (props: InstallMachineProps) => { setConfirmDisk(true); } }; + + const generateReport = async (e: Event) => { + e.preventDefault(); + const curr_uri = activeURI(); + if (!curr_uri || !props.name) { + return; + } + + const loading_toast = toast.loading("Generating hardware report..."); + const r = await callApi("generate_machine_hardware_info", { + clan_dir: { loc: curr_uri }, + machine_name: props.name, + keyfile: props.sshKey?.name, + hostname: props.targetHost, + }); + toast.dismiss(loading_toast); + hwInfoQuery.refetch(); + + if (r.status === "error") { + toast.error(`Failed to generate report. ${r.errors[0].message}`); + } + if (r.status === "success") { + toast.success("Report generated successfully"); + } + }; return ( <>
-

{props.name}

-

Install to {props.targetHost}

+

+ Install: + {props.name} +

- Using {props.sshKey?.name || "default ssh key"} for authentication + Install the system for the first time. This will erase the disk and + bootstrap a new device.

+ +
+
Hardware detection
+ +
+ + + + + + + + close + Not Detected + +
+ This might still work, but it is recommended to generate + a hardware report. +
+ + } + > + + check + Detected + +
+
+
+
+ +
+
+
+ {(field, fieldProps) => ( { /> )} +