import { AnimatePresence, motion } from "framer-motion"; import { AlertCircle, CheckCircle, Cloud, Loader, Lock, LockOpen, Wifi, WifiOff, } from "lucide-react"; import { useState } from "react"; import { Button } from "@/components/ui/button"; import { Input, Textarea } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Muted } from "@/components/ui/typography"; import { useInstances } from "@/hooks/useInstances"; import { checkConnection, type HealthStatus, HONCHO_CLOUD_URL, type Instance, instanceSchema, isCloudInstance, } from "@/lib/config"; import { COLOR } from "@/lib/constants"; export type ConnectionPreset = "cloud" | "self-hosted"; interface SettingsFormProps { /** Instance to edit; pass `null` to create a new one. */ instance: Instance | null; /** Whether this form is for a Cloud or Self-Hosted connection. Inferred from `instance` in edit mode. */ preset?: ConnectionPreset; /** Called after a successful save. Receives the saved instance id. */ onSaved?: (id: string) => void; /** Called when the user cancels (only meaningful when there's something to cancel back to). */ onCancel?: () => void; /** Hide the cancel button. */ hideCancel?: boolean; /** Override the submit button label. */ submitLabel?: string; } const statusConfig = { ok: { icon: CheckCircle, color: COLOR.success, label: "Connected" }, "auth-required": { icon: AlertCircle, color: COLOR.warning, label: "Auth required" }, unreachable: { icon: WifiOff, color: COLOR.destructive, label: "Unreachable" }, checking: { icon: Loader, color: COLOR.accentText, label: "Checking..." }, }; export function SettingsForm({ instance, preset, onSaved, onCancel, hideCancel, submitLabel, }: SettingsFormProps) { const { add, update, activate } = useInstances(); const resolvedPreset: ConnectionPreset = preset ?? (instance && isCloudInstance(instance) ? "cloud" : "self-hosted"); const isCloud = resolvedPreset === "cloud"; const initialName = instance?.name ?? (isCloud ? "Honcho Cloud" : ""); const initialBaseUrl = isCloud ? HONCHO_CLOUD_URL : (instance?.baseUrl ?? "http://localhost:8000"); const [name, setName] = useState(initialName); const [baseUrl, setBaseUrl] = useState(initialBaseUrl); const [token, setToken] = useState(instance?.token ?? ""); const [errors, setErrors] = useState>>({}); const [saved, setSaved] = useState(false); const [health, setHealth] = useState<{ status: HealthStatus; message: string } | null>(null); const [checking, setChecking] = useState(false); const isCreate = instance === null; async function handleTest() { setChecking(true); setHealth({ status: "checking", message: "Connecting..." }); const result = await checkConnection(baseUrl, token || undefined); setHealth(result); setChecking(false); if (result.status === "auth-required" && !token) { document.getElementById("honcho-token")?.focus(); } } function handleSubmit(e: React.SyntheticEvent) { e.preventDefault(); const candidate = { id: instance?.id ?? "placeholder", name: name.trim() || (isCloud ? "Honcho Cloud" : "Default"), baseUrl: isCloud ? HONCHO_CLOUD_URL : baseUrl, token, }; const result = instanceSchema.safeParse(candidate); if (!result.success) { const fieldErrors: typeof errors = {}; for (const issue of result.error.issues) { const key = issue.path[0] as keyof Instance; fieldErrors[key] = issue.message; } setErrors(fieldErrors); return; } if (isCloud && !token.trim()) { setErrors({ token: "API key is required for Honcho Cloud" }); return; } setErrors({}); let id: string; if (isCreate) { const created = add({ name: result.data.name, baseUrl: result.data.baseUrl, token: result.data.token, }); activate(created.id); id = created.id; } else { update(instance.id, { name: result.data.name, baseUrl: result.data.baseUrl, token: result.data.token, }); id = instance.id; } setSaved(true); setTimeout(() => { setSaved(false); onSaved?.(id); }, 600); } const StatusIcon = health ? statusConfig[health.status].icon : null; return (
{/* Name */}
setName(e.target.value)} placeholder="e.g. Local, Staging, Production" className="rounded-xl" /> {errors.name && (

{errors.name}

)} A short label to identify this connection
{/* Base URL */}
{isCloud ? (
{HONCHO_CLOUD_URL}
) : ( { setBaseUrl(e.target.value); setHealth(null); }} placeholder="http://localhost:8000" className="flex-1 font-mono rounded-xl" /> )}
{errors.baseUrl && !isCloud && (

{errors.baseUrl}

)} {isCloud ? "Hosted Honcho service — endpoint is fixed" : "URL of your self-hosted Honcho instance"}
{/* Health status */} {health && (
{StatusIcon && ( )}

{statusConfig[health.status].label}

{health.message}
)}
{/* Token */}