feat: updated frontend with the new endpoints for project identity

memberships
This commit is contained in:
=
2025-11-11 13:56:20 +05:30
parent 3d69d48835
commit 5eb67aefae
13 changed files with 91 additions and 33 deletions

View File

@@ -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(),

View File

@@ -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" });

View File

@@ -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;

View File

@@ -56,7 +56,7 @@ export type IdentityMembershipOrg = {
updatedAt: string;
};
export type IdentityProjectMembership = {
export type IdentityProjectMembershipV1 = {
id: string;
identity: Identity;
project: Pick<Project, "id" | "name" | "type">;
@@ -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;
};

View File

@@ -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;
},

View File

@@ -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<typeof projectKeys.getProjectIdentityMembershipsWithParams>
>,
"queryKey" | "queryFn"
@@ -74,8 +74,8 @@ export const useListProjectIdentityMemberships = (
search: String(search)
});
const { data } = await apiRequest.get<TProjectIdentityMembershipsList>(
`/api/v1/projects/${projectId}/identity-memberships`,
const { data } = await apiRequest.get<TProjectIdentityMembershipsListV2>(
`/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;
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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}
>
<div className="flex items-center gap-2">
<Button
@@ -207,6 +210,23 @@ const Page = () => {
)}
</div>
</PageHeader>
{!isProjectIdentity && (
<Alert hideTitle className="mb-4 border-primary/50 bg-primary/10">
<AlertDescription>
This identity is managed by your organization.{" "}
<Link
to="/organization/identities/$identityId"
params={{
identityId
}}
>
<span className="cursor-pointer text-primary underline underline-offset-2">
Click here to retrieve credentials.
</span>
</Link>
</AlertDescription>
</Alert>
)}
<div className="flex gap-x-4">
{identity ? (
<div className="flex w-72 flex-col gap-y-4">

View File

@@ -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) => {

View File

@@ -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;
};

View File

@@ -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<typeof roleFormSchema>;
type Props = {
identityProjectMembership: IdentityProjectMembership;
identityProjectMembership: IdentityProjectMembershipV1;
};
export const IdentityRoleModify = ({ identityProjectMembership }: Props) => {

View File

@@ -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) => {