diff --git a/static/app/views/settings/organizationIntegrations/addIntegrationButton.spec.tsx b/static/app/views/settings/organizationIntegrations/addIntegrationButton.spec.tsx index f40c74a190d5..7d27acdf8e26 100644 --- a/static/app/views/settings/organizationIntegrations/addIntegrationButton.spec.tsx +++ b/static/app/views/settings/organizationIntegrations/addIntegrationButton.spec.tsx @@ -1,7 +1,7 @@ import {IntegrationProviderFixture} from 'sentry-fixture/integrationProvider'; import {OrganizationFixture} from 'sentry-fixture/organization'; -import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary'; +import {act, render, screen, userEvent} from 'sentry-test/reactTestingLibrary'; import * as pipelineModal from 'sentry/components/pipeline/modal'; import {AddIntegrationButton} from 'sentry/views/settings/organizationIntegrations/addIntegrationButton'; @@ -36,4 +36,31 @@ describe('AddIntegrationButton', () => { }) ); }); + + it('keeps the button focusable with a tooltip when the provider cannot be added', async () => { + const openPipelineModalSpy = jest + .spyOn(pipelineModal, 'openPipelineModal') + .mockImplementation(() => {}); + + render( + + ); + + const button = screen.getByRole('button', {name: 'Add integration'}); + expect(button).toHaveAttribute('aria-disabled', 'true'); + + act(() => button.focus()); + expect( + await screen.findByText( + `Integration cannot be added on Sentry. Enable this integration via the ${provider.name} instance.` + ) + ).toBeInTheDocument(); + + await userEvent.click(button); + expect(openPipelineModalSpy).not.toHaveBeenCalled(); + }); }); diff --git a/static/app/views/settings/organizationIntegrations/addIntegrationButton.tsx b/static/app/views/settings/organizationIntegrations/addIntegrationButton.tsx index f6a4b70a76e5..a503eb438420 100644 --- a/static/app/views/settings/organizationIntegrations/addIntegrationButton.tsx +++ b/static/app/views/settings/organizationIntegrations/addIntegrationButton.tsx @@ -1,6 +1,5 @@ import type {ButtonProps} from '@sentry/scraps/button'; import {Button} from '@sentry/scraps/button'; -import {Tooltip} from '@sentry/scraps/tooltip'; import {t} from 'sentry/locale'; import type {IntegrationWithConfig} from 'sentry/types/integrations'; @@ -55,34 +54,44 @@ export function AddIntegrationButton({ }); return ( - - - + } + startFlow({ + provider, + organization, + onInstall: onAddIntegration, + analyticsParams, + suppressSuccessMessage, + onCancel, + onError, + }); + }} + > + {label} + ); } diff --git a/static/app/views/settings/organizationIntegrations/directEnableButton.spec.tsx b/static/app/views/settings/organizationIntegrations/directEnableButton.spec.tsx index cf6b89e08779..e131ecef3759 100644 --- a/static/app/views/settings/organizationIntegrations/directEnableButton.spec.tsx +++ b/static/app/views/settings/organizationIntegrations/directEnableButton.spec.tsx @@ -1,6 +1,6 @@ import {OrganizationFixture} from 'sentry-fixture/organization'; -import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary'; +import {act, render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary'; import {DirectEnableButton} from 'sentry/views/settings/organizationIntegrations/directEnableButton'; @@ -42,8 +42,8 @@ describe('DirectEnableButton', () => { await waitFor(() => expect(mockPost).toHaveBeenCalledTimes(1)); }); - it('disables button when user does not have access', () => { - MockApiClient.addMockResponse({ + it('keeps the button focusable with a tooltip when user does not have access', async () => { + const mockPost = MockApiClient.addMockResponse({ url: `/organizations/${organization.slug}/integrations/direct-enable/github_copilot/`, method: 'POST', body: {}, @@ -53,6 +53,15 @@ describe('DirectEnableButton', () => { organization, }); - expect(screen.getByRole('button', {name: 'Enable Integration'})).toBeDisabled(); + const button = screen.getByRole('button', {name: 'Enable Integration'}); + expect(button).toHaveAttribute('aria-disabled', 'true'); + + act(() => button.focus()); + expect( + await screen.findByText('You do not have permission to enable this integration.') + ).toBeInTheDocument(); + + await userEvent.click(button); + expect(mockPost).not.toHaveBeenCalled(); }); }); diff --git a/static/app/views/settings/organizationIntegrations/directEnableButton.tsx b/static/app/views/settings/organizationIntegrations/directEnableButton.tsx index b95a61cbf060..460a02cb9522 100644 --- a/static/app/views/settings/organizationIntegrations/directEnableButton.tsx +++ b/static/app/views/settings/organizationIntegrations/directEnableButton.tsx @@ -1,7 +1,6 @@ import {useMutation, useQueryClient} from '@tanstack/react-query'; import {Button} from '@sentry/scraps/button'; -import {Tooltip} from '@sentry/scraps/tooltip'; import {addErrorMessage} from 'sentry/actionCreators/indicator'; import {t} from 'sentry/locale'; @@ -57,19 +56,29 @@ export function DirectEnableButton({ onError: () => addErrorMessage(t('Failed to enable integration.')), }); + const nativelyDisabled = buttonProps.disabled || isPending; + return ( - { + if (!userHasAccess) { + return; + } + enable(); + }} > - - + {t('Enable Integration')} + ); }