41 lines
1.7 KiB
JavaScript
41 lines
1.7 KiB
JavaScript
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) => `<div class="account-row"><div><strong>${escapeHtml(user.username)}</strong><span>${escapeHtml(user.role.replace('_', ' '))}</span></div><span class="account-permission">${user.can_data_tools ? 'Export, backup, restore' : 'Inventory access only'}</span></div>`).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));
|