ui/install: hook up stepper store and api

This commit is contained in:
Johannes Kirschbauer
2025-08-07 12:53:58 +02:00
parent 7d23189c1c
commit 518de45d41
2 changed files with 96 additions and 21 deletions

View File

@@ -50,6 +50,14 @@ const steps = [
] as const; ] as const;
export type InstallSteps = typeof steps; export type InstallSteps = typeof steps;
export interface InstallStoreType {
flash: {
language: string;
keymap: string;
ssh_file: string;
device: string;
};
}
export const InstallModal = (props: InstallModalProps) => { export const InstallModal = (props: InstallModalProps) => {
const stepper = createStepper( const stepper = createStepper(

View File

@@ -1,4 +1,4 @@
import { useStepper } from "@/src/hooks/stepper"; import { getStepStore, useStepper } from "@/src/hooks/stepper";
import { import {
createForm, createForm,
getError, getError,
@@ -6,8 +6,7 @@ import {
valiForm, valiForm,
} from "@modular-forms/solid"; } from "@modular-forms/solid";
import * as v from "valibot"; import * as v from "valibot";
import { InstallSteps } from "../install"; import { InstallSteps, InstallStoreType } from "../install";
import { callApi } from "@/src/hooks/api";
import { Fieldset } from "@/src/components/Form/Fieldset"; import { Fieldset } from "@/src/components/Form/Fieldset";
import { HostFileInput } from "@/src/components/Form/HostFileInput"; import { HostFileInput } from "@/src/components/Form/HostFileInput";
import { Select } from "@/src/components/Select/Select"; import { Select } from "@/src/components/Select/Select";
@@ -17,6 +16,12 @@ import { Alert } from "@/src/components/Alert/Alert";
import { LoadingBar } from "@/src/components/LoadingBar/LoadingBar"; import { LoadingBar } from "@/src/components/LoadingBar/LoadingBar";
import { Button } from "@/src/components/Button/Button"; import { Button } from "@/src/components/Button/Button";
import Icon from "@/src/components/Icon/Icon"; import Icon from "@/src/components/Icon/Icon";
import {
useMachineFlashOptions,
useSystemStorageOptions,
} from "@/src/hooks/queries";
import { useClanURI } from "@/src/hooks/clan";
import { useApiClient } from "@/src/hooks/ApiClient";
const Prose = () => ( const Prose = () => (
<StepLayout <StepLayout
@@ -47,7 +52,7 @@ const Prose = () => (
</Typography> </Typography>
</div> </div>
</div> </div>
<div class="flex flex-col px-4 gap-4"> <div class="flex flex-col gap-4 px-4">
<div class="flex flex-col gap-1"> <div class="flex flex-col gap-1">
<Typography hierarchy="body" size="default" weight="bold"> <Typography hierarchy="body" size="default" weight="bold">
Let's walk through it. Let's walk through it.
@@ -101,15 +106,23 @@ const ConfigureImage = () => {
}); });
const stepSignal = useStepper<InstallSteps>(); const stepSignal = useStepper<InstallSteps>();
// TODO: push values to the parent form Store const [store, set] = getStepStore<InstallStoreType>(stepSignal);
const handleSubmit: SubmitHandler<ConfigureImageForm> = (values, event) => { const handleSubmit: SubmitHandler<ConfigureImageForm> = (values, event) => {
console.log("ISO creation submitted", values); // Push values to the store
// Here you would typically trigger the ISO creation process set("flash", (s) => ({
...s,
language: values.language,
keymap: values.keymap,
ssh_file: values.ssh_key,
}));
stepSignal.next(); stepSignal.next();
}; };
const client = useApiClient();
const onSelectFile = async () => { const onSelectFile = async () => {
const req = callApi("get_system_file", { const req = client.fetch("get_system_file", {
file_request: { file_request: {
mode: "select_folder", mode: "select_folder",
title: "Select a folder for you new Clan", title: "Select a folder for you new Clan",
@@ -131,6 +144,9 @@ const ConfigureImage = () => {
throw new Error("No data returned from api call"); throw new Error("No data returned from api call");
}; };
const currClan = useClanURI();
const optionsQuery = useMachineFlashOptions(currClan);
return ( return (
<Form onSubmit={handleSubmit}> <Form onSubmit={handleSubmit}>
<StepLayout <StepLayout
@@ -168,10 +184,19 @@ const ConfigureImage = () => {
label: "Language", label: "Language",
description: "Select your preferred language", description: "Select your preferred language",
}} }}
options={[ getOptions={async () => {
{ value: "en", label: "English" }, if (!optionsQuery.data) {
{ value: "fr", label: "Français" }, await optionsQuery.refetch();
]} }
return (optionsQuery.data?.languages ?? []).map(
(lang) => ({
// TODO: Pretty label ?
value: lang,
label: lang,
}),
);
}}
placeholder="Language" placeholder="Language"
name={field.name} name={field.name}
/> />
@@ -188,10 +213,19 @@ const ConfigureImage = () => {
label: "Keymap", label: "Keymap",
description: "Select your keyboard layout", description: "Select your keyboard layout",
}} }}
options={[ getOptions={async () => {
{ value: "EN_US", label: "QWERTY" }, if (!optionsQuery.data) {
{ value: "DE_DE", label: "QWERTZ" }, await optionsQuery.refetch();
]} }
return (optionsQuery.data?.keymaps ?? []).map(
(keymap) => ({
// TODO: Pretty label ?
value: keymap,
label: keymap,
}),
);
}}
placeholder="Keymap" placeholder="Keymap"
name={field.name} name={field.name}
/> />
@@ -226,9 +260,34 @@ const ChooseDisk = () => {
const [formStore, { Form, Field }] = createForm<ChooseDiskForm>({ const [formStore, { Form, Field }] = createForm<ChooseDiskForm>({
validate: valiForm(ChooseDiskSchema), validate: valiForm(ChooseDiskSchema),
}); });
const [store, set] = getStepStore<InstallStoreType>(stepSignal);
const client = useApiClient();
const systemStorageQuery = useSystemStorageOptions();
const handleSubmit: SubmitHandler<ChooseDiskForm> = (values, event) => { const handleSubmit: SubmitHandler<ChooseDiskForm> = (values, event) => {
console.log("Disk selected", values); // Just for completeness, set the disk in the store
console.log("Flashing", store.flash);
set("flash", (s) => ({
...s,
device: values.disk,
}));
const call = client.fetch("run_machine_flash", {
system_config: {
keymap: store.flash.keymap,
language: store.flash.language,
ssh_keys_path: [store.flash.ssh_file],
},
disks: [
{
name: "main",
device: values.disk,
},
],
});
// TOOD: Pass the "call" Promise to the "progress step"
console.log("Flashing", store.flash);
// Here you would typically trigger the disk selection process // Here you would typically trigger the disk selection process
stepSignal.next(); stepSignal.next();
}; };
@@ -249,10 +308,18 @@ const ChooseDisk = () => {
label: "USB Stick", label: "USB Stick",
description: "Select the usb stick", description: "Select the usb stick",
}} }}
options={[ getOptions={async () => {
{ value: "1", label: "sda1" }, if (!systemStorageQuery.data) {
{ value: "2", label: "sdb2" }, await systemStorageQuery.refetch();
]} }
return (systemStorageQuery.data?.blockdevices ?? []).map(
(dev) => ({
value: dev.path,
label: dev.name,
}),
);
}}
placeholder="Choose Device" placeholder="Choose Device"
name={field.name} name={field.name}
/> />