From 5eb67aefaeb2c0fd05f210137eb72a10c54e7708 Mon Sep 17 00:00:00 2001 From: = Date: Tue, 11 Nov 2025 13:56:20 +0530 Subject: [PATCH] feat: updated frontend with the new endpoints for project identity memberships --- .../v1/identity-project-membership-router.ts | 6 +-- backend/src/server/routes/v1/index.ts | 4 +- frontend/src/hooks/api/identities/queries.tsx | 4 +- frontend/src/hooks/api/identities/types.ts | 42 ++++++++++++++++++- .../projectIdentityMembership/mutations.tsx | 6 +-- .../api/projectIdentityMembership/queries.ts | 20 ++++----- .../IdentityProjectRow.tsx | 4 +- .../components/ProjectLinkIdentityModal.tsx | 2 +- .../IdentityDetailsByIDPage.tsx | 20 +++++++++ ...ntityProjectAdditionalPrivilegeSection.tsx | 4 +- .../IdentityRoleDetailsSection.tsx | 4 +- .../IdentityRoleModify.tsx | 4 +- .../ProjectIdentityDetailsSection.tsx | 4 +- 13 files changed, 91 insertions(+), 33 deletions(-) diff --git a/backend/src/server/routes/v1/identity-project-membership-router.ts b/backend/src/server/routes/v1/identity-project-membership-router.ts index 3ac43efe4..74ffdb39b 100644 --- a/backend/src/server/routes/v1/identity-project-membership-router.ts +++ b/backend/src/server/routes/v1/identity-project-membership-router.ts @@ -7,13 +7,13 @@ import { ProjectMembershipRole, TemporaryPermissionMode } from "@app/db/schemas"; +import { EventType } from "@app/ee/services/audit-log/audit-log-types"; import { ApiDocsTags, PROJECT_IDENTITIES, PROJECT_IDENTITY_MEMBERSHIP } from "@app/lib/api-docs"; import { BadRequestError } from "@app/lib/errors"; import { ms } from "@app/lib/ms"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; -import { EventType } from "@app/ee/services/audit-log/audit-log-types"; export const registerIdentityProjectMembershipRouter = async (server: FastifyZodProvider) => { server.route({ @@ -289,7 +289,7 @@ export const registerIdentityProjectMembershipRouter = async (server: FastifyZod limit: z.coerce .number() .min(1) - .max(100) + .max(1000) .default(20) .describe(PROJECT_IDENTITY_MEMBERSHIP.LIST_IDENTITY_MEMBERSHIPS.limit) .optional(), @@ -456,7 +456,7 @@ export const registerIdentityProjectMembershipRouter = async (server: FastifyZod limit: z.coerce .number() .min(1) - .max(100) + .max(1000) .default(20) .describe(PROJECT_IDENTITY_MEMBERSHIP.LIST_AVAILABLE_IDENTITIES.limit) .optional(), diff --git a/backend/src/server/routes/v1/index.ts b/backend/src/server/routes/v1/index.ts index 4fb7a5d93..b480a5144 100644 --- a/backend/src/server/routes/v1/index.ts +++ b/backend/src/server/routes/v1/index.ts @@ -14,6 +14,7 @@ import { CERTIFICATE_AUTHORITY_REGISTER_ROUTER_MAP } from "./certificate-authori import { registerCertificateProfilesRouter } from "./certificate-profiles-router"; import { registerCertRouter } from "./certificate-router"; import { registerCertificateTemplateRouter } from "./certificate-template-router"; +import { registerDeprecatedIdentityProjectMembershipRouter } from "./deprecated-identity-project-membership-router"; import { registerDeprecatedProjectEnvRouter } from "./deprecated-project-env-router"; import { registerDeprecatedProjectMembershipRouter } from "./deprecated-project-membership-router"; import { registerDeprecatedProjectRouter } from "./deprecated-project-router"; @@ -34,7 +35,7 @@ import { registerIdentityLdapAuthRouter } from "./identity-ldap-auth-router"; import { registerIdentityOciAuthRouter } from "./identity-oci-auth-router"; import { registerIdentityOidcAuthRouter } from "./identity-oidc-auth-router"; import { registerIdentityOrgMembershipRouter } from "./identity-org-membership-router"; -import { registerDeprecatedIdentityProjectMembershipRouter } from "./deprecated-identity-project-membership-router"; +import { registerIdentityProjectMembershipRouter } from "./identity-project-membership-router"; import { registerIdentityRouter } from "./identity-router"; import { registerIdentityTlsCertAuthRouter } from "./identity-tls-cert-auth-router"; import { registerIdentityTokenAuthRouter } from "./identity-token-auth-router"; @@ -69,7 +70,6 @@ import { registerUserEngagementRouter } from "./user-engagement-router"; import { registerUserRouter } from "./user-router"; import { registerWebhookRouter } from "./webhook-router"; import { registerWorkflowIntegrationRouter } from "./workflow-integration-router"; -import { registerIdentityProjectMembershipRouter } from "./identity-project-membership-router"; export const registerV1Routes = async (server: FastifyZodProvider) => { await server.register(registerSsoRouter, { prefix: "/sso" }); diff --git a/frontend/src/hooks/api/identities/queries.tsx b/frontend/src/hooks/api/identities/queries.tsx index dae668624..866bcac80 100644 --- a/frontend/src/hooks/api/identities/queries.tsx +++ b/frontend/src/hooks/api/identities/queries.tsx @@ -16,7 +16,7 @@ import { IdentityMembershipOrg, IdentityOciAuth, IdentityOidcAuth, - IdentityProjectMembership, + IdentityProjectMembershipV1, IdentityTlsCertAuth, IdentityTokenAuth, IdentityUniversalAuth, @@ -95,7 +95,7 @@ export const useGetIdentityProjectMemberships = (identityId: string) => { queryFn: async () => { const { data: { identityMemberships } - } = await apiRequest.get<{ identityMemberships: IdentityProjectMembership[] }>( + } = await apiRequest.get<{ identityMemberships: IdentityProjectMembershipV1[] }>( `/api/v1/identities/${identityId}/identity-memberships` ); return identityMemberships; diff --git a/frontend/src/hooks/api/identities/types.ts b/frontend/src/hooks/api/identities/types.ts index cdf05e621..4a0f91f09 100644 --- a/frontend/src/hooks/api/identities/types.ts +++ b/frontend/src/hooks/api/identities/types.ts @@ -56,7 +56,7 @@ export type IdentityMembershipOrg = { updatedAt: string; }; -export type IdentityProjectMembership = { +export type IdentityProjectMembershipV1 = { id: string; identity: Identity; project: Pick; @@ -90,6 +90,39 @@ export type IdentityProjectMembership = { lastLoginAuthMethod?: IdentityAuthMethod; }; +export type IdentityProjectMembershipV2 = { + id: string; + identity: Identity; + roles: Array< + { + id: string; + role: "owner" | "admin" | "member" | "no-access" | "custom"; + customRoleId: string; + customRoleName: string; + customRoleSlug: string; + } & ( + | { + isTemporary: false; + temporaryRange: null; + temporaryMode: null; + temporaryAccessEndTime: null; + temporaryAccessStartTime: null; + } + | { + isTemporary: true; + temporaryRange: string; + temporaryMode: TemporaryPermissionMode; + temporaryAccessEndTime: string; + temporaryAccessStartTime: string; + } + ) + >; + createdAt: string; + updatedAt: string; + lastLoginTime?: string; + lastLoginAuthMethod?: IdentityAuthMethod; +}; + export type CreateIdentityDTO = { name: string; organizationId: string; @@ -828,7 +861,12 @@ export type RevokeTokenRes = { }; export type TProjectIdentityMembershipsList = { - identityMemberships: IdentityProjectMembership[]; + identityMemberships: IdentityProjectMembershipV1[]; + totalCount: number; +}; + +export type TProjectIdentityMembershipsListV2 = { + identityMemberships: IdentityProjectMembershipV2[]; totalCount: number; }; diff --git a/frontend/src/hooks/api/projectIdentityMembership/mutations.tsx b/frontend/src/hooks/api/projectIdentityMembership/mutations.tsx index 053d44a54..54b9158de 100644 --- a/frontend/src/hooks/api/projectIdentityMembership/mutations.tsx +++ b/frontend/src/hooks/api/projectIdentityMembership/mutations.tsx @@ -18,7 +18,7 @@ export const useCreateProjectIdentityMembership = () => { const { data: { identityMembership } } = await apiRequest.post<{ identityMembership: TProjectIdentityMembership }>( - `/api/v1/projects/${projectId}/identity-memberships/${identityId}`, + `/api/v1/projects/${projectId}/memberships/identities/${identityId}`, { role } @@ -49,7 +49,7 @@ export const useUpdateProjectIdentityMembership = () => { const { data: { identityMembership } } = await apiRequest.patch<{ identityMembership: TProjectIdentityMembership }>( - `/api/v1/projects/${projectId}/identity-memberships/${identityId}`, + `/api/v1/projects/${projectId}/memberships/identities/${identityId}`, updates ); return identityMembership; @@ -76,7 +76,7 @@ export const useDeleteProjectIdentityMembership = () => { const { data: { identityMembership } } = await apiRequest.delete<{ identityMembership: TProjectIdentityMembership }>( - `/api/v1/projects/${projectId}/identity-memberships/${identityId}` + `/api/v1/projects/${projectId}/memberships/identities/${identityId}` ); return identityMembership; }, diff --git a/frontend/src/hooks/api/projectIdentityMembership/queries.ts b/frontend/src/hooks/api/projectIdentityMembership/queries.ts index 80b68db6c..3f67f3fbf 100644 --- a/frontend/src/hooks/api/projectIdentityMembership/queries.ts +++ b/frontend/src/hooks/api/projectIdentityMembership/queries.ts @@ -8,8 +8,8 @@ import { } from "@app/hooks/api"; import { OrderByDirection } from "@app/hooks/api/generic/types"; import { - IdentityProjectMembership, - TProjectIdentityMembershipsList + IdentityProjectMembershipV1, + TProjectIdentityMembershipsListV2 } from "@app/hooks/api/identities/types"; import { ProjectIdentityOrderBy, TListProjectIdentitiesDTO } from "@app/hooks/api/projects/types"; @@ -23,7 +23,7 @@ export const projectIdentityMembershipQuery = { queryFn: async () => { const { data } = await apiRequest.get<{ identities: TAvailableProjectIdentities; - }>(`/api/v1/projects/${params.projectId}/available-identities`, { + }>(`/api/v1/projects/${params.projectId}/memberships/available-identities`, { params: { offset: params.offset, limit: params.limit, @@ -48,9 +48,9 @@ export const useListProjectIdentityMemberships = ( }: TListProjectIdentitiesDTO, options?: Omit< UseQueryOptions< - TProjectIdentityMembershipsList, + TProjectIdentityMembershipsListV2, unknown, - TProjectIdentityMembershipsList, + TProjectIdentityMembershipsListV2, ReturnType >, "queryKey" | "queryFn" @@ -74,8 +74,8 @@ export const useListProjectIdentityMemberships = ( search: String(search) }); - const { data } = await apiRequest.get( - `/api/v1/projects/${projectId}/identity-memberships`, + const { data } = await apiRequest.get( + `/api/v1/projects/${projectId}/memberships/identities`, { params } ); return data; @@ -92,7 +92,7 @@ export const useGetProjectIdentityMembership = (projectId: string, identityId: s queryFn: async () => { const { data: { identityMembership } - } = await apiRequest.get<{ identityMembership: IdentityProjectMembership }>( + } = await apiRequest.get<{ identityMembership: IdentityProjectMembershipV1 }>( `/api/v1/projects/${projectId}/identity-memberships/${identityId}` ); return identityMembership; @@ -107,8 +107,8 @@ export const useGetProjectIdentityMembershipV2 = (projectId: string, identityId: queryFn: async () => { const { data: { identityMembership } - } = await apiRequest.get<{ identityMembership: IdentityProjectMembership }>( - `/api/v2/projects/${projectId}/identity-memberships/${identityId}` + } = await apiRequest.get<{ identityMembership: IdentityProjectMembershipV1 }>( + `/api/v1/projects/${projectId}/memberships/identities/${identityId}` ); return identityMembership; } diff --git a/frontend/src/pages/organization/IdentityDetailsByIDPage/components/IdentityProjectsSection/IdentityProjectRow.tsx b/frontend/src/pages/organization/IdentityDetailsByIDPage/components/IdentityProjectsSection/IdentityProjectRow.tsx index 431986990..6bb25e2c1 100644 --- a/frontend/src/pages/organization/IdentityDetailsByIDPage/components/IdentityProjectsSection/IdentityProjectRow.tsx +++ b/frontend/src/pages/organization/IdentityDetailsByIDPage/components/IdentityProjectsSection/IdentityProjectRow.tsx @@ -9,7 +9,7 @@ import { IconButton, Td, Tooltip, Tr } from "@app/components/v2"; import { getProjectBaseURL } from "@app/helpers/project"; import { formatProjectRoleName } from "@app/helpers/roles"; import { useGetUserProjects } from "@app/hooks/api"; -import { IdentityProjectMembership } from "@app/hooks/api/identities/types"; +import { IdentityProjectMembershipV1 } from "@app/hooks/api/identities/types"; import { UsePopUpState } from "@app/hooks/usePopUp"; export enum TabSections { @@ -20,7 +20,7 @@ export enum TabSections { } type Props = { - membership: IdentityProjectMembership; + membership: IdentityProjectMembershipV1; handlePopUpOpen: ( popUpName: keyof UsePopUpState<["removeIdentityFromProject"]>, data?: object diff --git a/frontend/src/pages/project/AccessControlPage/components/IdentityTab/components/ProjectLinkIdentityModal.tsx b/frontend/src/pages/project/AccessControlPage/components/IdentityTab/components/ProjectLinkIdentityModal.tsx index 20629d46d..46e910432 100644 --- a/frontend/src/pages/project/AccessControlPage/components/IdentityTab/components/ProjectLinkIdentityModal.tsx +++ b/frontend/src/pages/project/AccessControlPage/components/IdentityTab/components/ProjectLinkIdentityModal.tsx @@ -47,7 +47,7 @@ export const ProjectLinkIdentityModal = ({ handlePopUpToggle }: Props) => { const { data: identityMembershipsData } = useListProjectIdentityMemberships({ projectId, - limit: 20000 // TODO: this is temp to preserve functionality for larger projects, will optimize in PR referenced above + limit: 1000 // TODO: this is temp to preserve functionality for larger projects, will optimize in PR referenced above }); const identityMemberships = identityMembershipsData?.identityMemberships; diff --git a/frontend/src/pages/project/IdentityDetailsByIDPage/IdentityDetailsByIDPage.tsx b/frontend/src/pages/project/IdentityDetailsByIDPage/IdentityDetailsByIDPage.tsx index 9137021ff..1690e3637 100644 --- a/frontend/src/pages/project/IdentityDetailsByIDPage/IdentityDetailsByIDPage.tsx +++ b/frontend/src/pages/project/IdentityDetailsByIDPage/IdentityDetailsByIDPage.tsx @@ -10,6 +10,8 @@ import { formatRelative } from "date-fns"; import { createNotification } from "@app/components/notifications"; import { ProjectPermissionCan } from "@app/components/permissions"; import { + Alert, + AlertDescription, Button, ConfirmActionModal, DeleteActionModal, @@ -147,6 +149,7 @@ const Page = () => { scope={currentProject.type} title={identityMembershipDetails?.identity?.name} description={`Identity ${isProjectIdentity ? "created" : "added"} on ${identityMembershipDetails?.createdAt && formatRelative(new Date(identityMembershipDetails?.createdAt || ""), new Date())}`} + className={!isProjectIdentity ? "mb-4" : undefined} >
+ {!isProjectIdentity && ( + + + This identity is managed by your organization.{" "} + + + Click here to retrieve credentials. + + + + + )}
{identity ? (
diff --git a/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityProjectAdditionalPrivilegeSection/IdentityProjectAdditionalPrivilegeSection.tsx b/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityProjectAdditionalPrivilegeSection/IdentityProjectAdditionalPrivilegeSection.tsx index f8960d72c..b11bd9dae 100644 --- a/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityProjectAdditionalPrivilegeSection/IdentityProjectAdditionalPrivilegeSection.tsx +++ b/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityProjectAdditionalPrivilegeSection/IdentityProjectAdditionalPrivilegeSection.tsx @@ -31,13 +31,13 @@ import { } from "@app/context"; import { usePopUp } from "@app/hooks"; import { useDeleteIdentityProjectAdditionalPrivilege } from "@app/hooks/api"; -import { IdentityProjectMembership } from "@app/hooks/api/identities/types"; +import { IdentityProjectMembershipV1 } from "@app/hooks/api/identities/types"; import { useListIdentityProjectPrivileges } from "@app/hooks/api/identityProjectAdditionalPrivilege/queries"; import { IdentityProjectAdditionalPrivilegeModifySection } from "./IdentityProjectAdditionalPrivilegeModifySection"; type Props = { - identityMembershipDetails: IdentityProjectMembership; + identityMembershipDetails: IdentityProjectMembershipV1; }; export const IdentityProjectAdditionalPrivilegeSection = ({ identityMembershipDetails }: Props) => { diff --git a/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityRoleDetailsSection/IdentityRoleDetailsSection.tsx b/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityRoleDetailsSection/IdentityRoleDetailsSection.tsx index f96218bb5..507a83a56 100644 --- a/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityRoleDetailsSection/IdentityRoleDetailsSection.tsx +++ b/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityRoleDetailsSection/IdentityRoleDetailsSection.tsx @@ -27,13 +27,13 @@ import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app import { formatProjectRoleName } from "@app/helpers/roles"; import { usePopUp } from "@app/hooks"; import { useUpdateProjectIdentityMembership } from "@app/hooks/api"; -import { IdentityProjectMembership } from "@app/hooks/api/identities/types"; +import { IdentityProjectMembershipV1 } from "@app/hooks/api/identities/types"; import { TProjectRole } from "@app/hooks/api/roles/types"; import { IdentityRoleModify } from "./IdentityRoleModify"; type Props = { - identityMembershipDetails: IdentityProjectMembership; + identityMembershipDetails: IdentityProjectMembershipV1; isMembershipDetailsLoading?: boolean; }; diff --git a/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityRoleDetailsSection/IdentityRoleModify.tsx b/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityRoleDetailsSection/IdentityRoleModify.tsx index 38a1c8c5a..6216e1321 100644 --- a/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityRoleDetailsSection/IdentityRoleModify.tsx +++ b/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityRoleDetailsSection/IdentityRoleModify.tsx @@ -33,7 +33,7 @@ import { useProjectPermission } from "@app/context"; import { useGetProjectRoles, useUpdateProjectIdentityMembership } from "@app/hooks/api"; -import { IdentityProjectMembership } from "@app/hooks/api/identities/types"; +import { IdentityProjectMembershipV1 } from "@app/hooks/api/identities/types"; import { ProjectMembershipRole } from "@app/hooks/api/roles/types"; import { TemporaryPermissionMode } from "@app/hooks/api/shared"; @@ -58,7 +58,7 @@ const roleFormSchema = z.object({ type TRoleForm = z.infer; type Props = { - identityProjectMembership: IdentityProjectMembership; + identityProjectMembership: IdentityProjectMembershipV1; }; export const IdentityRoleModify = ({ identityProjectMembership }: Props) => { diff --git a/frontend/src/pages/project/IdentityDetailsByIDPage/components/ProjectIdentityDetailsSection.tsx b/frontend/src/pages/project/IdentityDetailsByIDPage/components/ProjectIdentityDetailsSection.tsx index 1c29ddde5..dae996489 100644 --- a/frontend/src/pages/project/IdentityDetailsByIDPage/components/ProjectIdentityDetailsSection.tsx +++ b/frontend/src/pages/project/IdentityDetailsByIDPage/components/ProjectIdentityDetailsSection.tsx @@ -31,13 +31,13 @@ import { ProjectPermissionIdentityActions, ProjectPermissionSub, useProject } fr import { getProjectBaseURL } from "@app/helpers/project"; import { usePopUp, useTimedReset } from "@app/hooks"; import { identityAuthToNameMap, TProjectIdentity, useDeleteProjectIdentity } from "@app/hooks/api"; -import { IdentityProjectMembership } from "@app/hooks/api/identities/types"; +import { IdentityProjectMembershipV1 } from "@app/hooks/api/identities/types"; import { ProjectIdentityModal } from "@app/pages/project/AccessControlPage/components/IdentityTab/components/ProjectIdentityModal"; type Props = { identity: TProjectIdentity; isOrgIdentity?: boolean; - membership: IdentityProjectMembership; + membership: IdentityProjectMembershipV1; }; export const ProjectIdentityDetailsSection = ({ identity, isOrgIdentity, membership }: Props) => {