diff --git a/static/app/views/detectors/components/forms/metric/metricFormData.tsx b/static/app/views/detectors/components/forms/metric/metricFormData.tsx index ef068a97c0a0a6..2f0b409add555f 100644 --- a/static/app/views/detectors/components/forms/metric/metricFormData.tsx +++ b/static/app/views/detectors/components/forms/metric/metricFormData.tsx @@ -399,6 +399,14 @@ function processDetectorConditions( conditionType = mainCondition.type; } + // Determine resolution strategy: automatic if OK threshold matches warning or critical + const resolutionValue = okCondition?.comparison ?? undefined; + const computedResolutionStrategy: 'automatic' | 'manual' = + defined(resolutionValue) && + ![mainCondition?.comparison, highCondition?.comparison].includes(resolutionValue) + ? 'manual' + : 'automatic'; + return { initialPriorityLevel, conditionValue: @@ -410,8 +418,7 @@ function processDetectorConditions( typeof highCondition?.comparison === 'number' ? highCondition.comparison.toString() : '', - resolutionStrategy: - typeof okCondition?.comparison === 'number' ? 'manual' : 'automatic', + resolutionStrategy: computedResolutionStrategy, resolutionValue: typeof okCondition?.comparison === 'number' ? okCondition.comparison.toString() diff --git a/static/app/views/detectors/edit.spec.tsx b/static/app/views/detectors/edit.spec.tsx index 3871b25dfd84a4..d090a5d53ece76 100644 --- a/static/app/views/detectors/edit.spec.tsx +++ b/static/app/views/detectors/edit.spec.tsx @@ -19,6 +19,11 @@ import { import OrganizationStore from 'sentry/stores/organizationStore'; import ProjectsStore from 'sentry/stores/projectsStore'; +import { + DataConditionGroupLogicType, + DataConditionType, + DetectorPriorityLevel, +} from 'sentry/types/workflowEngine/dataConditions'; import {Dataset, EventTypes} from 'sentry/views/alerts/rules/metric/types'; import {SnubaQueryType} from 'sentry/views/detectors/components/forms/metric/metricFormData'; import DetectorEdit from 'sentry/views/detectors/edit'; @@ -379,6 +384,54 @@ describe('DetectorEdit', () => { expect(screen.getByRole('option', {name: 'Last 7 days'})).toBeInTheDocument(); }); + it('sets resolution method to Automatic when OK equals critical threshold', async () => { + const detectorWithOkEqualsHigh = MetricDetectorFixture({ + conditionGroup: { + id: 'cg2', + logicType: DataConditionGroupLogicType.ANY, + conditions: [ + { + id: 'c-main', + type: DataConditionType.GREATER, + comparison: 5, + conditionResult: DetectorPriorityLevel.MEDIUM, + }, + { + id: 'c-high', + type: DataConditionType.GREATER, + comparison: 10, + conditionResult: DetectorPriorityLevel.HIGH, + }, + { + id: 'c-ok', + type: DataConditionType.LESS, + comparison: 10, // equals high threshold + conditionResult: DetectorPriorityLevel.OK, + }, + ], + }, + dataSources: [SnubaQueryDataSourceFixture()], + }); + + MockApiClient.addMockResponse({ + url: `/organizations/${organization.slug}/detectors/${detectorWithOkEqualsHigh.id}/`, + body: detectorWithOkEqualsHigh, + }); + + render(, {organization, initialRouterConfig}); + + expect( + await screen.findByRole('link', {name: detectorWithOkEqualsHigh.name}) + ).toBeInTheDocument(); + + expect(screen.getByRole('radio', {name: 'Automatic'})).toBeChecked(); + + // Switching to Manual should reveal prefilled resolution input with the current OK value + await userEvent.click(screen.getByRole('radio', {name: 'Manual'})); + const resolutionInput = await screen.findByLabelText('Resolution threshold'); + expect(resolutionInput).toHaveValue(10); + }); + it('includes comparisonDelta in events-stats request when using percent change detection', async () => { MockApiClient.addMockResponse({ url: `/organizations/${organization.slug}/detectors/${mockDetector.id}/`,