RuleDetailsMatchingInstances.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. import { css, cx } from '@emotion/css';
  2. import React, { useMemo, useState } from 'react';
  3. import { GrafanaTheme } from '@grafana/data';
  4. import { useStyles } from '@grafana/ui';
  5. import { MatcherFilter } from 'app/features/alerting/unified/components/alert-groups/MatcherFilter';
  6. import {
  7. AlertInstanceStateFilter,
  8. InstanceStateFilter,
  9. } from 'app/features/alerting/unified/components/rules/AlertInstanceStateFilter';
  10. import { labelsMatchMatchers, parseMatchers } from 'app/features/alerting/unified/utils/alertmanager';
  11. import { sortAlerts } from 'app/features/alerting/unified/utils/misc';
  12. import { SortOrder } from 'app/plugins/panel/alertlist/types';
  13. import { Alert, CombinedRule } from 'app/types/unified-alerting';
  14. import { mapStateWithReasonToBaseState } from 'app/types/unified-alerting-dto';
  15. import { GRAFANA_RULES_SOURCE_NAME, isGrafanaRulesSource } from '../../utils/datasource';
  16. import { isAlertingRule } from '../../utils/rules';
  17. import { DetailsField } from '../DetailsField';
  18. import { AlertInstancesTable } from './AlertInstancesTable';
  19. type Props = {
  20. rule: CombinedRule;
  21. };
  22. export function RuleDetailsMatchingInstances(props: Props): JSX.Element | null {
  23. const {
  24. rule: { promRule, namespace },
  25. } = props;
  26. const [queryString, setQueryString] = useState<string>();
  27. const [alertState, setAlertState] = useState<InstanceStateFilter>();
  28. // This key is used to force a rerender on the inputs when the filters are cleared
  29. const [filterKey] = useState<number>(Math.floor(Math.random() * 100));
  30. const queryStringKey = `queryString-${filterKey}`;
  31. const styles = useStyles(getStyles);
  32. const stateFilterType = isGrafanaRulesSource(namespace.rulesSource) ? GRAFANA_RULES_SOURCE_NAME : 'prometheus';
  33. const alerts = useMemo(
  34. (): Alert[] =>
  35. isAlertingRule(promRule) && promRule.alerts?.length
  36. ? filterAlerts(queryString, alertState, sortAlerts(SortOrder.Importance, promRule.alerts))
  37. : [],
  38. [promRule, alertState, queryString]
  39. );
  40. if (!isAlertingRule(promRule)) {
  41. return null;
  42. }
  43. return (
  44. <DetailsField label="Matching instances" horizontal={true}>
  45. <div className={cx(styles.flexRow, styles.spaceBetween)}>
  46. <div className={styles.flexRow}>
  47. <MatcherFilter
  48. className={styles.rowChild}
  49. key={queryStringKey}
  50. defaultQueryString={queryString}
  51. onFilterChange={(value) => setQueryString(value)}
  52. />
  53. <AlertInstanceStateFilter
  54. className={styles.rowChild}
  55. filterType={stateFilterType}
  56. stateFilter={alertState}
  57. onStateFilterChange={setAlertState}
  58. />
  59. </div>
  60. </div>
  61. <AlertInstancesTable instances={alerts} />
  62. </DetailsField>
  63. );
  64. }
  65. function filterAlerts(
  66. alertInstanceLabel: string | undefined,
  67. alertInstanceState: InstanceStateFilter | undefined,
  68. alerts: Alert[]
  69. ): Alert[] {
  70. let filteredAlerts = [...alerts];
  71. if (alertInstanceLabel) {
  72. const matchers = parseMatchers(alertInstanceLabel || '');
  73. filteredAlerts = filteredAlerts.filter(({ labels }) => labelsMatchMatchers(labels, matchers));
  74. }
  75. if (alertInstanceState) {
  76. filteredAlerts = filteredAlerts.filter((alert) => {
  77. return mapStateWithReasonToBaseState(alert.state) === alertInstanceState;
  78. });
  79. }
  80. return filteredAlerts;
  81. }
  82. const getStyles = (theme: GrafanaTheme) => {
  83. return {
  84. flexRow: css`
  85. display: flex;
  86. flex-direction: row;
  87. align-items: flex-end;
  88. width: 100%;
  89. flex-wrap: wrap;
  90. margin-bottom: ${theme.spacing.sm};
  91. `,
  92. spaceBetween: css`
  93. justify-content: space-between;
  94. `,
  95. rowChild: css`
  96. margin-right: ${theme.spacing.sm};
  97. `,
  98. };
  99. };