UI/install: bootstrap steps for {DiskSchema, Vars, Summary}

This commit is contained in:
Johannes Kirschbauer
2025-08-05 19:28:47 +02:00
parent c0bc0417a6
commit 9e43285ba8
2 changed files with 272 additions and 7 deletions

View File

@@ -66,3 +66,38 @@ export const InstallCheckHardware: Story = {
initialStep: "install:check-hardware",
},
};
export const InstallSelectDisk: Story = {
description: "Select disk to install the system on",
args: {
machineName: "Test Machine",
initialStep: "install:disk",
},
};
export const InstallVars: Story = {
description: "Fill required credentials and data for the installation",
args: {
machineName: "Test Machine",
initialStep: "install:data",
},
};
export const InstallSummary: Story = {
description: "Summary of the installation steps",
args: {
machineName: "Test Machine",
initialStep: "install:summary",
},
};
export const InstallProgress: Story = {
description: "Shown while the installation is in progress",
args: {
machineName: "Test Machine",
initialStep: "install:progress",
},
};
export const InstallDone: Story = {
description: "Shown after the installation is done",
args: {
machineName: "Test Machine",
initialStep: "install:done",
},
};

View File

@@ -16,10 +16,11 @@ import { createSignal, Show } from "solid-js";
import { Divider } from "@/src/components/Divider/Divider";
import { Orienter } from "@/src/components/Form/Orienter";
import { Button } from "@/src/components/Button/Button";
import { Select } from "@/src/components/Select/Select";
export const InstallHeader = (props: { machineName: string }) => {
return (
<Typography hierarchy="label" size="default" class="px-6">
<Typography hierarchy="label" size="default">
Installing: {props.machineName}
</Typography>
);
@@ -129,6 +130,216 @@ const CheckHardware = () => {
);
};
const DiskSchema = v.object({
mainDisk: v.pipe(
v.string("Please select a disk"),
v.nonEmpty("Please select a disk"),
),
});
type DiskForm = v.InferInput<typeof DiskSchema>;
const ConfigureDisk = () => {
const [formStore, { Form, Field }] = createForm<DiskForm>({
validate: valiForm(DiskSchema),
});
const stepSignal = useStepper<InstallSteps>();
const handleSubmit: SubmitHandler<DiskForm> = (values, event) => {
console.log("submitted", values);
// Here you would typically trigger the ISO creation process
stepSignal.next();
};
return (
<Form onSubmit={handleSubmit}>
<StepLayout
body={
<div class="flex flex-col gap-2">
<Fieldset>
<Field name="mainDisk">
{(field, props) => (
<Select
{...props}
value={field.value}
error={field.error}
required
label={{
label: "Main disk",
description: "Select the disk to install the system on",
}}
// TODO: Get from api
options={[{ value: "disk", label: "Disk0" }]}
placeholder="Select a disk"
name={field.name}
/>
)}
</Field>
</Fieldset>
</div>
}
footer={
<div class="flex justify-between">
<BackButton />
<NextButton type="submit">Next</NextButton>
</div>
}
/>
</Form>
);
};
type DynamicForm = Record<string, string>;
const ConfigureData = () => {
const [formStore, { Form, Field }] = createForm<DynamicForm>({
// TODO: Dynamically validate fields
});
const stepSignal = useStepper<InstallSteps>();
const handleSubmit: SubmitHandler<DynamicForm> = (values, event) => {
console.log("vars submitted", values);
// Here you would typically trigger the ISO creation process
stepSignal.next();
};
return (
<Form onSubmit={handleSubmit}>
<StepLayout
body={
<div class="flex flex-col gap-2">
<Fieldset legend="Root password">
<Field name="root-password">
{(field, props) => (
<TextInput
{...field}
label="Root password"
description="Set the root password for the machine"
value={field.value}
required
orientation="horizontal"
validationState={
getError(formStore, "root-password") ? "invalid" : "valid"
}
icon="EyeClose"
input={{
...props,
type: "password",
}}
/>
)}
</Field>
</Fieldset>
<Fieldset legend="WIFI TU-YAN">
<Field name="networkSSID">
{(field, props) => (
<TextInput
{...field}
label="ssid"
description="Name of the wifi network"
value={field.value}
required
orientation="horizontal"
validationState={
getError(formStore, "wifi/password") ? "invalid" : "valid"
}
input={{
...props,
}}
/>
)}
</Field>
<Field name="password">
{(field, props) => (
<TextInput
{...field}
label="password"
description="Password for the wifi network"
value={field.value}
required
orientation="horizontal"
validationState={
getError(formStore, "wifi/password") ? "invalid" : "valid"
}
icon="EyeClose"
input={{
...props,
type: "password",
}}
/>
)}
</Field>
</Fieldset>
</div>
}
footer={
<div class="flex justify-between">
<BackButton />
<NextButton type="submit">Next</NextButton>
</div>
}
/>
</Form>
);
};
const Display = (props: { value: string; label: string }) => {
return (
<>
<Typography hierarchy="label" size="xs" color="primary" weight="bold">
{props.label}
</Typography>
<Typography hierarchy="body" size="s" weight="medium">
{props.value}
</Typography>
</>
);
};
const InstallSummary = () => {
const stepSignal = useStepper<InstallSteps>();
const handleInstall = () => {
// Here you would typically trigger the installation process
console.log("Installation started");
stepSignal.setActiveStep("install:progress");
};
return (
<StepLayout
body={
<div class="flex flex-col gap-4">
<Fieldset legend="Deploy to">
<Orienter orientation="horizontal">
{/* TOOD: Display the values emited from previous steps */}
<Display label="Target" value="flash-installer.local" />
</Orienter>
</Fieldset>
<Fieldset legend="Disk Configuration">
<Orienter orientation="horizontal">
<Display label="Disk Schema" value="Single" />
</Orienter>
<Divider orientation="horizontal" />
<Orienter orientation="horizontal">
<Display
label="Main Disk"
value="nvme-WD_PC_SN740_SDDQNQD-512G"
/>
</Orienter>
</Fieldset>
</div>
}
footer={
<div class="flex justify-between">
<BackButton />
<NextButton type="button" onClick={handleInstall} endIcon="Flash">
Install
</NextButton>
</div>
}
/>
);
};
export const installSteps = [
{
id: "install:address",
@@ -141,14 +352,28 @@ export const installSteps = [
content: CheckHardware,
},
{
id: "install:confirm",
id: "install:check-hardware",
title: InstallHeader,
content: (props: { machineName: string }) => (
<div>
Confirm the installation of {props.machineName}
<NextButton />
</div>
content: CheckHardware,
},
{
id: "install:disk",
title: InstallHeader,
content: ConfigureDisk,
},
{
id: "install:data",
title: InstallHeader,
content: ConfigureData,
},
{
id: "install:summary",
title: () => (
<Typography hierarchy="label" size="default">
Summary
</Typography>
),
content: InstallSummary,
},
{
id: "install:progress",
@@ -160,4 +385,9 @@ export const installSteps = [
</div>
),
},
{
id: "install:done",
title: InstallHeader,
content: () => <div>Done</div>,
},
] as const;