← 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>