diff --git a/pkgs/webview-ui/app/src/components/FileInput.tsx b/pkgs/webview-ui/app/src/components/FileInput.tsx index 601ee632d..6c92a5d9f 100644 --- a/pkgs/webview-ui/app/src/components/FileInput.tsx +++ b/pkgs/webview-ui/app/src/components/FileInput.tsx @@ -15,6 +15,7 @@ interface FileInputProps { class?: string; label?: string; error?: string; + helperText?: string; } /** @@ -53,7 +54,9 @@ export function FileInput(props: FileInputProps) { {props.label} - + + {props.helperText} +
{ @@ -9,6 +10,7 @@ interface SelectInputProps { label: JSX.Element; error?: string; required?: boolean; + topRightLabel?: JSX.Element; } export function SelectInput( @@ -29,8 +31,10 @@ export function SelectInput( > {props.label} + + {props.topRightLabel} +
- ( required disabled={props.formStore.submitting} /> + + {props.adornment?.content} + {props.error && ( {props.error} diff --git a/pkgs/webview-ui/app/src/routes/flash/view.tsx b/pkgs/webview-ui/app/src/routes/flash/view.tsx index d27847f19..37618e419 100644 --- a/pkgs/webview-ui/app/src/routes/flash/view.tsx +++ b/pkgs/webview-ui/app/src/routes/flash/view.tsx @@ -1,4 +1,4 @@ -import { callApi, OperationResponse } from "@/src/api"; +import { callApi } from "@/src/api"; import { FileInput } from "@/src/components/FileInput"; import { SelectInput } from "@/src/components/SelectInput"; import { TextInput } from "@/src/components/TextInput"; @@ -10,7 +10,7 @@ import { getValue, } from "@modular-forms/solid"; import { createQuery } from "@tanstack/solid-query"; -import { createEffect, createSignal, For } from "solid-js"; +import { createEffect, createSignal, For, Show } from "solid-js"; import toast from "solid-toast"; interface Wifi extends FieldValues { @@ -97,7 +97,7 @@ export const Flash = () => { if (result.status === "error") throw new Error("Failed to fetch data"); return result.data; }, - staleTime: 1000 * 60 * 15, // 15 minutes + staleTime: Infinity, })); const langQuery = createQuery(() => ({ @@ -107,7 +107,7 @@ export const Flash = () => { if (result.status === "error") throw new Error("Failed to fetch data"); return result.data; }, - staleTime: 1000 * 60 * 15, // 15 minutes + staleTime: Infinity, })); /** @@ -136,11 +136,7 @@ export const Flash = () => { }; const handleSubmit = async (values: FlashFormValues) => { - console.log("Submit WiFi Networks:", values.wifi); - console.log( - "Submit SSH Keys:", - values.sshKeys.map((file) => file.name), - ); + console.log("Submit:", values); try { await callApi("flash_machine", { machine: { @@ -171,47 +167,57 @@ export const Flash = () => { }; return ( -
+
- - {(field, props) => ( - <> - file_download} - error={field.error} - required - /> - - )} - - - {(field, props) => ( - <> - devices} - error={field.error} - required - /> - - )} - +
+ + {(field, props) => ( + <> + { + event.preventDefault(); // Prevent the native file dialog from opening + const input = event.target; + const files = await selectSshKeys(); + + // Set the files + Object.defineProperty(input, "files", { + value: files, + writable: true, + }); + // Define the files property on the input element + const changeEvent = new Event("input", { + bubbles: true, + cancelable: true, + }); + input.dispatchEvent(changeEvent); + }} + value={field.value} + error={field.error} + helperText="Provide your SSH public key. For secure and passwordless SSH connections." + label="Authorized SSH Keys" + multiple + required + /> + + )} + +
+ {(field, props) => ( { + e.preventDefault(); + deviceQuery.refetch(); + }} + > + refresh + + } formStore={formStore} selectProps={props} label="Flash Disk" @@ -221,8 +227,9 @@ export const Flash = () => { options={ <> + {(device) => ( - - {(field, props) => ( - <> - - {(language) => } - - } - /> - - )} - - - {(field, props) => ( - <> - - {(keymap) => } - - } - /> - - )} - - - - {(field, props) => ( - <> - { - event.preventDefault(); // Prevent the native file dialog from opening - const input = event.target; - const files = await selectSshKeys(); - - // Set the files - Object.defineProperty(input, "files", { - value: files, - writable: true, - }); - // Define the files property on the input element - const changeEvent = new Event("input", { - bubbles: true, - cancelable: true, - }); - input.dispatchEvent(changeEvent); - }} - value={field.value} - error={field.error} - label="Authorized SSH Keys" - multiple - required - /> - - )} - {/* WiFi Networks */} -
+

WiFi Networks

+ Add preconfigured networks {(network, index) => ( -
+
{ label="SSID" value={field.value ?? ""} error={field.error} + class="col-span-3" required /> )} @@ -332,7 +271,7 @@ export const Flash = () => { validate={[required("Password is required")]} > {(field, props) => ( -
+
{ label="Password" value={field.value ?? ""} error={field.error} + adornment={{ + position: "end", + content: ( + + ), + }} required /> -
)} - +
+ +
)} - +
+ +
- +
+ + +
+ + {(field, props) => ( + <> + file_download + } + error={field.error} + required + /> + + )} + + + {(field, props) => ( + <> + devices} + error={field.error} + required + /> + + )} + +
+ Source URL: + + {getValue(formStore, "machine.flake") + + "#" + + getValue(formStore, "machine.devicePath")} + +
+ + {(field, props) => ( + <> + + + + {(language) => ( + + )} + + + } + /> + + )} + + + + {(field, props) => ( + <> + + + + {(keymap) => } + + + } + /> + + )} + +
+
+ +
+
+ +
);