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:
Yunus M 2024-01-29 11:12:41 +05:30 committed by GitHub
parent 4db3e5e542
commit 824d9aaf85
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 111 additions and 24 deletions

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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>
); );

View File

@ -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>
</> </>
); );

View File

@ -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;

View File

@ -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}
> >

View File

@ -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 {