feat: added an option to create channel when no Channels are available in alert config (#5195)

* feat: added an option to create channel when no Channels are availabel in alert config

* feat: added tooltip for the case when nochannel

* feat: opened notification channel creation in new tab

* feat: added role permission on create-notification-btn and disabled on loading

* feat: added admin permission required message in tooltip

---------

Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
This commit is contained in:
SagarRajput-7 2024-06-14 11:23:34 +05:30 committed by GitHub
parent f391ca8bb1
commit aa9689e025
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 119 additions and 37 deletions

View File

@ -1,5 +1,5 @@
import { PlusOutlined } from '@ant-design/icons';
import { Typography } from 'antd';
import { Tooltip, Typography } from 'antd';
import getAll from 'api/channels/getAll';
import Spinner from 'components/Spinner';
import TextToolTip from 'components/TextToolTip';
@ -52,11 +52,21 @@ function AlertChannels(): JSX.Element {
url="https://signoz.io/docs/userguide/alerts-management/#setting-notification-channel"
/>
{addNewChannelPermission && (
<Button onClick={onToggleHandler} icon={<PlusOutlined />}>
<Tooltip
title={
!addNewChannelPermission
? 'Ask an admin to create alert channel'
: undefined
}
>
<Button
onClick={onToggleHandler}
icon={<PlusOutlined />}
disabled={!addNewChannelPermission}
>
{t('button_new_channel')}
</Button>
)}
</Tooltip>
</RightActionContainer>
</ButtonContainer>

View File

@ -1,7 +1,17 @@
import { Form, Select, Switch } from 'antd';
import { useEffect, useState } from 'react';
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 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 { AlertDef, Labels } from 'types/api/alerts/def';
import AppReducer from 'types/reducer/app';
import { requireErrorMessage } from 'utils/form/requireErrorMessage';
import { popupContainer } from 'utils/selectPopupContainer';
@ -31,6 +41,13 @@ function BasicInfo({
}: 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,
@ -54,6 +71,11 @@ function BasicInfo({
});
};
const noChannels = channels.payload?.length === 0;
const handleCreateNewChannels = useCallback(() => {
window.open(ROUTES.CHANNELS_NEW, '_blank');
}, []);
return (
<>
<StepHeading> {t('alert_form_step3')} </StepHeading>
@ -137,32 +159,74 @@ function BasicInfo({
name="alert_all_configured_channels"
label="Alert all the configured channels"
>
<Switch
checked={shouldBroadCastToAllChannels}
onChange={handleBroadcastToAllChannels}
/>
<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}
/>
</Tooltip>
</FormItemMedium>
{!shouldBroadCastToAllChannels && (
<FormItemMedium
label="Notification Channels"
name="notification_channels"
required
rules={[
{ required: true, message: requireErrorMessage(t('field_alert_name')) },
]}
<Tooltip
title={
noChannels
? 'No channels. Ask an admin to create a notification channel'
: undefined
}
placement="right"
>
<ChannelSelect
disabled={shouldBroadCastToAllChannels}
currentValue={alertDef.preferredChannels}
onSelectChannels={(preferredChannels): void => {
setAlertDef({
...alertDef,
preferredChannels,
});
}}
/>
</FormItemMedium>
<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>
</>

View File

@ -1,9 +1,9 @@
import { Select } from 'antd';
import getChannels from 'api/channels/getAll';
import useFetch from 'hooks/useFetch';
import { State } from 'hooks/useFetch';
import { useNotifications } from 'hooks/useNotifications';
import { ReactNode } from 'react';
import { useTranslation } from 'react-i18next';
import { PayloadProps } from 'types/api/channels/getAll';
import { StyledSelect } from './styles';
@ -11,38 +11,42 @@ export interface ChannelSelectProps {
disabled?: boolean;
currentValue?: string[];
onSelectChannels: (s: string[]) => void;
channels: State<PayloadProps | undefined>;
}
function ChannelSelect({
disabled,
currentValue,
onSelectChannels,
channels,
}: ChannelSelectProps): JSX.Element | null {
// init namespace for translations
const { t } = useTranslation('alerts');
const { loading, payload, error, errorMessage } = useFetch(getChannels);
const { notifications } = useNotifications();
const handleChange = (value: string[]): void => {
onSelectChannels(value);
};
if (error && errorMessage !== '') {
if (channels.error && channels.errorMessage !== '') {
notifications.error({
message: 'Error',
description: errorMessage,
description: channels.errorMessage,
});
}
const renderOptions = (): ReactNode[] => {
const children: ReactNode[] = [];
if (loading || payload === undefined || payload.length === 0) {
if (
channels.loading ||
channels.payload === undefined ||
channels.payload.length === 0
) {
return children;
}
payload.forEach((o) => {
channels.payload.forEach((o) => {
children.push(
<Select.Option key={o.id} value={o.name}>
{o.name}
@ -55,7 +59,7 @@ function ChannelSelect({
return (
<StyledSelect
disabled={disabled}
status={error ? 'error' : ''}
status={channels.error ? 'error' : ''}
mode="multiple"
style={{ width: '100%' }}
placeholder={t('placeholder_channel_select')}

View File

@ -71,3 +71,7 @@
}
}
}
.create-notification-btn {
box-shadow: none;
}