From 073750e4c5a0cfebe9f563822ca0e88a48172b32 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Wed, 6 Aug 2025 16:41:11 +0200 Subject: [PATCH 1/6] clanServices: update description of generators that can be left empty --- clanServices/admin/root-password.nix | 2 +- clanServices/users/default.nix | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clanServices/admin/root-password.nix b/clanServices/admin/root-password.nix index 3d7d6c09f..8891709e3 100644 --- a/clanServices/admin/root-password.nix +++ b/clanServices/admin/root-password.nix @@ -24,7 +24,7 @@ prompts.password.type = "hidden"; prompts.password.persist = true; - prompts.password.description = "You can autogenerate a password, if you leave this prompt blank."; + prompts.password.description = "Leave empty to generate automatically"; script = '' prompt_value="$(cat "$prompts"/password)" diff --git a/clanServices/users/default.nix b/clanServices/users/default.nix index f59336a34..1477aaee5 100644 --- a/clanServices/users/default.nix +++ b/clanServices/users/default.nix @@ -98,7 +98,7 @@ }; type = "hidden"; persist = true; - description = "You can autogenerate a password, if you leave this prompt blank."; + description = "Leave empty to generate automatically"; }; runtimeInputs = [ From e5db3e269b2dbd5eaedee07d57e3e7f54d937071 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Wed, 6 Aug 2025 16:42:03 +0200 Subject: [PATCH 2/6] UI/stepper: hooks add helper to more typesafe define steps --- pkgs/clan-app/ui/src/hooks/stepper.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pkgs/clan-app/ui/src/hooks/stepper.tsx b/pkgs/clan-app/ui/src/hooks/stepper.tsx index b7de50845..29030345b 100644 --- a/pkgs/clan-app/ui/src/hooks/stepper.tsx +++ b/pkgs/clan-app/ui/src/hooks/stepper.tsx @@ -118,3 +118,10 @@ export function StepperProvider< ); } + +/** + * Helper function to define steps in a type-safe manner. + */ +export function defineSteps(steps: T) { + return steps; +} From 65101ad55a21692a4c2fe2418fbd6e254e026139 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Wed, 6 Aug 2025 16:42:45 +0200 Subject: [PATCH 3/6] UI/steps: make step footer next text customizable --- pkgs/clan-app/ui/src/workflows/Steps.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pkgs/clan-app/ui/src/workflows/Steps.tsx b/pkgs/clan-app/ui/src/workflows/Steps.tsx index 9ee63db14..986d44485 100644 --- a/pkgs/clan-app/ui/src/workflows/Steps.tsx +++ b/pkgs/clan-app/ui/src/workflows/Steps.tsx @@ -57,12 +57,17 @@ export const BackButton = () => { * * Use this for overview steps where no form submission is required. */ -export const StepFooter = () => { +interface StepFooterProps { + nextText?: string; +} +export const StepFooter = (props: StepFooterProps) => { const stepper = useStepper(); return (
- stepper.next()} /> + stepper.next()}> + {props.nextText || undefined} +
); }; From fa03c190f88c2c6d79ee3c0ca52d9666d69f48f3 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Wed, 6 Aug 2025 16:43:11 +0200 Subject: [PATCH 4/6] UI/install: split initial choice --- .../ui/src/workflows/Install/install.tsx | 10 +- .../src/workflows/Install/steps/Initial.tsx | 128 +++++++++++++----- 2 files changed, 104 insertions(+), 34 deletions(-) diff --git a/pkgs/clan-app/ui/src/workflows/Install/install.tsx b/pkgs/clan-app/ui/src/workflows/Install/install.tsx index 73c3637b2..ed25edc38 100644 --- a/pkgs/clan-app/ui/src/workflows/Install/install.tsx +++ b/pkgs/clan-app/ui/src/workflows/Install/install.tsx @@ -7,7 +7,7 @@ import { import { createForm, FieldValues, SubmitHandler } from "@modular-forms/solid"; import { Show } from "solid-js"; import { Dynamic } from "solid-js/web"; -import { InitialStep } from "./steps/Initial"; +import { initialSteps } from "./steps/Initial"; import { createInstallerSteps } from "./steps/createInstaller"; import { installSteps } from "./steps/installSteps"; @@ -40,10 +40,14 @@ const InstallStepper = () => { export interface InstallModalProps { machineName: string; - initialStep?: string; + initialStep?: InstallSteps[number]["id"]; } -const steps = [InitialStep, ...createInstallerSteps, ...installSteps] as const; +const steps = [ + ...initialSteps, + ...createInstallerSteps, + ...installSteps, +] as const; export type InstallSteps = typeof steps; diff --git a/pkgs/clan-app/ui/src/workflows/Install/steps/Initial.tsx b/pkgs/clan-app/ui/src/workflows/Install/steps/Initial.tsx index e12054206..ebf1d52c9 100644 --- a/pkgs/clan-app/ui/src/workflows/Install/steps/Initial.tsx +++ b/pkgs/clan-app/ui/src/workflows/Install/steps/Initial.tsx @@ -1,32 +1,24 @@ -import { useStepper } from "@/src/hooks/stepper"; +import { defineSteps, Step, StepBase, useStepper } from "@/src/hooks/stepper"; import { InstallSteps } from "../install"; import { Typography } from "@/src/components/Typography/Typography"; import { Button } from "@/src/components/Button/Button"; import { Divider } from "@/src/components/Divider/Divider"; +import { StepLayout } from "../../Steps"; -const InitialChoice = () => { +const ChoiceLocalOrRemote = () => { const stepSignal = useStepper(); return (
-
-
+
+
- Remote setup - - - Is your machine currently online? Does it have an IP-address, can - you SSH into it? And does it support Kexec? + I have physical access to the machine.
+ onClick={() => stepSignal.setActiveStep("local:choice")} + />
- - -
- - I don't have an installer, yet - +
+
+
+
+ + The Machine is remote and i have ssh access to it. + +
+ icon="CaretRight" + onClick={() => stepSignal.setActiveStep("install:address")} + />
); }; -export const InitialStep = { - id: "init", - content: InitialChoice, +const ChoiceLocalInstaller = () => { + const stepSignal = useStepper(); + return ( + +
+
+
+ + I have an installer + +
+
+
+
+
+
+ + I don't have an installer, yet + +
+
+
+
+ } + footer={ +
+
+ } + /> + ); }; + +export const initialSteps = defineSteps([ + { + id: "init", + content: ChoiceLocalOrRemote, + }, + { + id: "local:choice", + content: ChoiceLocalInstaller, + }, +] as const); From 7d20f3a33bd40ca19bda53efc2d9815683b53e58 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Wed, 6 Aug 2025 16:43:48 +0200 Subject: [PATCH 5/6] UI/install: create installer improve wording --- .../Install/steps/createInstaller.tsx | 54 ++++++++++++------- 1 file changed, 35 insertions(+), 19 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 0bfb974d1..0b8212be7 100644 --- a/pkgs/clan-app/ui/src/workflows/Install/steps/createInstaller.tsx +++ b/pkgs/clan-app/ui/src/workflows/Install/steps/createInstaller.tsx @@ -32,7 +32,7 @@ const Prose = () => ( family="mono" inverted > - Create a portable installer + Local Setup ( color="inherit" class="text-balance" > - Grab a disposable USB stick and plug it in + Here's what you +
+ need to do
-
- - We will erase everything on it during this process - - - Create a portable installer tool that can turn any machine into a - fully configured Clan machine. - +
+
+ + Let's walk through it. + + + In the following we will help you to write the clan installer + software to a USB-stick. This USB-stick will then be used to set + up the new machine. Get a USB-stick with at least 8GB of capacity, + and plug it into the machine on which you read this text. Note, + all data on the USB-Stick will be lost. + +
+
+ + Why do you need to do this? + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. + Suspendisse varius enim in eros elementum tristique. Duis cursus, + +
} - footer={} + footer={} /> ); @@ -128,7 +144,7 @@ const ConfigureImage = () => { onSelectFile={onSelectFile} {...field} value={field.value} - label="Select directory" + label="Public Key" orientation="horizontal" placeholder="Select SSH Key" required={true} @@ -230,14 +246,14 @@ const ChooseDisk = () => { error={field.error} required label={{ - label: "Disk", - description: "Select a usb stick", + label: "USB Stick", + description: "Select the usb stick", }} options={[ { value: "1", label: "sda1" }, { value: "2", label: "sdb2" }, ]} - placeholder="Disk" + placeholder="Choose Device" name={field.name} /> )} @@ -246,7 +262,7 @@ const ChooseDisk = () => { type="error" icon="Info" title="You're about to format this drive" - description="It will erase all existing data on the target device" + description="It will erase all existing data" />
@@ -274,7 +290,7 @@ const FlashProgress = () => { > USB stick is being flashed - + @@ -296,11 +312,11 @@ const FlashDone = () => { weight="bold" color="inherit" > - Device has been successfully flashed! + USB Stick is ready!
From 19603e1a1c08a5ec891c0b59677d95e066e49543 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Wed, 6 Aug 2025 16:44:30 +0200 Subject: [PATCH 6/6] UI/install: add machine progress --- .../workflows/Install/steps/installSteps.tsx | 82 +++++++++++++++---- 1 file changed, 64 insertions(+), 18 deletions(-) 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 1f94c759c..2a5b78f1b 100644 --- a/pkgs/clan-app/ui/src/workflows/Install/steps/installSteps.tsx +++ b/pkgs/clan-app/ui/src/workflows/Install/steps/installSteps.tsx @@ -17,6 +17,8 @@ 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"; +import { LoadingBar } from "@/src/components/LoadingBar/LoadingBar"; +import Icon from "@/src/components/Icon/Icon"; export const InstallHeader = (props: { machineName: string }) => { return ( @@ -103,10 +105,10 @@ const CheckHardware = () => {
- Check hardware + Hardware Report @@ -123,7 +125,9 @@ const CheckHardware = () => { footer={
- Next + + Next +
} /> @@ -214,7 +218,7 @@ const ConfigureData = () => { { ); }; +const InstallProgress = () => { + return ( +
+
+ + Machine is beeing installed + + + +
+
+ ); +}; + +const FlashDone = () => { + const stepSignal = useStepper(); + return ( +
+
+
+ +
+ + Machine installation finished! + +
+ +
+
+
+ ); +}; + export const installSteps = [ { id: "install:address", @@ -351,11 +407,6 @@ export const installSteps = [ title: InstallHeader, content: CheckHardware, }, - { - id: "install:check-hardware", - title: InstallHeader, - content: CheckHardware, - }, { id: "install:disk", title: InstallHeader, @@ -377,17 +428,12 @@ export const installSteps = [ }, { id: "install:progress", - title: InstallHeader, - content: () => ( -
-

Installation in progress...

-

Please wait while we set up your machine.

-
- ), + content: InstallProgress, + isSplash: true, }, { id: "install:done", - title: InstallHeader, - content: () =>
Done
, + content: FlashDone, + isSplash: true, }, ] as const;