From af3c6282c9c05116ad7b4f0807fe11950e77a601 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Tue, 5 Aug 2025 18:19:51 +0200 Subject: [PATCH 01/10] UI/Alert: make description optional --- pkgs/clan-app/ui/src/components/Alert/Alert.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pkgs/clan-app/ui/src/components/Alert/Alert.tsx b/pkgs/clan-app/ui/src/components/Alert/Alert.tsx index 5fb0e8be9..6eefb82d1 100644 --- a/pkgs/clan-app/ui/src/components/Alert/Alert.tsx +++ b/pkgs/clan-app/ui/src/components/Alert/Alert.tsx @@ -4,11 +4,12 @@ import Icon, { IconVariant } from "@/src/components/Icon/Icon"; import { Typography } from "@/src/components/Typography/Typography"; import { Button } from "@kobalte/core/button"; import { Alert as KAlert } from "@kobalte/core/alert"; +import { Show } from "solid-js"; export interface AlertProps { type: "success" | "error" | "warning" | "info"; title: string; - description: string; + description?: string; icon?: IconVariant; onDismiss?: () => void; } @@ -25,9 +26,11 @@ export const Alert = (props: AlertProps) => ( {props.title} - - {props.description} - + + + {props.description} + + {props.onDismiss && ( + > ); }; @@ -62,7 +60,7 @@ export const BackButton = () => { export const StepFooter = () => { const stepper = useStepper(); return ( -
+
stepper.next()} />
From b8e9546762d19fe501dc85e402d423131c3e9b06 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Tue, 5 Aug 2025 18:22:56 +0200 Subject: [PATCH 05/10] UI/install: bootstrap visuals for createInstaller --- .../src/workflows/Install/Install.stories.tsx | 14 ++++ .../ui/src/workflows/Install/install.tsx | 2 + .../Install/steps/createInstaller.tsx | 66 +++++++++++++++++-- 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/pkgs/clan-app/ui/src/workflows/Install/Install.stories.tsx b/pkgs/clan-app/ui/src/workflows/Install/Install.stories.tsx index ce2c870cb..855368b0b 100644 --- a/pkgs/clan-app/ui/src/workflows/Install/Install.stories.tsx +++ b/pkgs/clan-app/ui/src/workflows/Install/Install.stories.tsx @@ -38,3 +38,17 @@ export const CreateInstallerDisk: Story = { initialStep: "create:disk", }, }; +export const CreateInstallerProgress: Story = { + description: "Showed while the USB stick is being flashed", + args: { + machineName: "Test Machine", + initialStep: "create:progress", + }, +}; +export const CreateInstallerDone: Story = { + description: "Installation done step", + args: { + machineName: "Test Machine", + initialStep: "create:done", + }, +}; diff --git a/pkgs/clan-app/ui/src/workflows/Install/install.tsx b/pkgs/clan-app/ui/src/workflows/Install/install.tsx index cb84e7fe9..988d55391 100644 --- a/pkgs/clan-app/ui/src/workflows/Install/install.tsx +++ b/pkgs/clan-app/ui/src/workflows/Install/install.tsx @@ -73,6 +73,8 @@ export const InstallModal = (props: InstallModalProps) => { ); }} + // @ts-expect-error some steps might not have this + disablePadding={stepper.currentStep()?.isSplash} > {(ctx) => } diff --git a/pkgs/clan-app/ui/src/workflows/Install/steps/createInstaller.tsx b/pkgs/clan-app/ui/src/workflows/Install/steps/createInstaller.tsx index d0d36c1f8..08e758434 100644 --- a/pkgs/clan-app/ui/src/workflows/Install/steps/createInstaller.tsx +++ b/pkgs/clan-app/ui/src/workflows/Install/steps/createInstaller.tsx @@ -15,6 +15,8 @@ import { BackButton, NextButton, StepFooter, StepLayout } from "../../Steps"; import { Typography } from "@/src/components/Typography/Typography"; import { Alert } from "@/src/components/Alert/Alert"; import { LoadingBar } from "@/src/components/LoadingBar/LoadingBar"; +import { Button } from "@/src/components/Button/Button"; +import Icon from "@/src/components/Icon/Icon"; const Prose = () => ( ( hierarchy="label" size="xs" weight="medium" - color="inherit" + color="quaternary" + family="mono" + inverted > Create a portable installer @@ -35,6 +39,7 @@ const Prose = () => ( size="default" weight="bold" color="inherit" + class="text-balance" > Grab a disposable USB stick and plug it in @@ -246,6 +251,7 @@ const ChooseDisk = () => { @@ -265,8 +271,55 @@ const ChooseDisk = () => { const FlashProgress = () => { return ( -
- +
+
+ + USB stick is being flashed + + + +
+
+ ); +}; +const FlashDone = () => { + const stepSignal = useStepper(); + return ( +
+
+
+ +
+ + Device has been successfully flashed! + + +
+ +
+
); }; @@ -288,7 +341,12 @@ export const createInstallerSteps = [ }, { id: "create:progress", - title: CreateHeader, content: FlashProgress, + isSplash: true, + }, + { + id: "create:done", + content: FlashDone, + isSplash: true, }, ] as const; From 92726ecebcc991cb11bb786fd4d6dcff3f86c7a0 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Tue, 5 Aug 2025 18:25:25 +0200 Subject: [PATCH 06/10] UI/install: installer steps bootstrap visuals {TargetHost,hw_report} --- .../src/workflows/Install/Install.stories.tsx | 14 ++ .../workflows/Install/steps/installSteps.tsx | 138 ++++++++++++++++-- 2 files changed, 143 insertions(+), 9 deletions(-) diff --git a/pkgs/clan-app/ui/src/workflows/Install/Install.stories.tsx b/pkgs/clan-app/ui/src/workflows/Install/Install.stories.tsx index 855368b0b..eba2f9658 100644 --- a/pkgs/clan-app/ui/src/workflows/Install/Install.stories.tsx +++ b/pkgs/clan-app/ui/src/workflows/Install/Install.stories.tsx @@ -52,3 +52,17 @@ export const CreateInstallerDone: Story = { initialStep: "create:done", }, }; +export const InstallConfigureAddress: Story = { + description: "Installation configure address step", + args: { + machineName: "Test Machine", + initialStep: "install:address", + }, +}; +export const InstallCheckHardware: Story = { + description: "Installation check hardware step", + args: { + machineName: "Test Machine", + initialStep: "install:check-hardware", + }, +}; diff --git a/pkgs/clan-app/ui/src/workflows/Install/steps/installSteps.tsx b/pkgs/clan-app/ui/src/workflows/Install/steps/installSteps.tsx index 17bde23d2..4aebfdd9c 100644 --- a/pkgs/clan-app/ui/src/workflows/Install/steps/installSteps.tsx +++ b/pkgs/clan-app/ui/src/workflows/Install/steps/installSteps.tsx @@ -1,24 +1,144 @@ import { Typography } from "@/src/components/Typography/Typography"; -import { NextButton } from "../../Steps"; +import { BackButton, NextButton, StepLayout } from "../../Steps"; +import { + createForm, + getError, + SubmitHandler, + valiForm, +} from "@modular-forms/solid"; +import { Fieldset } from "@/src/components/Form/Fieldset"; +import * as v from "valibot"; +import { useStepper } from "@/src/hooks/stepper"; +import { InstallSteps } from "../install"; +import { TextInput } from "@/src/components/Form/TextInput"; +import { Alert } from "@/src/components/Alert/Alert"; +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"; export const InstallHeader = (props: { machineName: string }) => { return ( - + Installing: {props.machineName} ); }; +const ConfigureAdressSchema = v.object({ + targetHost: v.pipe( + v.string("Please set a target host."), + v.nonEmpty("Please set a target host."), + ), +}); + +type ConfigureAdressForm = v.InferInput; + +const ConfigureAddress = () => { + const [formStore, { Form, Field }] = createForm({ + validate: valiForm(ConfigureAdressSchema), + }); + const stepSignal = useStepper(); + + // TODO: push values to the parent form Store + const handleSubmit: SubmitHandler = (values, event) => { + console.log("ISO creation submitted", values); + // Here you would typically trigger the ISO creation process + stepSignal.next(); + }; + + return ( +
+ +
+ + {(field, props) => ( + + )} + +
+
+ } + footer={ +
+ + Next +
+ } + /> + + ); +}; + +const CheckHardware = () => { + const stepSignal = useStepper(); + // TODO: Hook this up with api + const [report, setReport] = createSignal(true); + + const handleNext = () => { + stepSignal.next(); + }; + + return ( + +
+ + + Check hardware + + + + + + + +
+
+ } + footer={ +
+ + Next +
+ } + /> + ); +}; + export const installSteps = [ { - id: "install:machine-0", + id: "install:address", title: InstallHeader, - content: () => ( -
- Enter the targetHost - -
- ), + content: ConfigureAddress, + }, + { + id: "install:check-hardware", + title: InstallHeader, + content: CheckHardware, }, { id: "install:confirm", From 0240acdf3e2383be75728358fd0646b841f02dde Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Tue, 5 Aug 2025 19:27:01 +0200 Subject: [PATCH 07/10] UI/modal: move common styling into meta header --- pkgs/clan-app/ui/src/components/Modal/Modal.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pkgs/clan-app/ui/src/components/Modal/Modal.tsx b/pkgs/clan-app/ui/src/components/Modal/Modal.tsx index 81df90da9..2248b2b1a 100644 --- a/pkgs/clan-app/ui/src/components/Modal/Modal.tsx +++ b/pkgs/clan-app/ui/src/components/Modal/Modal.tsx @@ -1,9 +1,10 @@ -import { createSignal, JSX, Show } from "solid-js"; +import { Component, createSignal, JSX, Show } from "solid-js"; import { Dialog as KDialog } from "@kobalte/core/dialog"; import styles from "./Modal.module.css"; import { Typography } from "../Typography/Typography"; import Icon from "../Icon/Icon"; import cx from "classnames"; +import { Dynamic } from "solid-js/web"; export interface ModalContext { close(): void; @@ -16,7 +17,7 @@ export interface ModalProps { children: (ctx: ModalContext) => JSX.Element; mount?: Node; class?: string; - metaHeader?: () => JSX.Element; + metaHeader?: Component; disablePadding?: boolean; } @@ -45,10 +46,12 @@ export const Modal = (props: ModalProps) => { - + {(metaHeader) => ( <> - {metaHeader()} +
+ +
)} From c90b69d499992d3a046b6aea8d1a1f96ebb5ea18 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Tue, 5 Aug 2025 19:27:29 +0200 Subject: [PATCH 08/10] UI/install: clean up create steps --- .../Install/steps/createInstaller.tsx | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/pkgs/clan-app/ui/src/workflows/Install/steps/createInstaller.tsx b/pkgs/clan-app/ui/src/workflows/Install/steps/createInstaller.tsx index 08e758434..0bfb974d1 100644 --- a/pkgs/clan-app/ui/src/workflows/Install/steps/createInstaller.tsx +++ b/pkgs/clan-app/ui/src/workflows/Install/steps/createInstaller.tsx @@ -62,16 +62,9 @@ const Prose = () => ( const CreateHeader = (props: { machineName: string }) => { return ( -
- - Create installer - -
+ + Create installer + ); }; @@ -271,8 +264,8 @@ const ChooseDisk = () => { const FlashProgress = () => { return ( -
-
+
+
{ const FlashDone = () => { const stepSignal = useStepper(); return ( -
-
+
+
@@ -310,7 +303,7 @@ const FlashDone = () => { title="Plug the flashed device into the machine that you want to install." description="" /> -
+