import { useState } from "react"; import { useNavigate } from "react-router"; import { AuthLayout } from "../components/auth-layout"; import { ErrorMessage, INPUT_CLASS, PRIMARY_BUTTON_CLASS, } from "../components/ui"; import { useLoginDevToken } from "../lib/mutations"; import { useAuthConfig } from "../lib/queries"; export default function AuthLogin() { const { data: authConfig } = useAuthConfig(); const loginDevToken = useLoginDevToken(); const methods = authConfig?.methods ?? []; const hasDevToken = methods.includes("dev-token"); const hasGitHub = methods.includes("github"); const navigate = useNavigate(); const [token, setToken] = useState(""); const [error, setError] = useState(null); async function handleSubmit(event: React.FormEvent) { event.preventDefault(); setError(null); try { await loginDevToken.trigger({ token }); navigate("/runs"); } catch { setError("Invalid dev token."); } } return (

Sign in to Fabro

{hasGitHub ? "Authenticate with your GitHub account to continue." : hasDevToken ? "Paste your dev token to continue." : "No authentication method is configured on this server."}

{hasGitHub ? ( Sign in with GitHub ) : null} {hasDevToken && hasGitHub ? ( ) : hasDevToken ? ( ) : null}
); } function DevTokenForm({ token, setToken, error, onSubmit, showLocation = false, }: { token: string; setToken: (v: string) => void; error: string | null; onSubmit: (e: React.FormEvent) => void; showLocation?: boolean; }) { return (
setToken(event.target.value)} placeholder="fabro_dev_…" className={`${INPUT_CLASS} font-mono`} autoComplete="off" autoCapitalize="off" spellCheck={false} />
{error ? : null} {showLocation ? (

Paste the dev token from your server terminal or install output.

) : null} ); } function DevTokenCollapsible({ token, setToken, error, onSubmit, }: { token: string; setToken: (v: string) => void; error: string | null; onSubmit: (e: React.FormEvent) => void; }) { const [open, setOpen] = useState(false); return (
{open ? (
) : null}
); } function GitHubMark() { return ( ); }