Files
cameleer-server/ui/src/api/queries/admin/rbac.ts
2026-03-23 18:13:37 +01:00

367 lines
10 KiB
TypeScript

import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { adminFetch } from './admin-api';
// ── Types ──────────────────────────────────────────────────────────────
export interface RoleSummary {
id: string;
name: string;
scope: string;
}
export interface GroupSummary {
id: string;
name: string;
parentGroupId: string | null;
}
export interface UserSummary {
userId: string;
displayName: string;
}
export interface UserDetail {
userId: string;
provider: string;
email: string;
displayName: string;
createdAt: string;
directRoles: RoleSummary[];
directGroups: GroupSummary[];
effectiveRoles: RoleSummary[];
effectiveGroups: GroupSummary[];
}
export interface RoleDetail {
id: string;
name: string;
description: string;
scope: string;
system: boolean;
createdAt: string;
assignedGroups: GroupSummary[];
directUsers: UserSummary[];
effectivePrincipals: UserSummary[];
}
export interface GroupDetail {
id: string;
name: string;
parentGroupId: string | null;
createdAt: string;
directRoles: RoleSummary[];
effectiveRoles: RoleSummary[];
members: UserSummary[];
childGroups: GroupSummary[];
}
export interface CreateUserRequest {
username: string;
displayName?: string;
email?: string;
password?: string;
}
export interface UpdateUserRequest {
displayName?: string;
email?: string;
}
export interface CreateRoleRequest {
name: string;
description?: string;
scope?: string;
}
export interface UpdateRoleRequest {
name: string;
description?: string;
scope?: string;
}
export interface CreateGroupRequest {
name: string;
parentGroupId?: string | null;
}
export interface UpdateGroupRequest {
name: string;
parentGroupId?: string | null;
}
// ── Stats Hook ───────────────────────────────────────────────────────
export interface RbacStats {
userCount: number;
activeUserCount: number;
groupCount: number;
maxGroupDepth: number;
roleCount: number;
}
export function useRbacStats() {
return useQuery({
queryKey: ['admin', 'rbac', 'stats'],
queryFn: () => adminFetch<RbacStats>('/rbac/stats'),
});
}
// ── User Query Hooks ───────────────────────────────────────────────────
export function useUsers() {
return useQuery({
queryKey: ['admin', 'users'],
queryFn: () => adminFetch<UserDetail[]>('/users'),
});
}
export function useUser(userId: string | null) {
return useQuery({
queryKey: ['admin', 'users', userId],
queryFn: () => adminFetch<UserDetail>(`/users/${userId}`),
enabled: !!userId,
});
}
// ── Role Query Hooks ───────────────────────────────────────────────────
export function useRoles() {
return useQuery({
queryKey: ['admin', 'roles'],
queryFn: () => adminFetch<RoleDetail[]>('/roles'),
});
}
export function useRole(roleId: string | null) {
return useQuery({
queryKey: ['admin', 'roles', roleId],
queryFn: () => adminFetch<RoleDetail>(`/roles/${roleId}`),
enabled: !!roleId,
});
}
// ── Group Query Hooks ──────────────────────────────────────────────────
export function useGroups() {
return useQuery({
queryKey: ['admin', 'groups'],
queryFn: () => adminFetch<GroupDetail[]>('/groups'),
});
}
export function useGroup(groupId: string | null) {
return useQuery({
queryKey: ['admin', 'groups', groupId],
queryFn: () => adminFetch<GroupDetail>(`/groups/${groupId}`),
enabled: !!groupId,
});
}
// ── User Mutation Hooks ────────────────────────────────────────────────
export function useCreateUser() {
const qc = useQueryClient();
return useMutation({
mutationFn: (req: CreateUserRequest) =>
adminFetch<UserDetail>('/users', {
method: 'POST',
body: JSON.stringify(req),
}),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['admin', 'users'] });
},
});
}
export function useUpdateUser() {
const qc = useQueryClient();
return useMutation({
mutationFn: ({ userId, ...req }: UpdateUserRequest & { userId: string }) =>
adminFetch<void>(`/users/${userId}`, {
method: 'PUT',
body: JSON.stringify(req),
}),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['admin', 'users'] });
},
});
}
export function useDeleteUser() {
const qc = useQueryClient();
return useMutation({
mutationFn: (userId: string) =>
adminFetch<void>(`/users/${userId}`, { method: 'DELETE' }),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['admin', 'users'] });
},
});
}
export function useSetPassword() {
const qc = useQueryClient();
return useMutation({
mutationFn: async ({ userId, password }: { userId: string; password: string }) => {
await adminFetch(`/users/${userId}/password`, {
method: 'POST',
body: JSON.stringify({ password }),
});
},
onSuccess: () => qc.invalidateQueries({ queryKey: ['admin', 'users'] }),
});
}
export function useAssignRoleToUser() {
const qc = useQueryClient();
return useMutation({
mutationFn: ({ userId, roleId }: { userId: string; roleId: string }) =>
adminFetch<void>(`/users/${userId}/roles/${roleId}`, { method: 'POST' }),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['admin', 'users'] });
qc.invalidateQueries({ queryKey: ['admin', 'roles'] });
},
});
}
export function useRemoveRoleFromUser() {
const qc = useQueryClient();
return useMutation({
mutationFn: ({ userId, roleId }: { userId: string; roleId: string }) =>
adminFetch<void>(`/users/${userId}/roles/${roleId}`, { method: 'DELETE' }),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['admin', 'users'] });
qc.invalidateQueries({ queryKey: ['admin', 'roles'] });
},
});
}
export function useAddUserToGroup() {
const qc = useQueryClient();
return useMutation({
mutationFn: ({ userId, groupId }: { userId: string; groupId: string }) =>
adminFetch<void>(`/users/${userId}/groups/${groupId}`, { method: 'POST' }),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['admin', 'users'] });
qc.invalidateQueries({ queryKey: ['admin', 'groups'] });
},
});
}
export function useRemoveUserFromGroup() {
const qc = useQueryClient();
return useMutation({
mutationFn: ({ userId, groupId }: { userId: string; groupId: string }) =>
adminFetch<void>(`/users/${userId}/groups/${groupId}`, { method: 'DELETE' }),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['admin', 'users'] });
qc.invalidateQueries({ queryKey: ['admin', 'groups'] });
},
});
}
// ── Role Mutation Hooks ────────────────────────────────────────────────
export function useCreateRole() {
const qc = useQueryClient();
return useMutation({
mutationFn: (req: CreateRoleRequest) =>
adminFetch<{ id: string }>('/roles', {
method: 'POST',
body: JSON.stringify(req),
}),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['admin', 'roles'] });
},
});
}
export function useUpdateRole() {
const qc = useQueryClient();
return useMutation({
mutationFn: ({ id, ...req }: UpdateRoleRequest & { id: string }) =>
adminFetch<void>(`/roles/${id}`, {
method: 'PUT',
body: JSON.stringify(req),
}),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['admin', 'roles'] });
},
});
}
export function useDeleteRole() {
const qc = useQueryClient();
return useMutation({
mutationFn: (id: string) =>
adminFetch<void>(`/roles/${id}`, { method: 'DELETE' }),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['admin', 'roles'] });
},
});
}
// ── Group Mutation Hooks ───────────────────────────────────────────────
export function useCreateGroup() {
const qc = useQueryClient();
return useMutation({
mutationFn: (req: CreateGroupRequest) =>
adminFetch<{ id: string }>('/groups', {
method: 'POST',
body: JSON.stringify(req),
}),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['admin', 'groups'] });
},
});
}
export function useUpdateGroup() {
const qc = useQueryClient();
return useMutation({
mutationFn: ({ id, ...req }: UpdateGroupRequest & { id: string }) =>
adminFetch<void>(`/groups/${id}`, {
method: 'PUT',
body: JSON.stringify(req),
}),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['admin', 'groups'] });
},
});
}
export function useDeleteGroup() {
const qc = useQueryClient();
return useMutation({
mutationFn: (id: string) =>
adminFetch<void>(`/groups/${id}`, { method: 'DELETE' }),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['admin', 'groups'] });
},
});
}
export function useAssignRoleToGroup() {
const qc = useQueryClient();
return useMutation({
mutationFn: ({ groupId, roleId }: { groupId: string; roleId: string }) =>
adminFetch<void>(`/groups/${groupId}/roles/${roleId}`, { method: 'POST' }),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['admin', 'groups'] });
qc.invalidateQueries({ queryKey: ['admin', 'roles'] });
},
});
}
export function useRemoveRoleFromGroup() {
const qc = useQueryClient();
return useMutation({
mutationFn: ({ groupId, roleId }: { groupId: string; roleId: string }) =>
adminFetch<void>(`/groups/${groupId}/roles/${roleId}`, { method: 'DELETE' }),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['admin', 'groups'] });
qc.invalidateQueries({ queryKey: ['admin', 'roles'] });
},
});
}