From 3a3ab37a1892fa847c90818170fb5cf6b531bda3 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Tue, 7 Jan 2025 09:20:00 +0100 Subject: [PATCH] UI: improve disk workflow when already initialized --- .../app/src/routes/machines/details.tsx | 130 +++++++++++------- .../src/routes/machines/install/disk-step.tsx | 16 +-- 2 files changed, 87 insertions(+), 59 deletions(-) diff --git a/pkgs/webview-ui/app/src/routes/machines/details.tsx b/pkgs/webview-ui/app/src/routes/machines/details.tsx index 9e8249712..1f3c3dfaf 100644 --- a/pkgs/webview-ui/app/src/routes/machines/details.tsx +++ b/pkgs/webview-ui/app/src/routes/machines/details.tsx @@ -21,10 +21,10 @@ import { InputLabel } from "@/src/components/inputBase"; import { FieldLayout } from "@/src/Form/fields/layout"; import { Modal } from "@/src/components/modal"; import { Typography } from "@/src/components/Typography"; -import cx from "classnames"; import { HardwareValues, HWStep } from "./install/hardware-step"; import { DiskStep, DiskValues } from "./install/disk-step"; import { SummaryStep } from "./install/summary-step"; +import cx from "classnames"; import { SectionHeader } from "@/src/components/group"; type MachineFormInterface = MachineData & { @@ -48,12 +48,30 @@ export interface AllStepsValues extends FieldValues { "3": NonNullable; } +const LoadingBar = () => ( +
+); + function sleep(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)); } interface InstallMachineProps { name?: string; targetHost?: string | null; + machine: MachineData; } const InstallMachine = (props: InstallMachineProps) => { const curr = activeURI(); @@ -64,9 +82,9 @@ const InstallMachine = (props: InstallMachineProps) => { const [formStore, { Form, Field }] = createForm(); + const [isDone, setIsDone] = createSignal(false); const [isInstalling, setIsInstalling] = createSignal(false); const [progressText, setProgressText] = createSignal(); - const [installError, setInstallError] = createSignal(); const handleInstall = async (values: AllStepsValues) => { console.log("Installing", values); @@ -86,42 +104,36 @@ const InstallMachine = (props: InstallMachineProps) => { "Installing machine. Grab coffee (15min)...", ); setIsInstalling(true); - setProgressText("Setting up disk ... (1/5)"); - const disk_response = await callApi("set_machine_disk_schema", { - base_path: curr_uri, - machine_name: props.name, - placeholders: diskValues.placeholders, - schema_name: diskValues.schema, - force: true, - }); + // props.machine.disk_ + const shouldRunDisk = + JSON.stringify(props.machine.disk_schema?.placeholders) !== + JSON.stringify(diskValues.placeholders); - if (disk_response.status === "error") { - toast.error( - `Failed to set disk schema: ${disk_response.errors[0].message}`, - ); - setProgressText( - "Failed to set disk schema. \n" + disk_response.errors[0].message, - ); - return; + if (shouldRunDisk) { + setProgressText("Setting up disk ... (1/5)"); + const disk_response = await callApi("set_machine_disk_schema", { + base_path: curr_uri, + machine_name: props.name, + placeholders: diskValues.placeholders, + schema_name: diskValues.schema, + force: true, + }); + + if (disk_response.status === "error") { + toast.error( + `Failed to set disk schema: ${disk_response.errors[0].message}`, + ); + setProgressText( + "Failed to set disk schema. \n" + disk_response.errors[0].message, + ); + return; + } } - // Next step - if (disk_response.status === "success") { - setProgressText("Evaluate configuration ... (2/5)"); - } - // Next step - await sleep(2000); - setProgressText("Building machine ... (3/5)"); - await sleep(2000); - setProgressText("Formatting remote disk ... (4/5)"); - await sleep(2000); - setProgressText("Copying system ... (5/5)"); - await sleep(2000); - setProgressText("Rebooting remote system ... "); - await sleep(2000); + setProgressText("Installing machine ... (2/5)"); - const r = await callApi("install_machine", { + const installPromise = callApi("install_machine", { opts: { machine: { name: props.name, @@ -133,13 +145,36 @@ const InstallMachine = (props: InstallMachineProps) => { password: "", }, }); + + // Next step + await sleep(10 * 1000); + setProgressText("Building machine ... (3/5)"); + await sleep(10 * 1000); + setProgressText("Formatting remote disk ... (4/5)"); + await sleep(10 * 1000); + setProgressText("Copying system ... (5/5)"); + await sleep(20 * 1000); + setProgressText("Rebooting remote system ... "); + await sleep(10 * 1000); + + const installResponse = await installPromise; + toast.dismiss(loading_toast); - if (r.status === "error") { + if (installResponse.status === "error") { toast.error("Failed to install machine"); + setIsDone(true); + setProgressText( + "Failed to install machine. \n" + installResponse.errors[0].message, + ); } - if (r.status === "success") { + + if (installResponse.status === "success") { toast.success("Machine installed successfully"); + setIsDone(true); + setProgressText( + "Machine installed successfully. Please unplug the usb stick and reboot the system.", + ); } }; @@ -271,7 +306,12 @@ const InstallMachine = (props: InstallMachineProps) => { setValue(formStore, "2", { ...prev, ...data }); handleNext(); }} - initial={getValue(formStore, "2")} + // @ts-expect-error: The placeholder type is to wide + initial={{ + ...props.machine.disk_schema, + ...getValue(formStore, "2"), + initialized: !!props.machine.disk_schema, + }} /> @@ -326,20 +366,7 @@ const InstallMachine = (props: InstallMachineProps) => {
-
+ {isDone() && } { /> )} - + {(field, props) => ( <> { diff --git a/pkgs/webview-ui/app/src/routes/machines/install/disk-step.tsx b/pkgs/webview-ui/app/src/routes/machines/install/disk-step.tsx index a23e9388b..78b1bf3b3 100644 --- a/pkgs/webview-ui/app/src/routes/machines/install/disk-step.tsx +++ b/pkgs/webview-ui/app/src/routes/machines/install/disk-step.tsx @@ -17,6 +17,7 @@ export interface DiskValues extends FieldValues { mainDisk: string; }; schema: string; + initialized: boolean; } export const DiskStep = (props: StepProps) => { const [formStore, { Form, Field }] = createForm({ @@ -74,9 +75,14 @@ export const DiskStep = (props: StepProps) => { + {props.initial?.initialized && "Disk has been initialized already"} {(field, fieldProps) => ( ) => { { label: "No options", value: "" }, ] } - // options={ - // deviceQuery.data?.blockdevices.map((d) => ({ - // value: d.path, - // label: `${d.path} -- ${d.size} bytes`, - // })) || [] - // } error={field.error} label="Main Disk" value={field.value || ""} placeholder="Select a disk" selectProps={fieldProps} - required + required={!props.initial?.initialized} /> )}