@@ -23,6 +23,7 @@ import {
23
23
FeaturesFormikValues ,
24
24
CustomValueFormikValues ,
25
25
ImputationFormikValues ,
26
+ RuleFormikValues ,
26
27
} from '../../ConfigureModel/models/interfaces' ;
27
28
import { INITIAL_MODEL_CONFIGURATION_VALUES } from '../../ConfigureModel/utils/constants' ;
28
29
import {
@@ -32,6 +33,11 @@ import {
32
33
import {
33
34
ImputationMethod ,
34
35
ImputationOption ,
36
+ Condition ,
37
+ Rule ,
38
+ ThresholdType ,
39
+ Operator ,
40
+ Action ,
35
41
} from '../../../models/types' ;
36
42
import {
37
43
SparseDataOptionValue
@@ -218,6 +224,11 @@ export const focusOnImputationOption = () => {
218
224
component ?. focus ( ) ;
219
225
} ;
220
226
227
+ export const focusOnSuppressionRules = ( ) => {
228
+ const component = document . getElementById ( 'suppressionRules' ) ;
229
+ component ?. focus ( ) ;
230
+ } ;
231
+
221
232
export const getShingleSizeFromObject = ( obj : object ) => {
222
233
return get ( obj , 'shingleSize' , DEFAULT_SHINGLE_SIZE ) ;
223
234
} ;
@@ -269,6 +280,7 @@ export function modelConfigurationToFormik(
269
280
categoryField : get ( detector , 'categoryField' , [ ] ) ,
270
281
shingleSize : get ( detector , 'shingleSize' , DEFAULT_SHINGLE_SIZE ) ,
271
282
imputationOption : imputationFormikValues ,
283
+ suppressionRules : rulesToFormik ( detector . rules ) ,
272
284
} ;
273
285
}
274
286
@@ -317,6 +329,7 @@ export function formikToModelConfiguration(
317
329
? values . categoryField
318
330
: undefined ,
319
331
imputationOption : formikToImputationOption ( values . imputationOption ) ,
332
+ rules : formikToRules ( values . suppressionRules ) ,
320
333
} as Detector ;
321
334
322
335
return detectorBody ;
@@ -425,3 +438,138 @@ export const getCustomValueStrArray = (imputationMethodStr : string, detector: D
425
438
}
426
439
return [ ]
427
440
}
441
+
442
+ export const getSuppressionRulesArray = ( detector : Detector ) : string [ ] => {
443
+ if ( ! detector . rules || detector . rules . length === 0 ) {
444
+ return [ ] ; // Return an empty array if there are no rules
445
+ }
446
+
447
+ return detector . rules . flatMap ( ( rule ) => {
448
+ // Convert each condition to a readable string
449
+ return rule . conditions . map ( ( condition ) => {
450
+ const featureName = condition . featureName ;
451
+ const thresholdType = condition . thresholdType ;
452
+ let value = condition . value ;
453
+ const isPercentage = thresholdType === ThresholdType . ACTUAL_OVER_EXPECTED_RATIO || thresholdType === ThresholdType . EXPECTED_OVER_ACTUAL_RATIO ;
454
+
455
+ // If it is a percentage, multiply by 100
456
+ if ( isPercentage ) {
457
+ value *= 100 ;
458
+ }
459
+
460
+ // Determine whether it is "above" or "below" based on ThresholdType
461
+ const aboveOrBelow = thresholdType === ThresholdType . ACTUAL_OVER_EXPECTED_MARGIN || thresholdType === ThresholdType . ACTUAL_OVER_EXPECTED_RATIO ? 'above' : 'below' ;
462
+
463
+ // Construct the formatted string
464
+ return `Ignore anomalies for feature "${ featureName } " with no more than ${ value } ${ isPercentage ? '%' : '' } ${ aboveOrBelow } expected value.` ;
465
+ } ) ;
466
+ } ) ;
467
+ } ;
468
+
469
+
470
+ // Convert RuleFormikValues[] to Rule[]
471
+ export const formikToRules = ( formikValues ?: RuleFormikValues [ ] ) : Rule [ ] | undefined => {
472
+ if ( ! formikValues || formikValues . length === 0 ) {
473
+ return undefined ; // Return undefined for undefined or empty input
474
+ }
475
+
476
+ return formikValues . map ( ( formikValue ) => {
477
+ const conditions : Condition [ ] = [ ] ;
478
+
479
+ // Determine the threshold type based on aboveBelow and the threshold type (absolute or relative)
480
+ const getThresholdType = ( aboveBelow : string , isAbsolute : boolean ) : ThresholdType => {
481
+ if ( isAbsolute ) {
482
+ return aboveBelow === 'above'
483
+ ? ThresholdType . ACTUAL_OVER_EXPECTED_MARGIN
484
+ : ThresholdType . EXPECTED_OVER_ACTUAL_MARGIN ;
485
+ } else {
486
+ return aboveBelow === 'above'
487
+ ? ThresholdType . ACTUAL_OVER_EXPECTED_RATIO
488
+ : ThresholdType . EXPECTED_OVER_ACTUAL_RATIO ;
489
+ }
490
+ } ;
491
+
492
+ // Check if absoluteThreshold is provided, create a condition
493
+ if ( formikValue . absoluteThreshold !== undefined && formikValue . absoluteThreshold !== 0 && formikValue . absoluteThreshold !== null
494
+ && typeof formikValue . absoluteThreshold === 'number' && // Check if it's a number
495
+ ! isNaN ( formikValue . absoluteThreshold ) && // Ensure it's not NaN
496
+ formikValue . absoluteThreshold > 0 // Check if it's positive
497
+ ) {
498
+ conditions . push ( {
499
+ featureName : formikValue . featureName ,
500
+ thresholdType : getThresholdType ( formikValue . aboveBelow , true ) ,
501
+ operator : Operator . LTE ,
502
+ value : formikValue . absoluteThreshold ,
503
+ } ) ;
504
+ }
505
+
506
+ // Check if relativeThreshold is provided, create a condition
507
+ if ( formikValue . relativeThreshold !== undefined && formikValue . relativeThreshold !== 0 && formikValue . relativeThreshold !== null
508
+ && typeof formikValue . relativeThreshold === 'number' && // Check if it's a number
509
+ ! isNaN ( formikValue . relativeThreshold ) && // Ensure it's not NaN
510
+ formikValue . relativeThreshold > 0 // Check if it's positive
511
+ ) {
512
+ conditions . push ( {
513
+ featureName : formikValue . featureName ,
514
+ thresholdType : getThresholdType ( formikValue . aboveBelow , false ) ,
515
+ operator : Operator . LTE ,
516
+ value : formikValue . relativeThreshold / 100 , // Convert percentage to decimal,
517
+ } ) ;
518
+ }
519
+
520
+ return {
521
+ action : Action . IGNORE_ANOMALY ,
522
+ conditions,
523
+ } ;
524
+ } ) ;
525
+ } ;
526
+
527
+ // Convert Rule[] to RuleFormikValues[]
528
+ export const rulesToFormik = ( rules ?: Rule [ ] ) : RuleFormikValues [ ] => {
529
+ if ( ! rules || rules . length === 0 ) {
530
+ return [ ] ; // Return empty array for undefined or empty input
531
+ }
532
+
533
+ return rules . map ( ( rule ) => {
534
+ // Start with default values
535
+ const formikValue : RuleFormikValues = {
536
+ featureName : '' ,
537
+ absoluteThreshold : undefined ,
538
+ relativeThreshold : undefined ,
539
+ aboveBelow : 'above' , // Default to 'above', adjust as needed
540
+ } ;
541
+
542
+ // Loop through conditions to populate formikValue
543
+ rule . conditions . forEach ( ( condition ) => {
544
+ formikValue . featureName = condition . featureName ;
545
+
546
+ // Determine the value and type of threshold
547
+ switch ( condition . thresholdType ) {
548
+ case ThresholdType . ACTUAL_OVER_EXPECTED_MARGIN :
549
+ formikValue . absoluteThreshold = condition . value ;
550
+ formikValue . aboveBelow = 'above' ;
551
+ break ;
552
+ case ThresholdType . EXPECTED_OVER_ACTUAL_MARGIN :
553
+ formikValue . absoluteThreshold = condition . value ;
554
+ formikValue . aboveBelow = 'below' ;
555
+ break ;
556
+ case ThresholdType . ACTUAL_OVER_EXPECTED_RATIO :
557
+ // *100 to convert to percentage
558
+ formikValue . relativeThreshold = condition . value * 100 ;
559
+ formikValue . aboveBelow = 'above' ;
560
+ break ;
561
+ case ThresholdType . EXPECTED_OVER_ACTUAL_RATIO :
562
+ // *100 to convert to percentage
563
+ formikValue . relativeThreshold = condition . value * 100 ;
564
+ formikValue . aboveBelow = 'below' ;
565
+ break ;
566
+ default :
567
+ break ;
568
+ }
569
+ } ) ;
570
+
571
+ return formikValue ;
572
+ } ) ;
573
+ } ;
574
+
575
+
0 commit comments