123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- import { css } from '@emotion/css';
- import React, { FC, useMemo, useState } from 'react';
- import { useDispatch } from 'react-redux';
- import { GrafanaTheme2 } from '@grafana/data';
- import { IconButton, LinkButton, Link, useStyles2, ConfirmModal } from '@grafana/ui';
- import { contextSrv } from 'app/core/services/context_srv';
- import { AlertManagerCortexConfig, MuteTimeInterval, TimeInterval } from 'app/plugins/datasource/alertmanager/types';
- import { Authorize } from '../../components/Authorize';
- import { useUnifiedAlertingSelector } from '../../hooks/useUnifiedAlertingSelector';
- import { deleteMuteTimingAction } from '../../state/actions';
- import { getNotificationsPermissions } from '../../utils/access-control';
- import {
- getTimeString,
- getWeekdayString,
- getDaysOfMonthString,
- getMonthsString,
- getYearsString,
- } from '../../utils/alertmanager';
- import { makeAMLink } from '../../utils/misc';
- import { AsyncRequestState, initialAsyncRequestState } from '../../utils/redux';
- import { DynamicTable, DynamicTableItemProps, DynamicTableColumnProps } from '../DynamicTable';
- import { EmptyAreaWithCTA } from '../EmptyAreaWithCTA';
- interface Props {
- alertManagerSourceName: string;
- muteTimingNames?: string[];
- hideActions?: boolean;
- }
- export const MuteTimingsTable: FC<Props> = ({ alertManagerSourceName, muteTimingNames, hideActions }) => {
- const styles = useStyles2(getStyles);
- const dispatch = useDispatch();
- const permissions = getNotificationsPermissions(alertManagerSourceName);
- const amConfigs = useUnifiedAlertingSelector((state) => state.amConfigs);
- const [muteTimingName, setMuteTimingName] = useState<string>('');
- const { result }: AsyncRequestState<AlertManagerCortexConfig> =
- (alertManagerSourceName && amConfigs[alertManagerSourceName]) || initialAsyncRequestState;
- const items = useMemo((): Array<DynamicTableItemProps<MuteTimeInterval>> => {
- const muteTimings = result?.alertmanager_config?.mute_time_intervals ?? [];
- return muteTimings
- .filter(({ name }) => (muteTimingNames ? muteTimingNames.includes(name) : true))
- .map((mute) => {
- return {
- id: mute.name,
- data: mute,
- };
- });
- }, [result?.alertmanager_config?.mute_time_intervals, muteTimingNames]);
- const columns = useColumns(alertManagerSourceName, hideActions, setMuteTimingName);
- return (
- <div className={styles.container}>
- {!hideActions && <h5>Mute timings</h5>}
- {!hideActions && (
- <p>
- Mute timings are a named interval of time that may be referenced in the notification policy tree to mute
- particular notification policies for specific times of the day.
- </p>
- )}
- {!hideActions && items.length > 0 && (
- <Authorize actions={[permissions.create]}>
- <LinkButton
- className={styles.addMuteButton}
- icon="plus"
- variant="primary"
- href={makeAMLink('alerting/routes/mute-timing/new', alertManagerSourceName)}
- >
- New mute timing
- </LinkButton>
- </Authorize>
- )}
- {items.length > 0 ? (
- <DynamicTable items={items} cols={columns} />
- ) : !hideActions ? (
- <EmptyAreaWithCTA
- text="You haven't created any mute timings yet"
- buttonLabel="Add mute timing"
- buttonIcon="plus"
- buttonSize="lg"
- href={makeAMLink('alerting/routes/mute-timing/new', alertManagerSourceName)}
- showButton={contextSrv.hasPermission(permissions.create)}
- />
- ) : (
- <p>No mute timings configured</p>
- )}
- {!hideActions && (
- <ConfirmModal
- isOpen={!!muteTimingName}
- title="Delete mute timing"
- body={`Are you sure you would like to delete "${muteTimingName}"`}
- confirmText="Delete"
- onConfirm={() => dispatch(deleteMuteTimingAction(alertManagerSourceName, muteTimingName))}
- onDismiss={() => setMuteTimingName('')}
- />
- )}
- </div>
- );
- };
- function useColumns(alertManagerSourceName: string, hideActions = false, setMuteTimingName: (name: string) => void) {
- const permissions = getNotificationsPermissions(alertManagerSourceName);
- const userHasEditPermissions = contextSrv.hasPermission(permissions.update);
- const userHasDeletePermissions = contextSrv.hasPermission(permissions.delete);
- const showActions = !hideActions && (userHasEditPermissions || userHasDeletePermissions);
- return useMemo((): Array<DynamicTableColumnProps<MuteTimeInterval>> => {
- const columns: Array<DynamicTableColumnProps<MuteTimeInterval>> = [
- {
- id: 'name',
- label: 'Name',
- renderCell: function renderName({ data }) {
- return data.name;
- },
- size: '250px',
- },
- {
- id: 'timeRange',
- label: 'Time range',
- renderCell: ({ data }) => renderTimeIntervals(data.time_intervals),
- },
- ];
- if (showActions) {
- columns.push({
- id: 'actions',
- label: 'Actions',
- renderCell: function renderActions({ data }) {
- return (
- <div>
- <Authorize actions={[permissions.update]}>
- <Link
- href={makeAMLink(`/alerting/routes/mute-timing/edit`, alertManagerSourceName, {
- muteName: data.name,
- })}
- >
- <IconButton name="edit" title="Edit mute timing" />
- </Link>
- </Authorize>
- <Authorize actions={[permissions.delete]}>
- <IconButton
- name={'trash-alt'}
- title="Delete mute timing"
- onClick={() => setMuteTimingName(data.name)}
- />
- </Authorize>
- </div>
- );
- },
- size: '100px',
- });
- }
- return columns;
- }, [alertManagerSourceName, setMuteTimingName, showActions, permissions]);
- }
- function renderTimeIntervals(timeIntervals: TimeInterval[]) {
- return timeIntervals.map((interval, index) => {
- const { times, weekdays, days_of_month, months, years } = interval;
- const timeString = getTimeString(times);
- const weekdayString = getWeekdayString(weekdays);
- const daysString = getDaysOfMonthString(days_of_month);
- const monthsString = getMonthsString(months);
- const yearsString = getYearsString(years);
- return (
- <React.Fragment key={JSON.stringify(interval) + index}>
- {`${timeString} ${weekdayString}`}
- <br />
- {[daysString, monthsString, yearsString].join(' | ')}
- <br />
- </React.Fragment>
- );
- });
- }
- const getStyles = (theme: GrafanaTheme2) => ({
- container: css`
- display: flex;
- flex-flow: column nowrap;
- `,
- addMuteButton: css`
- margin-bottom: ${theme.spacing(2)};
- align-self: flex-end;
- `,
- });
|