feat(admin): visible Test/Test-seed badges + filter toggle
Users table shows [Test] next to soak-harness accounts, invite codes list shows [Test-seed] next to codes that flag new accounts as test, and a new "Include test accounts" checkbox lets admins hide bot traffic from the user list. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -67,12 +67,13 @@ async function getStats() {
|
||||
return apiRequest('/api/admin/stats');
|
||||
}
|
||||
|
||||
async function getUsers(query = '', offset = 0, includeBanned = true) {
|
||||
async function getUsers(query = '', offset = 0, includeBanned = true, includeTest = true) {
|
||||
const params = new URLSearchParams({
|
||||
query,
|
||||
offset,
|
||||
limit: PAGE_SIZE,
|
||||
include_banned: includeBanned,
|
||||
include_test: includeTest,
|
||||
});
|
||||
return apiRequest(`/api/admin/users?${params}`);
|
||||
}
|
||||
@@ -306,15 +307,19 @@ async function loadUsers() {
|
||||
try {
|
||||
const query = document.getElementById('user-search').value;
|
||||
const includeBanned = document.getElementById('include-banned').checked;
|
||||
const data = await getUsers(query, usersPage * PAGE_SIZE, includeBanned);
|
||||
const includeTest = document.getElementById('include-test').checked;
|
||||
const data = await getUsers(query, usersPage * PAGE_SIZE, includeBanned, includeTest);
|
||||
|
||||
const tbody = document.querySelector('#users-table tbody');
|
||||
tbody.innerHTML = '';
|
||||
|
||||
data.users.forEach(user => {
|
||||
const testBadge = user.is_test_account
|
||||
? ' <span class="badge badge-info" title="Soak harness test account">Test</span>'
|
||||
: '';
|
||||
tbody.innerHTML += `
|
||||
<tr>
|
||||
<td>${escapeHtml(user.username)}</td>
|
||||
<td>${escapeHtml(user.username)}${testBadge}</td>
|
||||
<td>${escapeHtml(user.email || '-')}</td>
|
||||
<td><span class="badge badge-${user.role === 'admin' ? 'info' : 'muted'}">${user.role}</span></td>
|
||||
<td>${getStatusBadge(user)}</td>
|
||||
@@ -447,10 +452,13 @@ async function loadInvites() {
|
||||
: invite.remaining_uses <= 0
|
||||
? '<span class="badge badge-warning">Used Up</span>'
|
||||
: '<span class="badge badge-success">Active</span>';
|
||||
const testSeedBadge = invite.marks_as_test
|
||||
? ' <span class="badge badge-info" title="Creates test accounts">Test-seed</span>'
|
||||
: '';
|
||||
|
||||
tbody.innerHTML += `
|
||||
<tr>
|
||||
<td><code>${escapeHtml(invite.code)}</code></td>
|
||||
<td><code>${escapeHtml(invite.code)}</code>${testSeedBadge}</td>
|
||||
<td>${invite.use_count} / ${invite.max_uses}</td>
|
||||
<td>${invite.remaining_uses}</td>
|
||||
<td>${escapeHtml(invite.created_by_username)}</td>
|
||||
@@ -827,6 +835,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
usersPage = 0;
|
||||
loadUsers();
|
||||
});
|
||||
document.getElementById('include-test').addEventListener('change', () => {
|
||||
usersPage = 0;
|
||||
loadUsers();
|
||||
});
|
||||
document.getElementById('users-prev').addEventListener('click', () => {
|
||||
if (usersPage > 0) {
|
||||
usersPage--;
|
||||
|
||||
Reference in New Issue
Block a user