1+ // LOGZ.IO CHANGES :: DEV-48338 , file taken from https://github.com/grafana/grafana/pull/87320 
12import  {  css  }  from  '@emotion/css' ; 
2- import  React  from  'react' ; 
3+ import  React ,  {  useState  }  from  'react' ; 
4+ import  {  useDebounce ,  useDeepCompareEffect  }  from  'react-use' ; 
35
46import  {  dateTime ,  GrafanaTheme2  }  from  '@grafana/data' ; 
57import  {  Alert ,  Badge ,  LoadingPlaceholder ,  useStyles2  }  from  '@grafana/ui' ; 
6- import  {  AlertmanagerAlert ,  Matcher  }  from  'app/plugins/datasource/alertmanager/types' ; 
8+ import  {  MatcherFieldValue  }  from  'app/features/alerting/unified/types/silence-form' ; 
9+ import  {  matcherFieldToMatcher  }  from  'app/features/alerting/unified/utils/alertmanager' ; 
10+ import  {  AlertmanagerAlert ,  Matcher ,  MatcherOperator  }  from  'app/plugins/datasource/alertmanager/types' ; 
711
812import  {  alertmanagerApi  }  from  '../../api/alertmanagerApi' ; 
913import  {  isNullDate  }  from  '../../utils/time' ; 
@@ -12,27 +16,52 @@ import { DynamicTable, DynamicTableColumnProps, DynamicTableItemProps } from '..
1216
1317import  {  AmAlertStateTag  }  from  './AmAlertStateTag' ; 
1418
19+ const  MATCHER_ALERT_RULE_UID  =  '__alert_rule_uid__' ; 
1520interface  Props  { 
1621  amSourceName : string ; 
17-   matchers : Matcher [ ] ; 
22+   matchers : MatcherFieldValue [ ] ; 
23+   ruleUid ?: string ; 
1824} 
1925
20- export  const  SilencedInstancesPreview  =  ( {  amSourceName,  matchers } : Props )  =>  { 
21-   const  {  useGetAlertmanagerAlertsQuery }  =  alertmanagerApi ; 
26+ /** 
27+  * Performs a deep equality check on the dependencies, and debounces the callback 
28+  */ 
29+ const  useDebouncedDeepCompare  =  ( cb : ( )  =>  void ,  debounceMs : number ,  dependencies : unknown [ ] )  =>  { 
30+   const  [ state ,  setState ]  =  useState < unknown [ ] > ( ) ; 
31+ 
32+   useDebounce ( cb ,  debounceMs ,  [ state ] ) ; 
33+ 
34+   useDeepCompareEffect ( ( )  =>  { 
35+     setState ( dependencies ) ; 
36+   } ,  [ dependencies ] ) ; 
37+ } ; 
38+ 
39+ export  const  SilencedInstancesPreview  =  ( {  amSourceName,  matchers : inputMatchers ,  ruleUid } : Props )  =>  { 
40+   const  matchers : Matcher [ ]  =  [ 
41+     ...( ruleUid  ? [ {  name : MATCHER_ALERT_RULE_UID ,  value : ruleUid ,  operator : MatcherOperator . equal  } ]  : [ ] ) , 
42+     ...inputMatchers , 
43+   ] . map ( matcherFieldToMatcher ) ; 
44+   const  useLazyQuery  =  alertmanagerApi . endpoints . getAlertmanagerAlerts . useLazyQuery ; 
2245  const  styles  =  useStyles2 ( getStyles ) ; 
2346  const  columns  =  useColumns ( ) ; 
2447
2548  // By default the form contains an empty matcher - with empty name and value and = operator 
2649  // We don't want to fetch previews for empty matchers as it results in all alerts returned 
27-   const  hasValidMatchers  =  matchers . some ( ( matcher )  =>  matcher . value  &&  matcher . name ) ; 
28- 
29-   const  { 
30-     currentData : alerts  =  [ ] , 
31-     isFetching, 
32-     isError, 
33-   }  =  useGetAlertmanagerAlertsQuery ( 
34-     {  amSourceName,  filter : {  matchers }  } , 
35-     {  skip : ! hasValidMatchers ,  refetchOnMountOrArgChange : true  } 
50+   const  hasValidMatchers  =  ruleUid  ||  inputMatchers . some ( ( matcher )  =>  matcher . value  &&  matcher . name ) ; 
51+ 
52+   const  [ getAlertmanagerAlerts ,  {  currentData : alerts  =  [ ] ,  isFetching,  isError } ]  =  useLazyQuery ( ) ; 
53+ 
54+   // We need to deep compare the matchers, as otherwise the preview API call is triggered on every render 
55+   // of the component. This is because between react-hook-form's useFieldArray, and our parsing of the matchers, 
56+   // we end up otherwise triggering the call too frequently 
57+   useDebouncedDeepCompare ( 
58+     ( )  =>  { 
59+       if  ( hasValidMatchers )  { 
60+         getAlertmanagerAlerts ( {  amSourceName,  filter : {  matchers }  } ) ; 
61+       } 
62+     } , 
63+     500 , 
64+     [ amSourceName ,  matchers ] 
3665  ) ; 
3766
3867  const  tableItemAlerts  =  alerts . map < DynamicTableItemProps < AlertmanagerAlert > > ( ( alert )  =>  ( { 
@@ -43,18 +72,18 @@ export const SilencedInstancesPreview = ({ amSourceName, matchers }: Props) => {
4372  return  ( 
4473    < div > 
4574      < h4  className = { styles . title } > 
46-         Affected alert instances
75+         Affected alert rule  instances
4776        { tableItemAlerts . length  >  0  ? ( 
4877          < Badge  className = { styles . badge }  color = "blue"  text = { tableItemAlerts . length }  /> 
4978        )  : null } 
5079      </ h4 > 
5180      { ! hasValidMatchers  &&  < span > Add a valid matcher to see affected alerts</ span > } 
5281      { isError  &&  ( 
5382        < Alert  title = "Preview not available"  severity = "error" > 
54-           Error occured when generating affected alerts preview . Are you  matchers valid?
83+           Error occured when generating preview of  affected alerts. Are your  matchers valid?
5584        </ Alert > 
5685      ) } 
57-       { isFetching  &&  < LoadingPlaceholder  text = "Loading..."  /> } 
86+       { isFetching  &&  < LoadingPlaceholder  text = "Loading affected alert rule instances ..."  /> } 
5887      { ! isFetching  &&  ! isError  &&  hasValidMatchers  &&  ( 
5988        < div  className = { styles . table } > 
6089          { tableItemAlerts . length  >  0  ? ( 
@@ -65,7 +94,7 @@ export const SilencedInstancesPreview = ({ amSourceName, matchers }: Props) => {
6594              pagination = { {  itemsPerPage : 10  } } 
6695            /> 
6796          )  : ( 
68-             < span > No matching  alert instances found</ span > 
97+             < span > No firing  alert instances found</ span > 
6998          ) } 
7099        </ div > 
71100      ) } 
@@ -106,21 +135,21 @@ function useColumns(): Array<DynamicTableColumnProps<AlertmanagerAlert>> {
106135} 
107136
108137const  getStyles  =  ( theme : GrafanaTheme2 )  =>  ( { 
109-   table : css ` 
110-     max-width :   ${ theme . breakpoints . values . lg } ;  
111-   `  , 
112-   moreMatches : css ` 
113-     margin-top :   ${ theme . spacing ( 1 ) } ;  
114-   `  , 
115-   title : css ` 
116-     display :  flex;  
117-     align-items :   center;  
118-   `  , 
119-   badge : css ` 
120-     margin-left :   ${ theme . spacing ( 1 ) } ;  
121-   `  , 
122-   stateColumn : css ` 
123-     display :  flex;  
124-     align-items :   center;  
125-   `  , 
138+   table : css ( { 
139+     maxWidth :  ` ${ theme . breakpoints . values . lg } ` , 
140+   } ) , 
141+   moreMatches : css ( { 
142+     marginTop :  theme . spacing ( 1 ) , 
143+   } ) , 
144+   title : css ( { 
145+     display : ' flex' , 
146+     alignItems :  ' center' , 
147+   } ) , 
148+   badge : css ( { 
149+     marginLeft :  theme . spacing ( 1 ) , 
150+   } ) , 
151+   stateColumn : css ( { 
152+     display : ' flex' , 
153+     alignItems :  ' center' , 
154+   } ) , 
126155} ) ; 
0 commit comments