fix: add missing onError handlers on RBAC mutations

- deleteMutation onError in AdminRoles and AdminPolicies
- revokeMutation onError in AdminRoleAssign
- handleExport error handling in AdminAuditLog
- add missing i18n keys: deleteFailed, revokeFailed, exportError
This commit is contained in:
Fringg
2026-02-25 03:17:12 +03:00
parent 874ee2682e
commit c4e3211baa
8 changed files with 60 additions and 23 deletions

View File

@@ -2990,7 +2990,8 @@
"loadFailed": "Failed to load roles", "loadFailed": "Failed to load roles",
"createFailed": "Failed to create role", "createFailed": "Failed to create role",
"updateFailed": "Failed to update role", "updateFailed": "Failed to update role",
"nameRequired": "Role name is required" "nameRequired": "Role name is required",
"deleteFailed": "Failed to delete role"
} }
}, },
"roleAssign": { "roleAssign": {
@@ -3041,7 +3042,8 @@
"errors": { "errors": {
"userRequired": "Please select a user", "userRequired": "Please select a user",
"roleRequired": "Please select a role", "roleRequired": "Please select a role",
"assignFailed": "Failed to assign role" "assignFailed": "Failed to assign role",
"revokeFailed": "Failed to revoke role"
} }
}, },
"policies": { "policies": {
@@ -3117,7 +3119,8 @@
"updateFailed": "Failed to update policy", "updateFailed": "Failed to update policy",
"nameRequired": "Policy name is required", "nameRequired": "Policy name is required",
"resourceRequired": "Please select a resource", "resourceRequired": "Please select a resource",
"actionsRequired": "Please select at least one action" "actionsRequired": "Please select at least one action",
"deleteFailed": "Failed to delete policy"
} }
}, },
"auditLog": { "auditLog": {
@@ -3125,6 +3128,7 @@
"subtitle": "Review system activity and access history", "subtitle": "Review system activity and access history",
"back": "Back", "back": "Back",
"exportCsv": "Export CSV", "exportCsv": "Export CSV",
"exportError": "Failed to export",
"exporting": "Exporting...", "exporting": "Exporting...",
"refresh": "Refresh", "refresh": "Refresh",
"unknownUser": "Unknown user", "unknownUser": "Unknown user",

View File

@@ -2850,7 +2850,8 @@
"loadFailed": "بارگذاری نقش‌ها ناموفق بود", "loadFailed": "بارگذاری نقش‌ها ناموفق بود",
"createFailed": "ایجاد نقش ناموفق بود", "createFailed": "ایجاد نقش ناموفق بود",
"updateFailed": "به‌روزرسانی نقش ناموفق بود", "updateFailed": "به‌روزرسانی نقش ناموفق بود",
"nameRequired": "نام نقش الزامی است" "nameRequired": "نام نقش الزامی است",
"deleteFailed": "حذف نقش ناموفق بود"
} }
}, },
"roleAssign": { "roleAssign": {
@@ -2900,7 +2901,8 @@
"errors": { "errors": {
"userRequired": "لطفاً یک کاربر انتخاب کنید", "userRequired": "لطفاً یک کاربر انتخاب کنید",
"roleRequired": "لطفاً یک نقش انتخاب کنید", "roleRequired": "لطفاً یک نقش انتخاب کنید",
"assignFailed": "تخصیص نقش ناموفق بود" "assignFailed": "تخصیص نقش ناموفق بود",
"revokeFailed": "لغو نقش ناموفق بود"
} }
}, },
"policies": { "policies": {
@@ -2975,7 +2977,8 @@
"updateFailed": "به‌روزرسانی سیاست ناموفق بود", "updateFailed": "به‌روزرسانی سیاست ناموفق بود",
"nameRequired": "نام سیاست الزامی است", "nameRequired": "نام سیاست الزامی است",
"resourceRequired": "لطفاً یک منبع انتخاب کنید", "resourceRequired": "لطفاً یک منبع انتخاب کنید",
"actionsRequired": "لطفاً حداقل یک عملیات انتخاب کنید" "actionsRequired": "لطفاً حداقل یک عملیات انتخاب کنید",
"deleteFailed": "حذف سیاست ناموفق بود"
} }
}, },
"auditLog": { "auditLog": {
@@ -2983,6 +2986,7 @@
"subtitle": "بررسی فعالیت سیستم و تاریخچه دسترسی", "subtitle": "بررسی فعالیت سیستم و تاریخچه دسترسی",
"back": "بازگشت", "back": "بازگشت",
"exportCsv": "خروجی CSV", "exportCsv": "خروجی CSV",
"exportError": "خطا در خروجی",
"exporting": "در حال خروجی...", "exporting": "در حال خروجی...",
"refresh": "بازخوانی", "refresh": "بازخوانی",
"unknownUser": "کاربر ناشناخته", "unknownUser": "کاربر ناشناخته",

View File

@@ -3545,7 +3545,8 @@
"loadFailed": "Не удалось загрузить роли", "loadFailed": "Не удалось загрузить роли",
"createFailed": "Не удалось создать роль", "createFailed": "Не удалось создать роль",
"updateFailed": "Не удалось обновить роль", "updateFailed": "Не удалось обновить роль",
"nameRequired": "Укажите название роли" "nameRequired": "Укажите название роли",
"deleteFailed": "Не удалось удалить роль"
} }
}, },
"roleAssign": { "roleAssign": {
@@ -3597,7 +3598,8 @@
"errors": { "errors": {
"userRequired": "Выберите пользователя", "userRequired": "Выберите пользователя",
"roleRequired": "Выберите роль", "roleRequired": "Выберите роль",
"assignFailed": "Не удалось назначить роль" "assignFailed": "Не удалось назначить роль",
"revokeFailed": "Не удалось отозвать роль"
} }
}, },
"policies": { "policies": {
@@ -3674,7 +3676,8 @@
"updateFailed": "Не удалось обновить политику", "updateFailed": "Не удалось обновить политику",
"nameRequired": "Укажите название политики", "nameRequired": "Укажите название политики",
"resourceRequired": "Выберите ресурс", "resourceRequired": "Выберите ресурс",
"actionsRequired": "Выберите хотя бы одно действие" "actionsRequired": "Выберите хотя бы одно действие",
"deleteFailed": "Не удалось удалить политику"
} }
}, },
"auditLog": { "auditLog": {
@@ -3682,6 +3685,7 @@
"subtitle": "Просмотр активности системы и истории доступа", "subtitle": "Просмотр активности системы и истории доступа",
"back": "Назад", "back": "Назад",
"exportCsv": "Экспорт CSV", "exportCsv": "Экспорт CSV",
"exportError": "Ошибка экспорта",
"exporting": "Экспорт...", "exporting": "Экспорт...",
"refresh": "Обновить", "refresh": "Обновить",
"unknownUser": "Неизвестный пользователь", "unknownUser": "Неизвестный пользователь",

View File

@@ -2876,7 +2876,8 @@
"loadFailed": "加载角色失败", "loadFailed": "加载角色失败",
"createFailed": "创建角色失败", "createFailed": "创建角色失败",
"updateFailed": "更新角色失败", "updateFailed": "更新角色失败",
"nameRequired": "请输入角色名称" "nameRequired": "请输入角色名称",
"deleteFailed": "删除角色失败"
} }
}, },
"roleAssign": { "roleAssign": {
@@ -2926,7 +2927,8 @@
"errors": { "errors": {
"userRequired": "请选择用户", "userRequired": "请选择用户",
"roleRequired": "请选择角色", "roleRequired": "请选择角色",
"assignFailed": "角色分配失败" "assignFailed": "角色分配失败",
"revokeFailed": "角色撤销失败"
} }
}, },
"policies": { "policies": {
@@ -3001,7 +3003,8 @@
"updateFailed": "更新策略失败", "updateFailed": "更新策略失败",
"nameRequired": "请输入策略名称", "nameRequired": "请输入策略名称",
"resourceRequired": "请选择资源", "resourceRequired": "请选择资源",
"actionsRequired": "请至少选择一个操作" "actionsRequired": "请至少选择一个操作",
"deleteFailed": "删除策略失败"
} }
}, },
"auditLog": { "auditLog": {
@@ -3009,6 +3012,7 @@
"subtitle": "查看系统活动和访问历史", "subtitle": "查看系统活动和访问历史",
"back": "返回", "back": "返回",
"exportCsv": "导出CSV", "exportCsv": "导出CSV",
"exportError": "导出失败",
"exporting": "导出中...", "exporting": "导出中...",
"refresh": "刷新", "refresh": "刷新",
"unknownUser": "未知用户", "unknownUser": "未知用户",

View File

@@ -381,6 +381,7 @@ export default function AdminAuditLog() {
const [expandedIds, setExpandedIds] = useState<Set<number>>(new Set()); const [expandedIds, setExpandedIds] = useState<Set<number>>(new Set());
const [autoRefresh, setAutoRefresh] = useState(false); const [autoRefresh, setAutoRefresh] = useState(false);
const [exporting, setExporting] = useState(false); const [exporting, setExporting] = useState(false);
const [exportError, setExportError] = useState<string | null>(null);
// Auto-refresh interval ref // Auto-refresh interval ref
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null); const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
@@ -479,10 +480,12 @@ export default function AdminAuditLog() {
a.click(); a.click();
document.body.removeChild(a); document.body.removeChild(a);
URL.revokeObjectURL(url); URL.revokeObjectURL(url);
} catch {
setExportError(t('admin.auditLog.exportError'));
} finally { } finally {
setExporting(false); setExporting(false);
} }
}, [appliedFilters]); }, [appliedFilters, t]);
const handlePageSizeChange = useCallback((newSize: number) => { const handlePageSizeChange = useCallback((newSize: number) => {
setPageSize(newSize); setPageSize(newSize);
@@ -552,16 +555,22 @@ export default function AdminAuditLog() {
{/* Export */} {/* Export */}
<PermissionGate permission="audit_log:export"> <PermissionGate permission="audit_log:export">
<button <div className="flex items-center gap-2">
onClick={handleExport} {exportError && <p className="text-sm text-error-400">{exportError}</p>}
disabled={exporting} <button
className="flex items-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600 disabled:opacity-50" onClick={() => {
> setExportError(null);
<DownloadIcon /> handleExport();
<span className="hidden sm:inline"> }}
{exporting ? t('admin.auditLog.exporting') : t('admin.auditLog.exportCsv')} disabled={exporting}
</span> className="flex items-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600 disabled:opacity-50"
</button> >
<DownloadIcon />
<span className="hidden sm:inline">
{exporting ? t('admin.auditLog.exporting') : t('admin.auditLog.exportCsv')}
</span>
</button>
</div>
</PermissionGate> </PermissionGate>
</div> </div>
</div> </div>

View File

@@ -379,6 +379,10 @@ export default function AdminPolicies() {
queryClient.invalidateQueries({ queryKey: ['admin-policies'] }); queryClient.invalidateQueries({ queryKey: ['admin-policies'] });
setDeleteConfirm(null); setDeleteConfirm(null);
}, },
onError: () => {
setDeleteConfirm(null);
setFormError(t('admin.policies.errors.deleteFailed'));
},
}); });
// Derived data // Derived data

View File

@@ -330,6 +330,10 @@ export default function AdminRoleAssign() {
queryClient.invalidateQueries({ queryKey: ['admin-roles'] }); queryClient.invalidateQueries({ queryKey: ['admin-roles'] });
setRevokeConfirm(null); setRevokeConfirm(null);
}, },
onError: () => {
setRevokeConfirm(null);
setFormError(t('admin.roleAssign.errors.revokeFailed'));
},
}); });
// Handlers // Handlers

View File

@@ -350,6 +350,10 @@ export default function AdminRoles() {
queryClient.invalidateQueries({ queryKey: ['admin-roles'] }); queryClient.invalidateQueries({ queryKey: ['admin-roles'] });
setDeleteConfirm(null); setDeleteConfirm(null);
}, },
onError: () => {
setDeleteConfirm(null);
setFormError(t('admin.roles.errors.deleteFailed'));
},
}); });
// Handlers // Handlers