fix: RBAC policies page role handling and permission gates

- Read policy role_id from top-level field instead of conditions object
- Use policy.role_name for display, remove conditions.role_id lookup
- Remove duplicate role_id injection into conditions payload on submit
- Fix PermissionGate strings: policies:* -> roles:* to match backend
- Remove redundant client-side status filtering in audit log (already
  filtered server-side)
This commit is contained in:
Fringg
2026-02-25 04:07:13 +03:00
parent 4c9c3992ab
commit 56188b1f8a
2 changed files with 11 additions and 21 deletions

View File

@@ -476,11 +476,8 @@ export default function AdminAuditLog() {
setPage(0); setPage(0);
}, []); }, []);
// Filter status entries client-side (status is derived from details, not a backend field) // Status is filtered server-side via query params
const filteredEntries = useMemo(() => { const filteredEntries = entries;
if (!appliedFilters.status) return entries;
return entries.filter((entry) => entry.status === appliedFilters.status);
}, [entries, appliedFilters.status]);
const hasActiveFilters = useMemo(() => { const hasActiveFilters = useMemo(() => {
return ( return (

View File

@@ -430,9 +430,6 @@ export default function AdminPolicies() {
const openEditModal = useCallback((policy: AccessPolicy) => { const openEditModal = useCallback((policy: AccessPolicy) => {
const parsed = parseConditions(policy.conditions); const parsed = parseConditions(policy.conditions);
// Determine the role_id from conditions if present
const roleId = typeof policy.conditions.role_id === 'number' ? policy.conditions.role_id : null;
const actions = Array.isArray(policy.actions) ? policy.actions : []; const actions = Array.isArray(policy.actions) ? policy.actions : [];
setEditingPolicy(policy); setEditingPolicy(policy);
@@ -442,7 +439,7 @@ export default function AdminPolicies() {
effect: policy.effect, effect: policy.effect,
resource: policy.resource, resource: policy.resource,
actions, actions,
role_id: roleId, role_id: policy.role_id ?? null,
priority: policy.priority, priority: policy.priority,
conditions: { conditions: {
time_range: parsed.time_range ?? { start: '09:00', end: '18:00' }, time_range: parsed.time_range ?? { start: '09:00', end: '18:00' },
@@ -500,10 +497,6 @@ export default function AdminPolicies() {
formData.conditionsEnabled, formData.conditionsEnabled,
); );
if (formData.role_id !== null) {
conditionsPayload.role_id = formData.role_id;
}
if (editingPolicy) { if (editingPolicy) {
const payload: UpdatePolicyPayload = { const payload: UpdatePolicyPayload = {
name: formData.name.trim(), name: formData.name.trim(),
@@ -586,10 +579,10 @@ export default function AdminPolicies() {
); );
const getRoleName = useCallback( const getRoleName = useCallback(
(conditions: Record<string, unknown>): string => { (policy: AccessPolicy): string => {
const roleId = typeof conditions.role_id === 'number' ? conditions.role_id : null; if (policy.role_name) return policy.role_name;
if (roleId === null) return t('admin.policies.global'); if (policy.role_id === null) return t('admin.policies.global');
const role = rolesMap.get(roleId); const role = rolesMap.get(policy.role_id);
return role?.name ?? t('admin.policies.unknownRole'); return role?.name ?? t('admin.policies.unknownRole');
}, },
[rolesMap, t], [rolesMap, t],
@@ -613,7 +606,7 @@ export default function AdminPolicies() {
<p className="text-sm text-dark-400">{t('admin.policies.subtitle')}</p> <p className="text-sm text-dark-400">{t('admin.policies.subtitle')}</p>
</div> </div>
</div> </div>
<PermissionGate permission="policies:create"> <PermissionGate permission="roles:create">
<button <button
onClick={openCreateModal} onClick={openCreateModal}
className="flex items-center justify-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600" className="flex items-center justify-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600"
@@ -670,7 +663,7 @@ export default function AdminPolicies() {
<div className="space-y-3"> <div className="space-y-3">
{sortedPolicies.map((policy) => { {sortedPolicies.map((policy) => {
const conditionIcons = renderConditionIcons(policy.conditions); const conditionIcons = renderConditionIcons(policy.conditions);
const roleName = getRoleName(policy.conditions); const roleName = getRoleName(policy);
return ( return (
<div <div
@@ -721,7 +714,7 @@ export default function AdminPolicies() {
{/* Actions */} {/* Actions */}
<div className="flex items-center gap-2 border-t border-dark-700 pt-3 sm:border-0 sm:pt-0"> <div className="flex items-center gap-2 border-t border-dark-700 pt-3 sm:border-0 sm:pt-0">
<PermissionGate permission="policies:edit"> <PermissionGate permission="roles:edit">
<button <button
onClick={() => openEditModal(policy)} onClick={() => openEditModal(policy)}
className="flex-1 rounded-lg bg-dark-700 p-2 text-dark-300 transition-colors hover:bg-dark-600 hover:text-dark-100 sm:flex-none" className="flex-1 rounded-lg bg-dark-700 p-2 text-dark-300 transition-colors hover:bg-dark-600 hover:text-dark-100 sm:flex-none"
@@ -730,7 +723,7 @@ export default function AdminPolicies() {
<EditIcon /> <EditIcon />
</button> </button>
</PermissionGate> </PermissionGate>
<PermissionGate permission="policies:delete"> <PermissionGate permission="roles:delete">
<button <button
onClick={() => setDeleteConfirm(policy.id)} onClick={() => setDeleteConfirm(policy.id)}
className="flex-1 rounded-lg bg-dark-700 p-2 text-dark-300 transition-colors hover:bg-error-500/20 hover:text-error-400 sm:flex-none" className="flex-1 rounded-lg bg-dark-700 p-2 text-dark-300 transition-colors hover:bg-error-500/20 hover:text-error-400 sm:flex-none"