diff --git a/frontend/src/hooks/api/index.tsx b/frontend/src/hooks/api/index.tsx index 48d85c285..8ea1985df 100644 --- a/frontend/src/hooks/api/index.tsx +++ b/frontend/src/hooks/api/index.tsx @@ -12,6 +12,7 @@ export * from "./integrations"; export * from "./keys"; export * from "./ldapConfig"; export * from "./organization"; +export * from "./projectUserAdditionalPrivilege"; export * from "./roles"; export * from "./scim"; export * from "./secretApproval"; diff --git a/frontend/src/hooks/api/projectUserAdditionalPrivilege/index.tsx b/frontend/src/hooks/api/projectUserAdditionalPrivilege/index.tsx new file mode 100644 index 000000000..53512c52b --- /dev/null +++ b/frontend/src/hooks/api/projectUserAdditionalPrivilege/index.tsx @@ -0,0 +1,7 @@ +export { + useCreateProjectUserAdditionalPrivilege, + useDeleteProjectUserAdditionalPrivilege, + useUpdateProjectUserAdditionalPrivilege +} from "./mutation"; +export { useGetProjectUserPrivilegeDetails } from "./queries"; +export type { TProjectUserPrivilege } from "./types"; diff --git a/frontend/src/hooks/api/projectUserAdditionalPrivilege/mutation.tsx b/frontend/src/hooks/api/projectUserAdditionalPrivilege/mutation.tsx new file mode 100644 index 000000000..135920e0e --- /dev/null +++ b/frontend/src/hooks/api/projectUserAdditionalPrivilege/mutation.tsx @@ -0,0 +1,62 @@ +import { packRules } from "@casl/ability/extra"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; + +import { apiRequest } from "@app/config/request"; + +import { workspaceKeys } from "../workspace/queries"; +import { + TCreateProjectUserPrivilegeDTO, + TDeleteProjectUserPrivilegeDTO, + TProjectUserPrivilege, + TUpdateProjectUserPrivlegeDTO +} from "./types"; + +export const useCreateProjectUserAdditionalPrivilege = () => { + const queryClient = useQueryClient(); + + return useMutation<{ privilege: TProjectUserPrivilege }, {}, TCreateProjectUserPrivilegeDTO>({ + mutationFn: async (dto) => { + const { data } = await apiRequest.post("/api/v1/additional-privilege/users", { + ...dto, + permissions: packRules(dto.permissions) + }); + return data.privilege; + }, + onSuccess: (_, { workspaceId }) => { + queryClient.invalidateQueries(workspaceKeys.getWorkspaceUsers(workspaceId)); + } + }); +}; + +export const useUpdateProjectUserAdditionalPrivilege = () => { + const queryClient = useQueryClient(); + + return useMutation<{ privilege: TProjectUserPrivilege }, {}, TUpdateProjectUserPrivlegeDTO>({ + mutationFn: async (dto) => { + const { data } = await apiRequest.patch( + `/api/v1/additional-privilege/users/${dto.privilegeId}`, + { ...dto, permissions: dto.permissions ? packRules(dto.permissions) : undefined } + ); + return data.privilege; + }, + onSuccess: (_, { workspaceId }) => { + queryClient.invalidateQueries(workspaceKeys.getWorkspaceUsers(workspaceId)); + } + }); +}; + +export const useDeleteProjectUserAdditionalPrivilege = () => { + const queryClient = useQueryClient(); + + return useMutation<{ privilege: TProjectUserPrivilege }, {}, TDeleteProjectUserPrivilegeDTO>({ + mutationFn: async (dto) => { + const { data } = await apiRequest.delete( + `/api/v1/additional-privilege/users/${dto.privilegeId}` + ); + return data.privilege; + }, + onSuccess: (_, { workspaceId }) => { + queryClient.invalidateQueries(workspaceKeys.getWorkspaceUsers(workspaceId)); + } + }); +}; diff --git a/frontend/src/hooks/api/projectUserAdditionalPrivilege/queries.tsx b/frontend/src/hooks/api/projectUserAdditionalPrivilege/queries.tsx new file mode 100644 index 000000000..1f814d411 --- /dev/null +++ b/frontend/src/hooks/api/projectUserAdditionalPrivilege/queries.tsx @@ -0,0 +1,31 @@ +import { PackRule, unpackRules } from "@casl/ability/extra"; +import { useQuery } from "@tanstack/react-query"; + +import { apiRequest } from "@app/config/request"; + +import { TProjectPermission } from "../roles/types"; +import { TProjectUserPrivilege } from "./types"; + +export const projectUserPrivilegeKeys = { + details: (privilegeId: string) => ["project-user-privilege", { privilegeId }] as const +}; + +const fetchProjectUserPrivilegeDetails = async (privilegeId: string) => { + const { + data: { privilege } + } = await apiRequest.get<{ + privilege: Omit & { permissions: unknown }; + }>(`/api/v1/additional-privilege/users/${privilegeId}`); + return { + ...privilege, + permissions: unpackRules(privilege.permissions as PackRule[]) + }; +}; + +export const useGetProjectUserPrivilegeDetails = (privilegeId: string) => { + return useQuery({ + enabled: Boolean(privilegeId), + queryKey: projectUserPrivilegeKeys.details(privilegeId), + queryFn: () => fetchProjectUserPrivilegeDetails(privilegeId) + }); +}; diff --git a/frontend/src/hooks/api/projectUserAdditionalPrivilege/types.tsx b/frontend/src/hooks/api/projectUserAdditionalPrivilege/types.tsx new file mode 100644 index 000000000..c8e78db43 --- /dev/null +++ b/frontend/src/hooks/api/projectUserAdditionalPrivilege/types.tsx @@ -0,0 +1,48 @@ +import { TProjectPermission } from "../roles/types"; + +export enum ProjectUserAdditionalPrivilegeTemporaryMode { + Relative = "relative" +} + +export type TProjectUserPrivilege = { + projectMembershipId: string; + slug: string; + name: string; + isTemporary: boolean; + id: string; + createdAt: Date; + updatedAt: Date; + description?: string | null | undefined; + temporaryMode?: string | null | undefined; + temporaryRange?: string | null | undefined; + temporaryAccessStartTime?: string | null | undefined; + temporaryAccessEndTime?: Date | null | undefined; + permissions?: TProjectPermission[]; +}; + +export type TCreateProjectUserPrivilegeDTO = { + projectMembershipId: string; + slug: string; + name: string; + workspaceId: string; + description?: string; + isTemporary?: boolean; + temporaryMode?: ProjectUserAdditionalPrivilegeTemporaryMode; + temporaryRange?: string; + temporaryAccessStartTime?: string; + permissions: TProjectPermission[]; +}; + +export type TUpdateProjectUserPrivlegeDTO = { + privilegeId: string; + workspaceId: string; +} & Partial>; + +export type TDeleteProjectUserPrivilegeDTO = { + privilegeId: string; + workspaceId: string; +}; + +export type TGetProejctUserPrivilegeDetails = { + privilegeId: string; +}; diff --git a/frontend/src/hooks/api/users/types.ts b/frontend/src/hooks/api/users/types.ts index edc3bdf9e..326bb71c0 100644 --- a/frontend/src/hooks/api/users/types.ts +++ b/frontend/src/hooks/api/users/types.ts @@ -76,6 +76,18 @@ export type TWorkspaceUser = { }; inviteEmail: string; organization: string; + additionalPrivileges: { + id: string; + name: string; + description: string | null | undefined; + slug: string; + temporaryRange: string | null | undefined; + temporaryMode: string | null | undefined; + temporaryAccessEndTime: string | null | undefined; + temporaryAccessStartTime: string | null | undefined; + isTemporary: boolean; + createdAt: string; + }[]; roles: { id: string; role: "owner" | "admin" | "member" | "no-access" | "custom"; diff --git a/frontend/src/hooks/api/workspace/queries.tsx b/frontend/src/hooks/api/workspace/queries.tsx index 001454233..30e341a6a 100644 --- a/frontend/src/hooks/api/workspace/queries.tsx +++ b/frontend/src/hooks/api/workspace/queries.tsx @@ -315,6 +315,13 @@ export const useGetWorkspaceUsers = (workspaceId: string) => { ); return users; }, + select: (data) => + data.map((el) => ({ + ...el, + additionalPrivileges: el.additionalPrivileges.sort((a, b) => + a.createdAt.localeCompare(b.createdAt) + ) + })), enabled: true }); };