55 DetectorPriorityLevel ,
66} from 'sentry/types/workflowEngine/dataConditions' ;
77import type {
8+ AnomalyDetectionComparison ,
89 Detector ,
910 MetricCondition ,
1011 MetricConditionGroup ,
@@ -183,6 +184,22 @@ interface NewDataSource {
183184 timeWindow : number ;
184185}
185186
187+ function createAnomalyDetectionCondition (
188+ data : Pick < MetricDetectorFormData , 'sensitivity' | 'thresholdType' >
189+ ) : NewConditionGroup [ 'conditions' ] {
190+ return [
191+ {
192+ type : DataConditionType . ANOMALY_DETECTION ,
193+ comparison : {
194+ sensitivity : data . sensitivity ,
195+ seasonality : 'auto' as const ,
196+ thresholdType : data . thresholdType ,
197+ } ,
198+ conditionResult : DetectorPriorityLevel . HIGH ,
199+ } ,
200+ ] ;
201+ }
202+
186203/**
187204 * Creates escalation conditions based on priority level and available thresholds
188205 */
@@ -303,30 +320,30 @@ function createDataSource(data: MetricDetectorFormData): NewDataSource {
303320export function metricDetectorFormDataToEndpointPayload (
304321 data : MetricDetectorFormData
305322) : MetricDetectorUpdatePayload {
306- const conditions = createConditions ( data ) ;
323+ const conditions =
324+ data . detectionType === 'dynamic'
325+ ? createAnomalyDetectionCondition ( data )
326+ : createConditions ( data ) ;
327+
307328 const dataSource = createDataSource ( data ) ;
308329
309330 // Create config based on detection type
310331 let config : MetricDetectorConfig ;
311332 switch ( data . detectionType ) {
312333 case 'percent' :
313334 config = {
314- thresholdPeriod : 1 ,
315335 detectionType : 'percent' ,
316336 comparisonDelta : data . conditionComparisonAgo || 3600 ,
317337 } ;
318338 break ;
319339 case 'dynamic' :
320340 config = {
321- thresholdPeriod : 1 ,
322341 detectionType : 'dynamic' ,
323- sensitivity : data . sensitivity ,
324342 } ;
325343 break ;
326344 case 'static' :
327345 default :
328346 config = {
329- thresholdPeriod : 1 ,
330347 detectionType : 'static' ,
331348 } ;
332349 break ;
@@ -423,6 +440,24 @@ function processDetectorConditions(
423440 } ;
424441}
425442
443+ function getAnomalyCondition ( detector : MetricDetector ) : AnomalyDetectionComparison {
444+ const anomalyCondition = detector . conditionGroup ?. conditions ?. find (
445+ condition => condition . type === DataConditionType . ANOMALY_DETECTION
446+ ) ;
447+
448+ const comparison = anomalyCondition ?. comparison ;
449+ if ( typeof comparison === 'object' ) {
450+ return comparison ;
451+ }
452+
453+ // Fallback to default values
454+ return {
455+ sensitivity : AlertRuleSensitivity . MEDIUM ,
456+ seasonality : 'auto' ,
457+ thresholdType : AlertRuleThresholdType . ABOVE_AND_BELOW ,
458+ } ;
459+ }
460+
426461/**
427462 * Converts a Detector to MetricDetectorFormData for editing
428463 */
@@ -444,6 +479,7 @@ export function metricSavedDetectorToFormData(
444479 : DetectorDataset . SPANS ;
445480
446481 const datasetConfig = getDatasetConfig ( dataset ) ;
482+ const anomalyCondition = getAnomalyCondition ( detector ) ;
447483
448484 return {
449485 // Core detector fields
@@ -471,15 +507,8 @@ export function metricSavedDetectorToFormData(
471507 ? detector . config . comparisonDelta
472508 : DEFAULT_THRESHOLD_METRIC_FORM_DATA . conditionComparisonAgo ,
473509
474- // Dynamic fields - extract from config for dynamic detectors
475- sensitivity :
476- detector . config . detectionType === 'dynamic' && defined ( detector . config . sensitivity )
477- ? detector . config . sensitivity
478- : DEFAULT_THRESHOLD_METRIC_FORM_DATA . sensitivity ,
479- thresholdType :
480- detector . config . detectionType === 'dynamic' &&
481- defined ( detector . config . thresholdType )
482- ? detector . config . thresholdType
483- : DEFAULT_THRESHOLD_METRIC_FORM_DATA . thresholdType ,
510+ // Dynamic fields - extract from anomaly detection condition for dynamic detectors
511+ sensitivity : anomalyCondition . sensitivity ,
512+ thresholdType : anomalyCondition . thresholdType ,
484513 } ;
485514}
0 commit comments