Add paginated users/roles, user status, frontend permissions, profile pictures, identifier file storage

- Users page: paginated, searchable, sortable with inline roles (no N+1)
- Roles page: paginated, searchable, sortable + /roles/all for dropdowns
- User is_active field with migration, PATCH toggle, auth check (disabled=401)
- Frontend permission checks: auth store loads permissions, sidebar/buttons conditional
- Profile pictures via file storage for users and members, avatar component
- Identifier images use file storage API instead of base64
- Fix TypeScript errors across admin UI
- 64 API tests passing (10 new)
This commit is contained in:
Ryan Moon
2026-03-29 08:16:34 -05:00
parent 92371ff228
commit b9f78639e2
48 changed files with 1689 additions and 643 deletions

View File

@@ -1,10 +1,12 @@
import { queryOptions } from '@tanstack/react-query'
import { api } from '@/lib/api-client'
import type { Permission, Role } from '@/types/rbac'
import type { PaginationInput, PaginatedResponse } from '@forte/shared/schemas'
export const rbacKeys = {
permissions: ['permissions'] as const,
roles: ['roles'] as const,
roleList: (params: PaginationInput) => ['roles', 'list', params] as const,
role: (id: string) => ['roles', id] as const,
userRoles: (userId: string) => ['users', userId, 'roles'] as const,
myPermissions: ['me', 'permissions'] as const,
@@ -17,10 +19,19 @@ export function permissionListOptions() {
})
}
/** All roles (for dropdowns, selectors) */
export function roleListOptions() {
return queryOptions({
queryKey: rbacKeys.roles,
queryFn: () => api.get<{ data: Role[] }>('/v1/roles'),
queryFn: () => api.get<{ data: Role[] }>('/v1/roles/all'),
})
}
/** Paginated roles (for the roles list page) */
export function rolePageOptions(params: PaginationInput) {
return queryOptions({
queryKey: rbacKeys.roleList(params),
queryFn: () => api.get<PaginatedResponse<Role>>('/v1/roles', params as Record<string, unknown>),
})
}