mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-10 09:28:36 +00:00
feat: complete project identities
This commit is contained in:
@@ -78,7 +78,11 @@ export enum ProjectPermissionIdentityActions {
|
||||
Edit = "edit",
|
||||
Delete = "delete",
|
||||
GrantPrivileges = "grant-privileges",
|
||||
AssumePrivileges = "assume-privileges"
|
||||
AssumePrivileges = "assume-privileges",
|
||||
RevokeAuth = "revoke-auth",
|
||||
CreateToken = "create-token",
|
||||
GetToken = "get-token",
|
||||
DeleteToken = "delete-token"
|
||||
}
|
||||
|
||||
export enum ProjectPermissionMemberActions {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
import { projectIdentityQuery, projectKeys } from "@app/hooks/api";
|
||||
|
||||
import { organizationKeys } from "../organization/queries";
|
||||
import { subscriptionQueryKeys } from "../subscriptions/queries";
|
||||
import { identitiesKeys } from "./queries";
|
||||
import {
|
||||
AddIdentityAliCloudAuthDTO,
|
||||
@@ -21,7 +21,6 @@ import {
|
||||
ClearIdentityLdapAuthLockoutsDTO,
|
||||
ClearIdentityUniversalAuthLockoutsDTO,
|
||||
ClientSecretData,
|
||||
CreateIdentityDTO,
|
||||
CreateIdentityUniversalAuthClientSecretDTO,
|
||||
CreateIdentityUniversalAuthClientSecretRes,
|
||||
CreateTokenIdentityTokenAuthDTO,
|
||||
@@ -29,7 +28,6 @@ import {
|
||||
DeleteIdentityAliCloudAuthDTO,
|
||||
DeleteIdentityAwsAuthDTO,
|
||||
DeleteIdentityAzureAuthDTO,
|
||||
DeleteIdentityDTO,
|
||||
DeleteIdentityGcpAuthDTO,
|
||||
DeleteIdentityJwtAuthDTO,
|
||||
DeleteIdentityKubernetesAuthDTO,
|
||||
@@ -40,7 +38,6 @@ import {
|
||||
DeleteIdentityTokenAuthDTO,
|
||||
DeleteIdentityUniversalAuthClientSecretDTO,
|
||||
DeleteIdentityUniversalAuthDTO,
|
||||
Identity,
|
||||
IdentityAccessToken,
|
||||
IdentityAliCloudAuth,
|
||||
IdentityAwsAuth,
|
||||
@@ -59,7 +56,6 @@ import {
|
||||
UpdateIdentityAliCloudAuthDTO,
|
||||
UpdateIdentityAwsAuthDTO,
|
||||
UpdateIdentityAzureAuthDTO,
|
||||
UpdateIdentityDTO,
|
||||
UpdateIdentityGcpAuthDTO,
|
||||
UpdateIdentityJwtAuthDTO,
|
||||
UpdateIdentityKubernetesAuthDTO,
|
||||
@@ -72,73 +68,6 @@ import {
|
||||
UpdateTokenIdentityTokenAuthDTO
|
||||
} from "./types";
|
||||
|
||||
export const useCreateIdentity = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<Identity, object, CreateIdentityDTO>({
|
||||
mutationFn: async (body) => {
|
||||
const {
|
||||
data: { identity }
|
||||
} = await apiRequest.post("/api/v1/identities/", body);
|
||||
return identity;
|
||||
},
|
||||
onSuccess: (_, { organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: subscriptionQueryKeys.getOrgSubsription(organizationId)
|
||||
});
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.searchIdentitiesRoot });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateIdentity = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<Identity, object, UpdateIdentityDTO>({
|
||||
mutationFn: async ({ identityId, name, role, hasDeleteProtection, metadata }) => {
|
||||
const {
|
||||
data: { identity }
|
||||
} = await apiRequest.patch(`/api/v1/identities/${identityId}`, {
|
||||
name,
|
||||
role,
|
||||
hasDeleteProtection,
|
||||
metadata
|
||||
});
|
||||
|
||||
return identity;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.searchIdentitiesRoot });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useDeleteIdentity = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<Identity, object, DeleteIdentityDTO>({
|
||||
mutationFn: async ({ identityId }) => {
|
||||
const {
|
||||
data: { identity }
|
||||
} = await apiRequest.delete(`/api/v1/identities/${identityId}`);
|
||||
return identity;
|
||||
},
|
||||
onSuccess: (_, { organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: subscriptionQueryKeys.getOrgSubsription(organizationId)
|
||||
});
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.searchIdentitiesRoot });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: move these to /auth
|
||||
|
||||
export const useAddIdentityUniversalAuth = () => {
|
||||
@@ -171,10 +100,20 @@ export const useAddIdentityUniversalAuth = () => {
|
||||
});
|
||||
return identityUniversalAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityUniversalAuth(identityId)
|
||||
@@ -215,10 +154,20 @@ export const useUpdateIdentityUniversalAuth = () => {
|
||||
});
|
||||
return identityUniversalAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityUniversalAuth(identityId)
|
||||
@@ -236,10 +185,20 @@ export const useDeleteIdentityUniversalAuth = () => {
|
||||
} = await apiRequest.delete(`/api/v1/auth/universal-auth/identities/${identityId}`);
|
||||
return identityUniversalAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { organizationId, identityId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityUniversalAuth(identityId)
|
||||
@@ -344,10 +303,20 @@ export const useAddIdentityGcpAuth = () => {
|
||||
|
||||
return identityGcpAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityGcpAuth(identityId) });
|
||||
}
|
||||
@@ -386,10 +355,20 @@ export const useUpdateIdentityGcpAuth = () => {
|
||||
|
||||
return identityGcpAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityGcpAuth(identityId) });
|
||||
}
|
||||
@@ -405,10 +384,20 @@ export const useDeleteIdentityGcpAuth = () => {
|
||||
} = await apiRequest.delete(`/api/v1/auth/gcp-auth/identities/${identityId}`);
|
||||
return identityGcpAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { organizationId, identityId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityGcpAuth(identityId) });
|
||||
}
|
||||
@@ -445,10 +434,20 @@ export const useAddIdentityAwsAuth = () => {
|
||||
|
||||
return identityAwsAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityAwsAuth(identityId) });
|
||||
}
|
||||
@@ -485,10 +484,20 @@ export const useUpdateIdentityAwsAuth = () => {
|
||||
|
||||
return identityAwsAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityAwsAuth(identityId) });
|
||||
}
|
||||
@@ -504,10 +513,20 @@ export const useDeleteIdentityAwsAuth = () => {
|
||||
} = await apiRequest.delete(`/api/v1/auth/aws-auth/identities/${identityId}`);
|
||||
return identityAwsAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { organizationId, identityId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityAwsAuth(identityId) });
|
||||
}
|
||||
@@ -542,10 +561,20 @@ export const useAddIdentityOciAuth = () => {
|
||||
|
||||
return identityOciAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityOciAuth(identityId) });
|
||||
}
|
||||
@@ -580,10 +609,20 @@ export const useUpdateIdentityOciAuth = () => {
|
||||
|
||||
return identityOciAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityOciAuth(identityId) });
|
||||
}
|
||||
@@ -599,10 +638,20 @@ export const useDeleteIdentityOciAuth = () => {
|
||||
} = await apiRequest.delete(`/api/v1/auth/oci-auth/identities/${identityId}`);
|
||||
return identityOciAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { organizationId, identityId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityOciAuth(identityId) });
|
||||
}
|
||||
@@ -635,10 +684,20 @@ export const useAddIdentityAliCloudAuth = () => {
|
||||
|
||||
return identityAliCloudAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityAliCloudAuth(identityId)
|
||||
@@ -673,10 +732,20 @@ export const useUpdateIdentityAliCloudAuth = () => {
|
||||
|
||||
return identityAliCloudAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityAliCloudAuth(identityId)
|
||||
@@ -694,10 +763,20 @@ export const useDeleteIdentityAliCloudAuth = () => {
|
||||
} = await apiRequest.delete(`/api/v1/auth/alicloud-auth/identities/${identityId}`);
|
||||
return identityAliCloudAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { organizationId, identityId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityAliCloudAuth(identityId)
|
||||
@@ -734,10 +813,20 @@ export const useAddIdentityTlsCertAuth = () => {
|
||||
|
||||
return identityTlsCertAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityTlsCertAuth(identityId)
|
||||
@@ -774,10 +863,20 @@ export const useUpdateIdentityTlsCertAuth = () => {
|
||||
|
||||
return identityTlsCertAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityTlsCertAuth(identityId)
|
||||
@@ -795,10 +894,20 @@ export const useDeleteIdentityTlsCertAuth = () => {
|
||||
} = await apiRequest.delete(`/api/v1/auth/tls-cert-auth/identities/${identityId}`);
|
||||
return identityTlsCertAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { organizationId, identityId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityTlsCertAuth(identityId)
|
||||
@@ -845,10 +954,20 @@ export const useUpdateIdentityOidcAuth = () => {
|
||||
|
||||
return identityOidcAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityOidcAuth(identityId) });
|
||||
}
|
||||
@@ -893,10 +1012,20 @@ export const useAddIdentityOidcAuth = () => {
|
||||
|
||||
return identityOidcAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityOidcAuth(identityId) });
|
||||
}
|
||||
@@ -912,10 +1041,20 @@ export const useDeleteIdentityOidcAuth = () => {
|
||||
} = await apiRequest.delete(`/api/v1/auth/oidc-auth/identities/${identityId}`);
|
||||
return identityOidcAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { organizationId, identityId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityOidcAuth(identityId) });
|
||||
}
|
||||
@@ -961,10 +1100,20 @@ export const useUpdateIdentityJwtAuth = () => {
|
||||
|
||||
return identityJwtAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityJwtAuth(identityId) });
|
||||
}
|
||||
@@ -1011,10 +1160,20 @@ export const useAddIdentityJwtAuth = () => {
|
||||
|
||||
return identityJwtAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityJwtAuth(identityId) });
|
||||
}
|
||||
@@ -1030,10 +1189,20 @@ export const useDeleteIdentityJwtAuth = () => {
|
||||
} = await apiRequest.delete(`/api/v1/auth/jwt-auth/identities/${identityId}`);
|
||||
return identityJwtAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { organizationId, identityId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityJwtAuth(identityId) });
|
||||
}
|
||||
@@ -1070,10 +1239,20 @@ export const useAddIdentityAzureAuth = () => {
|
||||
|
||||
return identityAzureAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityKubernetesAuth(identityId)
|
||||
@@ -1122,10 +1301,20 @@ export const useAddIdentityKubernetesAuth = () => {
|
||||
|
||||
return identityKubernetesAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityAzureAuth(identityId) });
|
||||
}
|
||||
@@ -1162,10 +1351,20 @@ export const useUpdateIdentityAzureAuth = () => {
|
||||
|
||||
return identityAzureAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityAzureAuth(identityId) });
|
||||
}
|
||||
@@ -1181,10 +1380,20 @@ export const useDeleteIdentityAzureAuth = () => {
|
||||
} = await apiRequest.delete(`/api/v1/auth/azure-auth/identities/${identityId}`);
|
||||
return identityAzureAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { organizationId, identityId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityAzureAuth(identityId) });
|
||||
}
|
||||
@@ -1231,10 +1440,20 @@ export const useUpdateIdentityKubernetesAuth = () => {
|
||||
|
||||
return identityKubernetesAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityKubernetesAuth(identityId)
|
||||
@@ -1252,10 +1471,20 @@ export const useDeleteIdentityKubernetesAuth = () => {
|
||||
} = await apiRequest.delete(`/api/v1/auth/kubernetes-auth/identities/${identityId}`);
|
||||
return identityKubernetesAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { organizationId, identityId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityKubernetesAuth(identityId)
|
||||
@@ -1288,10 +1517,20 @@ export const useAddIdentityTokenAuth = () => {
|
||||
|
||||
return identityTokenAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityTokenAuth(identityId)
|
||||
@@ -1324,10 +1563,20 @@ export const useUpdateIdentityTokenAuth = () => {
|
||||
|
||||
return identityTokenAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityTokenAuth(identityId)
|
||||
@@ -1345,10 +1594,20 @@ export const useDeleteIdentityTokenAuth = () => {
|
||||
} = await apiRequest.delete(`/api/v1/auth/token-auth/identities/${identityId}`);
|
||||
return identityTokenAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { organizationId, identityId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityTokenAuth(identityId) });
|
||||
}
|
||||
@@ -1462,10 +1721,20 @@ export const useAddIdentityLdapAuth = () => {
|
||||
);
|
||||
return data.identityLdapAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityLdapAuth(identityId)
|
||||
@@ -1519,10 +1788,20 @@ export const useUpdateIdentityLdapAuth = () => {
|
||||
);
|
||||
return data.identityLdapAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityLdapAuth(identityId)
|
||||
@@ -1538,10 +1817,20 @@ export const useDeleteIdentityLdapAuth = () => {
|
||||
const { data } = await apiRequest.delete(`/api/v1/auth/ldap-auth/identities/${identityId}`);
|
||||
return data.identityLdapAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { organizationId, identityId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityLdapAuth(identityId)
|
||||
|
||||
@@ -13,10 +13,10 @@ import {
|
||||
IdentityJwtAuth,
|
||||
IdentityKubernetesAuth,
|
||||
IdentityLdapAuth,
|
||||
IdentityMembership,
|
||||
IdentityMembershipOrg,
|
||||
IdentityOciAuth,
|
||||
IdentityOidcAuth,
|
||||
IdentityProjectMembership,
|
||||
IdentityTlsCertAuth,
|
||||
IdentityTokenAuth,
|
||||
IdentityUniversalAuth,
|
||||
@@ -52,7 +52,7 @@ export const identitiesKeys = {
|
||||
[{ identityId }, "identity-project-memberships"] as const
|
||||
};
|
||||
|
||||
export const useGetIdentityById = (identityId: string) => {
|
||||
export const useGetOrgIdentityMembershipById = (identityId: string) => {
|
||||
return useQuery({
|
||||
enabled: Boolean(identityId),
|
||||
queryKey: identitiesKeys.getIdentityById(identityId),
|
||||
@@ -67,7 +67,7 @@ export const useGetIdentityById = (identityId: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useSearchIdentities = (dto: TSearchIdentitiesDTO) => {
|
||||
export const useSearchOrgIdentityMemberships = (dto: TSearchIdentitiesDTO) => {
|
||||
const { limit, search, offset, orderBy, orderDirection } = dto;
|
||||
return useQuery({
|
||||
queryKey: identitiesKeys.searchIdentities(dto),
|
||||
@@ -95,7 +95,7 @@ export const useGetIdentityProjectMemberships = (identityId: string) => {
|
||||
queryFn: async () => {
|
||||
const {
|
||||
data: { identityMemberships }
|
||||
} = await apiRequest.get<{ identityMemberships: IdentityMembership[] }>(
|
||||
} = await apiRequest.get<{ identityMemberships: IdentityProjectMembership[] }>(
|
||||
`/api/v1/identities/${identityId}/identity-memberships`
|
||||
);
|
||||
return identityMemberships;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { TemporaryPermissionMode } from "@app/hooks/api/shared";
|
||||
|
||||
import { OrderByDirection } from "../generic/types";
|
||||
import { OrgIdentityOrderBy } from "../organization/types";
|
||||
import { Project, ProjectUserMembershipTemporaryMode } from "../projects/types";
|
||||
import { Project } from "../projects/types";
|
||||
import { TOrgRole } from "../roles/types";
|
||||
import { IdentityAuthMethod, IdentityJwtConfigurationType } from "./enums";
|
||||
|
||||
@@ -21,6 +23,8 @@ export type Identity = {
|
||||
updatedAt: string;
|
||||
isInstanceAdmin?: boolean;
|
||||
orgId: string;
|
||||
projectId?: string | null;
|
||||
metadata?: { key: string; value: string; id: string }[];
|
||||
};
|
||||
|
||||
export type IdentityAccessToken = {
|
||||
@@ -52,7 +56,7 @@ export type IdentityMembershipOrg = {
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export type IdentityMembership = {
|
||||
export type IdentityProjectMembership = {
|
||||
id: string;
|
||||
identity: Identity;
|
||||
project: Pick<Project, "id" | "name" | "type">;
|
||||
@@ -74,7 +78,7 @@ export type IdentityMembership = {
|
||||
| {
|
||||
isTemporary: true;
|
||||
temporaryRange: string;
|
||||
temporaryMode: ProjectUserMembershipTemporaryMode;
|
||||
temporaryMode: TemporaryPermissionMode;
|
||||
temporaryAccessEndTime: string;
|
||||
temporaryAccessStartTime: string;
|
||||
}
|
||||
@@ -82,6 +86,8 @@ export type IdentityMembership = {
|
||||
>;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
lastLoginTime?: string;
|
||||
lastLoginAuthMethod?: IdentityAuthMethod;
|
||||
};
|
||||
|
||||
export type CreateIdentityDTO = {
|
||||
@@ -122,7 +128,8 @@ export type IdentityUniversalAuth = {
|
||||
};
|
||||
|
||||
export type AddIdentityUniversalAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
clientSecretTrustedIps: {
|
||||
ipAddress: string;
|
||||
@@ -138,10 +145,11 @@ export type AddIdentityUniversalAuthDTO = {
|
||||
lockoutThreshold: number;
|
||||
lockoutDurationSeconds: number;
|
||||
lockoutCounterResetSeconds: number;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type UpdateIdentityUniversalAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
clientSecretTrustedIps?: {
|
||||
ipAddress: string;
|
||||
@@ -157,12 +165,13 @@ export type UpdateIdentityUniversalAuthDTO = {
|
||||
lockoutThreshold?: number;
|
||||
lockoutDurationSeconds?: number;
|
||||
lockoutCounterResetSeconds?: number;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type DeleteIdentityUniversalAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type IdentityGcpAuth = {
|
||||
identityId: string;
|
||||
@@ -177,7 +186,8 @@ export type IdentityGcpAuth = {
|
||||
};
|
||||
|
||||
export type AddIdentityGcpAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
type: "iam" | "gce";
|
||||
allowedServiceAccounts: string;
|
||||
@@ -189,10 +199,11 @@ export type AddIdentityGcpAuthDTO = {
|
||||
accessTokenTrustedIps: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type UpdateIdentityGcpAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
type?: "iam" | "gce";
|
||||
allowedServiceAccounts?: string;
|
||||
@@ -204,12 +215,13 @@ export type UpdateIdentityGcpAuthDTO = {
|
||||
accessTokenTrustedIps?: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type DeleteIdentityGcpAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type IdentityOidcAuth = {
|
||||
identityId: string;
|
||||
@@ -227,7 +239,8 @@ export type IdentityOidcAuth = {
|
||||
};
|
||||
|
||||
export type AddIdentityOidcAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
oidcDiscoveryUrl: string;
|
||||
caCert: string;
|
||||
@@ -242,10 +255,11 @@ export type AddIdentityOidcAuthDTO = {
|
||||
accessTokenTrustedIps: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type UpdateIdentityOidcAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
oidcDiscoveryUrl?: string;
|
||||
caCert?: string;
|
||||
@@ -260,12 +274,13 @@ export type UpdateIdentityOidcAuthDTO = {
|
||||
accessTokenTrustedIps?: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type DeleteIdentityOidcAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type IdentityAwsAuth = {
|
||||
identityId: string;
|
||||
@@ -280,7 +295,8 @@ export type IdentityAwsAuth = {
|
||||
};
|
||||
|
||||
export type AddIdentityAwsAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
stsEndpoint: string;
|
||||
allowedPrincipalArns: string;
|
||||
@@ -291,10 +307,11 @@ export type AddIdentityAwsAuthDTO = {
|
||||
accessTokenTrustedIps: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type UpdateIdentityAwsAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
stsEndpoint?: string;
|
||||
allowedPrincipalArns?: string;
|
||||
@@ -308,9 +325,10 @@ export type UpdateIdentityAwsAuthDTO = {
|
||||
};
|
||||
|
||||
export type DeleteIdentityAwsAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type IdentityAliCloudAuth = {
|
||||
identityId: string;
|
||||
@@ -323,7 +341,8 @@ export type IdentityAliCloudAuth = {
|
||||
};
|
||||
|
||||
export type AddIdentityAliCloudAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
allowedArns: string;
|
||||
accessTokenTTL: number;
|
||||
@@ -332,10 +351,11 @@ export type AddIdentityAliCloudAuthDTO = {
|
||||
accessTokenTrustedIps: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type UpdateIdentityAliCloudAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
allowedArns: string;
|
||||
accessTokenTTL?: number;
|
||||
@@ -344,12 +364,13 @@ export type UpdateIdentityAliCloudAuthDTO = {
|
||||
accessTokenTrustedIps?: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type DeleteIdentityAliCloudAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type IdentityOciAuth = {
|
||||
identityId: string;
|
||||
@@ -363,7 +384,8 @@ export type IdentityOciAuth = {
|
||||
};
|
||||
|
||||
export type AddIdentityOciAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
tenancyOcid: string;
|
||||
allowedUsernames?: string | null;
|
||||
@@ -373,10 +395,11 @@ export type AddIdentityOciAuthDTO = {
|
||||
accessTokenTrustedIps: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type UpdateIdentityOciAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
tenancyOcid?: string;
|
||||
allowedUsernames?: string | null;
|
||||
@@ -386,12 +409,13 @@ export type UpdateIdentityOciAuthDTO = {
|
||||
accessTokenTrustedIps?: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type DeleteIdentityOciAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type IdentityAzureAuth = {
|
||||
identityId: string;
|
||||
@@ -405,7 +429,8 @@ export type IdentityAzureAuth = {
|
||||
};
|
||||
|
||||
export type AddIdentityAzureAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
tenantId: string;
|
||||
resource: string;
|
||||
@@ -416,10 +441,11 @@ export type AddIdentityAzureAuthDTO = {
|
||||
accessTokenTrustedIps: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type UpdateIdentityAzureAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
tenantId?: string;
|
||||
resource?: string;
|
||||
@@ -430,12 +456,13 @@ export type UpdateIdentityAzureAuthDTO = {
|
||||
accessTokenTrustedIps?: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type DeleteIdentityAzureAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export enum IdentityKubernetesAuthTokenReviewMode {
|
||||
Api = "api",
|
||||
@@ -459,7 +486,8 @@ export type IdentityKubernetesAuth = {
|
||||
};
|
||||
|
||||
export type AddIdentityKubernetesAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
kubernetesHost: string | null;
|
||||
tokenReviewerJwt?: string;
|
||||
@@ -475,10 +503,11 @@ export type AddIdentityKubernetesAuthDTO = {
|
||||
accessTokenTrustedIps: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type UpdateIdentityKubernetesAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
kubernetesHost?: string | null;
|
||||
tokenReviewerJwt?: string | null;
|
||||
@@ -494,12 +523,13 @@ export type UpdateIdentityKubernetesAuthDTO = {
|
||||
accessTokenTrustedIps?: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type DeleteIdentityKubernetesAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type IdentityTlsCertAuth = {
|
||||
identityId: string;
|
||||
@@ -512,7 +542,8 @@ export type IdentityTlsCertAuth = {
|
||||
};
|
||||
|
||||
export type AddIdentityTlsCertAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
caCertificate: string;
|
||||
allowedCommonNames?: string;
|
||||
@@ -522,10 +553,11 @@ export type AddIdentityTlsCertAuthDTO = {
|
||||
accessTokenTrustedIps: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type UpdateIdentityTlsCertAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
caCertificate: string;
|
||||
allowedCommonNames?: string | null;
|
||||
@@ -535,12 +567,13 @@ export type UpdateIdentityTlsCertAuthDTO = {
|
||||
accessTokenTrustedIps?: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type DeleteIdentityTlsCertAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type CreateIdentityUniversalAuthClientSecretDTO = {
|
||||
identityId: string;
|
||||
@@ -585,7 +618,8 @@ export type IdentityTokenAuth = {
|
||||
};
|
||||
|
||||
export type AddIdentityLdapAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
templateId?: string;
|
||||
url?: string;
|
||||
@@ -609,11 +643,12 @@ export type AddIdentityLdapAuthDTO = {
|
||||
lockoutThreshold: number;
|
||||
lockoutDurationSeconds: number;
|
||||
lockoutCounterResetSeconds: number;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type UpdateIdentityLdapAuthDTO = {
|
||||
identityId: string;
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
templateId?: string;
|
||||
url?: string;
|
||||
bindDN?: string;
|
||||
@@ -636,12 +671,13 @@ export type UpdateIdentityLdapAuthDTO = {
|
||||
lockoutThreshold?: number;
|
||||
lockoutDurationSeconds?: number;
|
||||
lockoutCounterResetSeconds?: number;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type DeleteIdentityLdapAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type IdentityLdapAuth = {
|
||||
url?: string;
|
||||
@@ -673,7 +709,8 @@ export type ClearIdentityLdapAuthLockoutsDTO = {
|
||||
};
|
||||
|
||||
export type AddIdentityTokenAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
accessTokenTTL: number;
|
||||
accessTokenMaxTTL: number;
|
||||
@@ -681,10 +718,11 @@ export type AddIdentityTokenAuthDTO = {
|
||||
accessTokenTrustedIps: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type UpdateIdentityTokenAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
accessTokenTTL?: number;
|
||||
accessTokenMaxTTL?: number;
|
||||
@@ -692,12 +730,13 @@ export type UpdateIdentityTokenAuthDTO = {
|
||||
accessTokenTrustedIps?: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type DeleteIdentityTokenAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type IdentityJwtAuth = {
|
||||
identityId: string;
|
||||
@@ -716,7 +755,8 @@ export type IdentityJwtAuth = {
|
||||
};
|
||||
|
||||
export type AddIdentityJwtAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
configurationType: string;
|
||||
jwksUrl?: string;
|
||||
@@ -732,10 +772,11 @@ export type AddIdentityJwtAuthDTO = {
|
||||
accessTokenTrustedIps: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type UpdateIdentityJwtAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
configurationType?: string;
|
||||
jwksUrl?: string;
|
||||
@@ -751,12 +792,13 @@ export type UpdateIdentityJwtAuthDTO = {
|
||||
accessTokenTrustedIps?: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type DeleteIdentityJwtAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type CreateTokenIdentityTokenAuthDTO = {
|
||||
identityId: string;
|
||||
@@ -785,8 +827,8 @@ export type RevokeTokenRes = {
|
||||
message: string;
|
||||
};
|
||||
|
||||
export type TProjectIdentitiesList = {
|
||||
identityMemberships: IdentityMembership[];
|
||||
export type TProjectIdentityMembershipsList = {
|
||||
identityMemberships: IdentityProjectMembership[];
|
||||
totalCount: number;
|
||||
};
|
||||
|
||||
|
||||
@@ -25,10 +25,14 @@ export * from "./ldapConfig";
|
||||
export * from "./oidcConfig";
|
||||
export * from "./orgAdmin";
|
||||
export * from "./organization";
|
||||
export * from "./orgIdentity";
|
||||
export * from "./orgIdentityMembership";
|
||||
export * from "./pkiAlerts";
|
||||
export * from "./pkiCollections";
|
||||
export * from "./pkiSubscriber";
|
||||
export * from "./pkiSyncs";
|
||||
export * from "./projectIdentity";
|
||||
export * from "./projectIdentityMembership";
|
||||
export * from "./projects";
|
||||
export * from "./projectUserAdditionalPrivilege";
|
||||
export * from "./rateLimit";
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from "./mutations";
|
||||
export * from "./queries";
|
||||
export type * from "./types";
|
||||
@@ -0,0 +1,116 @@
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
import { identitiesKeys } from "@app/hooks/api";
|
||||
import { CreateIdentityDTO, Identity, UpdateIdentityDTO } from "@app/hooks/api/identities/types";
|
||||
import { organizationKeys } from "@app/hooks/api/organization/queries";
|
||||
import { subscriptionQueryKeys } from "@app/hooks/api/subscriptions/queries";
|
||||
|
||||
import { orgIdentityQuery } from "./queries";
|
||||
import { TDeleteOrgIdentityDTO, TOrgIdentity } from "./types";
|
||||
|
||||
// TODO (scott/akhi): eventually move to the new api commented out below; the current ones use old api
|
||||
|
||||
export const useCreateOrgIdentity = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<Identity, object, CreateIdentityDTO>({
|
||||
mutationFn: async (body) => {
|
||||
const {
|
||||
data: { identity }
|
||||
} = await apiRequest.post("/api/v1/identities/", body);
|
||||
return identity;
|
||||
},
|
||||
onSuccess: (_, { organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: subscriptionQueryKeys.getOrgSubsription(organizationId)
|
||||
});
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.searchIdentitiesRoot });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateOrgIdentity = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<Identity, object, UpdateIdentityDTO>({
|
||||
mutationFn: async ({ identityId, name, role, hasDeleteProtection, metadata }) => {
|
||||
const {
|
||||
data: { identity }
|
||||
} = await apiRequest.patch(`/api/v1/identities/${identityId}`, {
|
||||
name,
|
||||
role,
|
||||
hasDeleteProtection,
|
||||
metadata
|
||||
});
|
||||
|
||||
return identity;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.searchIdentitiesRoot });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// export const useCreateOrgIdentity = () => {
|
||||
// const queryClient = useQueryClient();
|
||||
// return useMutation({
|
||||
// mutationFn: async (dto: TCreateOrgIdentityDTO) => {
|
||||
// const { data } = await apiRequest.post<{ identity: TOrgIdentity }>(
|
||||
// "/api/v1/organization/identities",
|
||||
// dto
|
||||
// );
|
||||
// return data;
|
||||
// },
|
||||
// onSuccess: () => {
|
||||
// queryClient.invalidateQueries({ queryKey: orgIdentityQuery.allKey() });
|
||||
// queryClient.invalidateQueries({
|
||||
// queryKey: subscriptionQueryKeys.all()
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
// };
|
||||
//
|
||||
// export const useUpdateOrgIdentity = () => {
|
||||
// const queryClient = useQueryClient();
|
||||
// return useMutation({
|
||||
// mutationFn: async ({ identityId, ...updates }: TUpdateOrgIdentityDTO) => {
|
||||
// const { data } = await apiRequest.patch<{ identity: TOrgIdentity }>(
|
||||
// `/api/v1/organization/identities/${identityId}`,
|
||||
// updates
|
||||
// );
|
||||
// return data;
|
||||
// },
|
||||
// onSuccess: () => {
|
||||
// queryClient.invalidateQueries({ queryKey: orgIdentityQuery.allKey() });
|
||||
// }
|
||||
// });
|
||||
// };
|
||||
|
||||
export const useDeleteOrgIdentity = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ identityId }: TDeleteOrgIdentityDTO) => {
|
||||
const { data } = await apiRequest.delete<{ identity: TOrgIdentity }>(
|
||||
`/api/v1/identities/${identityId}`
|
||||
);
|
||||
return data;
|
||||
},
|
||||
onSuccess: (_, { orgId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(orgId)
|
||||
});
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.searchIdentitiesRoot });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(orgId) });
|
||||
queryClient.invalidateQueries({ queryKey: orgIdentityQuery.allKey() });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: subscriptionQueryKeys.all()
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
import { queryOptions } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import { TGetOrgIdentityByIdDTO, TListOrgIdentitiesDTO, TOrgIdentity } from "./types";
|
||||
|
||||
export const orgIdentityQuery = {
|
||||
allKey: () => ["organization-identities"] as const,
|
||||
getByIdKey: (params: TGetOrgIdentityByIdDTO) =>
|
||||
[...orgIdentityQuery.allKey(), "by-id", params] as const,
|
||||
listKey: (params?: TListOrgIdentitiesDTO) =>
|
||||
[...orgIdentityQuery.allKey(), "list", params] as const,
|
||||
getById: (params: TGetOrgIdentityByIdDTO) =>
|
||||
queryOptions({
|
||||
queryKey: orgIdentityQuery.getByIdKey(params),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{ identity: TOrgIdentity }>(
|
||||
`/api/v1/organization/identities/${params.identityId}`
|
||||
);
|
||||
return data.identity;
|
||||
}
|
||||
}),
|
||||
list: (params: TListOrgIdentitiesDTO = {}) =>
|
||||
queryOptions({
|
||||
queryKey: orgIdentityQuery.listKey(params),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{
|
||||
identities: TOrgIdentity[];
|
||||
totalCount: number;
|
||||
}>("/api/v1/organization/identities", {
|
||||
params: {
|
||||
offset: params.offset,
|
||||
limit: params.limit,
|
||||
search: params.search
|
||||
}
|
||||
});
|
||||
return data;
|
||||
}
|
||||
})
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
import { TIdentity, TMetadata } from "@app/hooks/api/shared";
|
||||
|
||||
export type TOrgIdentity = TIdentity;
|
||||
|
||||
export type TCreateOrgIdentityDTO = {
|
||||
name: string;
|
||||
hasDeleteProtection?: boolean;
|
||||
metadata?: TMetadata;
|
||||
};
|
||||
|
||||
export type TUpdateOrgIdentityDTO = {
|
||||
identityId: string;
|
||||
name?: string;
|
||||
hasDeleteProtection?: boolean;
|
||||
metadata?: TMetadata;
|
||||
};
|
||||
|
||||
export type TGetOrgIdentityByIdDTO = {
|
||||
identityId: string;
|
||||
};
|
||||
|
||||
export type TListOrgIdentitiesDTO = {
|
||||
offset?: number;
|
||||
limit?: number;
|
||||
search?: string;
|
||||
};
|
||||
|
||||
export type TDeleteOrgIdentityDTO = {
|
||||
identityId: string;
|
||||
orgId: string;
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
import { queryOptions } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import {
|
||||
TAvailableOrganizationIdentities,
|
||||
TListAvailableOrganizationIdentitiesDTO,
|
||||
TListOrgIdentityMembershipsDTO
|
||||
} from "./types";
|
||||
|
||||
export const orgIdentityMembershipQuery = {
|
||||
allKey: () => ["organization-identity-memberships"] as const,
|
||||
listAvailableKey: (params?: TListOrgIdentityMembershipsDTO) =>
|
||||
[...orgIdentityMembershipQuery.allKey(), "list-available", params] as const,
|
||||
listAvailable: (params: TListAvailableOrganizationIdentitiesDTO = {}) =>
|
||||
queryOptions({
|
||||
queryKey: orgIdentityMembershipQuery.listAvailableKey(params),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{
|
||||
identities: TAvailableOrganizationIdentities;
|
||||
}>("/api/v1/organization/available-identities", {
|
||||
params: {
|
||||
offset: params.offset,
|
||||
limit: params.limit,
|
||||
identityName: params.identityName
|
||||
}
|
||||
});
|
||||
return data.identities;
|
||||
}
|
||||
})
|
||||
};
|
||||
@@ -1,6 +1,4 @@
|
||||
export enum TemporaryPermissionMode {
|
||||
Relative = "relative"
|
||||
}
|
||||
import { TRoles } from "@app/hooks/api/shared";
|
||||
|
||||
export type TOrgIdentityMembership = {
|
||||
id: string;
|
||||
@@ -12,21 +10,24 @@ export type TOrgIdentityMembership = {
|
||||
|
||||
export type TCreateOrgIdentityMembershipDTO = {
|
||||
identityId: string;
|
||||
roles: Array<
|
||||
| {
|
||||
role: string;
|
||||
isTemporary?: false;
|
||||
}
|
||||
| {
|
||||
role: string;
|
||||
isTemporary: true;
|
||||
temporaryMode: TemporaryPermissionMode;
|
||||
temporaryRange: string;
|
||||
temporaryAccessStartTime: string;
|
||||
}
|
||||
>;
|
||||
roles: TRoles;
|
||||
};
|
||||
|
||||
export type TDeleteOrgIdentityMembershipDTO = {
|
||||
identityId: string;
|
||||
};
|
||||
|
||||
export type TListOrgIdentityMembershipsDTO = {
|
||||
offset?: number;
|
||||
limit?: number;
|
||||
identityName?: string;
|
||||
roles?: string[];
|
||||
};
|
||||
|
||||
export type TListAvailableOrganizationIdentitiesDTO = {
|
||||
offset?: number;
|
||||
limit?: number;
|
||||
identityName?: string;
|
||||
};
|
||||
|
||||
export type TAvailableOrganizationIdentities = Array<{ id: string; name: string }>;
|
||||
|
||||
@@ -6,7 +6,6 @@ export {
|
||||
useDeleteOrgById,
|
||||
useDeleteOrgPmtMethod,
|
||||
useDeleteOrgTaxId,
|
||||
useGetAvailableOrgIdentities,
|
||||
useGetIdentityMembershipOrgs,
|
||||
useGetOrganizationGroups,
|
||||
useGetOrganizations,
|
||||
|
||||
@@ -579,19 +579,6 @@ export const useGetOrgIntegrationAuths = <TData = IntegrationAuth[],>(
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetAvailableOrgIdentities = (enabled = true) =>
|
||||
useQuery({
|
||||
queryKey: organizationKeys.getAvailableIdentities(),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{ identities: { name: string; id: string }[] }>(
|
||||
"/api/v1/organization/identities/available"
|
||||
);
|
||||
|
||||
return data.identities;
|
||||
},
|
||||
enabled
|
||||
});
|
||||
|
||||
export const useGetAvailableOrgUsers = (enabled = true) =>
|
||||
useQuery({
|
||||
queryKey: organizationKeys.getAvailableUsers(),
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
export {
|
||||
useCreateOrganizationIdentity,
|
||||
useDeleteOrganizationIdentity,
|
||||
useUpdateOrganizationIdentity
|
||||
} from "./mutations";
|
||||
export { organizationIdentityQuery } from "./queries";
|
||||
export type {
|
||||
TCreateOrganizationIdentityDTO,
|
||||
TDeleteOrganizationIdentityDTO,
|
||||
TGetOrganizationIdentityByIdDTO,
|
||||
TListOrganizationIdentitiesDTO,
|
||||
TMetadata,
|
||||
TOrganizationIdentity,
|
||||
TUpdateOrganizationIdentityDTO
|
||||
} from "./types";
|
||||
@@ -1,58 +0,0 @@
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import { organizationIdentityQuery } from "./queries";
|
||||
import {
|
||||
TCreateOrganizationIdentityDTO,
|
||||
TDeleteOrganizationIdentityDTO,
|
||||
TOrganizationIdentity,
|
||||
TUpdateOrganizationIdentityDTO
|
||||
} from "./types";
|
||||
|
||||
export const useCreateOrganizationIdentity = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async (dto: TCreateOrganizationIdentityDTO) => {
|
||||
const { data } = await apiRequest.post<{ identity: TOrganizationIdentity }>(
|
||||
"/api/v1/organization/identities",
|
||||
dto
|
||||
);
|
||||
return data;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: organizationIdentityQuery.allKey() });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateOrganizationIdentity = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ identityId, ...updates }: TUpdateOrganizationIdentityDTO) => {
|
||||
const { data } = await apiRequest.patch<{ identity: TOrganizationIdentity }>(
|
||||
`/api/v1/organization/identities/${identityId}`,
|
||||
updates
|
||||
);
|
||||
return data;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: organizationIdentityQuery.allKey() });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useDeleteOrganizationIdentity = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ identityId }: TDeleteOrganizationIdentityDTO) => {
|
||||
const { data } = await apiRequest.delete<{ identity: TOrganizationIdentity }>(
|
||||
`/api/v1/organization/identities/${identityId}`
|
||||
);
|
||||
return data;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: organizationIdentityQuery.allKey() });
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -1,44 +0,0 @@
|
||||
import { queryOptions } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import {
|
||||
TGetOrganizationIdentityByIdDTO,
|
||||
TListOrganizationIdentitiesDTO,
|
||||
TOrganizationIdentity
|
||||
} from "./types";
|
||||
|
||||
export const organizationIdentityQuery = {
|
||||
allKey: () => ["organization-identities"] as const,
|
||||
getByIdKey: (params: TGetOrganizationIdentityByIdDTO) =>
|
||||
[...organizationIdentityQuery.allKey(), "by-id", params] as const,
|
||||
listKey: (params?: TListOrganizationIdentitiesDTO) =>
|
||||
[...organizationIdentityQuery.allKey(), "list", params] as const,
|
||||
getById: (params: TGetOrganizationIdentityByIdDTO) =>
|
||||
queryOptions({
|
||||
queryKey: organizationIdentityQuery.getByIdKey(params),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{ identity: TOrganizationIdentity }>(
|
||||
`/api/v1/organization/identities/${params.identityId}`
|
||||
);
|
||||
return data.identity;
|
||||
}
|
||||
}),
|
||||
list: (params: TListOrganizationIdentitiesDTO = {}) =>
|
||||
queryOptions({
|
||||
queryKey: organizationIdentityQuery.listKey(params),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{
|
||||
identities: TOrganizationIdentity[];
|
||||
totalCount: number;
|
||||
}>("/api/v1/organization/identities", {
|
||||
params: {
|
||||
offset: params.offset,
|
||||
limit: params.limit,
|
||||
search: params.search
|
||||
}
|
||||
});
|
||||
return data;
|
||||
}
|
||||
})
|
||||
};
|
||||
@@ -1,43 +0,0 @@
|
||||
export type TMetadata = {
|
||||
key: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export type TOrganizationIdentity = {
|
||||
id: string;
|
||||
name: string;
|
||||
orgId: string;
|
||||
projectId: string | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
hasDeleteProtection: boolean;
|
||||
authMethods?: string[];
|
||||
metadata?: TMetadata[];
|
||||
};
|
||||
|
||||
export type TCreateOrganizationIdentityDTO = {
|
||||
name: string;
|
||||
hasDeleteProtection?: boolean;
|
||||
metadata?: TMetadata[];
|
||||
};
|
||||
|
||||
export type TUpdateOrganizationIdentityDTO = {
|
||||
identityId: string;
|
||||
name?: string;
|
||||
hasDeleteProtection?: boolean;
|
||||
metadata?: TMetadata[];
|
||||
};
|
||||
|
||||
export type TGetOrganizationIdentityByIdDTO = {
|
||||
identityId: string;
|
||||
};
|
||||
|
||||
export type TListOrganizationIdentitiesDTO = {
|
||||
offset?: number;
|
||||
limit?: number;
|
||||
search?: string;
|
||||
};
|
||||
|
||||
export type TDeleteOrganizationIdentityDTO = {
|
||||
identityId: string;
|
||||
};
|
||||
@@ -1,6 +1,8 @@
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
import { identitiesKeys, projectKeys } from "@app/hooks/api";
|
||||
import { subscriptionQueryKeys } from "@app/hooks/api/subscriptions/queries";
|
||||
|
||||
import { projectIdentityQuery } from "./queries";
|
||||
import {
|
||||
@@ -18,10 +20,13 @@ export const useCreateProjectIdentity = () => {
|
||||
`/api/v1/projects/${projectId}/identities`,
|
||||
dto
|
||||
);
|
||||
return data;
|
||||
return data.identity;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: projectIdentityQuery.allKey() });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: subscriptionQueryKeys.all()
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -34,10 +39,13 @@ export const useUpdateProjectIdentity = () => {
|
||||
`/api/v1/projects/${projectId}/identities/${identityId}`,
|
||||
updates
|
||||
);
|
||||
return data;
|
||||
return data.identity;
|
||||
},
|
||||
onSuccess: () => {
|
||||
onSuccess: (_, { projectId, identityId }) => {
|
||||
queryClient.invalidateQueries({ queryKey: projectIdentityQuery.allKey() });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMembershipDetails(projectId, identityId)
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -49,10 +57,20 @@ export const useDeleteProjectIdentity = () => {
|
||||
const { data } = await apiRequest.delete<{ identity: TProjectIdentity }>(
|
||||
`/api/v1/projects/${projectId}/identities/${identityId}`
|
||||
);
|
||||
return data;
|
||||
return data.identity;
|
||||
},
|
||||
onSuccess: () => {
|
||||
onSuccess: (_, { projectId, identityId }) => {
|
||||
queryClient.invalidateQueries({ queryKey: projectIdentityQuery.allKey() });
|
||||
queryClient.invalidateQueries({ queryKey: projectIdentityQuery.allKey() });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityProjectMemberships(identityId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: subscriptionQueryKeys.all()
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -2,11 +2,7 @@ import { queryOptions } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import {
|
||||
TGetProjectIdentityByIdDTO,
|
||||
TListProjectIdentitiesDTO,
|
||||
TProjectIdentity
|
||||
} from "./types";
|
||||
import { TGetProjectIdentityByIdDTO, TListProjectIdentitiesDTO, TProjectIdentity } from "./types";
|
||||
|
||||
export const projectIdentityQuery = {
|
||||
allKey: () => ["project-identities"] as const,
|
||||
|
||||
@@ -1,28 +1,18 @@
|
||||
import { TIdentity, TMetadata } from "@app/hooks/api/shared";
|
||||
|
||||
export type TProjectIdentityMetadata = {
|
||||
key: string;
|
||||
value: string;
|
||||
id: string;
|
||||
};
|
||||
|
||||
export type TProjectIdentity = {
|
||||
id: string;
|
||||
name: string;
|
||||
orgId: string;
|
||||
projectId: string | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
hasDeleteProtection: boolean;
|
||||
metadata?: TProjectIdentityMetadata[];
|
||||
};
|
||||
export type TProjectIdentity = TIdentity;
|
||||
|
||||
export type TCreateProjectIdentityDTO = {
|
||||
projectId: string;
|
||||
name: string;
|
||||
hasDeleteProtection?: boolean;
|
||||
metadata?: Array<{
|
||||
key: string;
|
||||
value: string;
|
||||
}>;
|
||||
metadata?: TMetadata[];
|
||||
};
|
||||
|
||||
export type TUpdateProjectIdentityDTO = {
|
||||
@@ -30,10 +20,7 @@ export type TUpdateProjectIdentityDTO = {
|
||||
identityId: string;
|
||||
name?: string;
|
||||
hasDeleteProtection?: boolean;
|
||||
metadata?: Array<{
|
||||
key: string;
|
||||
value: string;
|
||||
}>;
|
||||
metadata?: TMetadata[];
|
||||
};
|
||||
|
||||
export type TGetProjectIdentityByIdDTO = {
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from "./mutations";
|
||||
export * from "./queries";
|
||||
export * from "./types";
|
||||
@@ -0,0 +1,93 @@
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
import { identitiesKeys, projectKeys } from "@app/hooks/api";
|
||||
import { projectIdentityQuery } from "@app/hooks/api/projectIdentity";
|
||||
|
||||
import {
|
||||
TCreateProjectIdentityMembershipDTO,
|
||||
TDeleteProjectIdentityMembershipDTO,
|
||||
TProjectIdentityMembership,
|
||||
TUpdateProjectIdentityMembershipDTO
|
||||
} from "./types";
|
||||
|
||||
export const useCreateProjectIdentityMembership = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ identityId, projectId, role }: TCreateProjectIdentityMembershipDTO) => {
|
||||
const {
|
||||
data: { identityMembership }
|
||||
} = await apiRequest.post<{ identityMembership: TProjectIdentityMembership }>(
|
||||
`/api/v1/projects/${projectId}/identity-memberships/${identityId}`,
|
||||
{
|
||||
role
|
||||
}
|
||||
);
|
||||
|
||||
return identityMembership;
|
||||
},
|
||||
onSuccess: (_, { identityId, projectId }) => {
|
||||
queryClient.invalidateQueries({ queryKey: projectIdentityQuery.allKey() });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityProjectMemberships(identityId)
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateProjectIdentityMembership = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({
|
||||
projectId,
|
||||
identityId,
|
||||
...updates
|
||||
}: TUpdateProjectIdentityMembershipDTO) => {
|
||||
const {
|
||||
data: { identityMembership }
|
||||
} = await apiRequest.patch<{ identityMembership: TProjectIdentityMembership }>(
|
||||
`/api/v1/projects/${projectId}/identity-memberships/${identityId}`,
|
||||
updates
|
||||
);
|
||||
return identityMembership;
|
||||
},
|
||||
onSuccess: (_, { projectId, identityId }) => {
|
||||
queryClient.invalidateQueries({ queryKey: projectIdentityQuery.allKey() });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityProjectMemberships(identityId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMembershipDetails(projectId, identityId)
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useDeleteProjectIdentityMembership = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ identityId, projectId }: TDeleteProjectIdentityMembershipDTO) => {
|
||||
const {
|
||||
data: { identityMembership }
|
||||
} = await apiRequest.delete<{ identityMembership: TProjectIdentityMembership }>(
|
||||
`/api/v1/projects/${projectId}/identity-memberships/${identityId}`
|
||||
);
|
||||
return identityMembership;
|
||||
},
|
||||
onSuccess: (_, { identityId, projectId }) => {
|
||||
queryClient.invalidateQueries({ queryKey: projectIdentityQuery.allKey() });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityProjectMemberships(identityId)
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,101 @@
|
||||
import { queryOptions, useQuery, UseQueryOptions } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
import {
|
||||
projectKeys,
|
||||
TAvailableProjectIdentities,
|
||||
TListAvailableProjectIdentitiesDTO
|
||||
} from "@app/hooks/api";
|
||||
import { OrderByDirection } from "@app/hooks/api/generic/types";
|
||||
import {
|
||||
IdentityProjectMembership,
|
||||
TProjectIdentityMembershipsList
|
||||
} from "@app/hooks/api/identities/types";
|
||||
import { ProjectIdentityOrderBy, TListProjectIdentitiesDTO } from "@app/hooks/api/projects/types";
|
||||
|
||||
export const projectIdentityMembershipQuery = {
|
||||
allKey: () => ["project-identity-memberships"] as const,
|
||||
listAvailableKey: (params?: TListAvailableProjectIdentitiesDTO) =>
|
||||
[...projectIdentityMembershipQuery.allKey(), "list-available", params] as const,
|
||||
listAvailable: (params: TListAvailableProjectIdentitiesDTO) =>
|
||||
queryOptions({
|
||||
queryKey: projectIdentityMembershipQuery.listAvailableKey(params),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{
|
||||
identities: TAvailableProjectIdentities;
|
||||
}>(`/api/v1/projects/${params.projectId}/available-identities`, {
|
||||
params: {
|
||||
offset: params.offset,
|
||||
limit: params.limit,
|
||||
identityName: params.identityName
|
||||
}
|
||||
});
|
||||
return data.identities;
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
// TODO (scott/akhi): move to new projectIdentityMembershipQuery structure
|
||||
|
||||
export const useListProjectIdentityMemberships = (
|
||||
{
|
||||
projectId,
|
||||
offset = 0,
|
||||
limit = 100,
|
||||
orderBy = ProjectIdentityOrderBy.Name,
|
||||
orderDirection = OrderByDirection.ASC,
|
||||
search = ""
|
||||
}: TListProjectIdentitiesDTO,
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
TProjectIdentityMembershipsList,
|
||||
unknown,
|
||||
TProjectIdentityMembershipsList,
|
||||
ReturnType<typeof projectKeys.getProjectIdentityMembershipsWithParams>
|
||||
>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: projectKeys.getProjectIdentityMembershipsWithParams({
|
||||
projectId,
|
||||
offset,
|
||||
limit,
|
||||
orderBy,
|
||||
orderDirection,
|
||||
search
|
||||
}),
|
||||
queryFn: async () => {
|
||||
const params = new URLSearchParams({
|
||||
offset: String(offset),
|
||||
limit: String(limit),
|
||||
orderBy: String(orderBy),
|
||||
orderDirection: String(orderDirection),
|
||||
search: String(search)
|
||||
});
|
||||
|
||||
const { data } = await apiRequest.get<TProjectIdentityMembershipsList>(
|
||||
`/api/v1/projects/${projectId}/identity-memberships`,
|
||||
{ params }
|
||||
);
|
||||
return data;
|
||||
},
|
||||
enabled: true,
|
||||
...options
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetProjectIdentityMembership = (projectId: string, identityId: string) => {
|
||||
return useQuery({
|
||||
enabled: Boolean(projectId && identityId),
|
||||
queryKey: projectKeys.getProjectIdentityMembershipDetails(projectId, identityId),
|
||||
queryFn: async () => {
|
||||
const {
|
||||
data: { identityMembership }
|
||||
} = await apiRequest.get<{ identityMembership: IdentityProjectMembership }>(
|
||||
`/api/v1/projects/${projectId}/identity-memberships/${identityId}`
|
||||
);
|
||||
return identityMembership;
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
import { TRoles } from "@app/hooks/api/shared";
|
||||
|
||||
export type TProjectIdentityMembership = {
|
||||
id: string;
|
||||
projectId: string;
|
||||
identityId: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
// TODO
|
||||
};
|
||||
|
||||
export type TCreateProjectIdentityMembershipDTO = {
|
||||
identityId: string;
|
||||
projectId: string;
|
||||
role?: string;
|
||||
};
|
||||
|
||||
export type TUpdateProjectIdentityMembershipDTO = {
|
||||
identityId: string;
|
||||
projectId: string;
|
||||
roles: TRoles;
|
||||
};
|
||||
|
||||
export type TDeleteProjectIdentityMembershipDTO = {
|
||||
identityId: string;
|
||||
projectId: string;
|
||||
};
|
||||
|
||||
export type TListAvailableProjectIdentitiesDTO = {
|
||||
projectId: string;
|
||||
offset?: number;
|
||||
limit?: number;
|
||||
identityName?: string;
|
||||
};
|
||||
|
||||
export type TAvailableProjectIdentities = Array<{ id: string; name: string }>;
|
||||
@@ -8,10 +8,8 @@ export {
|
||||
useUpdateProjectSshConfig
|
||||
} from "./mutations";
|
||||
export {
|
||||
useAddIdentityToWorkspace,
|
||||
useCreateWorkspace,
|
||||
useCreateWsEnvironment,
|
||||
useDeleteIdentityFromWorkspace,
|
||||
useDeleteUserFromWorkspace,
|
||||
useDeleteWorkspace,
|
||||
useDeleteWsEnvironment,
|
||||
@@ -21,8 +19,6 @@ export {
|
||||
useGetUserWorkspaceMemberships,
|
||||
useGetWorkspaceAuthorizations,
|
||||
useGetWorkspaceById,
|
||||
useGetWorkspaceIdentityMembershipDetails,
|
||||
useGetWorkspaceIdentityMemberships,
|
||||
useGetWorkspaceIndexStatus,
|
||||
useGetWorkspaceIntegrations,
|
||||
useGetWorkspaceUserDetails,
|
||||
@@ -41,7 +37,6 @@ export {
|
||||
useListWorkspaceSshHostGroups,
|
||||
useListWorkspaceSshHosts,
|
||||
useSearchProjects,
|
||||
useUpdateIdentityWorkspaceRole,
|
||||
useUpdateProject,
|
||||
useUpdateUserWorkspaceRole,
|
||||
useUpdateWsEnvironment,
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import { useMutation, useQuery, useQueryClient, UseQueryOptions } from "@tanstack/react-query";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
import { OrderByDirection } from "@app/hooks/api/generic/types";
|
||||
|
||||
import { CaStatus } from "../ca/enums";
|
||||
import { TCertificateAuthority } from "../ca/types";
|
||||
import { TCertificate } from "../certificates/types";
|
||||
import { TCertificateTemplate } from "../certificateTemplates/types";
|
||||
import { TGroupMembership } from "../groups/types";
|
||||
import { identitiesKeys } from "../identities/queries";
|
||||
import { IdentityMembership, TProjectIdentitiesList } from "../identities/types";
|
||||
import { IntegrationAuth } from "../integrationAuth/types";
|
||||
import { TIntegration } from "../integrations/types";
|
||||
import { TPkiAlert } from "../pkiAlerts/types";
|
||||
@@ -33,13 +30,10 @@ import {
|
||||
DeleteWorkspaceDTO,
|
||||
Project,
|
||||
ProjectEnv,
|
||||
ProjectIdentityOrderBy,
|
||||
ProjectType,
|
||||
TGetUpgradeProjectStatusDTO,
|
||||
TListProjectIdentitiesDTO,
|
||||
TProjectSshConfig,
|
||||
TSearchProjectsDTO,
|
||||
TUpdateWorkspaceIdentityRoleDTO,
|
||||
TUpdateWorkspaceUserRoleDTO,
|
||||
UpdateAuditLogsRetentionDTO,
|
||||
UpdateEnvironmentDTO,
|
||||
@@ -452,154 +446,6 @@ export const useUpdateUserWorkspaceRole = () => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useAddIdentityToWorkspace = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({
|
||||
identityId,
|
||||
projectId,
|
||||
role
|
||||
}: {
|
||||
identityId: string;
|
||||
projectId: string;
|
||||
role?: string;
|
||||
}) => {
|
||||
const {
|
||||
data: { identityMembership }
|
||||
} = await apiRequest.post(
|
||||
`/api/v1/projects/${projectId}/identity-memberships/${identityId}`,
|
||||
{
|
||||
role
|
||||
}
|
||||
);
|
||||
|
||||
return identityMembership;
|
||||
},
|
||||
onSuccess: (_, { identityId, projectId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityProjectMemberships(identityId)
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateIdentityWorkspaceRole = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ identityId, projectId, roles }: TUpdateWorkspaceIdentityRoleDTO) => {
|
||||
const {
|
||||
data: { identityMembership }
|
||||
} = await apiRequest.patch(
|
||||
`/api/v1/projects/${projectId}/identity-memberships/${identityId}`,
|
||||
{
|
||||
roles
|
||||
}
|
||||
);
|
||||
|
||||
return identityMembership;
|
||||
},
|
||||
onSuccess: (_, { identityId, projectId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityProjectMemberships(identityId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMembershipDetails(projectId, identityId)
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useDeleteIdentityFromWorkspace = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ identityId, projectId }: { identityId: string; projectId: string }) => {
|
||||
const {
|
||||
data: { identityMembership }
|
||||
} = await apiRequest.delete(
|
||||
`/api/v1/projects/${projectId}/identity-memberships/${identityId}`
|
||||
);
|
||||
return identityMembership;
|
||||
},
|
||||
onSuccess: (_, { identityId, projectId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityProjectMemberships(identityId)
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetWorkspaceIdentityMemberships = (
|
||||
{
|
||||
projectId,
|
||||
offset = 0,
|
||||
limit = 100,
|
||||
orderBy = ProjectIdentityOrderBy.Name,
|
||||
orderDirection = OrderByDirection.ASC,
|
||||
search = ""
|
||||
}: TListProjectIdentitiesDTO,
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
TProjectIdentitiesList,
|
||||
unknown,
|
||||
TProjectIdentitiesList,
|
||||
ReturnType<typeof projectKeys.getProjectIdentityMembershipsWithParams>
|
||||
>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: projectKeys.getProjectIdentityMembershipsWithParams({
|
||||
projectId,
|
||||
offset,
|
||||
limit,
|
||||
orderBy,
|
||||
orderDirection,
|
||||
search
|
||||
}),
|
||||
queryFn: async () => {
|
||||
const params = new URLSearchParams({
|
||||
offset: String(offset),
|
||||
limit: String(limit),
|
||||
orderBy: String(orderBy),
|
||||
orderDirection: String(orderDirection),
|
||||
search: String(search)
|
||||
});
|
||||
|
||||
const { data } = await apiRequest.get<TProjectIdentitiesList>(
|
||||
`/api/v1/projects/${projectId}/identity-memberships`,
|
||||
{ params }
|
||||
);
|
||||
return data;
|
||||
},
|
||||
enabled: true,
|
||||
...options
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetWorkspaceIdentityMembershipDetails = (projectId: string, identityId: string) => {
|
||||
return useQuery({
|
||||
enabled: Boolean(projectId && identityId),
|
||||
queryKey: projectKeys.getProjectIdentityMembershipDetails(projectId, identityId),
|
||||
queryFn: async () => {
|
||||
const {
|
||||
data: { identityMembership }
|
||||
} = await apiRequest.get<{ identityMembership: IdentityMembership }>(
|
||||
`/api/v1/projects/${projectId}/identity-memberships/${identityId}`
|
||||
);
|
||||
return identityMembership;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetWorkspaceGroupMembershipDetails = (projectId: string, groupId: string) => {
|
||||
return useQuery({
|
||||
enabled: Boolean(projectId && groupId),
|
||||
|
||||
@@ -138,24 +138,6 @@ export type TUpdateWorkspaceUserRoleDTO = {
|
||||
)[];
|
||||
};
|
||||
|
||||
export type TUpdateWorkspaceIdentityRoleDTO = {
|
||||
identityId: string;
|
||||
projectId: string;
|
||||
roles: (
|
||||
| {
|
||||
role: string;
|
||||
isTemporary?: false;
|
||||
}
|
||||
| {
|
||||
role: string;
|
||||
isTemporary: true;
|
||||
temporaryMode: ProjectUserMembershipTemporaryMode;
|
||||
temporaryRange: string;
|
||||
temporaryAccessStartTime: string;
|
||||
}
|
||||
)[];
|
||||
};
|
||||
|
||||
export type TUpdateWorkspaceGroupRoleDTO = {
|
||||
groupId: string;
|
||||
projectId: string;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./types";
|
||||
@@ -0,0 +1,37 @@
|
||||
import { IdentityAuthMethod } from "@app/hooks/api";
|
||||
|
||||
export enum TemporaryPermissionMode {
|
||||
Relative = "relative"
|
||||
}
|
||||
|
||||
export type TMetadata = {
|
||||
key: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export type TIdentity = {
|
||||
id: string;
|
||||
name: string;
|
||||
orgId: string;
|
||||
projectId: string | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
hasDeleteProtection: boolean;
|
||||
authMethods: IdentityAuthMethod[];
|
||||
activeLockoutAuthMethods: string[];
|
||||
metadata?: Array<TMetadata & { id: string }>;
|
||||
};
|
||||
|
||||
export type TRoles = Array<
|
||||
| {
|
||||
role: string;
|
||||
isTemporary?: false;
|
||||
}
|
||||
| {
|
||||
role: string;
|
||||
isTemporary: true;
|
||||
temporaryMode: TemporaryPermissionMode;
|
||||
temporaryRange: string;
|
||||
temporaryAccessStartTime: string;
|
||||
}
|
||||
>;
|
||||
@@ -7,7 +7,8 @@ import { SubscriptionPlan } from "./types";
|
||||
// import { Workspace } from './types';
|
||||
|
||||
export const subscriptionQueryKeys = {
|
||||
getOrgSubsription: (orgID: string) => ["plan", { orgID }] as const
|
||||
all: () => ["plan"] as const,
|
||||
getOrgSubsription: (orgID: string) => [...subscriptionQueryKeys.all(), { orgID }] as const
|
||||
};
|
||||
|
||||
export const fetchOrgSubscription = async (orgID: string, refreshCache: boolean = false) => {
|
||||
|
||||
+6
-3
@@ -3,6 +3,7 @@ import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||
import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
@@ -76,7 +77,9 @@ export const IdentityAliCloudAuthForm = ({
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityAliCloudAuth();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityAliCloudAuth();
|
||||
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
|
||||
@@ -144,7 +147,7 @@ export const IdentityAliCloudAuthForm = ({
|
||||
|
||||
if (data) {
|
||||
await updateMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
allowedArns,
|
||||
identityId,
|
||||
accessTokenTTL: Number(accessTokenTTL),
|
||||
@@ -154,7 +157,7 @@ export const IdentityAliCloudAuthForm = ({
|
||||
});
|
||||
} else {
|
||||
await addMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
identityId,
|
||||
allowedArns,
|
||||
accessTokenTTL: Number(accessTokenTTL),
|
||||
|
||||
+7
-6
@@ -3,6 +3,7 @@ import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||
import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
@@ -78,7 +79,9 @@ export const IdentityAwsAuthForm = ({
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityAwsAuth();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityAwsAuth();
|
||||
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
|
||||
@@ -154,7 +157,7 @@ export const IdentityAwsAuthForm = ({
|
||||
|
||||
if (data) {
|
||||
await updateMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
stsEndpoint,
|
||||
allowedPrincipalArns,
|
||||
allowedAccountIds,
|
||||
@@ -166,7 +169,7 @@ export const IdentityAwsAuthForm = ({
|
||||
});
|
||||
} else {
|
||||
await addMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
identityId,
|
||||
stsEndpoint: stsEndpoint || "",
|
||||
allowedPrincipalArns: allowedPrincipalArns || "",
|
||||
@@ -176,10 +179,8 @@ export const IdentityAwsAuthForm = ({
|
||||
accessTokenNumUsesLimit: Number(accessTokenNumUsesLimit),
|
||||
accessTokenTrustedIps
|
||||
});
|
||||
handlePopUpToggle("identityAuthMethod", false);
|
||||
}
|
||||
|
||||
handlePopUpToggle("identityAuthMethod", false);
|
||||
|
||||
createNotification({
|
||||
text: `Successfully ${isUpdate ? "updated" : "configured"} auth method`,
|
||||
type: "success"
|
||||
|
||||
+6
-3
@@ -3,6 +3,7 @@ import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||
import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
@@ -73,7 +74,9 @@ export const IdentityAzureAuthForm = ({
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityAzureAuth();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityAzureAuth();
|
||||
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
|
||||
@@ -150,7 +153,7 @@ export const IdentityAzureAuthForm = ({
|
||||
|
||||
if (data) {
|
||||
await updateMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
identityId,
|
||||
tenantId,
|
||||
resource,
|
||||
@@ -162,7 +165,7 @@ export const IdentityAzureAuthForm = ({
|
||||
});
|
||||
} else {
|
||||
await addMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
identityId,
|
||||
tenantId: tenantId || "",
|
||||
resource: resource || "",
|
||||
|
||||
+6
-4
@@ -3,6 +3,7 @@ import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||
import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
@@ -76,7 +77,9 @@ export const IdentityGcpAuthForm = ({
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityGcpAuth();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityGcpAuth();
|
||||
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
|
||||
@@ -160,7 +163,7 @@ export const IdentityGcpAuthForm = ({
|
||||
if (data) {
|
||||
await updateMutateAsync({
|
||||
identityId,
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
type,
|
||||
allowedServiceAccounts,
|
||||
allowedProjects,
|
||||
@@ -173,7 +176,7 @@ export const IdentityGcpAuthForm = ({
|
||||
} else {
|
||||
await addMutateAsync({
|
||||
identityId,
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
type,
|
||||
allowedServiceAccounts: allowedServiceAccounts || "",
|
||||
allowedProjects: allowedProjects || "",
|
||||
@@ -191,7 +194,6 @@ export const IdentityGcpAuthForm = ({
|
||||
text: `Successfully ${isUpdate ? "updated" : "configured"} auth method`,
|
||||
type: "success"
|
||||
});
|
||||
|
||||
reset();
|
||||
};
|
||||
|
||||
|
||||
+6
-4
@@ -4,6 +4,7 @@ import { faQuestionCircle } from "@fortawesome/free-regular-svg-icons";
|
||||
import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
@@ -109,7 +110,9 @@ export const IdentityJwtAuthForm = ({
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityJwtAuth();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityJwtAuth();
|
||||
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
|
||||
@@ -227,7 +230,7 @@ export const IdentityJwtAuthForm = ({
|
||||
if (data) {
|
||||
await updateMutateAsync({
|
||||
identityId,
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
configurationType,
|
||||
jwksUrl,
|
||||
jwksCaCert,
|
||||
@@ -252,7 +255,7 @@ export const IdentityJwtAuthForm = ({
|
||||
boundAudiences,
|
||||
boundClaims: Object.fromEntries(boundClaims.map((entry) => [entry.key, entry.value])),
|
||||
boundSubject,
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
accessTokenTTL: Number(accessTokenTTL),
|
||||
accessTokenMaxTTL: Number(accessTokenMaxTTL),
|
||||
accessTokenNumUsesLimit: Number(accessTokenNumUsesLimit),
|
||||
@@ -266,7 +269,6 @@ export const IdentityJwtAuthForm = ({
|
||||
text: `Successfully ${isUpdate ? "updated" : "configured"} auth method`,
|
||||
type: "success"
|
||||
});
|
||||
|
||||
reset();
|
||||
};
|
||||
|
||||
|
||||
+6
-3
@@ -4,6 +4,7 @@ import { faInfoCircle, faPlus, faXmark } from "@fortawesome/free-solid-svg-icons
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
@@ -117,7 +118,9 @@ export const IdentityKubernetesAuthForm = ({
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityKubernetesAuth();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityKubernetesAuth();
|
||||
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
|
||||
@@ -318,7 +321,7 @@ export const IdentityKubernetesAuthForm = ({
|
||||
|
||||
if (data) {
|
||||
await updateMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
...(tokenReviewMode === IdentityKubernetesAuthTokenReviewMode.Api
|
||||
? {
|
||||
kubernetesHost: kubernetesHost || ""
|
||||
@@ -341,7 +344,7 @@ export const IdentityKubernetesAuthForm = ({
|
||||
});
|
||||
} else {
|
||||
await addMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
identityId,
|
||||
...(tokenReviewMode === IdentityKubernetesAuthTokenReviewMode.Api
|
||||
? {
|
||||
|
||||
+5
-2
@@ -3,6 +3,7 @@ import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||
import { faPlus, faQuestionCircle, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import ms from "ms";
|
||||
import { z } from "zod";
|
||||
|
||||
@@ -168,7 +169,9 @@ export const IdentityLdapAuthForm = ({
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityLdapAuth();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityLdapAuth();
|
||||
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
|
||||
@@ -345,7 +348,7 @@ export const IdentityLdapAuthForm = ({
|
||||
ms(`${lockoutCounterResetValue}${lockoutCounterResetUnit}`) / 1000;
|
||||
|
||||
const basePayload = {
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
identityId,
|
||||
searchFilter,
|
||||
ldapCaCertificate,
|
||||
|
||||
+6
-4
@@ -3,6 +3,7 @@ import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||
import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
@@ -84,7 +85,9 @@ export const IdentityOciAuthForm = ({
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityOciAuth();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityOciAuth();
|
||||
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
|
||||
@@ -156,7 +159,7 @@ export const IdentityOciAuthForm = ({
|
||||
|
||||
if (data) {
|
||||
await updateMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
tenancyOcid,
|
||||
allowedUsernames,
|
||||
identityId,
|
||||
@@ -167,7 +170,7 @@ export const IdentityOciAuthForm = ({
|
||||
});
|
||||
} else {
|
||||
await addMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
identityId,
|
||||
tenancyOcid,
|
||||
allowedUsernames: allowedUsernames || undefined,
|
||||
@@ -184,7 +187,6 @@ export const IdentityOciAuthForm = ({
|
||||
text: `Successfully ${isUpdate ? "updated" : "configured"} auth method`,
|
||||
type: "success"
|
||||
});
|
||||
|
||||
reset();
|
||||
};
|
||||
|
||||
|
||||
+6
-4
@@ -4,6 +4,7 @@ import { faQuestionCircle } from "@fortawesome/free-regular-svg-icons";
|
||||
import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
@@ -96,7 +97,9 @@ export const IdentityOidcAuthForm = ({
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityOidcAuth();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityOidcAuth();
|
||||
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
|
||||
@@ -211,7 +214,7 @@ export const IdentityOidcAuthForm = ({
|
||||
if (data) {
|
||||
await updateMutateAsync({
|
||||
identityId,
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
oidcDiscoveryUrl,
|
||||
caCert,
|
||||
boundIssuer,
|
||||
@@ -238,7 +241,7 @@ export const IdentityOidcAuthForm = ({
|
||||
? Object.fromEntries(claimMetadataMapping.map((entry) => [entry.key, entry.value]))
|
||||
: undefined,
|
||||
boundSubject,
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
accessTokenTTL: Number(accessTokenTTL),
|
||||
accessTokenMaxTTL: Number(accessTokenMaxTTL),
|
||||
accessTokenNumUsesLimit: Number(accessTokenNumUsesLimit),
|
||||
@@ -252,7 +255,6 @@ export const IdentityOidcAuthForm = ({
|
||||
text: `Successfully ${isUpdate ? "updated" : "configured"} auth method`,
|
||||
type: "success"
|
||||
});
|
||||
|
||||
reset();
|
||||
};
|
||||
|
||||
|
||||
+69
-40
@@ -1,10 +1,18 @@
|
||||
import { faLink, faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faChevronDown, faLink, faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { OrgPermissionCan } from "@app/components/permissions";
|
||||
import { Button, DeleteActionModal, Modal, ModalContent } from "@app/components/v2";
|
||||
import {
|
||||
Button,
|
||||
DeleteActionModal,
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuTrigger,
|
||||
Modal,
|
||||
ModalContent
|
||||
} from "@app/components/v2";
|
||||
import { DocumentationLinkBadge } from "@app/components/v3";
|
||||
import {
|
||||
OrgPermissionIdentityActions,
|
||||
@@ -14,17 +22,17 @@ import {
|
||||
} from "@app/context";
|
||||
import { OrgPermissionMachineIdentityAuthTemplateActions } from "@app/context/OrgPermissionContext/types";
|
||||
import { withPermission } from "@app/hoc";
|
||||
import { useDeleteIdentity } from "@app/hooks/api";
|
||||
import { useDeleteOrgIdentity } from "@app/hooks/api";
|
||||
import { useDeleteIdentityAuthTemplate } from "@app/hooks/api/identityAuthTemplates";
|
||||
import { usePopUp } from "@app/hooks/usePopUp";
|
||||
|
||||
import { IdentityAuthTemplateModal } from "./IdentityAuthTemplateModal";
|
||||
import { IdentityAuthTemplatesTable } from "./IdentityAuthTemplatesTable";
|
||||
import { IdentityLinkForm } from "./IdentityLinkForm";
|
||||
import { IdentityModal } from "./IdentityModal";
|
||||
import { IdentityTable } from "./IdentityTable";
|
||||
import { IdentityTokenAuthTokenModal } from "./IdentityTokenAuthTokenModal";
|
||||
import { MachineAuthTemplateUsagesModal } from "./MachineAuthTemplateUsagesModal";
|
||||
import { OrgIdentityLinkForm } from "./OrgIdentityLinkForm";
|
||||
import { OrgIdentityModal } from "./OrgIdentityModal";
|
||||
|
||||
export const IdentitySection = withPermission(
|
||||
() => {
|
||||
@@ -32,7 +40,7 @@ export const IdentitySection = withPermission(
|
||||
const { currentOrg, isSubOrganization } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
|
||||
const { mutateAsync: deleteMutateAsync } = useDeleteIdentity();
|
||||
const { mutateAsync: deleteMutateAsync } = useDeleteOrgIdentity();
|
||||
const { mutateAsync: deleteTemplateMutateAsync } = useDeleteIdentityAuthTemplate();
|
||||
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
|
||||
"identity",
|
||||
@@ -46,7 +54,8 @@ export const IdentitySection = withPermission(
|
||||
"editTemplate",
|
||||
"deleteTemplate",
|
||||
"viewUsages",
|
||||
"linkIdentity"
|
||||
"linkIdentity",
|
||||
"addOptions"
|
||||
] as const);
|
||||
|
||||
const isMoreIdentitiesAllowed = subscription?.identityLimit
|
||||
@@ -58,7 +67,7 @@ export const IdentitySection = withPermission(
|
||||
const onDeleteIdentitySubmit = async (identityId: string) => {
|
||||
await deleteMutateAsync({
|
||||
identityId,
|
||||
organizationId: orgId
|
||||
orgId
|
||||
});
|
||||
|
||||
createNotification({
|
||||
@@ -91,50 +100,70 @@ export const IdentitySection = withPermission(
|
||||
<p className="text-xl font-medium text-mineshaft-100">Identities</p>
|
||||
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/identities/machine-identities" />
|
||||
</div>
|
||||
{isSubOrganization && (
|
||||
<div className="flex items-center">
|
||||
<OrgPermissionCan
|
||||
I={OrgPermissionIdentityActions.Create}
|
||||
a={OrgPermissionSubjects.Identity}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
variant="plain"
|
||||
colorSchema="secondary"
|
||||
leftIcon={<FontAwesomeIcon icon={faLink} />}
|
||||
variant="outline_bg"
|
||||
className={isSubOrganization ? "rounded-r-none" : ""}
|
||||
type="submit"
|
||||
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||
onClick={() => {
|
||||
handlePopUpOpen("linkIdentity");
|
||||
if (!isMoreIdentitiesAllowed && !isEnterprise) {
|
||||
handlePopUpOpen("upgradePlan", {
|
||||
description:
|
||||
"You can add more identities if you upgrade your Infisical Pro plan."
|
||||
});
|
||||
return;
|
||||
}
|
||||
handlePopUpOpen("identity");
|
||||
}}
|
||||
isDisabled={!isAllowed}
|
||||
>
|
||||
Link Identity
|
||||
Create Identity
|
||||
</Button>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
)}
|
||||
<OrgPermissionCan
|
||||
I={OrgPermissionIdentityActions.Create}
|
||||
a={OrgPermissionSubjects.Identity}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
colorSchema="secondary"
|
||||
type="submit"
|
||||
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||
onClick={() => {
|
||||
if (!isMoreIdentitiesAllowed && !isEnterprise) {
|
||||
handlePopUpOpen("upgradePlan", {
|
||||
text: "You have reached the maximum number of identities allowed on your current plan. Upgrade to Infisical Pro plan to add more identities."
|
||||
});
|
||||
return;
|
||||
}
|
||||
handlePopUpOpen("identity");
|
||||
}}
|
||||
isDisabled={!isAllowed}
|
||||
{isSubOrganization && (
|
||||
<DropdownMenu
|
||||
open={popUp.addOptions.isOpen}
|
||||
onOpenChange={(isOpen) => handlePopUpToggle("addOptions", isOpen)}
|
||||
>
|
||||
Create Identity
|
||||
</Button>
|
||||
<DropdownMenuTrigger>
|
||||
<Button
|
||||
variant="outline_bg"
|
||||
className="rounded-l-none border-l-mineshaft-800 px-3"
|
||||
>
|
||||
<FontAwesomeIcon icon={faChevronDown} />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" sideOffset={6} className="p-1">
|
||||
<OrgPermissionCan
|
||||
I={OrgPermissionIdentityActions.Create}
|
||||
a={OrgPermissionSubjects.Identity}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
variant="outline_bg"
|
||||
className="w-full"
|
||||
isDisabled={!isAllowed}
|
||||
leftIcon={<FontAwesomeIcon icon={faLink} />}
|
||||
onClick={() => {
|
||||
handlePopUpClose("addOptions");
|
||||
handlePopUpOpen("linkIdentity");
|
||||
}}
|
||||
>
|
||||
Assign Org Identity
|
||||
</Button>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
</div>
|
||||
</div>
|
||||
<IdentityTable handlePopUpOpen={handlePopUpOpen} />
|
||||
</div>
|
||||
@@ -173,7 +202,7 @@ export const IdentitySection = withPermission(
|
||||
</div>
|
||||
<IdentityAuthTemplatesTable handlePopUpOpen={handlePopUpOpen} />
|
||||
</div>
|
||||
<IdentityModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||
<OrgIdentityModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||
<IdentityAuthTemplateModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||
<MachineAuthTemplateUsagesModal
|
||||
isOpen={popUp.viewUsages.isOpen}
|
||||
@@ -193,10 +222,10 @@ export const IdentitySection = withPermission(
|
||||
>
|
||||
<ModalContent
|
||||
title="Assign Existing Identity"
|
||||
subTitle="Assign an existing identity from your root organization to the sub organization. The identity will continue to be managed at its original scope."
|
||||
subTitle="Assign an existing identity from your root organization to this sub organization. The identity will continue to be managed at its original scope."
|
||||
bodyClassName="overflow-visible"
|
||||
>
|
||||
<IdentityLinkForm onClose={() => handlePopUpClose("linkIdentity")} />
|
||||
<OrgIdentityLinkForm onClose={() => handlePopUpClose("linkIdentity")} />
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
<IdentityTokenAuthTokenModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||
|
||||
+18
-9
@@ -2,7 +2,6 @@ import { useCallback, useState } from "react";
|
||||
import {
|
||||
faArrowDown,
|
||||
faArrowUp,
|
||||
faBuilding,
|
||||
faCheckCircle,
|
||||
faChevronRight,
|
||||
faEdit,
|
||||
@@ -46,6 +45,7 @@ import {
|
||||
Tooltip,
|
||||
Tr
|
||||
} from "@app/components/v2";
|
||||
import { Badge, OrgIcon, SubOrgIcon } from "@app/components/v3";
|
||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects, useOrganization } from "@app/context";
|
||||
import {
|
||||
getUserTablePreference,
|
||||
@@ -56,8 +56,8 @@ import { usePagination, useResetPageHelper } from "@app/hooks";
|
||||
import {
|
||||
identityAuthToNameMap,
|
||||
useGetOrgRoles,
|
||||
useSearchIdentities,
|
||||
useUpdateIdentity
|
||||
useSearchOrgIdentityMemberships,
|
||||
useUpdateOrgIdentity
|
||||
} from "@app/hooks/api";
|
||||
import { OrderByDirection } from "@app/hooks/api/generic/types";
|
||||
import { OrgIdentityOrderBy } from "@app/hooks/api/organization/types";
|
||||
@@ -110,9 +110,9 @@ export const IdentityTable = ({ handlePopUpOpen }: Props) => {
|
||||
|
||||
const organizationId = currentOrg?.id || "";
|
||||
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentity();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateOrgIdentity();
|
||||
|
||||
const { data, isPending, isFetching } = useSearchIdentities({
|
||||
const { data, isPending, isFetching } = useSearchOrgIdentityMemberships({
|
||||
offset,
|
||||
limit,
|
||||
orderDirection,
|
||||
@@ -357,10 +357,19 @@ export const IdentityTable = ({ handlePopUpOpen }: Props) => {
|
||||
</Td>
|
||||
{isSubOrganization && (
|
||||
<Td>
|
||||
<p className="truncate">
|
||||
<FontAwesomeIcon size="sm" className="mr-1.5" icon={faBuilding} />
|
||||
{currentOrg.id === orgId ? "Sub Organization" : "Root Organization"}
|
||||
</p>
|
||||
<Badge variant="ghost">
|
||||
{currentOrg.id === orgId ? (
|
||||
<>
|
||||
<SubOrgIcon />
|
||||
Sub-Organization
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<OrgIcon />
|
||||
Root Organization
|
||||
</>
|
||||
)}
|
||||
</Badge>
|
||||
</Td>
|
||||
)}
|
||||
<Td>
|
||||
|
||||
+6
-4
@@ -3,6 +3,7 @@ import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||
import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
@@ -71,7 +72,9 @@ export const IdentityTlsCertAuthForm = ({
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityTlsCertAuth();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityTlsCertAuth();
|
||||
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
|
||||
@@ -141,7 +144,7 @@ export const IdentityTlsCertAuthForm = ({
|
||||
|
||||
if (data) {
|
||||
await updateMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
caCertificate,
|
||||
allowedCommonNames: allowedCommonNames || null,
|
||||
identityId,
|
||||
@@ -152,7 +155,7 @@ export const IdentityTlsCertAuthForm = ({
|
||||
});
|
||||
} else {
|
||||
await addMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
identityId,
|
||||
caCertificate,
|
||||
allowedCommonNames: allowedCommonNames || undefined,
|
||||
@@ -169,7 +172,6 @@ export const IdentityTlsCertAuthForm = ({
|
||||
text: `Successfully ${isUpdate ? "updated" : "configured"} auth method`,
|
||||
type: "success"
|
||||
});
|
||||
|
||||
reset();
|
||||
};
|
||||
|
||||
|
||||
+6
-3
@@ -3,6 +3,7 @@ import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||
import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
@@ -70,7 +71,9 @@ export const IdentityTokenAuthForm = ({
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityTokenAuth();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityTokenAuth();
|
||||
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
|
||||
@@ -134,7 +137,7 @@ export const IdentityTokenAuthForm = ({
|
||||
|
||||
if (data) {
|
||||
await updateMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
identityId,
|
||||
accessTokenTTL: Number(accessTokenTTL),
|
||||
accessTokenMaxTTL: Number(accessTokenMaxTTL),
|
||||
@@ -143,7 +146,7 @@ export const IdentityTokenAuthForm = ({
|
||||
});
|
||||
} else {
|
||||
await addMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
identityId,
|
||||
accessTokenTTL: Number(accessTokenTTL),
|
||||
accessTokenMaxTTL: Number(accessTokenMaxTTL),
|
||||
|
||||
+6
-3
@@ -3,6 +3,7 @@ import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||
import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import ms from "ms";
|
||||
import { z } from "zod";
|
||||
|
||||
@@ -105,6 +106,9 @@ export const IdentityUniversalAuthForm = ({
|
||||
identityId,
|
||||
isUpdate
|
||||
}: Props) => {
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
@@ -232,7 +236,7 @@ export const IdentityUniversalAuthForm = ({
|
||||
if (data) {
|
||||
// update universal auth configuration
|
||||
await updateMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
identityId,
|
||||
clientSecretTrustedIps,
|
||||
accessTokenTTL: Number(accessTokenTTL),
|
||||
@@ -249,7 +253,7 @@ export const IdentityUniversalAuthForm = ({
|
||||
// create new universal auth configuration
|
||||
|
||||
await addMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
identityId,
|
||||
clientSecretTrustedIps,
|
||||
accessTokenTTL: Number(accessTokenTTL),
|
||||
@@ -270,7 +274,6 @@ export const IdentityUniversalAuthForm = ({
|
||||
text: `Successfully ${isUpdate ? "updated" : "created"} auth method`,
|
||||
type: "success"
|
||||
});
|
||||
|
||||
reset();
|
||||
};
|
||||
|
||||
|
||||
+17
-4
@@ -1,13 +1,15 @@
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { Button, FilterableSelect, FormControl } from "@app/components/v2";
|
||||
import { useOrganization } from "@app/context";
|
||||
import { useGetAvailableOrgIdentities, useGetOrgRoles } from "@app/hooks/api";
|
||||
import { useGetOrgRoles } from "@app/hooks/api";
|
||||
import { useCreateOrgIdentityMembership } from "@app/hooks/api/orgIdentityMembership";
|
||||
import { orgIdentityMembershipQuery } from "@app/hooks/api/orgIdentityMembership/queries";
|
||||
|
||||
const schema = z
|
||||
.object({
|
||||
@@ -22,15 +24,26 @@ type Props = {
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
export const IdentityLinkForm = ({ onClose }: Props) => {
|
||||
export const OrgIdentityLinkForm = ({ onClose }: Props) => {
|
||||
const navigate = useNavigate();
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
|
||||
const { data: roles } = useGetOrgRoles(orgId);
|
||||
|
||||
// const [searchValue, setSearchValue] = useState("");
|
||||
//
|
||||
// const [debouncedSearchValue] = useDebounce(searchValue);
|
||||
|
||||
const { mutateAsync: createMutateAsync } = useCreateOrgIdentityMembership();
|
||||
const { data: rootOrgIdentities, isPending: isRootOrgLoading } = useGetAvailableOrgIdentities();
|
||||
|
||||
// TODO: name filter needs to be implemented on backend
|
||||
const { data: rootOrgIdentities, isPending: isRootOrgLoading } = useQuery({
|
||||
...orgIdentityMembershipQuery.listAvailable({
|
||||
// identityName: debouncedSearchValue
|
||||
}),
|
||||
placeholderData: (prev) => prev
|
||||
});
|
||||
|
||||
const {
|
||||
control,
|
||||
@@ -69,6 +82,7 @@ export const IdentityLinkForm = ({ onClose }: Props) => {
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
placeholder="Select identity..."
|
||||
// onInputChange={setSearchValue}
|
||||
options={rootOrgIdentities}
|
||||
getOptionValue={(option) => option.id}
|
||||
getOptionLabel={(option) => option.name}
|
||||
@@ -94,7 +108,6 @@ export const IdentityLinkForm = ({ onClose }: Props) => {
|
||||
placeholder="Select role..."
|
||||
getOptionValue={(option) => option.slug}
|
||||
getOptionLabel={(option) => option.name}
|
||||
// menuPortalTarget={document.body}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
+4
-4
@@ -20,7 +20,7 @@ import {
|
||||
} from "@app/components/v2";
|
||||
import { useOrganization } from "@app/context";
|
||||
import { findOrgMembershipRole } from "@app/helpers/roles";
|
||||
import { useCreateIdentity, useGetOrgRoles, useUpdateIdentity } from "@app/hooks/api";
|
||||
import { useCreateOrgIdentity, useGetOrgRoles, useUpdateOrgIdentity } from "@app/hooks/api";
|
||||
import { useAddIdentityUniversalAuth } from "@app/hooks/api/identities";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
@@ -47,7 +47,7 @@ type Props = {
|
||||
handlePopUpToggle: (popUpName: keyof UsePopUpState<["identity"]>, state?: boolean) => void;
|
||||
};
|
||||
|
||||
export const IdentityModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
export const OrgIdentityModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
const navigate = useNavigate();
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
@@ -55,8 +55,8 @@ export const IdentityModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
const { data: roles } = useGetOrgRoles(orgId);
|
||||
const isOrgIdentity = popUp?.identity?.data ? orgId === popUp?.identity?.data?.orgId : true;
|
||||
|
||||
const { mutateAsync: createMutateAsync } = useCreateIdentity();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentity();
|
||||
const { mutateAsync: createMutateAsync } = useCreateOrgIdentity();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateOrgIdentity();
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityUniversalAuth();
|
||||
|
||||
const {
|
||||
@@ -10,13 +10,13 @@ import { OrgPermissionCan } from "@app/components/permissions";
|
||||
import { DeleteActionModal, PageHeader } from "@app/components/v2";
|
||||
import { ROUTE_PATHS } from "@app/const/routes";
|
||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects, useOrganization } from "@app/context";
|
||||
import { useDeleteIdentity, useGetIdentityById } from "@app/hooks/api";
|
||||
import { useDeleteOrgIdentity, useGetOrgIdentityMembershipById } from "@app/hooks/api";
|
||||
import { usePopUp } from "@app/hooks/usePopUp";
|
||||
import { ViewIdentityAuthModal } from "@app/pages/organization/IdentityDetailsByIDPage/components/ViewIdentityAuthModal/ViewIdentityAuthModal";
|
||||
import { OrgAccessControlTabSections } from "@app/types/org";
|
||||
|
||||
import { IdentityAuthMethodModal } from "../AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityAuthMethodModal";
|
||||
import { IdentityModal } from "../AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityModal";
|
||||
import { OrgIdentityModal } from "../AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/OrgIdentityModal";
|
||||
import {
|
||||
IdentityAuthenticationSection,
|
||||
IdentityDetailsSection,
|
||||
@@ -31,8 +31,8 @@ const Page = () => {
|
||||
const identityId = params.identityId as string;
|
||||
const { currentOrg, isSubOrganization } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { data } = useGetIdentityById(identityId);
|
||||
const { mutateAsync: deleteIdentity } = useDeleteIdentity();
|
||||
const { data } = useGetOrgIdentityMembershipById(identityId);
|
||||
const { mutateAsync: deleteIdentity } = useDeleteOrgIdentity();
|
||||
const isAuthHidden = orgId !== data?.identity?.orgId;
|
||||
|
||||
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
|
||||
@@ -46,7 +46,7 @@ const Page = () => {
|
||||
const onDeleteIdentitySubmit = async (id: string) => {
|
||||
await deleteIdentity({
|
||||
identityId: id,
|
||||
organizationId: orgId
|
||||
orgId
|
||||
});
|
||||
|
||||
createNotification({
|
||||
@@ -100,7 +100,7 @@ const Page = () => {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<IdentityModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||
<OrgIdentityModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||
<IdentityAuthMethodModal
|
||||
popUp={popUp}
|
||||
handlePopUpOpen={handlePopUpOpen}
|
||||
|
||||
+6
-2
@@ -4,7 +4,11 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { OrgPermissionCan } from "@app/components/permissions";
|
||||
import { Button, Tooltip } from "@app/components/v2";
|
||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/context";
|
||||
import { IdentityAuthMethod, identityAuthToNameMap, useGetIdentityById } from "@app/hooks/api";
|
||||
import {
|
||||
IdentityAuthMethod,
|
||||
identityAuthToNameMap,
|
||||
useGetOrgIdentityMembershipById
|
||||
} from "@app/hooks/api";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
type Props = {
|
||||
@@ -16,7 +20,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export const IdentityAuthenticationSection = ({ identityId, handlePopUpOpen }: Props) => {
|
||||
const { data, refetch } = useGetIdentityById(identityId);
|
||||
const { data, refetch } = useGetOrgIdentityMembershipById(identityId);
|
||||
|
||||
return data ? (
|
||||
<div className="mt-4 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
|
||||
+3
-3
@@ -7,9 +7,9 @@ import { Button, IconButton, Tooltip } from "@app/components/v2";
|
||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/context";
|
||||
import { useTimedReset } from "@app/hooks";
|
||||
import {
|
||||
useGetIdentityById,
|
||||
useGetIdentityUniversalAuth,
|
||||
useGetIdentityUniversalAuthClientSecrets
|
||||
useGetIdentityUniversalAuthClientSecrets,
|
||||
useGetOrgIdentityMembershipById
|
||||
} from "@app/hooks/api";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
@@ -30,7 +30,7 @@ export const IdentityClientSecrets = ({ identityId, handlePopUpOpen }: Props) =>
|
||||
initialState: "Copy Client ID to clipboard"
|
||||
});
|
||||
|
||||
const { data } = useGetIdentityById(identityId);
|
||||
const { data } = useGetOrgIdentityMembershipById(identityId);
|
||||
const { data: identityUniversalAuth } = useGetIdentityUniversalAuth(identityId);
|
||||
const { data: clientSecrets } = useGetIdentityUniversalAuthClientSecrets(identityId);
|
||||
return (
|
||||
|
||||
+2
-2
@@ -11,7 +11,7 @@ import {
|
||||
IconButton,
|
||||
Tooltip
|
||||
} from "@app/components/v2";
|
||||
import { useGetIdentityById, useGetIdentityTokensTokenAuth } from "@app/hooks/api";
|
||||
import { useGetIdentityTokensTokenAuth, useGetOrgIdentityMembershipById } from "@app/hooks/api";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
type Props = {
|
||||
@@ -23,7 +23,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export const IdentityTokens = ({ identityId, handlePopUpOpen }: Props) => {
|
||||
const { data } = useGetIdentityById(identityId);
|
||||
const { data } = useGetOrgIdentityMembershipById(identityId);
|
||||
const { data: tokens } = useGetIdentityTokensTokenAuth(identityId);
|
||||
return (
|
||||
<div>
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ import {
|
||||
} from "@app/components/v2";
|
||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects, useOrganization } from "@app/context";
|
||||
import { useTimedReset } from "@app/hooks";
|
||||
import { identityAuthToNameMap, useGetIdentityById } from "@app/hooks/api";
|
||||
import { identityAuthToNameMap, useGetOrgIdentityMembershipById } from "@app/hooks/api";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
type Props = {
|
||||
@@ -41,7 +41,7 @@ export const IdentityDetailsSection = ({ identityId, handlePopUpOpen, isOrgIdent
|
||||
});
|
||||
const { isSubOrganization } = useOrganization();
|
||||
|
||||
const { data } = useGetIdentityById(identityId);
|
||||
const { data } = useGetOrgIdentityMembershipById(identityId);
|
||||
return data ? (
|
||||
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<div className="flex items-center justify-between border-b border-mineshaft-400 pb-4">
|
||||
|
||||
+2
-2
@@ -14,7 +14,7 @@ import {
|
||||
} from "@app/components/v2";
|
||||
import { useOrganization } from "@app/context";
|
||||
import {
|
||||
useAddIdentityToWorkspace,
|
||||
useCreateProjectIdentityMembership,
|
||||
useGetIdentityProjectMemberships,
|
||||
useGetProjectRoles,
|
||||
useGetUserProjects,
|
||||
@@ -45,7 +45,7 @@ type Props = {
|
||||
const Content = ({ identityId, handlePopUpToggle }: Omit<Props, "popUp">) => {
|
||||
const { currentOrg } = useOrganization();
|
||||
const { data: workspaces = [] } = useGetUserProjects();
|
||||
const { mutateAsync: addIdentityToWorkspace } = useAddIdentityToWorkspace();
|
||||
const { mutateAsync: addIdentityToWorkspace } = useCreateProjectIdentityMembership();
|
||||
|
||||
const {
|
||||
control,
|
||||
|
||||
+2
-2
@@ -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 { IdentityMembership } from "@app/hooks/api/identities/types";
|
||||
import { IdentityProjectMembership } 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: IdentityMembership;
|
||||
membership: IdentityProjectMembership;
|
||||
handlePopUpOpen: (
|
||||
popUpName: keyof UsePopUpState<["removeIdentityFromProject"]>,
|
||||
data?: object
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { DeleteActionModal, IconButton } from "@app/components/v2";
|
||||
import { useDeleteIdentityFromWorkspace } from "@app/hooks/api";
|
||||
import { useDeleteProjectIdentityMembership } from "@app/hooks/api";
|
||||
import { usePopUp } from "@app/hooks/usePopUp";
|
||||
|
||||
import { IdentityAddToProjectModal } from "./IdentityAddToProjectModal";
|
||||
@@ -14,7 +14,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export const IdentityProjectsSection = ({ identityId }: Props) => {
|
||||
const { mutateAsync: deleteMutateAsync } = useDeleteIdentityFromWorkspace();
|
||||
const { mutateAsync: deleteMutateAsync } = useDeleteProjectIdentityMembership();
|
||||
|
||||
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
|
||||
"addIdentityToProject",
|
||||
|
||||
+27
-6
@@ -1,11 +1,18 @@
|
||||
import { useState } from "react";
|
||||
import { subject } from "@casl/ability";
|
||||
import { UseMutationResult } from "@tanstack/react-query";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import ms from "ms";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { OrgPermissionCan } from "@app/components/permissions";
|
||||
import { VariablePermissionCan } from "@app/components/permissions";
|
||||
import { Button } from "@app/components/v2";
|
||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/context";
|
||||
import {
|
||||
OrgPermissionIdentityActions,
|
||||
OrgPermissionSubjects,
|
||||
ProjectPermissionIdentityActions,
|
||||
ProjectPermissionSub
|
||||
} from "@app/context";
|
||||
|
||||
import { IdentityAuthFieldDisplay } from "./IdentityAuthFieldDisplay";
|
||||
|
||||
@@ -31,7 +38,11 @@ export const LockoutFields = ({
|
||||
|
||||
const [lockedOutState, setLockedOutState] = useState(lockedOut);
|
||||
|
||||
const clearLockouts = async () => {
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
|
||||
async function clearLockouts() {
|
||||
const deleted = await mutateAsync({ identityId });
|
||||
createNotification({
|
||||
text: `Successfully cleared ${deleted} lockout${deleted === 1 ? "" : "s"}`,
|
||||
@@ -39,13 +50,23 @@ export const LockoutFields = ({
|
||||
});
|
||||
setLockedOutState(false);
|
||||
onResetAllLockouts();
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="col-span-2 mt-3 flex justify-between border-b border-mineshaft-500 pb-2">
|
||||
<span className="text-bunker-300">Lockout Options</span>
|
||||
<OrgPermissionCan I={OrgPermissionIdentityActions.Edit} a={OrgPermissionSubjects.Identity}>
|
||||
<VariablePermissionCan
|
||||
type={projectId ? "project" : "org"}
|
||||
I={projectId ? ProjectPermissionIdentityActions.Edit : OrgPermissionIdentityActions.Edit}
|
||||
a={
|
||||
projectId
|
||||
? subject(ProjectPermissionSub.Identity, {
|
||||
identityId
|
||||
})
|
||||
: OrgPermissionSubjects.Identity
|
||||
}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
isDisabled={!isAllowed || !lockedOutState || isPending}
|
||||
@@ -57,7 +78,7 @@ export const LockoutFields = ({
|
||||
Reset All Lockouts
|
||||
</Button>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
</VariablePermissionCan>
|
||||
</div>
|
||||
<IdentityAuthFieldDisplay label="Lockout Threshold">
|
||||
{data.lockoutThreshold}
|
||||
|
||||
+55
-12
@@ -1,10 +1,12 @@
|
||||
import { useState } from "react";
|
||||
import { subject } from "@casl/ability";
|
||||
import { faBan, faEdit, faKey, faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { format } from "date-fns";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { OrgPermissionCan } from "@app/components/permissions";
|
||||
import { VariablePermissionCan } from "@app/components/permissions";
|
||||
import {
|
||||
Button,
|
||||
DeleteActionModal,
|
||||
@@ -20,7 +22,12 @@ import {
|
||||
Tooltip,
|
||||
Tr
|
||||
} from "@app/components/v2";
|
||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/context";
|
||||
import {
|
||||
OrgPermissionIdentityActions,
|
||||
OrgPermissionSubjects,
|
||||
ProjectPermissionIdentityActions,
|
||||
ProjectPermissionSub
|
||||
} from "@app/context";
|
||||
import { usePopUp } from "@app/hooks";
|
||||
import { useRevokeIdentityTokenAuthToken } from "@app/hooks/api";
|
||||
import { IdentityAccessToken } from "@app/hooks/api/identities/types";
|
||||
@@ -37,6 +44,10 @@ export const IdentityTokenAuthTokensTable = ({ tokens, identityId }: Props) => {
|
||||
"revokeToken"
|
||||
] as const);
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
|
||||
const [page, setPage] = useState(1);
|
||||
const [perPage, setPerPage] = useState(5);
|
||||
|
||||
@@ -68,7 +79,17 @@ export const IdentityTokenAuthTokensTable = ({ tokens, identityId }: Props) => {
|
||||
<div className="col-span-2 mt-3">
|
||||
<div className="flex items-end justify-between border-b border-mineshaft-500 pb-2">
|
||||
<span className="text-bunker-300">Access Tokens</span>
|
||||
<OrgPermissionCan I={OrgPermissionIdentityActions.Edit} a={OrgPermissionSubjects.Identity}>
|
||||
<VariablePermissionCan
|
||||
type={projectId ? "project" : "org"}
|
||||
I={projectId ? ProjectPermissionIdentityActions.Edit : OrgPermissionIdentityActions.Edit}
|
||||
a={
|
||||
projectId
|
||||
? subject(ProjectPermissionSub.Identity, {
|
||||
identityId
|
||||
})
|
||||
: OrgPermissionSubjects.Identity
|
||||
}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
size="xs"
|
||||
@@ -84,7 +105,7 @@ export const IdentityTokenAuthTokensTable = ({ tokens, identityId }: Props) => {
|
||||
Add Token
|
||||
</Button>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
</VariablePermissionCan>
|
||||
</div>
|
||||
<TableContainer className="mt-4 rounded-none border-none">
|
||||
<Table>
|
||||
@@ -132,9 +153,20 @@ export const IdentityTokenAuthTokensTable = ({ tokens, identityId }: Props) => {
|
||||
</Td>
|
||||
<Td>
|
||||
<div className="flex items-center gap-2">
|
||||
<OrgPermissionCan
|
||||
I={OrgPermissionIdentityActions.Edit}
|
||||
a={OrgPermissionSubjects.Identity}
|
||||
<VariablePermissionCan
|
||||
type={projectId ? "project" : "org"}
|
||||
I={
|
||||
projectId
|
||||
? ProjectPermissionIdentityActions.Edit
|
||||
: OrgPermissionIdentityActions.Edit
|
||||
}
|
||||
a={
|
||||
projectId
|
||||
? subject(ProjectPermissionSub.Identity, {
|
||||
identityId
|
||||
})
|
||||
: OrgPermissionSubjects.Identity
|
||||
}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Tooltip content={isAllowed ? "Edit Token" : "Access Restricted"}>
|
||||
@@ -155,11 +187,22 @@ export const IdentityTokenAuthTokensTable = ({ tokens, identityId }: Props) => {
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
</VariablePermissionCan>
|
||||
{!isAccessTokenRevoked && (
|
||||
<OrgPermissionCan
|
||||
I={OrgPermissionIdentityActions.Edit}
|
||||
a={OrgPermissionSubjects.Identity}
|
||||
<VariablePermissionCan
|
||||
type={projectId ? "project" : "org"}
|
||||
I={
|
||||
projectId
|
||||
? ProjectPermissionIdentityActions.Edit
|
||||
: OrgPermissionIdentityActions.Edit
|
||||
}
|
||||
a={
|
||||
projectId
|
||||
? subject(ProjectPermissionSub.Identity, {
|
||||
identityId
|
||||
})
|
||||
: OrgPermissionSubjects.Identity
|
||||
}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Tooltip content={isAllowed ? "Revoke Token" : "Access Restricted"}>
|
||||
@@ -181,7 +224,7 @@ export const IdentityTokenAuthTokensTable = ({ tokens, identityId }: Props) => {
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
</VariablePermissionCan>
|
||||
)}
|
||||
</div>
|
||||
</Td>
|
||||
|
||||
+40
-8
@@ -1,10 +1,12 @@
|
||||
import { useState } from "react";
|
||||
import { subject } from "@casl/ability";
|
||||
import { faKey, faPlus, faTrash } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { format } from "date-fns";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { OrgPermissionCan } from "@app/components/permissions";
|
||||
import { VariablePermissionCan } from "@app/components/permissions";
|
||||
import {
|
||||
Button,
|
||||
DeleteActionModal,
|
||||
@@ -20,7 +22,12 @@ import {
|
||||
Tooltip,
|
||||
Tr
|
||||
} from "@app/components/v2";
|
||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/context";
|
||||
import {
|
||||
OrgPermissionIdentityActions,
|
||||
OrgPermissionSubjects,
|
||||
ProjectPermissionIdentityActions,
|
||||
ProjectPermissionSub
|
||||
} from "@app/context";
|
||||
import { usePopUp } from "@app/hooks";
|
||||
import { useRevokeIdentityUniversalAuthClientSecret } from "@app/hooks/api";
|
||||
import { ClientSecretData } from "@app/hooks/api/identities/types";
|
||||
@@ -37,6 +44,10 @@ export const IdentityUniversalAuthClientSecretsTable = ({ clientSecrets, identit
|
||||
"clientSecret"
|
||||
] as const);
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
|
||||
const [page, setPage] = useState(1);
|
||||
const [perPage, setPerPage] = useState(5);
|
||||
|
||||
@@ -60,7 +71,17 @@ export const IdentityUniversalAuthClientSecretsTable = ({ clientSecrets, identit
|
||||
<div className="col-span-2">
|
||||
<div className="flex items-end justify-between border-b border-mineshaft-500 pb-2">
|
||||
<span className="text-bunker-300">Client Secrets</span>
|
||||
<OrgPermissionCan I={OrgPermissionIdentityActions.Edit} a={OrgPermissionSubjects.Identity}>
|
||||
<VariablePermissionCan
|
||||
type={projectId ? "project" : "org"}
|
||||
I={projectId ? ProjectPermissionIdentityActions.Edit : OrgPermissionIdentityActions.Edit}
|
||||
a={
|
||||
projectId
|
||||
? subject(ProjectPermissionSub.Identity, {
|
||||
identityId
|
||||
})
|
||||
: OrgPermissionSubjects.Identity
|
||||
}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
isDisabled={!isAllowed}
|
||||
@@ -76,7 +97,7 @@ export const IdentityUniversalAuthClientSecretsTable = ({ clientSecrets, identit
|
||||
Add Client Secret
|
||||
</Button>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
</VariablePermissionCan>
|
||||
</div>
|
||||
<TableContainer className="mt-4 rounded-none border-none">
|
||||
<Table>
|
||||
@@ -120,9 +141,20 @@ export const IdentityUniversalAuthClientSecretsTable = ({ clientSecrets, identit
|
||||
{expiresAt ? format(expiresAt, "yyyy-MM-dd") : "-"}
|
||||
</Td>
|
||||
<Td>
|
||||
<OrgPermissionCan
|
||||
I={OrgPermissionIdentityActions.Edit}
|
||||
a={OrgPermissionSubjects.Identity}
|
||||
<VariablePermissionCan
|
||||
type={projectId ? "project" : "org"}
|
||||
I={
|
||||
projectId
|
||||
? ProjectPermissionIdentityActions.Edit
|
||||
: OrgPermissionIdentityActions.Edit
|
||||
}
|
||||
a={
|
||||
projectId
|
||||
? subject(ProjectPermissionSub.Identity, {
|
||||
identityId
|
||||
})
|
||||
: OrgPermissionSubjects.Identity
|
||||
}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Tooltip content={isAllowed ? "Delete Secret" : "Access Restricted"}>
|
||||
@@ -143,7 +175,7 @@ export const IdentityUniversalAuthClientSecretsTable = ({ clientSecrets, identit
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
</VariablePermissionCan>
|
||||
</Td>
|
||||
</Tr>
|
||||
);
|
||||
|
||||
+1
@@ -49,6 +49,7 @@ export const ViewIdentityAliCloudAuthContent = ({
|
||||
<ViewIdentityContentWrapper
|
||||
onEdit={() => handlePopUpOpen("identityAuthMethod")}
|
||||
onDelete={onDelete}
|
||||
identityId={identityId}
|
||||
>
|
||||
<IdentityAuthFieldDisplay label="Access Token TTL (seconds)">
|
||||
{data.accessTokenTTL}
|
||||
|
||||
+11
-4
@@ -1,3 +1,5 @@
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
|
||||
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { DeleteActionModal, Modal, ModalContent } from "@app/components/v2";
|
||||
@@ -46,8 +48,7 @@ type Props = {
|
||||
|
||||
type TRevokeOptions = {
|
||||
identityId: string;
|
||||
organizationId: string;
|
||||
};
|
||||
} & ({ projectId: string } | { organizationId: string });
|
||||
|
||||
export const Content = ({
|
||||
identityId,
|
||||
@@ -61,7 +62,9 @@ export const Content = ({
|
||||
>) => {
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp([
|
||||
"revokeAuthMethod",
|
||||
"upgradePlan",
|
||||
@@ -142,7 +145,11 @@ export const Content = ({
|
||||
const handleDeleteAuthMethod = async () => {
|
||||
await revokeMethod({
|
||||
identityId,
|
||||
organizationId: orgId
|
||||
...(projectId
|
||||
? { projectId }
|
||||
: {
|
||||
organizationId: orgId
|
||||
})
|
||||
});
|
||||
|
||||
createNotification({
|
||||
|
||||
+1
@@ -46,6 +46,7 @@ export const ViewIdentityAwsAuthContent = ({
|
||||
<ViewIdentityContentWrapper
|
||||
onEdit={() => handlePopUpOpen("identityAuthMethod")}
|
||||
onDelete={onDelete}
|
||||
identityId={identityId}
|
||||
>
|
||||
<IdentityAuthFieldDisplay label="Access Token TTL (seconds)">
|
||||
{data.accessTokenTTL}
|
||||
|
||||
+1
@@ -46,6 +46,7 @@ export const ViewIdentityAzureAuthContent = ({
|
||||
<ViewIdentityContentWrapper
|
||||
onEdit={() => handlePopUpOpen("identityAuthMethod")}
|
||||
onDelete={onDelete}
|
||||
identityId={identityId}
|
||||
>
|
||||
<IdentityAuthFieldDisplay label="Access Token TTL (seconds)">
|
||||
{data.accessTokenTTL}
|
||||
|
||||
+45
-11
@@ -1,8 +1,10 @@
|
||||
import { ReactNode } from "react";
|
||||
import { subject } from "@casl/ability";
|
||||
import { faChevronDown, faEdit, faTrash } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
|
||||
import { OrgPermissionCan } from "@app/components/permissions";
|
||||
import { VariablePermissionCan } from "@app/components/permissions";
|
||||
import {
|
||||
Button,
|
||||
DropdownMenu,
|
||||
@@ -10,15 +12,25 @@ import {
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger
|
||||
} from "@app/components/v2";
|
||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/context";
|
||||
import {
|
||||
OrgPermissionIdentityActions,
|
||||
OrgPermissionSubjects,
|
||||
ProjectPermissionIdentityActions,
|
||||
ProjectPermissionSub
|
||||
} from "@app/context";
|
||||
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
onEdit: VoidFunction;
|
||||
onDelete: VoidFunction;
|
||||
identityId: string;
|
||||
};
|
||||
|
||||
export const ViewIdentityContentWrapper = ({ children, onDelete, onEdit }: Props) => {
|
||||
export const ViewIdentityContentWrapper = ({ children, onDelete, onEdit, identityId }: Props) => {
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
<div>
|
||||
@@ -36,9 +48,20 @@ export const ViewIdentityContentWrapper = ({ children, onDelete, onEdit }: Props
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="mt-3 min-w-[120px]" align="end">
|
||||
<OrgPermissionCan
|
||||
I={OrgPermissionIdentityActions.Edit}
|
||||
a={OrgPermissionSubjects.Identity}
|
||||
<VariablePermissionCan
|
||||
type={projectId ? "project" : "org"}
|
||||
I={
|
||||
projectId
|
||||
? ProjectPermissionIdentityActions.Edit
|
||||
: OrgPermissionIdentityActions.Edit
|
||||
}
|
||||
a={
|
||||
projectId
|
||||
? subject(ProjectPermissionSub.Identity, {
|
||||
identityId
|
||||
})
|
||||
: OrgPermissionSubjects.Identity
|
||||
}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<DropdownMenuItem
|
||||
@@ -49,10 +72,21 @@ export const ViewIdentityContentWrapper = ({ children, onDelete, onEdit }: Props
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
<OrgPermissionCan
|
||||
I={OrgPermissionIdentityActions.Delete}
|
||||
a={OrgPermissionSubjects.Identity}
|
||||
</VariablePermissionCan>
|
||||
<VariablePermissionCan
|
||||
type={projectId ? "project" : "org"}
|
||||
I={
|
||||
projectId
|
||||
? ProjectPermissionIdentityActions.Delete
|
||||
: OrgPermissionIdentityActions.Delete
|
||||
}
|
||||
a={
|
||||
projectId
|
||||
? subject(ProjectPermissionSub.Identity, {
|
||||
identityId
|
||||
})
|
||||
: OrgPermissionSubjects.Identity
|
||||
}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<DropdownMenuItem
|
||||
@@ -63,7 +97,7 @@ export const ViewIdentityContentWrapper = ({ children, onDelete, onEdit }: Props
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
</VariablePermissionCan>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
|
||||
+1
@@ -46,6 +46,7 @@ export const ViewIdentityGcpAuthContent = ({
|
||||
<ViewIdentityContentWrapper
|
||||
onEdit={() => handlePopUpOpen("identityAuthMethod")}
|
||||
onDelete={onDelete}
|
||||
identityId={identityId}
|
||||
>
|
||||
<IdentityAuthFieldDisplay label="Access Token TTL (seconds)">
|
||||
{data.accessTokenTTL}
|
||||
|
||||
+1
@@ -49,6 +49,7 @@ export const ViewIdentityJwtAuthContent = ({
|
||||
<ViewIdentityContentWrapper
|
||||
onEdit={() => handlePopUpOpen("identityAuthMethod")}
|
||||
onDelete={onDelete}
|
||||
identityId={identityId}
|
||||
>
|
||||
<IdentityAuthFieldDisplay label="Access Token TTL (seconds)">
|
||||
{data.accessTokenTTL}
|
||||
|
||||
+1
@@ -59,6 +59,7 @@ export const ViewIdentityKubernetesAuthContent = ({
|
||||
<ViewIdentityContentWrapper
|
||||
onEdit={() => handlePopUpOpen("identityAuthMethod")}
|
||||
onDelete={onDelete}
|
||||
identityId={identityId}
|
||||
>
|
||||
<IdentityAuthFieldDisplay label="Access Token TTL (seconds)">
|
||||
{data.accessTokenTTL}
|
||||
|
||||
+1
@@ -52,6 +52,7 @@ export const ViewIdentityLdapAuthContent = ({
|
||||
<ViewIdentityContentWrapper
|
||||
onEdit={() => handlePopUpOpen("identityAuthMethod")}
|
||||
onDelete={onDelete}
|
||||
identityId={identityId}
|
||||
>
|
||||
<IdentityAuthFieldDisplay label="Access Token TTL (seconds)">
|
||||
{data.accessTokenTTL}
|
||||
|
||||
+1
@@ -46,6 +46,7 @@ export const ViewIdentityOciAuthContent = ({
|
||||
<ViewIdentityContentWrapper
|
||||
onEdit={() => handlePopUpOpen("identityAuthMethod")}
|
||||
onDelete={onDelete}
|
||||
identityId={identityId}
|
||||
>
|
||||
<IdentityAuthFieldDisplay label="Access Token TTL (seconds)">
|
||||
{data.accessTokenTTL}
|
||||
|
||||
+1
@@ -48,6 +48,7 @@ export const ViewIdentityOidcAuthContent = ({
|
||||
<ViewIdentityContentWrapper
|
||||
onEdit={() => handlePopUpOpen("identityAuthMethod")}
|
||||
onDelete={onDelete}
|
||||
identityId={identityId}
|
||||
>
|
||||
<IdentityAuthFieldDisplay label="Access Token TTL (seconds)">
|
||||
{data.accessTokenTTL}
|
||||
|
||||
+1
@@ -51,6 +51,7 @@ export const ViewIdentityTlsCertAuthContent = ({
|
||||
<ViewIdentityContentWrapper
|
||||
onEdit={() => handlePopUpOpen("identityAuthMethod")}
|
||||
onDelete={onDelete}
|
||||
identityId={identityId}
|
||||
>
|
||||
<IdentityAuthFieldDisplay label="Access Token TTL (seconds)">
|
||||
{data.accessTokenTTL}
|
||||
|
||||
+1
@@ -49,6 +49,7 @@ export const ViewIdentityTokenAuthContent = ({
|
||||
<ViewIdentityContentWrapper
|
||||
onEdit={() => handlePopUpOpen("identityAuthMethod")}
|
||||
onDelete={onDelete}
|
||||
identityId={identityId}
|
||||
>
|
||||
<IdentityAuthFieldDisplay label="Access Token TTL (seconds)">
|
||||
{data.accessTokenTTL}
|
||||
|
||||
+1
@@ -66,6 +66,7 @@ export const ViewIdentityUniversalAuthContent = ({
|
||||
<ViewIdentityContentWrapper
|
||||
onEdit={() => handlePopUpOpen("identityAuthMethod")}
|
||||
onDelete={onDelete}
|
||||
identityId={identityId}
|
||||
>
|
||||
{Number(data.accessTokenPeriod) > 0 ? (
|
||||
<IdentityAuthFieldDisplay label="Access Token Period (seconds)">
|
||||
|
||||
+136
-43
@@ -2,16 +2,17 @@ import { subject } from "@casl/ability";
|
||||
import {
|
||||
faArrowDown,
|
||||
faArrowUp,
|
||||
faChevronDown,
|
||||
faCircleXmark,
|
||||
faClock,
|
||||
faEllipsisV,
|
||||
faLink,
|
||||
faMagnifyingGlass,
|
||||
faPlus,
|
||||
faServer
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
import { format } from "date-fns";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
@@ -42,8 +43,19 @@ import {
|
||||
Tooltip,
|
||||
Tr
|
||||
} from "@app/components/v2";
|
||||
import { DocumentationLinkBadge } from "@app/components/v3";
|
||||
import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context";
|
||||
import {
|
||||
Badge,
|
||||
DocumentationLinkBadge,
|
||||
OrgIcon,
|
||||
ProjectIcon,
|
||||
SubOrgIcon
|
||||
} from "@app/components/v3";
|
||||
import {
|
||||
ProjectPermissionActions,
|
||||
ProjectPermissionSub,
|
||||
useOrganization,
|
||||
useProject
|
||||
} from "@app/context";
|
||||
import { getProjectBaseURL } from "@app/helpers/project";
|
||||
import { formatProjectRoleName } from "@app/helpers/roles";
|
||||
import {
|
||||
@@ -53,12 +65,17 @@ import {
|
||||
} from "@app/helpers/userTablePreferences";
|
||||
import { withProjectPermission } from "@app/hoc";
|
||||
import { usePagination, useResetPageHelper } from "@app/hooks";
|
||||
import { useDeleteIdentityFromWorkspace, useGetWorkspaceIdentityMemberships } from "@app/hooks/api";
|
||||
import {
|
||||
useDeleteProjectIdentity,
|
||||
useDeleteProjectIdentityMembership,
|
||||
useListProjectIdentityMemberships
|
||||
} from "@app/hooks/api";
|
||||
import { OrderByDirection } from "@app/hooks/api/generic/types";
|
||||
import { ProjectIdentityOrderBy } from "@app/hooks/api/projects/types";
|
||||
import { usePopUp } from "@app/hooks/usePopUp";
|
||||
import { ProjectIdentityModal } from "@app/pages/project/AccessControlPage/components/IdentityTab/components/ProjectIdentityModal";
|
||||
|
||||
import { IdentityModal } from "./components/IdentityModal";
|
||||
import { ProjectLinkIdentityModal } from "./components/ProjectLinkIdentityModal";
|
||||
|
||||
const MAX_ROLES_TO_BE_SHOWN_IN_TABLE = 2;
|
||||
|
||||
@@ -66,6 +83,7 @@ export const IdentityTab = withProjectPermission(
|
||||
() => {
|
||||
const { currentProject, projectId } = useProject();
|
||||
const navigate = useNavigate();
|
||||
const { isSubOrganization } = useOrganization();
|
||||
|
||||
const {
|
||||
offset,
|
||||
@@ -90,7 +108,7 @@ export const IdentityTab = withProjectPermission(
|
||||
setUserTablePreference("projectIdentityTable", PreferenceKey.PerPage, newPerPage);
|
||||
};
|
||||
|
||||
const { data, isPending, isFetching } = useGetWorkspaceIdentityMemberships(
|
||||
const { data, isPending, isFetching } = useListProjectIdentityMemberships(
|
||||
{
|
||||
projectId,
|
||||
offset,
|
||||
@@ -110,24 +128,39 @@ export const IdentityTab = withProjectPermission(
|
||||
setPage
|
||||
});
|
||||
|
||||
const { mutateAsync: deleteMutateAsync } = useDeleteIdentityFromWorkspace();
|
||||
const { mutateAsync: deleteMembershipMutateAsync } = useDeleteProjectIdentityMembership();
|
||||
const { mutateAsync: deleteProjectIdentity } = useDeleteProjectIdentity();
|
||||
|
||||
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
|
||||
"identity",
|
||||
"createIdentity",
|
||||
"linkIdentity",
|
||||
"deleteIdentity",
|
||||
"upgradePlan"
|
||||
"upgradePlan",
|
||||
"addOptions"
|
||||
] as const);
|
||||
|
||||
const onRemoveIdentitySubmit = async (identityId: string) => {
|
||||
await deleteMutateAsync({
|
||||
identityId,
|
||||
projectId
|
||||
});
|
||||
const onRemoveIdentitySubmit = async (identityId: string, isProjectIdentity: boolean) => {
|
||||
if (isProjectIdentity) {
|
||||
await deleteProjectIdentity({
|
||||
identityId,
|
||||
projectId
|
||||
});
|
||||
|
||||
createNotification({
|
||||
text: "Successfully removed identity from project",
|
||||
type: "success"
|
||||
});
|
||||
createNotification({
|
||||
text: "Successfully deleted project identity",
|
||||
type: "success"
|
||||
});
|
||||
} else {
|
||||
await deleteMembershipMutateAsync({
|
||||
identityId,
|
||||
projectId
|
||||
});
|
||||
|
||||
createNotification({
|
||||
text: "Successfully removed identity from project",
|
||||
type: "success"
|
||||
});
|
||||
}
|
||||
|
||||
handlePopUpClose("deleteIdentity");
|
||||
};
|
||||
@@ -151,22 +184,55 @@ export const IdentityTab = withProjectPermission(
|
||||
<p className="text-xl font-medium text-mineshaft-100">Identities</p>
|
||||
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/identities/machine-identities" />
|
||||
</div>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Create}
|
||||
a={ProjectPermissionSub.Identity}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
colorSchema="secondary"
|
||||
type="submit"
|
||||
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||
onClick={() => handlePopUpOpen("identity")}
|
||||
isDisabled={!isAllowed}
|
||||
>
|
||||
Add Identity
|
||||
</Button>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
<div className="flex items-center">
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Create}
|
||||
a={ProjectPermissionSub.Identity}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
variant="outline_bg"
|
||||
className="rounded-r-none"
|
||||
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||
onClick={() => handlePopUpOpen("createIdentity")}
|
||||
isDisabled={!isAllowed}
|
||||
>
|
||||
Create Identity
|
||||
</Button>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
<DropdownMenu
|
||||
open={popUp.addOptions.isOpen}
|
||||
onOpenChange={(isOpen) => handlePopUpToggle("addOptions", isOpen)}
|
||||
>
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="outline_bg" className="rounded-l-none border-l-mineshaft-800 px-3">
|
||||
<FontAwesomeIcon icon={faChevronDown} />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" sideOffset={6} className="p-1">
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Create}
|
||||
a={ProjectPermissionSub.Identity}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
variant="outline_bg"
|
||||
className="w-full"
|
||||
isDisabled={!isAllowed}
|
||||
leftIcon={<FontAwesomeIcon icon={faLink} />}
|
||||
onClick={() => {
|
||||
handlePopUpOpen("linkIdentity");
|
||||
handlePopUpClose("addOptions");
|
||||
}}
|
||||
>
|
||||
Assign Org Identity
|
||||
</Button>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</div>
|
||||
<Input
|
||||
containerClassName="mb-4"
|
||||
@@ -202,7 +268,7 @@ export const IdentityTab = withProjectPermission(
|
||||
</div>
|
||||
</Th>
|
||||
<Th className="w-1/3">Role</Th>
|
||||
<Th>Added on</Th>
|
||||
<Th>Managed by</Th>
|
||||
<Th className="w-5">{isFetching ? <Spinner size="xs" /> : null}</Th>
|
||||
</Tr>
|
||||
</THead>
|
||||
@@ -213,9 +279,8 @@ export const IdentityTab = withProjectPermission(
|
||||
data.identityMemberships.length > 0 &&
|
||||
data.identityMemberships.map((identityMember) => {
|
||||
const {
|
||||
identity: { id, name },
|
||||
roles,
|
||||
createdAt
|
||||
identity: { id, name, projectId: identityProjectId },
|
||||
roles
|
||||
} = identityMember;
|
||||
return (
|
||||
<Tr
|
||||
@@ -339,7 +404,27 @@ export const IdentityTab = withProjectPermission(
|
||||
)}
|
||||
</div>
|
||||
</Td>
|
||||
<Td>{format(new Date(createdAt), "yyyy-MM-dd")}</Td>
|
||||
<Td>
|
||||
<Badge variant="ghost">
|
||||
{/* eslint-disable-next-line no-nested-ternary */}
|
||||
{identityProjectId ? (
|
||||
<>
|
||||
<ProjectIcon />
|
||||
Project
|
||||
</>
|
||||
) : isSubOrganization ? (
|
||||
<>
|
||||
<SubOrgIcon />
|
||||
Sub-Organization
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<OrgIcon />
|
||||
Organization
|
||||
</>
|
||||
)}
|
||||
</Badge>
|
||||
</Td>
|
||||
<Td className="flex justify-end space-x-2">
|
||||
<Tooltip className="max-w-sm text-center" content="Options">
|
||||
<DropdownMenu>
|
||||
@@ -369,11 +454,14 @@ export const IdentityTab = withProjectPermission(
|
||||
evt.preventDefault();
|
||||
handlePopUpOpen("deleteIdentity", {
|
||||
identityId: id,
|
||||
name
|
||||
name,
|
||||
isProjectIdentity: Boolean(identityProjectId)
|
||||
});
|
||||
}}
|
||||
>
|
||||
Remove Identity From Project
|
||||
{identityProjectId
|
||||
? "Delete Project Identity"
|
||||
: "Remove Identity From Project"}
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
@@ -406,7 +494,11 @@ export const IdentityTab = withProjectPermission(
|
||||
/>
|
||||
)}
|
||||
</TableContainer>
|
||||
<IdentityModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||
<ProjectIdentityModal
|
||||
isOpen={popUp.createIdentity.isOpen}
|
||||
onOpenChange={(isOpen) => handlePopUpToggle("createIdentity", isOpen)}
|
||||
/>
|
||||
<ProjectLinkIdentityModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||
<DeleteActionModal
|
||||
isOpen={popUp.deleteIdentity.isOpen}
|
||||
title={`Are you sure you want to remove ${
|
||||
@@ -416,7 +508,8 @@ export const IdentityTab = withProjectPermission(
|
||||
deleteKey="confirm"
|
||||
onDeleteApproved={() =>
|
||||
onRemoveIdentitySubmit(
|
||||
(popUp?.deleteIdentity?.data as { identityId: string })?.identityId
|
||||
popUp?.deleteIdentity?.data?.identityId,
|
||||
popUp?.deleteIdentity?.data?.isProjectIdentity
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
+310
@@ -0,0 +1,310 @@
|
||||
import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||
import { faPlus, faTrash } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import {
|
||||
Button,
|
||||
FilterableSelect,
|
||||
FormControl,
|
||||
FormLabel,
|
||||
IconButton,
|
||||
Input,
|
||||
Modal,
|
||||
ModalContent,
|
||||
Switch
|
||||
} from "@app/components/v2";
|
||||
import { useProject } from "@app/context";
|
||||
import { getProjectBaseURL } from "@app/helpers/project";
|
||||
import {
|
||||
TProjectIdentity,
|
||||
useCreateProjectIdentity,
|
||||
useGetProjectRoles,
|
||||
useUpdateProjectIdentity,
|
||||
useUpdateProjectIdentityMembership
|
||||
} from "@app/hooks/api";
|
||||
import { useAddIdentityUniversalAuth } from "@app/hooks/api/identities";
|
||||
import { ProjectMembershipRole } from "@app/hooks/api/roles/types";
|
||||
|
||||
const schema = z.object({
|
||||
name: z.string().min(1, "Required"),
|
||||
hasDeleteProtection: z.boolean(),
|
||||
role: z.object({ slug: z.string(), name: z.string() }).optional(),
|
||||
metadata: z
|
||||
.object({
|
||||
key: z.string().trim().min(1),
|
||||
value: z.string().trim().min(1)
|
||||
})
|
||||
.array()
|
||||
.default([])
|
||||
.optional()
|
||||
});
|
||||
export type FormData = z.infer<typeof schema>;
|
||||
|
||||
type ContentProps = {
|
||||
onClose: () => void;
|
||||
identity?: TProjectIdentity;
|
||||
};
|
||||
|
||||
const Content = ({ onClose, identity }: ContentProps) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const { currentProject } = useProject();
|
||||
|
||||
const isUpdate = Boolean(identity);
|
||||
|
||||
const { data: roles } = useGetProjectRoles(currentProject.id);
|
||||
|
||||
const { mutateAsync: createMutateAsync } = useCreateProjectIdentity();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateProjectIdentity();
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityUniversalAuth();
|
||||
const { mutateAsync: updateMembershipMutateAsync } = useUpdateProjectIdentityMembership();
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
reset,
|
||||
formState: { isSubmitting }
|
||||
} = useForm<FormData>({
|
||||
resolver: zodResolver(schema),
|
||||
defaultValues: {
|
||||
name: identity?.name ?? "",
|
||||
hasDeleteProtection: identity?.hasDeleteProtection ?? false,
|
||||
metadata: identity?.metadata ?? [],
|
||||
role: isUpdate ? undefined : { slug: ProjectMembershipRole.NoAccess, name: "No Access" }
|
||||
}
|
||||
});
|
||||
|
||||
const metadataFormFields = useFieldArray({
|
||||
control,
|
||||
name: "metadata"
|
||||
});
|
||||
|
||||
const onFormSubmit = async ({ name, role, metadata, hasDeleteProtection }: FormData) => {
|
||||
try {
|
||||
if (identity) {
|
||||
// update
|
||||
await updateMutateAsync({
|
||||
identityId: identity.id,
|
||||
name,
|
||||
hasDeleteProtection,
|
||||
projectId: currentProject.id,
|
||||
metadata
|
||||
});
|
||||
|
||||
onClose();
|
||||
} else {
|
||||
// create
|
||||
|
||||
const { id: createdId } = await createMutateAsync({
|
||||
name,
|
||||
projectId: currentProject.id,
|
||||
hasDeleteProtection,
|
||||
metadata
|
||||
});
|
||||
|
||||
if (role) {
|
||||
await updateMembershipMutateAsync({
|
||||
roles: [{ role: role.slug }],
|
||||
identityId: createdId,
|
||||
projectId: currentProject.id
|
||||
});
|
||||
}
|
||||
|
||||
await addMutateAsync({
|
||||
projectId: currentProject.id,
|
||||
identityId: createdId,
|
||||
clientSecretTrustedIps: [{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }],
|
||||
accessTokenTrustedIps: [{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }],
|
||||
accessTokenTTL: 2592000,
|
||||
accessTokenMaxTTL: 2592000,
|
||||
accessTokenNumUsesLimit: 0,
|
||||
accessTokenPeriod: 0,
|
||||
lockoutEnabled: true,
|
||||
lockoutThreshold: 3,
|
||||
lockoutDurationSeconds: 300,
|
||||
lockoutCounterResetSeconds: 30
|
||||
});
|
||||
|
||||
onClose();
|
||||
navigate({
|
||||
to: `${getProjectBaseURL(currentProject.type)}/identities/$identityId`,
|
||||
params: {
|
||||
identityId: createdId
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
createNotification({
|
||||
text: `Successfully ${isUpdate ? "updated" : "created"} project identity`,
|
||||
type: "success"
|
||||
});
|
||||
|
||||
reset();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
const error = err as any;
|
||||
const text =
|
||||
error?.response?.data?.message ??
|
||||
`Failed to ${isUpdate ? "update" : "create"} project identity`;
|
||||
|
||||
createNotification({
|
||||
text,
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(onFormSubmit)}>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="name"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
className="mb-4"
|
||||
label="Name"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
<Input {...field} placeholder="Machine 1" />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
{!isUpdate && (
|
||||
<Controller
|
||||
control={control}
|
||||
name="role"
|
||||
render={({ field: { onChange, value }, fieldState: { error } }) => (
|
||||
<FormControl label="Role" errorText={error?.message} isError={Boolean(error)}>
|
||||
<FilterableSelect
|
||||
placeholder="Select role..."
|
||||
options={roles}
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
getOptionValue={(option) => option.slug}
|
||||
getOptionLabel={(option) => option.name}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<Controller
|
||||
control={control}
|
||||
name="hasDeleteProtection"
|
||||
render={({ field: { onChange, value }, fieldState: { error } }) => (
|
||||
<FormControl errorText={error?.message} isError={Boolean(error)}>
|
||||
<Switch
|
||||
className="mr-2 ml-0 bg-mineshaft-400/80 shadow-inner data-[state=checked]:bg-green/80"
|
||||
containerClassName="flex-row-reverse w-fit"
|
||||
id="delete-protection-enabled"
|
||||
thumbClassName="bg-mineshaft-800"
|
||||
onCheckedChange={onChange}
|
||||
isChecked={value}
|
||||
>
|
||||
<p>Delete Protection {value ? "Enabled" : "Disabled"}</p>
|
||||
</Switch>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<div>
|
||||
<FormLabel label="Metadata" />
|
||||
</div>
|
||||
<div className="mb-3 flex flex-col space-y-2">
|
||||
{metadataFormFields.fields.map(({ id: metadataFieldId }, i) => (
|
||||
<div key={metadataFieldId} className="flex items-end space-x-2">
|
||||
<div className="grow">
|
||||
{i === 0 && <span className="text-xs text-mineshaft-400">Key</span>}
|
||||
<Controller
|
||||
control={control}
|
||||
name={`metadata.${i}.key`}
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
isError={Boolean(error?.message)}
|
||||
errorText={error?.message}
|
||||
className="mb-0"
|
||||
>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="grow">
|
||||
{i === 0 && (
|
||||
<FormLabel label="Value" className="text-xs text-mineshaft-400" isOptional />
|
||||
)}
|
||||
<Controller
|
||||
control={control}
|
||||
name={`metadata.${i}.value`}
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
isError={Boolean(error?.message)}
|
||||
errorText={error?.message}
|
||||
className="mb-0"
|
||||
>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<IconButton
|
||||
ariaLabel="delete key"
|
||||
className="bottom-0.5 h-9"
|
||||
variant="outline_bg"
|
||||
onClick={() => metadataFormFields.remove(i)}
|
||||
>
|
||||
<FontAwesomeIcon icon={faTrash} />
|
||||
</IconButton>
|
||||
</div>
|
||||
))}
|
||||
<div className="mt-2 flex justify-end">
|
||||
<Button
|
||||
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||
size="xs"
|
||||
variant="outline_bg"
|
||||
onClick={() => metadataFormFields.append({ key: "", value: "" })}
|
||||
>
|
||||
Add Key
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<Button
|
||||
className="mr-4"
|
||||
size="sm"
|
||||
type="submit"
|
||||
isLoading={isSubmitting}
|
||||
isDisabled={isSubmitting}
|
||||
>
|
||||
{isUpdate ? "Update" : "Create"}
|
||||
</Button>
|
||||
<Button colorSchema="secondary" variant="plain" onClick={() => onClose()}>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
type Props = {
|
||||
isOpen: boolean;
|
||||
onOpenChange: (isOpen: boolean) => void;
|
||||
identity?: TProjectIdentity;
|
||||
};
|
||||
|
||||
export const ProjectIdentityModal = ({ isOpen, onOpenChange, identity }: Props) => {
|
||||
return (
|
||||
<Modal isOpen={isOpen} onOpenChange={(open) => onOpenChange(open)}>
|
||||
<ModalContent
|
||||
bodyClassName="overflow-visible"
|
||||
title={`${identity ? "Update" : "Create"} Project Identity`}
|
||||
>
|
||||
<Content identity={identity} onClose={() => onOpenChange(false)} />
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
+45
-73
@@ -1,10 +1,7 @@
|
||||
import { useMemo } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { components, OptionProps } from "react-select";
|
||||
import { faCheckCircle } from "@fortawesome/free-regular-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Link } from "@tanstack/react-router";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
@@ -17,64 +14,47 @@ import {
|
||||
ModalContent,
|
||||
Spinner
|
||||
} from "@app/components/v2";
|
||||
import { Badge, OrgIcon } from "@app/components/v3";
|
||||
import { useOrganization, useProject } from "@app/context";
|
||||
import { useProject } from "@app/context";
|
||||
import {
|
||||
useAddIdentityToWorkspace,
|
||||
useGetIdentityMembershipOrgs,
|
||||
projectIdentityMembershipQuery,
|
||||
useCreateProjectIdentityMembership,
|
||||
useGetProjectRoles,
|
||||
useGetWorkspaceIdentityMemberships
|
||||
useListProjectIdentityMemberships
|
||||
} from "@app/hooks/api";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
const schema = z.object({
|
||||
identity: z.object({ name: z.string(), id: z.string(), isManagedByRootOrg: z.boolean() }),
|
||||
identity: z.object({
|
||||
name: z.string(),
|
||||
id: z.string()
|
||||
}),
|
||||
role: z.object({ name: z.string(), slug: z.string() })
|
||||
});
|
||||
|
||||
export type FormData = z.infer<typeof schema>;
|
||||
|
||||
type Props = {
|
||||
popUp: UsePopUpState<["identity"]>;
|
||||
handlePopUpToggle: (popUpName: keyof UsePopUpState<["identity"]>, state?: boolean) => void;
|
||||
};
|
||||
|
||||
const Option = ({
|
||||
isSelected,
|
||||
children,
|
||||
...props
|
||||
}: OptionProps<{ name: string; id: string; isManagedByRootOrg: boolean }>) => {
|
||||
return (
|
||||
<components.Option isSelected={isSelected} {...props}>
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<p className="truncate">{children}</p>
|
||||
{props.data.isManagedByRootOrg && (
|
||||
<Badge variant="org" className="ml-auto">
|
||||
<OrgIcon />
|
||||
Organization
|
||||
</Badge>
|
||||
)}
|
||||
{isSelected && (
|
||||
<FontAwesomeIcon className="ml-2 text-primary" icon={faCheckCircle} size="sm" />
|
||||
)}
|
||||
</div>
|
||||
</components.Option>
|
||||
);
|
||||
popUp: UsePopUpState<["linkIdentity"]>;
|
||||
handlePopUpToggle: (popUpName: keyof UsePopUpState<["linkIdentity"]>, state?: boolean) => void;
|
||||
};
|
||||
|
||||
const Content = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
const { currentOrg } = useOrganization();
|
||||
const { projectId } = useProject();
|
||||
|
||||
const organizationId = currentOrg?.id || "";
|
||||
// const [searchValue, setSearchValue] = useState("");
|
||||
|
||||
const { data: identityMembershipOrgsData, isPending: isMembershipsLoading } =
|
||||
useGetIdentityMembershipOrgs({
|
||||
organizationId,
|
||||
limit: 20000 // TODO: this is temp to preserve functionality for larger projects, will replace with combobox in separate PR
|
||||
});
|
||||
const identityMembershipOrgs = identityMembershipOrgsData?.identityMemberships;
|
||||
const { data: identityMembershipsData } = useGetWorkspaceIdentityMemberships({
|
||||
// const [debouncedSearchValue] = useDebounce(searchValue);
|
||||
|
||||
// TODO: name search needs to be implemented on the backend
|
||||
const { data: identityMembershipOrgs, isPending: isMembershipsLoading } = useQuery({
|
||||
...projectIdentityMembershipQuery.listAvailable({
|
||||
projectId
|
||||
// identityName: debouncedSearchValue
|
||||
}),
|
||||
placeholderData: (prev) => prev
|
||||
});
|
||||
|
||||
const { data: identityMembershipsData } = useListProjectIdentityMemberships({
|
||||
projectId,
|
||||
limit: 20000 // TODO: this is temp to preserve functionality for larger projects, will optimize in PR referenced above
|
||||
});
|
||||
@@ -82,7 +62,8 @@ const Content = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
|
||||
const { data: roles, isPending: isRolesLoading } = useGetProjectRoles(projectId);
|
||||
|
||||
const { mutateAsync: addIdentityToWorkspaceMutateAsync } = useAddIdentityToWorkspace();
|
||||
const { mutateAsync: createProjectIdentityMembershipMutateAsync } =
|
||||
useCreateProjectIdentityMembership();
|
||||
|
||||
const filteredIdentityMembershipOrgs = useMemo(() => {
|
||||
const wsIdentityIds = new Map();
|
||||
@@ -91,7 +72,7 @@ const Content = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
wsIdentityIds.set(identityMembership.identity.id, true);
|
||||
});
|
||||
|
||||
return (identityMembershipOrgs || []).filter(({ identity: i }) => !wsIdentityIds.has(i.id));
|
||||
return (identityMembershipOrgs || []).filter((i) => !wsIdentityIds.has(i.id));
|
||||
}, [identityMembershipOrgs, identityMemberships]);
|
||||
|
||||
const {
|
||||
@@ -104,7 +85,7 @@ const Content = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
});
|
||||
|
||||
const onFormSubmit = async ({ identity, role }: FormData) => {
|
||||
await addIdentityToWorkspaceMutateAsync({
|
||||
await createProjectIdentityMembershipMutateAsync({
|
||||
projectId,
|
||||
identityId: identity.id,
|
||||
role: role.slug || undefined
|
||||
@@ -116,17 +97,17 @@ const Content = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
});
|
||||
|
||||
const nextAvailableMembership = filteredIdentityMembershipOrgs.filter(
|
||||
(membership) => membership.identity.id !== identity.id
|
||||
(membership) => membership.id !== identity.id
|
||||
)[0];
|
||||
|
||||
// prevents combobox from displaying previously added identity
|
||||
reset({
|
||||
identity: {
|
||||
name: nextAvailableMembership?.identity.name,
|
||||
id: nextAvailableMembership?.identity.id
|
||||
name: nextAvailableMembership?.name,
|
||||
id: nextAvailableMembership?.id
|
||||
}
|
||||
});
|
||||
handlePopUpToggle("identity", false);
|
||||
handlePopUpToggle("linkIdentity", false);
|
||||
};
|
||||
|
||||
if (isMembershipsLoading || isRolesLoading)
|
||||
@@ -136,7 +117,7 @@ const Content = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
</div>
|
||||
);
|
||||
|
||||
return filteredIdentityMembershipOrgs.length ? (
|
||||
return (
|
||||
<form onSubmit={handleSubmit(onFormSubmit)}>
|
||||
<Controller
|
||||
control={control}
|
||||
@@ -147,15 +128,13 @@ const Content = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
placeholder="Select identity..."
|
||||
// onInputChange={setSearchValue}
|
||||
options={filteredIdentityMembershipOrgs.map((membership) => ({
|
||||
...membership.identity,
|
||||
isManagedByRootOrg: membership.identity.orgId !== currentOrg.id
|
||||
name: membership.name,
|
||||
id: membership.id
|
||||
}))}
|
||||
getOptionValue={(option) => option.id}
|
||||
getOptionLabel={(option) => option.name}
|
||||
components={{
|
||||
Option
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
@@ -189,7 +168,7 @@ const Content = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
isLoading={isSubmitting}
|
||||
isDisabled={isSubmitting}
|
||||
>
|
||||
{popUp?.identity?.data ? "Update" : "Add"}
|
||||
{popUp?.linkIdentity?.data ? "Update" : "Link"}
|
||||
</Button>
|
||||
<ModalClose asChild>
|
||||
<Button colorSchema="secondary" variant="plain">
|
||||
@@ -198,29 +177,22 @@ const Content = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
</ModalClose>
|
||||
</div>
|
||||
</form>
|
||||
) : (
|
||||
<div className="flex flex-col space-y-4">
|
||||
<div className="text-sm">
|
||||
All identities in your organization have already been added to this project.
|
||||
</div>
|
||||
<Link to={"/organization/access-management" as const}>
|
||||
<Button isDisabled={isRolesLoading} isLoading={isRolesLoading} variant="outline_bg">
|
||||
Create a new identity
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const IdentityModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
export const ProjectLinkIdentityModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
return (
|
||||
<Modal
|
||||
isOpen={popUp?.identity?.isOpen}
|
||||
isOpen={popUp?.linkIdentity?.isOpen}
|
||||
onOpenChange={(isOpen) => {
|
||||
handlePopUpToggle("identity", isOpen);
|
||||
handlePopUpToggle("linkIdentity", isOpen);
|
||||
}}
|
||||
>
|
||||
<ModalContent title="Add Identity to Project" bodyClassName="overflow-visible">
|
||||
<ModalContent
|
||||
title="Assign Existing Identity"
|
||||
subTitle="Assign an existing identity from the parent organization to this project. The identity will continue to be managed at its original scope."
|
||||
bodyClassName="overflow-visible"
|
||||
>
|
||||
<Content popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
@@ -3,6 +3,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { subject } from "@casl/ability";
|
||||
import { faChevronLeft } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { Link, useNavigate, useParams } from "@tanstack/react-router";
|
||||
import { formatRelative } from "date-fns";
|
||||
|
||||
@@ -26,10 +27,13 @@ import { getProjectBaseURL, getProjectHomePage } from "@app/helpers/project";
|
||||
import { usePopUp } from "@app/hooks";
|
||||
import {
|
||||
useAssumeProjectPrivileges,
|
||||
useDeleteIdentityFromWorkspace,
|
||||
useGetWorkspaceIdentityMembershipDetails
|
||||
useDeleteProjectIdentityMembership,
|
||||
useGetProjectIdentityMembership
|
||||
} from "@app/hooks/api";
|
||||
import { ActorType } from "@app/hooks/api/auditLogs/enums";
|
||||
import { projectIdentityQuery } from "@app/hooks/api/projectIdentity";
|
||||
import { ProjectIdentityAuthenticationSection } from "@app/pages/project/IdentityDetailsByIDPage/components/ProjectIdentityAuthSection";
|
||||
import { ProjectIdentityDetailsSection } from "@app/pages/project/IdentityDetailsByIDPage/components/ProjectIdentityDetailsSection";
|
||||
import { ProjectAccessControlTabs } from "@app/types/project";
|
||||
|
||||
import { IdentityProjectAdditionalPrivilegeSection } from "./components/IdentityProjectAdditionalPrivilegeSection";
|
||||
@@ -44,10 +48,24 @@ const Page = () => {
|
||||
const { currentProject, projectId } = useProject();
|
||||
|
||||
const { data: identityMembershipDetails, isPending: isMembershipDetailsLoading } =
|
||||
useGetWorkspaceIdentityMembershipDetails(projectId, identityId);
|
||||
useGetProjectIdentityMembership(projectId, identityId);
|
||||
|
||||
const { mutateAsync: deleteMutateAsync, isPending: isDeletingIdentity } =
|
||||
useDeleteIdentityFromWorkspace();
|
||||
useDeleteProjectIdentityMembership();
|
||||
|
||||
const isProjectIdentity = Boolean(identityMembershipDetails?.identity.projectId);
|
||||
|
||||
const {
|
||||
data: identity,
|
||||
isPending: isProjectIdentityPending,
|
||||
refetch: refetchIdentity
|
||||
} = useQuery({
|
||||
...projectIdentityQuery.getById({
|
||||
identityId: identityMembershipDetails?.identity.id as string,
|
||||
projectId: identityMembershipDetails?.identity.projectId as string
|
||||
}),
|
||||
enabled: isProjectIdentity
|
||||
});
|
||||
|
||||
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
|
||||
"deleteIdentity",
|
||||
@@ -96,7 +114,7 @@ const Page = () => {
|
||||
});
|
||||
};
|
||||
|
||||
if (isMembershipDetailsLoading) {
|
||||
if (isMembershipDetailsLoading || (isProjectIdentity && isProjectIdentityPending)) {
|
||||
return (
|
||||
<div className="flex w-full items-center justify-center p-24">
|
||||
<Spinner />
|
||||
@@ -124,7 +142,7 @@ const Page = () => {
|
||||
<PageHeader
|
||||
scope={currentProject.type}
|
||||
title={identityMembershipDetails?.identity?.name}
|
||||
description={`Identity joined on ${identityMembershipDetails?.createdAt && formatRelative(new Date(identityMembershipDetails?.createdAt || ""), new Date())}`}
|
||||
description={`Identity ${isProjectIdentity ? "created" : "added"} on ${identityMembershipDetails?.createdAt && formatRelative(new Date(identityMembershipDetails?.createdAt || ""), new Date())}`}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
@@ -142,7 +160,9 @@ const Page = () => {
|
||||
</Button>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionIdentityActions.AssumePrivileges}
|
||||
a={ProjectPermissionSub.Identity}
|
||||
a={subject(ProjectPermissionSub.Identity, {
|
||||
identityId: identityMembershipDetails?.identity.id
|
||||
})}
|
||||
renderTooltip
|
||||
allowedLabel="Assume privileges of the user"
|
||||
passThrough={false}
|
||||
@@ -158,36 +178,54 @@ const Page = () => {
|
||||
</Button>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Delete}
|
||||
a={subject(ProjectPermissionSub.Identity, {
|
||||
identityId: identityMembershipDetails?.identity?.id
|
||||
})}
|
||||
renderTooltip
|
||||
allowedLabel="Remove from project"
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
colorSchema="danger"
|
||||
variant="outline_bg"
|
||||
size="xs"
|
||||
isDisabled={!isAllowed}
|
||||
isLoading={isDeletingIdentity}
|
||||
onClick={() => handlePopUpOpen("deleteIdentity")}
|
||||
>
|
||||
Remove Identity
|
||||
</Button>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
{!isProjectIdentity && (
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Delete}
|
||||
a={subject(ProjectPermissionSub.Identity, {
|
||||
identityId: identityMembershipDetails?.identity?.id
|
||||
})}
|
||||
renderTooltip
|
||||
allowedLabel="Remove from project"
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
colorSchema="danger"
|
||||
variant="outline_bg"
|
||||
size="xs"
|
||||
isDisabled={!isAllowed}
|
||||
isLoading={isDeletingIdentity}
|
||||
onClick={() => handlePopUpOpen("deleteIdentity")}
|
||||
>
|
||||
Remove Identity
|
||||
</Button>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
)}
|
||||
</div>
|
||||
</PageHeader>
|
||||
<IdentityRoleDetailsSection
|
||||
identityMembershipDetails={identityMembershipDetails}
|
||||
isMembershipDetailsLoading={isMembershipDetailsLoading}
|
||||
/>
|
||||
<IdentityProjectAdditionalPrivilegeSection
|
||||
identityMembershipDetails={identityMembershipDetails}
|
||||
/>
|
||||
<div className="flex gap-x-4">
|
||||
{identity && (
|
||||
<div className="flex w-72 flex-col gap-y-4">
|
||||
<ProjectIdentityDetailsSection
|
||||
identity={identity}
|
||||
membership={identityMembershipDetails!}
|
||||
/>
|
||||
<ProjectIdentityAuthenticationSection
|
||||
identity={identity}
|
||||
refetchIdentity={() => refetchIdentity()}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex-1">
|
||||
<IdentityRoleDetailsSection
|
||||
identityMembershipDetails={identityMembershipDetails}
|
||||
isMembershipDetailsLoading={isMembershipDetailsLoading}
|
||||
/>
|
||||
<IdentityProjectAdditionalPrivilegeSection
|
||||
identityMembershipDetails={identityMembershipDetails}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<DeleteActionModal
|
||||
isOpen={popUp.deleteIdentity.isOpen}
|
||||
title={`Are you sure you want to remove ${identityMembershipDetails?.identity?.name} from the project?`}
|
||||
|
||||
+2
-2
@@ -30,13 +30,13 @@ import {
|
||||
} from "@app/context";
|
||||
import { usePopUp } from "@app/hooks";
|
||||
import { useDeleteIdentityProjectAdditionalPrivilege } from "@app/hooks/api";
|
||||
import { IdentityMembership } from "@app/hooks/api/identities/types";
|
||||
import { IdentityProjectMembership } from "@app/hooks/api/identities/types";
|
||||
import { useListIdentityProjectPrivileges } from "@app/hooks/api/identityProjectAdditionalPrivilege/queries";
|
||||
|
||||
import { IdentityProjectAdditionalPrivilegeModifySection } from "./IdentityProjectAdditionalPrivilegeModifySection";
|
||||
|
||||
type Props = {
|
||||
identityMembershipDetails: IdentityMembership;
|
||||
identityMembershipDetails: IdentityProjectMembership;
|
||||
};
|
||||
|
||||
export const IdentityProjectAdditionalPrivilegeSection = ({ identityMembershipDetails }: Props) => {
|
||||
|
||||
+5
-5
@@ -26,14 +26,14 @@ import {
|
||||
import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context";
|
||||
import { formatProjectRoleName } from "@app/helpers/roles";
|
||||
import { usePopUp } from "@app/hooks";
|
||||
import { useUpdateIdentityWorkspaceRole } from "@app/hooks/api";
|
||||
import { IdentityMembership } from "@app/hooks/api/identities/types";
|
||||
import { useUpdateProjectIdentityMembership } from "@app/hooks/api";
|
||||
import { IdentityProjectMembership } from "@app/hooks/api/identities/types";
|
||||
import { TProjectRole } from "@app/hooks/api/roles/types";
|
||||
|
||||
import { IdentityRoleModify } from "./IdentityRoleModify";
|
||||
|
||||
type Props = {
|
||||
identityMembershipDetails: IdentityMembership;
|
||||
identityMembershipDetails: IdentityProjectMembership;
|
||||
isMembershipDetailsLoading?: boolean;
|
||||
};
|
||||
|
||||
@@ -46,12 +46,12 @@ export const IdentityRoleDetailsSection = ({
|
||||
"deleteRole",
|
||||
"modifyRole"
|
||||
] as const);
|
||||
const { mutateAsync: updateIdentityWorkspaceRole } = useUpdateIdentityWorkspaceRole();
|
||||
const { mutateAsync: updateIdentityProjectMembership } = useUpdateProjectIdentityMembership();
|
||||
|
||||
const handleRoleDelete = async () => {
|
||||
const { id } = popUp?.deleteRole?.data as TProjectRole;
|
||||
const updatedRoles = identityMembershipDetails?.roles?.filter((el) => el.id !== id);
|
||||
await updateIdentityWorkspaceRole({
|
||||
await updateIdentityProjectMembership({
|
||||
projectId: currentProject?.id || "",
|
||||
identityId: identityMembershipDetails.identity.id,
|
||||
roles: updatedRoles.map(
|
||||
|
||||
+8
-8
@@ -32,10 +32,10 @@ import {
|
||||
useProject,
|
||||
useProjectPermission
|
||||
} from "@app/context";
|
||||
import { useGetProjectRoles, useUpdateIdentityWorkspaceRole } from "@app/hooks/api";
|
||||
import { IdentityMembership } from "@app/hooks/api/identities/types";
|
||||
import { ProjectUserMembershipTemporaryMode } from "@app/hooks/api/projects/types";
|
||||
import { useGetProjectRoles, useUpdateProjectIdentityMembership } from "@app/hooks/api";
|
||||
import { IdentityProjectMembership } from "@app/hooks/api/identities/types";
|
||||
import { ProjectMembershipRole } from "@app/hooks/api/roles/types";
|
||||
import { TemporaryPermissionMode } from "@app/hooks/api/shared";
|
||||
|
||||
const roleFormSchema = z.object({
|
||||
roles: z
|
||||
@@ -58,7 +58,7 @@ const roleFormSchema = z.object({
|
||||
type TRoleForm = z.infer<typeof roleFormSchema>;
|
||||
|
||||
type Props = {
|
||||
identityProjectMembership: IdentityMembership;
|
||||
identityProjectMembership: IdentityProjectMembership;
|
||||
};
|
||||
|
||||
export const IdentityRoleModify = ({ identityProjectMembership }: Props) => {
|
||||
@@ -95,10 +95,10 @@ export const IdentityRoleModify = ({ identityProjectMembership }: Props) => {
|
||||
|
||||
const formRoleField = roleForm.watch("roles");
|
||||
|
||||
const updateIdentityWorkspaceRole = useUpdateIdentityWorkspaceRole();
|
||||
const updateProjectIdentityMembership = useUpdateProjectIdentityMembership();
|
||||
|
||||
const handleRoleUpdate = async (data: TRoleForm) => {
|
||||
if (updateIdentityWorkspaceRole.isPending) return;
|
||||
if (updateProjectIdentityMembership.isPending) return;
|
||||
|
||||
const sanitizedRoles = data.roles.map((el) => {
|
||||
const { isTemporary } = el.temporaryAccess;
|
||||
@@ -108,13 +108,13 @@ export const IdentityRoleModify = ({ identityProjectMembership }: Props) => {
|
||||
return {
|
||||
role: el.slug,
|
||||
isTemporary: true as const,
|
||||
temporaryMode: ProjectUserMembershipTemporaryMode.Relative,
|
||||
temporaryMode: TemporaryPermissionMode.Relative,
|
||||
temporaryRange: el.temporaryAccess.temporaryRange,
|
||||
temporaryAccessStartTime: el.temporaryAccess.temporaryAccessStartTime
|
||||
};
|
||||
});
|
||||
|
||||
await updateIdentityWorkspaceRole.mutateAsync({
|
||||
await updateProjectIdentityMembership.mutateAsync({
|
||||
projectId,
|
||||
identityId: identityProjectMembership.identity.id,
|
||||
roles: sanitizedRoles
|
||||
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
import { subject } from "@casl/ability";
|
||||
import { faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { LockIcon, SettingsIcon } from "lucide-react";
|
||||
|
||||
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
|
||||
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||
import { Button, Tooltip } from "@app/components/v2";
|
||||
import { Badge } from "@app/components/v3";
|
||||
import { ProjectPermissionIdentityActions, ProjectPermissionSub } from "@app/context";
|
||||
import { IdentityAuthMethod, identityAuthToNameMap, TProjectIdentity } from "@app/hooks/api";
|
||||
import { usePopUp } from "@app/hooks/usePopUp";
|
||||
import { IdentityAuthMethodModal } from "@app/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityAuthMethodModal";
|
||||
import { ViewIdentityAuthModal } from "@app/pages/organization/IdentityDetailsByIDPage/components/ViewIdentityAuthModal";
|
||||
|
||||
type Props = {
|
||||
identity: TProjectIdentity;
|
||||
refetchIdentity: () => void;
|
||||
};
|
||||
|
||||
export const ProjectIdentityAuthenticationSection = ({ identity, refetchIdentity }: Props) => {
|
||||
const { popUp, handlePopUpToggle, handlePopUpOpen } = usePopUp([
|
||||
"viewAuthMethod",
|
||||
"identityAuthMethod",
|
||||
"upgradePlan"
|
||||
]);
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<div className="flex items-center justify-between border-b border-mineshaft-400 pb-4">
|
||||
<h3 className="text-lg font-medium text-mineshaft-100">Authentication</h3>
|
||||
</div>
|
||||
{identity.authMethods.length > 0 ? (
|
||||
<div className="flex flex-col divide-y divide-mineshaft-400/50">
|
||||
{identity.authMethods.map((authMethod) => (
|
||||
<button
|
||||
key={authMethod}
|
||||
onClick={() =>
|
||||
handlePopUpOpen("viewAuthMethod", {
|
||||
authMethod,
|
||||
lockedOut: identity.activeLockoutAuthMethods?.includes(authMethod) ?? false,
|
||||
refetchIdentity
|
||||
})
|
||||
}
|
||||
type="button"
|
||||
className="flex w-full items-center justify-between bg-mineshaft-900 px-4 py-2 text-sm hover:bg-mineshaft-700 data-[state=open]:bg-mineshaft-600"
|
||||
>
|
||||
<span>{identityAuthToNameMap[authMethod]}</span>
|
||||
<div className="flex items-center gap-2">
|
||||
{identity.activeLockoutAuthMethods?.includes(authMethod) && (
|
||||
<Tooltip content="Auth method has active lockouts">
|
||||
<Badge isSquare variant="danger">
|
||||
<LockIcon />
|
||||
</Badge>
|
||||
</Tooltip>
|
||||
)}
|
||||
<SettingsIcon className="size-4 text-neutral" />
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="w-full space-y-2 pt-2">
|
||||
<p className="text-sm text-mineshaft-300">
|
||||
No authentication methods configured. Get started by creating a new auth method.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
{!Object.values(IdentityAuthMethod).every((method) =>
|
||||
identity.authMethods.includes(method)
|
||||
) && (
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionIdentityActions.Edit}
|
||||
a={subject(ProjectPermissionSub.Identity, {
|
||||
identityId: identity.id
|
||||
})}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
isDisabled={!isAllowed}
|
||||
onClick={() => {
|
||||
handlePopUpOpen("identityAuthMethod", {
|
||||
identityId: identity.id,
|
||||
name: identity.name,
|
||||
allAuthMethods: identity.authMethods
|
||||
});
|
||||
}}
|
||||
variant="outline_bg"
|
||||
className="mt-3 w-full"
|
||||
size="xs"
|
||||
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||
>
|
||||
{identity.authMethods.length ? "Add" : "Create"} Auth Method
|
||||
</Button>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
)}
|
||||
<IdentityAuthMethodModal
|
||||
popUp={popUp}
|
||||
handlePopUpOpen={handlePopUpOpen}
|
||||
handlePopUpToggle={handlePopUpToggle}
|
||||
/>
|
||||
<UpgradePlanModal
|
||||
isOpen={popUp.upgradePlan.isOpen}
|
||||
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
|
||||
text={(popUp.upgradePlan?.data as { description: string })?.description}
|
||||
isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature}
|
||||
/>
|
||||
<ViewIdentityAuthModal
|
||||
isOpen={popUp.viewAuthMethod.isOpen}
|
||||
onOpenChange={(isOpen) => handlePopUpToggle("viewAuthMethod", isOpen)}
|
||||
authMethod={popUp.viewAuthMethod.data?.authMethod}
|
||||
lockedOut={popUp.viewAuthMethod.data?.lockedOut || false}
|
||||
identityId={identity.id}
|
||||
onResetAllLockouts={popUp.viewAuthMethod.data?.refetchIdentity}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
+227
@@ -0,0 +1,227 @@
|
||||
import { subject } from "@casl/ability";
|
||||
import {
|
||||
faCheck,
|
||||
faChevronDown,
|
||||
faCopy,
|
||||
faEdit,
|
||||
faKey,
|
||||
faTrash
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
import { format } from "date-fns";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||
import {
|
||||
Button,
|
||||
DeleteActionModal,
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
IconButton,
|
||||
Tag,
|
||||
Tooltip
|
||||
} from "@app/components/v2";
|
||||
import { ProjectPermissionIdentityActions, ProjectPermissionSub, useProject } from "@app/context";
|
||||
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 { ProjectIdentityModal } from "@app/pages/project/AccessControlPage/components/IdentityTab/components/ProjectIdentityModal";
|
||||
|
||||
type Props = {
|
||||
identity: TProjectIdentity;
|
||||
membership: IdentityProjectMembership;
|
||||
};
|
||||
|
||||
export const ProjectIdentityDetailsSection = ({ identity, membership }: Props) => {
|
||||
const [copyTextId, isCopyingId, setCopyTextId] = useTimedReset<string>({
|
||||
initialState: "Copy ID to clipboard"
|
||||
});
|
||||
|
||||
const { currentProject } = useProject();
|
||||
const { mutateAsync: deleteIdentity } = useDeleteProjectIdentity();
|
||||
const navigate = useNavigate();
|
||||
const { popUp, handlePopUpToggle, handlePopUpOpen } = usePopUp([
|
||||
"editIdentity",
|
||||
"deleteIdentity"
|
||||
] as const);
|
||||
|
||||
const handleDeleteIdentity = async () => {
|
||||
try {
|
||||
await deleteIdentity({
|
||||
identityId: identity.id,
|
||||
projectId: identity.projectId!
|
||||
});
|
||||
|
||||
navigate({
|
||||
to: `${getProjectBaseURL(currentProject.type)}/access-management`,
|
||||
search: {
|
||||
selectedTab: "identities"
|
||||
}
|
||||
});
|
||||
} catch {
|
||||
createNotification({
|
||||
type: "error",
|
||||
text: "Failed to delete project identity"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<div className="flex items-center justify-between border-b border-mineshaft-400 pb-4">
|
||||
<h3 className="text-lg font-medium text-mineshaft-100">Identity Details</h3>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="xs"
|
||||
rightIcon={
|
||||
<FontAwesomeIcon
|
||||
className="ml-1 transition-transform duration-200 group-data-[state=open]:rotate-180"
|
||||
icon={faChevronDown}
|
||||
/>
|
||||
}
|
||||
colorSchema="secondary"
|
||||
className="group select-none"
|
||||
>
|
||||
Options
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="mt-3 min-w-[120px]" align="end">
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionIdentityActions.Edit}
|
||||
a={subject(ProjectPermissionSub.Identity, {
|
||||
identityId: identity.id
|
||||
})}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<DropdownMenuItem
|
||||
className={twMerge(
|
||||
!isAllowed && "pointer-events-none cursor-not-allowed opacity-50"
|
||||
)}
|
||||
icon={<FontAwesomeIcon icon={faEdit} />}
|
||||
onClick={async () => {
|
||||
handlePopUpOpen("editIdentity");
|
||||
}}
|
||||
disabled={!isAllowed}
|
||||
>
|
||||
Edit Identity
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionIdentityActions.Delete}
|
||||
a={subject(ProjectPermissionSub.Identity, {
|
||||
identityId: identity.id
|
||||
})}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<DropdownMenuItem
|
||||
className={twMerge(
|
||||
isAllowed
|
||||
? "hover:bg-red-500! hover:text-white!"
|
||||
: "pointer-events-none cursor-not-allowed opacity-50"
|
||||
)}
|
||||
onClick={async () => {
|
||||
handlePopUpOpen("deleteIdentity");
|
||||
}}
|
||||
icon={<FontAwesomeIcon icon={faTrash} />}
|
||||
disabled={!isAllowed}
|
||||
>
|
||||
Delete Identity
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
<div className="pt-4">
|
||||
<div className="mb-4">
|
||||
<p className="text-sm font-medium text-mineshaft-300">Identity ID</p>
|
||||
<div className="group flex align-top">
|
||||
<p className="text-sm text-mineshaft-300">{identity.id}</p>
|
||||
<div className="opacity-0 transition-opacity duration-300 group-hover:opacity-100">
|
||||
<Tooltip content={copyTextId}>
|
||||
<IconButton
|
||||
ariaLabel="copy icon"
|
||||
variant="plain"
|
||||
className="group relative ml-2"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(identity.id);
|
||||
setCopyTextId("Copied");
|
||||
}}
|
||||
>
|
||||
<FontAwesomeIcon icon={isCopyingId ? faCheck : faCopy} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<p className="text-sm font-medium text-mineshaft-300">Last Login Auth Method</p>
|
||||
<p className="text-sm text-mineshaft-300">
|
||||
{membership.lastLoginAuthMethod
|
||||
? identityAuthToNameMap[membership.lastLoginAuthMethod]
|
||||
: "-"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<p className="text-sm font-medium text-mineshaft-300">Last Login Time</p>
|
||||
<p className="text-sm text-mineshaft-300">
|
||||
{membership.lastLoginTime ? format(membership.lastLoginTime, "PPpp") : "-"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<p className="text-sm font-medium text-mineshaft-300">Delete Protection</p>
|
||||
<p className="text-sm text-mineshaft-300">
|
||||
{identity.hasDeleteProtection ? "On" : "Off"}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm font-medium text-mineshaft-300">Metadata</p>
|
||||
{identity?.metadata?.length ? (
|
||||
<div className="mt-1 flex flex-wrap gap-2 text-sm text-mineshaft-300">
|
||||
{identity.metadata?.map((el) => (
|
||||
<div key={el.id} className="flex items-center">
|
||||
<Tag
|
||||
size="xs"
|
||||
className="mr-0 flex items-center rounded-r-none border border-mineshaft-500"
|
||||
>
|
||||
<FontAwesomeIcon icon={faKey} size="xs" className="mr-1" />
|
||||
<div>{el.key}</div>
|
||||
</Tag>
|
||||
<Tag
|
||||
size="xs"
|
||||
className="flex items-center rounded-l-none border border-mineshaft-500 bg-mineshaft-900 pl-1"
|
||||
>
|
||||
<div className="max-w-[150px] overflow-hidden text-ellipsis whitespace-nowrap">
|
||||
{el.value}
|
||||
</div>
|
||||
</Tag>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-sm text-mineshaft-300">-</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<ProjectIdentityModal
|
||||
identity={identity}
|
||||
isOpen={popUp.editIdentity.isOpen}
|
||||
onOpenChange={(isOpen) => handlePopUpToggle("editIdentity", isOpen)}
|
||||
/>
|
||||
<DeleteActionModal
|
||||
isOpen={popUp.deleteIdentity.isOpen}
|
||||
title={`Are you sure you want to delete ${identity.name}?`}
|
||||
onChange={(isOpen) => handlePopUpToggle("deleteIdentity", isOpen)}
|
||||
deleteKey="confirm"
|
||||
onDeleteApproved={handleDeleteIdentity}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
+18
-2
@@ -180,7 +180,11 @@ const IdentityPolicyActionSchema = z.object({
|
||||
[ProjectPermissionIdentityActions.Edit]: z.boolean().optional(),
|
||||
[ProjectPermissionIdentityActions.Delete]: z.boolean().optional(),
|
||||
[ProjectPermissionIdentityActions.GrantPrivileges]: z.boolean().optional(),
|
||||
[ProjectPermissionIdentityActions.AssumePrivileges]: z.boolean().optional()
|
||||
[ProjectPermissionIdentityActions.AssumePrivileges]: z.boolean().optional(),
|
||||
[ProjectPermissionIdentityActions.RevokeAuth]: z.boolean().optional(),
|
||||
[ProjectPermissionIdentityActions.GetToken]: z.boolean().optional(),
|
||||
[ProjectPermissionIdentityActions.CreateToken]: z.boolean().optional(),
|
||||
[ProjectPermissionIdentityActions.DeleteToken]: z.boolean().optional()
|
||||
});
|
||||
|
||||
const GroupPolicyActionSchema = z.object({
|
||||
@@ -962,6 +966,10 @@ export const rolePermission2Form = (permissions: TProjectPermission[] = []) => {
|
||||
const canAssumePrivileges = action.includes(
|
||||
ProjectPermissionIdentityActions.AssumePrivileges
|
||||
);
|
||||
const canRevokeAuth = action.includes(ProjectPermissionIdentityActions.RevokeAuth);
|
||||
const canCreateToken = action.includes(ProjectPermissionIdentityActions.CreateToken);
|
||||
const canGetToken = action.includes(ProjectPermissionIdentityActions.GetToken);
|
||||
const canDeleteToken = action.includes(ProjectPermissionIdentityActions.DeleteToken);
|
||||
|
||||
if (!formVal[subject]) formVal[subject] = [{ conditions: [] }];
|
||||
|
||||
@@ -974,6 +982,10 @@ export const rolePermission2Form = (permissions: TProjectPermission[] = []) => {
|
||||
formVal[subject]![0][ProjectPermissionIdentityActions.GrantPrivileges] = true;
|
||||
if (canAssumePrivileges)
|
||||
formVal[subject]![0][ProjectPermissionIdentityActions.AssumePrivileges] = true;
|
||||
if (canRevokeAuth) formVal[subject]![0][ProjectPermissionIdentityActions.RevokeAuth] = true;
|
||||
if (canCreateToken) formVal[subject]![0][ProjectPermissionIdentityActions.CreateToken] = true;
|
||||
if (canGetToken) formVal[subject]![0][ProjectPermissionIdentityActions.GetToken] = true;
|
||||
if (canDeleteToken) formVal[subject]![0][ProjectPermissionIdentityActions.DeleteToken] = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1453,7 +1465,11 @@ export const PROJECT_PERMISSION_OBJECT: TProjectPermissionObject = {
|
||||
{ label: "Modify", value: ProjectPermissionIdentityActions.Edit },
|
||||
{ label: "Remove", value: ProjectPermissionIdentityActions.Delete },
|
||||
{ label: "Grant Privileges", value: ProjectPermissionIdentityActions.GrantPrivileges },
|
||||
{ label: "Assume Privileges", value: ProjectPermissionIdentityActions.AssumePrivileges }
|
||||
{ label: "Assume Privileges", value: ProjectPermissionIdentityActions.AssumePrivileges },
|
||||
{ label: "Revoke Auth", value: ProjectPermissionIdentityActions.RevokeAuth },
|
||||
{ label: "Create Token", value: ProjectPermissionIdentityActions.CreateToken },
|
||||
{ label: "Get Token", value: ProjectPermissionIdentityActions.GetToken },
|
||||
{ label: "Delete Token", value: ProjectPermissionIdentityActions.DeleteToken }
|
||||
]
|
||||
},
|
||||
[ProjectPermissionSub.Groups]: {
|
||||
|
||||
Reference in New Issue
Block a user