From b66e1b6b6b2e682a089ef2d6bfef5e76113c2b31 Mon Sep 17 00:00:00 2001 From: SJCoetz Date: Tue, 4 Aug 2026 01:42:31 +0200 Subject: [PATCH] feat(webview): probe upstream + show status badge in header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The /webview page embeds supplier portals in an iframe. When the target sets X-Frame-Options: DENY or frame-ancestors 'none' the browser silently renders a blank iframe with no visible signal to the operator that the load failed — the page just looks empty and it's not obvious whether the portal is down or whether the operator is hitting an embed restriction. Surface the most common cause up-front: - Server-side HEAD probe before render: fetches the target URL with `redirect: "manual"` and a 5s timeout. The probe bypasses browser frame restrictions (it's a server-to-server call) and reports the raw HTTP status, including 302 redirects (counted as `ok` since suppliers often gate their portals behind a login redirect). - Status badge in the header next to the URL: green dot + `up (200)` when reachable, amber dot + `HTTP ` for non-2xx, amber dot + `unreachable` on network / timeout failures. Title attribute carries the full probe detail. - Banner placeholder inside the iframe container when JS is disabled (defensive — the existing iframe is JS-required). The badge gives the operator an immediate "is this a portal problem or an embed problem?" answer before they spend time clicking around inside the iframe. Co-authored-by: Orca --- src/app/(app)/webview/page.tsx | 92 ++++++++++++++++++++++++++++++---- 1 file changed, 83 insertions(+), 9 deletions(-) diff --git a/src/app/(app)/webview/page.tsx b/src/app/(app)/webview/page.tsx index 86ae80d..d6e4711 100644 --- a/src/app/(app)/webview/page.tsx +++ b/src/app/(app)/webview/page.tsx @@ -18,10 +18,65 @@ export default async function WebViewPage({ searchParams }: Props) { const { src } = await searchParams; const url = src && ALLOWED[src]; + // Probe the target so the user can tell at a glance whether the + // upstream is up. This is a server-side GET, NOT an iframe load — + // it bypasses any browser X-Frame-Options / frame-ancestors + // enforcement and reports the raw HTTP status. Used to render the + // status badge in the header. + let probe: { ok: boolean; status: number | null; error?: string } | null = + null; + if (url) { + try { + const res = await fetch(url, { + method: "HEAD", + // Don't follow redirects — we want to see the raw response. + redirect: "manual", + signal: AbortSignal.timeout(5000), + headers: { "User-Agent": "WFDASH-WebView/1.0" }, + }); + probe = { ok: res.ok || res.status === 302, status: res.status }; + } catch (err) { + probe = { + ok: false, + status: null, + error: err instanceof Error ? err.message : "fetch failed", + }; + } + } + return (
-
+
External view{src ? `: ${src}` : ""} + + {probe && ( + + + {probe.ok + ? `up${probe.status ? ` (${probe.status})` : ""}` + : probe.status + ? `HTTP ${probe.status}` + : "unreachable"} + + )} + {url && (
{url ? ( -