Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,96 @@ describe('AutofixSetupContent', function () {
},
});

MockApiClient.addMockResponse({
url: '/organizations/org-slug/integrations/?provider_key=github&includeConfig=0',
body: [],
});

render(<AutofixSetupContent groupId="1" projectId="1" />);

expect(await screen.findByText('Install the GitHub Integration')).toBeInTheDocument();
expect(screen.getByText(/Install the GitHub integration/)).toBeInTheDocument();
});

it('renders the code mappings instructions', async function () {
MockApiClient.addMockResponse({
url: '/issues/1/autofix/setup/',
body: {
genAIConsent: {ok: true},
integration: {ok: false, reason: 'integration_no_code_mappings'},
githubWriteIntegration: {
ok: false,
repos: [
{
provider: 'integrations:github',
owner: 'getsentry',
name: 'sentry',
external_id: '123',
ok: false,
},
],
},
},
});

MockApiClient.addMockResponse({
url: '/organizations/org-slug/integrations/?provider_key=github&includeConfig=0',
body: [
{
id: '123',
},
],
});

render(<AutofixSetupContent groupId="1" projectId="1" />);

expect(await screen.findByText('Set up Code Mappings')).toBeInTheDocument();
expect(
screen.getByText(
/Set up code mappings for the Github repositories you want to run Autofix on/
)
).toBeInTheDocument();
expect(
screen.getByRole('button', {name: 'Configure Code Mappings'})
).toBeInTheDocument();
});

it('renders the code mappings with fallback if no integration is configured', async function () {
MockApiClient.addMockResponse({
url: '/issues/1/autofix/setup/',
body: {
genAIConsent: {ok: true},
integration: {ok: false, reason: 'integration_no_code_mappings'},
githubWriteIntegration: {
ok: false,
repos: [
{
provider: 'integrations:github',
owner: 'getsentry',
name: 'sentry',
external_id: '123',
ok: false,
},
],
},
},
});

MockApiClient.addMockResponse({
url: '/organizations/org-slug/integrations/?provider_key=github&includeConfig=0',
body: [],
});

render(<AutofixSetupContent groupId="1" projectId="1" />);

expect(await screen.findByText('Set up Code Mappings')).toBeInTheDocument();
expect(
screen.getByText(
/Set up code mappings for the Github repositories you want to run Autofix on/
)
).toBeInTheDocument();
expect(
screen.getByText(/Install the GitHub integration by navigating to/)
screen.getByRole('button', {name: 'Configure Integration'})
).toBeInTheDocument();
});
});
152 changes: 77 additions & 75 deletions static/app/components/events/autofix/autofixSetupModal.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import {Fragment, useEffect} from 'react';
import styled from '@emotion/styled';

import {Button} from 'sentry/components/button';
import {
type AutofixSetupRepoDefinition,
type AutofixSetupResponse,
useAutofixSetup,
} from 'sentry/components/events/autofix/useAutofixSetup';
import {GuidedSteps} from 'sentry/components/guidedSteps/guidedSteps';
import ExternalLink from 'sentry/components/links/externalLink';
import LoadingError from 'sentry/components/loadingError';
import LoadingIndicator from 'sentry/components/loadingIndicator';
import {IconCheckmark, IconGithub} from 'sentry/icons';
import {t, tct} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import type {Integration} from 'sentry/types/integrations';
import {trackAnalytics} from 'sentry/utils/analytics';
import {useApiQuery} from 'sentry/utils/queryClient';
import useOrganization from 'sentry/utils/useOrganization';

function AutofixIntegrationStep({autofixSetup}: {autofixSetup: AutofixSetupResponse}) {
Expand All @@ -22,6 +26,9 @@ function AutofixIntegrationStep({autofixSetup}: {autofixSetup: AutofixSetupRespo
{tct('The GitHub integration is already installed, [link: view in settings].', {
link: <ExternalLink href={`/settings/integrations/github/`} />,
})}
<GuidedSteps.ButtonWrapper>
<GuidedSteps.NextButton />
</GuidedSteps.ButtonWrapper>
</Fragment>
);
}
Expand All @@ -47,43 +54,23 @@ function AutofixIntegrationStep({autofixSetup}: {autofixSetup: AutofixSetupRespo
}
)}
</p>
</Fragment>
);
}

if (autofixSetup.integration.reason === 'integration_no_code_mappings') {
return (
<Fragment>
<p>
{tct(
'You have an active GitHub installation, but no code mappings for this project. Add code mappings by visiting the [link:integration settings page] and editing your configuration.',
{
link: <ExternalLink href={`/settings/integrations/github/`} />,
}
)}
</p>
<p>
{tct(
'Once added, come back to this page. For more information related to installing the GitHub integration, read the [link:documentation].',
{
link: (
<ExternalLink href="https://docs.sentry.io/product/integrations/source-code-mgmt/github/" />
),
}
)}
</p>
<GuidedSteps.ButtonWrapper>
<ExternalLink href="/settings/integrations/github/">
<Button size="sm" priority="primary">
{t('Set up Integration')}
</Button>
</ExternalLink>
<GuidedSteps.NextButton />
</GuidedSteps.ButtonWrapper>
</Fragment>
);
}

