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 @@ -95,6 +95,7 @@ export function ProjectAddRepoModal({Header, Body, Footer, title, closeModal}: P
.min(1, {message: t('Please add at least one repository')}),
agentOption: z.custom<AutofixAgentSelectOption>(),
stoppingPoint: z.enum(['off', 'root_cause', 'plan', 'create_pr']),
prIteration: z.boolean(),
});

const saveMutation = useMutateAutofixProject();
Expand All @@ -108,6 +109,7 @@ export function ProjectAddRepoModal({Header, Body, Footer, title, closeModal}: P
repoEntries: [] as Array<{branch: string; repoId: string}>,
agentOption,
stoppingPoint,
prIteration: true,
},
validators: {
onMount: formSchema.extend({
Expand Down Expand Up @@ -391,6 +393,24 @@ export function ProjectAddRepoModal({Header, Body, Footer, title, closeModal}: P
</field.Layout.Row>
)}
</form.AppField>

<Separator orientation="horizontal" />

<form.AppField name="prIteration">
{field => (
<field.Layout.Row
label={t('Auto-Iterate on PRs')}
hintText={t(
'After opening a PR, Seer automatically pushes fixes when CI checks fail. You can still ask Seer to iterate on a PR yourself.'
)}
>
<field.Switch
checked={field.state.value}
onChange={field.handleChange}
/>
</field.Layout.Row>
)}
</form.AppField>
</Stack>
</Body>
<Footer>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ describe('SeerProjectTable', () => {
autoCreatePr: null,
automationTuning: 'off',
scannerAutomation: false,
prIteration: true,
reposCount: 1,
},
],
Expand Down Expand Up @@ -188,6 +189,30 @@ describe('SeerProjectTable', () => {
expect(errorSpy).not.toHaveBeenCalled();
});

it('saves the PR iteration toggle for a project', async () => {
const settingsPut = MockApiClient.addMockResponse({
url: `/projects/${organization.slug}/${project.slug}/seer/settings/`,
method: 'PUT',
});

render(<ExampleSeerProjectTable />, {organization});

expect(await screen.findByText('Auto-Iterate on PRs')).toBeInTheDocument();
const toggle = await screen.findByRole('checkbox', {
name: 'Auto-iterate on PRs for project-slug',
});
expect(toggle).toBeChecked();

await userEvent.click(toggle);

await waitFor(() =>
expect(settingsPut).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({data: {prIteration: false}})
)
);
});

it('disables adding a project without organization write access', async () => {
render(<ExampleSeerProjectTable />, {
organization: OrganizationFixture({slug: organization.slug, access: []}),
Expand Down
23 changes: 23 additions & 0 deletions static/app/components/seer/projectTable/seerProjectTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ const TABLE_COLUMNS: TableColumnConfig[] = [
{key: 'repos', width: '74px'},
{key: 'fixes', width: '1fr'},
{key: 'automation_steps', width: '1fr'},
{key: 'pr_iteration', width: 'max-content'},
];

export function SeerProjectTable() {
Expand Down Expand Up @@ -311,6 +312,28 @@ export function SeerProjectTable() {
</AutoSaveForm>
</Stack>
</InfiniteTable.RowCell>
<InfiniteTable.RowCell justify="center">
<AutoSaveForm
name="prIteration"
schema={seerProjectSettingsSchema}
initialValue={item.prIteration}
mutationOptions={getMutateSeerProjectSettingsOptions({
organization,
project: {slug: item.projectSlug},
queryClient,
})}
>
{field => (
<field.Switch
aria-label={t('Auto-iterate on PRs for %s', item.projectSlug)}
size="sm"
checked={field.state.value}
onChange={field.handleChange}
disabled={!canWrite}
/>
)}
</AutoSaveForm>
</InfiniteTable.RowCell>
</InfiniteTable.Row>
)}
</InfiniteTable.Body>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,20 @@ const COLUMNS = [
key: 'automation_steps',
sortKey: 'stoppingPoint',
},
{
title: (
<Flex gap="sm" align="center">
{t('Auto-Iterate on PRs')}
<InfoTip
title={t(
'After opening a PR, Seer automatically pushes fixes when CI checks fail. You can still ask Seer to iterate on a PR yourself.'
)}
/>
</Flex>
),
key: 'pr_iteration',
sortKey: undefined,
},
];

export function ProjectTableHeader({mutableSearch, onSortClick, settings, sort}: Props) {
Expand Down
1 change: 1 addition & 0 deletions static/app/utils/seer/seerProjectSettings.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ function makeResponseFixture(
autoCreatePr: null,
automationTuning: 'medium',
integrationId: null,
prIteration: true,
projectId: '1',
projectSlug: 'project-slug',
reposCount: 1,
Expand Down
4 changes: 4 additions & 0 deletions static/app/utils/seer/seerProjectSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export const seerProjectSettingsSchema = z.object({
return isPreferredAgentProvider(provider);
}),
stoppingPoint: z.enum(['off', 'root_cause', 'solution', 'code_changes', 'open_pr']),
prIteration: z.boolean(),
});

export function getSeerProjectSettingsQueryOptions({
Expand Down Expand Up @@ -158,6 +159,9 @@ export function getMutateSeerProjectSettingsOptions({
if (data.autoCreatePr !== undefined) {
jsonUpdates.autoCreatePr = data.autoCreatePr;
}
if (data.prIteration !== undefined) {
jsonUpdates.prIteration = data.prIteration;
}

queryClient.setQueryData(
queryKey,
Expand Down
2 changes: 2 additions & 0 deletions static/app/utils/seer/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export type SeerProjectSettingUpdatePayload = {
autoCreatePr?: boolean;
automationTuning?: UserFacingAutomationTuning;
integrationId?: string;
prIteration?: boolean;
scannerAutomation?: boolean;
stoppingPoint?: SeerAutofixStoppingPoint;
};
Expand All @@ -55,6 +56,7 @@ export type SeerProjectSettingResponse = {
autoCreatePr: boolean | null;
automationTuning: InternalAutomationTuning;
integrationId: string | null;
prIteration: boolean;
projectId: string;
projectSlug: string;
reposCount: number;
Expand Down
3 changes: 3 additions & 0 deletions static/app/utils/seer/useMutateAutofixProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type TVariables = {
repoId: string;
}>;
stoppingPoint: UserFacingStoppingPoint;
prIteration?: boolean;
};

/**
Expand Down Expand Up @@ -66,6 +67,7 @@ export function useMutateAutofixProject() {
repoEntries,
agentOption,
stoppingPoint,
prIteration,
}: TVariables): Promise<void> => {
const tuning = getTuningFromStoppingPoint(stoppingPoint);
const {agent, integrationId} = parseAgentOption(agentOption, knownAgents);
Expand Down Expand Up @@ -131,6 +133,7 @@ export function useMutateAutofixProject() {
automationTuning: tuning,
...(stoppingPointValue ? {stoppingPoint: stoppingPointValue} : {}),
...(handoff ? {autoCreatePr: handoff.auto_create_pr} : {}),
...(prIteration === undefined ? {} : {prIteration}),
},
});
} catch (error) {
Expand Down
Loading