Merge pull request #2477 from meetcshah19/meet/eng-1519-allow-users-to-change-auth-method-in-the-ui-easily

feat: allow users to replace auth methods
This commit is contained in:
Maidul Islam
2024-09-30 23:38:02 -04:00
committed by GitHub
9 changed files with 1921 additions and 1539 deletions
+87 -23
View File
@@ -1,4 +1,4 @@
import { useQuery } from "@tanstack/react-query"; import { useQuery, UseQueryOptions } from "@tanstack/react-query";
import { apiRequest } from "@app/config/request"; import { apiRequest } from "@app/config/request";
@@ -13,7 +13,8 @@ import {
IdentityMembershipOrg, IdentityMembershipOrg,
IdentityOidcAuth, IdentityOidcAuth,
IdentityTokenAuth, IdentityTokenAuth,
IdentityUniversalAuth} from "./types"; IdentityUniversalAuth
} from "./types";
export const identitiesKeys = { export const identitiesKeys = {
getIdentityById: (identityId: string) => [{ identityId }, "identity"] as const, getIdentityById: (identityId: string) => [{ identityId }, "identity"] as const,
@@ -64,9 +65,16 @@ export const useGetIdentityProjectMemberships = (identityId: string) => {
}); });
}; };
export const useGetIdentityUniversalAuth = (identityId: string) => { export const useGetIdentityUniversalAuth = (
identityId: string,
options?: UseQueryOptions<
IdentityUniversalAuth,
unknown,
IdentityUniversalAuth,
ReturnType<typeof identitiesKeys.getIdentityUniversalAuth>
>
) => {
return useQuery({ return useQuery({
enabled: Boolean(identityId),
queryKey: identitiesKeys.getIdentityUniversalAuth(identityId), queryKey: identitiesKeys.getIdentityUniversalAuth(identityId),
queryFn: async () => { queryFn: async () => {
const { const {
@@ -76,8 +84,10 @@ export const useGetIdentityUniversalAuth = (identityId: string) => {
); );
return identityUniversalAuth; return identityUniversalAuth;
}, },
cacheTime: 0,
staleTime: 0, staleTime: 0,
cacheTime: 0 ...options,
enabled: Boolean(identityId) && (options?.enabled ?? true)
}); });
}; };
@@ -96,9 +106,16 @@ export const useGetIdentityUniversalAuthClientSecrets = (identityId: string) =>
}); });
}; };
export const useGetIdentityGcpAuth = (identityId: string) => { export const useGetIdentityGcpAuth = (
identityId: string,
options?: UseQueryOptions<
IdentityGcpAuth,
unknown,
IdentityGcpAuth,
ReturnType<typeof identitiesKeys.getIdentityGcpAuth>
>
) => {
return useQuery({ return useQuery({
enabled: Boolean(identityId),
queryKey: identitiesKeys.getIdentityGcpAuth(identityId), queryKey: identitiesKeys.getIdentityGcpAuth(identityId),
queryFn: async () => { queryFn: async () => {
const { const {
@@ -109,13 +126,22 @@ export const useGetIdentityGcpAuth = (identityId: string) => {
return identityGcpAuth; return identityGcpAuth;
}, },
staleTime: 0, staleTime: 0,
cacheTime: 0 cacheTime: 0,
...options,
enabled: Boolean(identityId) && (options?.enabled ?? true)
}); });
}; };
export const useGetIdentityAwsAuth = (identityId: string) => { export const useGetIdentityAwsAuth = (
identityId: string,
options?: UseQueryOptions<
IdentityAwsAuth,
unknown,
IdentityAwsAuth,
ReturnType<typeof identitiesKeys.getIdentityAwsAuth>
>
) => {
return useQuery({ return useQuery({
enabled: Boolean(identityId),
queryKey: identitiesKeys.getIdentityAwsAuth(identityId), queryKey: identitiesKeys.getIdentityAwsAuth(identityId),
queryFn: async () => { queryFn: async () => {
const { const {
@@ -126,13 +152,22 @@ export const useGetIdentityAwsAuth = (identityId: string) => {
return identityAwsAuth; return identityAwsAuth;
}, },
staleTime: 0, staleTime: 0,
cacheTime: 0 cacheTime: 0,
...options,
enabled: Boolean(identityId) && (options?.enabled ?? true)
}); });
}; };
export const useGetIdentityAzureAuth = (identityId: string) => { export const useGetIdentityAzureAuth = (
identityId: string,
options?: UseQueryOptions<
IdentityAzureAuth,
unknown,
IdentityAzureAuth,
ReturnType<typeof identitiesKeys.getIdentityAzureAuth>
>
) => {
return useQuery({ return useQuery({
enabled: Boolean(identityId),
queryKey: identitiesKeys.getIdentityAzureAuth(identityId), queryKey: identitiesKeys.getIdentityAzureAuth(identityId),
queryFn: async () => { queryFn: async () => {
const { const {
@@ -143,13 +178,22 @@ export const useGetIdentityAzureAuth = (identityId: string) => {
return identityAzureAuth; return identityAzureAuth;
}, },
staleTime: 0, staleTime: 0,
cacheTime: 0 cacheTime: 0,
...options,
enabled: Boolean(identityId) && (options?.enabled ?? true)
}); });
}; };
export const useGetIdentityKubernetesAuth = (identityId: string) => { export const useGetIdentityKubernetesAuth = (
identityId: string,
options?: UseQueryOptions<
IdentityKubernetesAuth,
unknown,
IdentityKubernetesAuth,
ReturnType<typeof identitiesKeys.getIdentityKubernetesAuth>
>
) => {
return useQuery({ return useQuery({
enabled: Boolean(identityId),
queryKey: identitiesKeys.getIdentityKubernetesAuth(identityId), queryKey: identitiesKeys.getIdentityKubernetesAuth(identityId),
queryFn: async () => { queryFn: async () => {
const { const {
@@ -160,13 +204,22 @@ export const useGetIdentityKubernetesAuth = (identityId: string) => {
return identityKubernetesAuth; return identityKubernetesAuth;
}, },
staleTime: 0, staleTime: 0,
cacheTime: 0 cacheTime: 0,
...options,
enabled: Boolean(identityId) && (options?.enabled ?? true)
}); });
}; };
export const useGetIdentityTokenAuth = (identityId: string) => { export const useGetIdentityTokenAuth = (
identityId: string,
options?: UseQueryOptions<
IdentityTokenAuth,
unknown,
IdentityTokenAuth,
ReturnType<typeof identitiesKeys.getIdentityTokenAuth>
>
) => {
return useQuery({ return useQuery({
enabled: Boolean(identityId),
queryKey: identitiesKeys.getIdentityTokenAuth(identityId), queryKey: identitiesKeys.getIdentityTokenAuth(identityId),
queryFn: async () => { queryFn: async () => {
const { const {
@@ -177,7 +230,9 @@ export const useGetIdentityTokenAuth = (identityId: string) => {
return identityTokenAuth; return identityTokenAuth;
}, },
staleTime: 0, staleTime: 0,
cacheTime: 0 cacheTime: 0,
...options,
enabled: Boolean(identityId) && (options?.enabled ?? true)
}); });
}; };
@@ -196,9 +251,16 @@ export const useGetIdentityTokensTokenAuth = (identityId: string) => {
}); });
}; };
export const useGetIdentityOidcAuth = (identityId: string) => { export const useGetIdentityOidcAuth = (
identityId: string,
options?: UseQueryOptions<
IdentityOidcAuth,
unknown,
IdentityOidcAuth,
ReturnType<typeof identitiesKeys.getIdentityOidcAuth>
>
) => {
return useQuery({ return useQuery({
enabled: Boolean(identityId),
queryKey: identitiesKeys.getIdentityOidcAuth(identityId), queryKey: identitiesKeys.getIdentityOidcAuth(identityId),
queryFn: async () => { queryFn: async () => {
const { const {
@@ -209,6 +271,8 @@ export const useGetIdentityOidcAuth = (identityId: string) => {
return identityOidcAuth; return identityOidcAuth;
}, },
staleTime: 0, staleTime: 0,
cacheTime: 0 cacheTime: 0,
...options,
enabled: Boolean(identityId) && (options?.enabled ?? true)
}); });
}; };
@@ -21,7 +21,8 @@ import {
useDeleteIdentityKubernetesAuth, useDeleteIdentityKubernetesAuth,
useDeleteIdentityOidcAuth, useDeleteIdentityOidcAuth,
useDeleteIdentityTokenAuth, useDeleteIdentityTokenAuth,
useDeleteIdentityUniversalAuth} from "@app/hooks/api"; useDeleteIdentityUniversalAuth
} from "@app/hooks/api";
import { IdentityAuthMethod, identityAuthToNameMap } from "@app/hooks/api/identities"; import { IdentityAuthMethod, identityAuthToNameMap } from "@app/hooks/api/identities";
import { UsePopUpState } from "@app/hooks/usePopUp"; import { UsePopUpState } from "@app/hooks/usePopUp";
@@ -54,7 +55,10 @@ const identityAuthMethods = [
const schema = yup const schema = yup
.object({ .object({
authMethod: yup.string().required("Auth method is required") authMethod: yup
.mixed<IdentityAuthMethod>()
.oneOf(Object.values(IdentityAuthMethod))
.required("Auth method is required")
}) })
.required(); .required();
@@ -72,14 +76,26 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog
const { mutateAsync: revokeAzureAuth } = useDeleteIdentityAzureAuth(); const { mutateAsync: revokeAzureAuth } = useDeleteIdentityAzureAuth();
const { mutateAsync: revokeOidcAuth } = useDeleteIdentityOidcAuth(); const { mutateAsync: revokeOidcAuth } = useDeleteIdentityOidcAuth();
const { control, watch, setValue } = useForm<FormData>({ const initialAuthMethod = popUp?.identityAuthMethod?.data?.authMethod;
const { control, watch, setValue, reset } = useForm<FormData>({
resolver: yupResolver(schema), resolver: yupResolver(schema),
defaultValues: { defaultValues: {
authMethod: IdentityAuthMethod.UNIVERSAL_AUTH authMethod: initialAuthMethod
} }
}); });
const identityAuthMethodData = popUp?.identityAuthMethod?.data as { useEffect(() => {
// reset form on open
if (popUp.identityAuthMethod.isOpen)
reset({ authMethod: popUp?.identityAuthMethod?.data?.authMethod });
}, [popUp.identityAuthMethod.isOpen]);
const identityAuthMethodData = {
identityId: popUp?.identityAuthMethod.data?.identityId,
name: popUp?.identityAuthMethod?.data?.name,
authMethod: watch("authMethod")
} as {
identityId: string; identityId: string;
name: string; name: string;
authMethod?: IdentityAuthMethod; authMethod?: IdentityAuthMethod;
@@ -94,85 +110,10 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog
setValue("authMethod", IdentityAuthMethod.UNIVERSAL_AUTH); setValue("authMethod", IdentityAuthMethod.UNIVERSAL_AUTH);
}, [identityAuthMethodData?.authMethod]); }, [identityAuthMethodData?.authMethod]);
const authMethod = watch("authMethod"); const onRevokeAuthMethodSubmit = async (authMethod: IdentityAuthMethod) => {
if (!orgId || !authMethod) return;
const renderIdentityAuthForm = () => {
switch (identityAuthMethodData?.authMethod ?? authMethod) {
case IdentityAuthMethod.AWS_AUTH: {
return (
<IdentityAwsAuthForm
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
identityAuthMethodData={identityAuthMethodData}
/>
);
}
case IdentityAuthMethod.KUBERNETES_AUTH: {
return (
<IdentityKubernetesAuthForm
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
identityAuthMethodData={identityAuthMethodData}
/>
);
}
case IdentityAuthMethod.GCP_AUTH: {
return (
<IdentityGcpAuthForm
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
identityAuthMethodData={identityAuthMethodData}
/>
);
}
case IdentityAuthMethod.AZURE_AUTH: {
return (
<IdentityAzureAuthForm
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
identityAuthMethodData={identityAuthMethodData}
/>
);
}
case IdentityAuthMethod.UNIVERSAL_AUTH: {
return (
<IdentityUniversalAuthForm
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
identityAuthMethodData={identityAuthMethodData}
/>
);
}
case IdentityAuthMethod.OIDC_AUTH: {
return (
<IdentityOidcAuthForm
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
identityAuthMethodData={identityAuthMethodData}
/>
);
}
case IdentityAuthMethod.TOKEN_AUTH: {
return (
<IdentityTokenAuthForm
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
identityAuthMethodData={identityAuthMethodData}
/>
);
}
default: {
return <div />;
}
}
};
const onRevokeAuthMethodSubmit = async () => {
if (!identityAuthMethodData.authMethod) return;
if (!orgId) return;
try { try {
console.log("onRevokeAuthMethodSubmit identityId: ", identityAuthMethodData); switch (authMethod) {
switch (identityAuthMethodData.authMethod) {
case IdentityAuthMethod.UNIVERSAL_AUTH: { case IdentityAuthMethod.UNIVERSAL_AUTH: {
await revokeUniversalAuth({ await revokeUniversalAuth({
identityId: identityAuthMethodData.identityId, identityId: identityAuthMethodData.identityId,
@@ -227,9 +168,7 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog
} }
createNotification({ createNotification({
text: `Successfully removed ${ text: `Successfully removed ${identityAuthToNameMap[authMethod]} on ${identityAuthMethodData.name}`,
identityAuthToNameMap[identityAuthMethodData.authMethod]
} on ${identityAuthMethodData.name}`,
type: "success" type: "success"
}); });
@@ -238,13 +177,95 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog
} catch (err) { } catch (err) {
console.error(err); console.error(err);
createNotification({ createNotification({
text: `Failed to remove ${identityAuthToNameMap[identityAuthMethodData.authMethod]} on ${ text: `Failed to remove ${identityAuthToNameMap[authMethod]} on ${identityAuthMethodData.name}`,
identityAuthMethodData.name
}`,
type: "error" type: "error"
}); });
} }
}; };
const renderIdentityAuthForm = () => {
switch (identityAuthMethodData.authMethod) {
case IdentityAuthMethod.AWS_AUTH: {
return (
<IdentityAwsAuthForm
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
identityAuthMethodData={identityAuthMethodData}
initialAuthMethod={initialAuthMethod!}
revokeAuth={onRevokeAuthMethodSubmit}
/>
);
}
case IdentityAuthMethod.KUBERNETES_AUTH: {
return (
<IdentityKubernetesAuthForm
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
identityAuthMethodData={identityAuthMethodData}
initialAuthMethod={initialAuthMethod!}
revokeAuth={onRevokeAuthMethodSubmit}
/>
);
}
case IdentityAuthMethod.GCP_AUTH: {
return (
<IdentityGcpAuthForm
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
identityAuthMethodData={identityAuthMethodData}
initialAuthMethod={initialAuthMethod!}
revokeAuth={onRevokeAuthMethodSubmit}
/>
);
}
case IdentityAuthMethod.AZURE_AUTH: {
return (
<IdentityAzureAuthForm
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
identityAuthMethodData={identityAuthMethodData}
initialAuthMethod={initialAuthMethod!}
revokeAuth={onRevokeAuthMethodSubmit}
/>
);
}
case IdentityAuthMethod.UNIVERSAL_AUTH: {
return (
<IdentityUniversalAuthForm
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
identityAuthMethodData={identityAuthMethodData}
initialAuthMethod={initialAuthMethod!}
revokeAuth={onRevokeAuthMethodSubmit}
/>
);
}
case IdentityAuthMethod.OIDC_AUTH: {
return (
<IdentityOidcAuthForm
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
identityAuthMethodData={identityAuthMethodData}
initialAuthMethod={initialAuthMethod!}
revokeAuth={onRevokeAuthMethodSubmit}
/>
);
}
case IdentityAuthMethod.TOKEN_AUTH: {
return (
<IdentityTokenAuthForm
handlePopUpOpen={handlePopUpOpen}
handlePopUpToggle={handlePopUpToggle}
identityAuthMethodData={identityAuthMethodData}
initialAuthMethod={initialAuthMethod!}
revokeAuth={onRevokeAuthMethodSubmit}
/>
);
}
default: {
return <div />;
}
}
};
return ( return (
<Modal <Modal
@@ -255,8 +276,10 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog
> >
<ModalContent <ModalContent
title={`${ title={`${
identityAuthMethodData?.authMethod ? "Update" : "Configure" identityAuthMethodData.authMethod === initialAuthMethod ? "Update" : "Configure"
} Identity Auth Method for ${identityAuthMethodData?.name ?? ""}`} } Identity Auth Method for ${
identityAuthToNameMap[identityAuthMethodData.authMethod!] ?? ""
}`}
> >
<Controller <Controller
control={control} control={control}
@@ -267,9 +290,10 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog
<Select <Select
defaultValue={field.value} defaultValue={field.value}
{...field} {...field}
onValueChange={(e) => onChange(e)} onValueChange={(e) => {
onChange(e);
}}
className="w-full" className="w-full"
isDisabled={!!identityAuthMethodData?.authMethod}
> >
{identityAuthMethods.map(({ label, value }) => ( {identityAuthMethods.map(({ label, value }) => (
<SelectItem value={String(value || "")} key={label}> <SelectItem value={String(value || "")} key={label}>
@@ -295,7 +319,8 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog
} on ${identityAuthMethodData?.name ?? ""}?`} } on ${identityAuthMethodData?.name ?? ""}?`}
onChange={(isOpen) => handlePopUpToggle("revokeAuthMethod", isOpen)} onChange={(isOpen) => handlePopUpToggle("revokeAuthMethod", isOpen)}
deleteKey="confirm" deleteKey="confirm"
onDeleteApproved={onRevokeAuthMethodSubmit} buttonText="Remove"
onDeleteApproved={() => onRevokeAuthMethodSubmit(identityAuthMethodData.authMethod!)}
/> />
</ModalContent> </ModalContent>
</Modal> </Modal>
@@ -6,7 +6,7 @@ import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup"; import * as yup from "yup";
import { createNotification } from "@app/components/notifications"; import { createNotification } from "@app/components/notifications";
import { Button, FormControl, IconButton, Input } from "@app/components/v2"; import { Button, DeleteActionModal, FormControl, IconButton, Input } from "@app/components/v2";
import { useOrganization, useSubscription } from "@app/context"; import { useOrganization, useSubscription } from "@app/context";
import { import {
useAddIdentityAwsAuth, useAddIdentityAwsAuth,
@@ -15,7 +15,7 @@ import {
} from "@app/hooks/api"; } from "@app/hooks/api";
import { IdentityAuthMethod } from "@app/hooks/api/identities"; import { IdentityAuthMethod } from "@app/hooks/api/identities";
import { IdentityTrustedIp } from "@app/hooks/api/identities/types"; import { IdentityTrustedIp } from "@app/hooks/api/identities/types";
import { UsePopUpState } from "@app/hooks/usePopUp"; import { usePopUp, UsePopUpState } from "@app/hooks/usePopUp";
const schema = yup const schema = yup
.object({ .object({
@@ -64,12 +64,16 @@ type Props = {
name: string; name: string;
authMethod?: IdentityAuthMethod; authMethod?: IdentityAuthMethod;
}; };
initialAuthMethod: IdentityAuthMethod;
revokeAuth: (authMethod: IdentityAuthMethod) => Promise<void>;
}; };
export const IdentityAwsAuthForm = ({ export const IdentityAwsAuthForm = ({
handlePopUpOpen, handlePopUpOpen,
handlePopUpToggle, handlePopUpToggle,
identityAuthMethodData identityAuthMethodData,
initialAuthMethod,
revokeAuth
}: Props) => { }: Props) => {
const { currentOrg } = useOrganization(); const { currentOrg } = useOrganization();
const orgId = currentOrg?.id || ""; const orgId = currentOrg?.id || "";
@@ -78,7 +82,12 @@ export const IdentityAwsAuthForm = ({
const { mutateAsync: addMutateAsync } = useAddIdentityAwsAuth(); const { mutateAsync: addMutateAsync } = useAddIdentityAwsAuth();
const { mutateAsync: updateMutateAsync } = useUpdateIdentityAwsAuth(); const { mutateAsync: updateMutateAsync } = useUpdateIdentityAwsAuth();
const { data } = useGetIdentityAwsAuth(identityAuthMethodData?.identityId ?? ""); const isCurrentAuthMethod = identityAuthMethodData?.authMethod === initialAuthMethod;
const { data } = useGetIdentityAwsAuth(identityAuthMethodData?.identityId ?? "", {
enabled: isCurrentAuthMethod
});
const internalPopUpState = usePopUp(["overwriteAuthMethod"] as const);
const { const {
control, control,
@@ -175,9 +184,7 @@ export const IdentityAwsAuthForm = ({
handlePopUpToggle("identityAuthMethod", false); handlePopUpToggle("identityAuthMethod", false);
createNotification({ createNotification({
text: `Successfully ${ text: `Successfully ${isCurrentAuthMethod ? "updated" : "configured"} auth method`,
identityAuthMethodData?.authMethod ? "updated" : "configured"
} auth method`,
type: "success" type: "success"
}); });
@@ -191,6 +198,7 @@ export const IdentityAwsAuthForm = ({
}; };
return ( return (
<>
<form onSubmit={handleSubmit(onFormSubmit)}> <form onSubmit={handleSubmit(onFormSubmit)}>
<Controller <Controller
control={control} control={control}
@@ -345,6 +353,17 @@ export const IdentityAwsAuthForm = ({
</div> </div>
<div className="flex justify-between"> <div className="flex justify-between">
<div className="flex items-center"> <div className="flex items-center">
{initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod ? (
<Button
className="mr-4"
size="sm"
isLoading={isSubmitting}
isDisabled={isSubmitting}
onClick={() => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", true)}
>
Overwrite
</Button>
) : (
<Button <Button
className="mr-4" className="mr-4"
size="sm" size="sm"
@@ -352,8 +371,9 @@ export const IdentityAwsAuthForm = ({
isLoading={isSubmitting} isLoading={isSubmitting}
isDisabled={isSubmitting} isDisabled={isSubmitting}
> >
{identityAuthMethodData?.authMethod ? "Update" : "Configure"} Submit
</Button> </Button>
)}
<Button <Button
colorSchema="secondary" colorSchema="secondary"
variant="plain" variant="plain"
@@ -362,7 +382,7 @@ export const IdentityAwsAuthForm = ({
Cancel Cancel
</Button> </Button>
</div> </div>
{identityAuthMethodData?.authMethod && ( {isCurrentAuthMethod && (
<Button <Button
size="sm" size="sm"
colorSchema="danger" colorSchema="danger"
@@ -375,5 +395,19 @@ export const IdentityAwsAuthForm = ({
)} )}
</div> </div>
</form> </form>
<DeleteActionModal
isOpen={internalPopUpState.popUp.overwriteAuthMethod?.isOpen}
title={`Are you sure want to overwrite ${initialAuthMethod || "the auth method"} on ${
identityAuthMethodData?.name ?? ""
}?`}
onChange={(isOpen) => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", isOpen)}
deleteKey="confirm"
buttonText="Overwrite"
onDeleteApproved={async () => {
await revokeAuth(initialAuthMethod);
handleSubmit(onFormSubmit)();
}}
/>
</>
); );
}; };
@@ -6,7 +6,7 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod"; import { z } from "zod";
import { createNotification } from "@app/components/notifications"; import { createNotification } from "@app/components/notifications";
import { Button, FormControl, IconButton, Input } from "@app/components/v2"; import { Button, DeleteActionModal, FormControl, IconButton, Input } from "@app/components/v2";
import { useOrganization, useSubscription } from "@app/context"; import { useOrganization, useSubscription } from "@app/context";
import { import {
useAddIdentityAzureAuth, useAddIdentityAzureAuth,
@@ -15,11 +15,11 @@ import {
} from "@app/hooks/api"; } from "@app/hooks/api";
import { IdentityAuthMethod } from "@app/hooks/api/identities"; import { IdentityAuthMethod } from "@app/hooks/api/identities";
import { IdentityTrustedIp } from "@app/hooks/api/identities/types"; import { IdentityTrustedIp } from "@app/hooks/api/identities/types";
import { UsePopUpState } from "@app/hooks/usePopUp"; import { usePopUp, UsePopUpState } from "@app/hooks/usePopUp";
const schema = z const schema = z
.object({ .object({
tenantId: z.string(), tenantId: z.string().min(1),
resource: z.string(), resource: z.string(),
allowedServicePrincipalIds: z.string(), allowedServicePrincipalIds: z.string(),
accessTokenTTL: z.string().refine((val) => Number(val) <= 315360000, { accessTokenTTL: z.string().refine((val) => Number(val) <= 315360000, {
@@ -52,12 +52,16 @@ type Props = {
name: string; name: string;
authMethod?: IdentityAuthMethod; authMethod?: IdentityAuthMethod;
}; };
initialAuthMethod: IdentityAuthMethod;
revokeAuth: (authMethod: IdentityAuthMethod) => Promise<void>;
}; };
export const IdentityAzureAuthForm = ({ export const IdentityAzureAuthForm = ({
handlePopUpOpen, handlePopUpOpen,
handlePopUpToggle, handlePopUpToggle,
identityAuthMethodData identityAuthMethodData,
initialAuthMethod,
revokeAuth
}: Props) => { }: Props) => {
const { currentOrg } = useOrganization(); const { currentOrg } = useOrganization();
const orgId = currentOrg?.id || ""; const orgId = currentOrg?.id || "";
@@ -66,12 +70,18 @@ export const IdentityAzureAuthForm = ({
const { mutateAsync: addMutateAsync } = useAddIdentityAzureAuth(); const { mutateAsync: addMutateAsync } = useAddIdentityAzureAuth();
const { mutateAsync: updateMutateAsync } = useUpdateIdentityAzureAuth(); const { mutateAsync: updateMutateAsync } = useUpdateIdentityAzureAuth();
const { data } = useGetIdentityAzureAuth(identityAuthMethodData?.identityId ?? ""); const isCurrentAuthMethod = identityAuthMethodData?.authMethod === initialAuthMethod;
const { data } = useGetIdentityAzureAuth(identityAuthMethodData?.identityId ?? "", {
enabled: isCurrentAuthMethod
});
const internalPopUpState = usePopUp(["overwriteAuthMethod"] as const);
const { const {
control, control,
handleSubmit, handleSubmit,
reset, reset,
trigger,
formState: { isSubmitting } formState: { isSubmitting }
} = useForm<FormData>({ } = useForm<FormData>({
resolver: zodResolver(schema), resolver: zodResolver(schema),
@@ -163,9 +173,7 @@ export const IdentityAzureAuthForm = ({
handlePopUpToggle("identityAuthMethod", false); handlePopUpToggle("identityAuthMethod", false);
createNotification({ createNotification({
text: `Successfully ${ text: `Successfully ${isCurrentAuthMethod ? "updated" : "configured"} auth method`,
identityAuthMethodData?.authMethod ? "updated" : "configured"
} auth method`,
type: "success" type: "success"
}); });
@@ -179,6 +187,7 @@ export const IdentityAzureAuthForm = ({
}; };
return ( return (
<>
<form onSubmit={handleSubmit(onFormSubmit)}> <form onSubmit={handleSubmit(onFormSubmit)}>
<Controller <Controller
control={control} control={control}
@@ -333,6 +342,17 @@ export const IdentityAzureAuthForm = ({
</div> </div>
<div className="flex justify-between"> <div className="flex justify-between">
<div className="flex items-center"> <div className="flex items-center">
{initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod ? (
<Button
className="mr-4"
size="sm"
isLoading={isSubmitting}
isDisabled={isSubmitting}
onClick={() => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", true)}
>
Overwrite
</Button>
) : (
<Button <Button
className="mr-4" className="mr-4"
size="sm" size="sm"
@@ -340,8 +360,9 @@ export const IdentityAzureAuthForm = ({
isLoading={isSubmitting} isLoading={isSubmitting}
isDisabled={isSubmitting} isDisabled={isSubmitting}
> >
{identityAuthMethodData?.authMethod ? "Update" : "Configure"} Submit
</Button> </Button>
)}
<Button <Button
colorSchema="secondary" colorSchema="secondary"
variant="plain" variant="plain"
@@ -350,7 +371,7 @@ export const IdentityAzureAuthForm = ({
Cancel Cancel
</Button> </Button>
</div> </div>
{identityAuthMethodData?.authMethod && ( {isCurrentAuthMethod && (
<Button <Button
size="sm" size="sm"
colorSchema="danger" colorSchema="danger"
@@ -363,5 +384,28 @@ export const IdentityAzureAuthForm = ({
)} )}
</div> </div>
</form> </form>
<DeleteActionModal
isOpen={internalPopUpState.popUp.overwriteAuthMethod?.isOpen}
title={`Are you sure want to overwrite ${initialAuthMethod || "the auth method"} on ${
identityAuthMethodData?.name ?? ""
}?`}
onChange={(isOpen) => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", isOpen)}
deleteKey="confirm"
buttonText="Overwrite"
onDeleteApproved={async () => {
const result = await trigger();
if (result) {
await revokeAuth(initialAuthMethod);
handleSubmit(onFormSubmit)();
} else {
createNotification({
text: "Please fill in all required fields",
type: "error"
});
internalPopUpState.handlePopUpToggle("overwriteAuthMethod", false);
}
}}
/>
</>
); );
}; };
@@ -6,7 +6,15 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod"; import { z } from "zod";
import { createNotification } from "@app/components/notifications"; import { createNotification } from "@app/components/notifications";
import { Button, FormControl, IconButton, Input, Select, SelectItem } from "@app/components/v2"; import {
Button,
DeleteActionModal,
FormControl,
IconButton,
Input,
Select,
SelectItem
} from "@app/components/v2";
import { useOrganization, useSubscription } from "@app/context"; import { useOrganization, useSubscription } from "@app/context";
import { import {
useAddIdentityGcpAuth, useAddIdentityGcpAuth,
@@ -15,7 +23,7 @@ import {
} from "@app/hooks/api"; } from "@app/hooks/api";
import { IdentityAuthMethod } from "@app/hooks/api/identities"; import { IdentityAuthMethod } from "@app/hooks/api/identities";
import { IdentityTrustedIp } from "@app/hooks/api/identities/types"; import { IdentityTrustedIp } from "@app/hooks/api/identities/types";
import { UsePopUpState } from "@app/hooks/usePopUp"; import { usePopUp, UsePopUpState } from "@app/hooks/usePopUp";
const schema = z const schema = z
.object({ .object({
@@ -53,12 +61,16 @@ type Props = {
name: string; name: string;
authMethod?: IdentityAuthMethod; authMethod?: IdentityAuthMethod;
}; };
initialAuthMethod: IdentityAuthMethod;
revokeAuth: (authMethod: IdentityAuthMethod) => Promise<void>;
}; };
export const IdentityGcpAuthForm = ({ export const IdentityGcpAuthForm = ({
handlePopUpOpen, handlePopUpOpen,
handlePopUpToggle, handlePopUpToggle,
identityAuthMethodData identityAuthMethodData,
revokeAuth,
initialAuthMethod
}: Props) => { }: Props) => {
const { currentOrg } = useOrganization(); const { currentOrg } = useOrganization();
const orgId = currentOrg?.id || ""; const orgId = currentOrg?.id || "";
@@ -67,7 +79,11 @@ export const IdentityGcpAuthForm = ({
const { mutateAsync: addMutateAsync } = useAddIdentityGcpAuth(); const { mutateAsync: addMutateAsync } = useAddIdentityGcpAuth();
const { mutateAsync: updateMutateAsync } = useUpdateIdentityGcpAuth(); const { mutateAsync: updateMutateAsync } = useUpdateIdentityGcpAuth();
const { data } = useGetIdentityGcpAuth(identityAuthMethodData?.identityId ?? ""); const isCurrentAuthMethod = identityAuthMethodData?.authMethod === initialAuthMethod;
const { data } = useGetIdentityGcpAuth(identityAuthMethodData?.identityId ?? "", {
enabled: isCurrentAuthMethod
});
const internalPopUpState = usePopUp(["overwriteAuthMethod"] as const);
const { const {
control, control,
@@ -100,7 +116,7 @@ export const IdentityGcpAuthForm = ({
useEffect(() => { useEffect(() => {
if (data) { if (data) {
reset({ reset({
type: data.type, type: data.type || "gce",
allowedServiceAccounts: data.allowedServiceAccounts, allowedServiceAccounts: data.allowedServiceAccounts,
allowedProjects: data.allowedProjects, allowedProjects: data.allowedProjects,
allowedZones: data.allowedZones, allowedZones: data.allowedZones,
@@ -117,7 +133,7 @@ export const IdentityGcpAuthForm = ({
}); });
} else { } else {
reset({ reset({
type: "iam", type: "gce",
allowedServiceAccounts: "", allowedServiceAccounts: "",
allowedProjects: "", allowedProjects: "",
allowedZones: "", allowedZones: "",
@@ -173,9 +189,7 @@ export const IdentityGcpAuthForm = ({
handlePopUpToggle("identityAuthMethod", false); handlePopUpToggle("identityAuthMethod", false);
createNotification({ createNotification({
text: `Successfully ${ text: `Successfully ${isCurrentAuthMethod ? "updated" : "configured"} auth method`,
identityAuthMethodData?.authMethod ? "updated" : "configured"
} auth method`,
type: "success" type: "success"
}); });
@@ -189,6 +203,7 @@ export const IdentityGcpAuthForm = ({
}; };
return ( return (
<>
<form onSubmit={handleSubmit(onFormSubmit)}> <form onSubmit={handleSubmit(onFormSubmit)}>
<Controller <Controller
control={control} control={control}
@@ -201,10 +216,10 @@ export const IdentityGcpAuthForm = ({
onValueChange={(e) => onChange(e)} onValueChange={(e) => onChange(e)}
className="w-full" className="w-full"
> >
<SelectItem value="gce" key="gcp-type-gce"> <SelectItem value="gce" key="gce">
GCP ID Token Auth (Recommended) GCP ID Token Auth (Recommended)
</SelectItem> </SelectItem>
<SelectItem value="iam" key="gcpiam"> <SelectItem value="iam" key="iam">
GCP IAM Auth GCP IAM Auth
</SelectItem> </SelectItem>
</Select> </Select>
@@ -249,7 +264,11 @@ export const IdentityGcpAuthForm = ({
control={control} control={control}
name="allowedZones" name="allowedZones"
render={({ field, fieldState: { error } }) => ( render={({ field, fieldState: { error } }) => (
<FormControl label="Allowed Zones" isError={Boolean(error)} errorText={error?.message}> <FormControl
label="Allowed Zones"
isError={Boolean(error)}
errorText={error?.message}
>
<Input {...field} placeholder="us-west2-a, us-central1-a, ..." /> <Input {...field} placeholder="us-west2-a, us-central1-a, ..." />
</FormControl> </FormControl>
)} )}
@@ -367,6 +386,17 @@ export const IdentityGcpAuthForm = ({
</div> </div>
<div className="flex justify-between"> <div className="flex justify-between">
<div className="flex items-center"> <div className="flex items-center">
{initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod ? (
<Button
className="mr-4"
size="sm"
isLoading={isSubmitting}
isDisabled={isSubmitting}
onClick={() => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", true)}
>
Overwrite
</Button>
) : (
<Button <Button
className="mr-4" className="mr-4"
size="sm" size="sm"
@@ -374,8 +404,9 @@ export const IdentityGcpAuthForm = ({
isLoading={isSubmitting} isLoading={isSubmitting}
isDisabled={isSubmitting} isDisabled={isSubmitting}
> >
{identityAuthMethodData?.authMethod ? "Update" : "Configure"} Submit
</Button> </Button>
)}
<Button <Button
colorSchema="secondary" colorSchema="secondary"
variant="plain" variant="plain"
@@ -384,7 +415,7 @@ export const IdentityGcpAuthForm = ({
Cancel Cancel
</Button> </Button>
</div> </div>
{identityAuthMethodData?.authMethod && ( {isCurrentAuthMethod && (
<Button <Button
size="sm" size="sm"
colorSchema="danger" colorSchema="danger"
@@ -397,5 +428,19 @@ export const IdentityGcpAuthForm = ({
)} )}
</div> </div>
</form> </form>
<DeleteActionModal
isOpen={internalPopUpState.popUp.overwriteAuthMethod?.isOpen}
title={`Are you sure want to overwrite ${initialAuthMethod || "the auth method"} on ${
identityAuthMethodData?.name ?? ""
}?`}
buttonText="Overwrite"
onChange={(isOpen) => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", isOpen)}
deleteKey="confirm"
onDeleteApproved={async () => {
await revokeAuth(initialAuthMethod);
handleSubmit(onFormSubmit)();
}}
/>
</>
); );
}; };
@@ -6,7 +6,14 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod"; import { z } from "zod";
import { createNotification } from "@app/components/notifications"; import { createNotification } from "@app/components/notifications";
import { Button, FormControl, IconButton, Input, TextArea } from "@app/components/v2"; import {
Button,
DeleteActionModal,
FormControl,
IconButton,
Input,
TextArea
} from "@app/components/v2";
import { useOrganization, useSubscription } from "@app/context"; import { useOrganization, useSubscription } from "@app/context";
import { import {
useAddIdentityKubernetesAuth, useAddIdentityKubernetesAuth,
@@ -15,12 +22,12 @@ import {
} from "@app/hooks/api"; } from "@app/hooks/api";
import { IdentityAuthMethod } from "@app/hooks/api/identities"; import { IdentityAuthMethod } from "@app/hooks/api/identities";
import { IdentityTrustedIp } from "@app/hooks/api/identities/types"; import { IdentityTrustedIp } from "@app/hooks/api/identities/types";
import { UsePopUpState } from "@app/hooks/usePopUp"; import { usePopUp, UsePopUpState } from "@app/hooks/usePopUp";
const schema = z const schema = z
.object({ .object({
kubernetesHost: z.string(), kubernetesHost: z.string().min(1),
tokenReviewerJwt: z.string(), tokenReviewerJwt: z.string().min(1),
allowedNames: z.string(), allowedNames: z.string(),
allowedNamespaces: z.string(), allowedNamespaces: z.string(),
allowedAudience: z.string(), allowedAudience: z.string(),
@@ -55,12 +62,16 @@ type Props = {
name: string; name: string;
authMethod?: IdentityAuthMethod; authMethod?: IdentityAuthMethod;
}; };
initialAuthMethod: IdentityAuthMethod;
revokeAuth: (authMethod: IdentityAuthMethod) => Promise<void>;
}; };
export const IdentityKubernetesAuthForm = ({ export const IdentityKubernetesAuthForm = ({
handlePopUpOpen, handlePopUpOpen,
handlePopUpToggle, handlePopUpToggle,
identityAuthMethodData identityAuthMethodData,
initialAuthMethod,
revokeAuth
}: Props) => { }: Props) => {
const { currentOrg } = useOrganization(); const { currentOrg } = useOrganization();
const orgId = currentOrg?.id || ""; const orgId = currentOrg?.id || "";
@@ -69,12 +80,17 @@ export const IdentityKubernetesAuthForm = ({
const { mutateAsync: addMutateAsync } = useAddIdentityKubernetesAuth(); const { mutateAsync: addMutateAsync } = useAddIdentityKubernetesAuth();
const { mutateAsync: updateMutateAsync } = useUpdateIdentityKubernetesAuth(); const { mutateAsync: updateMutateAsync } = useUpdateIdentityKubernetesAuth();
const { data } = useGetIdentityKubernetesAuth(identityAuthMethodData?.identityId ?? ""); const isCurrentAuthMethod = identityAuthMethodData?.authMethod === initialAuthMethod;
const { data } = useGetIdentityKubernetesAuth(identityAuthMethodData?.identityId ?? "", {
enabled: isCurrentAuthMethod
});
const internalPopUpState = usePopUp(["overwriteAuthMethod"] as const);
const { const {
control, control,
handleSubmit, handleSubmit,
reset, reset,
trigger,
formState: { isSubmitting } formState: { isSubmitting }
} = useForm<FormData>({ } = useForm<FormData>({
resolver: zodResolver(schema), resolver: zodResolver(schema),
@@ -184,9 +200,7 @@ export const IdentityKubernetesAuthForm = ({
handlePopUpToggle("identityAuthMethod", false); handlePopUpToggle("identityAuthMethod", false);
createNotification({ createNotification({
text: `Successfully ${ text: `Successfully ${isCurrentAuthMethod ? "updated" : "configured"} auth method`,
identityAuthMethodData?.authMethod ? "updated" : "configured"
} auth method`,
type: "success" type: "success"
}); });
@@ -200,6 +214,7 @@ export const IdentityKubernetesAuthForm = ({
}; };
return ( return (
<>
<form onSubmit={handleSubmit(onFormSubmit)}> <form onSubmit={handleSubmit(onFormSubmit)}>
<Controller <Controller
control={control} control={control}
@@ -268,7 +283,8 @@ export const IdentityKubernetesAuthForm = ({
render={({ field, fieldState: { error } }) => ( render={({ field, fieldState: { error } }) => (
<FormControl <FormControl
label="Allowed Audience" label="Allowed Audience"
isError={Boolean(error)} errorText={error?.message} isError={Boolean(error)}
errorText={error?.message}
tooltipText="An optional audience claim that the service account JWT token must have to authenticate with Infisical. Leave empty to allow any audience claim." tooltipText="An optional audience claim that the service account JWT token must have to authenticate with Infisical. Leave empty to allow any audience claim."
> >
<Input {...field} placeholder="" type="text" /> <Input {...field} placeholder="" type="text" />
@@ -281,7 +297,8 @@ export const IdentityKubernetesAuthForm = ({
render={({ field, fieldState: { error } }) => ( render={({ field, fieldState: { error } }) => (
<FormControl <FormControl
label="CA Certificate" label="CA Certificate"
errorText={error?.message} isError={Boolean(error)} errorText={error?.message}
isError={Boolean(error)}
tooltipText="An optional PEM-encoded CA cert for the Kubernetes API server. This is used by the TLS client for secure communication with the Kubernetes API server." tooltipText="An optional PEM-encoded CA cert for the Kubernetes API server. This is used by the TLS client for secure communication with the Kubernetes API server."
> >
<TextArea {...field} placeholder="-----BEGIN CERTIFICATE----- ..." /> <TextArea {...field} placeholder="-----BEGIN CERTIFICATE----- ..." />
@@ -404,6 +421,17 @@ export const IdentityKubernetesAuthForm = ({
</div> </div>
<div className="flex justify-between"> <div className="flex justify-between">
<div className="flex items-center"> <div className="flex items-center">
{initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod ? (
<Button
className="mr-4"
size="sm"
isLoading={isSubmitting}
isDisabled={isSubmitting}
onClick={() => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", true)}
>
Overwrite
</Button>
) : (
<Button <Button
className="mr-4" className="mr-4"
size="sm" size="sm"
@@ -411,8 +439,9 @@ export const IdentityKubernetesAuthForm = ({
isLoading={isSubmitting} isLoading={isSubmitting}
isDisabled={isSubmitting} isDisabled={isSubmitting}
> >
{identityAuthMethodData?.authMethod ? "Update" : "Configure"} Submit
</Button> </Button>
)}
<Button <Button
colorSchema="secondary" colorSchema="secondary"
variant="plain" variant="plain"
@@ -421,7 +450,7 @@ export const IdentityKubernetesAuthForm = ({
Cancel Cancel
</Button> </Button>
</div> </div>
{identityAuthMethodData?.authMethod && ( {isCurrentAuthMethod && (
<Button <Button
size="sm" size="sm"
colorSchema="danger" colorSchema="danger"
@@ -434,5 +463,28 @@ export const IdentityKubernetesAuthForm = ({
)} )}
</div> </div>
</form> </form>
<DeleteActionModal
isOpen={internalPopUpState.popUp.overwriteAuthMethod?.isOpen}
title={`Are you sure want to overwrite ${initialAuthMethod || "the auth method"} on ${
identityAuthMethodData?.name ?? ""
}?`}
onChange={(isOpen) => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", isOpen)}
deleteKey="confirm"
buttonText="Overwrite"
onDeleteApproved={async () => {
const result = await trigger();
if (result) {
await revokeAuth(initialAuthMethod);
handleSubmit(onFormSubmit)();
} else {
createNotification({
text: "Please fill in all required fields",
type: "error"
});
internalPopUpState.handlePopUpToggle("overwriteAuthMethod", false);
}
}}
/>
</>
); );
}; };
@@ -7,13 +7,21 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod"; import { z } from "zod";
import { createNotification } from "@app/components/notifications"; import { createNotification } from "@app/components/notifications";
import { Button, FormControl, IconButton, Input, TextArea, Tooltip } from "@app/components/v2"; import {
Button,
DeleteActionModal,
FormControl,
IconButton,
Input,
TextArea,
Tooltip
} from "@app/components/v2";
import { useOrganization, useSubscription } from "@app/context"; import { useOrganization, useSubscription } from "@app/context";
import { useAddIdentityOidcAuth, useUpdateIdentityOidcAuth } from "@app/hooks/api"; import { useAddIdentityOidcAuth, useUpdateIdentityOidcAuth } from "@app/hooks/api";
import { IdentityAuthMethod } from "@app/hooks/api/identities"; import { IdentityAuthMethod } from "@app/hooks/api/identities";
import { useGetIdentityOidcAuth } from "@app/hooks/api/identities/queries"; import { useGetIdentityOidcAuth } from "@app/hooks/api/identities/queries";
import { IdentityTrustedIp } from "@app/hooks/api/identities/types"; import { IdentityTrustedIp } from "@app/hooks/api/identities/types";
import { UsePopUpState } from "@app/hooks/usePopUp"; import { usePopUp, UsePopUpState } from "@app/hooks/usePopUp";
const schema = z.object({ const schema = z.object({
accessTokenTrustedIps: z accessTokenTrustedIps: z
@@ -56,12 +64,16 @@ type Props = {
name: string; name: string;
authMethod?: IdentityAuthMethod; authMethod?: IdentityAuthMethod;
}; };
initialAuthMethod: IdentityAuthMethod;
revokeAuth: (authMethod: IdentityAuthMethod) => Promise<void>;
}; };
export const IdentityOidcAuthForm = ({ export const IdentityOidcAuthForm = ({
handlePopUpOpen, handlePopUpOpen,
handlePopUpToggle, handlePopUpToggle,
identityAuthMethodData identityAuthMethodData,
initialAuthMethod,
revokeAuth
}: Props) => { }: Props) => {
const { currentOrg } = useOrganization(); const { currentOrg } = useOrganization();
const orgId = currentOrg?.id || ""; const orgId = currentOrg?.id || "";
@@ -70,12 +82,17 @@ export const IdentityOidcAuthForm = ({
const { mutateAsync: addMutateAsync } = useAddIdentityOidcAuth(); const { mutateAsync: addMutateAsync } = useAddIdentityOidcAuth();
const { mutateAsync: updateMutateAsync } = useUpdateIdentityOidcAuth(); const { mutateAsync: updateMutateAsync } = useUpdateIdentityOidcAuth();
const { data } = useGetIdentityOidcAuth(identityAuthMethodData?.identityId ?? ""); const isCurrentAuthMethod = identityAuthMethodData?.authMethod === initialAuthMethod;
const { data } = useGetIdentityOidcAuth(identityAuthMethodData?.identityId ?? "", {
enabled: isCurrentAuthMethod
});
const internalPopUpState = usePopUp(["overwriteAuthMethod"] as const);
const { const {
control, control,
handleSubmit, handleSubmit,
reset, reset,
trigger,
formState: { isSubmitting } formState: { isSubmitting }
} = useForm<FormData>({ } = useForm<FormData>({
resolver: zodResolver(schema), resolver: zodResolver(schema),
@@ -193,9 +210,7 @@ export const IdentityOidcAuthForm = ({
handlePopUpToggle("identityAuthMethod", false); handlePopUpToggle("identityAuthMethod", false);
createNotification({ createNotification({
text: `Successfully ${ text: `Successfully ${isCurrentAuthMethod ? "updated" : "configured"} auth method`,
identityAuthMethodData?.authMethod ? "updated" : "configured"
} auth method`,
type: "success" type: "success"
}); });
@@ -209,6 +224,7 @@ export const IdentityOidcAuthForm = ({
}; };
return ( return (
<>
<form onSubmit={handleSubmit(onFormSubmit)}> <form onSubmit={handleSubmit(onFormSubmit)}>
<Controller <Controller
control={control} control={control}
@@ -488,6 +504,17 @@ export const IdentityOidcAuthForm = ({
</div> </div>
<div className="flex justify-between"> <div className="flex justify-between">
<div className="flex items-center"> <div className="flex items-center">
{initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod ? (
<Button
className="mr-4"
size="sm"
isLoading={isSubmitting}
isDisabled={isSubmitting}
onClick={() => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", true)}
>
Overwrite
</Button>
) : (
<Button <Button
className="mr-4" className="mr-4"
size="sm" size="sm"
@@ -495,8 +522,9 @@ export const IdentityOidcAuthForm = ({
isLoading={isSubmitting} isLoading={isSubmitting}
isDisabled={isSubmitting} isDisabled={isSubmitting}
> >
{identityAuthMethodData?.authMethod ? "Update" : "Configure"} Submit
</Button> </Button>
)}
<Button <Button
colorSchema="secondary" colorSchema="secondary"
variant="plain" variant="plain"
@@ -505,7 +533,7 @@ export const IdentityOidcAuthForm = ({
Cancel Cancel
</Button> </Button>
</div> </div>
{identityAuthMethodData?.authMethod && ( {isCurrentAuthMethod && (
<Button <Button
size="sm" size="sm"
colorSchema="danger" colorSchema="danger"
@@ -518,5 +546,28 @@ export const IdentityOidcAuthForm = ({
)} )}
</div> </div>
</form> </form>
<DeleteActionModal
isOpen={internalPopUpState.popUp.overwriteAuthMethod?.isOpen}
title={`Are you sure want to overwrite ${initialAuthMethod || "the auth method"} on ${
identityAuthMethodData?.name ?? ""
}?`}
onChange={(isOpen) => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", isOpen)}
deleteKey="confirm"
buttonText="Overwrite"
onDeleteApproved={async () => {
const result = await trigger();
if (result) {
await revokeAuth(initialAuthMethod);
handleSubmit(onFormSubmit)();
} else {
createNotification({
text: "Please fill in all required fields",
type: "error"
});
internalPopUpState.handlePopUpToggle("overwriteAuthMethod", false);
}
}}
/>
</>
); );
}; };
@@ -5,7 +5,7 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod"; import { z } from "zod";
import { createNotification } from "@app/components/notifications"; import { createNotification } from "@app/components/notifications";
import { Button, FormControl, IconButton, Input } from "@app/components/v2"; import { Button, DeleteActionModal, FormControl, IconButton, Input } from "@app/components/v2";
import { useOrganization, useSubscription } from "@app/context"; import { useOrganization, useSubscription } from "@app/context";
import { import {
useAddIdentityTokenAuth, useAddIdentityTokenAuth,
@@ -13,7 +13,7 @@ import {
useUpdateIdentityTokenAuth useUpdateIdentityTokenAuth
} from "@app/hooks/api"; } from "@app/hooks/api";
import { IdentityAuthMethod } from "@app/hooks/api/identities"; import { IdentityAuthMethod } from "@app/hooks/api/identities";
import { UsePopUpState } from "@app/hooks/usePopUp"; import { usePopUp, UsePopUpState } from "@app/hooks/usePopUp";
const schema = z const schema = z
.object({ .object({
@@ -47,12 +47,16 @@ type Props = {
name: string; name: string;
authMethod?: IdentityAuthMethod; authMethod?: IdentityAuthMethod;
}; };
initialAuthMethod: IdentityAuthMethod;
revokeAuth: (authMethod: IdentityAuthMethod) => Promise<void>;
}; };
export const IdentityTokenAuthForm = ({ export const IdentityTokenAuthForm = ({
handlePopUpOpen, handlePopUpOpen,
handlePopUpToggle, handlePopUpToggle,
identityAuthMethodData identityAuthMethodData,
initialAuthMethod,
revokeAuth
}: Props) => { }: Props) => {
const { currentOrg } = useOrganization(); const { currentOrg } = useOrganization();
const orgId = currentOrg?.id || ""; const orgId = currentOrg?.id || "";
@@ -61,7 +65,11 @@ export const IdentityTokenAuthForm = ({
const { mutateAsync: addMutateAsync } = useAddIdentityTokenAuth(); const { mutateAsync: addMutateAsync } = useAddIdentityTokenAuth();
const { mutateAsync: updateMutateAsync } = useUpdateIdentityTokenAuth(); const { mutateAsync: updateMutateAsync } = useUpdateIdentityTokenAuth();
const { data } = useGetIdentityTokenAuth(identityAuthMethodData?.identityId ?? ""); const isCurrentAuthMethod = identityAuthMethodData?.authMethod === initialAuthMethod;
const { data } = useGetIdentityTokenAuth(identityAuthMethodData?.identityId ?? "", {
enabled: isCurrentAuthMethod
});
const internalPopUpState = usePopUp(["overwriteAuthMethod"] as const);
const { const {
control, control,
@@ -116,22 +124,21 @@ export const IdentityTokenAuthForm = ({
handlePopUpToggle("identityAuthMethod", false); handlePopUpToggle("identityAuthMethod", false);
createNotification({ createNotification({
text: `Successfully ${ text: `Successfully ${isCurrentAuthMethod ? "updated" : "configured"} auth method`,
identityAuthMethodData?.authMethod ? "updated" : "configured"
} auth method`,
type: "success" type: "success"
}); });
reset(); reset();
} catch (err) { } catch (err) {
createNotification({ createNotification({
text: `Failed to ${identityAuthMethodData?.authMethod ? "update" : "configure"} identity`, text: `Failed to ${isCurrentAuthMethod ? "update" : "configure"} identity`,
type: "error" type: "error"
}); });
} }
}; };
return ( return (
<>
<form onSubmit={handleSubmit(onFormSubmit)}> <form onSubmit={handleSubmit(onFormSubmit)}>
<Controller <Controller
control={control} control={control}
@@ -245,6 +252,17 @@ export const IdentityTokenAuthForm = ({
</div> </div>
<div className="flex justify-between"> <div className="flex justify-between">
<div className="flex items-center"> <div className="flex items-center">
{initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod ? (
<Button
className="mr-4"
size="sm"
isLoading={isSubmitting}
isDisabled={isSubmitting}
onClick={() => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", true)}
>
Overwrite
</Button>
) : (
<Button <Button
className="mr-4" className="mr-4"
size="sm" size="sm"
@@ -252,8 +270,9 @@ export const IdentityTokenAuthForm = ({
isLoading={isSubmitting} isLoading={isSubmitting}
isDisabled={isSubmitting} isDisabled={isSubmitting}
> >
{identityAuthMethodData?.authMethod ? "Update" : "Configure"} Submit
</Button> </Button>
)}
<Button <Button
colorSchema="secondary" colorSchema="secondary"
variant="plain" variant="plain"
@@ -262,7 +281,7 @@ export const IdentityTokenAuthForm = ({
Cancel Cancel
</Button> </Button>
</div> </div>
{identityAuthMethodData?.authMethod && ( {isCurrentAuthMethod && (
<Button <Button
size="sm" size="sm"
colorSchema="danger" colorSchema="danger"
@@ -275,5 +294,19 @@ export const IdentityTokenAuthForm = ({
)} )}
</div> </div>
</form> </form>
<DeleteActionModal
isOpen={internalPopUpState.popUp.overwriteAuthMethod?.isOpen}
title={`Are you sure want to overwrite ${initialAuthMethod || "the auth method"} on ${
identityAuthMethodData?.name ?? ""
}?`}
onChange={(isOpen) => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", isOpen)}
deleteKey="confirm"
buttonText="Overwrite"
onDeleteApproved={async () => {
await revokeAuth(initialAuthMethod);
handleSubmit(onFormSubmit)();
}}
/>
</>
); );
}; };
@@ -6,7 +6,7 @@ import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup"; import * as yup from "yup";
import { createNotification } from "@app/components/notifications"; import { createNotification } from "@app/components/notifications";
import { Button, FormControl, IconButton, Input } from "@app/components/v2"; import { Button, DeleteActionModal, FormControl, IconButton, Input } from "@app/components/v2";
import { useOrganization, useSubscription } from "@app/context"; import { useOrganization, useSubscription } from "@app/context";
import { import {
useAddIdentityUniversalAuth, useAddIdentityUniversalAuth,
@@ -15,7 +15,7 @@ import {
} from "@app/hooks/api"; } from "@app/hooks/api";
import { IdentityAuthMethod } from "@app/hooks/api/identities"; import { IdentityAuthMethod } from "@app/hooks/api/identities";
import { IdentityTrustedIp } from "@app/hooks/api/identities/types"; import { IdentityTrustedIp } from "@app/hooks/api/identities/types";
import { UsePopUpState } from "@app/hooks/usePopUp"; import { usePopUp, UsePopUpState } from "@app/hooks/usePopUp";
const schema = yup const schema = yup
.object({ .object({
@@ -70,19 +70,28 @@ type Props = {
name: string; name: string;
authMethod?: IdentityAuthMethod; authMethod?: IdentityAuthMethod;
}; };
initialAuthMethod: IdentityAuthMethod;
revokeAuth: (authMethod: IdentityAuthMethod) => Promise<void>;
}; };
export const IdentityUniversalAuthForm = ({ export const IdentityUniversalAuthForm = ({
handlePopUpOpen, handlePopUpOpen,
handlePopUpToggle, handlePopUpToggle,
identityAuthMethodData identityAuthMethodData,
initialAuthMethod,
revokeAuth
}: Props) => { }: Props) => {
const { currentOrg } = useOrganization(); const { currentOrg } = useOrganization();
const orgId = currentOrg?.id || ""; const orgId = currentOrg?.id || "";
const { subscription } = useSubscription(); const { subscription } = useSubscription();
const { mutateAsync: addMutateAsync } = useAddIdentityUniversalAuth(); const { mutateAsync: addMutateAsync } = useAddIdentityUniversalAuth();
const { mutateAsync: updateMutateAsync } = useUpdateIdentityUniversalAuth(); const { mutateAsync: updateMutateAsync } = useUpdateIdentityUniversalAuth();
const { data } = useGetIdentityUniversalAuth(identityAuthMethodData?.identityId ?? "");
const isCurrentAuthMethod = identityAuthMethodData?.authMethod === initialAuthMethod;
const { data } = useGetIdentityUniversalAuth(identityAuthMethodData?.identityId ?? "", {
enabled: isCurrentAuthMethod
});
const internalPopUpState = usePopUp(["overwriteAuthMethod"] as const);
const { const {
control, control,
@@ -181,9 +190,7 @@ export const IdentityUniversalAuthForm = ({
handlePopUpToggle("identityAuthMethod", false); handlePopUpToggle("identityAuthMethod", false);
createNotification({ createNotification({
text: `Successfully ${ text: `Successfully ${isCurrentAuthMethod ? "updated" : "configured"} auth method`,
identityAuthMethodData?.authMethod ? "updated" : "configured"
} auth method`,
type: "success" type: "success"
}); });
@@ -203,6 +210,7 @@ export const IdentityUniversalAuthForm = ({
}; };
return ( return (
<>
<form onSubmit={handleSubmit(onFormSubmit)}> <form onSubmit={handleSubmit(onFormSubmit)}>
<Controller <Controller
control={control} control={control}
@@ -384,6 +392,17 @@ export const IdentityUniversalAuthForm = ({
</div> </div>
<div className="flex justify-between"> <div className="flex justify-between">
<div className="flex items-center"> <div className="flex items-center">
{initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod ? (
<Button
className="mr-4"
size="sm"
isLoading={isSubmitting}
isDisabled={isSubmitting}
onClick={() => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", true)}
>
Overwrite
</Button>
) : (
<Button <Button
className="mr-4" className="mr-4"
size="sm" size="sm"
@@ -391,8 +410,9 @@ export const IdentityUniversalAuthForm = ({
isLoading={isSubmitting} isLoading={isSubmitting}
isDisabled={isSubmitting} isDisabled={isSubmitting}
> >
{identityAuthMethodData?.authMethod ? "Update" : "Configure"} Submit
</Button> </Button>
)}
<Button <Button
colorSchema="secondary" colorSchema="secondary"
variant="plain" variant="plain"
@@ -401,7 +421,7 @@ export const IdentityUniversalAuthForm = ({
Cancel Cancel
</Button> </Button>
</div> </div>
{identityAuthMethodData?.authMethod && ( {isCurrentAuthMethod && (
<Button <Button
size="sm" size="sm"
colorSchema="danger" colorSchema="danger"
@@ -414,5 +434,19 @@ export const IdentityUniversalAuthForm = ({
)} )}
</div> </div>
</form> </form>
<DeleteActionModal
isOpen={internalPopUpState.popUp.overwriteAuthMethod?.isOpen}
title={`Are you sure want to overwrite ${initialAuthMethod || "the auth method"} on ${
identityAuthMethodData?.name ?? ""
}?`}
onChange={(isOpen) => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", isOpen)}
deleteKey="confirm"
buttonText="Overwrite"
onDeleteApproved={async () => {
await revokeAuth(initialAuthMethod);
handleSubmit(onFormSubmit)();
}}
/>
</>
); );
}; };