mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
* wip: add form inputs for creating mute timing * form for mute timings * add action for submitting config * fix bug in payload * add table for viewing mute timings * remove mute timing from routes when deleted * attach mute timing to route * edit a mute timing * use field array for multiple intervals * Add confirmation modal for deleting mute timing * add default values to form inputs * fetch am config prior to renderring form * validation for mute timing fields * fix tests * tests for mute timing form * small ui fixes for the form and table * pass mute name as query param * make time fields inline * fix validation for an existing alert and overwrite on edit * rename mute timing in routes on edit * fix validation for time inputs * make time interval its own component * add descriptions for mute timings * refactor time interval parsing functions * fix linting and tests * refactor makeAmLink * docs for mute timings * reorganize docs and add intro for mute timings * doc review edits Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> * run prettier Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>
146 lines
5.1 KiB
TypeScript
146 lines
5.1 KiB
TypeScript
import React, { FC, useMemo, useState } from 'react';
|
|
import { css } from '@emotion/css';
|
|
import { GrafanaTheme2 } from '@grafana/data';
|
|
import { IconButton, LinkButton, Link, useStyles2, ConfirmModal } from '@grafana/ui';
|
|
import { AlertManagerCortexConfig, MuteTimeInterval, TimeInterval } from 'app/plugins/datasource/alertmanager/types';
|
|
import { useDispatch } from 'react-redux';
|
|
import { useUnifiedAlertingSelector } from '../../hooks/useUnifiedAlertingSelector';
|
|
import { deleteMuteTimingAction } from '../../state/actions';
|
|
import { makeAMLink } from '../../utils/misc';
|
|
import { AsyncRequestState, initialAsyncRequestState } from '../../utils/redux';
|
|
import { DynamicTable, DynamicTableItemProps, DynamicTableColumnProps } from '../DynamicTable';
|
|
import {
|
|
getTimeString,
|
|
getWeekdayString,
|
|
getDaysOfMonthString,
|
|
getMonthsString,
|
|
getYearsString,
|
|
} from '../../utils/alertmanager';
|
|
|
|
interface Props {
|
|
alertManagerSourceName: string;
|
|
muteTimingNames?: string[];
|
|
hideActions?: boolean;
|
|
}
|
|
|
|
export const MuteTimingsTable: FC<Props> = ({ alertManagerSourceName, muteTimingNames, hideActions }) => {
|
|
const styles = useStyles2(getStyles);
|
|
const dispatch = useDispatch();
|
|
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>
|
|
{!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>
|
|
)}
|
|
{items.length > 0 ? <DynamicTable items={items} cols={columns} /> : <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('')}
|
|
/>
|
|
)}
|
|
{!hideActions && (
|
|
<LinkButton
|
|
className={styles.addMuteButton}
|
|
variant="secondary"
|
|
href={makeAMLink('alerting/routes/mute-timing/new', alertManagerSourceName)}
|
|
>
|
|
Add mute timing
|
|
</LinkButton>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
function useColumns(alertManagerSourceName: string, hideActions = false, setMuteTimingName: (name: string) => void) {
|
|
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 (!hideActions) {
|
|
columns.push({
|
|
id: 'actions',
|
|
label: 'Actions',
|
|
renderCell: function renderActions({ data }) {
|
|
return (
|
|
<div>
|
|
<Link
|
|
href={makeAMLink(`/alerting/routes/mute-timing/edit`, alertManagerSourceName, { muteName: data.name })}
|
|
>
|
|
<IconButton name="edit" title="Edit mute timing" />
|
|
</Link>
|
|
<IconButton name={'trash-alt'} title="Delete mute timing" onClick={() => setMuteTimingName(data.name)} />
|
|
</div>
|
|
);
|
|
},
|
|
size: '100px',
|
|
});
|
|
}
|
|
return columns;
|
|
}, [alertManagerSourceName, hideActions, setMuteTimingName]);
|
|
}
|
|
|
|
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) => ({
|
|
addMuteButton: css`
|
|
margin-top: ${theme.spacing(1)};
|
|
`,
|
|
});
|