44 * you may not use this file except in compliance with the Elastic License.
55 */
66
7- import { debounce , pick } from 'lodash' ;
7+ import { debounce , pick , omit } from 'lodash' ;
88import { Unit } from '@elastic/datemath' ;
99import React , { useCallback , useMemo , useEffect , useState , ChangeEvent } from 'react' ;
1010import { IFieldType } from 'src/plugins/data/public' ;
@@ -20,6 +20,7 @@ import {
2020 EuiCheckbox ,
2121 EuiToolTip ,
2222 EuiIcon ,
23+ EuiHealth ,
2324} from '@elastic/eui' ;
2425import { FormattedMessage } from '@kbn/i18n/react' ;
2526import { i18n } from '@kbn/i18n' ;
@@ -422,9 +423,24 @@ const StyledExpression = euiStyled.div`
422423 padding: 0 4px;
423424` ;
424425
426+ const StyledHealth = euiStyled ( EuiHealth ) `
427+ margin-left: 4px;
428+ ` ;
429+
425430export const ExpressionRow : React . FC < ExpressionRowProps > = ( props ) => {
426431 const { setAlertParams, expression, errors, expressionId, remove, canDelete, fields } = props ;
427- const { metric, comparator = Comparator . GT , threshold = [ ] , customMetric } = expression ;
432+ const {
433+ metric,
434+ comparator = Comparator . GT ,
435+ threshold = [ ] ,
436+ customMetric,
437+ warningThreshold = [ ] ,
438+ warningComparator,
439+ } = expression ;
440+
441+ const [ displayWarningThreshold , setDisplayWarningThreshold ] = useState (
442+ Boolean ( warningThreshold ?. length )
443+ ) ;
428444
429445 const updateMetric = useCallback (
430446 ( m ?: SnapshotMetricType | string ) => {
@@ -451,6 +467,13 @@ export const ExpressionRow: React.FC<ExpressionRowProps> = (props) => {
451467 [ expressionId , expression , setAlertParams ]
452468 ) ;
453469
470+ const updateWarningComparator = useCallback (
471+ ( c ?: string ) => {
472+ setAlertParams ( expressionId , { ...expression , warningComparator : c as Comparator } ) ;
473+ } ,
474+ [ expressionId , expression , setAlertParams ]
475+ ) ;
476+
454477 const updateThreshold = useCallback (
455478 ( t ) => {
456479 if ( t . join ( ) !== expression . threshold . join ( ) ) {
@@ -460,6 +483,58 @@ export const ExpressionRow: React.FC<ExpressionRowProps> = (props) => {
460483 [ expressionId , expression , setAlertParams ]
461484 ) ;
462485
486+ const updateWarningThreshold = useCallback (
487+ ( t ) => {
488+ if ( t . join ( ) !== expression . warningThreshold ?. join ( ) ) {
489+ setAlertParams ( expressionId , { ...expression , warningThreshold : t } ) ;
490+ }
491+ } ,
492+ [ expressionId , expression , setAlertParams ]
493+ ) ;
494+
495+ const toggleWarningThreshold = useCallback ( ( ) => {
496+ if ( ! displayWarningThreshold ) {
497+ setDisplayWarningThreshold ( true ) ;
498+ setAlertParams ( expressionId , {
499+ ...expression ,
500+ warningComparator : comparator ,
501+ warningThreshold : [ ] ,
502+ } ) ;
503+ } else {
504+ setDisplayWarningThreshold ( false ) ;
505+ setAlertParams ( expressionId , omit ( expression , 'warningComparator' , 'warningThreshold' ) ) ;
506+ }
507+ } , [
508+ displayWarningThreshold ,
509+ setDisplayWarningThreshold ,
510+ setAlertParams ,
511+ comparator ,
512+ expression ,
513+ expressionId ,
514+ ] ) ;
515+
516+ const criticalThresholdExpression = (
517+ < ThresholdElement
518+ comparator = { comparator }
519+ threshold = { threshold }
520+ updateComparator = { updateComparator }
521+ updateThreshold = { updateThreshold }
522+ errors = { errors . critical as IErrorObject }
523+ metric = { metric }
524+ />
525+ ) ;
526+
527+ const warningThresholdExpression = displayWarningThreshold && (
528+ < ThresholdElement
529+ comparator = { warningComparator || comparator }
530+ threshold = { warningThreshold }
531+ updateComparator = { updateWarningComparator }
532+ updateThreshold = { updateWarningThreshold }
533+ errors = { errors . warning as IErrorObject }
534+ metric = { metric }
535+ />
536+ ) ;
537+
463538 const ofFields = useMemo ( ( ) => {
464539 let myMetrics = hostMetricTypes ;
465540
@@ -514,25 +589,62 @@ export const ExpressionRow: React.FC<ExpressionRowProps> = (props) => {
514589 fields = { fields }
515590 />
516591 </ StyledExpression >
517- < StyledExpression >
518- < ThresholdExpression
519- thresholdComparator = { comparator || Comparator . GT }
520- threshold = { threshold }
521- onChangeSelectedThresholdComparator = { updateComparator }
522- onChangeSelectedThreshold = { updateThreshold }
523- errors = { errors }
524- />
525- </ StyledExpression >
526- { metric && (
527- < div
528- style = { {
529- alignSelf : 'center' ,
530- } }
531- >
532- < EuiText size = { 's' } > { metricUnit [ metric ] ?. label || '' } </ EuiText >
533- </ div >
534- ) }
592+ { ! displayWarningThreshold && criticalThresholdExpression }
535593 </ StyledExpressionRow >
594+ { displayWarningThreshold && (
595+ < >
596+ < StyledExpressionRow >
597+ { criticalThresholdExpression }
598+ < StyledHealth color = "danger" >
599+ < FormattedMessage
600+ id = "xpack.infra.metrics.alertFlyout.criticalThreshold"
601+ defaultMessage = "Alert"
602+ />
603+ </ StyledHealth >
604+ </ StyledExpressionRow >
605+ < StyledExpressionRow >
606+ { warningThresholdExpression }
607+ < StyledHealth color = "warning" >
608+ < FormattedMessage
609+ id = "xpack.infra.metrics.alertFlyout.warningThreshold"
610+ defaultMessage = "Warning"
611+ />
612+ </ StyledHealth >
613+ < EuiButtonIcon
614+ aria-label = { i18n . translate (
615+ 'xpack.infra.metrics.alertFlyout.removeWarningThreshold' ,
616+ {
617+ defaultMessage : 'Remove warningThreshold' ,
618+ }
619+ ) }
620+ iconSize = "s"
621+ color = { 'subdued' }
622+ iconType = { 'crossInACircleFilled' }
623+ onClick = { toggleWarningThreshold }
624+ />
625+ </ StyledExpressionRow >
626+ </ >
627+ ) }
628+ { ! displayWarningThreshold && (
629+ < >
630+ { ' ' }
631+ < EuiSpacer size = { 'xs' } />
632+ < StyledExpressionRow >
633+ < EuiButtonEmpty
634+ color = { 'primary' }
635+ flush = { 'left' }
636+ size = "xs"
637+ iconType = { 'plusInCircleFilled' }
638+ onClick = { toggleWarningThreshold }
639+ >
640+ < FormattedMessage
641+ id = "xpack.infra.metrics.alertFlyout.addWarningThreshold"
642+ defaultMessage = "Add warning threshold"
643+ />
644+ </ EuiButtonEmpty >
645+ </ StyledExpressionRow >
646+ </ >
647+ ) }
536648 </ EuiFlexItem >
537649 { canDelete && (
538650 < EuiFlexItem grow = { false } >
@@ -552,6 +664,38 @@ export const ExpressionRow: React.FC<ExpressionRowProps> = (props) => {
552664 ) ;
553665} ;
554666
667+ const ThresholdElement : React . FC < {
668+ updateComparator : ( c ?: string ) => void ;
669+ updateThreshold : ( t ?: number [ ] ) => void ;
670+ threshold : InventoryMetricConditions [ 'threshold' ] ;
671+ comparator : InventoryMetricConditions [ 'comparator' ] ;
672+ errors : IErrorObject ;
673+ metric ?: SnapshotMetricType ;
674+ } > = ( { updateComparator, updateThreshold, threshold, metric, comparator, errors } ) => {
675+ return (
676+ < >
677+ < StyledExpression >
678+ < ThresholdExpression
679+ thresholdComparator = { comparator || Comparator . GT }
680+ threshold = { threshold }
681+ onChangeSelectedThresholdComparator = { updateComparator }
682+ onChangeSelectedThreshold = { updateThreshold }
683+ errors = { errors }
684+ />
685+ </ StyledExpression >
686+ { metric && (
687+ < div
688+ style = { {
689+ alignSelf : 'center' ,
690+ } }
691+ >
692+ < EuiText size = { 's' } > { metricUnit [ metric ] ?. label || '' } </ EuiText >
693+ </ div >
694+ ) }
695+ </ >
696+ ) ;
697+ } ;
698+
555699const getDisplayNameForType = ( type : InventoryItemType ) => {
556700 const inventoryModel = findInventoryModel ( type ) ;
557701 return inventoryModel . displayName ;
0 commit comments