AlertDetails.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import { css } from '@emotion/css';
  2. import React, { FC } from 'react';
  3. import { GrafanaTheme2 } from '@grafana/data';
  4. import { LinkButton, useStyles2 } from '@grafana/ui';
  5. import { contextSrv } from 'app/core/services/context_srv';
  6. import { AlertmanagerAlert, AlertState } from 'app/plugins/datasource/alertmanager/types';
  7. import { AccessControlAction } from 'app/types';
  8. import { getInstancesPermissions } from '../../utils/access-control';
  9. import { isGrafanaRulesSource } from '../../utils/datasource';
  10. import { makeAMLink, makeLabelBasedSilenceLink } from '../../utils/misc';
  11. import { AnnotationDetailsField } from '../AnnotationDetailsField';
  12. import { Authorize } from '../Authorize';
  13. interface AmNotificationsAlertDetailsProps {
  14. alertManagerSourceName: string;
  15. alert: AlertmanagerAlert;
  16. }
  17. export const AlertDetails: FC<AmNotificationsAlertDetailsProps> = ({ alert, alertManagerSourceName }) => {
  18. const styles = useStyles2(getStyles);
  19. const instancePermissions = getInstancesPermissions(alertManagerSourceName);
  20. // For Grafana Managed alerts the Generator URL redirects to the alert rule edit page, so update permission is required
  21. // For external alert manager the Generator URL redirects to an external service which we don't control
  22. const isGrafanaSource = isGrafanaRulesSource(alertManagerSourceName);
  23. const isSeeSourceButtonEnabled = isGrafanaSource
  24. ? contextSrv.hasPermission(AccessControlAction.AlertingRuleRead)
  25. : true;
  26. return (
  27. <>
  28. <div className={styles.actionsRow}>
  29. <Authorize actions={[instancePermissions.update, instancePermissions.create]} fallback={contextSrv.isEditor}>
  30. {alert.status.state === AlertState.Suppressed && (
  31. <LinkButton
  32. href={`${makeAMLink(
  33. '/alerting/silences',
  34. alertManagerSourceName
  35. )}&silenceIds=${alert.status.silencedBy.join(',')}`}
  36. className={styles.button}
  37. icon={'bell'}
  38. size={'sm'}
  39. >
  40. Manage silences
  41. </LinkButton>
  42. )}
  43. {alert.status.state === AlertState.Active && (
  44. <LinkButton
  45. href={makeLabelBasedSilenceLink(alertManagerSourceName, alert.labels)}
  46. className={styles.button}
  47. icon={'bell-slash'}
  48. size={'sm'}
  49. >
  50. Silence
  51. </LinkButton>
  52. )}
  53. </Authorize>
  54. {isSeeSourceButtonEnabled && alert.generatorURL && (
  55. <LinkButton className={styles.button} href={alert.generatorURL} icon={'chart-line'} size={'sm'}>
  56. See source
  57. </LinkButton>
  58. )}
  59. </div>
  60. {Object.entries(alert.annotations).map(([annotationKey, annotationValue]) => (
  61. <AnnotationDetailsField key={annotationKey} annotationKey={annotationKey} value={annotationValue} />
  62. ))}
  63. <div className={styles.receivers}>
  64. Receivers:{' '}
  65. {alert.receivers
  66. .map(({ name }) => name)
  67. .filter((name) => !!name)
  68. .join(', ')}
  69. </div>
  70. </>
  71. );
  72. };
  73. const getStyles = (theme: GrafanaTheme2) => ({
  74. button: css`
  75. & + & {
  76. margin-left: ${theme.spacing(1)};
  77. }
  78. `,
  79. actionsRow: css`
  80. padding: ${theme.spacing(2, 0)} !important;
  81. border-bottom: 1px solid ${theme.colors.border.medium};
  82. `,
  83. receivers: css`
  84. padding: ${theme.spacing(1, 0)};
  85. `,
  86. });