grafana/public/app/features/alerting/unified/components/alert-groups/AlertDetails.tsx
Nathan Rodman 5a25ada3d0
Alerting: Add FGAC for Silences (#46479)
* add FGAC actions for silences table

* redirect users without permissions

* hide silence button in rules list

* add permissions checks to routes

* add read action for silences page

* add permissions checks to navigation

* add additional access checks for rule viewing

* create authorize component

* add tests for silences

* hide alerting nav for users without access

* nolint: gocyclo

* add permission check to alert details

* add check for external instances

* remove unecessary new lines

* use correct actions for alert details

* fix failing tests

Co-authored-by: Yuriy Tseretyan <yuriy.tseretyan@grafana.com>
2022-03-21 16:54:37 -07:00

94 lines
3.2 KiB
TypeScript

import { css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { LinkButton, useStyles2 } from '@grafana/ui';
import { contextSrv } from 'app/core/services/context_srv';
import { AlertmanagerAlert, AlertState } from 'app/plugins/datasource/alertmanager/types';
import { AccessControlAction } from 'app/types';
import React, { FC } from 'react';
import { isGrafanaRulesSource } from '../../utils/datasource';
import { makeAMLink, makeLabelBasedSilenceLink } from '../../utils/misc';
import { AnnotationDetailsField } from '../AnnotationDetailsField';
import { Authorize } from '../Authorize';
interface AmNotificationsAlertDetailsProps {
alertManagerSourceName: string;
alert: AlertmanagerAlert;
}
export const AlertDetails: FC<AmNotificationsAlertDetailsProps> = ({ alert, alertManagerSourceName }) => {
const styles = useStyles2(getStyles);
const isExternalAM = !isGrafanaRulesSource(alertManagerSourceName);
return (
<>
<div className={styles.actionsRow}>
<Authorize
actions={
isExternalAM
? [AccessControlAction.AlertingInstancesExternalWrite]
: [AccessControlAction.AlertingInstanceCreate, AccessControlAction.AlertingInstanceUpdate]
}
fallback={contextSrv.isEditor}
>
{alert.status.state === AlertState.Suppressed && (
<LinkButton
href={`${makeAMLink(
'/alerting/silences',
alertManagerSourceName
)}&silenceIds=${alert.status.silencedBy.join(',')}`}
className={styles.button}
icon={'bell'}
size={'sm'}
>
Manage silences
</LinkButton>
)}
{alert.status.state === AlertState.Active && (
<LinkButton
href={makeLabelBasedSilenceLink(alertManagerSourceName, alert.labels)}
className={styles.button}
icon={'bell-slash'}
size={'sm'}
>
Silence
</LinkButton>
)}
</Authorize>
<Authorize
actions={isExternalAM ? [AccessControlAction.DataSourcesExplore] : [AccessControlAction.AlertingInstanceRead]}
>
{alert.generatorURL && (
<LinkButton className={styles.button} href={alert.generatorURL} icon={'chart-line'} size={'sm'}>
See source
</LinkButton>
)}
</Authorize>
</div>
{Object.entries(alert.annotations).map(([annotationKey, annotationValue]) => (
<AnnotationDetailsField key={annotationKey} annotationKey={annotationKey} value={annotationValue} />
))}
<div className={styles.receivers}>
Receivers:{' '}
{alert.receivers
.map(({ name }) => name)
.filter((name) => !!name)
.join(', ')}
</div>
</>
);
};
const getStyles = (theme: GrafanaTheme2) => ({
button: css`
& + & {
margin-left: ${theme.spacing(1)};
}
`,
actionsRow: css`
padding: ${theme.spacing(2, 0)} !important;
border-bottom: 1px solid ${theme.colors.border.medium};
`,
receivers: css`
padding: ${theme.spacing(1, 0)};
`,
});