Add roles and users admin UI with role management API
Backend: - GET /v1/users (list company users) - GET/POST/PATCH/DELETE /v1/roles (role CRUD with permissions) - GET/POST/DELETE /v1/users/:userId/roles (role assignment) - GET /v1/me/permissions (current user's effective permissions) Frontend: - Roles list page with kebab menu (edit permissions, delete custom) - Role detail page with grouped permission checkboxes and inheritance note - New role page with auto-generated slug - Users list page showing assigned roles per user - Manage Roles dialog for adding/removing roles per user - Sidebar: Admin section with Users, Roles, Help links
This commit is contained in:
56
packages/admin/src/api/rbac.ts
Normal file
56
packages/admin/src/api/rbac.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { queryOptions } from '@tanstack/react-query'
|
||||
import { api } from '@/lib/api-client'
|
||||
import type { Permission, Role } from '@/types/rbac'
|
||||
|
||||
export const rbacKeys = {
|
||||
permissions: ['permissions'] as const,
|
||||
roles: ['roles'] as const,
|
||||
role: (id: string) => ['roles', id] as const,
|
||||
userRoles: (userId: string) => ['users', userId, 'roles'] as const,
|
||||
myPermissions: ['me', 'permissions'] as const,
|
||||
}
|
||||
|
||||
export function permissionListOptions() {
|
||||
return queryOptions({
|
||||
queryKey: rbacKeys.permissions,
|
||||
queryFn: () => api.get<{ data: Permission[] }>('/v1/permissions'),
|
||||
})
|
||||
}
|
||||
|
||||
export function roleListOptions() {
|
||||
return queryOptions({
|
||||
queryKey: rbacKeys.roles,
|
||||
queryFn: () => api.get<{ data: Role[] }>('/v1/roles'),
|
||||
})
|
||||
}
|
||||
|
||||
export function roleDetailOptions(id: string) {
|
||||
return queryOptions({
|
||||
queryKey: rbacKeys.role(id),
|
||||
queryFn: () => api.get<Role & { permissions: string[] }>(`/v1/roles/${id}`),
|
||||
})
|
||||
}
|
||||
|
||||
export function myPermissionsOptions() {
|
||||
return queryOptions({
|
||||
queryKey: rbacKeys.myPermissions,
|
||||
queryFn: () => api.get<{ permissions: string[]; roles: { id: string; name: string; slug: string }[] }>('/v1/me/permissions'),
|
||||
})
|
||||
}
|
||||
|
||||
export const rbacMutations = {
|
||||
createRole: (data: Record<string, unknown>) =>
|
||||
api.post<Role>('/v1/roles', data),
|
||||
|
||||
updateRole: (id: string, data: Record<string, unknown>) =>
|
||||
api.patch<Role>(`/v1/roles/${id}`, data),
|
||||
|
||||
deleteRole: (id: string) =>
|
||||
api.del<Role>(`/v1/roles/${id}`),
|
||||
|
||||
assignRole: (userId: string, roleId: string) =>
|
||||
api.post(`/v1/users/${userId}/roles`, { roleId }),
|
||||
|
||||
removeRole: (userId: string, roleId: string) =>
|
||||
api.del(`/v1/users/${userId}/roles/${roleId}`),
|
||||
}
|
||||
22
packages/admin/src/api/users.ts
Normal file
22
packages/admin/src/api/users.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { queryOptions } from '@tanstack/react-query'
|
||||
import { api } from '@/lib/api-client'
|
||||
|
||||
export interface UserRecord {
|
||||
id: string
|
||||
email: string
|
||||
firstName: string
|
||||
lastName: string
|
||||
role: string
|
||||
createdAt: string
|
||||
}
|
||||
|
||||
export const userKeys = {
|
||||
roles: (userId: string) => ['users', userId, 'roles'] as const,
|
||||
}
|
||||
|
||||
export function userRolesOptions(userId: string) {
|
||||
return queryOptions({
|
||||
queryKey: userKeys.roles(userId),
|
||||
queryFn: () => api.get<{ data: { id: string; name: string; slug: string; isSystem: boolean }[] }>(`/v1/users/${userId}/roles`),
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user