'use strict'; const $ = (id) => document.getElementById(id); let me = null; const esc = (s) => String(s == null ? '' : s).replace(/[&<>"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c])); function when(iso) { if (!iso) return 'never'; // Timestamps are stored as naive UTC, so say so before parsing. const d = new Date(/[Zz+]|\d-\d\d:\d\d$/.test(iso) ? iso : iso + 'Z'); return esc(d.toLocaleString()); } function statusPill(u) { if (!u.is_active) return 'disabled'; if (!u.verified) return 'unconfirmed'; return 'active'; } function actions(u) { const out = []; if (!u.verified) out.push(``); if (u.signed_in) out.push(``); if (u.is_active) { // Disabling yourself would lock you out of this page immediately. if (!me || u.id !== me.id) { out.push(``); } } else { out.push(``); } return out.join(''); } async function load() { const res = await A.api('/api/admin/users'); if (res.status === 403) { location.replace('/'); return; } const data = await res.json(); $('summary').textContent = `${data.users.length} account${data.users.length === 1 ? '' : 's'}, ` + `${data.sessions} live session${data.sessions === 1 ? '' : 's'}, ` + `${data.workspaces} workspace${data.workspaces === 1 ? '' : 's'} in memory`; $('rows').innerHTML = data.users.map((u) => ` ${esc(u.email)} ${esc(u.name) || ''} ${statusPill(u)} ${u.is_admin ? 'admin' : 'member'} ${when(u.last_login_at)}
${actions(u)}
`).join(''); } $('rows').addEventListener('click', async (ev) => { const btn = ev.target.closest('button[data-act]'); if (!btn) return; A.busy(btn, true, '…'); try { const r = await A.postJSON(`/api/admin/users/${btn.dataset.id}/${btn.dataset.act}`, {}); A.msg($('note'), r.message, 'ok'); await load(); } catch (err) { A.msg($('note'), String(err.message || err), 'err'); A.busy(btn, false); } }); $('signout').addEventListener('click', async () => { await fetch('/api/auth/logout', { method: 'POST' }); location.replace('/login'); }); (async () => { const res = await A.api('/api/auth/me'); me = (await res.json()).user; await load(); })().catch((err) => A.msg($('note'), String(err.message || err), 'err'));