Pagerduty - Create, Edit and Test Features (#1016)

* enabled sending alerts to pagerduty
This commit is contained in:
Amol Umbark 2022-05-03 11:28:00 +05:30 committed by GitHub
parent 642ece288e
commit 3ef9d96678
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 728 additions and 45 deletions

View File

@ -12,9 +12,27 @@
"field_slack_description": "Description",
"field_webhook_username": "User Name (optional)",
"field_webhook_password": "Password (optional)",
"field_pager_routing_key": "Routing Key",
"field_pager_description": "Description",
"field_pager_severity": "Severity",
"field_pager_details": "Additional Information",
"field_pager_component": "Component",
"field_pager_group": "Group",
"field_pager_class": "Class",
"field_pager_client": "Client",
"field_pager_client_url": "Client URL",
"placeholder_slack_description": "Description",
"placeholder_pager_description": "Description",
"help_pager_client": "Shows up as event source in Pagerduty",
"help_pager_client_url": "Shows up as event source link in Pagerduty",
"help_pager_class": "The class/type of the event",
"help_pager_details": "Specify a key-value format (must be a valid json)",
"help_pager_group": "A cluster or grouping of sources",
"help_pager_component": "The part or component of the affected system that is broke",
"help_pager_severity": "Severity of the incident, must be one of: must be one of the following: 'critical', 'warning', 'error' or 'info'",
"help_webhook_username": "Leave empty for bearer auth or when authentication is not necessary.",
"help_webhook_password": "Specify a password or bearer token",
"help_pager_description": "Shows up as description in pagerduty",
"channel_creation_done": "Successfully created the channel",
"channel_creation_failed": "An unexpected error occurred while creating this channel",
"channel_edit_done": "Channels Edited Successfully",

View File

@ -12,9 +12,27 @@
"field_slack_description": "Description",
"field_webhook_username": "User Name (optional)",
"field_webhook_password": "Password (optional)",
"field_pager_routing_key": "Routing Key",
"field_pager_description": "Description",
"field_pager_severity": "Severity",
"field_pager_details": "Additional Information",
"field_pager_component": "Component",
"field_pager_group": "Group",
"field_pager_class": "Class",
"field_pager_client": "Client",
"field_pager_client_url": "Client URL",
"placeholder_slack_description": "Description",
"placeholder_pager_description": "Description",
"help_pager_client": "Shows up as event source in Pagerduty",
"help_pager_client_url": "Shows up as event source link in Pagerduty",
"help_pager_class": "The class/type of the event",
"help_pager_details": "Specify a key-value format (must be a valid json)",
"help_pager_group": "A cluster or grouping of sources",
"help_pager_component": "The part or component of the affected system that is broke",
"help_pager_severity": "Severity of the incident, must be one of: must be one of the following: 'critical', 'warning', 'error' or 'info'",
"help_webhook_username": "Leave empty for bearer auth or when authentication is not necessary.",
"help_webhook_password": "Specify a password or bearer token",
"help_pager_description": "Shows up as description in pagerduty",
"channel_creation_done": "Successfully created the channel",
"channel_creation_failed": "An unexpected error occurred while creating this channel",
"channel_edit_done": "Channels Edited Successfully",

View File

@ -0,0 +1,42 @@
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/createPager';
const create = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
const response = await axios.post('/channels', {
name: props.name,
pagerduty_configs: [
{
send_resolved: true,
routing_key: props.routing_key,
client: props.client,
client_url: props.client_url,
description: props.description,
severity: props.severity,
class: props.class,
component: props.component,
group: props.group,
details: {
...props.detailsArray,
},
},
],
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default create;

View File

@ -0,0 +1,42 @@
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/editPager';
const editPager = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
const response = await axios.put(`/channels/${props.id}`, {
name: props.name,
pagerduty_configs: [
{
send_resolved: true,
routing_key: props.routing_key,
client: props.client,
client_url: props.client_url,
description: props.description,
severity: props.severity,
class: props.class,
component: props.component,
group: props.group,
details: {
...props.detailsArray,
},
},
],
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default editPager;

View File

@ -0,0 +1,42 @@
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/createPager';
const testPager = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
const response = await axios.post('/testChannel', {
name: props.name,
pagerduty_configs: [
{
send_resolved: true,
routing_key: props.routing_key,
client: props.client,
client_url: props.client_url,
description: props.description,
severity: props.severity,
class: props.class,
component: props.component,
group: props.group,
details: {
...props.detailsArray,
},
},
],
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default testPager;

View File

@ -1,6 +1,7 @@
export interface Channel {
send_resolved?: boolean;
name: string;
filter?: Partial<Array<LabelFilterStatement>>;
}
export interface SlackChannel extends Channel {
@ -17,6 +18,66 @@ export interface WebhookChannel extends Channel {
password?: string;
}
export type ChannelType = 'slack' | 'email' | 'webhook';
// PagerChannel configures alert manager to send
// events to pagerduty
export interface PagerChannel extends Channel {
// ref: https://prometheus.io/docs/alerting/latest/configuration/#pagerduty_config
routing_key?: string;
// displays source of the event in pager duty
client?: string;
client_url?: string;
// A description of the incident
description?: string;
// Severity of the incident
severity?: string;
// The part or component of the affected system that is broken
component?: string;
// A cluster or grouping of sources
group?: string;
// The class/type of the event.
class?: string;
details?: string;
detailsArray?: Record<string, string>;
}
export const ValidatePagerChannel = (p: PagerChannel): string => {
if (!p) {
return 'Received unexpected input for this channel, please contact your administrator ';
}
if (!p.name || p.name === '') {
return 'Name is mandatory for creating a channel';
}
if (!p.routing_key || p.routing_key === '') {
return 'Routing Key is mandatory for creating pagerduty channel';
}
// validate details json
try {
JSON.parse(p.details || '{}');
} catch (e) {
return 'failed to parse additional information, please enter a valid json';
}
return '';
};
export type ChannelType = 'slack' | 'email' | 'webhook' | 'pagerduty';
export const SlackType: ChannelType = 'slack';
export const WebhookType: ChannelType = 'webhook';
export const PagerType: ChannelType = 'pagerduty';
// LabelFilterStatement will be used for preparing filter conditions / matchers
export interface LabelFilterStatement {
// ref: https://prometheus.io/docs/alerting/latest/configuration/#matcher
// label name
name: string;
// comparators supported by promql are =, !=, =~, or !~. =
comparator: string;
// filter value
value: string;
}

View File

@ -0,0 +1,22 @@
import { PagerChannel } from './config';
export const PagerInitialConfig: Partial<PagerChannel> = {
description: `{{ range .Alerts -}}
*Alert:* {{ if .Annotations.title }} {{ .Annotations.title }} {{ else }} {{ .Annotations.summary }} {{end}} {{ if .Labels.severity }} - {{ .Labels.severity }}{{ end }}
*Description:* {{ .Annotations.description }}
*Details:*
{{ range .Labels.SortedPairs }} *{{ .Name }}:* {{ .Value }}
{{ end }}
{{ end }}`,
severity: '{{ (index .Alerts 0).Labels.severity }}',
client: 'SigNoz Alert Manager',
client_url: 'https://enter-signoz-host-n-port-here/alerts',
details: JSON.stringify({
firing: `{{ template "pagerduty.default.instances" .Alerts.Firing }}`,
resolved: `{{ template "pagerduty.default.instances" .Alerts.Resolved }}`,
num_firing: '{{ .Alerts.Firing | len }}',
num_resolved: '{{ .Alerts.Resolved | len }}',
}),
};

View File

@ -1,6 +1,8 @@
import { Form, notification } from 'antd';
import createPagerApi from 'api/channels/createPager';
import createSlackApi from 'api/channels/createSlack';
import createWebhookApi from 'api/channels/createWebhook';
import testPagerApi from 'api/channels/testPager';
import testSlackApi from 'api/channels/testSlack';
import testWebhookApi from 'api/channels/testWebhook';
import ROUTES from 'constants/routes';
@ -11,11 +13,15 @@ import { useTranslation } from 'react-i18next';
import {
ChannelType,
PagerChannel,
PagerType,
SlackChannel,
SlackType,
ValidatePagerChannel,
WebhookChannel,
WebhookType,
} from './config';
import { PagerInitialConfig } from './defaults';
function CreateAlertChannels({
preType = 'slack',
@ -26,7 +32,7 @@ function CreateAlertChannels({
const [formInstance] = Form.useForm();
const [selectedConfig, setSelectedConfig] = useState<
Partial<SlackChannel & WebhookChannel>
Partial<SlackChannel & WebhookChannel & PagerChannel>
>({
text: `{{ range .Alerts -}}
*Alert:* {{ .Labels.alertname }}{{ if .Labels.severity }} - {{ .Labels.severity }}{{ end }}
@ -55,9 +61,22 @@ function CreateAlertChannels({
const [notifications, NotificationElement] = notification.useNotification();
const [type, setType] = useState<ChannelType>(preType);
const onTypeChangeHandler = useCallback((value: string) => {
setType(value as ChannelType);
}, []);
const onTypeChangeHandler = useCallback(
(value: string) => {
const currentType = type;
setType(value as ChannelType);
if (value === PagerType && currentType !== value) {
// reset config to pager defaults
setSelectedConfig({
name: selectedConfig?.name,
send_resolved: selectedConfig.send_resolved,
...PagerInitialConfig,
});
}
},
[type, selectedConfig],
);
const prepareSlackRequest = useCallback(() => {
return {
@ -71,8 +90,9 @@ function CreateAlertChannels({
}, [selectedConfig]);
const onSlackHandler = useCallback(async () => {
setSavingState(true);
try {
setSavingState(true);
const response = await createSlackApi(prepareSlackRequest());
if (response.statusCode === 200) {
@ -89,14 +109,13 @@ function CreateAlertChannels({
description: response.error || t('channel_creation_failed'),
});
}
setSavingState(false);
} catch (error) {
notifications.error({
message: 'Error',
description: t('channel_creation_failed'),
});
setSavingState(false);
}
setSavingState(false);
}, [prepareSlackRequest, t, notifications]);
const prepareWebhookRequest = useCallback(() => {
@ -161,6 +180,65 @@ function CreateAlertChannels({
}
setSavingState(false);
}, [prepareWebhookRequest, t, notifications]);
const preparePagerRequest = useCallback(() => {
const validationError = ValidatePagerChannel(selectedConfig as PagerChannel);
if (validationError !== '') {
notifications.error({
message: 'Error',
description: validationError,
});
return null;
}
return {
name: selectedConfig?.name || '',
send_resolved: true,
routing_key: selectedConfig?.routing_key || '',
client: selectedConfig?.client || '',
client_url: selectedConfig?.client_url || '',
description: selectedConfig?.description || '',
severity: selectedConfig?.severity || '',
component: selectedConfig?.component || '',
group: selectedConfig?.group || '',
class: selectedConfig?.class || '',
details: selectedConfig.details || '',
detailsArray: JSON.parse(selectedConfig.details || '{}'),
};
}, [selectedConfig, notifications]);
const onPagerHandler = useCallback(async () => {
setSavingState(true);
const request = preparePagerRequest();
if (request) {
try {
const response = await createPagerApi(request);
if (response.statusCode === 200) {
notifications.success({
message: 'Success',
description: t('channel_creation_done'),
});
setTimeout(() => {
history.replace(ROUTES.SETTINGS);
}, 2000);
} else {
notifications.error({
message: 'Error',
description: response.error || t('channel_creation_failed'),
});
}
} catch (e) {
notifications.error({
message: 'Error',
description: t('channel_creation_failed'),
});
}
}
setSavingState(false);
}, [t, notifications, preparePagerRequest]);
const onSaveHandler = useCallback(
async (value: ChannelType) => {
switch (value) {
@ -170,6 +248,9 @@ function CreateAlertChannels({
case WebhookType:
onWebhookHandler();
break;
case PagerType:
onPagerHandler();
break;
default:
notifications.error({
message: 'Error',
@ -177,7 +258,7 @@ function CreateAlertChannels({
});
}
},
[onSlackHandler, t, onWebhookHandler, notifications],
[onSlackHandler, t, onPagerHandler, onWebhookHandler, notifications],
);
const performChannelTest = useCallback(
@ -195,6 +276,10 @@ function CreateAlertChannels({
request = prepareSlackRequest();
response = await testSlackApi(request);
break;
case PagerType:
request = preparePagerRequest();
if (request) response = await testPagerApi(request);
break;
default:
notifications.error({
message: 'Error',
@ -204,7 +289,7 @@ function CreateAlertChannels({
return;
}
if (response.statusCode === 200) {
if (response && response.statusCode === 200) {
notifications.success({
message: 'Success',
description: t('channel_test_done'),
@ -223,7 +308,13 @@ function CreateAlertChannels({
}
setTestingState(false);
},
[prepareWebhookRequest, t, prepareSlackRequest, notifications],
[
prepareWebhookRequest,
t,
preparePagerRequest,
prepareSlackRequest,
notifications,
],
);
const onTestHandler = useCallback(
@ -249,6 +340,7 @@ function CreateAlertChannels({
initialValue: {
type,
...selectedConfig,
...PagerInitialConfig,
},
}}
/>

View File

@ -1,13 +1,18 @@
import { Form, notification } from 'antd';
import editPagerApi from 'api/channels/editPager';
import editSlackApi from 'api/channels/editSlack';
import editWebhookApi from 'api/channels/editWebhook';
import testPagerApi from 'api/channels/testPager';
import testSlackApi from 'api/channels/testSlack';
import testWebhookApi from 'api/channels/testWebhook';
import ROUTES from 'constants/routes';
import {
ChannelType,
PagerChannel,
PagerType,
SlackChannel,
SlackType,
ValidatePagerChannel,
WebhookChannel,
WebhookType,
} from 'container/CreateAlertChannels/config';
@ -25,7 +30,7 @@ function EditAlertChannels({
const [formInstance] = Form.useForm();
const [selectedConfig, setSelectedConfig] = useState<
Partial<SlackChannel & WebhookChannel>
Partial<SlackChannel & WebhookChannel & PagerChannel>
>({
...initialValue,
});
@ -138,15 +143,66 @@ function EditAlertChannels({
setSavingState(false);
}, [prepareWebhookRequest, t, notifications, selectedConfig]);
const preparePagerRequest = useCallback(() => {
return {
name: selectedConfig.name || '',
routing_key: selectedConfig.routing_key,
client: selectedConfig.client,
client_url: selectedConfig.client_url,
description: selectedConfig.description,
severity: selectedConfig.severity,
component: selectedConfig.component,
class: selectedConfig.class,
group: selectedConfig.group,
details: selectedConfig.details,
detailsArray: JSON.parse(selectedConfig.details || '{}'),
id,
};
}, [id, selectedConfig]);
const onPagerEditHandler = useCallback(async () => {
setSavingState(true);
const validationError = ValidatePagerChannel(selectedConfig as PagerChannel);
if (validationError !== '') {
notifications.error({
message: 'Error',
description: validationError,
});
setSavingState(false);
return;
}
const response = await editPagerApi(preparePagerRequest());
if (response.statusCode === 200) {
notifications.success({
message: 'Success',
description: t('channel_edit_done'),
});
setTimeout(() => {
history.replace(ROUTES.SETTINGS);
}, 2000);
} else {
notifications.error({
message: 'Error',
description: response.error || t('channel_edit_failed'),
});
}
setSavingState(false);
}, [preparePagerRequest, notifications, selectedConfig, t]);
const onSaveHandler = useCallback(
(value: ChannelType) => {
if (value === SlackType) {
onSlackEditHandler();
} else if (value === WebhookType) {
onWebhookEditHandler();
} else if (value === PagerType) {
onPagerEditHandler();
}
},
[onSlackEditHandler, onWebhookEditHandler],
[onSlackEditHandler, onWebhookEditHandler, onPagerEditHandler],
);
const performChannelTest = useCallback(
@ -164,6 +220,10 @@ function EditAlertChannels({
request = prepareSlackRequest();
response = await testSlackApi(request);
break;
case PagerType:
request = preparePagerRequest();
if (request) response = await testPagerApi(request);
break;
default:
notifications.error({
message: 'Error',
@ -173,7 +233,7 @@ function EditAlertChannels({
return;
}
if (response.statusCode === 200) {
if (response && response.statusCode === 200) {
notifications.success({
message: 'Success',
description: t('channel_test_done'),
@ -192,7 +252,13 @@ function EditAlertChannels({
}
setTestingState(false);
},
[prepareWebhookRequest, t, prepareSlackRequest, notifications],
[
t,
prepareWebhookRequest,
preparePagerRequest,
prepareSlackRequest,
notifications,
],
);
const onTestHandler = useCallback(
@ -216,7 +282,7 @@ function EditAlertChannels({
NotificationElement,
title: t('page_title_edit'),
initialValue,
nameDisable: true,
editing: true,
}}
/>
);

View File

@ -0,0 +1,64 @@
import { Input, Select } from 'antd';
import FormItem from 'antd/lib/form/FormItem';
import { LabelFilterStatement } from 'container/CreateAlertChannels/config';
import React from 'react';
const { Option } = Select;
// LabelFilterForm supports filters or matchers on alert notifications
// presently un-used but will be introduced to the channel creation at some
// point
function LabelFilterForm({ setFilter }: LabelFilterProps): JSX.Element {
return (
<FormItem name="label_filter" label="Notify When (Optional)">
<Input.Group compact>
<Select
defaultValue="Severity"
style={{ width: '15%' }}
onChange={(event): void => {
setFilter((value) => {
const first: LabelFilterStatement = value[0] as LabelFilterStatement;
first.name = event;
return [first];
});
}}
>
<Option value="severity">Severity</Option>
<Option value="service">Service</Option>
</Select>
<Select
defaultValue="="
onChange={(event): void => {
setFilter((value) => {
const first: LabelFilterStatement = value[0] as LabelFilterStatement;
first.comparator = event;
return [first];
});
}}
>
<Option value="=">=</Option>
<Option value="!=">!=</Option>
</Select>
<Input
style={{ width: '20%' }}
placeholder="enter a text here"
onChange={(event): void => {
setFilter((value) => {
const first: LabelFilterStatement = value[0] as LabelFilterStatement;
first.value = event.target.value;
return [first];
});
}}
/>
</Input.Group>
</FormItem>
);
}
export interface LabelFilterProps {
setFilter: React.Dispatch<
React.SetStateAction<Partial<Array<LabelFilterStatement>>>
>;
}
export default LabelFilterForm;

View File

@ -0,0 +1,155 @@
import { Input } from 'antd';
import FormItem from 'antd/lib/form/FormItem';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { PagerChannel } from '../../CreateAlertChannels/config';
const { TextArea } = Input;
function PagerForm({ setSelectedConfig }: PagerFormProps): JSX.Element {
const { t } = useTranslation('channels');
return (
<>
<FormItem name="routing_key" label={t('field_pager_routing_key')} required>
<Input
onChange={(event): void => {
setSelectedConfig((value) => ({
...value,
routing_key: event.target.value,
}));
}}
/>
</FormItem>
<FormItem
name="description"
help={t('help_pager_description')}
label={t('field_pager_description')}
required
>
<TextArea
rows={4}
onChange={(event): void =>
setSelectedConfig((value) => ({
...value,
description: event.target.value,
}))
}
placeholder={t('placeholder_pager_description')}
/>
</FormItem>
<FormItem
name="severity"
help={t('help_pager_severity')}
label={t('field_pager_severity')}
>
<Input
onChange={(event): void =>
setSelectedConfig((value) => ({
...value,
severity: event.target.value,
}))
}
/>
</FormItem>
<FormItem
name="details"
help={t('help_pager_details')}
label={t('field_pager_details')}
>
<TextArea
rows={4}
onChange={(event): void =>
setSelectedConfig((value) => ({
...value,
details: event.target.value,
}))
}
/>
</FormItem>
<FormItem
name="component"
help={t('help_pager_component')}
label={t('field_pager_component')}
>
<Input
onChange={(event): void =>
setSelectedConfig((value) => ({
...value,
component: event.target.value,
}))
}
/>
</FormItem>
<FormItem
name="group"
help={t('help_pager_group')}
label={t('field_pager_group')}
>
<Input
onChange={(event): void =>
setSelectedConfig((value) => ({
...value,
group: event.target.value,
}))
}
/>
</FormItem>
<FormItem
name="class"
help={t('help_pager_class')}
label={t('field_pager_class')}
>
<Input
onChange={(event): void =>
setSelectedConfig((value) => ({
...value,
class: event.target.value,
}))
}
/>
</FormItem>
<FormItem
name="client"
help={t('help_pager_client')}
label={t('field_pager_client')}
>
<Input
onChange={(event): void =>
setSelectedConfig((value) => ({
...value,
client: event.target.value,
}))
}
/>
</FormItem>
<FormItem
name="client_url"
help={t('help_pager_client_url')}
label={t('field_pager_client_url')}
>
<Input
onChange={(event): void =>
setSelectedConfig((value) => ({
...value,
client_url: event.target.value,
}))
}
/>
</FormItem>
</>
);
}
interface PagerFormProps {
setSelectedConfig: React.Dispatch<React.SetStateAction<Partial<PagerChannel>>>;
}
export default PagerForm;

View File

@ -4,14 +4,18 @@ import { Store } from 'antd/lib/form/interface';
import ROUTES from 'constants/routes';
import {
ChannelType,
PagerChannel,
PagerType,
SlackChannel,
SlackType,
WebhookChannel,
WebhookType,
} from 'container/CreateAlertChannels/config';
import history from 'lib/history';
import React from 'react';
import { useTranslation } from 'react-i18next';
import PagerSettings from './Settings/Pager';
import SlackSettings from './Settings/Slack';
import WebhookSettings from './Settings/Webhook';
import { Button } from './styles';
@ -31,7 +35,7 @@ function FormAlertChannels({
NotificationElement,
title,
initialValue,
nameDisable = false,
editing = false,
}: FormAlertChannelsProps): JSX.Element {
const { t } = useTranslation('channels');
@ -41,6 +45,9 @@ function FormAlertChannels({
return <SlackSettings setSelectedConfig={setSelectedConfig} />;
case WebhookType:
return <WebhookSettings setSelectedConfig={setSelectedConfig} />;
case PagerType:
return <PagerSettings setSelectedConfig={setSelectedConfig} />;
default:
return null;
}
@ -54,7 +61,7 @@ function FormAlertChannels({
<Form initialValues={initialValue} layout="vertical" form={formInstance}>
<FormItem label={t('field_channel_name')} labelAlign="left" name="name">
<Input
disabled={nameDisable}
disabled={editing}
onChange={(event): void => {
setSelectedConfig((state) => ({
...state,
@ -65,13 +72,16 @@ function FormAlertChannels({
</FormItem>
<FormItem label={t('field_channel_type')} labelAlign="left" name="type">
<Select onChange={onTypeChangeHandler} value={type}>
<Select disabled={editing} onChange={onTypeChangeHandler} value={type}>
<Option value="slack" key="slack">
Slack
</Option>
<Option value="webhook" key="webhook">
Webhook
</Option>
<Option value="pagerduty" key="pagerduty">
Pagerduty
</Option>
</Select>
</FormItem>
@ -109,7 +119,9 @@ function FormAlertChannels({
interface FormAlertChannelsProps {
formInstance: FormInstance;
type: ChannelType;
setSelectedConfig: React.Dispatch<React.SetStateAction<Partial<SlackChannel>>>;
setSelectedConfig: React.Dispatch<
React.SetStateAction<Partial<SlackChannel & WebhookChannel & PagerChannel>>
>;
onTypeChangeHandler: (value: ChannelType) => void;
onSaveHandler: (props: ChannelType) => void;
onTestHandler: (props: ChannelType) => void;
@ -121,11 +133,12 @@ interface FormAlertChannelsProps {
>;
title: string;
initialValue: Store;
nameDisable?: boolean;
// editing indicates if the form is opened in edit mode
editing?: boolean;
}
FormAlertChannels.defaultProps = {
nameDisable: undefined,
editing: undefined,
};
export default FormAlertChannels;

View File

@ -2,6 +2,8 @@ import { Typography } from 'antd';
import get from 'api/channels/get';
import Spinner from 'components/Spinner';
import {
PagerChannel,
PagerType,
SlackChannel,
SlackType,
WebhookChannel,
@ -35,36 +37,64 @@ function ChannelsEdit(): JSX.Element {
const { data: ChannelData } = data.payload;
const value = JSON.parse(ChannelData);
let type = '';
let channel: SlackChannel & WebhookChannel = { name: '' };
if (value && 'slack_configs' in value) {
const slackConfig = value.slack_configs[0];
channel = slackConfig;
type = SlackType;
} else if (value && 'webhook_configs' in value) {
const webhookConfig = value.webhook_configs[0];
channel = webhookConfig;
channel.api_url = webhookConfig.url;
if ('http_config' in webhookConfig) {
const httpConfig = webhookConfig.http_config;
if ('basic_auth' in httpConfig) {
channel.username = webhookConfig.http_config?.basic_auth?.username;
channel.password = webhookConfig.http_config?.basic_auth?.password;
} else if ('authorization' in httpConfig) {
channel.password = webhookConfig.http_config?.authorization?.credentials;
}
const prepChannelConfig = (): {
type: string;
channel: SlackChannel & WebhookChannel & PagerChannel;
} => {
let channel: SlackChannel & WebhookChannel & PagerChannel = { name: '' };
if (value && 'slack_configs' in value) {
const slackConfig = value.slack_configs[0];
channel = slackConfig;
return {
type: SlackType,
channel,
};
}
type = WebhookType;
}
if (value && 'pagerduty_configs' in value) {
const pagerConfig = value.pagerduty_configs[0];
channel = pagerConfig;
channel.details = JSON.stringify(pagerConfig.details);
channel.detailsArray = { ...pagerConfig.details };
return {
type: PagerType,
channel,
};
}
if (value && 'webhook_configs' in value) {
const webhookConfig = value.webhook_configs[0];
channel = webhookConfig;
channel.api_url = webhookConfig.url;
if ('http_config' in webhookConfig) {
const httpConfig = webhookConfig.http_config;
if ('basic_auth' in httpConfig) {
channel.username = webhookConfig.http_config?.basic_auth?.username;
channel.password = webhookConfig.http_config?.basic_auth?.password;
} else if ('authorization' in httpConfig) {
channel.password = webhookConfig.http_config?.authorization?.credentials;
}
}
return {
type: WebhookType,
channel,
};
}
return {
type: SlackType,
channel,
};
};
const target = prepChannelConfig();
return (
<EditAlertChannels
{...{
initialValue: {
...channel,
type,
...target.channel,
type: target.type,
name: value.name,
},
}}

View File

@ -0,0 +1,8 @@
import { PagerChannel } from 'container/CreateAlertChannels/config';
export type Props = PagerChannel;
export interface PayloadProps {
data: string;
status: string;
}

View File

@ -0,0 +1,10 @@
import { PagerChannel } from 'container/CreateAlertChannels/config';
export interface Props extends PagerChannel {
id: string;
}
export interface PayloadProps {
data: string;
status: string;
}