mirror of
https://github.com/SigNoz/signoz.git
synced 2025-12-20 08:56:29 +00:00
* feat: anamoly detection - initial ui * feat: anamoly detection - oct 10 * feat: use antd checkbox * feat: handle multiple series * feat: handle chart height on switch btwn threshold / anomaly * feat: do not update url on detection type change * chore: pr clean up * feat: remove chart container background
256 lines
6.6 KiB
TypeScript
256 lines
6.6 KiB
TypeScript
import './FormAlertRules.styles.scss';
|
|
|
|
import { PlusOutlined } from '@ant-design/icons';
|
|
import { Button, Form, Select, Switch, Tooltip } from 'antd';
|
|
import getChannels from 'api/channels/getAll';
|
|
import logEvent from 'api/common/logEvent';
|
|
import { ALERTS_DATA_SOURCE_MAP } from 'constants/alerts';
|
|
import ROUTES from 'constants/routes';
|
|
import useComponentPermission from 'hooks/useComponentPermission';
|
|
import useFetch from 'hooks/useFetch';
|
|
import { useCallback, useEffect, useState } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { useSelector } from 'react-redux';
|
|
import { AppState } from 'store/reducers';
|
|
import { AlertTypes } from 'types/api/alerts/alertTypes';
|
|
import { AlertDef, Labels } from 'types/api/alerts/def';
|
|
import AppReducer from 'types/reducer/app';
|
|
import { requireErrorMessage } from 'utils/form/requireErrorMessage';
|
|
import { popupContainer } from 'utils/selectPopupContainer';
|
|
|
|
import ChannelSelect from './ChannelSelect';
|
|
import LabelSelect from './labels';
|
|
import {
|
|
FormContainer,
|
|
FormItemMedium,
|
|
InputSmall,
|
|
SeveritySelect,
|
|
StepHeading,
|
|
TextareaMedium,
|
|
} from './styles';
|
|
|
|
const { Option } = Select;
|
|
|
|
interface BasicInfoProps {
|
|
isNewRule: boolean;
|
|
alertDef: AlertDef;
|
|
setAlertDef: (a: AlertDef) => void;
|
|
}
|
|
|
|
function BasicInfo({
|
|
isNewRule,
|
|
alertDef,
|
|
setAlertDef,
|
|
}: BasicInfoProps): JSX.Element {
|
|
const { t } = useTranslation('alerts');
|
|
|
|
const channels = useFetch(getChannels);
|
|
const { role } = useSelector<AppState, AppReducer>((state) => state.app);
|
|
const [addNewChannelPermission] = useComponentPermission(
|
|
['add_new_channel'],
|
|
role,
|
|
);
|
|
|
|
const [
|
|
shouldBroadCastToAllChannels,
|
|
setShouldBroadCastToAllChannels,
|
|
] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const hasPreferredChannels =
|
|
(alertDef.preferredChannels && alertDef.preferredChannels.length > 0) ||
|
|
isNewRule;
|
|
|
|
setShouldBroadCastToAllChannels(!hasPreferredChannels);
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, []);
|
|
|
|
const handleBroadcastToAllChannels = (shouldBroadcast: boolean): void => {
|
|
setShouldBroadCastToAllChannels(shouldBroadcast);
|
|
|
|
setAlertDef({
|
|
...alertDef,
|
|
broadcastToAll: shouldBroadcast,
|
|
});
|
|
};
|
|
|
|
const noChannels = channels.payload?.length === 0;
|
|
const handleCreateNewChannels = useCallback(() => {
|
|
logEvent('Alert: Create notification channel button clicked', {
|
|
dataSource: ALERTS_DATA_SOURCE_MAP[alertDef?.alertType as AlertTypes],
|
|
ruleId: isNewRule ? 0 : alertDef?.id,
|
|
});
|
|
window.open(ROUTES.CHANNELS_NEW, '_blank');
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (!channels.loading && isNewRule) {
|
|
logEvent('Alert: New alert creation page visited', {
|
|
dataSource: ALERTS_DATA_SOURCE_MAP[alertDef?.alertType as AlertTypes],
|
|
numberOfChannels: channels?.payload?.length,
|
|
});
|
|
}
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [channels.payload, channels.loading]);
|
|
|
|
return (
|
|
<>
|
|
<StepHeading> {t('alert_form_step4')} </StepHeading>
|
|
<FormContainer>
|
|
<Form.Item
|
|
label={t('field_severity')}
|
|
labelAlign="left"
|
|
name={['labels', 'severity']}
|
|
>
|
|
<SeveritySelect
|
|
getPopupContainer={popupContainer}
|
|
defaultValue="critical"
|
|
onChange={(value: unknown | string): void => {
|
|
const s = (value as string) || 'critical';
|
|
setAlertDef({
|
|
...alertDef,
|
|
labels: {
|
|
...alertDef.labels,
|
|
severity: s,
|
|
},
|
|
});
|
|
}}
|
|
>
|
|
<Option value="critical">{t('option_critical')}</Option>
|
|
<Option value="error">{t('option_error')}</Option>
|
|
<Option value="warning">{t('option_warning')}</Option>
|
|
<Option value="info">{t('option_info')}</Option>
|
|
</SeveritySelect>
|
|
</Form.Item>
|
|
|
|
<Form.Item
|
|
required
|
|
name="alert"
|
|
labelAlign="left"
|
|
label={t('field_alert_name')}
|
|
rules={[
|
|
{ required: true, message: requireErrorMessage(t('field_alert_name')) },
|
|
]}
|
|
>
|
|
<InputSmall
|
|
onChange={(e): void => {
|
|
setAlertDef({
|
|
...alertDef,
|
|
alert: e.target.value,
|
|
});
|
|
}}
|
|
/>
|
|
</Form.Item>
|
|
<Form.Item
|
|
label={t('field_alert_desc')}
|
|
labelAlign="left"
|
|
name={['annotations', 'description']}
|
|
>
|
|
<TextareaMedium
|
|
onChange={(e): void => {
|
|
setAlertDef({
|
|
...alertDef,
|
|
annotations: {
|
|
...alertDef.annotations,
|
|
description: e.target.value,
|
|
},
|
|
});
|
|
}}
|
|
/>
|
|
</Form.Item>
|
|
<FormItemMedium label={t('field_labels')}>
|
|
<LabelSelect
|
|
onSetLabels={(l: Labels): void => {
|
|
setAlertDef({
|
|
...alertDef,
|
|
labels: {
|
|
...l,
|
|
},
|
|
});
|
|
}}
|
|
initialValues={alertDef.labels}
|
|
/>
|
|
</FormItemMedium>
|
|
|
|
<FormItemMedium
|
|
name="alert_all_configured_channels"
|
|
label="Alert all the configured channels"
|
|
>
|
|
<Tooltip
|
|
title={
|
|
noChannels
|
|
? 'No channels. Ask an admin to create a notification channel'
|
|
: undefined
|
|
}
|
|
placement="right"
|
|
>
|
|
<Switch
|
|
checked={shouldBroadCastToAllChannels}
|
|
onChange={handleBroadcastToAllChannels}
|
|
disabled={noChannels || !!channels.loading}
|
|
data-testid="alert-broadcast-to-all-channels"
|
|
/>
|
|
</Tooltip>
|
|
</FormItemMedium>
|
|
|
|
{!shouldBroadCastToAllChannels && (
|
|
<Tooltip
|
|
title={
|
|
noChannels
|
|
? 'No channels. Ask an admin to create a notification channel'
|
|
: undefined
|
|
}
|
|
placement="right"
|
|
>
|
|
<FormItemMedium
|
|
label="Notification Channels"
|
|
name="notification_channels"
|
|
required
|
|
rules={[
|
|
{ required: true, message: requireErrorMessage(t('field_alert_name')) },
|
|
]}
|
|
>
|
|
<ChannelSelect
|
|
disabled={
|
|
shouldBroadCastToAllChannels || noChannels || !!channels.loading
|
|
}
|
|
currentValue={alertDef.preferredChannels}
|
|
channels={channels}
|
|
onSelectChannels={(preferredChannels): void => {
|
|
setAlertDef({
|
|
...alertDef,
|
|
preferredChannels,
|
|
});
|
|
}}
|
|
/>
|
|
</FormItemMedium>
|
|
</Tooltip>
|
|
)}
|
|
|
|
{noChannels && (
|
|
<Tooltip
|
|
title={
|
|
!addNewChannelPermission
|
|
? 'Ask an admin to create a notification channel'
|
|
: undefined
|
|
}
|
|
placement="right"
|
|
>
|
|
<Button
|
|
onClick={handleCreateNewChannels}
|
|
icon={<PlusOutlined />}
|
|
className="create-notification-btn"
|
|
disabled={!addNewChannelPermission}
|
|
>
|
|
Create a notification channel
|
|
</Button>
|
|
</Tooltip>
|
|
)}
|
|
</FormContainer>
|
|
</>
|
|
);
|
|
}
|
|
|
|
export default BasicInfo;
|