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 @@ -64,7 +64,7 @@ describe('IssuePreview', () => {
});
});

it('links to an open user pull request without an Autofix state', async () => {
it('links to an open user pull request and shows the next Autofix step', async () => {
MockApiClient.addMockResponse({
url: `/organizations/${organization.slug}/issues/${group.id}/autofix/`,
body: ExplorerAutofixResponseFixture({autofix: null}),
Expand Down Expand Up @@ -93,6 +93,7 @@ describe('IssuePreview', () => {
expect(
await screen.findByRole('button', {name: 'View example/repo-name#10'})
).toHaveAttribute('href', 'https://github.com/example/repo-name/pull/10');
expect(screen.getByRole('button', {name: 'Find Root Cause'})).toBeInTheDocument();
});

it('offers to restart Autofix after PR creation when the linked PR is closed', async () => {
Expand Down
124 changes: 87 additions & 37 deletions static/app/views/issueDetails/issuePreview/issuePreviewActions.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {useState, type ReactNode} from 'react';
import {Fragment, useState, type ReactNode} from 'react';

import {Button, ButtonBar, LinkButton, type ButtonProps} from '@sentry/scraps/button';
import {MenuComponents} from '@sentry/scraps/compactSelect';
Expand Down Expand Up @@ -77,6 +77,7 @@ function getAutofixActionProps({
}

function StartAutofixAction({
variant = 'primary',
action,
analyticsAction,
analyticsEventKey,
Expand All @@ -100,6 +101,7 @@ function StartAutofixAction({
codingAgentStep?: 'root_cause' | 'solution';
icon?: ReactNode;
tooltip?: string | null;
variant?: 'primary' | 'secondary';
}) {
const organization = useOrganization();
const [isStartingAction, setIsStartingAction] = useState(false);
Expand Down Expand Up @@ -160,6 +162,7 @@ function StartAutofixAction({
disabled={disabled || busy}
onClick={handleClick}
tooltipProps={tooltip ? {title: tooltip} : undefined}
variant={variant}
>
{label}
</Button>
Expand All @@ -178,7 +181,7 @@ function StartAutofixAction({
trigger={(triggerProps, isOpen) => (
<Button
{...triggerProps}
variant="primary"
variant={variant}
size="sm"
icon={<IconChevron direction={isOpen ? 'up' : 'down'} size="xs" />}
aria-label={t('More code fix options')}
Expand All @@ -203,39 +206,21 @@ function StartAutofixAction({
);
}

function ActionButtons({
function NextAutofixStepButton({
autofix,
disabled,
group,
linkedPullRequestsData,
onContinueInSeer,
}: AutofixActionProps) {
variant = 'primary',
}: Omit<AutofixActionProps, 'linkedPullRequestsData'> & {
autofix: ExplorerAutofix;
group: Group;
onContinueInSeer: () => void;
disabled?: boolean;
variant?: 'primary' | 'secondary';
}) {
const {runState} = autofix;
const sections = getOrderedAutofixSections(runState);
const latestOpenPullRequest = linkedPullRequestsData?.pullRequests
.filter(
pullRequest => pullRequest.status === 'open' || pullRequest.status === 'draft'
)
.toSorted((a, b) => Date.parse(b.dateCreated) - Date.parse(a.dateCreated))[0];

if (latestOpenPullRequest) {
return (
<LinkButton
{...getAutofixActionProps({
analyticsEventKey: 'issue_inbox.seer_cta_clicked',
analyticsEventName: 'Issue Inbox: Seer CTA Clicked',
analyticsParams: {destination: 'pull_request'},
group,
})}
external
disabled={disabled}
href={latestOpenPullRequest.externalUrl}
icon={<IconGithub data-test-id="pull-request-github" />}
>
{t('View %s#%s', latestOpenPullRequest.repository.name, latestOpenPullRequest.id)}
</LinkButton>
);
}

if (!runState || sections.length === 0) {
return (
Expand All @@ -249,6 +234,7 @@ function ActionButtons({
group={group}
label={t('Find Root Cause')}
onContinueInSeer={onContinueInSeer}
variant={variant}
/>
);
}
Expand All @@ -271,6 +257,7 @@ function ActionButtons({
disabled={disabled || autofix.isPolling}
icon={<IconSeer />}
onClick={onContinueInSeer}
variant={variant}
>
{runState.pending_user_input?.input_type === 'file_change_approval'
? t('Review Changes')
Expand Down Expand Up @@ -300,6 +287,7 @@ function ActionButtons({
label={t('Retry PR in %s', failedPullRequest.repo_name)}
onContinueInSeer={onContinueInSeer}
tooltip={failedPullRequest.pr_creation_error}
variant={variant}
/>
);
}
Expand Down Expand Up @@ -327,6 +315,7 @@ function ActionButtons({
disabled={disabled}
href={resultLink.url}
icon={<IconOpen />}
variant={variant}
>
{resultLink.label}
</LinkButton>
Expand All @@ -349,14 +338,14 @@ function ActionButtons({
disabled={disabled}
href={codingAgent.agent_url}
icon={<IconOpen />}
variant={variant}
>
{t('Open in %s', getCodingAgentName(codingAgent.provider))}
</LinkButton>
);
}

const nextStep = getAutofixNextStep({sections});

switch (nextStep?.action) {
case 'create_pr':
return (
Expand All @@ -371,6 +360,7 @@ function ActionButtons({
group={group}
label={t('Create PR')}
onContinueInSeer={onContinueInSeer}
variant={variant}
/>
);
case 'code_changes':
Expand All @@ -386,6 +376,7 @@ function ActionButtons({
codingAgentStep="solution"
label={t('Write a Code Fix')}
onContinueInSeer={onContinueInSeer}
variant={variant}
/>
);
case 'solution':
Expand All @@ -401,6 +392,7 @@ function ActionButtons({
codingAgentStep="root_cause"
label={t('Make a Plan')}
onContinueInSeer={onContinueInSeer}
variant={variant}
/>
);
// We are not yet supporting PR iteration
Expand All @@ -418,11 +410,67 @@ function ActionButtons({
icon={<IconRefresh />}
label={t('Restart Autofix')}
onContinueInSeer={onContinueInSeer}
variant={variant}
/>
);
}
}

function ActionButtons({

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i swear the other PR had this change already

autofix,
disabled,
group,
linkedPullRequestsData,
onContinueInSeer,
}: AutofixActionProps) {
const latestOpenPullRequest = linkedPullRequestsData?.pullRequests
.filter(
pullRequest => pullRequest.status === 'open' || pullRequest.status === 'draft'
)
.toSorted((a, b) => Date.parse(b.dateCreated) - Date.parse(a.dateCreated))[0];

if (latestOpenPullRequest) {
return (
<Fragment>
<LinkButton
{...getAutofixActionProps({
analyticsEventKey: 'issue_inbox.seer_cta_clicked',
analyticsEventName: 'Issue Inbox: Seer CTA Clicked',
analyticsParams: {destination: 'pull_request'},
group,
})}
external
disabled={disabled}
href={latestOpenPullRequest.externalUrl}
icon={<IconGithub data-test-id="pull-request-github" />}
>
{t(
'View %s#%s',
latestOpenPullRequest.repository.name,
latestOpenPullRequest.id
)}
</LinkButton>
<NextAutofixStepButton
autofix={autofix}
disabled={disabled}
group={group}
onContinueInSeer={onContinueInSeer}
variant="secondary"
/>
</Fragment>
);
Comment thread
cursor[bot] marked this conversation as resolved.
}

return (
<NextAutofixStepButton
autofix={autofix}
disabled={disabled}
group={group}
onContinueInSeer={onContinueInSeer}
/>
);
}

export function IssuePreviewActions({
autofix,
disabled,
Expand All @@ -437,12 +485,14 @@ export function IssuePreviewActions({
}

return (
<ActionButtons
autofix={autofix}
disabled={disabled}
group={group}
linkedPullRequestsData={linkedPullRequestsData}
onContinueInSeer={onContinueInSeer}
/>
<Flex gap="sm">
<ActionButtons
autofix={autofix}
disabled={disabled}
group={group}
linkedPullRequestsData={linkedPullRequestsData}
onContinueInSeer={onContinueInSeer}
/>{' '}
</Flex>
);
}
Loading