(feature): UI for Test alert channels (#994)

* (feature): Implemented test channel function for webhook and slack
This commit is contained in:
Amol Umbark 2022-04-22 16:56:18 +05:30 committed by GitHub
parent 508c6ced80
commit 2b5b79e34a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 389 additions and 88 deletions

View File

@ -0,0 +1,30 @@
{
"page_title_create": "New Notification Channels",
"page_title_edit": "Edit Notification Channels",
"button_save_channel": "Save",
"button_test_channel": "Test",
"button_return": "Back",
"field_channel_name": "Name",
"field_channel_type": "Type",
"field_webhook_url": "Webhook URL",
"field_slack_recipient": "Recipient",
"field_slack_title": "Title",
"field_slack_description": "Description",
"field_webhook_username": "User Name (optional)",
"field_webhook_password": "Password (optional)",
"placeholder_slack_description": "Description",
"help_webhook_username": "Leave empty for bearer auth or when authentication is not necessary.",
"help_webhook_password": "Specify a password or bearer token",
"channel_creation_done": "Successfully created the channel",
"channel_creation_failed": "An unexpected error occurred while creating this channel",
"channel_edit_done": "Channels Edited Successfully",
"channel_edit_failed": "An unexpected error occurred while updating this channel",
"selected_channel_invalid": "Channel type selected is invalid",
"username_no_password": "A Password must be provided with user name",
"test_unsupported": "Sorry, this channel type does not support test yet",
"channel_test_done": "An alert has been sent to this channel",
"channel_test_failed": "Failed to send a test message to this channel, please confirm that the parameters are set correctly",
"channel_test_unexpected": "An unexpected error occurred while sending a message to this channel, please try again",
"webhook_url_required": "Webhook URL is mandatory",
"slack_channel_help": "Specify channel or user, use #channel-name, @username (has to be all lowercase, no whitespace)"
}

View File

@ -0,0 +1,30 @@
{
"page_title_create": "New Notification Channels",
"page_title_edit": "Edit Notification Channels",
"button_save_channel": "Save",
"button_test_channel": "Test",
"button_return": "Back",
"field_channel_name": "Name",
"field_channel_type": "Type",
"field_webhook_url": "Webhook URL",
"field_slack_recipient": "Recipient",
"field_slack_title": "Title",
"field_slack_description": "Description",
"field_webhook_username": "User Name (optional)",
"field_webhook_password": "Password (optional)",
"placeholder_slack_description": "Description",
"help_webhook_username": "Leave empty for bearer auth or when authentication is not necessary.",
"help_webhook_password": "Specify a password or bearer token",
"channel_creation_done": "Successfully created the channel",
"channel_creation_failed": "An unexpected error occurred while creating this channel",
"channel_edit_done": "Channels Edited Successfully",
"channel_edit_failed": "An unexpected error occurred while updating this channel",
"selected_channel_invalid": "Channel type selected is invalid",
"username_no_password": "A Password must be provided with user name",
"test_unsupported": "Sorry, this channel type does not support test yet",
"channel_test_done": "An alert has been sent to this channel",
"channel_test_failed": "Failed to send a test message to this channel, please confirm that the parameters are set correctly",
"channel_test_unexpected": "An unexpected error occurred while sending a message to this channel, please try again",
"webhook_url_required": "Webhook URL is mandatory",
"slack_channel_help": "Specify channel or user, use #channel-name, @username (has to be all lowercase, no whitespace)"
}

View File

@ -0,0 +1,35 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createSlack';
const testSlack = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
const response = await axios.post('/testChannel', {
name: props.name,
slack_configs: [
{
send_resolved: true,
api_url: props.api_url,
channel: props.channel,
title: props.title,
text: props.text,
},
],
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default testSlack;

View File

@ -0,0 +1,51 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createWebhook';
const testWebhook = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
let httpConfig = {};
if (props.username !== '' && props.password !== '') {
httpConfig = {
basic_auth: {
username: props.username,
password: props.password,
},
};
} else if (props.username === '' && props.password !== '') {
httpConfig = {
authorization: {
type: 'bearer',
credentials: props.password,
},
};
}
const response = await axios.post('/testChannel', {
name: props.name,
webhook_configs: [
{
send_resolved: true,
url: props.api_url,
http_config: httpConfig,
},
],
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default testWebhook;

View File

@ -1,10 +1,13 @@
import { Form, notification } from 'antd'; import { Form, notification } from 'antd';
import createSlackApi from 'api/channels/createSlack'; import createSlackApi from 'api/channels/createSlack';
import createWebhookApi from 'api/channels/createWebhook'; import createWebhookApi from 'api/channels/createWebhook';
import testSlackApi from 'api/channels/testSlack';
import testWebhookApi from 'api/channels/testWebhook';
import ROUTES from 'constants/routes'; import ROUTES from 'constants/routes';
import FormAlertChannels from 'container/FormAlertChannels'; import FormAlertChannels from 'container/FormAlertChannels';
import history from 'lib/history'; import history from 'lib/history';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { import {
ChannelType, ChannelType,
@ -17,6 +20,9 @@ import {
function CreateAlertChannels({ function CreateAlertChannels({
preType = 'slack', preType = 'slack',
}: CreateAlertChannelsProps): JSX.Element { }: CreateAlertChannelsProps): JSX.Element {
// init namespace for translations
const { t } = useTranslation('channels');
const [formInstance] = Form.useForm(); const [formInstance] = Form.useForm();
const [selectedConfig, setSelectedConfig] = useState< const [selectedConfig, setSelectedConfig] = useState<
@ -45,6 +51,7 @@ function CreateAlertChannels({
{{- end }}`, {{- end }}`,
}); });
const [savingState, setSavingState] = useState<boolean>(false); const [savingState, setSavingState] = useState<boolean>(false);
const [testingState, setTestingState] = useState<boolean>(false);
const [notifications, NotificationElement] = notification.useNotification(); const [notifications, NotificationElement] = notification.useNotification();
const [type, setType] = useState<ChannelType>(preType); const [type, setType] = useState<ChannelType>(preType);
@ -52,26 +59,26 @@ function CreateAlertChannels({
setType(value as ChannelType); setType(value as ChannelType);
}, []); }, []);
const onTestHandler = useCallback(() => { const prepareSlackRequest = useCallback(() => {
console.log('test'); return {
}, []);
const onSlackHandler = useCallback(async () => {
try {
setSavingState(true);
const response = await createSlackApi({
api_url: selectedConfig?.api_url || '', api_url: selectedConfig?.api_url || '',
channel: selectedConfig?.channel || '', channel: selectedConfig?.channel || '',
name: selectedConfig?.name || '', name: selectedConfig?.name || '',
send_resolved: true, send_resolved: true,
text: selectedConfig?.text || '', text: selectedConfig?.text || '',
title: selectedConfig?.title || '', title: selectedConfig?.title || '',
}); };
}, [selectedConfig]);
const onSlackHandler = useCallback(async () => {
try {
setSavingState(true);
const response = await createSlackApi(prepareSlackRequest());
if (response.statusCode === 200) { if (response.statusCode === 200) {
notifications.success({ notifications.success({
message: 'Success', message: 'Success',
description: 'Successfully created the channel', description: t('channel_creation_done'),
}); });
setTimeout(() => { setTimeout(() => {
history.replace(ROUTES.SETTINGS); history.replace(ROUTES.SETTINGS);
@ -79,21 +86,20 @@ function CreateAlertChannels({
} else { } else {
notifications.error({ notifications.error({
message: 'Error', message: 'Error',
description: response.error || 'Error while creating the channel', description: response.error || t('channel_creation_failed'),
}); });
} }
setSavingState(false); setSavingState(false);
} catch (error) { } catch (error) {
notifications.error({ notifications.error({
message: 'Error', message: 'Error',
description: description: t('channel_creation_failed'),
'An unexpected error occurred while creating this channel, please try again',
}); });
setSavingState(false); setSavingState(false);
} }
}, [notifications, selectedConfig]); }, [prepareSlackRequest, t, notifications]);
const onWebhookHandler = useCallback(async () => { const prepareWebhookRequest = useCallback(() => {
// initial api request without auth params // initial api request without auth params
let request: WebhookChannel = { let request: WebhookChannel = {
api_url: selectedConfig?.api_url || '', api_url: selectedConfig?.api_url || '',
@ -101,9 +107,6 @@ function CreateAlertChannels({
send_resolved: true, send_resolved: true,
}; };
setSavingState(true);
try {
if (selectedConfig?.username !== '' || selectedConfig?.password !== '') { if (selectedConfig?.username !== '' || selectedConfig?.password !== '') {
if (selectedConfig?.username !== '') { if (selectedConfig?.username !== '') {
// if username is not null then password must be passed // if username is not null then password must be passed
@ -116,7 +119,7 @@ function CreateAlertChannels({
} else { } else {
notifications.error({ notifications.error({
message: 'Error', message: 'Error',
description: 'A Password must be provided with user name', description: t('username_no_password'),
}); });
} }
} else if (selectedConfig?.password !== '') { } else if (selectedConfig?.password !== '') {
@ -128,12 +131,18 @@ function CreateAlertChannels({
}; };
} }
} }
return request;
}, [notifications, t, selectedConfig]);
const onWebhookHandler = useCallback(async () => {
setSavingState(true);
try {
const request = prepareWebhookRequest();
const response = await createWebhookApi(request); const response = await createWebhookApi(request);
if (response.statusCode === 200) { if (response.statusCode === 200) {
notifications.success({ notifications.success({
message: 'Success', message: 'Success',
description: 'Successfully created the channel', description: t('channel_creation_done'),
}); });
setTimeout(() => { setTimeout(() => {
history.replace(ROUTES.SETTINGS); history.replace(ROUTES.SETTINGS);
@ -141,19 +150,17 @@ function CreateAlertChannels({
} else { } else {
notifications.error({ notifications.error({
message: 'Error', message: 'Error',
description: response.error || 'Error while creating the channel', description: response.error || t('channel_creation_failed'),
}); });
} }
} catch (error) { } catch (error) {
notifications.error({ notifications.error({
message: 'Error', message: 'Error',
description: description: t('channel_creation_failed'),
'An unexpected error occurred while creating this channel, please try again',
}); });
} }
setSavingState(false); setSavingState(false);
}, [notifications, selectedConfig]); }, [prepareWebhookRequest, t, notifications]);
const onSaveHandler = useCallback( const onSaveHandler = useCallback(
async (value: ChannelType) => { async (value: ChannelType) => {
switch (value) { switch (value) {
@ -166,11 +173,64 @@ function CreateAlertChannels({
default: default:
notifications.error({ notifications.error({
message: 'Error', message: 'Error',
description: 'channel type selected is invalid', description: t('selected_channel_invalid'),
}); });
} }
}, },
[onSlackHandler, onWebhookHandler, notifications], [onSlackHandler, t, onWebhookHandler, notifications],
);
const performChannelTest = useCallback(
async (channelType: ChannelType) => {
setTestingState(true);
try {
let request;
let response;
switch (channelType) {
case WebhookType:
request = prepareWebhookRequest();
response = await testWebhookApi(request);
break;
case SlackType:
request = prepareSlackRequest();
response = await testSlackApi(request);
break;
default:
notifications.error({
message: 'Error',
description: t('test_unsupported'),
});
setTestingState(false);
return;
}
if (response.statusCode === 200) {
notifications.success({
message: 'Success',
description: t('channel_test_done'),
});
} else {
notifications.error({
message: 'Error',
description: t('channel_test_failed'),
});
}
} catch (error) {
notifications.error({
message: 'Error',
description: t('channel_test_unexpected'),
});
}
setTestingState(false);
},
[prepareWebhookRequest, t, prepareSlackRequest, notifications],
);
const onTestHandler = useCallback(
async (value: ChannelType) => {
performChannelTest(value);
},
[performChannelTest],
); );
return ( return (
@ -183,8 +243,9 @@ function CreateAlertChannels({
onTestHandler, onTestHandler,
onSaveHandler, onSaveHandler,
savingState, savingState,
testingState,
NotificationElement, NotificationElement,
title: 'New Notification Channels', title: t('page_title_create'),
initialValue: { initialValue: {
type, type,
...selectedConfig, ...selectedConfig,

View File

@ -1,6 +1,8 @@
import { Form, notification } from 'antd'; import { Form, notification } from 'antd';
import editSlackApi from 'api/channels/editSlack'; import editSlackApi from 'api/channels/editSlack';
import editWebhookApi from 'api/channels/editWebhook'; import editWebhookApi from 'api/channels/editWebhook';
import testSlackApi from 'api/channels/testSlack';
import testWebhookApi from 'api/channels/testWebhook';
import ROUTES from 'constants/routes'; import ROUTES from 'constants/routes';
import { import {
ChannelType, ChannelType,
@ -12,11 +14,15 @@ import {
import FormAlertChannels from 'container/FormAlertChannels'; import FormAlertChannels from 'container/FormAlertChannels';
import history from 'lib/history'; import history from 'lib/history';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
function EditAlertChannels({ function EditAlertChannels({
initialValue, initialValue,
}: EditAlertChannelsProps): JSX.Element { }: EditAlertChannelsProps): JSX.Element {
// init namespace for translations
const { t } = useTranslation('channels');
const [formInstance] = Form.useForm(); const [formInstance] = Form.useForm();
const [selectedConfig, setSelectedConfig] = useState< const [selectedConfig, setSelectedConfig] = useState<
Partial<SlackChannel & WebhookChannel> Partial<SlackChannel & WebhookChannel>
@ -24,6 +30,7 @@ function EditAlertChannels({
...initialValue, ...initialValue,
}); });
const [savingState, setSavingState] = useState<boolean>(false); const [savingState, setSavingState] = useState<boolean>(false);
const [testingState, setTestingState] = useState<boolean>(false);
const [notifications, NotificationElement] = notification.useNotification(); const [notifications, NotificationElement] = notification.useNotification();
const { id } = useParams<{ id: string }>(); const { id } = useParams<{ id: string }>();
@ -35,9 +42,8 @@ function EditAlertChannels({
setType(value as ChannelType); setType(value as ChannelType);
}, []); }, []);
const onSlackEditHandler = useCallback(async () => { const prepareSlackRequest = useCallback(() => {
setSavingState(true); return {
const response = await editSlackApi({
api_url: selectedConfig?.api_url || '', api_url: selectedConfig?.api_url || '',
channel: selectedConfig?.channel || '', channel: selectedConfig?.channel || '',
name: selectedConfig?.name || '', name: selectedConfig?.name || '',
@ -45,12 +51,27 @@ function EditAlertChannels({
text: selectedConfig?.text || '', text: selectedConfig?.text || '',
title: selectedConfig?.title || '', title: selectedConfig?.title || '',
id, id,
};
}, [id, selectedConfig]);
const onSlackEditHandler = useCallback(async () => {
setSavingState(true);
if (selectedConfig?.api_url === '') {
notifications.error({
message: 'Error',
description: t('webhook_url_required'),
}); });
setSavingState(false);
return;
}
const response = await editSlackApi(prepareSlackRequest());
if (response.statusCode === 200) { if (response.statusCode === 200) {
notifications.success({ notifications.success({
message: 'Success', message: 'Success',
description: 'Channels Edited Successfully', description: t('channel_edit_done'),
}); });
setTimeout(() => { setTimeout(() => {
@ -59,15 +80,27 @@ function EditAlertChannels({
} else { } else {
notifications.error({ notifications.error({
message: 'Error', message: 'Error',
description: response.error || 'error while updating the Channels', description: response.error || t('channel_edit_failed'),
}); });
} }
setSavingState(false); setSavingState(false);
}, [selectedConfig, notifications, id]); }, [prepareSlackRequest, t, notifications, selectedConfig]);
const prepareWebhookRequest = useCallback(() => {
const { name, username, password } = selectedConfig;
return {
api_url: selectedConfig?.api_url || '',
name: name || '',
send_resolved: true,
username,
password,
id,
};
}, [id, selectedConfig]);
const onWebhookEditHandler = useCallback(async () => { const onWebhookEditHandler = useCallback(async () => {
setSavingState(true); setSavingState(true);
const { name, username, password } = selectedConfig; const { username, password } = selectedConfig;
const showError = (msg: string): void => { const showError = (msg: string): void => {
notifications.error({ notifications.error({
@ -77,40 +110,33 @@ function EditAlertChannels({
}; };
if (selectedConfig?.api_url === '') { if (selectedConfig?.api_url === '') {
showError('Webhook URL is mandatory'); showError(t('webhook_url_required'));
setSavingState(false); setSavingState(false);
return; return;
} }
if (username && (!password || password === '')) { if (username && (!password || password === '')) {
showError('Please enter a password'); showError(t('username_no_password'));
setSavingState(false); setSavingState(false);
return; return;
} }
const response = await editWebhookApi({ const response = await editWebhookApi(prepareWebhookRequest());
api_url: selectedConfig?.api_url || '',
name: name || '',
send_resolved: true,
username,
password,
id,
});
if (response.statusCode === 200) { if (response.statusCode === 200) {
notifications.success({ notifications.success({
message: 'Success', message: 'Success',
description: 'Channels Edited Successfully', description: t('channel_edit_done'),
}); });
setTimeout(() => { setTimeout(() => {
history.replace(ROUTES.SETTINGS); history.replace(ROUTES.SETTINGS);
}, 2000); }, 2000);
} else { } else {
showError(response.error || 'error while updating the Channels'); showError(response.error || t('channel_edit_failed'));
} }
setSavingState(false); setSavingState(false);
}, [selectedConfig, notifications, id]); }, [prepareWebhookRequest, t, notifications, selectedConfig]);
const onSaveHandler = useCallback( const onSaveHandler = useCallback(
(value: ChannelType) => { (value: ChannelType) => {
@ -123,9 +149,58 @@ function EditAlertChannels({
[onSlackEditHandler, onWebhookEditHandler], [onSlackEditHandler, onWebhookEditHandler],
); );
const onTestHandler = useCallback(() => { const performChannelTest = useCallback(
console.log('test'); async (channelType: ChannelType) => {
}, []); setTestingState(true);
try {
let request;
let response;
switch (channelType) {
case WebhookType:
request = prepareWebhookRequest();
response = await testWebhookApi(request);
break;
case SlackType:
request = prepareSlackRequest();
response = await testSlackApi(request);
break;
default:
notifications.error({
message: 'Error',
description: t('test_unsupported'),
});
setTestingState(false);
return;
}
if (response.statusCode === 200) {
notifications.success({
message: 'Success',
description: t('channel_test_done'),
});
} else {
notifications.error({
message: 'Error',
description: t('channel_test_failed'),
});
}
} catch (error) {
notifications.error({
message: 'Error',
description: t('channel_test_failed'),
});
}
setTestingState(false);
},
[prepareWebhookRequest, t, prepareSlackRequest, notifications],
);
const onTestHandler = useCallback(
async (value: ChannelType) => {
performChannelTest(value);
},
[performChannelTest],
);
return ( return (
<FormAlertChannels <FormAlertChannels
@ -136,9 +211,10 @@ function EditAlertChannels({
type, type,
onTestHandler, onTestHandler,
onSaveHandler, onSaveHandler,
testingState,
savingState, savingState,
NotificationElement, NotificationElement,
title: 'Edit Notification Channels', title: t('page_title_edit'),
initialValue, initialValue,
nameDisable: true, nameDisable: true,
}} }}

View File

@ -1,15 +1,18 @@
import { Input } from 'antd'; import { Input } from 'antd';
import FormItem from 'antd/lib/form/FormItem'; import FormItem from 'antd/lib/form/FormItem';
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next';
import { SlackChannel } from '../../CreateAlertChannels/config'; import { SlackChannel } from '../../CreateAlertChannels/config';
const { TextArea } = Input; const { TextArea } = Input;
function Slack({ setSelectedConfig }: SlackProps): JSX.Element { function Slack({ setSelectedConfig }: SlackProps): JSX.Element {
const { t } = useTranslation('channels');
return ( return (
<> <>
<FormItem name="api_url" label="Webhook URL"> <FormItem name="api_url" label={t('field_webhook_url')}>
<Input <Input
onChange={(event): void => { onChange={(event): void => {
setSelectedConfig((value) => ({ setSelectedConfig((value) => ({
@ -22,8 +25,8 @@ function Slack({ setSelectedConfig }: SlackProps): JSX.Element {
<FormItem <FormItem
name="channel" name="channel"
help="Specify channel or user, use #channel-name, @username (has to be all lowercase, no whitespace)," help={t('slack_channel_help')}
label="Recipient" label={t('field_slack_recipient')}
> >
<Input <Input
onChange={(event): void => onChange={(event): void =>
@ -35,7 +38,7 @@ function Slack({ setSelectedConfig }: SlackProps): JSX.Element {
/> />
</FormItem> </FormItem>
<FormItem name="title" label="Title"> <FormItem name="title" label={t('field_slack_title')}>
<TextArea <TextArea
rows={4} rows={4}
// value={`[{{ .Status | toUpper }}{{ if eq .Status \"firing\" }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .CommonLabels.alertname }} for {{ .CommonLabels.job }}\n{{- if gt (len .CommonLabels) (len .GroupLabels) -}}\n{{\" \"}}(\n{{- with .CommonLabels.Remove .GroupLabels.Names }}\n {{- range $index, $label := .SortedPairs -}}\n {{ if $index }}, {{ end }}\n {{- $label.Name }}=\"{{ $label.Value -}}\"\n {{- end }}\n{{- end -}}\n)\n{{- end }}`} // value={`[{{ .Status | toUpper }}{{ if eq .Status \"firing\" }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .CommonLabels.alertname }} for {{ .CommonLabels.job }}\n{{- if gt (len .CommonLabels) (len .GroupLabels) -}}\n{{\" \"}}(\n{{- with .CommonLabels.Remove .GroupLabels.Names }}\n {{- range $index, $label := .SortedPairs -}}\n {{ if $index }}, {{ end }}\n {{- $label.Name }}=\"{{ $label.Value -}}\"\n {{- end }}\n{{- end -}}\n)\n{{- end }}`}
@ -48,7 +51,7 @@ function Slack({ setSelectedConfig }: SlackProps): JSX.Element {
/> />
</FormItem> </FormItem>
<FormItem name="text" label="Description"> <FormItem name="text" label={t('field_slack_description')}>
<TextArea <TextArea
onChange={(event): void => onChange={(event): void =>
setSelectedConfig((value) => ({ setSelectedConfig((value) => ({
@ -56,7 +59,7 @@ function Slack({ setSelectedConfig }: SlackProps): JSX.Element {
text: event.target.value, text: event.target.value,
})) }))
} }
placeholder="description" placeholder={t('placeholder_slack_description')}
/> />
</FormItem> </FormItem>
</> </>

View File

@ -1,13 +1,16 @@
import { Input } from 'antd'; import { Input } from 'antd';
import FormItem from 'antd/lib/form/FormItem'; import FormItem from 'antd/lib/form/FormItem';
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next';
import { WebhookChannel } from '../../CreateAlertChannels/config'; import { WebhookChannel } from '../../CreateAlertChannels/config';
function WebhookSettings({ setSelectedConfig }: WebhookProps): JSX.Element { function WebhookSettings({ setSelectedConfig }: WebhookProps): JSX.Element {
const { t } = useTranslation('channels');
return ( return (
<> <>
<FormItem name="api_url" label="Webhook URL"> <FormItem name="api_url" label={t('field_webhook_url')}>
<Input <Input
onChange={(event): void => { onChange={(event): void => {
setSelectedConfig((value) => ({ setSelectedConfig((value) => ({
@ -19,8 +22,8 @@ function WebhookSettings({ setSelectedConfig }: WebhookProps): JSX.Element {
</FormItem> </FormItem>
<FormItem <FormItem
name="username" name="username"
label="User Name (optional)" label={t('field_webhook_username')}
help="Leave empty for bearer auth or when authentication is not necessary." help={t('help_webhook_username')}
> >
<Input <Input
onChange={(event): void => { onChange={(event): void => {
@ -34,7 +37,7 @@ function WebhookSettings({ setSelectedConfig }: WebhookProps): JSX.Element {
<FormItem <FormItem
name="password" name="password"
label="Password (optional)" label="Password (optional)"
help="Specify a password or bearer token" help={t('help_webhook_password')}
> >
<Input <Input
type="password" type="password"

View File

@ -10,6 +10,7 @@ import {
} from 'container/CreateAlertChannels/config'; } from 'container/CreateAlertChannels/config';
import history from 'lib/history'; import history from 'lib/history';
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next';
import SlackSettings from './Settings/Slack'; import SlackSettings from './Settings/Slack';
import WebhookSettings from './Settings/Webhook'; import WebhookSettings from './Settings/Webhook';
@ -23,14 +24,17 @@ function FormAlertChannels({
type, type,
setSelectedConfig, setSelectedConfig,
onTypeChangeHandler, onTypeChangeHandler,
// onTestHandler, onTestHandler,
onSaveHandler, onSaveHandler,
savingState, savingState,
testingState,
NotificationElement, NotificationElement,
title, title,
initialValue, initialValue,
nameDisable = false, nameDisable = false,
}: FormAlertChannelsProps): JSX.Element { }: FormAlertChannelsProps): JSX.Element {
const { t } = useTranslation('channels');
const renderSettings = (): React.ReactElement | null => { const renderSettings = (): React.ReactElement | null => {
switch (type) { switch (type) {
case SlackType: case SlackType:
@ -48,7 +52,7 @@ function FormAlertChannels({
<Title level={3}>{title}</Title> <Title level={3}>{title}</Title>
<Form initialValues={initialValue} layout="vertical" form={formInstance}> <Form initialValues={initialValue} layout="vertical" form={formInstance}>
<FormItem label="Name" labelAlign="left" name="name"> <FormItem label={t('field_channel_name')} labelAlign="left" name="name">
<Input <Input
disabled={nameDisable} disabled={nameDisable}
onChange={(event): void => { onChange={(event): void => {
@ -60,7 +64,7 @@ function FormAlertChannels({
/> />
</FormItem> </FormItem>
<FormItem label="Type" labelAlign="left" name="type"> <FormItem label={t('field_channel_type')} labelAlign="left" name="type">
<Select onChange={onTypeChangeHandler} value={type}> <Select onChange={onTypeChangeHandler} value={type}>
<Option value="slack" key="slack"> <Option value="slack" key="slack">
Slack Slack
@ -80,15 +84,21 @@ function FormAlertChannels({
type="primary" type="primary"
onClick={(): void => onSaveHandler(type)} onClick={(): void => onSaveHandler(type)}
> >
Save {t('button_save_channel')}
</Button>
<Button
disabled={testingState}
loading={testingState}
onClick={(): void => onTestHandler(type)}
>
{t('button_test_channel')}
</Button> </Button>
{/* <Button onClick={onTestHandler}>Test</Button> */}
<Button <Button
onClick={(): void => { onClick={(): void => {
history.replace(ROUTES.SETTINGS); history.replace(ROUTES.SETTINGS);
}} }}
> >
Back {t('button_return')}
</Button> </Button>
</FormItem> </FormItem>
</Form> </Form>
@ -102,6 +112,8 @@ interface FormAlertChannelsProps {
setSelectedConfig: React.Dispatch<React.SetStateAction<Partial<SlackChannel>>>; setSelectedConfig: React.Dispatch<React.SetStateAction<Partial<SlackChannel>>>;
onTypeChangeHandler: (value: ChannelType) => void; onTypeChangeHandler: (value: ChannelType) => void;
onSaveHandler: (props: ChannelType) => void; onSaveHandler: (props: ChannelType) => void;
onTestHandler: (props: ChannelType) => void;
testingState: boolean;
savingState: boolean; savingState: boolean;
NotificationElement: React.ReactElement< NotificationElement: React.ReactElement<
unknown, unknown,