diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsRowDropdownMenu.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsRowDropdownMenu.tsx index ebcc16b94dd..4f4e1984736 100644 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsRowDropdownMenu.tsx +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsRowDropdownMenu.tsx @@ -7,7 +7,10 @@ import { SettingsPath, } from 'twenty-shared/types'; -import { useTriggerProviderReconnect } from '@/settings/accounts/hooks/useTriggerProviderReconnect'; +import { + isReconnectableProvider, + useTriggerProviderReconnect, +} from '@/settings/accounts/hooks/useTriggerProviderReconnect'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; @@ -121,16 +124,17 @@ export const SettingsAccountsRowDropdownMenu = ({ closeDropdown(dropdownId); }} /> - {account.authFailedAt && ( - { - triggerProviderReconnect(account.provider, account.id); - closeDropdown(dropdownId); - }} - /> - )} + {account.authFailedAt && + isReconnectableProvider(account.provider) && ( + { + triggerProviderReconnect(account.provider, account.id); + closeDropdown(dropdownId); + }} + /> + )} { }); }); + describe('unsupported providers', () => { + it('should not trigger OAuth for OIDC provider', async () => { + const { result } = renderHook(() => useTriggerProviderReconnect()); + + await act(async () => { + await result.current.triggerProviderReconnect( + ConnectedAccountProvider.OIDC, + ); + }); + + expect(mockTriggerApisOAuth).not.toHaveBeenCalled(); + expect(mockNavigate).not.toHaveBeenCalled(); + }); + + it('should not trigger OAuth for SAML provider', async () => { + const { result } = renderHook(() => useTriggerProviderReconnect()); + + await act(async () => { + await result.current.triggerProviderReconnect( + ConnectedAccountProvider.SAML, + ); + }); + + expect(mockTriggerApisOAuth).not.toHaveBeenCalled(); + expect(mockNavigate).not.toHaveBeenCalled(); + }); + + it('should not trigger OAuth for unknown provider values', async () => { + const { result } = renderHook(() => useTriggerProviderReconnect()); + + await act(async () => { + await result.current.triggerProviderReconnect( + 'EmailEngine' as ConnectedAccountProvider, + ); + }); + + expect(mockTriggerApisOAuth).not.toHaveBeenCalled(); + expect(mockNavigate).not.toHaveBeenCalled(); + }); + }); + describe('error handling', () => { it('should handle triggerApisOAuth errors gracefully', async () => { const { result } = renderHook(() => useTriggerProviderReconnect()); diff --git a/packages/twenty-front/src/modules/settings/accounts/hooks/useTriggerProviderReconnect.ts b/packages/twenty-front/src/modules/settings/accounts/hooks/useTriggerProviderReconnect.ts index d7f43b74407..dc78a539e56 100644 --- a/packages/twenty-front/src/modules/settings/accounts/hooks/useTriggerProviderReconnect.ts +++ b/packages/twenty-front/src/modules/settings/accounts/hooks/useTriggerProviderReconnect.ts @@ -5,6 +5,17 @@ import { getSettingsPath } from 'twenty-shared/utils'; import { useTriggerApisOAuth } from '@/settings/accounts/hooks/useTriggerApiOAuth'; import { useNavigateSettings } from '~/hooks/useNavigateSettings'; +const OAUTH_RECONNECTABLE_PROVIDERS: ConnectedAccountProvider[] = [ + ConnectedAccountProvider.GOOGLE, + ConnectedAccountProvider.MICROSOFT, +]; + +export const isReconnectableProvider = ( + provider: ConnectedAccountProvider, +): boolean => + provider === ConnectedAccountProvider.IMAP_SMTP_CALDAV || + OAUTH_RECONNECTABLE_PROVIDERS.includes(provider); + export const useTriggerProviderReconnect = () => { const { triggerApisOAuth } = useTriggerApisOAuth(); const navigate = useNavigateSettings(); @@ -27,6 +38,10 @@ export const useTriggerProviderReconnect = () => { return; } + if (!OAUTH_RECONNECTABLE_PROVIDERS.includes(provider)) { + return; + } + await triggerApisOAuth(provider, { ...options, redirectLocation: getSettingsPath(SettingsPath.Accounts),