← back to Ventura Claw
server/public/admin-users.html
66 lines
<!doctype html>
<html lang="en"><head>
<meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Users — VenturaClaw</title>
<link rel="stylesheet" href="/static/style.css" />
</head><body>
<div class="bg-orb orb-1"></div><div class="bg-orb orb-2"></div><div class="bg-orb orb-3"></div>
<header class="topbar glass">
<div class="brand"><div class="logo-dot"></div><div><div class="brand-name">VenturaClaw</div><div class="brand-sub">USERS</div></div></div>
<nav class="nav">
<a href="/admin">Dashboard</a><a class="active" href="/admin/users">Users</a><a href="/admin/connectors">Connectors</a>
<a href="/admin/approvals">Approvals</a><a href="/admin/audit">Audit</a><a href="/chat">Chat</a>
<a href="#" id="logout">Sign out</a>
</nav>
</header>
<main style="padding:0 14px 14px;display:flex;flex-direction:column;gap:14px">
<div class="glass" style="padding:18px">
<div style="display:flex;justify-content:space-between;align-items:baseline;margin-bottom:12px">
<div class="brand-sub">TEAM</div>
<button class="btn" id="add-user">+ Add user</button>
</div>
<table><thead><tr><th>Email</th><th>Name</th><th>Role</th><th></th></tr></thead><tbody id="rows"></tbody></table>
</div>
<div class="glass" style="padding:18px;display:none" id="form-card">
<div class="brand-sub" style="margin-bottom:12px">NEW USER</div>
<form id="f" style="display:grid;gap:10px;grid-template-columns:1fr 1fr 1fr 120px;align-items:end">
<input id="email" placeholder="email" required />
<input id="name" placeholder="name" />
<input id="password" placeholder="password" required />
<select id="role"><option value="user">user</option><option value="admin">admin</option></select>
<button type="submit" class="btn" style="grid-column:1/-1;justify-content:center">Create user</button>
</form>
</div>
</main>
<div class="footer">VenturaClaw</div>
<script>
async function refresh() {
const d = await (await fetch('/api/admin/users')).json();
document.getElementById('rows').innerHTML = d.users.map(u => `
<tr><td>${u.email}</td><td>${u.name||''}</td>
<td><span class="badge badge-${u.role}">${u.role}</span></td>
<td style="text-align:right"><button class="btn btn-ghost" data-del="${u.id}">Delete</button></td></tr>`).join('');
document.querySelectorAll('[data-del]').forEach(b => b.addEventListener('click', async () => {
if (!confirm('Delete user?')) return;
await fetch('/api/admin/users/' + b.dataset.del, { method: 'DELETE' });
refresh();
}));
}
document.getElementById('add-user').addEventListener('click', () => {
document.getElementById('form-card').style.display = 'block';
});
document.getElementById('f').addEventListener('submit', async e => {
e.preventDefault();
const r = await fetch('/api/admin/users', { method: 'POST', headers: {'content-type':'application/json'},
body: JSON.stringify({ email: email.value, name: name.value, password: password.value, role: role.value })});
if (r.ok) { e.target.reset(); document.getElementById('form-card').style.display='none'; refresh(); }
else alert((await r.json()).error || 'failed');
});
refresh();
document.getElementById('logout').addEventListener('click', async e => {
e.preventDefault(); await fetch('/api/auth/logout', { method: 'POST' }); location.href = '/login';
});
</script>
</body></html>