Unify edit-role dialog with AdminFormDialog (#621)
The "edit role" dialog in admin.tsx was hand-rolled as a bespoke <div role-less wrapper> with its own close button, sticky footer and full-width split buttons. That made it look different from every other admin dialog (add role, add/edit group, add user), and on iPad the action buttons floated mid-dialog because the content exceeded max-h-[92vh]. The custom wrapper also lacked role="dialog", so the new `:has(:focus)` CSS keyboard rule (index.css:492) never applied to it. Replaced the wrapper with AdminFormDialog (maxWidth="lg", KeyRound icon, same title key). All inner content — name/desc fields, rename warning, permissions list, removal impact, RolePermissionHistory, RecentActivityForTarget — moved verbatim as children. Removed the custom sticky footer; AdminFormDialog provides the unified footer with cancel/save buttons. Preserved testIds `edit-role-dialog` and `edit-role-submit`. Disabled logic translated 1:1 into submitDisabled + isPending props (note: `impactError` coerced to boolean via `!!` to satisfy the prop type). No behavior change: same handlers (closeEditDialog, handleEdit), same loading spinner, same disabled conditions. Bonus: the keyboard override CSS now applies because AdminFormDialog already sets role="dialog". `tsc --noEmit` clean.
This commit is contained in:
@@ -6867,20 +6867,21 @@ function RolesPanel({
|
||||
)}
|
||||
|
||||
{editingId != null && (
|
||||
<div className="fixed inset-0 bg-slate-900/50 backdrop-blur-sm z-50 flex items-center justify-center p-4">
|
||||
<div
|
||||
className="relative bg-white rounded-2xl sm:rounded-3xl shadow-2xl ring-1 ring-slate-200 p-5 sm:p-6 w-full max-w-[min(100%,560px)] sm:max-w-xl md:max-w-2xl space-y-4 max-h-[92vh] overflow-y-auto"
|
||||
data-testid="edit-role-dialog"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
onClick={closeEditDialog}
|
||||
aria-label={t("common.cancel")}
|
||||
className="absolute top-3 end-3 inline-flex items-center justify-center w-9 h-9 rounded-full text-slate-500 hover:text-slate-900 hover:bg-slate-100"
|
||||
>
|
||||
<X size={18} />
|
||||
</button>
|
||||
<h2 className="text-lg sm:text-xl font-semibold text-foreground pe-10">{t("admin.roles.editRole")}</h2>
|
||||
<AdminFormDialog
|
||||
title={t("admin.roles.editRole")}
|
||||
icon={<KeyRound size={20} />}
|
||||
maxWidth="lg"
|
||||
onCancel={closeEditDialog}
|
||||
onSubmit={handleEdit}
|
||||
submitDisabled={
|
||||
!editForm.name.trim() ||
|
||||
(!editingIsSystem && hasRemovals && (impactLoading || !!impactError))
|
||||
}
|
||||
isPending={updateRole.isPending || replaceRolePermissions.isPending}
|
||||
testId="edit-role-dialog"
|
||||
submitTestId="edit-role-submit"
|
||||
>
|
||||
<>
|
||||
<div className="space-y-1">
|
||||
<Label>{t("admin.roles.name")}</Label>
|
||||
<Input
|
||||
@@ -7079,30 +7080,8 @@ function RolesPanel({
|
||||
onOpenAuditLogForTarget("role", editingPermissionsId);
|
||||
}}
|
||||
/>
|
||||
<div className="flex gap-2 pt-3 sticky bottom-0 bg-white -mx-5 sm:-mx-6 px-5 sm:px-6 -mb-5 sm:-mb-6 pb-5 sm:pb-6 border-t border-slate-100">
|
||||
<Button variant="outline" className="flex-1 min-h-11 rounded-xl text-base" onClick={closeEditDialog}>
|
||||
{t("common.cancel")}
|
||||
</Button>
|
||||
<Button
|
||||
className="flex-1 min-h-11 rounded-xl text-base"
|
||||
disabled={
|
||||
!editForm.name.trim() ||
|
||||
updateRole.isPending ||
|
||||
replaceRolePermissions.isPending ||
|
||||
(!editingIsSystem && hasRemovals && (impactLoading || impactError))
|
||||
}
|
||||
onClick={handleEdit}
|
||||
data-testid="edit-role-submit"
|
||||
>
|
||||
{updateRole.isPending || replaceRolePermissions.isPending ? (
|
||||
<Loader2 size={14} className="animate-spin" />
|
||||
) : (
|
||||
t("common.save")
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</AdminFormDialog>
|
||||
)}
|
||||
|
||||
{confirmRemoval && permissionsImpact && permissionsImpact.totalAffectedUsers > 0 && (
|
||||
|
||||
Reference in New Issue
Block a user