mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-13 01:38:59 +08:00
feat: users should choose either to broadcast all or enter specific channels to alert (#4441)
* feat: users should choose either to broadcast all or enter specific channels to alert * fix: remove console logs
This commit is contained in:
parent
4db3e5e542
commit
824d9aaf85
@ -62,6 +62,7 @@
|
|||||||
"button_cancel": "No",
|
"button_cancel": "No",
|
||||||
"field_promql_expr": "PromQL Expression",
|
"field_promql_expr": "PromQL Expression",
|
||||||
"field_alert_name": "Alert Name",
|
"field_alert_name": "Alert Name",
|
||||||
|
"field_notification_channel": "Notification Channel",
|
||||||
"field_alert_desc": "Alert Description",
|
"field_alert_desc": "Alert Description",
|
||||||
"field_labels": "Labels",
|
"field_labels": "Labels",
|
||||||
"field_severity": "Severity",
|
"field_severity": "Severity",
|
||||||
@ -100,7 +101,7 @@
|
|||||||
"user_guide_ch_step3a": "Set alert severity, name and descriptions",
|
"user_guide_ch_step3a": "Set alert severity, name and descriptions",
|
||||||
"user_guide_ch_step3b": "Add tags to the alert in the Label field if needed",
|
"user_guide_ch_step3b": "Add tags to the alert in the Label field if needed",
|
||||||
"user_tooltip_more_help": "More details on how to create alerts",
|
"user_tooltip_more_help": "More details on how to create alerts",
|
||||||
"choose_alert_type": "Choose a type for the alert:",
|
"choose_alert_type": "Choose a type for the alert",
|
||||||
"metric_based_alert": "Metric based Alert",
|
"metric_based_alert": "Metric based Alert",
|
||||||
"metric_based_alert_desc": "Send a notification when a condition occurs in the metric data",
|
"metric_based_alert_desc": "Send a notification when a condition occurs in the metric data",
|
||||||
"log_based_alert": "Log-based Alert",
|
"log_based_alert": "Log-based Alert",
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
"field_promql_expr": "PromQL Expression",
|
"field_promql_expr": "PromQL Expression",
|
||||||
"field_alert_name": "Alert Name",
|
"field_alert_name": "Alert Name",
|
||||||
"field_alert_desc": "Alert Description",
|
"field_alert_desc": "Alert Description",
|
||||||
|
"field_notification_channel": "Notification Channel",
|
||||||
"field_labels": "Labels",
|
"field_labels": "Labels",
|
||||||
"field_severity": "Severity",
|
"field_severity": "Severity",
|
||||||
"option_critical": "Critical",
|
"option_critical": "Critical",
|
||||||
|
@ -63,6 +63,7 @@
|
|||||||
"field_promql_expr": "PromQL Expression",
|
"field_promql_expr": "PromQL Expression",
|
||||||
"field_alert_name": "Alert Name",
|
"field_alert_name": "Alert Name",
|
||||||
"field_alert_desc": "Alert Description",
|
"field_alert_desc": "Alert Description",
|
||||||
|
"field_notification_channel": "Notification Channel",
|
||||||
"field_labels": "Labels",
|
"field_labels": "Labels",
|
||||||
"field_severity": "Severity",
|
"field_severity": "Severity",
|
||||||
"option_critical": "Critical",
|
"option_critical": "Critical",
|
||||||
@ -100,7 +101,7 @@
|
|||||||
"user_guide_ch_step3a": "Set alert severity, name and descriptions",
|
"user_guide_ch_step3a": "Set alert severity, name and descriptions",
|
||||||
"user_guide_ch_step3b": "Add tags to the alert in the Label field if needed",
|
"user_guide_ch_step3b": "Add tags to the alert in the Label field if needed",
|
||||||
"user_tooltip_more_help": "More details on how to create alerts",
|
"user_tooltip_more_help": "More details on how to create alerts",
|
||||||
"choose_alert_type": "Choose a type for the alert:",
|
"choose_alert_type": "Choose a type for the alert",
|
||||||
"metric_based_alert": "Metric based Alert",
|
"metric_based_alert": "Metric based Alert",
|
||||||
"metric_based_alert_desc": "Send a notification when a condition occurs in the metric data",
|
"metric_based_alert_desc": "Send a notification when a condition occurs in the metric data",
|
||||||
"log_based_alert": "Log-based Alert",
|
"log_based_alert": "Log-based Alert",
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
"field_promql_expr": "PromQL Expression",
|
"field_promql_expr": "PromQL Expression",
|
||||||
"field_alert_name": "Alert Name",
|
"field_alert_name": "Alert Name",
|
||||||
"field_alert_desc": "Alert Description",
|
"field_alert_desc": "Alert Description",
|
||||||
|
"field_notification_channel": "Notification Channel",
|
||||||
"field_labels": "Labels",
|
"field_labels": "Labels",
|
||||||
"field_severity": "Severity",
|
"field_severity": "Severity",
|
||||||
"option_critical": "Critical",
|
"option_critical": "Critical",
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Row } from 'antd';
|
import { Row, Typography } from 'antd';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { AlertTypes } from 'types/api/alerts/alertTypes';
|
import { AlertTypes } from 'types/api/alerts/alertTypes';
|
||||||
@ -33,7 +33,14 @@ function SelectAlertType({ onSelect }: SelectAlertTypeProps): JSX.Element {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SelectTypeContainer>
|
<SelectTypeContainer>
|
||||||
<h3> {t('choose_alert_type')} </h3>
|
<Typography.Title
|
||||||
|
level={4}
|
||||||
|
style={{
|
||||||
|
padding: '0 8px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('choose_alert_type')}
|
||||||
|
</Typography.Title>
|
||||||
<Row>{renderOptions}</Row>
|
<Row>{renderOptions}</Row>
|
||||||
</SelectTypeContainer>
|
</SelectTypeContainer>
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Form, Select } from 'antd';
|
import { Form, Select, Switch } from 'antd';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { AlertDef, Labels } from 'types/api/alerts/def';
|
import { AlertDef, Labels } from 'types/api/alerts/def';
|
||||||
import { requireErrorMessage } from 'utils/form/requireErrorMessage';
|
import { requireErrorMessage } from 'utils/form/requireErrorMessage';
|
||||||
@ -7,7 +8,6 @@ import { popupContainer } from 'utils/selectPopupContainer';
|
|||||||
import ChannelSelect from './ChannelSelect';
|
import ChannelSelect from './ChannelSelect';
|
||||||
import LabelSelect from './labels';
|
import LabelSelect from './labels';
|
||||||
import {
|
import {
|
||||||
ChannelSelectTip,
|
|
||||||
FormContainer,
|
FormContainer,
|
||||||
FormItemMedium,
|
FormItemMedium,
|
||||||
InputSmall,
|
InputSmall,
|
||||||
@ -19,14 +19,41 @@ import {
|
|||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
|
|
||||||
interface BasicInfoProps {
|
interface BasicInfoProps {
|
||||||
|
isNewRule: boolean;
|
||||||
alertDef: AlertDef;
|
alertDef: AlertDef;
|
||||||
setAlertDef: (a: AlertDef) => void;
|
setAlertDef: (a: AlertDef) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function BasicInfo({ alertDef, setAlertDef }: BasicInfoProps): JSX.Element {
|
function BasicInfo({
|
||||||
// init namespace for translations
|
isNewRule,
|
||||||
|
alertDef,
|
||||||
|
setAlertDef,
|
||||||
|
}: BasicInfoProps): JSX.Element {
|
||||||
const { t } = useTranslation('alerts');
|
const { t } = useTranslation('alerts');
|
||||||
|
|
||||||
|
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,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StepHeading> {t('alert_form_step3')} </StepHeading>
|
<StepHeading> {t('alert_form_step3')} </StepHeading>
|
||||||
@ -105,18 +132,38 @@ function BasicInfo({ alertDef, setAlertDef }: BasicInfoProps): JSX.Element {
|
|||||||
initialValues={alertDef.labels}
|
initialValues={alertDef.labels}
|
||||||
/>
|
/>
|
||||||
</FormItemMedium>
|
</FormItemMedium>
|
||||||
<FormItemMedium label="Notification Channels">
|
|
||||||
<ChannelSelect
|
<FormItemMedium
|
||||||
currentValue={alertDef.preferredChannels}
|
name="alert_all_configured_channels"
|
||||||
onSelectChannels={(preferredChannels): void => {
|
label="Alert all the configured channels"
|
||||||
setAlertDef({
|
>
|
||||||
...alertDef,
|
<Switch
|
||||||
preferredChannels,
|
checked={shouldBroadCastToAllChannels}
|
||||||
});
|
onChange={handleBroadcastToAllChannels}
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
<ChannelSelectTip> {t('channel_select_tooltip')}</ChannelSelectTip>
|
|
||||||
</FormItemMedium>
|
</FormItemMedium>
|
||||||
|
|
||||||
|
{!shouldBroadCastToAllChannels && (
|
||||||
|
<FormItemMedium
|
||||||
|
label="Notification Channels"
|
||||||
|
name="notification_channels"
|
||||||
|
required
|
||||||
|
rules={[
|
||||||
|
{ required: true, message: requireErrorMessage(t('field_alert_name')) },
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<ChannelSelect
|
||||||
|
disabled={shouldBroadCastToAllChannels}
|
||||||
|
currentValue={alertDef.preferredChannels}
|
||||||
|
onSelectChannels={(preferredChannels): void => {
|
||||||
|
setAlertDef({
|
||||||
|
...alertDef,
|
||||||
|
preferredChannels,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</FormItemMedium>
|
||||||
|
)}
|
||||||
</FormContainer>
|
</FormContainer>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -8,11 +8,13 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { StyledSelect } from './styles';
|
import { StyledSelect } from './styles';
|
||||||
|
|
||||||
export interface ChannelSelectProps {
|
export interface ChannelSelectProps {
|
||||||
|
disabled?: boolean;
|
||||||
currentValue?: string[];
|
currentValue?: string[];
|
||||||
onSelectChannels: (s: string[]) => void;
|
onSelectChannels: (s: string[]) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ChannelSelect({
|
function ChannelSelect({
|
||||||
|
disabled,
|
||||||
currentValue,
|
currentValue,
|
||||||
onSelectChannels,
|
onSelectChannels,
|
||||||
}: ChannelSelectProps): JSX.Element | null {
|
}: ChannelSelectProps): JSX.Element | null {
|
||||||
@ -52,6 +54,7 @@ function ChannelSelect({
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<StyledSelect
|
<StyledSelect
|
||||||
|
disabled={disabled}
|
||||||
status={error ? 'error' : ''}
|
status={error ? 'error' : ''}
|
||||||
mode="multiple"
|
mode="multiple"
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
@ -68,6 +71,7 @@ function ChannelSelect({
|
|||||||
}
|
}
|
||||||
|
|
||||||
ChannelSelect.defaultProps = {
|
ChannelSelect.defaultProps = {
|
||||||
|
disabled: false,
|
||||||
currentValue: [],
|
currentValue: [],
|
||||||
};
|
};
|
||||||
export default ChannelSelect;
|
export default ChannelSelect;
|
||||||
|
@ -53,6 +53,7 @@ import {
|
|||||||
import UserGuide from './UserGuide';
|
import UserGuide from './UserGuide';
|
||||||
import { getSelectedQueryOptions } from './utils';
|
import { getSelectedQueryOptions } from './utils';
|
||||||
|
|
||||||
|
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||||
function FormAlertRules({
|
function FormAlertRules({
|
||||||
alertType,
|
alertType,
|
||||||
formInstance,
|
formInstance,
|
||||||
@ -78,6 +79,8 @@ function FormAlertRules({
|
|||||||
// use query client
|
// use query client
|
||||||
const ruleCache = useQueryClient();
|
const ruleCache = useQueryClient();
|
||||||
|
|
||||||
|
const isNewRule = ruleId === 0;
|
||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
// alertDef holds the form values to be posted
|
// alertDef holds the form values to be posted
|
||||||
@ -108,8 +111,17 @@ function FormAlertRules({
|
|||||||
useShareBuilderUrl(sq);
|
useShareBuilderUrl(sq);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setAlertDef(initialValue);
|
const broadcastToSpecificChannels =
|
||||||
}, [initialValue]);
|
(initialValue &&
|
||||||
|
initialValue.preferredChannels &&
|
||||||
|
initialValue.preferredChannels.length > 0) ||
|
||||||
|
isNewRule;
|
||||||
|
|
||||||
|
setAlertDef({
|
||||||
|
...initialValue,
|
||||||
|
broadcastToAll: !broadcastToSpecificChannels,
|
||||||
|
});
|
||||||
|
}, [initialValue, isNewRule]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Set selectedQueryName based on the length of queryOptions
|
// Set selectedQueryName based on the length of queryOptions
|
||||||
@ -243,6 +255,7 @@ function FormAlertRules({
|
|||||||
const preparePostData = (): AlertDef => {
|
const preparePostData = (): AlertDef => {
|
||||||
const postableAlert: AlertDef = {
|
const postableAlert: AlertDef = {
|
||||||
...alertDef,
|
...alertDef,
|
||||||
|
preferredChannels: alertDef.broadcastToAll ? [] : alertDef.preferredChannels,
|
||||||
alertType,
|
alertType,
|
||||||
source: window?.location.toString(),
|
source: window?.location.toString(),
|
||||||
ruleType:
|
ruleType:
|
||||||
@ -386,7 +399,11 @@ function FormAlertRules({
|
|||||||
}, [t, isFormValid, memoizedPreparePostData, notifications]);
|
}, [t, isFormValid, memoizedPreparePostData, notifications]);
|
||||||
|
|
||||||
const renderBasicInfo = (): JSX.Element => (
|
const renderBasicInfo = (): JSX.Element => (
|
||||||
<BasicInfo alertDef={alertDef} setAlertDef={setAlertDef} />
|
<BasicInfo
|
||||||
|
alertDef={alertDef}
|
||||||
|
setAlertDef={setAlertDef}
|
||||||
|
isNewRule={isNewRule}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
const renderQBChartPreview = (): JSX.Element => (
|
const renderQBChartPreview = (): JSX.Element => (
|
||||||
@ -421,8 +438,6 @@ function FormAlertRules({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
const isNewRule = ruleId === 0;
|
|
||||||
|
|
||||||
const isAlertNameMissing = !formInstance.getFieldValue('alert');
|
const isAlertNameMissing = !formInstance.getFieldValue('alert');
|
||||||
|
|
||||||
const isAlertAvialableToSave =
|
const isAlertAvialableToSave =
|
||||||
@ -442,6 +457,10 @@ function FormAlertRules({
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isChannelConfigurationValid =
|
||||||
|
alertDef?.broadcastToAll ||
|
||||||
|
(alertDef.preferredChannels && alertDef.preferredChannels.length > 0);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{Element}
|
{Element}
|
||||||
@ -489,7 +508,11 @@ function FormAlertRules({
|
|||||||
type="primary"
|
type="primary"
|
||||||
onClick={onSaveHandler}
|
onClick={onSaveHandler}
|
||||||
icon={<SaveOutlined />}
|
icon={<SaveOutlined />}
|
||||||
disabled={isAlertNameMissing || isAlertAvialableToSave}
|
disabled={
|
||||||
|
isAlertNameMissing ||
|
||||||
|
isAlertAvialableToSave ||
|
||||||
|
!isChannelConfigurationValid
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{isNewRule ? t('button_createrule') : t('button_savechanges')}
|
{isNewRule ? t('button_createrule') : t('button_savechanges')}
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
@ -497,6 +520,7 @@ function FormAlertRules({
|
|||||||
|
|
||||||
<ActionButton
|
<ActionButton
|
||||||
loading={loading || false}
|
loading={loading || false}
|
||||||
|
disabled={isAlertNameMissing || !isChannelConfigurationValid}
|
||||||
type="default"
|
type="default"
|
||||||
onClick={onTestRuleHandler}
|
onClick={onTestRuleHandler}
|
||||||
>
|
>
|
||||||
|
@ -21,6 +21,7 @@ export interface AlertDef {
|
|||||||
source?: string;
|
source?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
preferredChannels?: string[];
|
preferredChannels?: string[];
|
||||||
|
broadcastToAll?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RuleCondition {
|
export interface RuleCondition {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user