diff --git a/admin/index.html b/admin/index.html index b86dfbf..dd1921f 100644 --- a/admin/index.html +++ b/admin/index.html @@ -231,7 +231,7 @@ // ── tiny utils ────────────────────────────────────────────────────────── const $ = (sel) => document.querySelector(sel); const fmtDate = (d) => d ? new Date(d).toLocaleString() : '—'; -const esc = (s) => String(s ?? '').replace(/&/g,'&').replace(//g,'>'); +const esc = (s) => String(s ?? '').replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"').replace(/'/g,'''); const api = { async request(method, path, body) { @@ -240,13 +240,24 @@ opts.headers['Content-Type'] = 'application/json'; opts.body = JSON.stringify(body); } - const r = await fetch(path, opts); - if (!r.ok) { - const txt = await r.text().catch(() => ''); - throw new Error(`${method} ${path} → ${r.status}: ${txt}`); + try { + const r = await fetch(path, opts); + if (r.status === 401) { + window.location.href = '/'; + return; + } + if (!r.ok) { + const txt = await r.text().catch(() => ''); + throw new Error(`${method} ${path} → ${r.status}: ${txt}`); + } + if (r.status === 204) return null; + return r.json(); + } catch (err) { + if (err.name === 'TypeError') { + throw new Error('Network error — check your connection or server availability'); + } + throw err; } - if (r.status === 204) return null; - return r.json(); }, get(path) { return this.request('GET', path); }, patch(path, body) { return this.request('PATCH', path, body); }, @@ -588,7 +599,7 @@ function renderProfiles(profiles) { if (!profiles.length) return '
No profiles.
'; let html = ''; - ['ID','Name','Description','Admin Only','Actions'].forEach(h => html += ``); + ['ID','Name','Description','Admin Only'].forEach(h => html += ``); html += ''; for (const p of profiles) { html += ` @@ -601,7 +612,6 @@ - `; } html += '
${h}${h}
${p.is_admin_only ? 'Yes' : 'No'}
'; diff --git a/webclient/src/api/index.js b/webclient/src/api/index.js index 36a49da..904c607 100644 --- a/webclient/src/api/index.js +++ b/webclient/src/api/index.js @@ -105,14 +105,3 @@ return res.json() } -// ─── Admin ───────────────────────────────────────────────────────────────── -export function getAdminUsers() { return request('GET', '/admin/users') } -export function getAdminSessions() { return request('GET', '/admin/sessions') } -export function getAdminMemory() { return request('GET', '/admin/memory') } -export function getAdminProfiles() { return request('GET', '/admin/profiles') } -export function getAdminSession(id) { return request('GET', `/admin/sessions/${id}`) } -export function deleteAdminSession(id) { return request('DELETE', `/admin/sessions/${id}`) } -export function getAdminUser(id) { return request('GET', `/admin/users/${id}`) } -export function getAdminUserSessions(id) { return request('GET', `/admin/users/${id}/sessions`) } -export function updateUserRole(id, role) { return request('PATCH', `/admin/users/${id}/role`, { role }) } -export function updateProfileAvailability(id, isAdminOnly) { return request('PATCH', `/admin/profiles/${id}/availability`, { is_admin_only: isAdminOnly }) }