From f63c6b725b576f9ae67f4e582c0df80160b18cdc Mon Sep 17 00:00:00 2001 From: Meet Date: Tue, 24 Sep 2024 21:07:43 +0530 Subject: [PATCH 1/2] feat: allow users to replace auth methods --- .../IdentityAuthMethodModal.tsx | 211 ++++++++++-------- .../IdentitySection/IdentityAwsAuthForm.tsx | 57 +++-- .../IdentitySection/IdentityAzureAuthForm.tsx | 72 ++++-- .../IdentitySection/IdentityGcpAuthForm.tsx | 67 ++++-- .../IdentityKubernetesAuthForm.tsx | 75 +++++-- .../IdentitySection/IdentityOidcAuthForm.tsx | 69 ++++-- .../IdentitySection/IdentityTokenAuthForm.tsx | 57 +++-- .../IdentityUniversalAuthForm.tsx | 56 +++-- 8 files changed, 444 insertions(+), 220 deletions(-) diff --git a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityAuthMethodModal.tsx b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityAuthMethodModal.tsx index b144c9cc8..cf5774c0f 100644 --- a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityAuthMethodModal.tsx +++ b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityAuthMethodModal.tsx @@ -54,7 +54,7 @@ const identityAuthMethods = [ const schema = yup .object({ - authMethod: yup.string().required("Auth method is required") + authMethod: yup.mixed().oneOf(Object.values(IdentityAuthMethod)).required("Auth method is required") }) .required(); @@ -71,21 +71,27 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog const { mutateAsync: revokeAwsAuth } = useDeleteIdentityAwsAuth(); const { mutateAsync: revokeAzureAuth } = useDeleteIdentityAzureAuth(); const { mutateAsync: revokeOidcAuth } = useDeleteIdentityOidcAuth(); - - const { control, watch, setValue } = useForm({ - resolver: yupResolver(schema), - defaultValues: { - authMethod: IdentityAuthMethod.UNIVERSAL_AUTH - } - }); - - const identityAuthMethodData = popUp?.identityAuthMethod?.data as { - identityId: string; - name: string; - authMethod?: IdentityAuthMethod; + + const initialAuthMethod = popUp?.identityAuthMethod?.data?.authMethod; + + const { control, watch, setValue } = useForm({ + resolver: yupResolver(schema), + defaultValues: { + authMethod: initialAuthMethod + } + }); + + const identityAuthMethodData = { + identityId: popUp?.identityAuthMethod.data?.identityId, + name: popUp?.identityAuthMethod?.data?.name, + authMethod: watch("authMethod") + } as { + identityId: string; + name: string; + authMethod?: IdentityAuthMethod; }; - useEffect(() => { + useEffect(() => { if (identityAuthMethodData?.authMethod) { setValue("authMethod", identityAuthMethodData.authMethod); return; @@ -94,85 +100,11 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog setValue("authMethod", IdentityAuthMethod.UNIVERSAL_AUTH); }, [identityAuthMethodData?.authMethod]); - const authMethod = watch("authMethod"); - - const renderIdentityAuthForm = () => { - switch (identityAuthMethodData?.authMethod ?? authMethod) { - case IdentityAuthMethod.AWS_AUTH: { - return ( - - ); - } - case IdentityAuthMethod.KUBERNETES_AUTH: { - return ( - - ); - } - case IdentityAuthMethod.GCP_AUTH: { - return ( - - ); - } - case IdentityAuthMethod.AZURE_AUTH: { - return ( - - ); - } - case IdentityAuthMethod.UNIVERSAL_AUTH: { - return ( - - ); - } - case IdentityAuthMethod.OIDC_AUTH: { - return ( - - ); - } - case IdentityAuthMethod.TOKEN_AUTH: { - return ( - - ); - } - default: { - return
; - } - } - }; - - const onRevokeAuthMethodSubmit = async () => { - if (!identityAuthMethodData.authMethod) return; - if (!orgId) return; + const onRevokeAuthMethodSubmit = async (authMethod: IdentityAuthMethod) => { + if (!orgId || !authMethod) return; try { console.log("onRevokeAuthMethodSubmit identityId: ", identityAuthMethodData); - switch (identityAuthMethodData.authMethod) { + switch (authMethod) { case IdentityAuthMethod.UNIVERSAL_AUTH: { await revokeUniversalAuth({ identityId: identityAuthMethodData.identityId, @@ -228,7 +160,7 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog createNotification({ text: `Successfully removed ${ - identityAuthToNameMap[identityAuthMethodData.authMethod] + identityAuthToNameMap[authMethod] } on ${identityAuthMethodData.name}`, type: "success" }); @@ -238,13 +170,97 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog } catch (err) { console.error(err); createNotification({ - text: `Failed to remove ${identityAuthToNameMap[identityAuthMethodData.authMethod]} on ${ + text: `Failed to remove ${identityAuthToNameMap[authMethod]} on ${ identityAuthMethodData.name }`, type: "error" }); } }; + const renderIdentityAuthForm = () => { + switch (identityAuthMethodData.authMethod) { + case IdentityAuthMethod.AWS_AUTH: { + return ( + + ); + } + case IdentityAuthMethod.KUBERNETES_AUTH: { + return ( + + ); + } + case IdentityAuthMethod.GCP_AUTH: { + return ( + + ); + } + case IdentityAuthMethod.AZURE_AUTH: { + return ( + + ); + } + case IdentityAuthMethod.UNIVERSAL_AUTH: { + return ( + + ); + } + case IdentityAuthMethod.OIDC_AUTH: { + return ( + + ); + } + case IdentityAuthMethod.TOKEN_AUTH: { + return ( + + ); + } + default: { + return
; + } + } + }; return ( onChange(e)} + onValueChange={(e) => {onChange(e)}} className="w-full" - isDisabled={!!identityAuthMethodData?.authMethod} > {identityAuthMethods.map(({ label, value }) => ( @@ -295,7 +310,7 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog } on ${identityAuthMethodData?.name ?? ""}?`} onChange={(isOpen) => handlePopUpToggle("revokeAuthMethod", isOpen)} deleteKey="confirm" - onDeleteApproved={onRevokeAuthMethodSubmit} + onDeleteApproved={() => onRevokeAuthMethodSubmit(identityAuthMethodData.authMethod!)} /> diff --git a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityAwsAuthForm.tsx b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityAwsAuthForm.tsx index d56f4b738..54c148616 100644 --- a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityAwsAuthForm.tsx +++ b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityAwsAuthForm.tsx @@ -6,7 +6,7 @@ import { yupResolver } from "@hookform/resolvers/yup"; import * as yup from "yup"; 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 { useAddIdentityAwsAuth, @@ -15,7 +15,7 @@ import { } from "@app/hooks/api"; import { IdentityAuthMethod } from "@app/hooks/api/identities"; import { IdentityTrustedIp } from "@app/hooks/api/identities/types"; -import { UsePopUpState } from "@app/hooks/usePopUp"; +import { usePopUp, UsePopUpState } from "@app/hooks/usePopUp"; const schema = yup .object({ @@ -64,12 +64,16 @@ type Props = { name: string; authMethod?: IdentityAuthMethod; }; + initialAuthMethod: IdentityAuthMethod; + revokeAuth: (authMethod: IdentityAuthMethod) => Promise; }; export const IdentityAwsAuthForm = ({ handlePopUpOpen, handlePopUpToggle, - identityAuthMethodData + identityAuthMethodData, + initialAuthMethod, + revokeAuth }: Props) => { const { currentOrg } = useOrganization(); const orgId = currentOrg?.id || ""; @@ -80,6 +84,10 @@ export const IdentityAwsAuthForm = ({ const { data } = useGetIdentityAwsAuth(identityAuthMethodData?.identityId ?? ""); + const popup = usePopUp([ + "overwriteAuthMethod", + ] as const); + const { control, handleSubmit, @@ -175,9 +183,8 @@ export const IdentityAwsAuthForm = ({ handlePopUpToggle("identityAuthMethod", false); createNotification({ - text: `Successfully ${ - identityAuthMethodData?.authMethod ? "updated" : "configured" - } auth method`, + text: `Successfully ${identityAuthMethodData?.authMethod === initialAuthMethod ? "updated" : "configured" + } auth method`, type: "success" }); @@ -345,15 +352,24 @@ export const IdentityAwsAuthForm = ({
- + {(initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod) ? + + : + }
- {identityAuthMethodData?.authMethod && ( + {identityAuthMethodData?.authMethod === initialAuthMethod && (
+ popup.handlePopUpToggle("overwriteAuthMethod", isOpen)} + deleteKey="confirm" + onDeleteApproved={async () => { await revokeAuth(initialAuthMethod); handleSubmit(onFormSubmit)(); }} + /> ); }; diff --git a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityAzureAuthForm.tsx b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityAzureAuthForm.tsx index a3902d120..ec15e556d 100644 --- a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityAzureAuthForm.tsx +++ b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityAzureAuthForm.tsx @@ -6,7 +6,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; 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 { useAddIdentityAzureAuth, @@ -15,11 +15,11 @@ import { } from "@app/hooks/api"; import { IdentityAuthMethod } from "@app/hooks/api/identities"; 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({ - tenantId: z.string(), + tenantId: z.string().min(1), resource: z.string(), allowedServicePrincipalIds: z.string(), accessTokenTTL: z.string().refine((val) => Number(val) <= 315360000, { @@ -52,12 +52,16 @@ type Props = { name: string; authMethod?: IdentityAuthMethod; }; + initialAuthMethod: IdentityAuthMethod; + revokeAuth: (authMethod: IdentityAuthMethod) => Promise; }; export const IdentityAzureAuthForm = ({ handlePopUpOpen, handlePopUpToggle, - identityAuthMethodData + identityAuthMethodData, + initialAuthMethod, + revokeAuth }: Props) => { const { currentOrg } = useOrganization(); const orgId = currentOrg?.id || ""; @@ -68,10 +72,15 @@ export const IdentityAzureAuthForm = ({ const { data } = useGetIdentityAzureAuth(identityAuthMethodData?.identityId ?? ""); + const popup = usePopUp([ + "overwriteAuthMethod", + ] as const); + const { control, handleSubmit, reset, + trigger, formState: { isSubmitting } } = useForm({ resolver: zodResolver(schema), @@ -163,9 +172,8 @@ export const IdentityAzureAuthForm = ({ handlePopUpToggle("identityAuthMethod", false); createNotification({ - text: `Successfully ${ - identityAuthMethodData?.authMethod ? "updated" : "configured" - } auth method`, + text: `Successfully ${identityAuthMethodData?.authMethod === initialAuthMethod ? "updated" : "configured" + } auth method`, type: "success" }); @@ -333,15 +341,23 @@ export const IdentityAzureAuthForm = ({
- + {(initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod) ? + + : + }
- {identityAuthMethodData?.authMethod && ( + {identityAuthMethodData?.authMethod === initialAuthMethod && (
+ popup.handlePopUpToggle("overwriteAuthMethod", isOpen)} + deleteKey="confirm" + onDeleteApproved={async () => { + const result = await trigger(); + if(result){ + await revokeAuth(initialAuthMethod); + handleSubmit(onFormSubmit)(); + }else{ + createNotification({ + text: "Please fill in all required fields", + type: "error" + }); + popup.handlePopUpToggle("overwriteAuthMethod", false); + } + }} + /> + ); }; diff --git a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityGcpAuthForm.tsx b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityGcpAuthForm.tsx index a0834b3ae..4c59f46fa 100644 --- a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityGcpAuthForm.tsx +++ b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityGcpAuthForm.tsx @@ -6,7 +6,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; 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 { useAddIdentityGcpAuth, @@ -15,7 +15,7 @@ import { } from "@app/hooks/api"; import { IdentityAuthMethod } from "@app/hooks/api/identities"; 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({ @@ -53,12 +53,16 @@ type Props = { name: string; authMethod?: IdentityAuthMethod; }; + initialAuthMethod: IdentityAuthMethod; + revokeAuth: (authMethod: IdentityAuthMethod) => Promise; }; export const IdentityGcpAuthForm = ({ handlePopUpOpen, handlePopUpToggle, - identityAuthMethodData + identityAuthMethodData, + revokeAuth, + initialAuthMethod }: Props) => { const { currentOrg } = useOrganization(); const orgId = currentOrg?.id || ""; @@ -68,13 +72,16 @@ export const IdentityGcpAuthForm = ({ const { mutateAsync: updateMutateAsync } = useUpdateIdentityGcpAuth(); const { data } = useGetIdentityGcpAuth(identityAuthMethodData?.identityId ?? ""); + const popup = usePopUp([ + "overwriteAuthMethod", + ] as const); const { control, handleSubmit, reset, formState: { isSubmitting }, - watch + watch, } = useForm({ resolver: zodResolver(schema), defaultValues: { @@ -100,7 +107,7 @@ export const IdentityGcpAuthForm = ({ useEffect(() => { if (data) { reset({ - type: data.type, + type: data.type || "gce", allowedServiceAccounts: data.allowedServiceAccounts, allowedProjects: data.allowedProjects, allowedZones: data.allowedZones, @@ -117,7 +124,7 @@ export const IdentityGcpAuthForm = ({ }); } else { reset({ - type: "iam", + type: "gce", allowedServiceAccounts: "", allowedProjects: "", allowedZones: "", @@ -173,12 +180,12 @@ export const IdentityGcpAuthForm = ({ handlePopUpToggle("identityAuthMethod", false); createNotification({ - text: `Successfully ${ - identityAuthMethodData?.authMethod ? "updated" : "configured" - } auth method`, + text: `Successfully ${identityAuthMethodData?.authMethod === initialAuthMethod ? "updated" : "configured" + } auth method`, type: "success" }); + reset(); } catch (err) { createNotification({ @@ -201,10 +208,10 @@ export const IdentityGcpAuthForm = ({ onValueChange={(e) => onChange(e)} className="w-full" > - + GCP ID Token Auth (Recommended) - + GCP IAM Auth @@ -367,15 +374,24 @@ export const IdentityGcpAuthForm = ({
- + {(initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod) ? + + : + }
- {identityAuthMethodData?.authMethod && ( + {identityAuthMethodData?.authMethod === initialAuthMethod && (
+ popup.handlePopUpToggle("overwriteAuthMethod", isOpen)} + deleteKey="confirm" + onDeleteApproved={async () => { await revokeAuth(initialAuthMethod); handleSubmit(onFormSubmit)(); }} + /> ); }; diff --git a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityKubernetesAuthForm.tsx b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityKubernetesAuthForm.tsx index 44bb2d8c9..adcf93cbe 100644 --- a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityKubernetesAuthForm.tsx +++ b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityKubernetesAuthForm.tsx @@ -6,7 +6,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; 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 { useAddIdentityKubernetesAuth, @@ -15,12 +15,12 @@ import { } from "@app/hooks/api"; import { IdentityAuthMethod } from "@app/hooks/api/identities"; 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({ - kubernetesHost: z.string(), - tokenReviewerJwt: z.string(), + kubernetesHost: z.string().min(1), + tokenReviewerJwt: z.string().min(1), allowedNames: z.string(), allowedNamespaces: z.string(), allowedAudience: z.string(), @@ -55,12 +55,16 @@ type Props = { name: string; authMethod?: IdentityAuthMethod; }; + initialAuthMethod: IdentityAuthMethod; + revokeAuth: (authMethod: IdentityAuthMethod) => Promise; }; export const IdentityKubernetesAuthForm = ({ handlePopUpOpen, handlePopUpToggle, - identityAuthMethodData + identityAuthMethodData, + initialAuthMethod, + revokeAuth }: Props) => { const { currentOrg } = useOrganization(); const orgId = currentOrg?.id || ""; @@ -70,12 +74,16 @@ export const IdentityKubernetesAuthForm = ({ const { mutateAsync: updateMutateAsync } = useUpdateIdentityKubernetesAuth(); const { data } = useGetIdentityKubernetesAuth(identityAuthMethodData?.identityId ?? ""); + const popup = usePopUp([ + "overwriteAuthMethod", + ] as const); const { control, handleSubmit, reset, - formState: { isSubmitting } + trigger, + formState: { isSubmitting }, } = useForm({ resolver: zodResolver(schema), defaultValues: { @@ -184,9 +192,8 @@ export const IdentityKubernetesAuthForm = ({ handlePopUpToggle("identityAuthMethod", false); createNotification({ - text: `Successfully ${ - identityAuthMethodData?.authMethod ? "updated" : "configured" - } auth method`, + text: `Successfully ${identityAuthMethodData?.authMethod === initialAuthMethod ? "updated" : "configured" + } auth method`, type: "success" }); @@ -404,15 +411,24 @@ export const IdentityKubernetesAuthForm = ({
- + {(initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod) ? + + : + }
- {identityAuthMethodData?.authMethod && ( + {identityAuthMethodData?.authMethod === initialAuthMethod && (
+ popup.handlePopUpToggle("overwriteAuthMethod", isOpen)} + deleteKey="confirm" + onDeleteApproved={async () => { + const result = await trigger(); + if(result){ + await revokeAuth(initialAuthMethod); + handleSubmit(onFormSubmit)(); + }else{ + createNotification({ + text: "Please fill in all required fields", + type: "error" + }); + popup.handlePopUpToggle("overwriteAuthMethod", false); + } + }} + /> ); }; diff --git a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityOidcAuthForm.tsx b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityOidcAuthForm.tsx index fdfb17e0d..f35d1469b 100644 --- a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityOidcAuthForm.tsx +++ b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityOidcAuthForm.tsx @@ -7,13 +7,13 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; 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 { useAddIdentityOidcAuth, useUpdateIdentityOidcAuth } from "@app/hooks/api"; import { IdentityAuthMethod } from "@app/hooks/api/identities"; import { useGetIdentityOidcAuth } from "@app/hooks/api/identities/queries"; 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({ accessTokenTrustedIps: z @@ -56,12 +56,16 @@ type Props = { name: string; authMethod?: IdentityAuthMethod; }; + initialAuthMethod: IdentityAuthMethod; + revokeAuth: (authMethod: IdentityAuthMethod) => Promise; }; export const IdentityOidcAuthForm = ({ handlePopUpOpen, handlePopUpToggle, - identityAuthMethodData + identityAuthMethodData, + initialAuthMethod, + revokeAuth }: Props) => { const { currentOrg } = useOrganization(); const orgId = currentOrg?.id || ""; @@ -71,11 +75,15 @@ export const IdentityOidcAuthForm = ({ const { mutateAsync: updateMutateAsync } = useUpdateIdentityOidcAuth(); const { data } = useGetIdentityOidcAuth(identityAuthMethodData?.identityId ?? ""); + const popup = usePopUp([ + "overwriteAuthMethod", + ] as const); const { control, handleSubmit, reset, + trigger, formState: { isSubmitting } } = useForm({ resolver: zodResolver(schema), @@ -193,9 +201,8 @@ export const IdentityOidcAuthForm = ({ handlePopUpToggle("identityAuthMethod", false); createNotification({ - text: `Successfully ${ - identityAuthMethodData?.authMethod ? "updated" : "configured" - } auth method`, + text: `Successfully ${identityAuthMethodData?.authMethod === initialAuthMethod ? "updated" : "configured" + } auth method`, type: "success" }); @@ -488,15 +495,24 @@ export const IdentityOidcAuthForm = ({
- + {(initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod) ? + + : + }
- {identityAuthMethodData?.authMethod && ( + {identityAuthMethodData?.authMethod === initialAuthMethod && (
+ popup.handlePopUpToggle("overwriteAuthMethod", isOpen)} + deleteKey="confirm" + onDeleteApproved={async () => { + const result = await trigger(); + if(result){ + await revokeAuth(initialAuthMethod); + handleSubmit(onFormSubmit)(); + }else{ + createNotification({ + text: "Please fill in all required fields", + type: "error" + }); + popup.handlePopUpToggle("overwriteAuthMethod", false); + } + }} + /> ); }; diff --git a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityTokenAuthForm.tsx b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityTokenAuthForm.tsx index 4ce437fc1..4f3828a6e 100644 --- a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityTokenAuthForm.tsx +++ b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityTokenAuthForm.tsx @@ -5,7 +5,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; 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 { useAddIdentityTokenAuth, @@ -13,7 +13,7 @@ import { useUpdateIdentityTokenAuth } from "@app/hooks/api"; import { IdentityAuthMethod } from "@app/hooks/api/identities"; -import { UsePopUpState } from "@app/hooks/usePopUp"; +import { usePopUp, UsePopUpState } from "@app/hooks/usePopUp"; const schema = z .object({ @@ -47,12 +47,16 @@ type Props = { name: string; authMethod?: IdentityAuthMethod; }; + initialAuthMethod: IdentityAuthMethod; + revokeAuth: (authMethod: IdentityAuthMethod) => Promise; }; export const IdentityTokenAuthForm = ({ handlePopUpOpen, handlePopUpToggle, - identityAuthMethodData + identityAuthMethodData, + initialAuthMethod, + revokeAuth }: Props) => { const { currentOrg } = useOrganization(); const orgId = currentOrg?.id || ""; @@ -62,6 +66,9 @@ export const IdentityTokenAuthForm = ({ const { mutateAsync: updateMutateAsync } = useUpdateIdentityTokenAuth(); const { data } = useGetIdentityTokenAuth(identityAuthMethodData?.identityId ?? ""); + const popup = usePopUp([ + "overwriteAuthMethod", + ] as const); const { control, @@ -116,16 +123,15 @@ export const IdentityTokenAuthForm = ({ handlePopUpToggle("identityAuthMethod", false); createNotification({ - text: `Successfully ${ - identityAuthMethodData?.authMethod ? "updated" : "configured" - } auth method`, + text: `Successfully ${identityAuthMethodData?.authMethod === initialAuthMethod ? "updated" : "configured" + } auth method`, type: "success" }); reset(); } catch (err) { createNotification({ - text: `Failed to ${identityAuthMethodData?.authMethod ? "update" : "configure"} identity`, + text: `Failed to ${identityAuthMethodData?.authMethod === initialAuthMethod ? "update" : "configure"} identity`, type: "error" }); } @@ -245,15 +251,23 @@ export const IdentityTokenAuthForm = ({
- + {(initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod) ? + + : + }
- {identityAuthMethodData?.authMethod && ( + {identityAuthMethodData?.authMethod === initialAuthMethod && (
+ popup.handlePopUpToggle("overwriteAuthMethod", isOpen)} + deleteKey="confirm" + onDeleteApproved={async () => { await revokeAuth(initialAuthMethod); handleSubmit(onFormSubmit)(); }} + /> ); }; diff --git a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityUniversalAuthForm.tsx b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityUniversalAuthForm.tsx index cb8c3f580..e0cc6407e 100644 --- a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityUniversalAuthForm.tsx +++ b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityUniversalAuthForm.tsx @@ -6,7 +6,7 @@ import { yupResolver } from "@hookform/resolvers/yup"; import * as yup from "yup"; 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 { useAddIdentityUniversalAuth, @@ -15,7 +15,7 @@ import { } from "@app/hooks/api"; import { IdentityAuthMethod } from "@app/hooks/api/identities"; import { IdentityTrustedIp } from "@app/hooks/api/identities/types"; -import { UsePopUpState } from "@app/hooks/usePopUp"; +import { usePopUp, UsePopUpState } from "@app/hooks/usePopUp"; const schema = yup .object({ @@ -70,12 +70,16 @@ type Props = { name: string; authMethod?: IdentityAuthMethod; }; + initialAuthMethod: IdentityAuthMethod; + revokeAuth: (authMethod: IdentityAuthMethod) => Promise; }; export const IdentityUniversalAuthForm = ({ handlePopUpOpen, handlePopUpToggle, - identityAuthMethodData + identityAuthMethodData, + initialAuthMethod, + revokeAuth }: Props) => { const { currentOrg } = useOrganization(); const orgId = currentOrg?.id || ""; @@ -83,6 +87,9 @@ export const IdentityUniversalAuthForm = ({ const { mutateAsync: addMutateAsync } = useAddIdentityUniversalAuth(); const { mutateAsync: updateMutateAsync } = useUpdateIdentityUniversalAuth(); const { data } = useGetIdentityUniversalAuth(identityAuthMethodData?.identityId ?? ""); + const popup = usePopUp([ + "overwriteAuthMethod", + ] as const); const { control, @@ -181,9 +188,8 @@ export const IdentityUniversalAuthForm = ({ handlePopUpToggle("identityAuthMethod", false); createNotification({ - text: `Successfully ${ - identityAuthMethodData?.authMethod ? "updated" : "configured" - } auth method`, + text: `Successfully ${identityAuthMethodData?.authMethod === initialAuthMethod ? "updated" : "configured" + } auth method`, type: "success" }); @@ -384,15 +390,24 @@ export const IdentityUniversalAuthForm = ({
- + {(initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod) ? + + : + }
- {identityAuthMethodData?.authMethod && ( + {identityAuthMethodData?.authMethod === initialAuthMethod && (
+ popup.handlePopUpToggle("overwriteAuthMethod", isOpen)} + deleteKey="confirm" + onDeleteApproved={async () => { await revokeAuth(initialAuthMethod); handleSubmit(onFormSubmit)(); }} + /> ); }; From ad88aaf17f809165e0a47f5e44944704bae49a7c Mon Sep 17 00:00:00 2001 From: Scott Wilson Date: Mon, 30 Sep 2024 16:53:42 -0700 Subject: [PATCH 2/2] fix: address changes --- frontend/src/hooks/api/identities/queries.tsx | 110 ++- .../IdentityAuthMethodModal.tsx | 68 +- .../IdentitySection/IdentityAwsAuthForm.tsx | 389 ++++++----- .../IdentitySection/IdentityAzureAuthForm.tsx | 412 +++++------ .../IdentitySection/IdentityGcpAuthForm.tsx | 430 ++++++------ .../IdentityKubernetesAuthForm.tsx | 521 +++++++------- .../IdentitySection/IdentityOidcAuthForm.tsx | 660 +++++++++--------- .../IdentitySection/IdentityTokenAuthForm.tsx | 310 ++++---- .../IdentityUniversalAuthForm.tsx | 462 ++++++------ 9 files changed, 1760 insertions(+), 1602 deletions(-) diff --git a/frontend/src/hooks/api/identities/queries.tsx b/frontend/src/hooks/api/identities/queries.tsx index 0e07136c8..c5c442407 100644 --- a/frontend/src/hooks/api/identities/queries.tsx +++ b/frontend/src/hooks/api/identities/queries.tsx @@ -1,4 +1,4 @@ -import { useQuery } from "@tanstack/react-query"; +import { useQuery, UseQueryOptions } from "@tanstack/react-query"; import { apiRequest } from "@app/config/request"; @@ -13,7 +13,8 @@ import { IdentityMembershipOrg, IdentityOidcAuth, IdentityTokenAuth, - IdentityUniversalAuth} from "./types"; + IdentityUniversalAuth +} from "./types"; export const identitiesKeys = { 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 + > +) => { return useQuery({ - enabled: Boolean(identityId), queryKey: identitiesKeys.getIdentityUniversalAuth(identityId), queryFn: async () => { const { @@ -76,8 +84,10 @@ export const useGetIdentityUniversalAuth = (identityId: string) => { ); return identityUniversalAuth; }, + cacheTime: 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 + > +) => { return useQuery({ - enabled: Boolean(identityId), queryKey: identitiesKeys.getIdentityGcpAuth(identityId), queryFn: async () => { const { @@ -109,13 +126,22 @@ export const useGetIdentityGcpAuth = (identityId: string) => { return identityGcpAuth; }, 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 + > +) => { return useQuery({ - enabled: Boolean(identityId), queryKey: identitiesKeys.getIdentityAwsAuth(identityId), queryFn: async () => { const { @@ -126,13 +152,22 @@ export const useGetIdentityAwsAuth = (identityId: string) => { return identityAwsAuth; }, 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 + > +) => { return useQuery({ - enabled: Boolean(identityId), queryKey: identitiesKeys.getIdentityAzureAuth(identityId), queryFn: async () => { const { @@ -143,13 +178,22 @@ export const useGetIdentityAzureAuth = (identityId: string) => { return identityAzureAuth; }, 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 + > +) => { return useQuery({ - enabled: Boolean(identityId), queryKey: identitiesKeys.getIdentityKubernetesAuth(identityId), queryFn: async () => { const { @@ -160,13 +204,22 @@ export const useGetIdentityKubernetesAuth = (identityId: string) => { return identityKubernetesAuth; }, 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 + > +) => { return useQuery({ - enabled: Boolean(identityId), queryKey: identitiesKeys.getIdentityTokenAuth(identityId), queryFn: async () => { const { @@ -177,7 +230,9 @@ export const useGetIdentityTokenAuth = (identityId: string) => { return identityTokenAuth; }, 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 + > +) => { return useQuery({ - enabled: Boolean(identityId), queryKey: identitiesKeys.getIdentityOidcAuth(identityId), queryFn: async () => { const { @@ -209,6 +271,8 @@ export const useGetIdentityOidcAuth = (identityId: string) => { return identityOidcAuth; }, staleTime: 0, - cacheTime: 0 + cacheTime: 0, + ...options, + enabled: Boolean(identityId) && (options?.enabled ?? true) }); }; diff --git a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityAuthMethodModal.tsx b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityAuthMethodModal.tsx index cf5774c0f..c924b4b66 100644 --- a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityAuthMethodModal.tsx +++ b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityAuthMethodModal.tsx @@ -21,7 +21,8 @@ import { useDeleteIdentityKubernetesAuth, useDeleteIdentityOidcAuth, useDeleteIdentityTokenAuth, - useDeleteIdentityUniversalAuth} from "@app/hooks/api"; + useDeleteIdentityUniversalAuth +} from "@app/hooks/api"; import { IdentityAuthMethod, identityAuthToNameMap } from "@app/hooks/api/identities"; import { UsePopUpState } from "@app/hooks/usePopUp"; @@ -54,7 +55,10 @@ const identityAuthMethods = [ const schema = yup .object({ - authMethod: yup.mixed().oneOf(Object.values(IdentityAuthMethod)).required("Auth method is required") + authMethod: yup + .mixed() + .oneOf(Object.values(IdentityAuthMethod)) + .required("Auth method is required") }) .required(); @@ -71,27 +75,33 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog const { mutateAsync: revokeAwsAuth } = useDeleteIdentityAwsAuth(); const { mutateAsync: revokeAzureAuth } = useDeleteIdentityAzureAuth(); const { mutateAsync: revokeOidcAuth } = useDeleteIdentityOidcAuth(); - + const initialAuthMethod = popUp?.identityAuthMethod?.data?.authMethod; - - const { control, watch, setValue } = useForm({ - resolver: yupResolver(schema), - defaultValues: { - authMethod: initialAuthMethod - } - }); - - const identityAuthMethodData = { - identityId: popUp?.identityAuthMethod.data?.identityId, - name: popUp?.identityAuthMethod?.data?.name, - authMethod: watch("authMethod") - } as { - identityId: string; - name: string; - authMethod?: IdentityAuthMethod; + + const { control, watch, setValue, reset } = useForm({ + resolver: yupResolver(schema), + defaultValues: { + authMethod: initialAuthMethod + } + }); + + 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; + name: string; + authMethod?: IdentityAuthMethod; }; - useEffect(() => { + useEffect(() => { if (identityAuthMethodData?.authMethod) { setValue("authMethod", identityAuthMethodData.authMethod); return; @@ -103,7 +113,6 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog const onRevokeAuthMethodSubmit = async (authMethod: IdentityAuthMethod) => { if (!orgId || !authMethod) return; try { - console.log("onRevokeAuthMethodSubmit identityId: ", identityAuthMethodData); switch (authMethod) { case IdentityAuthMethod.UNIVERSAL_AUTH: { await revokeUniversalAuth({ @@ -159,9 +168,7 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog } createNotification({ - text: `Successfully removed ${ - identityAuthToNameMap[authMethod] - } on ${identityAuthMethodData.name}`, + text: `Successfully removed ${identityAuthToNameMap[authMethod]} on ${identityAuthMethodData.name}`, type: "success" }); @@ -170,9 +177,7 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog } catch (err) { console.error(err); createNotification({ - text: `Failed to remove ${identityAuthToNameMap[authMethod]} on ${ - identityAuthMethodData.name - }`, + text: `Failed to remove ${identityAuthToNameMap[authMethod]} on ${identityAuthMethodData.name}`, type: "error" }); } @@ -272,7 +277,9 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog {onChange(e)}} + onValueChange={(e) => { + onChange(e); + }} className="w-full" > {identityAuthMethods.map(({ label, value }) => ( @@ -310,6 +319,7 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog } on ${identityAuthMethodData?.name ?? ""}?`} onChange={(isOpen) => handlePopUpToggle("revokeAuthMethod", isOpen)} deleteKey="confirm" + buttonText="Remove" onDeleteApproved={() => onRevokeAuthMethodSubmit(identityAuthMethodData.authMethod!)} /> diff --git a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityAwsAuthForm.tsx b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityAwsAuthForm.tsx index 54c148616..781a78125 100644 --- a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityAwsAuthForm.tsx +++ b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityAwsAuthForm.tsx @@ -82,11 +82,12 @@ export const IdentityAwsAuthForm = ({ const { mutateAsync: addMutateAsync } = useAddIdentityAwsAuth(); const { mutateAsync: updateMutateAsync } = useUpdateIdentityAwsAuth(); - const { data } = useGetIdentityAwsAuth(identityAuthMethodData?.identityId ?? ""); + const isCurrentAuthMethod = identityAuthMethodData?.authMethod === initialAuthMethod; + const { data } = useGetIdentityAwsAuth(identityAuthMethodData?.identityId ?? "", { + enabled: isCurrentAuthMethod + }); - const popup = usePopUp([ - "overwriteAuthMethod", - ] as const); + const internalPopUpState = usePopUp(["overwriteAuthMethod"] as const); const { control, @@ -183,8 +184,7 @@ export const IdentityAwsAuthForm = ({ handlePopUpToggle("identityAuthMethod", false); createNotification({ - text: `Successfully ${identityAuthMethodData?.authMethod === initialAuthMethod ? "updated" : "configured" - } auth method`, + text: `Successfully ${isCurrentAuthMethod ? "updated" : "configured"} auth method`, type: "success" }); @@ -198,207 +198,216 @@ export const IdentityAwsAuthForm = ({ }; return ( -
- ( - - - - )} - /> - ( - - - - )} - /> - ( - - - - )} - /> - ( - - - - )} - /> - ( - - - - )} - /> - ( - - - - )} - /> - {accessTokenTrustedIpsFields.map(({ id }, index) => ( -
- { - return ( - - { - if (subscription?.ipAllowlisting) { - field.onChange(e); - return; - } + <> + + ( + + + + )} + /> + ( + + + + )} + /> + ( + + + + )} + /> + ( + + + + )} + /> + ( + + + + )} + /> + ( + + + + )} + /> + {accessTokenTrustedIpsFields.map(({ id }, index) => ( +
+ { + return ( + + { + if (subscription?.ipAllowlisting) { + field.onChange(e); + return; + } - handlePopUpOpen("upgradePlan"); - }} - placeholder="123.456.789.0" - /> - - ); - }} - /> - + + ); + }} + /> + { + if (subscription?.ipAllowlisting) { + removeAccessTokenTrustedIp(index); + return; + } + + handlePopUpOpen("upgradePlan"); + }} + size="lg" + colorSchema="danger" + variant="plain" + ariaLabel="update" + className="p-3" + > + + +
+ ))} +
+
- ))} -
- -
-
-
- {(initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod) ? +
+
+ {initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod ? ( + + ) : ( + + )} - : - } - + onClick={() => handlePopUpToggle("revokeAuthMethod", true)} + > + Remove Auth Method + + )}
- {identityAuthMethodData?.authMethod === initialAuthMethod && ( - - )} -
+ popup.handlePopUpToggle("overwriteAuthMethod", isOpen)} - deleteKey="confirm" - onDeleteApproved={async () => { await revokeAuth(initialAuthMethod); handleSubmit(onFormSubmit)(); }} - /> - + 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)(); + }} + /> + ); }; diff --git a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityAzureAuthForm.tsx b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityAzureAuthForm.tsx index ec15e556d..a2a6387fb 100644 --- a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityAzureAuthForm.tsx +++ b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityAzureAuthForm.tsx @@ -70,11 +70,12 @@ export const IdentityAzureAuthForm = ({ const { mutateAsync: addMutateAsync } = useAddIdentityAzureAuth(); const { mutateAsync: updateMutateAsync } = useUpdateIdentityAzureAuth(); - const { data } = useGetIdentityAzureAuth(identityAuthMethodData?.identityId ?? ""); + const isCurrentAuthMethod = identityAuthMethodData?.authMethod === initialAuthMethod; + const { data } = useGetIdentityAzureAuth(identityAuthMethodData?.identityId ?? "", { + enabled: isCurrentAuthMethod + }); - const popup = usePopUp([ - "overwriteAuthMethod", - ] as const); + const internalPopUpState = usePopUp(["overwriteAuthMethod"] as const); const { control, @@ -172,8 +173,7 @@ export const IdentityAzureAuthForm = ({ handlePopUpToggle("identityAuthMethod", false); createNotification({ - text: `Successfully ${identityAuthMethodData?.authMethod === initialAuthMethod ? "updated" : "configured" - } auth method`, + text: `Successfully ${isCurrentAuthMethod ? "updated" : "configured"} auth method`, type: "success" }); @@ -187,219 +187,225 @@ export const IdentityAzureAuthForm = ({ }; return ( -
- ( - - - - )} - /> - ( - - - - )} - /> - ( - - - - )} - /> - ( - - - - )} - /> - ( - - - - )} - /> - ( - - - - )} - /> - {accessTokenTrustedIpsFields.map(({ id }, index) => ( -
- { - return ( - - { - if (subscription?.ipAllowlisting) { - field.onChange(e); - return; - } + <> + + ( + + + + )} + /> + ( + + + + )} + /> + ( + + + + )} + /> + ( + + + + )} + /> + ( + + + + )} + /> + ( + + + + )} + /> + {accessTokenTrustedIpsFields.map(({ id }, index) => ( +
+ { + return ( + + { + if (subscription?.ipAllowlisting) { + field.onChange(e); + return; + } - handlePopUpOpen("upgradePlan"); - }} - placeholder="123.456.789.0" - /> - - ); - }} - /> - + + ); + }} + /> + { + if (subscription?.ipAllowlisting) { + removeAccessTokenTrustedIp(index); + return; + } + + handlePopUpOpen("upgradePlan"); + }} + size="lg" + colorSchema="danger" + variant="plain" + ariaLabel="update" + className="p-3" + > + + +
+ ))} +
+
- ))} -
- -
-
-
- {(initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod) ? +
+
+ {initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod ? ( + + ) : ( + + )} - : - } - + onClick={() => handlePopUpToggle("revokeAuthMethod", true)} + > + Remove Auth Method + + )}
- {identityAuthMethodData?.authMethod === initialAuthMethod && ( - - )} -
+ popup.handlePopUpToggle("overwriteAuthMethod", isOpen)} - deleteKey="confirm" - onDeleteApproved={async () => { - const result = await trigger(); - if(result){ - await revokeAuth(initialAuthMethod); - handleSubmit(onFormSubmit)(); - }else{ - createNotification({ - text: "Please fill in all required fields", - type: "error" - }); - popup.handlePopUpToggle("overwriteAuthMethod", false); - } - }} - /> - - + 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); + } + }} + /> + ); }; diff --git a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityGcpAuthForm.tsx b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityGcpAuthForm.tsx index 4c59f46fa..81dd51d22 100644 --- a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityGcpAuthForm.tsx +++ b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityGcpAuthForm.tsx @@ -6,7 +6,15 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; import { createNotification } from "@app/components/notifications"; -import { Button, DeleteActionModal, 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 { useAddIdentityGcpAuth, @@ -71,17 +79,18 @@ export const IdentityGcpAuthForm = ({ const { mutateAsync: addMutateAsync } = useAddIdentityGcpAuth(); const { mutateAsync: updateMutateAsync } = useUpdateIdentityGcpAuth(); - const { data } = useGetIdentityGcpAuth(identityAuthMethodData?.identityId ?? ""); - const popup = usePopUp([ - "overwriteAuthMethod", - ] as const); + const isCurrentAuthMethod = identityAuthMethodData?.authMethod === initialAuthMethod; + const { data } = useGetIdentityGcpAuth(identityAuthMethodData?.identityId ?? "", { + enabled: isCurrentAuthMethod + }); + const internalPopUpState = usePopUp(["overwriteAuthMethod"] as const); const { control, handleSubmit, reset, formState: { isSubmitting }, - watch, + watch } = useForm({ resolver: zodResolver(schema), defaultValues: { @@ -180,12 +189,10 @@ export const IdentityGcpAuthForm = ({ handlePopUpToggle("identityAuthMethod", false); createNotification({ - text: `Successfully ${identityAuthMethodData?.authMethod === initialAuthMethod ? "updated" : "configured" - } auth method`, + text: `Successfully ${isCurrentAuthMethod ? "updated" : "configured"} auth method`, type: "success" }); - reset(); } catch (err) { createNotification({ @@ -196,231 +203,244 @@ export const IdentityGcpAuthForm = ({ }; return ( -
- ( - - - - )} - /> - ( - - - - )} - /> - {watchedType === "gce" && ( + <> + ( + + + + )} + /> + ( - + )} /> - )} - {watchedType === "gce" && ( - ( - - - - )} - /> - )} - ( - - - - )} - /> - ( - - - - )} - /> - ( - - - - )} - /> - {accessTokenTrustedIpsFields.map(({ id }, index) => ( -
+ {watchedType === "gce" && ( { - return ( - - { - if (subscription?.ipAllowlisting) { - field.onChange(e); - return; - } - - handlePopUpOpen("upgradePlan"); - }} - placeholder="123.456.789.0" - /> - - ); - }} + name="allowedProjects" + render={({ field, fieldState: { error } }) => ( + + + + )} /> - ( + + + + )} + /> + )} + ( + + + + )} + /> + ( + + + + )} + /> + ( + + + + )} + /> + {accessTokenTrustedIpsFields.map(({ id }, index) => ( +
+ { + return ( + + { + if (subscription?.ipAllowlisting) { + field.onChange(e); + return; + } + + handlePopUpOpen("upgradePlan"); + }} + placeholder="123.456.789.0" + /> + + ); + }} + /> + { + if (subscription?.ipAllowlisting) { + removeAccessTokenTrustedIp(index); + return; + } + + handlePopUpOpen("upgradePlan"); + }} + size="lg" + colorSchema="danger" + variant="plain" + ariaLabel="update" + className="p-3" + > + + +
+ ))} +
+
- ))} -
- -
-
-
- {(initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod) ? +
+
+ {initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod ? ( + + ) : ( + + )} - : - } - + onClick={() => handlePopUpToggle("revokeAuthMethod", true)} + > + Remove Auth Method + + )}
- {identityAuthMethodData?.authMethod === initialAuthMethod && ( - - )} -
+ popup.handlePopUpToggle("overwriteAuthMethod", isOpen)} - deleteKey="confirm" - onDeleteApproved={async () => { await revokeAuth(initialAuthMethod); handleSubmit(onFormSubmit)(); }} - /> - + 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)(); + }} + /> + ); }; diff --git a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityKubernetesAuthForm.tsx b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityKubernetesAuthForm.tsx index adcf93cbe..fc272a63f 100644 --- a/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityKubernetesAuthForm.tsx +++ b/frontend/src/views/Org/MembersPage/components/OrgIdentityTab/components/IdentitySection/IdentityKubernetesAuthForm.tsx @@ -6,7 +6,14 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; import { createNotification } from "@app/components/notifications"; -import { Button, DeleteActionModal, 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 { useAddIdentityKubernetesAuth, @@ -73,17 +80,18 @@ export const IdentityKubernetesAuthForm = ({ const { mutateAsync: addMutateAsync } = useAddIdentityKubernetesAuth(); const { mutateAsync: updateMutateAsync } = useUpdateIdentityKubernetesAuth(); - const { data } = useGetIdentityKubernetesAuth(identityAuthMethodData?.identityId ?? ""); - const popup = usePopUp([ - "overwriteAuthMethod", - ] as const); + const isCurrentAuthMethod = identityAuthMethodData?.authMethod === initialAuthMethod; + const { data } = useGetIdentityKubernetesAuth(identityAuthMethodData?.identityId ?? "", { + enabled: isCurrentAuthMethod + }); + const internalPopUpState = usePopUp(["overwriteAuthMethod"] as const); const { control, handleSubmit, reset, trigger, - formState: { isSubmitting }, + formState: { isSubmitting } } = useForm({ resolver: zodResolver(schema), defaultValues: { @@ -192,8 +200,7 @@ export const IdentityKubernetesAuthForm = ({ handlePopUpToggle("identityAuthMethod", false); createNotification({ - text: `Successfully ${identityAuthMethodData?.authMethod === initialAuthMethod ? "updated" : "configured" - } auth method`, + text: `Successfully ${isCurrentAuthMethod ? "updated" : "configured"} auth method`, type: "success" }); @@ -207,269 +214,277 @@ export const IdentityKubernetesAuthForm = ({ }; return ( -
- ( - - - - )} - /> - ( - - - - )} - /> - ( - - - - )} - /> - ( - - - - )} - /> - ( - + + ( + - - - )} - /> - ( - -