fix: address changes

This commit is contained in:
Scott Wilson
2024-09-30 16:53:42 -07:00
parent f63c6b725b
commit ad88aaf17f
9 changed files with 1760 additions and 1602 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.mixed<IdentityAuthMethod>().oneOf(Object.values(IdentityAuthMethod)).required("Auth method is required") authMethod: yup
.mixed<IdentityAuthMethod>()
.oneOf(Object.values(IdentityAuthMethod))
.required("Auth method is required")
}) })
.required(); .required();
@@ -71,27 +75,33 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog
const { mutateAsync: revokeAwsAuth } = useDeleteIdentityAwsAuth(); const { mutateAsync: revokeAwsAuth } = useDeleteIdentityAwsAuth();
const { mutateAsync: revokeAzureAuth } = useDeleteIdentityAzureAuth(); const { mutateAsync: revokeAzureAuth } = useDeleteIdentityAzureAuth();
const { mutateAsync: revokeOidcAuth } = useDeleteIdentityOidcAuth(); const { mutateAsync: revokeOidcAuth } = useDeleteIdentityOidcAuth();
const initialAuthMethod = popUp?.identityAuthMethod?.data?.authMethod; const initialAuthMethod = popUp?.identityAuthMethod?.data?.authMethod;
const { control, watch, setValue } = useForm<FormData>({ const { control, watch, setValue, reset } = useForm<FormData>({
resolver: yupResolver(schema), resolver: yupResolver(schema),
defaultValues: { defaultValues: {
authMethod: initialAuthMethod authMethod: initialAuthMethod
} }
}); });
const identityAuthMethodData = { useEffect(() => {
identityId: popUp?.identityAuthMethod.data?.identityId, // reset form on open
name: popUp?.identityAuthMethod?.data?.name, if (popUp.identityAuthMethod.isOpen)
authMethod: watch("authMethod") reset({ authMethod: popUp?.identityAuthMethod?.data?.authMethod });
} as { }, [popUp.identityAuthMethod.isOpen]);
identityId: string;
name: string; const identityAuthMethodData = {
authMethod?: IdentityAuthMethod; 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) { if (identityAuthMethodData?.authMethod) {
setValue("authMethod", identityAuthMethodData.authMethod); setValue("authMethod", identityAuthMethodData.authMethod);
return; return;
@@ -103,7 +113,6 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog
const onRevokeAuthMethodSubmit = async (authMethod: IdentityAuthMethod) => { const onRevokeAuthMethodSubmit = async (authMethod: IdentityAuthMethod) => {
if (!orgId || !authMethod) return; if (!orgId || !authMethod) return;
try { try {
console.log("onRevokeAuthMethodSubmit identityId: ", identityAuthMethodData);
switch (authMethod) { switch (authMethod) {
case IdentityAuthMethod.UNIVERSAL_AUTH: { case IdentityAuthMethod.UNIVERSAL_AUTH: {
await revokeUniversalAuth({ await revokeUniversalAuth({
@@ -159,9 +168,7 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog
} }
createNotification({ createNotification({
text: `Successfully removed ${ text: `Successfully removed ${identityAuthToNameMap[authMethod]} on ${identityAuthMethodData.name}`,
identityAuthToNameMap[authMethod]
} on ${identityAuthMethodData.name}`,
type: "success" type: "success"
}); });
@@ -170,9 +177,7 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog
} catch (err) { } catch (err) {
console.error(err); console.error(err);
createNotification({ createNotification({
text: `Failed to remove ${identityAuthToNameMap[authMethod]} on ${ text: `Failed to remove ${identityAuthToNameMap[authMethod]} on ${identityAuthMethodData.name}`,
identityAuthMethodData.name
}`,
type: "error" type: "error"
}); });
} }
@@ -272,7 +277,9 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog
<ModalContent <ModalContent
title={`${ title={`${
identityAuthMethodData.authMethod === initialAuthMethod ? "Update" : "Configure" identityAuthMethodData.authMethod === initialAuthMethod ? "Update" : "Configure"
} Identity Auth Method for ${identityAuthToNameMap[identityAuthMethodData.authMethod!] ?? ""}`} } Identity Auth Method for ${
identityAuthToNameMap[identityAuthMethodData.authMethod!] ?? ""
}`}
> >
<Controller <Controller
control={control} control={control}
@@ -283,7 +290,9 @@ 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"
> >
{identityAuthMethods.map(({ label, value }) => ( {identityAuthMethods.map(({ label, value }) => (
@@ -310,6 +319,7 @@ 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"
buttonText="Remove"
onDeleteApproved={() => onRevokeAuthMethodSubmit(identityAuthMethodData.authMethod!)} onDeleteApproved={() => onRevokeAuthMethodSubmit(identityAuthMethodData.authMethod!)}
/> />
</ModalContent> </ModalContent>
@@ -82,11 +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 popup = usePopUp([ const internalPopUpState = usePopUp(["overwriteAuthMethod"] as const);
"overwriteAuthMethod",
] as const);
const { const {
control, control,
@@ -183,8 +184,7 @@ export const IdentityAwsAuthForm = ({
handlePopUpToggle("identityAuthMethod", false); handlePopUpToggle("identityAuthMethod", false);
createNotification({ createNotification({
text: `Successfully ${identityAuthMethodData?.authMethod === initialAuthMethod ? "updated" : "configured" text: `Successfully ${isCurrentAuthMethod ? "updated" : "configured"} auth method`,
} auth method`,
type: "success" type: "success"
}); });
@@ -198,207 +198,216 @@ export const IdentityAwsAuthForm = ({
}; };
return ( return (
<form onSubmit={handleSubmit(onFormSubmit)}> <>
<Controller <form onSubmit={handleSubmit(onFormSubmit)}>
control={control} <Controller
defaultValue="2592000" control={control}
name="allowedPrincipalArns" defaultValue="2592000"
render={({ field, fieldState: { error } }) => ( name="allowedPrincipalArns"
<FormControl render={({ field, fieldState: { error } }) => (
label="Allowed Principal ARNs" <FormControl
isError={Boolean(error)} label="Allowed Principal ARNs"
errorText={error?.message} isError={Boolean(error)}
> errorText={error?.message}
<Input >
{...field} <Input
placeholder="arn:aws:iam::123456789012:role/MyRoleName, arn:aws:iam::123456789012:user/MyUserName..." {...field}
type="text" placeholder="arn:aws:iam::123456789012:role/MyRoleName, arn:aws:iam::123456789012:user/MyUserName..."
/> type="text"
</FormControl> />
)} </FormControl>
/> )}
<Controller />
control={control} <Controller
name="allowedAccountIds" control={control}
render={({ field, fieldState: { error } }) => ( name="allowedAccountIds"
<FormControl render={({ field, fieldState: { error } }) => (
label="Allowed Account IDs" <FormControl
isError={Boolean(error)} label="Allowed Account IDs"
errorText={error?.message} isError={Boolean(error)}
> errorText={error?.message}
<Input {...field} placeholder="123456789012, ..." /> >
</FormControl> <Input {...field} placeholder="123456789012, ..." />
)} </FormControl>
/> )}
<Controller />
control={control} <Controller
defaultValue="https://sts.amazonaws.com/" control={control}
name="stsEndpoint" defaultValue="https://sts.amazonaws.com/"
render={({ field, fieldState: { error } }) => ( name="stsEndpoint"
<FormControl label="STS Endpoint" isError={Boolean(error)} errorText={error?.message}> render={({ field, fieldState: { error } }) => (
<Input {...field} placeholder="https://sts.amazonaws.com/" type="text" /> <FormControl label="STS Endpoint" isError={Boolean(error)} errorText={error?.message}>
</FormControl> <Input {...field} placeholder="https://sts.amazonaws.com/" type="text" />
)} </FormControl>
/> )}
<Controller />
control={control} <Controller
defaultValue="2592000" control={control}
name="accessTokenTTL" defaultValue="2592000"
render={({ field, fieldState: { error } }) => ( name="accessTokenTTL"
<FormControl render={({ field, fieldState: { error } }) => (
label="Access Token TTL (seconds)" <FormControl
isError={Boolean(error)} label="Access Token TTL (seconds)"
errorText={error?.message} isError={Boolean(error)}
> errorText={error?.message}
<Input {...field} placeholder="2592000" type="number" min="1" step="1" /> >
</FormControl> <Input {...field} placeholder="2592000" type="number" min="1" step="1" />
)} </FormControl>
/> )}
<Controller />
control={control} <Controller
defaultValue="2592000" control={control}
name="accessTokenMaxTTL" defaultValue="2592000"
render={({ field, fieldState: { error } }) => ( name="accessTokenMaxTTL"
<FormControl render={({ field, fieldState: { error } }) => (
label="Access Token Max TTL (seconds)" <FormControl
isError={Boolean(error)} label="Access Token Max TTL (seconds)"
errorText={error?.message} isError={Boolean(error)}
> errorText={error?.message}
<Input {...field} placeholder="2592000" type="number" min="1" step="1" /> >
</FormControl> <Input {...field} placeholder="2592000" type="number" min="1" step="1" />
)} </FormControl>
/> )}
<Controller />
control={control} <Controller
defaultValue="0" control={control}
name="accessTokenNumUsesLimit" defaultValue="0"
render={({ field, fieldState: { error } }) => ( name="accessTokenNumUsesLimit"
<FormControl render={({ field, fieldState: { error } }) => (
label="Access Token Max Number of Uses" <FormControl
isError={Boolean(error)} label="Access Token Max Number of Uses"
errorText={error?.message} isError={Boolean(error)}
> errorText={error?.message}
<Input {...field} placeholder="0" type="number" min="0" step="1" /> >
</FormControl> <Input {...field} placeholder="0" type="number" min="0" step="1" />
)} </FormControl>
/> )}
{accessTokenTrustedIpsFields.map(({ id }, index) => ( />
<div className="mb-3 flex items-end space-x-2" key={id}> {accessTokenTrustedIpsFields.map(({ id }, index) => (
<Controller <div className="mb-3 flex items-end space-x-2" key={id}>
control={control} <Controller
name={`accessTokenTrustedIps.${index}.ipAddress`} control={control}
defaultValue="0.0.0.0/0" name={`accessTokenTrustedIps.${index}.ipAddress`}
render={({ field, fieldState: { error } }) => { defaultValue="0.0.0.0/0"
return ( render={({ field, fieldState: { error } }) => {
<FormControl return (
className="mb-0 flex-grow" <FormControl
label={index === 0 ? "Access Token Trusted IPs" : undefined} className="mb-0 flex-grow"
isError={Boolean(error)} label={index === 0 ? "Access Token Trusted IPs" : undefined}
errorText={error?.message} isError={Boolean(error)}
> errorText={error?.message}
<Input >
value={field.value} <Input
onChange={(e) => { value={field.value}
if (subscription?.ipAllowlisting) { onChange={(e) => {
field.onChange(e); if (subscription?.ipAllowlisting) {
return; field.onChange(e);
} return;
}
handlePopUpOpen("upgradePlan"); handlePopUpOpen("upgradePlan");
}} }}
placeholder="123.456.789.0" placeholder="123.456.789.0"
/> />
</FormControl> </FormControl>
); );
}} }}
/> />
<IconButton <IconButton
onClick={() => {
if (subscription?.ipAllowlisting) {
removeAccessTokenTrustedIp(index);
return;
}
handlePopUpOpen("upgradePlan");
}}
size="lg"
colorSchema="danger"
variant="plain"
ariaLabel="update"
className="p-3"
>
<FontAwesomeIcon icon={faXmark} />
</IconButton>
</div>
))}
<div className="my-4 ml-1">
<Button
variant="outline_bg"
onClick={() => { onClick={() => {
if (subscription?.ipAllowlisting) { if (subscription?.ipAllowlisting) {
removeAccessTokenTrustedIp(index); appendAccessTokenTrustedIp({
ipAddress: "0.0.0.0/0"
});
return; return;
} }
handlePopUpOpen("upgradePlan"); handlePopUpOpen("upgradePlan");
}} }}
size="lg" leftIcon={<FontAwesomeIcon icon={faPlus} />}
colorSchema="danger" size="xs"
variant="plain"
ariaLabel="update"
className="p-3"
> >
<FontAwesomeIcon icon={faXmark} /> Add IP Address
</IconButton> </Button>
</div> </div>
))} <div className="flex justify-between">
<div className="my-4 ml-1"> <div className="flex items-center">
<Button {initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod ? (
variant="outline_bg" <Button
onClick={() => { className="mr-4"
if (subscription?.ipAllowlisting) { size="sm"
appendAccessTokenTrustedIp({ isLoading={isSubmitting}
ipAddress: "0.0.0.0/0" isDisabled={isSubmitting}
}); onClick={() => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", true)}
return; >
} Overwrite
</Button>
handlePopUpOpen("upgradePlan"); ) : (
}} <Button
leftIcon={<FontAwesomeIcon icon={faPlus} />} className="mr-4"
size="xs" size="sm"
> type="submit"
Add IP Address isLoading={isSubmitting}
</Button> isDisabled={isSubmitting}
</div> >
<div className="flex justify-between"> Submit
<div className="flex items-center"> </Button>
{(initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod) ? )}
<Button <Button
className="mr-4" colorSchema="secondary"
size="sm" variant="plain"
isLoading={isSubmitting} onClick={() => handlePopUpToggle("identityAuthMethod", false)}
isDisabled={isSubmitting}
onClick={() => popup.handlePopUpToggle("overwriteAuthMethod", true)}
> >
Overwrite Cancel
</Button> </Button>
: <Button </div>
className="mr-4" {isCurrentAuthMethod && (
<Button
size="sm" size="sm"
type="submit" colorSchema="danger"
isLoading={isSubmitting} isLoading={isSubmitting}
isDisabled={isSubmitting} isDisabled={isSubmitting}
>Submit</Button> onClick={() => handlePopUpToggle("revokeAuthMethod", true)}
} >
<Button Remove Auth Method
colorSchema="secondary" </Button>
variant="plain" )}
onClick={() => handlePopUpToggle("identityAuthMethod", false)}
>
Cancel
</Button>
</div> </div>
{identityAuthMethodData?.authMethod === initialAuthMethod && ( </form>
<Button
size="sm"
colorSchema="danger"
isLoading={isSubmitting}
isDisabled={isSubmitting}
onClick={() => handlePopUpToggle("revokeAuthMethod", true)}
>
Remove Auth Method
</Button>
)}
</div>
<DeleteActionModal <DeleteActionModal
isOpen={popup.popUp.overwriteAuthMethod?.isOpen} isOpen={internalPopUpState.popUp.overwriteAuthMethod?.isOpen}
title={`Are you sure want to overwrite ${ title={`Are you sure want to overwrite ${initialAuthMethod || "the auth method"} on ${
initialAuthMethod || "the auth method" identityAuthMethodData?.name ?? ""
} on ${identityAuthMethodData?.name ?? ""}?`} }?`}
onChange={(isOpen) => popup.handlePopUpToggle("overwriteAuthMethod", isOpen)} onChange={(isOpen) => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", isOpen)}
deleteKey="confirm" deleteKey="confirm"
onDeleteApproved={async () => { await revokeAuth(initialAuthMethod); handleSubmit(onFormSubmit)(); }} buttonText="Overwrite"
/> onDeleteApproved={async () => {
</form> await revokeAuth(initialAuthMethod);
handleSubmit(onFormSubmit)();
}}
/>
</>
); );
}; };
@@ -70,11 +70,12 @@ 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 popup = usePopUp([ const internalPopUpState = usePopUp(["overwriteAuthMethod"] as const);
"overwriteAuthMethod",
] as const);
const { const {
control, control,
@@ -172,8 +173,7 @@ export const IdentityAzureAuthForm = ({
handlePopUpToggle("identityAuthMethod", false); handlePopUpToggle("identityAuthMethod", false);
createNotification({ createNotification({
text: `Successfully ${identityAuthMethodData?.authMethod === initialAuthMethod ? "updated" : "configured" text: `Successfully ${isCurrentAuthMethod ? "updated" : "configured"} auth method`,
} auth method`,
type: "success" type: "success"
}); });
@@ -187,219 +187,225 @@ export const IdentityAzureAuthForm = ({
}; };
return ( return (
<form onSubmit={handleSubmit(onFormSubmit)}> <>
<Controller <form onSubmit={handleSubmit(onFormSubmit)}>
control={control} <Controller
defaultValue="2592000" control={control}
name="tenantId" defaultValue="2592000"
render={({ field, fieldState: { error } }) => ( name="tenantId"
<FormControl render={({ field, fieldState: { error } }) => (
label="Tenant ID" <FormControl
isError={Boolean(error)} label="Tenant ID"
errorText={error?.message} isError={Boolean(error)}
isRequired errorText={error?.message}
> isRequired
<Input {...field} placeholder="00000000-0000-0000-0000-000000000000" type="text" /> >
</FormControl> <Input {...field} placeholder="00000000-0000-0000-0000-000000000000" type="text" />
)} </FormControl>
/> )}
<Controller />
control={control} <Controller
name="resource" control={control}
render={({ field, fieldState: { error } }) => ( name="resource"
<FormControl render={({ field, fieldState: { error } }) => (
label="Resource / Audience" <FormControl
isError={Boolean(error)} label="Resource / Audience"
errorText={error?.message} isError={Boolean(error)}
> errorText={error?.message}
<Input {...field} placeholder="https://management.azure.com/" /> >
</FormControl> <Input {...field} placeholder="https://management.azure.com/" />
)} </FormControl>
/> )}
<Controller />
control={control} <Controller
name="allowedServicePrincipalIds" control={control}
render={({ field, fieldState: { error } }) => ( name="allowedServicePrincipalIds"
<FormControl render={({ field, fieldState: { error } }) => (
label="Allowed Service Principal IDs" <FormControl
isError={Boolean(error)} label="Allowed Service Principal IDs"
errorText={error?.message} isError={Boolean(error)}
> errorText={error?.message}
<Input {...field} placeholder="00000000-0000-0000-0000-000000000000, ..." /> >
</FormControl> <Input {...field} placeholder="00000000-0000-0000-0000-000000000000, ..." />
)} </FormControl>
/> )}
<Controller />
control={control} <Controller
defaultValue="2592000" control={control}
name="accessTokenTTL" defaultValue="2592000"
render={({ field, fieldState: { error } }) => ( name="accessTokenTTL"
<FormControl render={({ field, fieldState: { error } }) => (
label="Access Token TTL (seconds)" <FormControl
isError={Boolean(error)} label="Access Token TTL (seconds)"
errorText={error?.message} isError={Boolean(error)}
> errorText={error?.message}
<Input {...field} placeholder="2592000" type="number" min="1" step="1" /> >
</FormControl> <Input {...field} placeholder="2592000" type="number" min="1" step="1" />
)} </FormControl>
/> )}
<Controller />
control={control} <Controller
defaultValue="2592000" control={control}
name="accessTokenMaxTTL" defaultValue="2592000"
render={({ field, fieldState: { error } }) => ( name="accessTokenMaxTTL"
<FormControl render={({ field, fieldState: { error } }) => (
label="Access Token Max TTL (seconds)" <FormControl
isError={Boolean(error)} label="Access Token Max TTL (seconds)"
errorText={error?.message} isError={Boolean(error)}
> errorText={error?.message}
<Input {...field} placeholder="2592000" type="number" min="1" step="1" /> >
</FormControl> <Input {...field} placeholder="2592000" type="number" min="1" step="1" />
)} </FormControl>
/> )}
<Controller />
control={control} <Controller
defaultValue="0" control={control}
name="accessTokenNumUsesLimit" defaultValue="0"
render={({ field, fieldState: { error } }) => ( name="accessTokenNumUsesLimit"
<FormControl render={({ field, fieldState: { error } }) => (
label="Access Token Max Number of Uses" <FormControl
isError={Boolean(error)} label="Access Token Max Number of Uses"
errorText={error?.message} isError={Boolean(error)}
> errorText={error?.message}
<Input {...field} placeholder="0" type="number" min="0" step="1" /> >
</FormControl> <Input {...field} placeholder="0" type="number" min="0" step="1" />
)} </FormControl>
/> )}
{accessTokenTrustedIpsFields.map(({ id }, index) => ( />
<div className="mb-3 flex items-end space-x-2" key={id}> {accessTokenTrustedIpsFields.map(({ id }, index) => (
<Controller <div className="mb-3 flex items-end space-x-2" key={id}>
control={control} <Controller
name={`accessTokenTrustedIps.${index}.ipAddress`} control={control}
defaultValue="0.0.0.0/0" name={`accessTokenTrustedIps.${index}.ipAddress`}
render={({ field, fieldState: { error } }) => { defaultValue="0.0.0.0/0"
return ( render={({ field, fieldState: { error } }) => {
<FormControl return (
className="mb-0 flex-grow" <FormControl
label={index === 0 ? "Access Token Trusted IPs" : undefined} className="mb-0 flex-grow"
isError={Boolean(error)} label={index === 0 ? "Access Token Trusted IPs" : undefined}
errorText={error?.message} isError={Boolean(error)}
> errorText={error?.message}
<Input >
value={field.value} <Input
onChange={(e) => { value={field.value}
if (subscription?.ipAllowlisting) { onChange={(e) => {
field.onChange(e); if (subscription?.ipAllowlisting) {
return; field.onChange(e);
} return;
}
handlePopUpOpen("upgradePlan"); handlePopUpOpen("upgradePlan");
}} }}
placeholder="123.456.789.0" placeholder="123.456.789.0"
/> />
</FormControl> </FormControl>
); );
}} }}
/> />
<IconButton <IconButton
onClick={() => {
if (subscription?.ipAllowlisting) {
removeAccessTokenTrustedIp(index);
return;
}
handlePopUpOpen("upgradePlan");
}}
size="lg"
colorSchema="danger"
variant="plain"
ariaLabel="update"
className="p-3"
>
<FontAwesomeIcon icon={faXmark} />
</IconButton>
</div>
))}
<div className="my-4 ml-1">
<Button
variant="outline_bg"
onClick={() => { onClick={() => {
if (subscription?.ipAllowlisting) { if (subscription?.ipAllowlisting) {
removeAccessTokenTrustedIp(index); appendAccessTokenTrustedIp({
ipAddress: "0.0.0.0/0"
});
return; return;
} }
handlePopUpOpen("upgradePlan"); handlePopUpOpen("upgradePlan");
}} }}
size="lg" leftIcon={<FontAwesomeIcon icon={faPlus} />}
colorSchema="danger" size="xs"
variant="plain"
ariaLabel="update"
className="p-3"
> >
<FontAwesomeIcon icon={faXmark} /> Add IP Address
</IconButton> </Button>
</div> </div>
))} <div className="flex justify-between">
<div className="my-4 ml-1"> <div className="flex items-center">
<Button {initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod ? (
variant="outline_bg" <Button
onClick={() => { className="mr-4"
if (subscription?.ipAllowlisting) { size="sm"
appendAccessTokenTrustedIp({ isLoading={isSubmitting}
ipAddress: "0.0.0.0/0" isDisabled={isSubmitting}
}); onClick={() => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", true)}
return; >
} Overwrite
</Button>
handlePopUpOpen("upgradePlan"); ) : (
}} <Button
leftIcon={<FontAwesomeIcon icon={faPlus} />} className="mr-4"
size="xs" size="sm"
> type="submit"
Add IP Address isLoading={isSubmitting}
</Button> isDisabled={isSubmitting}
</div> >
<div className="flex justify-between"> Submit
<div className="flex items-center"> </Button>
{(initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod) ? )}
<Button <Button
className="mr-4" colorSchema="secondary"
size="sm" variant="plain"
isLoading={isSubmitting} onClick={() => handlePopUpToggle("identityAuthMethod", false)}
isDisabled={isSubmitting} >
onClick={() => popup.handlePopUpToggle("overwriteAuthMethod", true)}> Cancel
Overwrite
</Button> </Button>
: <Button </div>
className="mr-4" {isCurrentAuthMethod && (
<Button
size="sm" size="sm"
type="submit" colorSchema="danger"
isLoading={isSubmitting} isLoading={isSubmitting}
isDisabled={isSubmitting} isDisabled={isSubmitting}
>Submit</Button> onClick={() => handlePopUpToggle("revokeAuthMethod", true)}
} >
<Button Remove Auth Method
colorSchema="secondary" </Button>
variant="plain" )}
onClick={() => handlePopUpToggle("identityAuthMethod", false)}
>
Cancel
</Button>
</div> </div>
{identityAuthMethodData?.authMethod === initialAuthMethod && ( </form>
<Button
size="sm"
colorSchema="danger"
isLoading={isSubmitting}
isDisabled={isSubmitting}
onClick={() => handlePopUpToggle("revokeAuthMethod", true)}
>
Remove Auth Method
</Button>
)}
</div>
<DeleteActionModal <DeleteActionModal
isOpen={popup.popUp.overwriteAuthMethod?.isOpen} isOpen={internalPopUpState.popUp.overwriteAuthMethod?.isOpen}
title={`Are you sure want to overwrite ${ title={`Are you sure want to overwrite ${initialAuthMethod || "the auth method"} on ${
initialAuthMethod || "the auth method" identityAuthMethodData?.name ?? ""
} on ${identityAuthMethodData?.name ?? ""}?`} }?`}
onChange={(isOpen) => popup.handlePopUpToggle("overwriteAuthMethod", isOpen)} onChange={(isOpen) => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", isOpen)}
deleteKey="confirm" deleteKey="confirm"
onDeleteApproved={async () => { buttonText="Overwrite"
const result = await trigger(); onDeleteApproved={async () => {
if(result){ const result = await trigger();
await revokeAuth(initialAuthMethod); if (result) {
handleSubmit(onFormSubmit)(); await revokeAuth(initialAuthMethod);
}else{ handleSubmit(onFormSubmit)();
createNotification({ } else {
text: "Please fill in all required fields", createNotification({
type: "error" text: "Please fill in all required fields",
}); type: "error"
popup.handlePopUpToggle("overwriteAuthMethod", false); });
} internalPopUpState.handlePopUpToggle("overwriteAuthMethod", false);
}} }
/> }}
/>
</form> </>
); );
}; };
@@ -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, 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 { useOrganization, useSubscription } from "@app/context";
import { import {
useAddIdentityGcpAuth, useAddIdentityGcpAuth,
@@ -71,17 +79,18 @@ 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 popup = usePopUp([ const { data } = useGetIdentityGcpAuth(identityAuthMethodData?.identityId ?? "", {
"overwriteAuthMethod", enabled: isCurrentAuthMethod
] as const); });
const internalPopUpState = usePopUp(["overwriteAuthMethod"] as const);
const { const {
control, control,
handleSubmit, handleSubmit,
reset, reset,
formState: { isSubmitting }, formState: { isSubmitting },
watch, watch
} = useForm<FormData>({ } = useForm<FormData>({
resolver: zodResolver(schema), resolver: zodResolver(schema),
defaultValues: { defaultValues: {
@@ -180,12 +189,10 @@ export const IdentityGcpAuthForm = ({
handlePopUpToggle("identityAuthMethod", false); handlePopUpToggle("identityAuthMethod", false);
createNotification({ createNotification({
text: `Successfully ${identityAuthMethodData?.authMethod === initialAuthMethod ? "updated" : "configured" text: `Successfully ${isCurrentAuthMethod ? "updated" : "configured"} auth method`,
} auth method`,
type: "success" type: "success"
}); });
reset(); reset();
} catch (err) { } catch (err) {
createNotification({ createNotification({
@@ -196,231 +203,244 @@ export const IdentityGcpAuthForm = ({
}; };
return ( return (
<form onSubmit={handleSubmit(onFormSubmit)}> <>
<Controller <form onSubmit={handleSubmit(onFormSubmit)}>
control={control}
name="type"
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
<FormControl label="Type" isError={Boolean(error)} errorText={error?.message}>
<Select
defaultValue={field.value}
{...field}
onValueChange={(e) => onChange(e)}
className="w-full"
>
<SelectItem value="gce" key="gce">
GCP ID Token Auth (Recommended)
</SelectItem>
<SelectItem value="iam" key="iam">
GCP IAM Auth
</SelectItem>
</Select>
</FormControl>
)}
/>
<Controller
control={control}
defaultValue="2592000"
name="allowedServiceAccounts"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Allowed Service Account Emails"
isError={Boolean(error)}
errorText={error?.message}
>
<Input
{...field}
placeholder="[email protected], [email protected]"
type="text"
/>
</FormControl>
)}
/>
{watchedType === "gce" && (
<Controller <Controller
control={control} control={control}
name="allowedProjects" name="type"
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
<FormControl label="Type" isError={Boolean(error)} errorText={error?.message}>
<Select
defaultValue={field.value}
{...field}
onValueChange={(e) => onChange(e)}
className="w-full"
>
<SelectItem value="gce" key="gce">
GCP ID Token Auth (Recommended)
</SelectItem>
<SelectItem value="iam" key="iam">
GCP IAM Auth
</SelectItem>
</Select>
</FormControl>
)}
/>
<Controller
control={control}
defaultValue="2592000"
name="allowedServiceAccounts"
render={({ field, fieldState: { error } }) => ( render={({ field, fieldState: { error } }) => (
<FormControl <FormControl
label="Allowed Projects" label="Allowed Service Account Emails"
isError={Boolean(error)} isError={Boolean(error)}
errorText={error?.message} errorText={error?.message}
> >
<Input {...field} placeholder="my-gcp-project, ..." /> <Input
{...field}
placeholder="[email protected], [email protected]"
type="text"
/>
</FormControl> </FormControl>
)} )}
/> />
)} {watchedType === "gce" && (
{watchedType === "gce" && (
<Controller
control={control}
name="allowedZones"
render={({ field, fieldState: { error } }) => (
<FormControl label="Allowed Zones" isError={Boolean(error)} errorText={error?.message}>
<Input {...field} placeholder="us-west2-a, us-central1-a, ..." />
</FormControl>
)}
/>
)}
<Controller
control={control}
defaultValue="2592000"
name="accessTokenTTL"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Access Token TTL (seconds)"
isError={Boolean(error)}
errorText={error?.message}
>
<Input {...field} placeholder="2592000" type="number" min="1" step="1" />
</FormControl>
)}
/>
<Controller
control={control}
defaultValue="2592000"
name="accessTokenMaxTTL"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Access Token Max TTL (seconds)"
isError={Boolean(error)}
errorText={error?.message}
>
<Input {...field} placeholder="2592000" type="number" min="1" step="1" />
</FormControl>
)}
/>
<Controller
control={control}
defaultValue="0"
name="accessTokenNumUsesLimit"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Access Token Max Number of Uses"
isError={Boolean(error)}
errorText={error?.message}
>
<Input {...field} placeholder="0" type="number" min="0" step="1" />
</FormControl>
)}
/>
{accessTokenTrustedIpsFields.map(({ id }, index) => (
<div className="mb-3 flex items-end space-x-2" key={id}>
<Controller <Controller
control={control} control={control}
name={`accessTokenTrustedIps.${index}.ipAddress`} name="allowedProjects"
defaultValue="0.0.0.0/0" render={({ field, fieldState: { error } }) => (
render={({ field, fieldState: { error } }) => { <FormControl
return ( label="Allowed Projects"
<FormControl isError={Boolean(error)}
className="mb-0 flex-grow" errorText={error?.message}
label={index === 0 ? "Access Token Trusted IPs" : undefined} >
isError={Boolean(error)} <Input {...field} placeholder="my-gcp-project, ..." />
errorText={error?.message} </FormControl>
> )}
<Input
value={field.value}
onChange={(e) => {
if (subscription?.ipAllowlisting) {
field.onChange(e);
return;
}
handlePopUpOpen("upgradePlan");
}}
placeholder="123.456.789.0"
/>
</FormControl>
);
}}
/> />
<IconButton )}
{watchedType === "gce" && (
<Controller
control={control}
name="allowedZones"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Allowed Zones"
isError={Boolean(error)}
errorText={error?.message}
>
<Input {...field} placeholder="us-west2-a, us-central1-a, ..." />
</FormControl>
)}
/>
)}
<Controller
control={control}
defaultValue="2592000"
name="accessTokenTTL"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Access Token TTL (seconds)"
isError={Boolean(error)}
errorText={error?.message}
>
<Input {...field} placeholder="2592000" type="number" min="1" step="1" />
</FormControl>
)}
/>
<Controller
control={control}
defaultValue="2592000"
name="accessTokenMaxTTL"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Access Token Max TTL (seconds)"
isError={Boolean(error)}
errorText={error?.message}
>
<Input {...field} placeholder="2592000" type="number" min="1" step="1" />
</FormControl>
)}
/>
<Controller
control={control}
defaultValue="0"
name="accessTokenNumUsesLimit"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Access Token Max Number of Uses"
isError={Boolean(error)}
errorText={error?.message}
>
<Input {...field} placeholder="0" type="number" min="0" step="1" />
</FormControl>
)}
/>
{accessTokenTrustedIpsFields.map(({ id }, index) => (
<div className="mb-3 flex items-end space-x-2" key={id}>
<Controller
control={control}
name={`accessTokenTrustedIps.${index}.ipAddress`}
defaultValue="0.0.0.0/0"
render={({ field, fieldState: { error } }) => {
return (
<FormControl
className="mb-0 flex-grow"
label={index === 0 ? "Access Token Trusted IPs" : undefined}
isError={Boolean(error)}
errorText={error?.message}
>
<Input
value={field.value}
onChange={(e) => {
if (subscription?.ipAllowlisting) {
field.onChange(e);
return;
}
handlePopUpOpen("upgradePlan");
}}
placeholder="123.456.789.0"
/>
</FormControl>
);
}}
/>
<IconButton
onClick={() => {
if (subscription?.ipAllowlisting) {
removeAccessTokenTrustedIp(index);
return;
}
handlePopUpOpen("upgradePlan");
}}
size="lg"
colorSchema="danger"
variant="plain"
ariaLabel="update"
className="p-3"
>
<FontAwesomeIcon icon={faXmark} />
</IconButton>
</div>
))}
<div className="my-4 ml-1">
<Button
variant="outline_bg"
onClick={() => { onClick={() => {
if (subscription?.ipAllowlisting) { if (subscription?.ipAllowlisting) {
removeAccessTokenTrustedIp(index); appendAccessTokenTrustedIp({
ipAddress: "0.0.0.0/0"
});
return; return;
} }
handlePopUpOpen("upgradePlan"); handlePopUpOpen("upgradePlan");
}} }}
size="lg" leftIcon={<FontAwesomeIcon icon={faPlus} />}
colorSchema="danger" size="xs"
variant="plain"
ariaLabel="update"
className="p-3"
> >
<FontAwesomeIcon icon={faXmark} /> Add IP Address
</IconButton> </Button>
</div> </div>
))} <div className="flex justify-between">
<div className="my-4 ml-1"> <div className="flex items-center">
<Button {initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod ? (
variant="outline_bg" <Button
onClick={() => { className="mr-4"
if (subscription?.ipAllowlisting) { size="sm"
appendAccessTokenTrustedIp({ isLoading={isSubmitting}
ipAddress: "0.0.0.0/0" isDisabled={isSubmitting}
}); onClick={() => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", true)}
return; >
} Overwrite
</Button>
handlePopUpOpen("upgradePlan"); ) : (
}} <Button
leftIcon={<FontAwesomeIcon icon={faPlus} />} className="mr-4"
size="xs" size="sm"
> type="submit"
Add IP Address isLoading={isSubmitting}
</Button> isDisabled={isSubmitting}
</div> >
<div className="flex justify-between"> Submit
<div className="flex items-center"> </Button>
{(initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod) ? )}
<Button <Button
className="mr-4" colorSchema="secondary"
size="sm" variant="plain"
isLoading={isSubmitting} onClick={() => handlePopUpToggle("identityAuthMethod", false)}
isDisabled={isSubmitting}
onClick={() => popup.handlePopUpToggle("overwriteAuthMethod", true)}
> >
Overwrite Cancel
</Button> </Button>
: <Button </div>
className="mr-4" {isCurrentAuthMethod && (
<Button
size="sm" size="sm"
type="submit" colorSchema="danger"
isLoading={isSubmitting} isLoading={isSubmitting}
isDisabled={isSubmitting} isDisabled={isSubmitting}
>Submit</Button> onClick={() => handlePopUpToggle("revokeAuthMethod", true)}
} >
<Button Remove Auth Method
colorSchema="secondary" </Button>
variant="plain" )}
onClick={() => handlePopUpToggle("identityAuthMethod", false)}
>
Cancel
</Button>
</div> </div>
{identityAuthMethodData?.authMethod === initialAuthMethod && ( </form>
<Button
size="sm"
colorSchema="danger"
isLoading={isSubmitting}
isDisabled={isSubmitting}
onClick={() => handlePopUpToggle("revokeAuthMethod", true)}
>
Remove Auth Method
</Button>
)}
</div>
<DeleteActionModal <DeleteActionModal
isOpen={popup.popUp.overwriteAuthMethod?.isOpen} isOpen={internalPopUpState.popUp.overwriteAuthMethod?.isOpen}
title={`Are you sure want to overwrite ${ title={`Are you sure want to overwrite ${initialAuthMethod || "the auth method"} on ${
initialAuthMethod || "the auth method" identityAuthMethodData?.name ?? ""
} on ${identityAuthMethodData?.name ?? ""}?`} }?`}
onChange={(isOpen) => popup.handlePopUpToggle("overwriteAuthMethod", isOpen)} buttonText="Overwrite"
deleteKey="confirm" onChange={(isOpen) => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", isOpen)}
onDeleteApproved={async () => { await revokeAuth(initialAuthMethod); handleSubmit(onFormSubmit)(); }} deleteKey="confirm"
/> onDeleteApproved={async () => {
</form> 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, 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 { useOrganization, useSubscription } from "@app/context";
import { import {
useAddIdentityKubernetesAuth, useAddIdentityKubernetesAuth,
@@ -73,17 +80,18 @@ 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 popup = usePopUp([ const { data } = useGetIdentityKubernetesAuth(identityAuthMethodData?.identityId ?? "", {
"overwriteAuthMethod", enabled: isCurrentAuthMethod
] as const); });
const internalPopUpState = usePopUp(["overwriteAuthMethod"] as const);
const { const {
control, control,
handleSubmit, handleSubmit,
reset, reset,
trigger, trigger,
formState: { isSubmitting }, formState: { isSubmitting }
} = useForm<FormData>({ } = useForm<FormData>({
resolver: zodResolver(schema), resolver: zodResolver(schema),
defaultValues: { defaultValues: {
@@ -192,8 +200,7 @@ export const IdentityKubernetesAuthForm = ({
handlePopUpToggle("identityAuthMethod", false); handlePopUpToggle("identityAuthMethod", false);
createNotification({ createNotification({
text: `Successfully ${identityAuthMethodData?.authMethod === initialAuthMethod ? "updated" : "configured" text: `Successfully ${isCurrentAuthMethod ? "updated" : "configured"} auth method`,
} auth method`,
type: "success" type: "success"
}); });
@@ -207,269 +214,277 @@ export const IdentityKubernetesAuthForm = ({
}; };
return ( return (
<form onSubmit={handleSubmit(onFormSubmit)}> <>
<Controller <form onSubmit={handleSubmit(onFormSubmit)}>
control={control} <Controller
defaultValue="2592000" control={control}
name="kubernetesHost" defaultValue="2592000"
render={({ field, fieldState: { error } }) => ( name="kubernetesHost"
<FormControl render={({ field, fieldState: { error } }) => (
label="Kubernetes Host / Base Kubernetes API URL " <FormControl
isError={Boolean(error)} label="Kubernetes Host / Base Kubernetes API URL "
errorText={error?.message} isError={Boolean(error)}
tooltipText="The host string, host:port pair, or URL to the base of the Kubernetes API server. This can usually be obtained by running 'kubectl cluster-info'" errorText={error?.message}
isRequired tooltipText="The host string, host:port pair, or URL to the base of the Kubernetes API server. This can usually be obtained by running 'kubectl cluster-info'"
> isRequired
<Input {...field} placeholder="https://my-example-k8s-api-host.com" type="text" />
</FormControl>
)}
/>
<Controller
control={control}
name="tokenReviewerJwt"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Token Reviewer JWT"
isError={Boolean(error)}
errorText={error?.message}
tooltipText="A long-lived service account JWT token for Infisical to access the TokenReview API to validate other service account JWT tokens submitted by applications/pods."
isRequired
>
<Input {...field} placeholder="" type="password" />
</FormControl>
)}
/>
<Controller
control={control}
name="allowedNames"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Allowed Service Account Names"
isError={Boolean(error)}
tooltipText="An optional comma-separated list of trusted service account names that are allowed to authenticate with Infisical. Leave empty to allow any service account."
errorText={error?.message}
>
<Input {...field} placeholder="service-account-1-name, service-account-1-name" />
</FormControl>
)}
/>
<Controller
control={control}
defaultValue=""
name="allowedNamespaces"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Allowed Namespaces"
isError={Boolean(error)}
errorText={error?.message}
tooltipText="An optional comma-separated list of trusted service account names that are allowed to authenticate with Infisical. Leave empty to allow any namespaces."
>
<Input {...field} placeholder="namespaceA, namespaceB" type="text" />
</FormControl>
)}
/>
<Controller
control={control}
defaultValue=""
name="allowedAudience"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Allowed Audience"
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."
> >
<Input {...field} placeholder="" type="text" /> <Input {...field} placeholder="https://my-example-k8s-api-host.com" type="text" />
</FormControl> </FormControl>
)} )}
/> />
<Controller <Controller
control={control} control={control}
name="caCert" name="tokenReviewerJwt"
render={({ field, fieldState: { error } }) => ( render={({ field, fieldState: { error } }) => (
<FormControl <FormControl
label="CA Certificate" label="Token Reviewer JWT"
errorText={error?.message} isError={Boolean(error)} 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." errorText={error?.message}
> tooltipText="A long-lived service account JWT token for Infisical to access the TokenReview API to validate other service account JWT tokens submitted by applications/pods."
<TextArea {...field} placeholder="-----BEGIN CERTIFICATE----- ..." /> isRequired
</FormControl> >
)} <Input {...field} placeholder="" type="password" />
/> </FormControl>
<Controller )}
control={control} />
defaultValue="2592000" <Controller
name="accessTokenTTL" control={control}
render={({ field, fieldState: { error } }) => ( name="allowedNames"
<FormControl render={({ field, fieldState: { error } }) => (
label="Access Token TTL (seconds)" <FormControl
tooltipText="The lifetime for an acccess token in seconds. This value will be referenced at renewal time." label="Allowed Service Account Names"
isError={Boolean(error)} isError={Boolean(error)}
errorText={error?.message} tooltipText="An optional comma-separated list of trusted service account names that are allowed to authenticate with Infisical. Leave empty to allow any service account."
> errorText={error?.message}
<Input {...field} placeholder="2592000" type="number" min="1" step="1" /> >
</FormControl> <Input {...field} placeholder="service-account-1-name, service-account-1-name" />
)} </FormControl>
/> )}
<Controller />
control={control} <Controller
defaultValue="2592000" control={control}
name="accessTokenMaxTTL" defaultValue=""
render={({ field, fieldState: { error } }) => ( name="allowedNamespaces"
<FormControl render={({ field, fieldState: { error } }) => (
label="Access Token Max TTL (seconds)" <FormControl
isError={Boolean(error)} label="Allowed Namespaces"
errorText={error?.message} isError={Boolean(error)}
tooltipText="The maximum lifetime for an access token in seconds. This value will be referenced at renewal time." errorText={error?.message}
> tooltipText="An optional comma-separated list of trusted service account names that are allowed to authenticate with Infisical. Leave empty to allow any namespaces."
<Input {...field} placeholder="2592000" type="number" min="1" step="1" /> >
</FormControl> <Input {...field} placeholder="namespaceA, namespaceB" type="text" />
)} </FormControl>
/> )}
<Controller />
control={control} <Controller
defaultValue="0" control={control}
name="accessTokenNumUsesLimit" defaultValue=""
render={({ field, fieldState: { error } }) => ( name="allowedAudience"
<FormControl render={({ field, fieldState: { error } }) => (
label="Access Token Max Number of Uses" <FormControl
isError={Boolean(error)} label="Allowed Audience"
errorText={error?.message} isError={Boolean(error)}
tooltipText="The maximum number of times that an access token can be used; a value of 0 implies infinite number of uses." 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."
<Input {...field} placeholder="0" type="number" min="0" step="1" /> >
</FormControl> <Input {...field} placeholder="" type="text" />
)} </FormControl>
/> )}
{accessTokenTrustedIpsFields.map(({ id }, index) => ( />
<div className="mb-3 flex items-end space-x-2" key={id}> <Controller
<Controller control={control}
control={control} name="caCert"
name={`accessTokenTrustedIps.${index}.ipAddress`} render={({ field, fieldState: { error } }) => (
defaultValue="0.0.0.0/0" <FormControl
render={({ field, fieldState: { error } }) => { label="CA Certificate"
return ( errorText={error?.message}
<FormControl isError={Boolean(error)}
className="mb-0 flex-grow" 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."
label={index === 0 ? "Access Token Trusted IPs" : undefined} >
isError={Boolean(error)} <TextArea {...field} placeholder="-----BEGIN CERTIFICATE----- ..." />
errorText={error?.message} </FormControl>
tooltipText="The IPs or CIDR ranges that access tokens can be used from. By default, each token is given the 0.0.0.0/0, allowing usage from any network address." )}
> />
<Input <Controller
value={field.value} control={control}
onChange={(e) => { defaultValue="2592000"
if (subscription?.ipAllowlisting) { name="accessTokenTTL"
field.onChange(e); render={({ field, fieldState: { error } }) => (
return; <FormControl
} label="Access Token TTL (seconds)"
tooltipText="The lifetime for an acccess token in seconds. This value will be referenced at renewal time."
isError={Boolean(error)}
errorText={error?.message}
>
<Input {...field} placeholder="2592000" type="number" min="1" step="1" />
</FormControl>
)}
/>
<Controller
control={control}
defaultValue="2592000"
name="accessTokenMaxTTL"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Access Token Max TTL (seconds)"
isError={Boolean(error)}
errorText={error?.message}
tooltipText="The maximum lifetime for an access token in seconds. This value will be referenced at renewal time."
>
<Input {...field} placeholder="2592000" type="number" min="1" step="1" />
</FormControl>
)}
/>
<Controller
control={control}
defaultValue="0"
name="accessTokenNumUsesLimit"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Access Token Max Number of Uses"
isError={Boolean(error)}
errorText={error?.message}
tooltipText="The maximum number of times that an access token can be used; a value of 0 implies infinite number of uses."
>
<Input {...field} placeholder="0" type="number" min="0" step="1" />
</FormControl>
)}
/>
{accessTokenTrustedIpsFields.map(({ id }, index) => (
<div className="mb-3 flex items-end space-x-2" key={id}>
<Controller
control={control}
name={`accessTokenTrustedIps.${index}.ipAddress`}
defaultValue="0.0.0.0/0"
render={({ field, fieldState: { error } }) => {
return (
<FormControl
className="mb-0 flex-grow"
label={index === 0 ? "Access Token Trusted IPs" : undefined}
isError={Boolean(error)}
errorText={error?.message}
tooltipText="The IPs or CIDR ranges that access tokens can be used from. By default, each token is given the 0.0.0.0/0, allowing usage from any network address."
>
<Input
value={field.value}
onChange={(e) => {
if (subscription?.ipAllowlisting) {
field.onChange(e);
return;
}
handlePopUpOpen("upgradePlan"); handlePopUpOpen("upgradePlan");
}} }}
placeholder="123.456.789.0" placeholder="123.456.789.0"
/> />
</FormControl> </FormControl>
); );
}} }}
/> />
<IconButton <IconButton
onClick={() => {
if (subscription?.ipAllowlisting) {
removeAccessTokenTrustedIp(index);
return;
}
handlePopUpOpen("upgradePlan");
}}
size="lg"
colorSchema="danger"
variant="plain"
ariaLabel="update"
className="p-3"
>
<FontAwesomeIcon icon={faXmark} />
</IconButton>
</div>
))}
<div className="my-4 ml-1">
<Button
variant="outline_bg"
onClick={() => { onClick={() => {
if (subscription?.ipAllowlisting) { if (subscription?.ipAllowlisting) {
removeAccessTokenTrustedIp(index); appendAccessTokenTrustedIp({
ipAddress: "0.0.0.0/0"
});
return; return;
} }
handlePopUpOpen("upgradePlan"); handlePopUpOpen("upgradePlan");
}} }}
size="lg" leftIcon={<FontAwesomeIcon icon={faPlus} />}
colorSchema="danger" size="xs"
variant="plain"
ariaLabel="update"
className="p-3"
> >
<FontAwesomeIcon icon={faXmark} /> Add IP Address
</IconButton> </Button>
</div> </div>
))} <div className="flex justify-between">
<div className="my-4 ml-1"> <div className="flex items-center">
<Button {initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod ? (
variant="outline_bg" <Button
onClick={() => { className="mr-4"
if (subscription?.ipAllowlisting) { size="sm"
appendAccessTokenTrustedIp({ isLoading={isSubmitting}
ipAddress: "0.0.0.0/0" isDisabled={isSubmitting}
}); onClick={() => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", true)}
return; >
} Overwrite
</Button>
handlePopUpOpen("upgradePlan"); ) : (
}} <Button
leftIcon={<FontAwesomeIcon icon={faPlus} />} className="mr-4"
size="xs" size="sm"
> type="submit"
Add IP Address isLoading={isSubmitting}
</Button> isDisabled={isSubmitting}
</div> >
<div className="flex justify-between"> Submit
<div className="flex items-center"> </Button>
{(initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod) ? )}
<Button <Button
className="mr-4" colorSchema="secondary"
size="sm" variant="plain"
isLoading={isSubmitting} onClick={() => handlePopUpToggle("identityAuthMethod", false)}
isDisabled={isSubmitting}
onClick={() => popup.handlePopUpToggle("overwriteAuthMethod", true)}
> >
Overwrite Cancel
</Button> </Button>
: <Button </div>
className="mr-4" {isCurrentAuthMethod && (
<Button
size="sm" size="sm"
type="submit" colorSchema="danger"
isLoading={isSubmitting} isLoading={isSubmitting}
isDisabled={isSubmitting} isDisabled={isSubmitting}
>Submit</Button> onClick={() => handlePopUpToggle("revokeAuthMethod", true)}
} >
<Button Remove Auth Method
colorSchema="secondary" </Button>
variant="plain" )}
onClick={() => handlePopUpToggle("identityAuthMethod", false)}
>
Cancel
</Button>
</div> </div>
{identityAuthMethodData?.authMethod === initialAuthMethod && ( </form>
<Button
size="sm"
colorSchema="danger"
isLoading={isSubmitting}
isDisabled={isSubmitting}
onClick={() => handlePopUpToggle("revokeAuthMethod", true)}
>
Remove Auth Method
</Button>
)}
</div>
<DeleteActionModal <DeleteActionModal
isOpen={popup.popUp.overwriteAuthMethod?.isOpen} isOpen={internalPopUpState.popUp.overwriteAuthMethod?.isOpen}
title={`Are you sure want to overwrite ${ title={`Are you sure want to overwrite ${initialAuthMethod || "the auth method"} on ${
initialAuthMethod || "the auth method" identityAuthMethodData?.name ?? ""
} on ${identityAuthMethodData?.name ?? ""}?`} }?`}
onChange={(isOpen) => popup.handlePopUpToggle("overwriteAuthMethod", isOpen)} onChange={(isOpen) => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", isOpen)}
deleteKey="confirm" deleteKey="confirm"
onDeleteApproved={async () => { buttonText="Overwrite"
const result = await trigger(); onDeleteApproved={async () => {
if(result){ const result = await trigger();
await revokeAuth(initialAuthMethod); if (result) {
handleSubmit(onFormSubmit)(); await revokeAuth(initialAuthMethod);
}else{ handleSubmit(onFormSubmit)();
createNotification({ } else {
text: "Please fill in all required fields", createNotification({
type: "error" text: "Please fill in all required fields",
}); type: "error"
popup.handlePopUpToggle("overwriteAuthMethod", false); });
} internalPopUpState.handlePopUpToggle("overwriteAuthMethod", false);
}} }
/> }}
</form> />
</>
); );
}; };
@@ -7,7 +7,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, DeleteActionModal,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";
@@ -74,10 +82,11 @@ 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 popup = usePopUp([ const { data } = useGetIdentityOidcAuth(identityAuthMethodData?.identityId ?? "", {
"overwriteAuthMethod", enabled: isCurrentAuthMethod
] as const); });
const internalPopUpState = usePopUp(["overwriteAuthMethod"] as const);
const { const {
control, control,
@@ -201,8 +210,7 @@ export const IdentityOidcAuthForm = ({
handlePopUpToggle("identityAuthMethod", false); handlePopUpToggle("identityAuthMethod", false);
createNotification({ createNotification({
text: `Successfully ${identityAuthMethodData?.authMethod === initialAuthMethod ? "updated" : "configured" text: `Successfully ${isCurrentAuthMethod ? "updated" : "configured"} auth method`,
} auth method`,
type: "success" type: "success"
}); });
@@ -216,344 +224,350 @@ export const IdentityOidcAuthForm = ({
}; };
return ( return (
<form onSubmit={handleSubmit(onFormSubmit)}> <>
<Controller <form onSubmit={handleSubmit(onFormSubmit)}>
control={control} <Controller
name="oidcDiscoveryUrl" control={control}
render={({ field, fieldState: { error } }) => ( name="oidcDiscoveryUrl"
<FormControl render={({ field, fieldState: { error } }) => (
isRequired <FormControl
label="OIDC Discovery URL" isRequired
isError={Boolean(error)} label="OIDC Discovery URL"
errorText={error?.message} isError={Boolean(error)}
> errorText={error?.message}
<Input >
{...field} <Input
placeholder="https://token.actions.githubusercontent.com" {...field}
type="text" placeholder="https://token.actions.githubusercontent.com"
/> type="text"
</FormControl> />
)} </FormControl>
/> )}
<Controller />
control={control} <Controller
name="boundIssuer" control={control}
render={({ field, fieldState: { error } }) => ( name="boundIssuer"
<FormControl render={({ field, fieldState: { error } }) => (
isRequired <FormControl
label="Issuer" isRequired
isError={Boolean(error)} label="Issuer"
errorText={error?.message} isError={Boolean(error)}
> errorText={error?.message}
<Input >
{...field} <Input
type="text" {...field}
placeholder="https://token.actions.githubusercontent.com" type="text"
/> placeholder="https://token.actions.githubusercontent.com"
</FormControl> />
)} </FormControl>
/> )}
<Controller />
control={control} <Controller
name="caCert" control={control}
render={({ field, fieldState: { error } }) => ( name="caCert"
<FormControl label="CA Certificate" errorText={error?.message} isError={Boolean(error)}> render={({ field, fieldState: { error } }) => (
<TextArea {...field} placeholder="-----BEGIN CERTIFICATE----- ..." /> <FormControl label="CA Certificate" errorText={error?.message} isError={Boolean(error)}>
</FormControl> <TextArea {...field} placeholder="-----BEGIN CERTIFICATE----- ..." />
)} </FormControl>
/> )}
<Controller />
control={control} <Controller
name="boundSubject" control={control}
render={({ field, fieldState: { error } }) => ( name="boundSubject"
<FormControl render={({ field, fieldState: { error } }) => (
label="Subject" <FormControl
isError={Boolean(error)} label="Subject"
errorText={error?.message} isError={Boolean(error)}
icon={ errorText={error?.message}
<Tooltip icon={
className="text-center" <Tooltip
content={<span>This field supports glob patterns</span>} className="text-center"
> content={<span>This field supports glob patterns</span>}
<FontAwesomeIcon icon={faQuestionCircle} size="sm" />
</Tooltip>
}
>
<Input {...field} type="text" />
</FormControl>
)}
/>
<Controller
control={control}
name="boundAudiences"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Audiences"
isError={Boolean(error)}
errorText={error?.message}
icon={
<Tooltip
className="text-center"
content={<span>This field supports glob patterns</span>}
>
<FontAwesomeIcon icon={faQuestionCircle} size="sm" />
</Tooltip>
}
>
<Input {...field} type="text" placeholder="service1, service2" />
</FormControl>
)}
/>
{boundClaimsFields.map(({ id }, index) => (
<div className="mb-3 flex items-end space-x-2" key={id}>
<Controller
control={control}
name={`boundClaims.${index}.key`}
render={({ field, fieldState: { error } }) => {
return (
<FormControl
className="mb-0 flex-grow"
label={index === 0 ? "Claims" : undefined}
icon={
index === 0 ? (
<Tooltip
className="text-center"
content={<span>This field supports glob patterns</span>}
>
<FontAwesomeIcon icon={faQuestionCircle} size="sm" />
</Tooltip>
) : undefined
}
isError={Boolean(error)}
errorText={error?.message}
> >
<Input <FontAwesomeIcon icon={faQuestionCircle} size="sm" />
value={field.value} </Tooltip>
onChange={(e) => field.onChange(e)} }
placeholder="property" >
/> <Input {...field} type="text" />
</FormControl> </FormControl>
); )}
}} />
/> <Controller
<Controller control={control}
control={control} name="boundAudiences"
name={`boundClaims.${index}.value`} render={({ field, fieldState: { error } }) => (
render={({ field, fieldState: { error } }) => { <FormControl
return ( label="Audiences"
<FormControl isError={Boolean(error)}
className="mb-0 flex-grow" errorText={error?.message}
isError={Boolean(error)} icon={
errorText={error?.message} <Tooltip
className="text-center"
content={<span>This field supports glob patterns</span>}
> >
<Input <FontAwesomeIcon icon={faQuestionCircle} size="sm" />
value={field.value} </Tooltip>
onChange={(e) => field.onChange(e)} }
placeholder="value1, value2" >
/> <Input {...field} type="text" placeholder="service1, service2" />
</FormControl> </FormControl>
); )}
}} />
/> {boundClaimsFields.map(({ id }, index) => (
<div className="mb-3 flex items-end space-x-2" key={id}>
<Controller
control={control}
name={`boundClaims.${index}.key`}
render={({ field, fieldState: { error } }) => {
return (
<FormControl
className="mb-0 flex-grow"
label={index === 0 ? "Claims" : undefined}
icon={
index === 0 ? (
<Tooltip
className="text-center"
content={<span>This field supports glob patterns</span>}
>
<FontAwesomeIcon icon={faQuestionCircle} size="sm" />
</Tooltip>
) : undefined
}
isError={Boolean(error)}
errorText={error?.message}
>
<Input
value={field.value}
onChange={(e) => field.onChange(e)}
placeholder="property"
/>
</FormControl>
);
}}
/>
<Controller
control={control}
name={`boundClaims.${index}.value`}
render={({ field, fieldState: { error } }) => {
return (
<FormControl
className="mb-0 flex-grow"
isError={Boolean(error)}
errorText={error?.message}
>
<Input
value={field.value}
onChange={(e) => field.onChange(e)}
placeholder="value1, value2"
/>
</FormControl>
);
}}
/>
<IconButton <IconButton
onClick={() => removeBoundClaimField(index)} onClick={() => removeBoundClaimField(index)}
size="lg" size="lg"
colorSchema="danger" colorSchema="danger"
variant="plain" variant="plain"
ariaLabel="update" ariaLabel="update"
className="p-3" className="p-3"
>
<FontAwesomeIcon icon={faXmark} />
</IconButton>
</div>
))}
<div className="my-4 ml-1">
<Button
variant="outline_bg"
onClick={() =>
appendBoundClaimField({
key: "",
value: ""
})
}
leftIcon={<FontAwesomeIcon icon={faPlus} />}
size="xs"
> >
<FontAwesomeIcon icon={faXmark} /> Add Claims
</IconButton> </Button>
</div> </div>
))} <Controller
<div className="my-4 ml-1"> control={control}
<Button defaultValue="2592000"
variant="outline_bg" name="accessTokenTTL"
onClick={() => render={({ field, fieldState: { error } }) => (
appendBoundClaimField({ <FormControl
key: "", label="Access Token TTL (seconds)"
value: "" isError={Boolean(error)}
}) errorText={error?.message}
} >
leftIcon={<FontAwesomeIcon icon={faPlus} />} <Input {...field} placeholder="2592000" type="number" min="1" step="1" />
size="xs" </FormControl>
> )}
Add Claims />
</Button> <Controller
</div> control={control}
<Controller defaultValue="2592000"
control={control} name="accessTokenMaxTTL"
defaultValue="2592000" render={({ field, fieldState: { error } }) => (
name="accessTokenTTL" <FormControl
render={({ field, fieldState: { error } }) => ( label="Access Token Max TTL (seconds)"
<FormControl isError={Boolean(error)}
label="Access Token TTL (seconds)" errorText={error?.message}
isError={Boolean(error)} >
errorText={error?.message} <Input {...field} placeholder="2592000" type="number" min="1" step="1" />
> </FormControl>
<Input {...field} placeholder="2592000" type="number" min="1" step="1" /> )}
</FormControl> />
)} <Controller
/> control={control}
<Controller defaultValue="0"
control={control} name="accessTokenNumUsesLimit"
defaultValue="2592000" render={({ field, fieldState: { error } }) => (
name="accessTokenMaxTTL" <FormControl
render={({ field, fieldState: { error } }) => ( label="Access Token Max Number of Uses"
<FormControl isError={Boolean(error)}
label="Access Token Max TTL (seconds)" errorText={error?.message}
isError={Boolean(error)} >
errorText={error?.message} <Input {...field} placeholder="0" type="number" min="0" step="1" />
> </FormControl>
<Input {...field} placeholder="2592000" type="number" min="1" step="1" /> )}
</FormControl> />
)} {accessTokenTrustedIpsFields.map(({ id }, index) => (
/> <div className="mb-3 flex items-end space-x-2" key={id}>
<Controller <Controller
control={control} control={control}
defaultValue="0" name={`accessTokenTrustedIps.${index}.ipAddress`}
name="accessTokenNumUsesLimit" defaultValue="0.0.0.0/0"
render={({ field, fieldState: { error } }) => ( render={({ field, fieldState: { error } }) => {
<FormControl return (
label="Access Token Max Number of Uses" <FormControl
isError={Boolean(error)} className="mb-0 flex-grow"
errorText={error?.message} label={index === 0 ? "Access Token Trusted IPs" : undefined}
> isError={Boolean(error)}
<Input {...field} placeholder="0" type="number" min="0" step="1" /> errorText={error?.message}
</FormControl> >
)} <Input
/> value={field.value}
{accessTokenTrustedIpsFields.map(({ id }, index) => ( onChange={(e) => {
<div className="mb-3 flex items-end space-x-2" key={id}> if (subscription?.ipAllowlisting) {
<Controller field.onChange(e);
control={control} return;
name={`accessTokenTrustedIps.${index}.ipAddress`} }
defaultValue="0.0.0.0/0"
render={({ field, fieldState: { error } }) => {
return (
<FormControl
className="mb-0 flex-grow"
label={index === 0 ? "Access Token Trusted IPs" : undefined}
isError={Boolean(error)}
errorText={error?.message}
>
<Input
value={field.value}
onChange={(e) => {
if (subscription?.ipAllowlisting) {
field.onChange(e);
return;
}
handlePopUpOpen("upgradePlan"); handlePopUpOpen("upgradePlan");
}} }}
placeholder="123.456.789.0" placeholder="123.456.789.0"
/> />
</FormControl> </FormControl>
); );
}} }}
/> />
<IconButton <IconButton
onClick={() => {
if (subscription?.ipAllowlisting) {
removeAccessTokenTrustedIp(index);
return;
}
handlePopUpOpen("upgradePlan");
}}
size="lg"
colorSchema="danger"
variant="plain"
ariaLabel="update"
className="p-3"
>
<FontAwesomeIcon icon={faXmark} />
</IconButton>
</div>
))}
<div className="my-4 ml-1">
<Button
variant="outline_bg"
onClick={() => { onClick={() => {
if (subscription?.ipAllowlisting) { if (subscription?.ipAllowlisting) {
removeAccessTokenTrustedIp(index); appendAccessTokenTrustedIp({
ipAddress: "0.0.0.0/0"
});
return; return;
} }
handlePopUpOpen("upgradePlan"); handlePopUpOpen("upgradePlan");
}} }}
size="lg" leftIcon={<FontAwesomeIcon icon={faPlus} />}
colorSchema="danger" size="xs"
variant="plain"
ariaLabel="update"
className="p-3"
> >
<FontAwesomeIcon icon={faXmark} /> Add IP Address
</IconButton> </Button>
</div> </div>
))} <div className="flex justify-between">
<div className="my-4 ml-1"> <div className="flex items-center">
<Button {initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod ? (
variant="outline_bg" <Button
onClick={() => { className="mr-4"
if (subscription?.ipAllowlisting) { size="sm"
appendAccessTokenTrustedIp({ isLoading={isSubmitting}
ipAddress: "0.0.0.0/0" isDisabled={isSubmitting}
}); onClick={() => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", true)}
return; >
} Overwrite
</Button>
handlePopUpOpen("upgradePlan"); ) : (
}} <Button
leftIcon={<FontAwesomeIcon icon={faPlus} />} className="mr-4"
size="xs" size="sm"
> type="submit"
Add IP Address isLoading={isSubmitting}
</Button> isDisabled={isSubmitting}
</div> >
<div className="flex justify-between"> Submit
<div className="flex items-center"> </Button>
{(initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod) ? )}
<Button <Button
className="mr-4" colorSchema="secondary"
size="sm" variant="plain"
isLoading={isSubmitting} onClick={() => handlePopUpToggle("identityAuthMethod", false)}
isDisabled={isSubmitting}
onClick={() => popup.handlePopUpToggle("overwriteAuthMethod", true)}
> >
Overwrite Cancel
</Button> </Button>
: <Button </div>
className="mr-4" {isCurrentAuthMethod && (
<Button
size="sm" size="sm"
type="submit" colorSchema="danger"
isLoading={isSubmitting} isLoading={isSubmitting}
isDisabled={isSubmitting} isDisabled={isSubmitting}
>Submit</Button> onClick={() => handlePopUpToggle("revokeAuthMethod", true)}
} >
<Button Remove Auth Method
colorSchema="secondary" </Button>
variant="plain" )}
onClick={() => handlePopUpToggle("identityAuthMethod", false)}
>
Cancel
</Button>
</div> </div>
{identityAuthMethodData?.authMethod === initialAuthMethod && ( </form>
<Button
size="sm"
colorSchema="danger"
isLoading={isSubmitting}
isDisabled={isSubmitting}
onClick={() => handlePopUpToggle("revokeAuthMethod", true)}
>
Remove Auth Method
</Button>
)}
</div>
<DeleteActionModal <DeleteActionModal
isOpen={popup.popUp.overwriteAuthMethod?.isOpen} isOpen={internalPopUpState.popUp.overwriteAuthMethod?.isOpen}
title={`Are you sure want to overwrite ${ title={`Are you sure want to overwrite ${initialAuthMethod || "the auth method"} on ${
initialAuthMethod || "the auth method" identityAuthMethodData?.name ?? ""
} on ${identityAuthMethodData?.name ?? ""}?`} }?`}
onChange={(isOpen) => popup.handlePopUpToggle("overwriteAuthMethod", isOpen)} onChange={(isOpen) => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", isOpen)}
deleteKey="confirm" deleteKey="confirm"
onDeleteApproved={async () => { buttonText="Overwrite"
const result = await trigger(); onDeleteApproved={async () => {
if(result){ const result = await trigger();
await revokeAuth(initialAuthMethod); if (result) {
handleSubmit(onFormSubmit)(); await revokeAuth(initialAuthMethod);
}else{ handleSubmit(onFormSubmit)();
createNotification({ } else {
text: "Please fill in all required fields", createNotification({
type: "error" text: "Please fill in all required fields",
}); type: "error"
popup.handlePopUpToggle("overwriteAuthMethod", false); });
} internalPopUpState.handlePopUpToggle("overwriteAuthMethod", false);
}} }
/> }}
</form> />
</>
); );
}; };
@@ -65,10 +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 popup = usePopUp([ const { data } = useGetIdentityTokenAuth(identityAuthMethodData?.identityId ?? "", {
"overwriteAuthMethod", enabled: isCurrentAuthMethod
] as const); });
const internalPopUpState = usePopUp(["overwriteAuthMethod"] as const);
const { const {
control, control,
@@ -123,180 +124,189 @@ export const IdentityTokenAuthForm = ({
handlePopUpToggle("identityAuthMethod", false); handlePopUpToggle("identityAuthMethod", false);
createNotification({ createNotification({
text: `Successfully ${identityAuthMethodData?.authMethod === initialAuthMethod ? "updated" : "configured" text: `Successfully ${isCurrentAuthMethod ? "updated" : "configured"} auth method`,
} auth method`,
type: "success" type: "success"
}); });
reset(); reset();
} catch (err) { } catch (err) {
createNotification({ createNotification({
text: `Failed to ${identityAuthMethodData?.authMethod === initialAuthMethod ? "update" : "configure"} identity`, text: `Failed to ${isCurrentAuthMethod ? "update" : "configure"} identity`,
type: "error" type: "error"
}); });
} }
}; };
return ( return (
<form onSubmit={handleSubmit(onFormSubmit)}> <>
<Controller <form onSubmit={handleSubmit(onFormSubmit)}>
control={control} <Controller
defaultValue="2592000" control={control}
name="accessTokenTTL" defaultValue="2592000"
render={({ field, fieldState: { error } }) => ( name="accessTokenTTL"
<FormControl render={({ field, fieldState: { error } }) => (
label="Access Token TTL (seconds)" <FormControl
isError={Boolean(error)} label="Access Token TTL (seconds)"
errorText={error?.message} isError={Boolean(error)}
> errorText={error?.message}
<Input {...field} placeholder="2592000" type="number" min="1" step="1" /> >
</FormControl> <Input {...field} placeholder="2592000" type="number" min="1" step="1" />
)} </FormControl>
/> )}
<Controller />
control={control} <Controller
defaultValue="2592000" control={control}
name="accessTokenMaxTTL" defaultValue="2592000"
render={({ field, fieldState: { error } }) => ( name="accessTokenMaxTTL"
<FormControl render={({ field, fieldState: { error } }) => (
label="Access Token Max TTL (seconds)" <FormControl
isError={Boolean(error)} label="Access Token Max TTL (seconds)"
errorText={error?.message} isError={Boolean(error)}
> errorText={error?.message}
<Input {...field} placeholder="2592000" type="number" min="1" step="1" /> >
</FormControl> <Input {...field} placeholder="2592000" type="number" min="1" step="1" />
)} </FormControl>
/> )}
<Controller />
control={control} <Controller
defaultValue="0" control={control}
name="accessTokenNumUsesLimit" defaultValue="0"
render={({ field, fieldState: { error } }) => ( name="accessTokenNumUsesLimit"
<FormControl render={({ field, fieldState: { error } }) => (
label="Access Token Max Number of Uses" <FormControl
isError={Boolean(error)} label="Access Token Max Number of Uses"
errorText={error?.message} isError={Boolean(error)}
> errorText={error?.message}
<Input {...field} placeholder="0" type="number" min="0" step="1" /> >
</FormControl> <Input {...field} placeholder="0" type="number" min="0" step="1" />
)} </FormControl>
/> )}
{accessTokenTrustedIpsFields.map(({ id }, index) => ( />
<div className="mb-3 flex items-end space-x-2" key={id}> {accessTokenTrustedIpsFields.map(({ id }, index) => (
<Controller <div className="mb-3 flex items-end space-x-2" key={id}>
control={control} <Controller
name={`accessTokenTrustedIps.${index}.ipAddress`} control={control}
defaultValue="0.0.0.0/0" name={`accessTokenTrustedIps.${index}.ipAddress`}
render={({ field, fieldState: { error } }) => { defaultValue="0.0.0.0/0"
return ( render={({ field, fieldState: { error } }) => {
<FormControl return (
className="mb-0 flex-grow" <FormControl
label={index === 0 ? "Access Token Trusted IPs" : undefined} className="mb-0 flex-grow"
isError={Boolean(error)} label={index === 0 ? "Access Token Trusted IPs" : undefined}
errorText={error?.message} isError={Boolean(error)}
> errorText={error?.message}
<Input >
value={field.value} <Input
onChange={(e) => { value={field.value}
if (subscription?.ipAllowlisting) { onChange={(e) => {
field.onChange(e); if (subscription?.ipAllowlisting) {
return; field.onChange(e);
} return;
}
handlePopUpOpen("upgradePlan"); handlePopUpOpen("upgradePlan");
}} }}
placeholder="123.456.789.0" placeholder="123.456.789.0"
/> />
</FormControl> </FormControl>
); );
}} }}
/> />
<IconButton <IconButton
onClick={() => {
if (subscription?.ipAllowlisting) {
removeAccessTokenTrustedIp(index);
return;
}
handlePopUpOpen("upgradePlan");
}}
size="lg"
colorSchema="danger"
variant="plain"
ariaLabel="update"
className="p-3"
>
<FontAwesomeIcon icon={faXmark} />
</IconButton>
</div>
))}
<div className="my-4 ml-1">
<Button
variant="outline_bg"
onClick={() => { onClick={() => {
if (subscription?.ipAllowlisting) { if (subscription?.ipAllowlisting) {
removeAccessTokenTrustedIp(index); appendAccessTokenTrustedIp({
ipAddress: "0.0.0.0/0"
});
return; return;
} }
handlePopUpOpen("upgradePlan"); handlePopUpOpen("upgradePlan");
}} }}
size="lg" leftIcon={<FontAwesomeIcon icon={faPlus} />}
colorSchema="danger" size="xs"
variant="plain"
ariaLabel="update"
className="p-3"
> >
<FontAwesomeIcon icon={faXmark} /> Add IP Address
</IconButton> </Button>
</div> </div>
))} <div className="flex justify-between">
<div className="my-4 ml-1"> <div className="flex items-center">
<Button {initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod ? (
variant="outline_bg" <Button
onClick={() => { className="mr-4"
if (subscription?.ipAllowlisting) { size="sm"
appendAccessTokenTrustedIp({ isLoading={isSubmitting}
ipAddress: "0.0.0.0/0" isDisabled={isSubmitting}
}); onClick={() => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", true)}
return; >
} Overwrite
</Button>
handlePopUpOpen("upgradePlan"); ) : (
}} <Button
leftIcon={<FontAwesomeIcon icon={faPlus} />} className="mr-4"
size="xs" size="sm"
> type="submit"
Add IP Address isLoading={isSubmitting}
</Button> isDisabled={isSubmitting}
</div> >
<div className="flex justify-between"> Submit
<div className="flex items-center"> </Button>
{(initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod) ? )}
<Button <Button
className="mr-4" colorSchema="secondary"
size="sm" variant="plain"
isLoading={isSubmitting} onClick={() => handlePopUpToggle("identityAuthMethod", false)}
isDisabled={isSubmitting} >
onClick={() => popup.handlePopUpToggle("overwriteAuthMethod", true)}> Cancel
Overwrite
</Button> </Button>
: <Button </div>
className="mr-4" {isCurrentAuthMethod && (
<Button
size="sm" size="sm"
type="submit" colorSchema="danger"
isLoading={isSubmitting} isLoading={isSubmitting}
isDisabled={isSubmitting} isDisabled={isSubmitting}
>Submit</Button> onClick={() => handlePopUpToggle("revokeAuthMethod", true)}
} >
<Button Remove Auth Method
colorSchema="secondary" </Button>
variant="plain" )}
onClick={() => handlePopUpToggle("identityAuthMethod", false)}
>
Cancel
</Button>
</div> </div>
{identityAuthMethodData?.authMethod === initialAuthMethod && ( </form>
<Button
size="sm"
colorSchema="danger"
isLoading={isSubmitting}
isDisabled={isSubmitting}
onClick={() => handlePopUpToggle("revokeAuthMethod", true)}
>
Remove Auth Method
</Button>
)}
</div>
<DeleteActionModal <DeleteActionModal
isOpen={popup.popUp.overwriteAuthMethod?.isOpen} isOpen={internalPopUpState.popUp.overwriteAuthMethod?.isOpen}
title={`Are you sure want to overwrite ${ title={`Are you sure want to overwrite ${initialAuthMethod || "the auth method"} on ${
initialAuthMethod || "the auth method" identityAuthMethodData?.name ?? ""
} on ${identityAuthMethodData?.name ?? ""}?`} }?`}
onChange={(isOpen) => popup.handlePopUpToggle("overwriteAuthMethod", isOpen)} onChange={(isOpen) => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", isOpen)}
deleteKey="confirm" deleteKey="confirm"
onDeleteApproved={async () => { await revokeAuth(initialAuthMethod); handleSubmit(onFormSubmit)(); }} buttonText="Overwrite"
/> onDeleteApproved={async () => {
</form> await revokeAuth(initialAuthMethod);
handleSubmit(onFormSubmit)();
}}
/>
</>
); );
}; };
@@ -86,10 +86,12 @@ export const IdentityUniversalAuthForm = ({
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 popup = usePopUp([ const isCurrentAuthMethod = identityAuthMethodData?.authMethod === initialAuthMethod;
"overwriteAuthMethod", const { data } = useGetIdentityUniversalAuth(identityAuthMethodData?.identityId ?? "", {
] as const); enabled: isCurrentAuthMethod
});
const internalPopUpState = usePopUp(["overwriteAuthMethod"] as const);
const { const {
control, control,
@@ -188,8 +190,7 @@ export const IdentityUniversalAuthForm = ({
handlePopUpToggle("identityAuthMethod", false); handlePopUpToggle("identityAuthMethod", false);
createNotification({ createNotification({
text: `Successfully ${identityAuthMethodData?.authMethod === initialAuthMethod ? "updated" : "configured" text: `Successfully ${isCurrentAuthMethod ? "updated" : "configured"} auth method`,
} auth method`,
type: "success" type: "success"
}); });
@@ -209,234 +210,243 @@ export const IdentityUniversalAuthForm = ({
}; };
return ( return (
<form onSubmit={handleSubmit(onFormSubmit)}> <>
<Controller <form onSubmit={handleSubmit(onFormSubmit)}>
control={control} <Controller
defaultValue="2592000" control={control}
name="accessTokenTTL" defaultValue="2592000"
render={({ field, fieldState: { error } }) => ( name="accessTokenTTL"
<FormControl render={({ field, fieldState: { error } }) => (
label="Access Token TTL (seconds)" <FormControl
isError={Boolean(error)} label="Access Token TTL (seconds)"
errorText={error?.message} isError={Boolean(error)}
> errorText={error?.message}
<Input {...field} placeholder="2592000" type="number" min="1" step="1" />
</FormControl>
)}
/>
<Controller
control={control}
defaultValue="2592000"
name="accessTokenMaxTTL"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Access Token Max TTL (seconds)"
isError={Boolean(error)}
errorText={error?.message}
>
<Input {...field} placeholder="2592000" type="number" min="1" step="1" />
</FormControl>
)}
/>
<Controller
control={control}
defaultValue="0"
name="accessTokenNumUsesLimit"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Access Token Max Number of Uses"
isError={Boolean(error)}
errorText={error?.message}
>
<Input {...field} placeholder="0" type="number" min="0" step="1" />
</FormControl>
)}
/>
{clientSecretTrustedIpsFields.map(({ id }, index) => (
<div className="mb-3 flex items-end space-x-2" key={id}>
<Controller
control={control}
name={`clientSecretTrustedIps.${index}.ipAddress`}
defaultValue="0.0.0.0/0"
render={({ field, fieldState: { error } }) => {
return (
<FormControl
className="mb-0 flex-grow"
label={index === 0 ? "Client Secret Trusted IPs" : undefined}
isError={Boolean(error)}
errorText={error?.message}
>
<Input
value={field.value}
onChange={(e) => {
if (subscription?.ipAllowlisting) {
field.onChange(e);
return;
}
handlePopUpOpen("upgradePlan");
}}
placeholder="123.456.789.0"
/>
</FormControl>
);
}}
/>
<IconButton
onClick={() => {
if (subscription?.ipAllowlisting) {
removeClientSecretTrustedIp(index);
return;
}
handlePopUpOpen("upgradePlan");
}}
size="lg"
colorSchema="danger"
variant="plain"
ariaLabel="update"
className="p-3"
>
<FontAwesomeIcon icon={faXmark} />
</IconButton>
</div>
))}
<div className="my-4 ml-1">
<Button
variant="outline_bg"
onClick={() => {
if (subscription?.ipAllowlisting) {
appendClientSecretTrustedIp({
ipAddress: "0.0.0.0/0"
});
return;
}
handlePopUpOpen("upgradePlan");
}}
leftIcon={<FontAwesomeIcon icon={faPlus} />}
size="xs"
>
Add IP Address
</Button>
</div>
{accessTokenTrustedIpsFields.map(({ id }, index) => (
<div className="mb-3 flex items-end space-x-2" key={id}>
<Controller
control={control}
name={`accessTokenTrustedIps.${index}.ipAddress`}
defaultValue="0.0.0.0/0"
render={({ field, fieldState: { error } }) => {
return (
<FormControl
className="mb-0 flex-grow"
label={index === 0 ? "Access Token Trusted IPs" : undefined}
isError={Boolean(error)}
errorText={error?.message}
>
<Input
value={field.value}
onChange={(e) => {
if (subscription?.ipAllowlisting) {
field.onChange(e);
return;
}
handlePopUpOpen("upgradePlan");
}}
placeholder="123.456.789.0"
/>
</FormControl>
);
}}
/>
<IconButton
onClick={() => {
if (subscription?.ipAllowlisting) {
removeAccessTokenTrustedIp(index);
return;
}
handlePopUpOpen("upgradePlan");
}}
size="lg"
colorSchema="danger"
variant="plain"
ariaLabel="update"
className="p-3"
>
<FontAwesomeIcon icon={faXmark} />
</IconButton>
</div>
))}
<div className="my-4 ml-1">
<Button
variant="outline_bg"
onClick={() => {
if (subscription?.ipAllowlisting) {
appendAccessTokenTrustedIp({
ipAddress: "0.0.0.0/0"
});
return;
}
handlePopUpOpen("upgradePlan");
}}
leftIcon={<FontAwesomeIcon icon={faPlus} />}
size="xs"
>
Add IP Address
</Button>
</div>
<div className="flex justify-between">
<div className="flex items-center">
{(initialAuthMethod && identityAuthMethodData?.authMethod !== initialAuthMethod) ?
<Button
className="mr-4"
size="sm"
isLoading={isSubmitting}
isDisabled={isSubmitting}
onClick={() => popup.handlePopUpToggle("overwriteAuthMethod", true)}
> >
Overwrite <Input {...field} placeholder="2592000" type="number" min="1" step="1" />
</Button> </FormControl>
: <Button )}
className="mr-4" />
size="sm" <Controller
type="submit" control={control}
isLoading={isSubmitting} defaultValue="2592000"
isDisabled={isSubmitting} name="accessTokenMaxTTL"
>Submit</Button> render={({ field, fieldState: { error } }) => (
} <FormControl
label="Access Token Max TTL (seconds)"
isError={Boolean(error)}
errorText={error?.message}
>
<Input {...field} placeholder="2592000" type="number" min="1" step="1" />
</FormControl>
)}
/>
<Controller
control={control}
defaultValue="0"
name="accessTokenNumUsesLimit"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Access Token Max Number of Uses"
isError={Boolean(error)}
errorText={error?.message}
>
<Input {...field} placeholder="0" type="number" min="0" step="1" />
</FormControl>
)}
/>
{clientSecretTrustedIpsFields.map(({ id }, index) => (
<div className="mb-3 flex items-end space-x-2" key={id}>
<Controller
control={control}
name={`clientSecretTrustedIps.${index}.ipAddress`}
defaultValue="0.0.0.0/0"
render={({ field, fieldState: { error } }) => {
return (
<FormControl
className="mb-0 flex-grow"
label={index === 0 ? "Client Secret Trusted IPs" : undefined}
isError={Boolean(error)}
errorText={error?.message}
>
<Input
value={field.value}
onChange={(e) => {
if (subscription?.ipAllowlisting) {
field.onChange(e);
return;
}
handlePopUpOpen("upgradePlan");
}}
placeholder="123.456.789.0"
/>
</FormControl>
);
}}
/>
<IconButton
onClick={() => {
if (subscription?.ipAllowlisting) {
removeClientSecretTrustedIp(index);
return;
}
handlePopUpOpen("upgradePlan");
}}
size="lg"
colorSchema="danger"
variant="plain"
ariaLabel="update"
className="p-3"
>
<FontAwesomeIcon icon={faXmark} />
</IconButton>
</div>
))}
<div className="my-4 ml-1">
<Button <Button
colorSchema="secondary" variant="outline_bg"
variant="plain" onClick={() => {
onClick={() => handlePopUpToggle("identityAuthMethod", false)} if (subscription?.ipAllowlisting) {
appendClientSecretTrustedIp({
ipAddress: "0.0.0.0/0"
});
return;
}
handlePopUpOpen("upgradePlan");
}}
leftIcon={<FontAwesomeIcon icon={faPlus} />}
size="xs"
> >
Cancel Add IP Address
</Button> </Button>
</div> </div>
{identityAuthMethodData?.authMethod === initialAuthMethod && ( {accessTokenTrustedIpsFields.map(({ id }, index) => (
<div className="mb-3 flex items-end space-x-2" key={id}>
<Controller
control={control}
name={`accessTokenTrustedIps.${index}.ipAddress`}
defaultValue="0.0.0.0/0"
render={({ field, fieldState: { error } }) => {
return (
<FormControl
className="mb-0 flex-grow"
label={index === 0 ? "Access Token Trusted IPs" : undefined}
isError={Boolean(error)}
errorText={error?.message}
>
<Input
value={field.value}
onChange={(e) => {
if (subscription?.ipAllowlisting) {
field.onChange(e);
return;
}
handlePopUpOpen("upgradePlan");
}}
placeholder="123.456.789.0"
/>
</FormControl>
);
}}
/>
<IconButton
onClick={() => {
if (subscription?.ipAllowlisting) {
removeAccessTokenTrustedIp(index);
return;
}
handlePopUpOpen("upgradePlan");
}}
size="lg"
colorSchema="danger"
variant="plain"
ariaLabel="update"
className="p-3"
>
<FontAwesomeIcon icon={faXmark} />
</IconButton>
</div>
))}
<div className="my-4 ml-1">
<Button <Button
size="sm" variant="outline_bg"
colorSchema="danger" onClick={() => {
isLoading={isSubmitting} if (subscription?.ipAllowlisting) {
isDisabled={isSubmitting} appendAccessTokenTrustedIp({
onClick={() => handlePopUpToggle("revokeAuthMethod", true)} ipAddress: "0.0.0.0/0"
});
return;
}
handlePopUpOpen("upgradePlan");
}}
leftIcon={<FontAwesomeIcon icon={faPlus} />}
size="xs"
> >
Remove Auth Method Add IP Address
</Button> </Button>
)} </div>
</div> <div className="flex justify-between">
<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
className="mr-4"
size="sm"
type="submit"
isLoading={isSubmitting}
isDisabled={isSubmitting}
>
Submit
</Button>
)}
<Button
colorSchema="secondary"
variant="plain"
onClick={() => handlePopUpToggle("identityAuthMethod", false)}
>
Cancel
</Button>
</div>
{isCurrentAuthMethod && (
<Button
size="sm"
colorSchema="danger"
isLoading={isSubmitting}
isDisabled={isSubmitting}
onClick={() => handlePopUpToggle("revokeAuthMethod", true)}
>
Remove Auth Method
</Button>
)}
</div>
</form>
<DeleteActionModal <DeleteActionModal
isOpen={popup.popUp.overwriteAuthMethod?.isOpen} isOpen={internalPopUpState.popUp.overwriteAuthMethod?.isOpen}
title={`Are you sure want to overwrite ${ title={`Are you sure want to overwrite ${initialAuthMethod || "the auth method"} on ${
initialAuthMethod || "the auth method" identityAuthMethodData?.name ?? ""
} on ${identityAuthMethodData?.name ?? ""}?`} }?`}
onChange={(isOpen) => popup.handlePopUpToggle("overwriteAuthMethod", isOpen)} onChange={(isOpen) => internalPopUpState.handlePopUpToggle("overwriteAuthMethod", isOpen)}
deleteKey="confirm" deleteKey="confirm"
onDeleteApproved={async () => { await revokeAuth(initialAuthMethod); handleSubmit(onFormSubmit)(); }} buttonText="Overwrite"
/> onDeleteApproved={async () => {
</form> await revokeAuth(initialAuthMethod);
handleSubmit(onFormSubmit)();
}}
/>
</>
); );
}; };