mirror of
https://github.com/grafana/grafana.git
synced 2025-09-25 00:34:36 +08:00
194 lines
6.8 KiB
TypeScript
194 lines
6.8 KiB
TypeScript
import { css } from '@emotion/css';
|
|
import React, { useState } from 'react';
|
|
import { FormProvider, useForm } from 'react-hook-form';
|
|
|
|
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
|
|
import { Alert, Button, Field, FieldSet, Input, LinkButton, LoadingPlaceholder, useStyles2 } from '@grafana/ui';
|
|
import {
|
|
AlertmanagerConfig,
|
|
AlertManagerCortexConfig,
|
|
MuteTimeInterval,
|
|
} from 'app/plugins/datasource/alertmanager/types';
|
|
import { useDispatch } from 'app/types';
|
|
|
|
import { useAlertManagerSourceName } from '../../hooks/useAlertManagerSourceName';
|
|
import { useAlertManagersByPermission } from '../../hooks/useAlertManagerSources';
|
|
import { useUnifiedAlertingSelector } from '../../hooks/useUnifiedAlertingSelector';
|
|
import { updateAlertManagerConfigAction } from '../../state/actions';
|
|
import { MuteTimingFields } from '../../types/mute-timing-form';
|
|
import { renameMuteTimings } from '../../utils/alertmanager';
|
|
import { makeAMLink } from '../../utils/misc';
|
|
import { createMuteTiming, defaultTimeInterval } from '../../utils/mute-timings';
|
|
import { initialAsyncRequestState } from '../../utils/redux';
|
|
import { AlertManagerPicker } from '../AlertManagerPicker';
|
|
import { AlertingPageWrapper } from '../AlertingPageWrapper';
|
|
import { ProvisionedResource, ProvisioningAlert } from '../Provisioning';
|
|
|
|
import { MuteTimingTimeInterval } from './MuteTimingTimeInterval';
|
|
|
|
interface Props {
|
|
muteTiming?: MuteTimeInterval;
|
|
showError?: boolean;
|
|
provenance?: string;
|
|
loading?: boolean;
|
|
}
|
|
|
|
const useDefaultValues = (muteTiming?: MuteTimeInterval): MuteTimingFields => {
|
|
const defaultValues = {
|
|
name: '',
|
|
time_intervals: [defaultTimeInterval],
|
|
};
|
|
|
|
if (!muteTiming) {
|
|
return defaultValues;
|
|
}
|
|
|
|
const intervals = muteTiming.time_intervals.map((interval) => ({
|
|
times: interval.times ?? defaultTimeInterval.times,
|
|
weekdays: interval.weekdays?.join(', ') ?? defaultTimeInterval.weekdays,
|
|
days_of_month: interval.days_of_month?.join(', ') ?? defaultTimeInterval.days_of_month,
|
|
months: interval.months?.join(', ') ?? defaultTimeInterval.months,
|
|
years: interval.years?.join(', ') ?? defaultTimeInterval.years,
|
|
location: interval.location ?? defaultTimeInterval.location,
|
|
}));
|
|
|
|
return {
|
|
name: muteTiming.name,
|
|
time_intervals: intervals,
|
|
};
|
|
};
|
|
|
|
const defaultPageNav: Partial<NavModelItem> = {
|
|
icon: 'sitemap',
|
|
};
|
|
|
|
const MuteTimingForm = ({ muteTiming, showError, loading, provenance }: Props) => {
|
|
const dispatch = useDispatch();
|
|
const alertManagers = useAlertManagersByPermission('notification');
|
|
const [alertManagerSourceName, setAlertManagerSourceName] = useAlertManagerSourceName(alertManagers);
|
|
const styles = useStyles2(getStyles);
|
|
|
|
const [updating, setUpdating] = useState(false);
|
|
|
|
const defaultAmCortexConfig = { alertmanager_config: {}, template_files: {} };
|
|
const amConfigs = useUnifiedAlertingSelector((state) => state.amConfigs);
|
|
const { result = defaultAmCortexConfig } =
|
|
(alertManagerSourceName && amConfigs[alertManagerSourceName]) || initialAsyncRequestState;
|
|
|
|
const config: AlertmanagerConfig = result?.alertmanager_config ?? {};
|
|
const defaultValues = useDefaultValues(muteTiming);
|
|
const formApi = useForm({ defaultValues });
|
|
|
|
const onSubmit = (values: MuteTimingFields) => {
|
|
const newMuteTiming = createMuteTiming(values);
|
|
|
|
const muteTimings = muteTiming
|
|
? config?.mute_time_intervals?.filter(({ name }) => name !== muteTiming.name)
|
|
: config.mute_time_intervals;
|
|
|
|
const newConfig: AlertManagerCortexConfig = {
|
|
...result,
|
|
alertmanager_config: {
|
|
...config,
|
|
route:
|
|
muteTiming && newMuteTiming.name !== muteTiming.name
|
|
? renameMuteTimings(newMuteTiming.name, muteTiming.name, config.route ?? {})
|
|
: config.route,
|
|
mute_time_intervals: [...(muteTimings || []), newMuteTiming],
|
|
},
|
|
};
|
|
|
|
const saveAction = dispatch(
|
|
updateAlertManagerConfigAction({
|
|
newConfig,
|
|
oldConfig: result,
|
|
alertManagerSourceName: alertManagerSourceName!,
|
|
successMessage: 'Mute timing saved',
|
|
redirectPath: '/alerting/routes/',
|
|
redirectSearch: 'tab=mute_timings',
|
|
})
|
|
);
|
|
|
|
setUpdating(true);
|
|
|
|
saveAction.unwrap().finally(() => {
|
|
setUpdating(false);
|
|
});
|
|
};
|
|
|
|
return (
|
|
<AlertingPageWrapper
|
|
pageId="am-routes"
|
|
pageNav={{
|
|
...defaultPageNav,
|
|
id: muteTiming ? 'alert-policy-edit' : 'alert-policy-new',
|
|
text: muteTiming ? 'Edit mute timing' : 'Add mute timing',
|
|
}}
|
|
>
|
|
<AlertManagerPicker
|
|
current={alertManagerSourceName}
|
|
onChange={setAlertManagerSourceName}
|
|
disabled
|
|
dataSources={alertManagers}
|
|
/>
|
|
{provenance && <ProvisioningAlert resource={ProvisionedResource.MuteTiming} />}
|
|
{loading && <LoadingPlaceholder text="Loading mute timing" />}
|
|
{showError && <Alert title="No matching mute timing found" />}
|
|
{result && !loading && !showError && (
|
|
<FormProvider {...formApi}>
|
|
<form onSubmit={formApi.handleSubmit(onSubmit)} data-testid="mute-timing-form">
|
|
<FieldSet label={'Create mute timing'} disabled={Boolean(provenance) || updating}>
|
|
<Field
|
|
required
|
|
label="Name"
|
|
description="A unique name for the mute timing"
|
|
invalid={!!formApi.formState.errors?.name}
|
|
error={formApi.formState.errors.name?.message}
|
|
>
|
|
<Input
|
|
{...formApi.register('name', {
|
|
required: true,
|
|
validate: (value) => {
|
|
if (!muteTiming) {
|
|
const existingMuteTiming = config?.mute_time_intervals?.find(({ name }) => value === name);
|
|
return existingMuteTiming ? `Mute timing already exists for "${value}"` : true;
|
|
}
|
|
return;
|
|
},
|
|
})}
|
|
className={styles.input}
|
|
data-testid={'mute-timing-name'}
|
|
/>
|
|
</Field>
|
|
<MuteTimingTimeInterval />
|
|
<Button type="submit" className={styles.submitButton} disabled={updating}>
|
|
Save mute timing
|
|
</Button>
|
|
<LinkButton
|
|
type="button"
|
|
variant="secondary"
|
|
fill="outline"
|
|
href={makeAMLink('/alerting/routes/', alertManagerSourceName, { tab: 'mute_timings' })}
|
|
disabled={updating}
|
|
>
|
|
Cancel
|
|
</LinkButton>
|
|
</FieldSet>
|
|
</form>
|
|
</FormProvider>
|
|
)}
|
|
</AlertingPageWrapper>
|
|
);
|
|
};
|
|
|
|
const getStyles = (theme: GrafanaTheme2) => ({
|
|
input: css`
|
|
width: 400px;
|
|
`,
|
|
submitButton: css`
|
|
margin-right: ${theme.spacing(1)};
|
|
`,
|
|
});
|
|
|
|
export default MuteTimingForm;
|