mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-14 01:15:52 +08:00
feat: opsgenie integration (#3429)
This commit is contained in:
parent
e596dd77bd
commit
218eb5379e
@ -81,6 +81,13 @@ var BasicPlan = basemodel.FeatureSet{
|
||||
UsageLimit: -1,
|
||||
Route: "",
|
||||
},
|
||||
basemodel.Feature{
|
||||
Name: basemodel.AlertChannelOpsgenie,
|
||||
Active: true,
|
||||
Usage: 0,
|
||||
UsageLimit: -1,
|
||||
Route: "",
|
||||
},
|
||||
basemodel.Feature{
|
||||
Name: basemodel.AlertChannelMsTeams,
|
||||
Active: false,
|
||||
@ -161,6 +168,13 @@ var ProPlan = basemodel.FeatureSet{
|
||||
UsageLimit: -1,
|
||||
Route: "",
|
||||
},
|
||||
basemodel.Feature{
|
||||
Name: basemodel.AlertChannelOpsgenie,
|
||||
Active: true,
|
||||
Usage: 0,
|
||||
UsageLimit: -1,
|
||||
Route: "",
|
||||
},
|
||||
basemodel.Feature{
|
||||
Name: basemodel.AlertChannelMsTeams,
|
||||
Active: true,
|
||||
@ -241,6 +255,13 @@ var EnterprisePlan = basemodel.FeatureSet{
|
||||
UsageLimit: -1,
|
||||
Route: "",
|
||||
},
|
||||
basemodel.Feature{
|
||||
Name: basemodel.AlertChannelOpsgenie,
|
||||
Active: true,
|
||||
Usage: 0,
|
||||
UsageLimit: -1,
|
||||
Route: "",
|
||||
},
|
||||
basemodel.Feature{
|
||||
Name: basemodel.AlertChannelMsTeams,
|
||||
Active: true,
|
||||
|
@ -20,6 +20,9 @@
|
||||
"field_slack_recipient": "Recipient",
|
||||
"field_slack_title": "Title",
|
||||
"field_slack_description": "Description",
|
||||
"field_opsgenie_api_key": "API Key",
|
||||
"field_opsgenie_description": "Description",
|
||||
"placeholder_opsgenie_description": "Description",
|
||||
"field_webhook_username": "User Name (optional)",
|
||||
"field_webhook_password": "Password (optional)",
|
||||
"field_pager_routing_key": "Routing Key",
|
||||
@ -31,8 +34,12 @@
|
||||
"field_pager_class": "Class",
|
||||
"field_pager_client": "Client",
|
||||
"field_pager_client_url": "Client URL",
|
||||
"field_opsgenie_message": "Message",
|
||||
"field_opsgenie_priority": "Priority",
|
||||
"placeholder_slack_description": "Description",
|
||||
"placeholder_pager_description": "Description",
|
||||
"placeholder_opsgenie_message": "Message",
|
||||
"placeholder_opsgenie_priority": "Priority",
|
||||
"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",
|
||||
@ -43,6 +50,9 @@
|
||||
"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",
|
||||
"help_opsgenie_message": "Shows up as message in opsgenie",
|
||||
"help_opsgenie_priority": "Priority of the incident",
|
||||
"help_opsgenie_description": "Shows up as description in opsgenie",
|
||||
"channel_creation_done": "Successfully created the channel",
|
||||
"channel_creation_failed": "An unexpected error occurred while creating this channel",
|
||||
"channel_edit_done": "Channels Edited Successfully",
|
||||
|
37
frontend/src/api/channels/createOpsgenie.ts
Normal file
37
frontend/src/api/channels/createOpsgenie.ts
Normal file
@ -0,0 +1,37 @@
|
||||
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/createOpsgenie';
|
||||
|
||||
const create = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
try {
|
||||
const response = await axios.post('/channels', {
|
||||
name: props.name,
|
||||
opsgenie_configs: [
|
||||
{
|
||||
api_key: props.api_key,
|
||||
description: props.description,
|
||||
priority: props.priority,
|
||||
message: props.message,
|
||||
details: {
|
||||
...props.detailsArray,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: 'Success',
|
||||
payload: response.data.data,
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponseHandler(error as AxiosError);
|
||||
}
|
||||
};
|
||||
|
||||
export default create;
|
38
frontend/src/api/channels/editOpsgenie.ts
Normal file
38
frontend/src/api/channels/editOpsgenie.ts
Normal file
@ -0,0 +1,38 @@
|
||||
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/editOpsgenie';
|
||||
|
||||
const editOpsgenie = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
try {
|
||||
const response = await axios.put(`/channels/${props.id}`, {
|
||||
name: props.name,
|
||||
opsgenie_configs: [
|
||||
{
|
||||
send_resolved: true,
|
||||
api_key: props.api_key,
|
||||
description: props.description,
|
||||
priority: props.priority,
|
||||
message: props.message,
|
||||
details: {
|
||||
...props.detailsArray,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: 'Success',
|
||||
payload: response.data.data,
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponseHandler(error as AxiosError);
|
||||
}
|
||||
};
|
||||
|
||||
export default editOpsgenie;
|
37
frontend/src/api/channels/testOpsgenie.ts
Normal file
37
frontend/src/api/channels/testOpsgenie.ts
Normal file
@ -0,0 +1,37 @@
|
||||
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/createOpsgenie';
|
||||
|
||||
const testOpsgenie = async (
|
||||
props: Props,
|
||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||
try {
|
||||
const response = await axios.post('/testChannel', {
|
||||
name: props.name,
|
||||
opsgenie_configs: [
|
||||
{
|
||||
api_key: props.api_key,
|
||||
description: props.description,
|
||||
priority: props.priority,
|
||||
message: props.message,
|
||||
details: {
|
||||
...props.detailsArray,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: 'Success',
|
||||
payload: response.data.data,
|
||||
};
|
||||
} catch (error) {
|
||||
return ErrorResponseHandler(error as AxiosError);
|
||||
}
|
||||
};
|
||||
|
||||
export default testOpsgenie;
|
@ -6,6 +6,7 @@ export enum FeatureKeys {
|
||||
ALERT_CHANNEL_SLACK = 'ALERT_CHANNEL_SLACK',
|
||||
ALERT_CHANNEL_WEBHOOK = 'ALERT_CHANNEL_WEBHOOK',
|
||||
ALERT_CHANNEL_PAGERDUTY = 'ALERT_CHANNEL_PAGERDUTY',
|
||||
ALERT_CHANNEL_OPSGENIE = 'ALERT_CHANNEL_OPSGENIE',
|
||||
ALERT_CHANNEL_MSTEAMS = 'ALERT_CHANNEL_MSTEAMS',
|
||||
DurationSort = 'DurationSort',
|
||||
TimestampSort = 'TimestampSort',
|
||||
|
@ -40,6 +40,30 @@ export interface PagerChannel extends Channel {
|
||||
details?: string;
|
||||
detailsArray?: Record<string, string>;
|
||||
}
|
||||
|
||||
// OpsgenieChannel configures alert manager to send
|
||||
// events to opsgenie
|
||||
export interface OpsgenieChannel extends Channel {
|
||||
// ref: https://prometheus.io/docs/alerting/latest/configuration/#opsgenie_config
|
||||
api_key: string;
|
||||
|
||||
message?: string;
|
||||
|
||||
// A description of the incident
|
||||
description?: string;
|
||||
|
||||
// A backlink to the sender of the notification.
|
||||
source?: string;
|
||||
|
||||
// A set of arbitrary key/value pairs that provide further detail
|
||||
// about the alert.
|
||||
details?: string;
|
||||
detailsArray?: Record<string, string>;
|
||||
|
||||
// Priority level of alert. Possible values are P1, P2, P3, P4, and P5.
|
||||
priority?: string;
|
||||
}
|
||||
|
||||
export const ValidatePagerChannel = (p: PagerChannel): string => {
|
||||
if (!p) {
|
||||
return 'Received unexpected input for this channel, please contact your administrator ';
|
||||
@ -63,16 +87,14 @@ export const ValidatePagerChannel = (p: PagerChannel): string => {
|
||||
return '';
|
||||
};
|
||||
|
||||
export type ChannelType =
|
||||
| 'slack'
|
||||
| 'email'
|
||||
| 'webhook'
|
||||
| 'pagerduty'
|
||||
| 'msteams';
|
||||
export const SlackType: ChannelType = 'slack';
|
||||
export const WebhookType: ChannelType = 'webhook';
|
||||
export const PagerType: ChannelType = 'pagerduty';
|
||||
export const MsTeamsType: ChannelType = 'msteams';
|
||||
export enum ChannelType {
|
||||
Slack = 'slack',
|
||||
Email = 'email',
|
||||
Webhook = 'webhook',
|
||||
Pagerduty = 'pagerduty',
|
||||
Opsgenie = 'opsgenie',
|
||||
MsTeams = 'msteams',
|
||||
}
|
||||
|
||||
// LabelFilterStatement will be used for preparing filter conditions / matchers
|
||||
export interface LabelFilterStatement {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { PagerChannel } from './config';
|
||||
import { OpsgenieChannel, PagerChannel } from './config';
|
||||
|
||||
export const PagerInitialConfig: Partial<PagerChannel> = {
|
||||
description: `[{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .CommonLabels.alertname }} for {{ .CommonLabels.job }}
|
||||
@ -22,3 +22,31 @@ export const PagerInitialConfig: Partial<PagerChannel> = {
|
||||
num_resolved: '{{ .Alerts.Resolved | len }}',
|
||||
}),
|
||||
};
|
||||
|
||||
export const OpsgenieInitialConfig: Partial<OpsgenieChannel> = {
|
||||
message: '{{ .CommonLabels.alertname }}',
|
||||
description: `{{ if gt (len .Alerts.Firing) 0 -}}
|
||||
Alerts Firing:
|
||||
{{ range .Alerts.Firing }}
|
||||
- Message: {{ .Annotations.description }}
|
||||
Labels:
|
||||
{{ range .Labels.SortedPairs }} - {{ .Name }} = {{ .Value }}
|
||||
{{ end }} Annotations:
|
||||
{{ range .Annotations.SortedPairs }} - {{ .Name }} = {{ .Value }}
|
||||
{{ end }} Source: {{ .GeneratorURL }}
|
||||
{{ end }}
|
||||
{{- end }}
|
||||
{{ if gt (len .Alerts.Resolved) 0 -}}
|
||||
Alerts Resolved:
|
||||
{{ range .Alerts.Resolved }}
|
||||
- Message: {{ .Annotations.description }}
|
||||
Labels:
|
||||
{{ range .Labels.SortedPairs }} - {{ .Name }} = {{ .Value }}
|
||||
{{ end }} Annotations:
|
||||
{{ range .Annotations.SortedPairs }} - {{ .Name }} = {{ .Value }}
|
||||
{{ end }} Source: {{ .GeneratorURL }}
|
||||
{{ end }}
|
||||
{{- end }}`,
|
||||
priority:
|
||||
'{{ if eq (index .Alerts 0).Labels.severity "critical" }}P1{{ else if eq (index .Alerts 0).Labels.severity "warning" }}P2{{ else if eq (index .Alerts 0).Labels.severity "info" }}P3{{ else }}P4{{ end }}',
|
||||
};
|
||||
|
@ -1,9 +1,11 @@
|
||||
import { Form } from 'antd';
|
||||
import createMsTeamsApi from 'api/channels/createMsTeams';
|
||||
import createOpsgenie from 'api/channels/createOpsgenie';
|
||||
import createPagerApi from 'api/channels/createPager';
|
||||
import createSlackApi from 'api/channels/createSlack';
|
||||
import createWebhookApi from 'api/channels/createWebhook';
|
||||
import testMsTeamsApi from 'api/channels/testMsTeams';
|
||||
import testOpsGenie from 'api/channels/testOpsgenie';
|
||||
import testPagerApi from 'api/channels/testPager';
|
||||
import testSlackApi from 'api/channels/testSlack';
|
||||
import testWebhookApi from 'api/channels/testWebhook';
|
||||
@ -17,19 +19,17 @@ import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
ChannelType,
|
||||
MsTeamsChannel,
|
||||
MsTeamsType,
|
||||
OpsgenieChannel,
|
||||
PagerChannel,
|
||||
PagerType,
|
||||
SlackChannel,
|
||||
SlackType,
|
||||
ValidatePagerChannel,
|
||||
WebhookChannel,
|
||||
WebhookType,
|
||||
} from './config';
|
||||
import { PagerInitialConfig } from './defaults';
|
||||
import { OpsgenieInitialConfig, PagerInitialConfig } from './defaults';
|
||||
import { isChannelType } from './utils';
|
||||
|
||||
function CreateAlertChannels({
|
||||
preType = 'slack',
|
||||
preType = ChannelType.Slack,
|
||||
}: CreateAlertChannelsProps): JSX.Element {
|
||||
// init namespace for translations
|
||||
const { t } = useTranslation('channels');
|
||||
@ -37,7 +37,13 @@ function CreateAlertChannels({
|
||||
const [formInstance] = Form.useForm();
|
||||
|
||||
const [selectedConfig, setSelectedConfig] = useState<
|
||||
Partial<SlackChannel & WebhookChannel & PagerChannel & MsTeamsChannel>
|
||||
Partial<
|
||||
SlackChannel &
|
||||
WebhookChannel &
|
||||
PagerChannel &
|
||||
MsTeamsChannel &
|
||||
OpsgenieChannel
|
||||
>
|
||||
>({
|
||||
text: `{{ range .Alerts -}}
|
||||
*Alert:* {{ .Labels.alertname }}{{ if .Labels.severity }} - {{ .Labels.severity }}{{ end }}
|
||||
@ -71,7 +77,7 @@ function CreateAlertChannels({
|
||||
const currentType = type;
|
||||
setType(value as ChannelType);
|
||||
|
||||
if (value === PagerType && currentType !== value) {
|
||||
if (value === ChannelType.Pagerduty && currentType !== value) {
|
||||
// reset config to pager defaults
|
||||
setSelectedConfig({
|
||||
name: selectedConfig?.name,
|
||||
@ -79,6 +85,13 @@ function CreateAlertChannels({
|
||||
...PagerInitialConfig,
|
||||
});
|
||||
}
|
||||
|
||||
if (value === ChannelType.Opsgenie && currentType !== value) {
|
||||
setSelectedConfig((selectedConfig) => ({
|
||||
...selectedConfig,
|
||||
...OpsgenieInitialConfig,
|
||||
}));
|
||||
}
|
||||
},
|
||||
[type, selectedConfig],
|
||||
);
|
||||
@ -239,6 +252,45 @@ function CreateAlertChannels({
|
||||
setSavingState(false);
|
||||
}, [t, notifications, preparePagerRequest]);
|
||||
|
||||
const prepareOpsgenieRequest = useCallback(
|
||||
() => ({
|
||||
api_key: selectedConfig?.api_key || '',
|
||||
name: selectedConfig?.name || '',
|
||||
send_resolved: true,
|
||||
description: selectedConfig?.description || '',
|
||||
message: selectedConfig?.message || '',
|
||||
priority: selectedConfig?.priority || '',
|
||||
}),
|
||||
[selectedConfig],
|
||||
);
|
||||
|
||||
const onOpsgenieHandler = useCallback(async () => {
|
||||
setSavingState(true);
|
||||
|
||||
try {
|
||||
const response = await createOpsgenie(prepareOpsgenieRequest());
|
||||
|
||||
if (response.statusCode === 200) {
|
||||
notifications.success({
|
||||
message: 'Success',
|
||||
description: t('channel_creation_done'),
|
||||
});
|
||||
history.replace(ROUTES.ALL_CHANNELS);
|
||||
} else {
|
||||
notifications.error({
|
||||
message: 'Error',
|
||||
description: response.error || t('channel_creation_failed'),
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
notifications.error({
|
||||
message: 'Error',
|
||||
description: t('channel_creation_failed'),
|
||||
});
|
||||
}
|
||||
setSavingState(false);
|
||||
}, [prepareOpsgenieRequest, t, notifications]);
|
||||
|
||||
const prepareMsTeamsRequest = useCallback(
|
||||
() => ({
|
||||
webhook_url: selectedConfig?.webhook_url || '',
|
||||
@ -280,12 +332,15 @@ function CreateAlertChannels({
|
||||
const onSaveHandler = useCallback(
|
||||
async (value: ChannelType) => {
|
||||
const functionMapper = {
|
||||
[SlackType]: onSlackHandler,
|
||||
[WebhookType]: onWebhookHandler,
|
||||
[PagerType]: onPagerHandler,
|
||||
[MsTeamsType]: onMsTeamsHandler,
|
||||
[ChannelType.Slack]: onSlackHandler,
|
||||
[ChannelType.Webhook]: onWebhookHandler,
|
||||
[ChannelType.Pagerduty]: onPagerHandler,
|
||||
[ChannelType.Opsgenie]: onOpsgenieHandler,
|
||||
[ChannelType.MsTeams]: onMsTeamsHandler,
|
||||
};
|
||||
const functionToCall = functionMapper[value];
|
||||
|
||||
if (isChannelType(value)) {
|
||||
const functionToCall = functionMapper[value as keyof typeof functionMapper];
|
||||
|
||||
if (functionToCall) {
|
||||
functionToCall();
|
||||
@ -295,11 +350,13 @@ function CreateAlertChannels({
|
||||
description: t('selected_channel_invalid'),
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
[
|
||||
onSlackHandler,
|
||||
onWebhookHandler,
|
||||
onPagerHandler,
|
||||
onOpsgenieHandler,
|
||||
onMsTeamsHandler,
|
||||
notifications,
|
||||
t,
|
||||
@ -313,22 +370,26 @@ function CreateAlertChannels({
|
||||
let request;
|
||||
let response;
|
||||
switch (channelType) {
|
||||
case WebhookType:
|
||||
case ChannelType.Webhook:
|
||||
request = prepareWebhookRequest();
|
||||
response = await testWebhookApi(request);
|
||||
break;
|
||||
case SlackType:
|
||||
case ChannelType.Slack:
|
||||
request = prepareSlackRequest();
|
||||
response = await testSlackApi(request);
|
||||
break;
|
||||
case PagerType:
|
||||
case ChannelType.Pagerduty:
|
||||
request = preparePagerRequest();
|
||||
if (request) response = await testPagerApi(request);
|
||||
break;
|
||||
case MsTeamsType:
|
||||
case ChannelType.MsTeams:
|
||||
request = prepareMsTeamsRequest();
|
||||
response = await testMsTeamsApi(request);
|
||||
break;
|
||||
case ChannelType.Opsgenie:
|
||||
request = prepareOpsgenieRequest();
|
||||
response = await testOpsGenie(request);
|
||||
break;
|
||||
default:
|
||||
notifications.error({
|
||||
message: 'Error',
|
||||
@ -361,6 +422,7 @@ function CreateAlertChannels({
|
||||
prepareWebhookRequest,
|
||||
t,
|
||||
preparePagerRequest,
|
||||
prepareOpsgenieRequest,
|
||||
prepareSlackRequest,
|
||||
prepareMsTeamsRequest,
|
||||
notifications,
|
||||
@ -390,6 +452,7 @@ function CreateAlertChannels({
|
||||
type,
|
||||
...selectedConfig,
|
||||
...PagerInitialConfig,
|
||||
...OpsgenieInitialConfig,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
4
frontend/src/container/CreateAlertChannels/utils.ts
Normal file
4
frontend/src/container/CreateAlertChannels/utils.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import { ChannelType } from './config';
|
||||
|
||||
export const isChannelType = (type: string): type is ChannelType =>
|
||||
Object.values(ChannelType).includes(type as ChannelType);
|
@ -1,9 +1,11 @@
|
||||
import { Form } from 'antd';
|
||||
import editMsTeamsApi from 'api/channels/editMsTeams';
|
||||
import editOpsgenie from 'api/channels/editOpsgenie';
|
||||
import editPagerApi from 'api/channels/editPager';
|
||||
import editSlackApi from 'api/channels/editSlack';
|
||||
import editWebhookApi from 'api/channels/editWebhook';
|
||||
import testMsTeamsApi from 'api/channels/testMsTeams';
|
||||
import testOpsgenie from 'api/channels/testOpsgenie';
|
||||
import testPagerApi from 'api/channels/testPager';
|
||||
import testSlackApi from 'api/channels/testSlack';
|
||||
import testWebhookApi from 'api/channels/testWebhook';
|
||||
@ -11,14 +13,11 @@ import ROUTES from 'constants/routes';
|
||||
import {
|
||||
ChannelType,
|
||||
MsTeamsChannel,
|
||||
MsTeamsType,
|
||||
OpsgenieChannel,
|
||||
PagerChannel,
|
||||
PagerType,
|
||||
SlackChannel,
|
||||
SlackType,
|
||||
ValidatePagerChannel,
|
||||
WebhookChannel,
|
||||
WebhookType,
|
||||
} from 'container/CreateAlertChannels/config';
|
||||
import FormAlertChannels from 'container/FormAlertChannels';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
@ -35,7 +34,13 @@ function EditAlertChannels({
|
||||
|
||||
const [formInstance] = Form.useForm();
|
||||
const [selectedConfig, setSelectedConfig] = useState<
|
||||
Partial<SlackChannel & WebhookChannel & PagerChannel & MsTeamsChannel>
|
||||
Partial<
|
||||
SlackChannel &
|
||||
WebhookChannel &
|
||||
PagerChannel &
|
||||
MsTeamsChannel &
|
||||
OpsgenieChannel
|
||||
>
|
||||
>({
|
||||
...initialValue,
|
||||
});
|
||||
@ -45,7 +50,7 @@ function EditAlertChannels({
|
||||
const { id } = useParams<{ id: string }>();
|
||||
|
||||
const [type, setType] = useState<ChannelType>(
|
||||
initialValue?.type ? (initialValue.type as ChannelType) : SlackType,
|
||||
initialValue?.type ? (initialValue.type as ChannelType) : ChannelType.Slack,
|
||||
);
|
||||
|
||||
const onTypeChangeHandler = useCallback((value: string) => {
|
||||
@ -193,6 +198,48 @@ function EditAlertChannels({
|
||||
setSavingState(false);
|
||||
}, [preparePagerRequest, notifications, selectedConfig, t]);
|
||||
|
||||
const prepareOpsgenieRequest = useCallback(
|
||||
() => ({
|
||||
name: selectedConfig.name || '',
|
||||
api_key: selectedConfig.api_key || '',
|
||||
message: selectedConfig.message || '',
|
||||
description: selectedConfig.description || '',
|
||||
priority: selectedConfig.priority || '',
|
||||
id,
|
||||
}),
|
||||
[id, selectedConfig],
|
||||
);
|
||||
|
||||
const onOpsgenieEditHandler = useCallback(async () => {
|
||||
setSavingState(true);
|
||||
|
||||
if (selectedConfig?.api_key === '') {
|
||||
notifications.error({
|
||||
message: 'Error',
|
||||
description: t('api_key_required'),
|
||||
});
|
||||
setSavingState(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await editOpsgenie(prepareOpsgenieRequest());
|
||||
|
||||
if (response.statusCode === 200) {
|
||||
notifications.success({
|
||||
message: 'Success',
|
||||
description: t('channel_edit_done'),
|
||||
});
|
||||
|
||||
history.replace(ROUTES.ALL_CHANNELS);
|
||||
} else {
|
||||
notifications.error({
|
||||
message: 'Error',
|
||||
description: response.error || t('channel_edit_failed'),
|
||||
});
|
||||
}
|
||||
setSavingState(false);
|
||||
}, [prepareOpsgenieRequest, t, notifications, selectedConfig]);
|
||||
|
||||
const prepareMsTeamsRequest = useCallback(
|
||||
() => ({
|
||||
webhook_url: selectedConfig?.webhook_url || '',
|
||||
@ -237,14 +284,16 @@ function EditAlertChannels({
|
||||
|
||||
const onSaveHandler = useCallback(
|
||||
(value: ChannelType) => {
|
||||
if (value === SlackType) {
|
||||
if (value === ChannelType.Slack) {
|
||||
onSlackEditHandler();
|
||||
} else if (value === WebhookType) {
|
||||
} else if (value === ChannelType.Webhook) {
|
||||
onWebhookEditHandler();
|
||||
} else if (value === PagerType) {
|
||||
} else if (value === ChannelType.Pagerduty) {
|
||||
onPagerEditHandler();
|
||||
} else if (value === MsTeamsType) {
|
||||
} else if (value === ChannelType.MsTeams) {
|
||||
onMsTeamsEditHandler();
|
||||
} else if (value === ChannelType.Opsgenie) {
|
||||
onOpsgenieEditHandler();
|
||||
}
|
||||
},
|
||||
[
|
||||
@ -252,6 +301,7 @@ function EditAlertChannels({
|
||||
onWebhookEditHandler,
|
||||
onPagerEditHandler,
|
||||
onMsTeamsEditHandler,
|
||||
onOpsgenieEditHandler,
|
||||
],
|
||||
);
|
||||
|
||||
@ -262,22 +312,26 @@ function EditAlertChannels({
|
||||
let request;
|
||||
let response;
|
||||
switch (channelType) {
|
||||
case WebhookType:
|
||||
case ChannelType.Webhook:
|
||||
request = prepareWebhookRequest();
|
||||
response = await testWebhookApi(request);
|
||||
break;
|
||||
case SlackType:
|
||||
case ChannelType.Slack:
|
||||
request = prepareSlackRequest();
|
||||
response = await testSlackApi(request);
|
||||
break;
|
||||
case PagerType:
|
||||
case ChannelType.Pagerduty:
|
||||
request = preparePagerRequest();
|
||||
if (request) response = await testPagerApi(request);
|
||||
break;
|
||||
case MsTeamsType:
|
||||
case ChannelType.MsTeams:
|
||||
request = prepareMsTeamsRequest();
|
||||
if (request) response = await testMsTeamsApi(request);
|
||||
break;
|
||||
case ChannelType.Opsgenie:
|
||||
request = prepareOpsgenieRequest();
|
||||
if (request) response = await testOpsgenie(request);
|
||||
break;
|
||||
default:
|
||||
notifications.error({
|
||||
message: 'Error',
|
||||
@ -312,6 +366,7 @@ function EditAlertChannels({
|
||||
preparePagerRequest,
|
||||
prepareSlackRequest,
|
||||
prepareMsTeamsRequest,
|
||||
prepareOpsgenieRequest,
|
||||
notifications,
|
||||
],
|
||||
);
|
||||
|
@ -0,0 +1,74 @@
|
||||
import { Form, Input } from 'antd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { OpsgenieChannel } from '../../CreateAlertChannels/config';
|
||||
|
||||
const { TextArea } = Input;
|
||||
|
||||
function OpsgenieForm({ setSelectedConfig }: OpsgenieFormProps): JSX.Element {
|
||||
const { t } = useTranslation('channels');
|
||||
|
||||
const handleInputChange = (field: string) => (
|
||||
event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||
): void => {
|
||||
setSelectedConfig((value) => ({
|
||||
...value,
|
||||
[field]: event.target.value,
|
||||
}));
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item name="api_key" label={t('field_opsgenie_api_key')} required>
|
||||
<Input onChange={handleInputChange('api_key')} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="message"
|
||||
help={t('help_opsgenie_message')}
|
||||
label={t('field_opsgenie_message')}
|
||||
required
|
||||
>
|
||||
<TextArea
|
||||
rows={4}
|
||||
onChange={handleInputChange('message')}
|
||||
placeholder={t('placeholder_opsgenie_message')}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="description"
|
||||
help={t('help_opsgenie_description')}
|
||||
label={t('field_opsgenie_description')}
|
||||
required
|
||||
>
|
||||
<TextArea
|
||||
rows={4}
|
||||
onChange={handleInputChange('description')}
|
||||
placeholder={t('placeholder_opsgenie_description')}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="priority"
|
||||
help={t('help_opsgenie_priority')}
|
||||
label={t('field_opsgenie_priority')}
|
||||
required
|
||||
>
|
||||
<TextArea
|
||||
rows={4}
|
||||
onChange={handleInputChange('priority')}
|
||||
placeholder={t('placeholder_opsgenie_priority')}
|
||||
/>
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
interface OpsgenieFormProps {
|
||||
setSelectedConfig: React.Dispatch<
|
||||
React.SetStateAction<Partial<OpsgenieChannel>>
|
||||
>;
|
||||
}
|
||||
|
||||
export default OpsgenieForm;
|
@ -5,13 +5,10 @@ import { FeatureKeys } from 'constants/features';
|
||||
import ROUTES from 'constants/routes';
|
||||
import {
|
||||
ChannelType,
|
||||
MsTeamsType,
|
||||
OpsgenieChannel,
|
||||
PagerChannel,
|
||||
PagerType,
|
||||
SlackChannel,
|
||||
SlackType,
|
||||
WebhookChannel,
|
||||
WebhookType,
|
||||
} from 'container/CreateAlertChannels/config';
|
||||
import useFeatureFlags from 'hooks/useFeatureFlag';
|
||||
import { isFeatureKeys } from 'hooks/useFeatureFlag/utils';
|
||||
@ -20,6 +17,7 @@ import { Dispatch, ReactElement, SetStateAction } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import MsTeamsSettings from './Settings/MsTeams';
|
||||
import OpsgenieSettings from './Settings/Opsgenie';
|
||||
import PagerSettings from './Settings/Pager';
|
||||
import SlackSettings from './Settings/Slack';
|
||||
import WebhookSettings from './Settings/Webhook';
|
||||
@ -61,14 +59,16 @@ function FormAlertChannels({
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case SlackType:
|
||||
case ChannelType.Slack:
|
||||
return <SlackSettings setSelectedConfig={setSelectedConfig} />;
|
||||
case WebhookType:
|
||||
case ChannelType.Webhook:
|
||||
return <WebhookSettings setSelectedConfig={setSelectedConfig} />;
|
||||
case PagerType:
|
||||
case ChannelType.Pagerduty:
|
||||
return <PagerSettings setSelectedConfig={setSelectedConfig} />;
|
||||
case MsTeamsType:
|
||||
case ChannelType.MsTeams:
|
||||
return <MsTeamsSettings setSelectedConfig={setSelectedConfig} />;
|
||||
case ChannelType.Opsgenie:
|
||||
return <OpsgenieSettings setSelectedConfig={setSelectedConfig} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@ -102,6 +102,9 @@ function FormAlertChannels({
|
||||
<Select.Option value="pagerduty" key="pagerduty">
|
||||
Pagerduty
|
||||
</Select.Option>
|
||||
<Select.Option value="opsgenie" key="opsgenie">
|
||||
Opsgenie
|
||||
</Select.Option>
|
||||
{!isOssFeature?.active && (
|
||||
<Select.Option value="msteams" key="msteams">
|
||||
<div>
|
||||
@ -147,7 +150,9 @@ interface FormAlertChannelsProps {
|
||||
formInstance: FormInstance;
|
||||
type: ChannelType;
|
||||
setSelectedConfig: Dispatch<
|
||||
SetStateAction<Partial<SlackChannel & WebhookChannel & PagerChannel>>
|
||||
SetStateAction<
|
||||
Partial<SlackChannel & WebhookChannel & PagerChannel & OpsgenieChannel>
|
||||
>
|
||||
>;
|
||||
onTypeChangeHandler: (value: ChannelType) => void;
|
||||
onSaveHandler: (props: ChannelType) => void;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import ROUTES from 'constants/routes';
|
||||
import CreateAlertChannels from 'container/CreateAlertChannels';
|
||||
import { ChannelType } from 'container/CreateAlertChannels/config';
|
||||
import GeneralSettings from 'container/GeneralSettings';
|
||||
import { t } from 'i18next';
|
||||
|
||||
@ -11,7 +12,9 @@ export const alertsRoutesConfig = [
|
||||
key: ROUTES.SETTINGS,
|
||||
},
|
||||
{
|
||||
Component: (): JSX.Element => <CreateAlertChannels preType="slack" />,
|
||||
Component: (): JSX.Element => (
|
||||
<CreateAlertChannels preType={ChannelType.Slack} />
|
||||
),
|
||||
name: t('routes.alert_channels'),
|
||||
route: ROUTES.CHANNELS_NEW,
|
||||
key: ROUTES.CHANNELS_NEW,
|
||||
|
@ -1,15 +1,13 @@
|
||||
/* eslint-disable sonarjs/cognitive-complexity */
|
||||
import { Typography } from 'antd';
|
||||
import get from 'api/channels/get';
|
||||
import Spinner from 'components/Spinner';
|
||||
import {
|
||||
ChannelType,
|
||||
MsTeamsChannel,
|
||||
MsTeamsType,
|
||||
PagerChannel,
|
||||
PagerType,
|
||||
SlackChannel,
|
||||
SlackType,
|
||||
WebhookChannel,
|
||||
WebhookType,
|
||||
} from 'container/CreateAlertChannels/config';
|
||||
import EditAlertChannels from 'container/EditAlertChannels';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@ -50,7 +48,7 @@ function ChannelsEdit(): JSX.Element {
|
||||
const slackConfig = value.slack_configs[0];
|
||||
channel = slackConfig;
|
||||
return {
|
||||
type: SlackType,
|
||||
type: ChannelType.Slack,
|
||||
channel,
|
||||
};
|
||||
}
|
||||
@ -59,7 +57,7 @@ function ChannelsEdit(): JSX.Element {
|
||||
const msteamsConfig = value.msteams_configs[0];
|
||||
channel = msteamsConfig;
|
||||
return {
|
||||
type: MsTeamsType,
|
||||
type: ChannelType.MsTeams,
|
||||
channel,
|
||||
};
|
||||
}
|
||||
@ -69,7 +67,16 @@ function ChannelsEdit(): JSX.Element {
|
||||
channel.details = JSON.stringify(pagerConfig.details);
|
||||
channel.detailsArray = { ...pagerConfig.details };
|
||||
return {
|
||||
type: PagerType,
|
||||
type: ChannelType.Pagerduty,
|
||||
channel,
|
||||
};
|
||||
}
|
||||
|
||||
if (value && 'opsgenie_configs' in value) {
|
||||
const opsgenieConfig = value.opsgenie_configs[0];
|
||||
channel = opsgenieConfig;
|
||||
return {
|
||||
type: ChannelType.Opsgenie,
|
||||
channel,
|
||||
};
|
||||
}
|
||||
@ -89,12 +96,12 @@ function ChannelsEdit(): JSX.Element {
|
||||
}
|
||||
}
|
||||
return {
|
||||
type: WebhookType,
|
||||
type: ChannelType.Webhook,
|
||||
channel,
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: SlackType,
|
||||
type: ChannelType.Slack,
|
||||
channel,
|
||||
};
|
||||
};
|
||||
|
8
frontend/src/types/api/channels/createOpsgenie.ts
Normal file
8
frontend/src/types/api/channels/createOpsgenie.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { OpsgenieChannel } from 'container/CreateAlertChannels/config';
|
||||
|
||||
export type Props = OpsgenieChannel;
|
||||
|
||||
export interface PayloadProps {
|
||||
data: string;
|
||||
status: string;
|
||||
}
|
10
frontend/src/types/api/channels/editOpsgenie.ts
Normal file
10
frontend/src/types/api/channels/editOpsgenie.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { OpsgenieChannel } from 'container/CreateAlertChannels/config';
|
||||
|
||||
export interface Props extends OpsgenieChannel {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface PayloadProps {
|
||||
data: string;
|
||||
status: string;
|
||||
}
|
@ -20,6 +20,7 @@ const AlertChannelSlack = "ALERT_CHANNEL_SLACK"
|
||||
const AlertChannelWebhook = "ALERT_CHANNEL_WEBHOOK"
|
||||
const AlertChannelPagerduty = "ALERT_CHANNEL_PAGERDUTY"
|
||||
const AlertChannelMsTeams = "ALERT_CHANNEL_MSTEAMS"
|
||||
const AlertChannelOpsgenie = "ALERT_CHANNEL_OPSGENIE"
|
||||
|
||||
var BasicPlan = FeatureSet{
|
||||
Feature{
|
||||
@ -92,6 +93,13 @@ var BasicPlan = FeatureSet{
|
||||
UsageLimit: -1,
|
||||
Route: "",
|
||||
},
|
||||
Feature{
|
||||
Name: AlertChannelOpsgenie,
|
||||
Active: true,
|
||||
Usage: 0,
|
||||
UsageLimit: -1,
|
||||
Route: "",
|
||||
},
|
||||
Feature{
|
||||
Name: AlertChannelMsTeams,
|
||||
Active: false,
|
||||
|
Loading…
x
Reference in New Issue
Block a user