ui: move activate/inactivate/delete to user list table actions column
- New actions column (right of state) with inline buttons per row - Manage form keeps save user + clear only (no duplicate action buttons) - Themed to match admin dialog: JetBrains Mono, uppercase, square borders - Delete uses danger styling
This commit is contained in:
+63
-5
@@ -831,6 +831,38 @@ body {
|
|||||||
letter-spacing: 0.06em;
|
letter-spacing: 0.06em;
|
||||||
color: var(--ink-dim);
|
color: var(--ink-dim);
|
||||||
}
|
}
|
||||||
|
.user-list-table .user-actions-cell {
|
||||||
|
white-space: nowrap;
|
||||||
|
display: flex;
|
||||||
|
gap: 0.3rem;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
.user-list-table .user-actions-cell button {
|
||||||
|
font-family: var(--font);
|
||||||
|
font-size: 0.55rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.06em;
|
||||||
|
padding: 0.2rem 0.4rem;
|
||||||
|
min-height: 1.7rem;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid var(--border-light);
|
||||||
|
background: var(--input-bg);
|
||||||
|
color: var(--ink);
|
||||||
|
border-radius: 0;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
.user-list-table .user-actions-cell button:hover {
|
||||||
|
background: var(--hover);
|
||||||
|
border-color: var(--accent);
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
.user-list-table .user-actions-cell button.danger {
|
||||||
|
color: var(--danger);
|
||||||
|
}
|
||||||
|
.user-list-table .user-actions-cell button.danger:hover {
|
||||||
|
border-color: var(--danger);
|
||||||
|
color: var(--danger);
|
||||||
|
}
|
||||||
.user-state-active { color: var(--accent3); }
|
.user-state-active { color: var(--accent3); }
|
||||||
.user-state-inactive { color: var(--danger); }
|
.user-state-inactive { color: var(--danger); }
|
||||||
/* OAuth client list — compact, matches user table density */
|
/* OAuth client list — compact, matches user table density */
|
||||||
@@ -1384,9 +1416,6 @@ body {
|
|||||||
<input type="password" id="admin-password" placeholder="required for new users; leave blank to keep unchanged" autocomplete="new-password">
|
<input type="password" id="admin-password" placeholder="required for new users; leave blank to keep unchanged" autocomplete="new-password">
|
||||||
<div class="manage-user-actions">
|
<div class="manage-user-actions">
|
||||||
<button class="primary" type="button" onclick="saveManagedUser()">save user</button>
|
<button class="primary" type="button" onclick="saveManagedUser()">save user</button>
|
||||||
<button type="button" onclick="setManagedUserActive(false)">inactivate</button>
|
|
||||||
<button type="button" onclick="setManagedUserActive(true)">activate</button>
|
|
||||||
<button type="button" onclick="deleteManagedUser()">delete</button>
|
|
||||||
<button type="button" onclick="clearManageUserForm()">clear</button>
|
<button type="button" onclick="clearManageUserForm()">clear</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1714,14 +1743,20 @@ function renderUserList() {
|
|||||||
el.innerHTML = '<div class="empty-state">no users</div>';
|
el.innerHTML = '<div class="empty-state">no users</div>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
el.innerHTML = `<table class="user-list-table"><thead><tr><th>user id</th><th>name</th><th>role</th><th>state</th></tr></thead><tbody>${
|
el.innerHTML = `<table class="user-list-table"><thead><tr><th>user id</th><th>name</th><th>role</th><th>state</th><th style="text-align:right">actions</th></tr></thead><tbody>${
|
||||||
state.users.map(u => {
|
state.users.map(u => {
|
||||||
const active = u.active !== false;
|
const active = u.active !== false;
|
||||||
|
const uid = escapeHtml(u.user_id || '');
|
||||||
return `<tr>
|
return `<tr>
|
||||||
<td class="user-id">${escapeHtml(u.user_id || '')}</td>
|
<td class="user-id">${uid}</td>
|
||||||
<td>${escapeHtml(u.display_name || '')}</td>
|
<td>${escapeHtml(u.display_name || '')}</td>
|
||||||
<td>${escapeHtml(u.role || '')}</td>
|
<td>${escapeHtml(u.role || '')}</td>
|
||||||
<td class="${active ? 'user-state-active' : 'user-state-inactive'}">${active ? 'active' : 'inactive'}</td>
|
<td class="${active ? 'user-state-active' : 'user-state-inactive'}">${active ? 'active' : 'inactive'}</td>
|
||||||
|
<td class="user-actions-cell">
|
||||||
|
<button type="button" onclick="userListAction('${uid}', 'activate')">activate</button>
|
||||||
|
<button type="button" onclick="userListAction('${uid}', 'inactivate')">inactivate</button>
|
||||||
|
<button type="button" class="danger" onclick="userListAction('${uid}', 'delete')">delete</button>
|
||||||
|
</td>
|
||||||
</tr>`;
|
</tr>`;
|
||||||
}).join('')
|
}).join('')
|
||||||
}</tbody></table>`;
|
}</tbody></table>`;
|
||||||
@@ -1785,6 +1820,29 @@ async function setManagedUserActive(active) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function userListAction(userId, action) {
|
||||||
|
if (!userId) return;
|
||||||
|
if (action === 'delete') {
|
||||||
|
if (!confirm(`Delete user "${userId}"? If delete fails, inactivate instead.`)) return;
|
||||||
|
try {
|
||||||
|
await api('DELETE', `/users/${encodeURIComponent(userId)}`);
|
||||||
|
showToast(`user deleted · ${userId}`, 'success');
|
||||||
|
await loadUsers();
|
||||||
|
} catch (e) {
|
||||||
|
if (e.message !== 'unauthorized') showToast('delete failed: ' + e.message, 'error');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const active = action === 'activate';
|
||||||
|
try {
|
||||||
|
await api('PATCH', `/users/${encodeURIComponent(userId)}`, { active });
|
||||||
|
showToast(active ? `activated · ${userId}` : `inactivated · ${userId}`, 'success');
|
||||||
|
await loadUsers();
|
||||||
|
} catch (e) {
|
||||||
|
if (e.message !== 'unauthorized') showToast('update failed: ' + e.message, 'error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function deleteManagedUser() {
|
async function deleteManagedUser() {
|
||||||
const userId = document.getElementById('admin-manage-select').value || document.getElementById('admin-user-id').value.trim();
|
const userId = document.getElementById('admin-manage-select').value || document.getElementById('admin-user-id').value.trim();
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
|
|||||||
Reference in New Issue
Block a user