feat(web): wire RowActionsMenu in users admin page

Primary: toggle admin (most semantically distinct per-user action).
Secondary: toggle auto-approve, reset password, delete (danger).
'Delete' was previously styled as a regular border button — now
correctly marked danger. No Edit action existed; not adding one.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-09 20:21:17 -04:00
parent e266a0f2dc
commit f03a0042e8
+31 -37
View File
@@ -19,6 +19,8 @@
import { errCode } from '$lib/api/errors'; import { errCode } from '$lib/api/errors';
import { pushToast } from '$lib/stores/toast.svelte'; import { pushToast } from '$lib/stores/toast.svelte';
import Modal from '$lib/components/Modal.svelte'; import Modal from '$lib/components/Modal.svelte';
import RowActionsMenu, { type RowAction } from '$lib/components/RowActionsMenu.svelte';
import { Shield, ShieldOff, CheckCircle2, XCircle, KeyRound, Trash2 } from 'lucide-svelte';
const client = useQueryClient(); const client = useQueryClient();
@@ -254,43 +256,35 @@
{#if u.display_name}{u.display_name} · {/if}created {formatDate(u.created_at)} {#if u.display_name}{u.display_name} · {/if}created {formatDate(u.created_at)}
</div> </div>
</div> </div>
<div class="flex shrink-0 flex-wrap items-center gap-2"> {@const primary: RowAction = {
<button icon: u.is_admin ? ShieldOff : Shield,
type="button" label: u.is_admin ? 'Remove admin' : 'Make admin',
disabled={saving} onclick: () => onToggleAdmin(u),
aria-label={u.is_admin ? `Remove admin from ${u.username}` : `Make ${u.username} admin`} disabled: saving
class="inline-flex items-center gap-1 rounded-md border border-border bg-transparent px-3 py-1.5 text-sm text-text-secondary hover:bg-surface-hover hover:text-text-primary disabled:cursor-not-allowed disabled:opacity-50" }}
onclick={() => onToggleAdmin(u)} {@const secondary: RowAction[] = [
> {
{u.is_admin ? 'Remove admin' : 'Make admin'} icon: u.auto_approve_requests ? XCircle : CheckCircle2,
</button> label: u.auto_approve_requests ? 'Disable auto-approve' : 'Enable auto-approve',
<button onclick: () => onToggleAutoApprove(u),
type="button" disabled: saving
disabled={saving} },
aria-label={u.auto_approve_requests ? `Disable auto-approve for ${u.username}` : `Enable auto-approve for ${u.username}`} {
class="inline-flex items-center gap-1 rounded-md border border-border bg-transparent px-3 py-1.5 text-sm text-text-secondary hover:bg-surface-hover hover:text-text-primary disabled:cursor-not-allowed disabled:opacity-50" icon: KeyRound,
onclick={() => onToggleAutoApprove(u)} label: 'Reset password',
> onclick: () => { resetPasswordTarget = u; },
{u.auto_approve_requests ? 'Disable auto-approve' : 'Enable auto-approve'} disabled: saving
</button> },
<button {
type="button" icon: Trash2,
disabled={saving} label: 'Delete',
aria-label={`Reset password for ${u.username}`} onclick: () => { confirmDeleteTarget = u; },
class="inline-flex items-center gap-1 rounded-md border border-border bg-transparent px-3 py-1.5 text-sm text-text-secondary hover:bg-surface-hover hover:text-text-primary disabled:cursor-not-allowed disabled:opacity-50" disabled: saving,
onclick={() => { resetPasswordTarget = u; }} danger: true
> }
Reset password ]}
</button> <div class="shrink-0">
<button <RowActionsMenu {primary} {secondary} />
type="button"
disabled={saving}
aria-label={`Delete ${u.username}`}
class="inline-flex items-center gap-1 rounded-md border border-border bg-transparent px-3 py-1.5 text-sm text-text-secondary hover:bg-surface-hover hover:text-text-primary disabled:cursor-not-allowed disabled:opacity-50"
onclick={() => { confirmDeleteTarget = u; }}
>
Delete
</button>
</div> </div>
</li> </li>
{/each} {/each}