Skip to content

Commit 927f1e2

Browse files
JakeSCahillclaude
andcommitted
account: surface docs login errors (login_error) with a dismissible banner
The OAuth callback bounces a failed sign-in back to the page with ?login_error=<code> (upstream_failed / work_email_required / state_mismatch), but nothing displayed it — the user just saw a bare query param. Show a dismissible role="alert" banner with a friendly message per code, then strip the param from the URL so a refresh/re-click doesn't repeat it. Co-Authored-By: Claude Opus 4.8 <[email protected]>
1 parent cfe999e commit 927f1e2

1 file changed

Lines changed: 42 additions & 0 deletions

File tree

src/js/26-docs-account.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,48 @@
214214

215215
render()
216216

217+
// Surface a login failure bounced back by the OAuth callback (docs-login.mjs /
218+
// mcp-oauth.mjs redirect to ?login_error=<code>), then strip the param so a
219+
// refresh or a re-click of sign-in doesn't repeat the message.
220+
function showLoginError () {
221+
var params
222+
try { params = new URLSearchParams(window.location.search) } catch (e) { return }
223+
var code = params.get('login_error')
224+
if (!code) return
225+
var MESSAGES = {
226+
upstream_failed: 'Sorry, sign-in couldn’t be completed. Please try again.',
227+
work_email_required: 'Please sign in with your work Redpanda Cloud account.',
228+
state_mismatch: 'Your sign-in link expired. Please try again.',
229+
}
230+
var bar = document.createElement('div')
231+
bar.setAttribute('role', 'alert')
232+
bar.style.cssText = [
233+
'position:fixed;top:0;left:0;right:0;z-index:1000',
234+
'display:flex;align-items:center;justify-content:center;gap:12px',
235+
'padding:10px 16px;background:#fdecea;color:#611a15',
236+
'border-bottom:1px solid #f5c6cb',
237+
'font:14px/1.4 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif',
238+
].join(';')
239+
var text = document.createElement('span')
240+
text.textContent = MESSAGES[code] || 'Sorry, sign-in couldn’t be completed. Please try again.'
241+
var close = document.createElement('button')
242+
close.type = 'button'
243+
close.setAttribute('aria-label', 'Dismiss')
244+
close.textContent = '×'
245+
close.style.cssText = 'background:none;border:0;font-size:18px;line-height:1;cursor:pointer;color:inherit'
246+
close.addEventListener('click', function () { bar.remove() })
247+
bar.appendChild(text)
248+
bar.appendChild(close)
249+
document.body.appendChild(bar)
250+
251+
params.delete('login_error')
252+
var qs = params.toString()
253+
try {
254+
window.history.replaceState({}, '', window.location.pathname + (qs ? '?' + qs : '') + window.location.hash)
255+
} catch (e) { /* ignore */ }
256+
}
257+
showLoginError()
258+
217259
// The Ask AI panel's session probe may learn the identity first — reuse it
218260
window.addEventListener('kapa-session', function (e) {
219261
if (e.detail && e.detail.authenticated && e.detail.user) {

0 commit comments

Comments
 (0)