diff --git a/frontend/src/hooks/api/identities/mutations.tsx b/frontend/src/hooks/api/identities/mutations.tsx index 42de92e71..3e38d9067 100644 --- a/frontend/src/hooks/api/identities/mutations.tsx +++ b/frontend/src/hooks/api/identities/mutations.tsx @@ -923,7 +923,7 @@ export const useAddIdentityTokenAuth = () => { }); queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) }); queryClient.invalidateQueries({ - queryKey: identitiesKeys.getIdentityUniversalAuth(identityId) + queryKey: identitiesKeys.getIdentityTokenAuth(identityId) }); } }); @@ -959,7 +959,7 @@ export const useUpdateIdentityTokenAuth = () => { }); queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) }); queryClient.invalidateQueries({ - queryKey: identitiesKeys.getIdentityUniversalAuth(identityId) + queryKey: identitiesKeys.getIdentityTokenAuth(identityId) }); } }); diff --git a/frontend/src/hooks/api/reactQuery.tsx b/frontend/src/hooks/api/reactQuery.tsx index d6ffc9378..f6ae0ca76 100644 --- a/frontend/src/hooks/api/reactQuery.tsx +++ b/frontend/src/hooks/api/reactQuery.tsx @@ -182,7 +182,7 @@ export const queryClient = new QueryClient({ createNotification({ title: "Bad Request", type: "error", - text: `${serverResponse.message}${serverResponse.message.endsWith(".") ? "" : "."}`, + text: `${serverResponse.message}${serverResponse.message?.endsWith(".") ? "" : "."}`, copyActions: [ { value: serverResponse.reqId, diff --git a/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityAuthMethodModal.tsx b/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityAuthMethodModal.tsx index 70128fa1a..a5f2357dd 100644 --- a/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityAuthMethodModal.tsx +++ b/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityAuthMethodModal.tsx @@ -7,10 +7,10 @@ import { UsePopUpState } from "@app/hooks/usePopUp"; import { IdentityAuthMethodModalContent } from "./IdentityAuthMethodModalContent"; type Props = { - popUp: UsePopUpState<["identityAuthMethod", "upgradePlan", "revokeAuthMethod"]>; + popUp: UsePopUpState<["identityAuthMethod", "upgradePlan"]>; handlePopUpOpen: (popUpName: keyof UsePopUpState<["upgradePlan"]>) => void; handlePopUpToggle: ( - popUpName: keyof UsePopUpState<["identityAuthMethod", "upgradePlan", "revokeAuthMethod"]>, + popUpName: keyof UsePopUpState<["identityAuthMethod", "upgradePlan"]>, state?: boolean ) => void; }; @@ -34,7 +34,7 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog title={ isSelectedAuthAlreadyConfigured ? `Edit ${identityAuthToNameMap[selectedAuthMethod!] ?? ""}` - : `Create new ${identityAuthToNameMap[selectedAuthMethod!] ?? ""}` + : `Add ${identityAuthToNameMap[selectedAuthMethod!] ?? ""}` } > ; + popUp: UsePopUpState<["identityAuthMethod", "upgradePlan"]>; handlePopUpOpen: (popUpName: keyof UsePopUpState<["upgradePlan"]>) => void; handlePopUpToggle: ( - popUpName: keyof UsePopUpState<["identityAuthMethod", "upgradePlan", "revokeAuthMethod"]>, + popUpName: keyof UsePopUpState<["identityAuthMethod", "upgradePlan"]>, state?: boolean ) => void; @@ -56,13 +34,7 @@ type Props = { setSelectedAuthMethod: (authMethod: IdentityAuthMethod) => void; }; -type TRevokeOptions = { - identityId: string; - organizationId: string; -}; - type TRevokeMethods = { - revokeMethod: (revokeOptions: TRevokeOptions) => Promise; render: () => JSX.Element; }; @@ -96,18 +68,6 @@ export const IdentityAuthMethodModalContent = ({ initialAuthMethod, setSelectedAuthMethod }: Props) => { - const { currentOrg } = useOrganization(); - const orgId = currentOrg?.id || ""; - - const { mutateAsync: revokeUniversalAuth } = useDeleteIdentityUniversalAuth(); - const { mutateAsync: revokeTokenAuth } = useDeleteIdentityTokenAuth(); - const { mutateAsync: revokeKubernetesAuth } = useDeleteIdentityKubernetesAuth(); - const { mutateAsync: revokeGcpAuth } = useDeleteIdentityGcpAuth(); - const { mutateAsync: revokeAwsAuth } = useDeleteIdentityAwsAuth(); - const { mutateAsync: revokeAzureAuth } = useDeleteIdentityAzureAuth(); - const { mutateAsync: revokeOidcAuth } = useDeleteIdentityOidcAuth(); - const { mutateAsync: revokeJwtAuth } = useDeleteIdentityJwtAuth(); - const { control, watch } = useForm({ resolver: zodResolver(schema), defaultValues: async () => { @@ -149,10 +109,9 @@ export const IdentityAuthMethodModalContent = ({ const methodMap: Record = { [IdentityAuthMethod.UNIVERSAL_AUTH]: { - revokeMethod: revokeUniversalAuth, render: () => ( @@ -160,10 +119,9 @@ export const IdentityAuthMethodModalContent = ({ }, [IdentityAuthMethod.OIDC_AUTH]: { - revokeMethod: revokeOidcAuth, render: () => ( @@ -171,10 +129,9 @@ export const IdentityAuthMethodModalContent = ({ }, [IdentityAuthMethod.TOKEN_AUTH]: { - revokeMethod: revokeTokenAuth, render: () => ( @@ -182,10 +139,9 @@ export const IdentityAuthMethodModalContent = ({ }, [IdentityAuthMethod.AZURE_AUTH]: { - revokeMethod: revokeAzureAuth, render: () => ( @@ -193,10 +149,9 @@ export const IdentityAuthMethodModalContent = ({ }, [IdentityAuthMethod.GCP_AUTH]: { - revokeMethod: revokeGcpAuth, render: () => ( @@ -204,10 +159,9 @@ export const IdentityAuthMethodModalContent = ({ }, [IdentityAuthMethod.KUBERNETES_AUTH]: { - revokeMethod: revokeKubernetesAuth, render: () => ( @@ -215,10 +169,9 @@ export const IdentityAuthMethodModalContent = ({ }, [IdentityAuthMethod.AWS_AUTH]: { - revokeMethod: revokeAwsAuth, render: () => ( @@ -226,10 +179,9 @@ export const IdentityAuthMethodModalContent = ({ }, [IdentityAuthMethod.JWT_AUTH]: { - revokeMethod: revokeJwtAuth, render: () => ( @@ -294,42 +246,6 @@ export const IdentityAuthMethodModalContent = ({ onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)} text="You can use IP allowlisting if you switch to Infisical's Pro plan." /> - handlePopUpToggle("revokeAuthMethod", isOpen)} - deleteKey="confirm" - buttonText="Remove" - onDeleteApproved={async () => { - if (!identityAuthMethodData.authMethod || !orgId || !selectedMethodItem) { - return; - } - - try { - await selectedMethodItem.revokeMethod({ - identityId: identityAuthMethodData.identityId, - organizationId: orgId - }); - - createNotification({ - text: "Successfully removed auth method", - type: "success" - }); - - handlePopUpToggle("revokeAuthMethod", false); - handlePopUpToggle("identityAuthMethod", false); - } catch { - createNotification({ - text: "Failed to remove auth method", - type: "error" - }); - } - }} - /> ); }; diff --git a/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityAwsAuthForm.tsx b/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityAwsAuthForm.tsx index 59528e3a7..7f609305d 100644 --- a/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityAwsAuthForm.tsx +++ b/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityAwsAuthForm.tsx @@ -1,4 +1,4 @@ -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import { Controller, useFieldArray, useForm } from "react-hook-form"; import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -6,17 +6,27 @@ 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, + FormControl, + IconButton, + Input, + Tab, + TabList, + TabPanel, + Tabs +} from "@app/components/v2"; import { useOrganization, useSubscription } from "@app/context"; import { useAddIdentityAwsAuth, useGetIdentityAwsAuth, useUpdateIdentityAwsAuth } 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 { IdentityFormTab } from "./types"; + const schema = z .object({ stsEndpoint: z.string(), @@ -49,21 +59,18 @@ export type FormData = z.infer; type Props = { handlePopUpOpen: (popUpName: keyof UsePopUpState<["upgradePlan"]>) => void; handlePopUpToggle: ( - popUpName: keyof UsePopUpState<["identityAuthMethod", "revokeAuthMethod"]>, + popUpName: keyof UsePopUpState<["identityAuthMethod"]>, state?: boolean ) => void; - identityAuthMethodData: { - identityId: string; - name: string; - configuredAuthMethods?: IdentityAuthMethod[]; - authMethod?: IdentityAuthMethod; - }; + identityId?: string; + isUpdate?: boolean; }; export const IdentityAwsAuthForm = ({ handlePopUpOpen, handlePopUpToggle, - identityAuthMethodData + identityId, + isUpdate }: Props) => { const { currentOrg } = useOrganization(); const orgId = currentOrg?.id || ""; @@ -71,11 +78,9 @@ export const IdentityAwsAuthForm = ({ const { mutateAsync: addMutateAsync } = useAddIdentityAwsAuth(); const { mutateAsync: updateMutateAsync } = useUpdateIdentityAwsAuth(); + const [tabValue, setTabValue] = useState(IdentityFormTab.Configuration); - const isUpdate = identityAuthMethodData?.configuredAuthMethods?.includes( - identityAuthMethodData.authMethod! || "" - ); - const { data } = useGetIdentityAwsAuth(identityAuthMethodData?.identityId ?? "", { + const { data } = useGetIdentityAwsAuth(identityId ?? "", { enabled: isUpdate }); @@ -143,7 +148,7 @@ export const IdentityAwsAuthForm = ({ accessTokenTrustedIps }: FormData) => { try { - if (!identityAuthMethodData) return; + if (!identityId) return; if (data) { await updateMutateAsync({ @@ -151,7 +156,7 @@ export const IdentityAwsAuthForm = ({ stsEndpoint, allowedPrincipalArns, allowedAccountIds, - identityId: identityAuthMethodData.identityId, + identityId, accessTokenTTL: Number(accessTokenTTL), accessTokenMaxTTL: Number(accessTokenMaxTTL), accessTokenNumUsesLimit: Number(accessTokenNumUsesLimit), @@ -160,7 +165,7 @@ export const IdentityAwsAuthForm = ({ } else { await addMutateAsync({ organizationId: orgId, - identityId: identityAuthMethodData.identityId, + identityId, stsEndpoint: stsEndpoint || "", allowedPrincipalArns: allowedPrincipalArns || "", allowedAccountIds: allowedAccountIds || "", @@ -188,189 +193,194 @@ export const IdentityAwsAuthForm = ({ }; return ( -
- ( - - - - )} - /> - ( - - - - )} - /> - ( - - - - )} - /> - ( - - - - )} - /> - ( - - - - )} - /> - ( - - - - )} - /> - {accessTokenTrustedIpsFields.map(({ id }, index) => ( -
+ { + setTabValue( + ["accessTokenTrustedIps"].includes(Object.keys(fields)[0]) + ? IdentityFormTab.Advanced + : IdentityFormTab.Configuration + ); + })} + > + setTabValue(value as IdentityFormTab)}> + + Configuration + Advanced + + { - return ( - - { - if (subscription?.ipAllowlisting) { - field.onChange(e); - return; - } - - handlePopUpOpen("upgradePlan"); - }} - placeholder="123.456.789.0" - /> - - ); - }} + defaultValue="2592000" + name="allowedPrincipalArns" + render={({ field, fieldState: { error } }) => ( + + + + )} /> - { - if (subscription?.ipAllowlisting) { - removeAccessTokenTrustedIp(index); - return; - } + ( + + + + )} + /> + ( + + + + )} + /> + ( + + + + )} + /> + ( + + + + )} + /> + ( + + + + )} + /> + + + {accessTokenTrustedIpsFields.map(({ id }, index) => ( +
+ { + return ( + + { + if (subscription?.ipAllowlisting) { + field.onChange(e); + return; + } - handlePopUpOpen("upgradePlan"); - }} - size="lg" - colorSchema="danger" - variant="plain" - ariaLabel="update" - className="p-3" - > - - -
- ))} -
+ 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" + > + + +
+ ))} +
+ +
+
+
+
-
-
-
- - -
- {isUpdate && ( - - )} +
); diff --git a/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityAzureAuthForm.tsx b/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityAzureAuthForm.tsx index 7af879888..1bfdf2757 100644 --- a/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityAzureAuthForm.tsx +++ b/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityAzureAuthForm.tsx @@ -1,4 +1,4 @@ -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import { Controller, useFieldArray, useForm } from "react-hook-form"; import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -6,17 +6,27 @@ 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, + FormControl, + IconButton, + Input, + Tab, + TabList, + TabPanel, + Tabs +} from "@app/components/v2"; import { useOrganization, useSubscription } from "@app/context"; import { useAddIdentityAzureAuth, useGetIdentityAzureAuth, useUpdateIdentityAzureAuth } 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 { IdentityFormTab } from "./types"; + const schema = z .object({ tenantId: z.string().min(1), @@ -44,21 +54,18 @@ export type FormData = z.infer; type Props = { handlePopUpOpen: (popUpName: keyof UsePopUpState<["upgradePlan"]>) => void; handlePopUpToggle: ( - popUpName: keyof UsePopUpState<["identityAuthMethod", "revokeAuthMethod"]>, + popUpName: keyof UsePopUpState<["identityAuthMethod"]>, state?: boolean ) => void; - identityAuthMethodData: { - identityId: string; - name: string; - configuredAuthMethods?: IdentityAuthMethod[]; - authMethod?: IdentityAuthMethod; - }; + identityId?: string; + isUpdate?: boolean; }; export const IdentityAzureAuthForm = ({ handlePopUpOpen, handlePopUpToggle, - identityAuthMethodData + identityId, + isUpdate }: Props) => { const { currentOrg } = useOrganization(); const orgId = currentOrg?.id || ""; @@ -66,11 +73,9 @@ export const IdentityAzureAuthForm = ({ const { mutateAsync: addMutateAsync } = useAddIdentityAzureAuth(); const { mutateAsync: updateMutateAsync } = useUpdateIdentityAzureAuth(); + const [tabValue, setTabValue] = useState(IdentityFormTab.Configuration); - const isUpdate = identityAuthMethodData?.configuredAuthMethods?.includes( - identityAuthMethodData.authMethod! || "" - ); - const { data } = useGetIdentityAzureAuth(identityAuthMethodData?.identityId ?? "", { + const { data } = useGetIdentityAzureAuth(identityId ?? "", { enabled: isUpdate }); @@ -139,12 +144,12 @@ export const IdentityAzureAuthForm = ({ accessTokenTrustedIps }: FormData) => { try { - if (!identityAuthMethodData) return; + if (!identityId) return; if (data) { await updateMutateAsync({ organizationId: orgId, - identityId: identityAuthMethodData.identityId, + identityId, tenantId, resource, allowedServicePrincipalIds, @@ -156,7 +161,7 @@ export const IdentityAzureAuthForm = ({ } else { await addMutateAsync({ organizationId: orgId, - identityId: identityAuthMethodData.identityId, + identityId, tenantId: tenantId || "", resource: resource || "", allowedServicePrincipalIds: allowedServicePrincipalIds || "", @@ -184,189 +189,194 @@ export const IdentityAzureAuthForm = ({ }; return ( -
- ( - - - - )} - /> - ( - - - - )} - /> - ( - - - - )} - /> - ( - - - - )} - /> - ( - - - - )} - /> - ( - - - - )} - /> - {accessTokenTrustedIpsFields.map(({ id }, index) => ( -
+ { + setTabValue( + ["accessTokenTrustedIps"].includes(Object.keys(fields)[0]) + ? IdentityFormTab.Advanced + : IdentityFormTab.Configuration + ); + })} + > + setTabValue(value as IdentityFormTab)}> + + Configuration + Advanced + + { - return ( - - { - if (subscription?.ipAllowlisting) { - field.onChange(e); - return; - } - - handlePopUpOpen("upgradePlan"); - }} - placeholder="123.456.789.0" - /> - - ); - }} + defaultValue="2592000" + name="tenantId" + render={({ field, fieldState: { error } }) => ( + + + + )} /> - { - if (subscription?.ipAllowlisting) { - removeAccessTokenTrustedIp(index); - return; - } + ( + + + + )} + /> + ( + + + + )} + /> + ( + + + + )} + /> + ( + + + + )} + /> + ( + + + + )} + /> + + + {accessTokenTrustedIpsFields.map(({ id }, index) => ( +
+ { + return ( + + { + if (subscription?.ipAllowlisting) { + field.onChange(e); + return; + } - handlePopUpOpen("upgradePlan"); - }} - size="lg" - colorSchema="danger" - variant="plain" - ariaLabel="update" - className="p-3" - > - - -
- ))} -
+ 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" + > + + +
+ ))} +
+ +
+
+
+
-
-
-
- - -
- {isUpdate && ( - - )} +
); diff --git a/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityGcpAuthForm.tsx b/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityGcpAuthForm.tsx index 0cccb8213..2a3fc526d 100644 --- a/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityGcpAuthForm.tsx +++ b/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityGcpAuthForm.tsx @@ -1,4 +1,4 @@ -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import { Controller, useFieldArray, useForm } from "react-hook-form"; import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -6,17 +6,29 @@ 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, + FormControl, + IconButton, + Input, + Select, + SelectItem, + Tab, + TabList, + TabPanel, + Tabs +} from "@app/components/v2"; import { useOrganization, useSubscription } from "@app/context"; import { useAddIdentityGcpAuth, useGetIdentityGcpAuth, useUpdateIdentityGcpAuth } 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 { IdentityFormTab } from "./types"; + const schema = z .object({ type: z.enum(["iam", "gce"]), @@ -45,21 +57,18 @@ export type FormData = z.infer; type Props = { handlePopUpOpen: (popUpName: keyof UsePopUpState<["upgradePlan"]>) => void; handlePopUpToggle: ( - popUpName: keyof UsePopUpState<["identityAuthMethod", "revokeAuthMethod"]>, + popUpName: keyof UsePopUpState<["identityAuthMethod"]>, state?: boolean ) => void; - identityAuthMethodData: { - identityId: string; - name: string; - configuredAuthMethods?: IdentityAuthMethod[]; - authMethod?: IdentityAuthMethod; - }; + identityId?: string; + isUpdate?: boolean; }; export const IdentityGcpAuthForm = ({ handlePopUpOpen, handlePopUpToggle, - identityAuthMethodData + identityId, + isUpdate }: Props) => { const { currentOrg } = useOrganization(); const orgId = currentOrg?.id || ""; @@ -67,11 +76,9 @@ export const IdentityGcpAuthForm = ({ const { mutateAsync: addMutateAsync } = useAddIdentityGcpAuth(); const { mutateAsync: updateMutateAsync } = useUpdateIdentityGcpAuth(); + const [tabValue, setTabValue] = useState(IdentityFormTab.Configuration); - const isUpdate = identityAuthMethodData?.configuredAuthMethods?.includes( - identityAuthMethodData.authMethod! || "" - ); - const { data } = useGetIdentityGcpAuth(identityAuthMethodData?.identityId ?? "", { + const { data } = useGetIdentityGcpAuth(identityId ?? "", { enabled: isUpdate }); @@ -146,11 +153,11 @@ export const IdentityGcpAuthForm = ({ accessTokenTrustedIps }: FormData) => { try { - if (!identityAuthMethodData) return; + if (!identityId) return; if (data) { await updateMutateAsync({ - identityId: identityAuthMethodData.identityId, + identityId, organizationId: orgId, type, allowedServiceAccounts, @@ -163,7 +170,7 @@ export const IdentityGcpAuthForm = ({ }); } else { await addMutateAsync({ - identityId: identityAuthMethodData.identityId, + identityId, organizationId: orgId, type, allowedServiceAccounts: allowedServiceAccounts || "", @@ -193,213 +200,222 @@ export const IdentityGcpAuthForm = ({ }; return ( -
- ( - - - - )} - /> - ( - - - - )} - /> - {watchedType === "gce" && ( - ( - - - - )} - /> - )} - {watchedType === "gce" && ( - ( - - - - )} - /> - )} - ( - - - - )} - /> - ( - - - - )} - /> - ( - - - - )} - /> - {accessTokenTrustedIpsFields.map(({ id }, index) => ( -
+ { + setTabValue( + ["accessTokenTrustedIps"].includes(Object.keys(fields)[0]) + ? IdentityFormTab.Advanced + : IdentityFormTab.Configuration + ); + })} + > + setTabValue(value as IdentityFormTab)}> + + Configuration + Advanced + + { - return ( + name="type" + render={({ field: { onChange, ...field }, fieldState: { error } }) => ( + + + + )} + /> + ( + + + + )} + /> + {watchedType === "gce" && ( + ( - { - if (subscription?.ipAllowlisting) { - field.onChange(e); - return; - } - - handlePopUpOpen("upgradePlan"); - }} - placeholder="123.456.789.0" - /> + - ); - }} + )} + /> + )} + {watchedType === "gce" && ( + ( + + + + )} + /> + )} + ( + + + + )} /> - { - if (subscription?.ipAllowlisting) { - removeAccessTokenTrustedIp(index); - return; - } + ( + + + + )} + /> + ( + + + + )} + /> + + + {accessTokenTrustedIpsFields.map(({ id }, index) => ( +
+ { + return ( + + { + if (subscription?.ipAllowlisting) { + field.onChange(e); + return; + } - handlePopUpOpen("upgradePlan"); - }} - size="lg" - colorSchema="danger" - variant="plain" - ariaLabel="update" - className="p-3" - > - - -
- ))} -
+ 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" + > + + +
+ ))} +
+ +
+
+
+
-
-
-
- - -
- {isUpdate && ( - - )} +
); diff --git a/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityJwtAuthForm.tsx b/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityJwtAuthForm.tsx index e975b272d..32ad5b6ad 100644 --- a/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityJwtAuthForm.tsx +++ b/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityJwtAuthForm.tsx @@ -1,4 +1,4 @@ -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import { Controller, useFieldArray, useForm } from "react-hook-form"; import { faQuestionCircle } from "@fortawesome/free-regular-svg-icons"; import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons"; @@ -14,17 +14,22 @@ import { Input, Select, SelectItem, + Tab, + TabList, + TabPanel, + Tabs, TextArea, Tooltip } from "@app/components/v2"; import { useOrganization, useSubscription } from "@app/context"; import { useAddIdentityJwtAuth, useUpdateIdentityJwtAuth } from "@app/hooks/api"; -import { IdentityAuthMethod } from "@app/hooks/api/identities"; import { IdentityJwtConfigurationType } from "@app/hooks/api/identities/enums"; import { useGetIdentityJwtAuth } from "@app/hooks/api/identities/queries"; import { IdentityTrustedIp } from "@app/hooks/api/identities/types"; import { UsePopUpState } from "@app/hooks/usePopUp"; +import { IdentityFormTab } from "./types"; + const commonSchema = z.object({ accessTokenTrustedIps: z .array( @@ -85,21 +90,18 @@ export type FormData = z.infer; type Props = { handlePopUpOpen: (popUpName: keyof UsePopUpState<["upgradePlan"]>) => void; handlePopUpToggle: ( - popUpName: keyof UsePopUpState<["identityAuthMethod", "revokeAuthMethod"]>, + popUpName: keyof UsePopUpState<["identityAuthMethod"]>, state?: boolean ) => void; - identityAuthMethodData: { - identityId: string; - name: string; - configuredAuthMethods?: IdentityAuthMethod[]; - authMethod?: IdentityAuthMethod; - }; + identityId?: string; + isUpdate?: boolean; }; export const IdentityJwtAuthForm = ({ handlePopUpOpen, handlePopUpToggle, - identityAuthMethodData + identityId, + isUpdate }: Props) => { const { currentOrg } = useOrganization(); const orgId = currentOrg?.id || ""; @@ -107,11 +109,9 @@ export const IdentityJwtAuthForm = ({ const { mutateAsync: addMutateAsync } = useAddIdentityJwtAuth(); const { mutateAsync: updateMutateAsync } = useUpdateIdentityJwtAuth(); + const [tabValue, setTabValue] = useState(IdentityFormTab.Configuration); - const isUpdate = identityAuthMethodData?.configuredAuthMethods?.includes( - identityAuthMethodData.authMethod! || "" - ); - const { data } = useGetIdentityJwtAuth(identityAuthMethodData?.identityId ?? "", { + const { data } = useGetIdentityJwtAuth(identityId ?? "", { enabled: isUpdate }); @@ -218,13 +218,13 @@ export const IdentityJwtAuthForm = ({ boundSubject }: FormData) => { try { - if (!identityAuthMethodData) { + if (!identityId) { return; } if (data) { await updateMutateAsync({ - identityId: identityAuthMethodData.identityId, + identityId, organizationId: orgId, configurationType, jwksUrl, @@ -241,7 +241,7 @@ export const IdentityJwtAuthForm = ({ }); } else { await addMutateAsync({ - identityId: identityAuthMethodData.identityId, + identityId, configurationType, jwksUrl, jwksCaCert, @@ -275,56 +275,179 @@ export const IdentityJwtAuthForm = ({ }; return ( -
- ( - - - - )} - /> - {selectedConfigurationType === IdentityJwtConfigurationType.JWKS && ( - <> + { + setTabValue( + ["accessTokenTrustedIps"].includes(Object.keys(fields)[0]) + ? IdentityFormTab.Advanced + : IdentityFormTab.Configuration + ); + })} + > + setTabValue(value as IdentityFormTab)}> + + Configuration + Advanced + + ( + name="configurationType" + render={({ field: { onChange, ...field }, fieldState: { error } }) => ( + + + )} + /> + {selectedConfigurationType === IdentityJwtConfigurationType.JWKS && ( + <> + ( + + + + )} + /> + ( + +