import { useEffect, useState } from "react"; import { api, type IntegrationField, type IntegrationType } from "../api/client"; const TYPE_LABELS: Record = { tailscale: "Tailscale", proxmox: "Proxmox", synology: "Synology", semaphore: "Semaphore", gitea: "Gitea", dockhand: "Dockhand", }; export default function IntegrationForm({ onCreated, onCancel }: { onCreated: () => void; onCancel: () => void }) { const [allFields, setAllFields] = useState> | null>(null); const [type, setType] = useState(null); const [name, setName] = useState(""); const [values, setValues] = useState>({}); const [testResult, setTestResult] = useState<{ ok: boolean; latencyMs?: number; error?: string } | null>(null); const [testing, setTesting] = useState(false); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); useEffect(() => { api.integrations.fields().then((res) => { setAllFields(res.fields); const firstType = Object.keys(res.fields)[0] as IntegrationType | undefined; if (firstType) setType(firstType); }); }, []); useEffect(() => { setValues({}); setTestResult(null); }, [type]); const availableTypes = allFields ? (Object.keys(allFields) as IntegrationType[]) : []; const fields = (type && allFields?.[type]) ?? []; function setField(key: string, value: string | boolean) { setValues((v) => ({ ...v, [key]: value })); } async function testConnection() { if (!type) return; setTesting(true); setTestResult(null); try { const result = await api.integrations.test({ type, config: values }); setTestResult(result); } catch (err) { setTestResult({ ok: false, error: err instanceof Error ? err.message : String(err) }); } finally { setTesting(false); } } async function submit(e: React.FormEvent) { e.preventDefault(); if (!type) return; setError(null); setSaving(true); try { await api.integrations.create({ type, name, config: values }); onCreated(); } catch (err) { setError(err instanceof Error ? err.message : String(err)); } finally { setSaving(false); } } if (allFields && availableTypes.length === 0) { return (
No integration types are implemented yet.
); } return (

Add an integration

{error && (
{error}
)}
setName(e.target.value)} />
{fields.map((field) => (
{field.type === "checkbox" ? ( ) : ( <> setField(field.key, e.target.value)} /> )}
))} {testResult && (
{testResult.ok ? (
Connection OK{testResult.latencyMs !== undefined ? ` (${testResult.latencyMs}ms)` : ""}.
) : (
Connection failed: {testResult.error}
)}
)}
); }