fix(audit-wave-9): add mobile cardRender to remaining admin lists
Five DataTable consumers were rendering as horizontally-scrolling desktop tables on mobile because they had no cardRender prop. Now they collapse to a vertical card list below the lg: breakpoint with the same actions inline: - admin/tags/tag-list - admin/roles/role-list - admin/ports/port-list (also: Active/Inactive badge -> StatusPill) - admin/document-templates/template-list (also: Active/Inactive badge -> StatusPill) - admin/custom-fields/custom-fields-manager All five now share the user-list / berth-list pattern: row-card with title, secondary meta, and trailing action buttons; same TanStack table instance powers both the desktop table and the mobile cards. Closes ui/ux H2 + extends M2 (status-pill coverage). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -173,6 +173,67 @@ export function RoleList() {
|
||||
data={roles}
|
||||
isLoading={loading}
|
||||
getRowId={(row) => row.id}
|
||||
cardRender={({ original }) => (
|
||||
<div className="rounded-xl border border-border bg-card p-4 shadow-sm">
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<p className="truncate text-sm font-semibold text-foreground">
|
||||
{formatRole(original.name)}
|
||||
</p>
|
||||
{original.isSystem ? (
|
||||
<Badge variant="outline" className="text-xs">
|
||||
<Lock className="mr-1 h-3 w-3" aria-hidden />
|
||||
System
|
||||
</Badge>
|
||||
) : null}
|
||||
</div>
|
||||
{original.description ? (
|
||||
<p className="mt-1 text-xs text-muted-foreground">{original.description}</p>
|
||||
) : null}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setViewingPermissions(original)}
|
||||
className="mt-2 inline-flex"
|
||||
title="View permission breakdown"
|
||||
>
|
||||
<Badge variant="secondary" className="cursor-pointer hover:bg-secondary/80">
|
||||
{countPermissions(original.permissions)} permissions
|
||||
</Badge>
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex shrink-0 items-center gap-1">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => handleEditRole(original)}
|
||||
aria-label="Edit role"
|
||||
>
|
||||
<Pencil className="h-4 w-4" />
|
||||
</Button>
|
||||
{!original.isSystem ? (
|
||||
<ConfirmationDialog
|
||||
trigger={
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="text-destructive hover:text-destructive"
|
||||
aria-label="Delete role"
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
}
|
||||
title="Delete Role"
|
||||
description={`Delete "${original.name}"? Users assigned to this role must be reassigned first.`}
|
||||
confirmLabel="Delete"
|
||||
onConfirm={() => deleteMutation.mutate(original.id)}
|
||||
loading={deleteMutation.isPending && deleteMutation.variables === original.id}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
emptyState={
|
||||
<div className="text-center py-8">
|
||||
<p className="text-muted-foreground">No roles defined.</p>
|
||||
|
||||
Reference in New Issue
Block a user