diff --git a/apps/fabro-web/app/install-app.tsx b/apps/fabro-web/app/install-app.tsx index 6c390ede2..1b625ceaa 100644 --- a/apps/fabro-web/app/install-app.tsx +++ b/apps/fabro-web/app/install-app.tsx @@ -1,6 +1,18 @@ import { startTransition, useEffect, useMemo, useState } from "react"; -import type { ReactNode } from "react"; +import type { FormEvent, ReactNode } from "react"; import { Link, Navigate, useLocation, useNavigate } from "react-router"; +import { + ArrowLeftIcon, + ArrowRightIcon, + ArrowTopRightOnSquareIcon, + CheckCircleIcon, + CheckIcon, + ChevronDownIcon, + ClipboardDocumentCheckIcon, + ClipboardIcon, + EyeIcon, + EyeSlashIcon, +} from "@heroicons/react/16/solid"; import { type InstallFinishResponse, @@ -18,7 +30,6 @@ import { testInstallGithubToken, testInstallLlm, } from "./install-api"; -import { AuthLayout } from "./components/auth-layout"; import { INSTALL_PROVIDERS } from "./install-config"; import { shouldRedirectAfterHealthPoll } from "./install-flow"; import { @@ -29,12 +40,14 @@ import { const INSTALL_STEPS = [ { id: "welcome", label: "Welcome", href: "/install/welcome" }, - { id: "llm", label: "LLM", href: "/install/llm" }, { id: "server", label: "Server", href: "/install/server" }, + { id: "llm", label: "LLMs", href: "/install/llm" }, { id: "github", label: "GitHub", href: "/install/github" }, { id: "review", label: "Review", href: "/install/review" }, ] as const; +const STEPPER_STEPS = INSTALL_STEPS.slice(1); + type StepId = (typeof INSTALL_STEPS)[number]["id"]; type FinishState = InstallFinishResponse | null; type GithubStrategy = "token" | "app"; @@ -54,12 +67,7 @@ type AppForm = { allowedUsername: string; }; -type ProviderSelection = Record< - string, - { - apiKey: string; - } ->; +type ProviderSelection = Record; export default function InstallApp() { const navigate = useNavigate(); @@ -246,9 +254,9 @@ export default function InstallApp() { if (sessionState.status === "loading") { return ( - + Reading the current install state from the server. - + ); } @@ -278,11 +286,11 @@ export default function InstallApp() { ) : location.pathname === "/install/llm" ? ( { const providers = INSTALL_PROVIDERS.map(({ id }) => { const current = llmSelection[id] ?? { apiKey: "" }; @@ -306,7 +314,7 @@ export default function InstallApp() { await putInstallLlm(installToken, providers); const nextSession = await getInstallSession(installToken); setSessionState({ status: "ready", data: nextSession }); - navigate("/install/server"); + navigate("/install/github"); } catch (error) { setSaveError( error instanceof Error ? error.message : "Failed to save LLM settings.", @@ -320,11 +328,11 @@ export default function InstallApp() { ) : location.pathname === "/install/server" ? ( { if (!canonicalUrl.trim()) { setSaveError("Enter the canonical server URL before continuing."); @@ -336,7 +344,7 @@ export default function InstallApp() { await putInstallServer(installToken, canonicalUrl.trim()); const nextSession = await getInstallSession(installToken); setSessionState({ status: "ready", data: nextSession }); - navigate("/install/github"); + navigate("/install/llm"); } catch (error) { setSaveError( error instanceof Error ? error.message : "Failed to save server settings.", @@ -348,13 +356,17 @@ export default function InstallApp() { > setCanonicalUrl(event.target.value)} className={INPUT_CLASS} placeholder="https://fabro.example.com" + autoComplete="url" + spellCheck={false} /> @@ -362,12 +374,12 @@ export default function InstallApp() { ) : location.pathname === "/install/github" ? ( { setSubmitting(true); setSaveError(null); @@ -421,29 +433,43 @@ export default function InstallApp() { > {githubStrategy === "token" ? ( - <> - -