return (
<Fragment>
<p>
{tct(
'Install the GitHub integration by navigating to the [link:integration settings page] and clicking the "Install" button. Follow the steps provided.',
{
link: <ExternalLink href={`/settings/integrations/github/`} />,
}
{t(
'Install the GitHub integration on the integration settings page and clicking the "Install" button. Follow the steps provided.'
)}
</p>
<p>
Expand All @@ -96,6 +83,47 @@ function AutofixIntegrationStep({autofixSetup}: {autofixSetup: AutofixSetupRespo
}
)}
</p>
<GuidedSteps.ButtonWrapper>
<ExternalLink href="/settings/integrations/github/">
<Button size="sm" priority="primary">
{t('Set up Integration')}
</Button>
</ExternalLink>
<GuidedSteps.NextButton />
</GuidedSteps.ButtonWrapper>
</Fragment>
);
}

function AutofixCodeMappingStep() {
const organization = useOrganization();
const {data: integrationConfigurations} = useApiQuery<Integration[]>(
[
`/organizations/${organization.slug}/integrations/?provider_key=github&includeConfig=0`,
],
{
staleTime: Infinity,
}
);

const configurationId = integrationConfigurations?.at(0)?.id;
const url = `/settings/integrations/github/${configurationId ? configurationId + '/?tab=codeMappings' : ''}`;

return (
<Fragment>
<p>
{t(
'Set up code mappings for the Github repositories you want to run Autofix on for this project.'
)}
</p>
<GuidedSteps.ButtonWrapper>
<GuidedSteps.BackButton />
<ExternalLink href={url}>
<Button size="sm" priority="primary">
{configurationId ? t('Configure Code Mappings') : t('Configure Integration')}
</Button>
</ExternalLink>
</GuidedSteps.ButtonWrapper>
</Fragment>
);
}
Expand All @@ -122,34 +150,27 @@ export function GitRepoLink({repo}: {repo: AutofixSetupRepoDefinition}) {
);
}

function SetupStep({
title,
isCompleted,
children,
}: {
children: React.ReactNode;
isCompleted: boolean;
title: string;
}) {
return (
<StepWrapper>
<StepHeader>
<StepTitle>{title}</StepTitle>
{isCompleted && <IconCheckmark color="success" size="sm" />}
</StepHeader>
<div>{children}</div>
</StepWrapper>
);
}

function AutofixSetupSteps({autofixSetup}: {autofixSetup: AutofixSetupResponse}) {
return (
<SetupStep
title={t('Install the GitHub Integration')}
isCompleted={autofixSetup.integration.ok}
>
<AutofixIntegrationStep autofixSetup={autofixSetup} />
</SetupStep>
<GuidedSteps>
<GuidedSteps.Step
stepKey="integration"
title={t('Install the GitHub Integration')}
isCompleted={
autofixSetup.integration.ok ||
autofixSetup.integration.reason === 'integration_no_code_mappings'
}
>
<AutofixIntegrationStep autofixSetup={autofixSetup} />
</GuidedSteps.Step>
<GuidedSteps.Step
stepKey="codeMappings"
title={t('Set up Code Mappings')}
isCompleted={autofixSetup.integration.ok}
>
<AutofixCodeMappingStep />
</GuidedSteps.Step>
</GuidedSteps>
);
}

Expand Down Expand Up @@ -237,22 +258,3 @@ const Divider = styled('div')`
margin: ${space(3)} 0;
border-bottom: 2px solid ${p => p.theme.gray100};
`;

const StepWrapper = styled('div')`
margin-top: ${space(3)};
padding-left: ${space(2)};
border-left: 2px solid ${p => p.theme.border};
`;

const StepHeader = styled('div')`
display: flex;
align-items: center;
gap: ${space(1)};
margin-bottom: ${space(1)};
`;

const StepTitle = styled('p')`
font-size: ${p => p.theme.fontSizeMedium};
font-weight: 600;
margin: 0;
`;
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,10 @@ describe('SolutionsHubDrawer', () => {
url: `/issues/${mockGroup.id}/autofix/`,
body: {autofix: null},
});
MockApiClient.addMockResponse({
url: '/organizations/org-slug/integrations/?provider_key=github&includeConfig=0',
body: [],
});

render(
<SolutionsHubDrawer event={mockEvent} group={mockGroup} project={mockProject} />,
Expand Down
Loading