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
@@ -1,5 +1,6 @@
import {useCallback} from 'react';
import {useCallback, useMemo} from 'react';

import type {ProjectSeerPreferences} from 'sentry/components/events/autofix/types';
import useFetchSequentialPages from 'sentry/utils/api/useFetchSequentialPages';
import {
fetchMutation,
Expand All @@ -8,6 +9,7 @@ import {
type UseMutationOptions,
} from 'sentry/utils/queryClient';
import useOrganization from 'sentry/utils/useOrganization';
import useProjects from 'sentry/utils/useProjects';

type AutofixAutomationTuning =
| 'off'
Expand All @@ -18,13 +20,6 @@ type AutofixAutomationTuning =
| 'always' // deprecated
| null; // deprecated

type AutomatedRunStoppingPoint =
| 'root_cause'
| 'solution'
| 'code_changes'
| 'open_pr'
| 'background_agent';

// Mirrors the backend SeerRepoDefinition type
export interface BackendRepository {
external_id: string;
Expand All @@ -46,7 +41,8 @@ export interface BackendRepository {

export type AutofixAutomationSettings = {
autofixAutomationTuning: AutofixAutomationTuning;
automatedRunStoppingPoint: AutomatedRunStoppingPoint;
automatedRunStoppingPoint: ProjectSeerPreferences['automated_run_stopping_point'];
automationHandoff: ProjectSeerPreferences['automation_handoff'];
projectId: string;
reposCount: number;
};
Expand Down Expand Up @@ -80,26 +76,30 @@ type AutofixAutomationUpdate =
| {
autofixAutomationTuning: AutofixAutomationTuning;
projectIds: string[];
automatedRunStoppingPoint?: never | AutomatedRunStoppingPoint;
automatedRunStoppingPoint?:
| never
| ProjectSeerPreferences['automated_run_stopping_point'];
projectRepoMappings?: never | Record<string, BackendRepository[]>;
}
| {
automatedRunStoppingPoint: AutomatedRunStoppingPoint;
automatedRunStoppingPoint: ProjectSeerPreferences['automated_run_stopping_point'];
projectIds: string[];
autofixAutomationTuning?: never | AutofixAutomationTuning;
projectRepoMappings?: never | Record<string, BackendRepository[]>;
}
| {
autofixAutomationTuning: AutofixAutomationTuning;
automatedRunStoppingPoint: AutomatedRunStoppingPoint;
automatedRunStoppingPoint: ProjectSeerPreferences['automated_run_stopping_point'];
projectIds: string[];
projectRepoMappings?: never | Record<string, BackendRepository[]>;
}
| {
projectIds: string[];
projectRepoMappings: Record<string, BackendRepository[]>;
autofixAutomationTuning?: never | AutofixAutomationTuning;
automatedRunStoppingPoint?: never | AutomatedRunStoppingPoint;
automatedRunStoppingPoint?:
| never
| ProjectSeerPreferences['automated_run_stopping_point'];
};

export function useUpdateBulkAutofixAutomationSettings(
Expand All @@ -111,6 +111,12 @@ export function useUpdateBulkAutofixAutomationSettings(
const organization = useOrganization();
const queryClient = useQueryClient();

const {projects} = useProjects();
const projectsById = useMemo(
() => new Map(projects.map(project => [project.id, project])),
[projects]
);

return useMutation<unknown, Error, AutofixAutomationUpdate, unknown>({
mutationFn: (data: AutofixAutomationUpdate) => {
return fetchMutation({
Expand All @@ -124,6 +130,22 @@ export function useUpdateBulkAutofixAutomationSettings(
queryClient.invalidateQueries({
queryKey: [`/organizations/${organization.slug}/autofix/automation-settings/`],
});
const [, , data] = args;
data.projectIds.forEach(projectId => {
const project = projectsById.get(projectId);
if (!project) {
return;
}
// Invalidate the query for ProjectOptions to Settings>Project>Seer details page
queryClient.invalidateQueries({
queryKey: [`/projects/${organization.slug}/${project.slug}/`],
});
// Invalidate the query for SeerPreferences to Settings>Project>Seer details page
queryClient.invalidateQueries({
queryKey: [`/projects/${organization.slug}/${project.slug}/seer/preferences/`],
});
});

options?.onSettled?.(...args);
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ export function useUpdateProjectSeerPreferences(project: Project) {
},
onSettled: () => {
queryClient.invalidateQueries({queryKey});
queryClient.invalidateQueries({
queryKey: [`/organizations/${organization.slug}/autofix/automation-settings/`],
});
},
});
}
7 changes: 1 addition & 6 deletions static/app/components/events/autofix/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -320,12 +320,7 @@ interface SeerAutomationHandoffConfiguration {

export interface ProjectSeerPreferences {
repositories: SeerRepoDefinition[];
automated_run_stopping_point?:
| 'root_cause'
| 'solution'
| 'code_changes'
| 'open_pr'
| 'background_agent';
automated_run_stopping_point?: 'root_cause' | 'solution' | 'code_changes' | 'open_pr';
automation_handoff?: SeerAutomationHandoffConfiguration;
}

Expand Down
24 changes: 12 additions & 12 deletions static/app/views/settings/projectSeer/autofixRepositories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import {DropdownMenu} from 'sentry/components/dropdownMenu';
import {useOrganizationRepositories} from 'sentry/components/events/autofix/preferences/hooks/useOrganizationRepositories';
import {useProjectSeerPreferences} from 'sentry/components/events/autofix/preferences/hooks/useProjectSeerPreferences';
import {useUpdateProjectSeerPreferences} from 'sentry/components/events/autofix/preferences/hooks/useUpdateProjectSeerPreferences';
import type {RepoSettings} from 'sentry/components/events/autofix/types';
import type {
ProjectSeerPreferences,
RepoSettings,
} from 'sentry/components/events/autofix/types';
import LoadingIndicator from 'sentry/components/loadingIndicator';
import Panel from 'sentry/components/panels/panel';
import PanelHeader from 'sentry/components/panels/panelHeader';
Expand Down Expand Up @@ -46,19 +49,16 @@ export function AutofixRepositories({project}: ProjectSeerProps) {
const [repoSettings, setRepoSettings] = useState<Record<string, RepoSettings>>({});
const [showSaveNotice, setShowSaveNotice] = useState(false);

const getDefaultStoppingPoint = useCallback(():
| 'root_cause'
| 'solution'
| 'code_changes'
| 'open_pr' => {
if (organization.features.includes('seat-based-seer-enabled')) {
return organization.autoOpenPrs ? 'open_pr' : 'code_changes';
}
return 'root_cause';
}, [organization.features, organization.autoOpenPrs]);
const getDefaultStoppingPoint =
useCallback((): ProjectSeerPreferences['automated_run_stopping_point'] => {
if (organization.features.includes('seat-based-seer-enabled')) {
return organization.autoOpenPrs ? 'open_pr' : 'code_changes';
}
return 'root_cause';
}, [organization.features, organization.autoOpenPrs]);

const [automatedRunStoppingPoint, setAutomatedRunStoppingPoint] = useState<
'root_cause' | 'solution' | 'code_changes' | 'open_pr' | 'background_agent'
ProjectSeerPreferences['automated_run_stopping_point']
>(getDefaultStoppingPoint());

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ interface Props {
export default function AutoTriggeredFixesToggle({canWrite, project}: Props) {
const {mutate: updateProject} = useUpdateProject(project);

const isEnabled = Boolean(
const isAutoFixEnabled = Boolean(
project.autofixAutomationTuning && project.autofixAutomationTuning !== 'off'
);

Expand All @@ -28,11 +28,10 @@ export default function AutoTriggeredFixesToggle({canWrite, project}: Props) {
help={t(
'Automatically analyze highly actionable issues, and create a root cause analysis without a user needing to prompt it.'
)}
value={isEnabled}
value={isAutoFixEnabled}
onChange={value => {
const newValue: Project['autofixAutomationTuning'] = value ? 'medium' : 'off';
updateProject(
{autofixAutomationTuning: newValue},
{autofixAutomationTuning: value ? 'medium' : 'off'},
{
onSuccess: () =>
addSuccessMessage(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,15 @@ function CursorIntegrationFields({
}: Props) {
const {mutate: updateProjectSeerPreferences} = useUpdateProjectSeerPreferences(project);

const isBackgroundAgentEnabled = Boolean(preference?.automation_handoff);
const isAutoTriggeredFixesEnabled = Boolean(
const isAutoFixEnabled = Boolean(
Comment thread
ryan953 marked this conversation as resolved.
project.autofixAutomationTuning && project.autofixAutomationTuning !== 'off'
);
const isBackgroundAgentEnabled = Boolean(preference?.automation_handoff);

const isDisabled =
!canWrite || !isAutoTriggeredFixesEnabled || !isBackgroundAgentEnabled;
const isDisabled = !canWrite || !isAutoFixEnabled || !isBackgroundAgentEnabled;

let disabledReason: string | null = null;
if (!isAutoTriggeredFixesEnabled) {
if (!isAutoFixEnabled) {
disabledReason = t('Turn on Auto-Triggered Fixes to use this feature.');
} else if (!isBackgroundAgentEnabled) {
disabledReason = t('This setting is only available when using background agents.');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,19 @@ interface Props {
export default function SeerAgentSection({canWrite, project, preference}: Props) {
const {mutate: updateProjectSeerPreferences} = useUpdateProjectSeerPreferences(project);

const isAutoCreatePREnabled = Boolean(
const isAutoFixEnabled = Boolean(
Comment thread
ryan953 marked this conversation as resolved.
project.autofixAutomationTuning && project.autofixAutomationTuning !== 'off'
);
const isCreatePrEnabled = Boolean(
preference?.automated_run_stopping_point &&
preference.automated_run_stopping_point !== 'code_changes'
);

const isBackgroundAgentEnabled = Boolean(preference?.automation_handoff);
const isAutoTriggeredFixesEnabled = Boolean(
project.autofixAutomationTuning && project.autofixAutomationTuning !== 'off'
);

const isDisabled =
!canWrite || !isAutoTriggeredFixesEnabled || isBackgroundAgentEnabled;
const isDisabled = !canWrite || !isAutoFixEnabled || isBackgroundAgentEnabled;

let disabledReason: string | null = null;
if (!isAutoTriggeredFixesEnabled) {
if (!isAutoFixEnabled) {
disabledReason = t('Turn on Auto-Triggered Fixes to use this feature.');
} else if (isBackgroundAgentEnabled) {
disabledReason = t('This setting is not available when using background agents.');
Expand All @@ -52,7 +50,7 @@ export default function SeerAgentSection({canWrite, project, preference}: Props)
docsLink: <ExternalLink href="https://docs.sentry.io/product/ai-in-sentry/" />,
}
)}
value={isAutoCreatePREnabled}
value={isCreatePrEnabled}
onChange={value => {
const newValue: ProjectSeerPreferences['automated_run_stopping_point'] = value
? 'open_pr'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,27 @@ import LoadingIndicator from 'sentry/components/loadingIndicator';
import {SimpleTable} from 'sentry/components/tables/simpleTable';
import {IconSearch} from 'sentry/icons/iconSearch';
import {t, tct} from 'sentry/locale';
import type {Organization} from 'sentry/types/organization';
import type {Project} from 'sentry/types/project';
import type {Sort} from 'sentry/utils/discover/fields';
import {ListItemCheckboxProvider} from 'sentry/utils/list/useListItemCheckboxState';
import type {ApiQueryKey} from 'sentry/utils/queryClient';
import {parseAsSort} from 'sentry/utils/queryString';
import useOrganization from 'sentry/utils/useOrganization';
import useProjects from 'sentry/utils/useProjects';

import ProjectTableHeader from 'getsentry/views/seerAutomation/components/projectTable/seerProjectTableHeader';
import SeerProjectTableRow from 'getsentry/views/seerAutomation/components/projectTable/seerProjectTableRow';

function getDefaultAutofixSettings(
organization: Organization,
projectId: string
): AutofixAutomationSettings {
function getDefaultAutofixSettings(projectId: string): AutofixAutomationSettings {
return {
autofixAutomationTuning: organization.defaultAutofixAutomationTuning ?? 'off',
automatedRunStoppingPoint: organization.autoOpenPrs ? 'open_pr' : 'code_changes',
autofixAutomationTuning: 'off',
automatedRunStoppingPoint: 'code_changes',
automationHandoff: undefined,
projectId,
reposCount: 0,
};
}

export default function SeerProjectTable() {
const organization = useOrganization();
const {projects, fetching, fetchError} = useProjects();

const {pages: autofixAutomationSettings, isFetching: isFetchingSettings} =
Expand Down Expand Up @@ -184,7 +179,7 @@ export default function SeerProjectTable() {
project={project}
isFetchingSettings={isFetchingSettings}
autofixSettings={{
...getDefaultAutofixSettings(organization, project.id),
...getDefaultAutofixSettings(project.id),
...autofixSettingsByProjectId.get(project.id),
...mutationData[project.id],
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ const COLUMNS = [
{title: t('PR Creation'), key: 'pr_creation'},
{
title: (
<Flex gap="sm">
<Flex gap="sm" align="center">
{t('Background Agent')}
<QuestionTooltip
title={t(
'Background agent delegation can only be enabled on the individual project settings page. Background agents can have their own settings that are not shown here.'
'Background agent delegation can only be changed on the individual project settings page. Background agents have more settings that are not shown here.'
)}
size="xs"
/>
Expand Down
Loading
Loading