const $ = (selector) => document.querySelector(selector); async function request(url, options = {}) { const response = await fetch(url, { headers: { 'Content-Type': 'application/json' }, ...options }); const data = await response.json(); if (!response.ok) throw new Error(data.error || 'Something went wrong.'); return data; } function escapeHtml(value) { return String(value).replace(/[&<>'"]/g, (character) => ({ '&': '&', '<': '<', '>': '>', "'": ''', '"': '"' }[character])); } function toast(message) { const element = $('#toast'); element.textContent = message; element.classList.add('show'); setTimeout(() => element.classList.remove('show'), 2500); } async function loadUsers() { const users = await request('/api/users'); $('#userCount').textContent = `${users.length} ${users.length === 1 ? 'user' : 'users'}`; $('#usersList').innerHTML = users.map((user) => `
${escapeHtml(user.username)}${escapeHtml(user.role.replace('_', ' '))}
${user.can_data_tools ? 'Export, backup, restore' : 'Inventory access only'}
`).join(''); } $('#userForm').addEventListener('submit', async (event) => { event.preventDefault(); const form = new FormData(event.target); try { await request('/api/users', { method: 'POST', body: JSON.stringify({ username: form.get('username'), password: form.get('password'), role: form.get('role'), can_data_tools: form.get('can_data_tools') === 'on' }) }); event.target.reset(); await loadUsers(); toast('User added.'); } catch (error) { toast(error.message); } }); loadUsers().catch((error) => toast(error.message));