diff --git a/apps/studio/components/interfaces/Organization/SecuritySettings.tsx b/apps/studio/components/interfaces/Organization/SecuritySettings.tsx index a8ea11d9644..cba6de2cbbc 100644 --- a/apps/studio/components/interfaces/Organization/SecuritySettings.tsx +++ b/apps/studio/components/interfaces/Organization/SecuritySettings.tsx @@ -1,29 +1,18 @@ import { zodResolver } from '@hookform/resolvers/zod' import { PermissionAction } from '@supabase/shared-types/out/constants' import { useParams } from 'common' +import Link from 'next/link' import { useEffect } from 'react' import { useForm } from 'react-hook-form' import { toast } from 'sonner' -import { - Button, - Card, - CardContent, - CardFooter, - Form, - FormControl, - FormField, - Switch, - Tooltip, - TooltipContent, - TooltipTrigger, -} from 'ui' +import { Button, Card, CardContent, CardFooter, Form, FormControl, FormField, Switch } from 'ui' +import { Admonition } from 'ui-patterns' import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader' import { z } from 'zod' import { ScaffoldContainer, ScaffoldSection } from '@/components/layouts/Scaffold' import AlertError from '@/components/ui/AlertError' -import { InlineLink } from '@/components/ui/InlineLink' import NoPermission from '@/components/ui/NoPermission' import { UpgradeToPro } from '@/components/ui/UpgradeToPro' import { useOrganizationMembersQuery } from '@/data/organizations/organization-members-query' @@ -41,7 +30,13 @@ const schema = z.object({ export const SecuritySettings = () => { const { slug } = useParams() const { profile } = useProfile() - const { data: members } = useOrganizationMembersQuery({ slug }) + const { + data: members, + error: membersError, + isPending: isLoadingMembers, + isError: isMembersError, + isSuccess: isSuccessMembers, + } = useOrganizationMembersQuery({ slug }) const { can: canReadMfaConfig, isLoading: isLoadingPermissions } = useAsyncCheckPermissions( PermissionAction.READ, @@ -89,7 +84,19 @@ export const SecuritySettings = () => { }, [mfaConfig, form]) const hasMFAEnabled = - members?.find((member) => member.primary_email == profile?.primary_email)?.mfa_enabled || false + members?.find((member) => member.primary_email == profile?.primary_email)?.mfa_enabled ?? false + + const requiresPersonalMfa = isSuccessMembers && canUpdateMfaConfig && !hasMFAEnabled + + const isLoadingMfaEnforcementSettings = + isLoadingMfa || isLoadingPermissions || isLoadingEntitlement || isLoadingMembers + const hasMfaConfigError = (isErrorMfa || Boolean(mfaError)) && hasAccessToEnforceMfa + const canShowMfaEnforcementForm = + isSuccessMfa && hasAccessToEnforceMfa && isSuccessMembers && !requiresPersonalMfa + const isMfaEnforcementSwitchDisabled = + !hasAccessToEnforceMfa || !canUpdateMfaConfig || isUpdatingMfa + const isSaveMfaEnforcementDisabled = + isMfaEnforcementSwitchDisabled || isLoadingMfa || !form.formState.isDirty const onSubmit = (values: { enforceMfa: boolean }) => { if (!slug || !hasAccessToEnforceMfa) return @@ -108,7 +115,7 @@ export const SecuritySettings = () => { /> ) : ( <> - {isLoadingMfa || isLoadingPermissions || isLoadingEntitlement ? ( + {isLoadingMfaEnforcementSettings ? ( @@ -116,13 +123,31 @@ export const SecuritySettings = () => { ) : !canReadMfaConfig ? ( - ) : null} + ) : ( + requiresPersonalMfa && ( + + Set up MFA + + } + /> + ) + )} - {(isErrorMfa || mfaError) && hasAccessToEnforceMfa && ( + {isMembersError && ( + + )} + + {hasMfaConfigError && ( )} - {isSuccessMfa && hasAccessToEnforceMfa && ( + {canShowMfaEnforcementForm && (
@@ -133,36 +158,16 @@ export const SecuritySettings = () => { render={({ field }) => ( - - - - - {(!canUpdateMfaConfig || !hasMFAEnabled) && ( - - {!canUpdateMfaConfig ? ( - "You don't have permission to update MFA settings" - ) : ( - <> - Enable MFA{' '} - on your own account first - - )} - - )} - + )} @@ -183,16 +188,10 @@ export const SecuritySettings = () => {