From 01302a775c5113ecff38767affabae5fc9648779 Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Sat, 9 May 2026 17:52:44 +0200 Subject: [PATCH] feat: require explicit confirmation when JMAP probe finds no session --- app/setup/page.tsx | 98 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 87 insertions(+), 11 deletions(-) diff --git a/app/setup/page.tsx b/app/setup/page.tsx index 52952cab..7d7938a3 100644 --- a/app/setup/page.tsx +++ b/app/setup/page.tsx @@ -473,14 +473,21 @@ function StepContent({ stepIndex, config, setConfig, onNext, onBack, onFinish }: // ─── Server step ───────────────────────────────────────────────────────── +type ProbeStatus = 'jmap_detected' | 'reachable_no_jmap' | 'unreachable' | 'invalid_url'; + function ServerStep({ config, setConfig, onNext }: Pick) { const [submitting, setSubmitting] = useState(false); - const [probe, setProbe] = useState(null); + const [probe, setProbe] = useState<{ status: ProbeStatus; message: string; url: string } | null>(null); const [probing, setProbing] = useState(false); + // When the server is reachable but isn't a JMAP endpoint, the wizard + // shows a "looks wrong, are you sure?" inline confirmation. The flag + // resets every time the URL changes. + const [confirmedNonJmap, setConfirmedNonJmap] = useState(false); - async function testJmap() { + async function testJmap(): Promise<{ status: ProbeStatus; message: string; url: string } | null> { setProbe(null); setProbing(true); + setConfirmedNonJmap(false); try { const res = await apiFetch('/api/setup/test-jmap', { method: 'POST', @@ -488,15 +495,22 @@ function ServerStep({ config, setConfig, onNext }: Pick setConfig({ ...config, jmapServerUrl: v })} + onChange={(v) => { + setConfig({ ...config, jmapServerUrl: v }); + // Any URL change invalidates the previous probe result. + if (probe && probe.url !== v) { + setProbe(null); + setConfirmedNonJmap(false); + } + }} required placeholder="https://" type="url" /> - {probe &&

{probe}

} + {probe && probe.url === config.jmapServerUrl && ( + probe.status === 'reachable_no_jmap' ? ( +
+

{probe.message}

+

+ This is OK if a reverse proxy routes JMAP traffic separately (e.g. webmail and mail server share a domain), but more often it means the URL is wrong. +

+ +
+ ) : probe.status === 'jmap_detected' ? ( +

✓ {probe.message}

+ ) : ( +

{probe.message}

+ ) + )} {/* Additional servers (optional) */} @@ -682,8 +745,21 @@ function ServerStep({ config, setConfig, onNext }: Pick