AlertGroup.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. import { css } from '@emotion/css';
  2. import React, { useState, useEffect } from 'react';
  3. import { GrafanaTheme2, intervalToAbbreviatedDurationString } from '@grafana/data';
  4. import { useStyles2, LinkButton } from '@grafana/ui';
  5. import { AlertLabels } from 'app/features/alerting/unified/components/AlertLabels';
  6. import { CollapseToggle } from 'app/features/alerting/unified/components/CollapseToggle';
  7. import { AlertGroupHeader } from 'app/features/alerting/unified/components/alert-groups/AlertGroupHeader';
  8. import { getNotificationsTextColors } from 'app/features/alerting/unified/styles/notifications';
  9. import { makeAMLink, makeLabelBasedSilenceLink } from 'app/features/alerting/unified/utils/misc';
  10. import { AlertmanagerGroup, AlertState } from 'app/plugins/datasource/alertmanager/types';
  11. type Props = {
  12. alertManagerSourceName: string;
  13. group: AlertmanagerGroup;
  14. expandAll: boolean;
  15. };
  16. export const AlertGroup = ({ alertManagerSourceName, group, expandAll }: Props) => {
  17. const [showAlerts, setShowAlerts] = useState(expandAll);
  18. const styles = useStyles2(getStyles);
  19. const textStyles = useStyles2(getNotificationsTextColors);
  20. useEffect(() => setShowAlerts(expandAll), [expandAll]);
  21. return (
  22. <div className={styles.group} data-testid="alert-group">
  23. {Object.keys(group.labels).length > 0 ? (
  24. <AlertLabels labels={group.labels} />
  25. ) : (
  26. <div className={styles.noGroupingText}>No grouping</div>
  27. )}
  28. <div className={styles.row}>
  29. <CollapseToggle isCollapsed={!showAlerts} onToggle={() => setShowAlerts(!showAlerts)} />{' '}
  30. <AlertGroupHeader group={group} />
  31. </div>
  32. {showAlerts && (
  33. <div className={styles.alerts}>
  34. {group.alerts.map((alert, index) => {
  35. const state = alert.status.state.toUpperCase();
  36. const interval = intervalToAbbreviatedDurationString({
  37. start: new Date(alert.startsAt),
  38. end: Date.now(),
  39. });
  40. return (
  41. <div data-testid={'alert-group-alert'} className={styles.alert} key={`${alert.fingerprint}-${index}`}>
  42. <div>
  43. <span className={textStyles[alert.status.state]}>{state} </span>for {interval}
  44. </div>
  45. <div>
  46. <AlertLabels labels={alert.labels} />
  47. </div>
  48. <div className={styles.actionsRow}>
  49. {alert.status.state === AlertState.Suppressed && (
  50. <LinkButton
  51. href={`${makeAMLink(
  52. '/alerting/silences',
  53. alertManagerSourceName
  54. )}&silenceIds=${alert.status.silencedBy.join(',')}`}
  55. className={styles.button}
  56. icon={'bell'}
  57. size={'sm'}
  58. >
  59. Manage silences
  60. </LinkButton>
  61. )}
  62. {alert.status.state === AlertState.Active && (
  63. <LinkButton
  64. href={makeLabelBasedSilenceLink(alertManagerSourceName, alert.labels)}
  65. className={styles.button}
  66. icon={'bell-slash'}
  67. size={'sm'}
  68. >
  69. Silence
  70. </LinkButton>
  71. )}
  72. {alert.generatorURL && (
  73. <LinkButton className={styles.button} href={alert.generatorURL} icon={'chart-line'} size={'sm'}>
  74. See source
  75. </LinkButton>
  76. )}
  77. </div>
  78. </div>
  79. );
  80. })}
  81. </div>
  82. )}
  83. </div>
  84. );
  85. };
  86. const getStyles = (theme: GrafanaTheme2) => ({
  87. noGroupingText: css`
  88. height: ${theme.spacing(4)};
  89. `,
  90. group: css`
  91. background-color: ${theme.colors.background.secondary};
  92. margin: ${theme.spacing(0.5, 1, 0.5, 1)};
  93. padding: ${theme.spacing(1)};
  94. `,
  95. row: css`
  96. display: flex;
  97. flex-direction: row;
  98. align-items: center;
  99. `,
  100. alerts: css`
  101. margin: ${theme.spacing(0, 2, 0, 4)};
  102. `,
  103. alert: css`
  104. padding: ${theme.spacing(1, 0)};
  105. & + & {
  106. border-top: 1px solid ${theme.colors.border.medium};
  107. }
  108. `,
  109. button: css`
  110. & + & {
  111. margin-left: ${theme.spacing(1)};
  112. }
  113. `,
  114. actionsRow: css`
  115. padding: ${theme.spacing(1, 0)};
  116. `,
  117. });