fix: superadmin assignments show ENV badge, block UI revoke

Superadmin role (level 999) is managed via env config only. Hide X
button for superadmin assignments and show ENV badge instead. Filter
superadmin from assignable roles dropdown. Add envManaged translation
to all 4 locales.
This commit is contained in:
Fringg
2026-03-22 08:41:41 +03:00
parent 3e27472c8a
commit 8e59af96c5
5 changed files with 29 additions and 15 deletions

View File

@@ -3227,6 +3227,7 @@
"system": "System", "system": "System",
"permanent": "Permanent", "permanent": "Permanent",
"expired": "expired", "expired": "expired",
"envManaged": "Managed via ADMIN_IDS / ADMIN_EMAILS in env",
"revoke": "Revoke", "revoke": "Revoke",
"revokeAriaLabel": "Revoke role {{role}} from {{user}}", "revokeAriaLabel": "Revoke role {{role}} from {{user}}",
"table": { "table": {

View File

@@ -2968,6 +2968,7 @@
"system": "سیستم", "system": "سیستم",
"permanent": "دائمی", "permanent": "دائمی",
"expired": "منقضی شده", "expired": "منقضی شده",
"envManaged": "مدیریت از طریق ADMIN_IDS / ADMIN_EMAILS در env",
"revoke": "لغو", "revoke": "لغو",
"revokeAriaLabel": "لغو نقش {{role}} از {{user}}", "revokeAriaLabel": "لغو نقش {{role}} از {{user}}",
"table": { "table": {

View File

@@ -3773,6 +3773,7 @@
"system": "Система", "system": "Система",
"permanent": "Бессрочно", "permanent": "Бессрочно",
"expired": "истекло", "expired": "истекло",
"envManaged": "Управляется через ADMIN_IDS / ADMIN_EMAILS в env",
"revoke": "Отозвать", "revoke": "Отозвать",
"revokeAriaLabel": "Отозвать роль {{role}} у {{user}}", "revokeAriaLabel": "Отозвать роль {{role}} у {{user}}",
"table": { "table": {

View File

@@ -2967,6 +2967,7 @@
"system": "系统", "system": "系统",
"permanent": "永久", "permanent": "永久",
"expired": "已过期", "expired": "已过期",
"envManaged": "通过 ADMIN_IDS / ADMIN_EMAILS 环境变量管理",
"revoke": "撤销", "revoke": "撤销",
"revokeAriaLabel": "撤销 {{user}} 的角色 {{role}}", "revokeAriaLabel": "撤销 {{user}} 的角色 {{role}}",
"table": { "table": {

View File

@@ -79,6 +79,7 @@ const UserPlusIcon = () => (
// === Constants === // === Constants ===
const PAGE_SIZE = 10; const PAGE_SIZE = 10;
const SUPERADMIN_LEVEL = 999;
// === Sub-components === // === Sub-components ===
@@ -278,10 +279,10 @@ export default function AdminRoleAssign() {
enabled: !!roles && roles.length > 0, enabled: !!roles && roles.length > 0,
}); });
// Available roles filtered by canManageRole // Available roles filtered by canManageRole (superadmin excluded — env-only)
const assignableRoles = useMemo(() => { const assignableRoles = useMemo(() => {
if (!roles) return []; if (!roles) return [];
return roles.filter((r) => r.is_active && canManageRole(r.level)); return roles.filter((r) => r.is_active && r.level < SUPERADMIN_LEVEL && canManageRole(r.level));
}, [roles, canManageRole]); }, [roles, canManageRole]);
// Roles map for quick lookup // Roles map for quick lookup
@@ -627,6 +628,14 @@ export default function AdminRoleAssign() {
{/* Actions */} {/* Actions */}
<div className="col-span-1 flex justify-end sm:justify-start"> <div className="col-span-1 flex justify-end sm:justify-start">
{assignment.role_level >= SUPERADMIN_LEVEL ? (
<span
className="rounded px-1.5 py-0.5 text-[10px] font-medium text-dark-500"
title={t('admin.roleAssign.envManaged')}
>
ENV
</span>
) : (
<PermissionGate permission="roles:assign"> <PermissionGate permission="roles:assign">
<button <button
onClick={() => setRevokeConfirm(assignment.id)} onClick={() => setRevokeConfirm(assignment.id)}
@@ -641,6 +650,7 @@ export default function AdminRoleAssign() {
<XCircleIcon /> <XCircleIcon />
</button> </button>
</PermissionGate> </PermissionGate>
)}
</div> </div>
</div> </div>
); );