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 @@ -179,8 +179,10 @@ function AutofixGithubIntegrationStep({
size="sm"
disabled={!canStartAutofix}
onClick={handleClose}
analyticsEventName="Autofix Setup Enable Autofix"
analyticsEventKey="autofix.setup_enable_autofix"
>
{t("Let's Go!")}
{t('Enable Autofix')}
</Button>
)}
</GuidedSteps.StepButtons>
Expand Down Expand Up @@ -255,6 +257,8 @@ function AutofixGithubIntegrationStep({
size="sm"
disabled={!canStartAutofix}
onClick={handleClose}
analyticsEventName="Autofix Setup Skip & Enable Autofix"
analyticsEventKey="autofix.setup_skip_enable_autofix"
>
{t('Skip & Enable Autofix')}
</Button>
Expand Down
3 changes: 3 additions & 0 deletions static/app/components/events/autofix/useAutofixSetup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ export interface AutofixSetupRepoDefinition extends AutofixRepoDefinition {
}

export type AutofixSetupResponse = {
autofixEnabled: {
ok: boolean;
};
genAIConsent: {
ok: boolean;
};
Expand Down
1 change: 1 addition & 0 deletions static/app/types/organization.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import type {User} from './user';
*/
export interface OrganizationSummary {
aiSuggestedSolution: boolean;
autofixEnabled: boolean;
avatar: Avatar;
codecovAccess: boolean;
dateCreated: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ describe('SolutionsHubDrawer', () => {
genAIConsent: {ok: true},
integration: {ok: true},
githubWriteIntegration: {ok: true},
autofixEnabled: {ok: true},
},
});
MockApiClient.addMockResponse({
Expand All @@ -64,6 +65,7 @@ describe('SolutionsHubDrawer', () => {
genAIConsent: {ok: false},
integration: {ok: false},
githubWriteIntegration: {ok: false},
autofixEnabled: {ok: false},
},
});
MockApiClient.addMockResponse({
Expand Down Expand Up @@ -106,8 +108,6 @@ describe('SolutionsHubDrawer', () => {
screen.queryByTestId('ai-setup-loading-indicator')
);

expect(screen.getByText(mockEvent.id)).toBeInTheDocument();

expect(screen.getByRole('heading', {name: 'Solutions Hub'})).toBeInTheDocument();

const startButton = screen.getByRole('button', {name: 'Start Autofix'});
Expand Down Expand Up @@ -180,4 +180,39 @@ describe('SolutionsHubDrawer', () => {
expect(screen.getByRole('button', {name: 'Start Autofix'})).toBeInTheDocument();
});
});

it('continues to show setup if autofix is not enabled', async () => {
MockApiClient.addMockResponse({
url: `/issues/${mockGroup.id}/autofix/setup/`,
body: {
genAIConsent: {ok: true},
integration: {ok: true},
githubWriteIntegration: {ok: false, repos: []},
autofixEnabled: {ok: false},
},
});
MockApiClient.addMockResponse({
url: `/issues/${mockGroup.id}/autofix/`,
body: {autofix: null},
});

render(
<SolutionsHubDrawer event={mockEvent} group={mockGroup} project={mockProject} />,
{organization}
);

expect(screen.getByTestId('ai-setup-loading-indicator')).toBeInTheDocument();

await waitForElementToBeRemoved(() =>
screen.queryByTestId('ai-setup-loading-indicator')
);

expect(screen.getByRole('heading', {name: 'Solutions Hub'})).toBeInTheDocument();

expect(screen.queryByRole('button', {name: 'Start Autofix'})).not.toBeInTheDocument();

expect(
screen.getByRole('button', {name: 'Skip & Enable Autofix'})
).toBeInTheDocument();
});
});
43 changes: 34 additions & 9 deletions static/app/views/issueDetails/streamline/solutionsHubDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import AutofixFeedback from 'sentry/components/events/autofix/autofixFeedback';
import {AutofixSetupContent} from 'sentry/components/events/autofix/autofixSetupModal';
import {AutofixSteps} from 'sentry/components/events/autofix/autofixSteps';
import {useAiAutofix} from 'sentry/components/events/autofix/useAutofix';
import {useAutofixSetup} from 'sentry/components/events/autofix/useAutofixSetup';
import {
makeAutofixSetupQueryKey,
useAutofixSetup,
} from 'sentry/components/events/autofix/useAutofixSetup';
import {DrawerBody, DrawerHeader} from 'sentry/components/globalDrawer/components';
import {GroupSummaryBody, useGroupSummary} from 'sentry/components/group/groupSummary';
import HookOrDefault from 'sentry/components/hookOrDefault';
Expand All @@ -30,8 +33,10 @@ import {
getConfigForIssueType,
shouldShowCustomErrorResourceConfig,
} from 'sentry/utils/issueTypeConfig';
import {useMutation, useQueryClient} from 'sentry/utils/queryClient';
import {getRegionDataFromOrganization} from 'sentry/utils/regions';
import useRouteAnalyticsParams from 'sentry/utils/routeAnalytics/useRouteAnalyticsParams';
import useApi from 'sentry/utils/useApi';
import useOrganization from 'sentry/utils/useOrganization';
import {MIN_NAV_HEIGHT} from 'sentry/views/issueDetails/streamline/eventTitle';
import Resources from 'sentry/views/issueDetails/streamline/resources';
Expand Down Expand Up @@ -141,20 +146,37 @@ const AiSetupDataConsent = HookOrDefault({
defaultComponent: () => <div data-test-id="ai-setup-data-consent" />,
});

const useEnableAutofix = (groupId: string) => {
const api = useApi({persistInFlight: true});
const queryClient = useQueryClient();

const organization = useOrganization();
return useMutation({
mutationFn: () => {
return api.requestPromise(`/organizations/${organization.slug}/`, {
method: 'PUT',
data: {
autofixEnabled: true,
},
});
},
onSuccess: () => {
queryClient.invalidateQueries({queryKey: makeAutofixSetupQueryKey(groupId)});
},
});
};

export function SolutionsHubDrawer({group, project, event}: SolutionsHubDrawerProps) {
const {autofixData, triggerAutofix, reset} = useAiAutofix(group, event);
const {
data: summaryData,
isError,
isPending: isSummaryLoading,
} = useGroupSummary(group.id, group.issueCategory);
const {
data: setupData,
isPending: isSetupLoading,
refetch: refetchSetup,
} = useAutofixSetup({
const {data: setupData, isPending: isSetupLoading} = useAutofixSetup({
groupId: group.id,
});
const enableAutofixMutation = useEnableAutofix(group.id);

useRouteAnalyticsParams({
autofix_status: autofixData?.status ?? 'none',
Expand All @@ -164,6 +186,7 @@ export function SolutionsHubDrawer({group, project, event}: SolutionsHubDrawerPr

const hasConsent = Boolean(setupData?.genAIConsent.ok);
const isAutofixSetupComplete = setupData?.integration.ok && hasConsent;
const autofixEnabled = setupData?.autofixEnabled.ok;

const hasSummary = summaryData && !isError && hasConsent;

Expand Down Expand Up @@ -245,7 +268,7 @@ export function SolutionsHubDrawer({group, project, event}: SolutionsHubDrawerPr
</ButtonBar>
)}
</HeaderText>
{isSetupLoading ? (
{isSetupLoading || enableAutofixMutation.isPending ? (
<div data-test-id="ai-setup-loading-indicator">
<LoadingIndicator />
</div>
Expand All @@ -264,11 +287,13 @@ export function SolutionsHubDrawer({group, project, event}: SolutionsHubDrawerPr
)}
{displayAiAutofix && (
<Fragment>
{!isAutofixSetupComplete ? (
{!isAutofixSetupComplete || !autofixEnabled ? (
<AutofixSetupContent
groupId={group.id}
projectId={project.id}
onComplete={refetchSetup}
onComplete={() => {
enableAutofixMutation.mutate();
}}
/>
) : !autofixData ? (
<AutofixStartBox onSend={triggerAutofix} groupId={group.id} />
Expand Down
1 change: 1 addition & 0 deletions tests/js/fixtures/organization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export function OrganizationFixture( params: Partial<Organization> = {}): Organi
githubOpenPRBot: false,
githubPRBot: false,
hideAiFeatures: false,
autofixEnabled: false,
isDefault: false,
isDynamicallySampled: true,
isEarlyAdopter: false,
Expand Down
Loading