From 481a44c15a3151bf8a6a93a5439c632f4795df52 Mon Sep 17 00:00:00 2001 From: ScreenTinker Date: Mon, 10 Aug 2026 21:25:35 -0500 Subject: [PATCH] SSO settings: show a verification outcome once, not twice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First real-browser pass over this feature. Chrome via puppeteer-core, driving the actual settings page: login, the SSO card, and a real click on Verify. The click path works — the loadSso fix holds, no ReferenceError, and a failure shows the specific DNS answer ("no _screentinker-verify record found ... DNS can take a few minutes") rather than the generic catch-all. But the outcome was rendered TWICE: the server persists last_error on the row and the template drew it, while the click handler wrote the same sentence into a second element underneath. Anyone retrying a failed verification saw the identical line twice, in two different colours. One element now owns the outcome, and the handler replaces its text. Also colours the in-flight "Checking DNS…" as muted rather than leaving it red. Found by looking at a screenshot. Parsing, VM rendering and mutation testing all passed over it — none of them draws anything. 18/18 browser checks, 1598 unit tests. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Bvjey4FNam49MN7ybjcq6A --- frontend/js/views/settings.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/frontend/js/views/settings.js b/frontend/js/views/settings.js index ef1bdce..b552cee 100644 --- a/frontend/js/views/settings.js +++ b/frontend/js/views/settings.js @@ -743,8 +743,12 @@ export async function render(container) { ${d.verified ? '' : `
${esc(t('sso.dns_instructions'))}
${esc(d.record_name)} TXT ${esc(d.txt_value)} - ${d.last_error ? `
${esc(d.last_error)}
` : ''}`} -
+`} + +
${d.verified ? '' : esc(d.last_error || '')}
`).join('')} ` : ''} @@ -797,7 +801,7 @@ export async function render(container) { // `a-b-test`, and getElementById would put one domain's answer in the other's box. const out = document.getElementById(`ssoVerify-${id}-${btn.dataset.di}`); btn.disabled = true; - if (out) out.textContent = t('sso.verifying'); + if (out) { out.style.color = 'var(--text-muted)'; out.textContent = t('sso.verifying'); } try { const res = await fetch(`/api/organizations/${orgId}/sso/${id}/domains/${encodeURIComponent(domain)}/verify`, { method: 'POST', @@ -816,9 +820,9 @@ export async function render(container) { await loadSso(); return; } - if (out) out.textContent = body.error || t('sso.verify_failed'); + if (out) { out.style.color = 'var(--danger,#b91c1c)'; out.textContent = body.error || t('sso.verify_failed'); } } catch { - if (out) out.textContent = t('sso.verify_failed'); + if (out) { out.style.color = 'var(--danger,#b91c1c)'; out.textContent = t('sso.verify_failed'); } } finally { btn.disabled = false; }