diff --git a/dashboard/static/index.html b/dashboard/static/index.html index c50fa8f..ddf65b7 100644 --- a/dashboard/static/index.html +++ b/dashboard/static/index.html @@ -4,6 +4,7 @@ SNEK Dashboard + @@ -18,7 +19,32 @@ -
+ + + + +
@@ -78,20 +104,40 @@ const TOKEN_KEY = 'snek_dashboard_token'; let token = localStorage.getItem(TOKEN_KEY) || ''; async function ensureToken() { - // Probe if the server requires a token const probe = await fetch('/api/devices', { headers: authHeaders() }); if (probe.ok) return; if (probe.status !== 401) return; - while (true) { - const t = window.prompt('Access token'); - if (t === null) return; - const r = await fetch('/api/devices', { headers: { Authorization: 'Bearer ' + t } }); - if (r.ok) { - token = t.trim(); - localStorage.setItem(TOKEN_KEY, token); - return; - } - } + + const overlay = document.getElementById('login-overlay'); + const form = document.getElementById('login-form'); + const input = document.getElementById('login-token'); + const error = document.getElementById('login-error'); + const app = document.getElementById('app'); + + overlay.className = 'fixed inset-0 bg-slate-100 z-50 flex items-center justify-center px-4'; + app.classList.add('hidden'); + input.focus(); + + return new Promise((resolve) => { + form.addEventListener('submit', async (e) => { + e.preventDefault(); + const t = input.value.trim(); + error.classList.add('hidden'); + const r = await fetch('/api/devices', { headers: { Authorization: 'Bearer ' + t } }); + if (r.ok) { + token = t; + localStorage.setItem(TOKEN_KEY, token); + overlay.className = 'hidden'; + app.classList.remove('hidden'); + resolve(); + } else { + error.textContent = 'Invalid token. Please try again.'; + error.classList.remove('hidden'); + input.value = ''; + input.focus(); + } + }); + }); } function authHeaders() {