feat(dashboard): adopt ActionMenu for user row actions
Replaces the inline row-action buttons on the Users page with the new shared ActionMenu kebab. Drops the redundant `is_active` toggle from the edit form (Activate/Deactivate already lives in the kebab). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
import { currentUser } from '$lib/auth';
|
||||
import RoleChip from '$lib/RoleChip.svelte';
|
||||
import ConfirmModal from '$lib/ConfirmModal.svelte';
|
||||
import ActionMenu from '$lib/ActionMenu.svelte';
|
||||
import { generatePassword } from '$lib/password-gen';
|
||||
|
||||
const me = $derived($currentUser);
|
||||
@@ -70,8 +71,7 @@
|
||||
username: string;
|
||||
email: string;
|
||||
instance_role: InstanceRole;
|
||||
is_active: boolean;
|
||||
}>({ username: '', email: '', instance_role: 'admin', is_active: true });
|
||||
}>({ username: '', email: '', instance_role: 'admin' });
|
||||
let editPending = $state(false);
|
||||
let editError = $state<string | null>(null);
|
||||
|
||||
@@ -161,8 +161,7 @@
|
||||
editForm = {
|
||||
username: row.username,
|
||||
email: row.email ?? '',
|
||||
instance_role: row.instance_role,
|
||||
is_active: row.is_active
|
||||
instance_role: row.instance_role
|
||||
};
|
||||
editError = null;
|
||||
}
|
||||
@@ -176,7 +175,6 @@
|
||||
username?: string;
|
||||
email?: string | null;
|
||||
instance_role?: InstanceRole;
|
||||
is_active?: boolean;
|
||||
} = {};
|
||||
if (editForm.username !== editTarget.username) patch.username = editForm.username;
|
||||
if ((editTarget.email ?? '') !== editForm.email.trim()) {
|
||||
@@ -185,7 +183,6 @@
|
||||
if (editForm.instance_role !== editTarget.instance_role) {
|
||||
patch.instance_role = editForm.instance_role;
|
||||
}
|
||||
if (editForm.is_active !== editTarget.is_active) patch.is_active = editForm.is_active;
|
||||
try {
|
||||
const updated = await api.admins.update(editTarget.id, patch);
|
||||
admins = admins
|
||||
@@ -350,19 +347,22 @@
|
||||
<div>{shortDate(row.created_at)}</div>
|
||||
<div title={row.last_login_at ?? ''}>{relative(row.last_login_at)}</div>
|
||||
<div class="actions-col">
|
||||
<button type="button" class="row-action" onclick={() => openEdit(row)}>Edit</button>
|
||||
<button type="button" class="row-action" onclick={() => toggleActive(row)}>
|
||||
{row.is_active ? 'Deactivate' : 'Reactivate'}
|
||||
</button>
|
||||
{#if canDelete(row)}
|
||||
<button
|
||||
type="button"
|
||||
class="row-action danger-link"
|
||||
onclick={() => openDelete(row)}
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
{/if}
|
||||
<ActionMenu
|
||||
label="User actions for {row.username}"
|
||||
items={[
|
||||
{ label: 'Edit', onClick: () => openEdit(row) },
|
||||
{
|
||||
label: row.is_active ? 'Deactivate' : 'Reactivate',
|
||||
onClick: () => toggleActive(row)
|
||||
},
|
||||
{
|
||||
label: 'Delete',
|
||||
danger: true,
|
||||
disabled: !canDelete(row),
|
||||
onClick: () => openDelete(row)
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
@@ -514,11 +514,6 @@
|
||||
{/if}
|
||||
</small>
|
||||
</label>
|
||||
<label class="toggle">
|
||||
<input type="checkbox" bind:checked={editForm.is_active} />
|
||||
<span>Active</span>
|
||||
<small>Unchecking signs the user out and expires all their API keys immediately.</small>
|
||||
</label>
|
||||
{#if editError}
|
||||
<div class="error">{editError}</div>
|
||||
{/if}
|
||||
@@ -682,7 +677,7 @@
|
||||
}
|
||||
.row {
|
||||
display: grid;
|
||||
grid-template-columns: 1.3fr 0.7fr 1.5fr 0.9fr 0.8fr 0.9fr 1.6fr;
|
||||
grid-template-columns: 1.3fr 0.7fr 1.5fr 0.9fr 0.8fr 0.9fr 2.5rem;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.7rem 1rem;
|
||||
@@ -737,29 +732,6 @@
|
||||
.actions-col {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 0.25rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.row-action {
|
||||
background: transparent;
|
||||
color: #cbd5e1;
|
||||
border: 1px solid #334155;
|
||||
padding: 0.25rem 0.55rem;
|
||||
border-radius: 0.25rem;
|
||||
font-size: 0.75rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
.row-action:hover {
|
||||
background: #1e293b;
|
||||
color: #e2e8f0;
|
||||
}
|
||||
.danger-link {
|
||||
color: #fca5a5;
|
||||
border-color: #7f1d1d;
|
||||
}
|
||||
.danger-link:hover {
|
||||
background: #450a0a;
|
||||
color: #fecaca;
|
||||
}
|
||||
|
||||
button.primary {
|
||||
@@ -923,21 +895,6 @@
|
||||
color: #cbd5e1;
|
||||
}
|
||||
|
||||
.toggle {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
font-size: 0.85rem;
|
||||
color: #cbd5e1;
|
||||
}
|
||||
.toggle :global(input[type='checkbox']) {
|
||||
margin-right: 0.4rem;
|
||||
}
|
||||
.toggle small {
|
||||
color: #64748b;
|
||||
font-size: 0.72rem;
|
||||
margin-left: 1.3rem;
|
||||
}
|
||||
|
||||
.token-row {
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user