chore(error): update the channels module to use the new api errors (#7856)

* chore(error): integrate new errors for channels create and test

* chore(error): update all the channel APIs

* chore(error): update the edit org http issue

* chore(error): fix create channel test

* chore(error): fix create channel test

* chore(error): fix create channel test

* chore(error): fix create channel test

* chore(error): remove console logs
This commit is contained in:
Vikrant Gupta 2025-05-09 13:26:47 +05:30 committed by GitHub
parent 0ab50da7b0
commit 39f07e7477
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 476 additions and 539 deletions

View File

@ -1,9 +1,9 @@
import { AxiosError } from 'axios';
import { ErrorV2 } from 'types/api';
import { ErrorV2Resp } from 'types/api';
import APIError from 'types/api/error';
// reference - https://axios-http.com/docs/handling_errors
export function ErrorResponseHandlerV2(error: AxiosError<ErrorV2>): never {
export function ErrorResponseHandlerV2(error: AxiosError<ErrorV2Resp>): never {
const { response, request } = error;
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
@ -11,10 +11,10 @@ export function ErrorResponseHandlerV2(error: AxiosError<ErrorV2>): never {
throw new APIError({
httpStatusCode: response.status || 500,
error: {
code: response.data.code,
message: response.data.message,
url: response.data.url,
errors: response.data.errors,
code: response.data.error.code,
message: response.data.error.message,
url: response.data.error.url,
errors: response.data.error.errors,
},
});
}

View File

@ -1,14 +1,14 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createEmail';
const create = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
): Promise<SuccessResponseV2<PayloadProps>> => {
try {
const response = await axios.post('/channels', {
const response = await axios.post<PayloadProps>('/channels', {
name: props.name,
email_configs: [
{
@ -21,13 +21,12 @@ const create = async (
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
httpStatusCode: response.status,
data: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
throw error;
}
};

View File

@ -1,14 +1,14 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createMsTeams';
const create = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
): Promise<SuccessResponseV2<PayloadProps>> => {
try {
const response = await axios.post('/channels', {
const response = await axios.post<PayloadProps>('/channels', {
name: props.name,
msteamsv2_configs: [
{
@ -21,13 +21,12 @@ const create = async (
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
httpStatusCode: response.status,
data: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
throw error;
}
};

View File

@ -1,14 +1,14 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createOpsgenie';
const create = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
): Promise<SuccessResponseV2<PayloadProps>> => {
try {
const response = await axios.post('/channels', {
const response = await axios.post<PayloadProps>('/channels', {
name: props.name,
opsgenie_configs: [
{
@ -24,13 +24,12 @@ const create = async (
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
httpStatusCode: response.status,
data: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
throw error;
}
};

View File

@ -1,14 +1,14 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createPager';
const create = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
): Promise<SuccessResponseV2<PayloadProps>> => {
try {
const response = await axios.post('/channels', {
const response = await axios.post<PayloadProps>('/channels', {
name: props.name,
pagerduty_configs: [
{
@ -29,13 +29,12 @@ const create = async (
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
httpStatusCode: response.status,
data: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
throw error;
}
};

View File

@ -1,14 +1,14 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createSlack';
const create = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
): Promise<SuccessResponseV2<PayloadProps>> => {
try {
const response = await axios.post('/channels', {
const response = await axios.post<PayloadProps>('/channels', {
name: props.name,
slack_configs: [
{
@ -22,13 +22,12 @@ const create = async (
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
httpStatusCode: response.status,
data: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
throw error;
}
};

View File

@ -1,12 +1,12 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createWebhook';
const create = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
): Promise<SuccessResponseV2<PayloadProps>> => {
try {
let httpConfig = {};
const username = props.username ? props.username.trim() : '';
@ -28,7 +28,7 @@ const create = async (
};
}
const response = await axios.post('/channels', {
const response = await axios.post<PayloadProps>('/channels', {
name: props.name,
webhook_configs: [
{
@ -40,13 +40,12 @@ const create = async (
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
httpStatusCode: response.status,
data: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
throw error;
}
};

View File

@ -1,23 +1,22 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/delete';
const deleteChannel = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
): Promise<SuccessResponseV2<PayloadProps>> => {
try {
const response = await axios.delete(`/channels/${props.id}`);
const response = await axios.delete<PayloadProps>(`/channels/${props.id}`);
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
httpStatusCode: response.status,
data: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
throw error;
}
};

View File

@ -1,14 +1,14 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/editEmail';
const editEmail = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
): Promise<SuccessResponseV2<PayloadProps>> => {
try {
const response = await axios.put(`/channels/${props.id}`, {
const response = await axios.put<PayloadProps>(`/channels/${props.id}`, {
name: props.name,
email_configs: [
{
@ -21,13 +21,12 @@ const editEmail = async (
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
httpStatusCode: response.status,
data: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
throw error;
}
};

View File

@ -1,14 +1,14 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/editMsTeams';
const editMsTeams = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
): Promise<SuccessResponseV2<PayloadProps>> => {
try {
const response = await axios.put(`/channels/${props.id}`, {
const response = await axios.put<PayloadProps>(`/channels/${props.id}`, {
name: props.name,
msteamsv2_configs: [
{
@ -21,13 +21,12 @@ const editMsTeams = async (
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
httpStatusCode: response.status,
data: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
throw error;
}
};

View File

@ -1,14 +1,14 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { ErrorResponse, ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/editOpsgenie';
const editOpsgenie = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
): Promise<SuccessResponseV2<PayloadProps> | ErrorResponse> => {
try {
const response = await axios.put(`/channels/${props.id}`, {
const response = await axios.put<PayloadProps>(`/channels/${props.id}`, {
name: props.name,
opsgenie_configs: [
{
@ -25,13 +25,12 @@ const editOpsgenie = async (
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
httpStatusCode: response.status,
data: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
return ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
throw error;
}
};

View File

@ -1,14 +1,14 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/editPager';
const editPager = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
): Promise<SuccessResponseV2<PayloadProps>> => {
try {
const response = await axios.put(`/channels/${props.id}`, {
const response = await axios.put<PayloadProps>(`/channels/${props.id}`, {
name: props.name,
pagerduty_configs: [
{
@ -29,13 +29,12 @@ const editPager = async (
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
httpStatusCode: response.status,
data: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
throw error;
}
};

View File

@ -1,14 +1,14 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/editSlack';
const editSlack = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
): Promise<SuccessResponseV2<PayloadProps>> => {
try {
const response = await axios.put(`/channels/${props.id}`, {
const response = await axios.put<PayloadProps>(`/channels/${props.id}`, {
name: props.name,
slack_configs: [
{
@ -22,13 +22,12 @@ const editSlack = async (
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
httpStatusCode: response.status,
data: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
throw error;
}
};

View File

@ -1,12 +1,12 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/editWebhook';
const editWebhook = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
): Promise<SuccessResponseV2<PayloadProps>> => {
try {
let httpConfig = {};
const username = props.username ? props.username.trim() : '';
@ -28,7 +28,7 @@ const editWebhook = async (
};
}
const response = await axios.put(`/channels/${props.id}`, {
const response = await axios.put<PayloadProps>(`/channels/${props.id}`, {
name: props.name,
webhook_configs: [
{
@ -40,13 +40,12 @@ const editWebhook = async (
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
httpStatusCode: response.status,
data: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
throw error;
}
};

View File

@ -1,23 +1,21 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/get';
import { Channels } from 'types/api/channels/getAll';
const get = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
const get = async (props: Props): Promise<SuccessResponseV2<Channels>> => {
try {
const response = await axios.get(`/channels/${props.id}`);
const response = await axios.get<PayloadProps>(`/channels/${props.id}`);
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
httpStatusCode: response.status,
data: response.data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
throw error;
}
};

View File

@ -1,23 +1,20 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps } from 'types/api/channels/getAll';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { Channels, PayloadProps } from 'types/api/channels/getAll';
const getAll = async (): Promise<
SuccessResponse<PayloadProps> | ErrorResponse
> => {
const getAll = async (): Promise<SuccessResponseV2<Channels[]>> => {
try {
const response = await axios.get('/channels');
const response = await axios.get<PayloadProps>('/channels');
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
httpStatusCode: response.status,
data: response.data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
throw error;
}
};

View File

@ -1,14 +1,14 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createEmail';
const testEmail = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
): Promise<SuccessResponseV2<PayloadProps>> => {
try {
const response = await axios.post('/testChannel', {
const response = await axios.post<PayloadProps>('/testChannel', {
name: props.name,
email_configs: [
{
@ -21,13 +21,12 @@ const testEmail = async (
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
httpStatusCode: response.status,
data: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
throw error;
}
};

View File

@ -1,14 +1,14 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createMsTeams';
const testMsTeams = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
): Promise<SuccessResponseV2<PayloadProps>> => {
try {
const response = await axios.post('/testChannel', {
const response = await axios.post<PayloadProps>('/testChannel', {
name: props.name,
msteamsv2_configs: [
{
@ -21,13 +21,12 @@ const testMsTeams = async (
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
httpStatusCode: response.status,
data: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
throw error;
}
};

View File

@ -1,14 +1,14 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createOpsgenie';
const testOpsgenie = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
): Promise<SuccessResponseV2<PayloadProps>> => {
try {
const response = await axios.post('/testChannel', {
const response = await axios.post<PayloadProps>('/testChannel', {
name: props.name,
opsgenie_configs: [
{
@ -24,13 +24,12 @@ const testOpsgenie = async (
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
httpStatusCode: response.status,
data: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
throw error;
}
};

View File

@ -1,14 +1,14 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createPager';
const testPager = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
): Promise<SuccessResponseV2<PayloadProps>> => {
try {
const response = await axios.post('/testChannel', {
const response = await axios.post<PayloadProps>('/testChannel', {
name: props.name,
pagerduty_configs: [
{
@ -29,13 +29,12 @@ const testPager = async (
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
httpStatusCode: response.status,
data: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
throw error;
}
};

View File

@ -1,14 +1,14 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createSlack';
const testSlack = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
): Promise<SuccessResponseV2<PayloadProps>> => {
try {
const response = await axios.post('/testChannel', {
const response = await axios.post<PayloadProps>('/testChannel', {
name: props.name,
slack_configs: [
{
@ -22,13 +22,12 @@ const testSlack = async (
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
httpStatusCode: response.status,
data: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
throw error;
}
};

View File

@ -1,12 +1,12 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createWebhook';
const testWebhook = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
): Promise<SuccessResponseV2<PayloadProps>> => {
try {
let httpConfig = {};
const username = props.username ? props.username.trim() : '';
@ -28,7 +28,7 @@ const testWebhook = async (
};
}
const response = await axios.post('/testChannel', {
const response = await axios.post<PayloadProps>('/testChannel', {
name: props.name,
webhook_configs: [
{
@ -40,13 +40,12 @@ const testWebhook = async (
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
httpStatusCode: response.status,
data: response.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
throw error;
}
};

View File

@ -1,7 +1,7 @@
import axios from 'api';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios';
import { ErrorV2, SuccessResponseV2 } from 'types/api';
import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/user/login';
const login = async (
@ -17,7 +17,7 @@ const login = async (
data: response.data,
};
} catch (error) {
ErrorResponseHandlerV2(error as AxiosError<ErrorV2>);
ErrorResponseHandlerV2(error as AxiosError<ErrorV2Resp>);
// this line is never reached but ts isn't detecting the never type properly for the ErrorResponseHandlerV2
throw error;
}

View File

@ -10,7 +10,7 @@ import { useAppContext } from 'providers/App/App';
import { useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { generatePath } from 'react-router-dom';
import { Channels, PayloadProps } from 'types/api/channels/getAll';
import { Channels } from 'types/api/channels/getAll';
import Delete from './Delete';
@ -68,7 +68,7 @@ function AlertChannels({ allChannels }: AlertChannelsProps): JSX.Element {
}
interface AlertChannelsProps {
allChannels: PayloadProps;
allChannels: Channels[];
}
export default AlertChannels;

View File

@ -4,6 +4,7 @@ import deleteChannel from 'api/channels/delete';
import { Dispatch, SetStateAction, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Channels } from 'types/api/channels/getAll';
import APIError from 'types/api/error';
function Delete({ notifications, setChannels, id }: DeleteProps): JSX.Element {
const { t } = useTranslation(['channels']);
@ -12,30 +13,20 @@ function Delete({ notifications, setChannels, id }: DeleteProps): JSX.Element {
const onClickHandler = async (): Promise<void> => {
try {
setLoading(true);
const response = await deleteChannel({
await deleteChannel({
id,
});
if (response.statusCode === 200) {
notifications.success({
message: 'Success',
description: t('channel_delete_success'),
});
setChannels((preChannels) => preChannels.filter((e) => e.id !== id));
} else {
notifications.error({
message: 'Error',
description: response.error || t('channel_delete_unexp_error'),
});
}
notifications.success({
message: 'Success',
description: t('channel_delete_success'),
});
setChannels((preChannels) => preChannels.filter((e) => e.id !== id));
setLoading(false);
} catch (error) {
notifications.error({
message: 'Error',
description:
error instanceof Error
? error.toString()
: t('channel_delete_unexp_error'),
message: (error as APIError).getErrorCode(),
description: (error as APIError).getErrorMessage(),
});
setLoading(false);
}

View File

@ -1,15 +1,7 @@
import ROUTES from 'constants/routes';
import AlertChannels from 'container/AllAlertChannels';
import { allAlertChannels } from 'mocks-server/__mockdata__/alerts';
import { act, fireEvent, render, screen, waitFor } from 'tests/test-utils';
jest.mock('hooks/useFetch', () => ({
__esModule: true,
default: jest.fn().mockImplementation(() => ({
payload: allAlertChannels,
})),
}));
const successNotification = jest.fn();
jest.mock('hooks/useNotifications', () => ({
__esModule: true,
@ -29,8 +21,11 @@ jest.mock('react-router-dom', () => ({
}));
describe('Alert Channels Settings List page', () => {
beforeEach(() => {
beforeEach(async () => {
render(<AlertChannels />);
await waitFor(() =>
expect(screen.getByText('sending_channels_note')).toBeInTheDocument(),
);
});
afterEach(() => {
jest.restoreAllMocks();

View File

@ -1,15 +1,8 @@
/* eslint-disable sonarjs/no-identical-functions */
import ROUTES from 'constants/routes';
import AlertChannels from 'container/AllAlertChannels';
import { allAlertChannels } from 'mocks-server/__mockdata__/alerts';
import { fireEvent, render, screen, waitFor } from 'tests/test-utils';
jest.mock('hooks/useFetch', () => ({
__esModule: true,
default: jest.fn().mockImplementation(() => ({
payload: allAlertChannels,
})),
}));
const successNotification = jest.fn();
jest.mock('hooks/useNotifications', () => ({
__esModule: true,
@ -34,27 +27,31 @@ jest.mock('react-router-dom', () => ({
}));
describe('Alert Channels Settings List page (Normal User)', () => {
beforeEach(() => {
beforeEach(async () => {
render(<AlertChannels />);
await waitFor(() =>
expect(screen.getByText('sending_channels_note')).toBeInTheDocument(),
);
});
afterEach(() => {
jest.restoreAllMocks();
});
describe('Should display the Alert Channels page properly', () => {
it('Should check if "The alerts will be sent to all the configured channels." is visible ', () => {
expect(screen.getByText('sending_channels_note')).toBeInTheDocument();
it('Should check if "The alerts will be sent to all the configured channels." is visible ', async () => {
await waitFor(() =>
expect(screen.getByText('sending_channels_note')).toBeInTheDocument(),
);
});
it('Should check if "New Alert Channel" Button is visble and disabled', () => {
it('Should check if "New Alert Channel" Button is visble and disabled', async () => {
const newAlertButton = screen.getByRole('button', {
name: 'plus button_new_channel',
});
expect(newAlertButton).toBeInTheDocument();
await waitFor(() => expect(newAlertButton).toBeInTheDocument());
expect(newAlertButton).toBeDisabled();
});
it('Should check if the help icon is visible and displays "tooltip_notification_channels ', async () => {
const helpIcon = screen.getByLabelText('question-circle');
fireEvent.mouseOver(helpIcon);
await waitFor(() => {
@ -64,13 +61,13 @@ describe('Alert Channels Settings List page (Normal User)', () => {
});
});
describe('Should check if the channels table is properly displayed', () => {
it('Should check if the table columns are properly displayed', () => {
it('Should check if the table columns are properly displayed', async () => {
expect(screen.getByText('column_channel_name')).toBeInTheDocument();
expect(screen.getByText('column_channel_type')).toBeInTheDocument();
expect(screen.queryByText('column_channel_action')).not.toBeInTheDocument();
});
it('Should check if the data in the table is displayed properly', () => {
it('Should check if the data in the table is displayed properly', async () => {
expect(screen.getByText('Dummy-Channel')).toBeInTheDocument();
expect(screen.getAllByText('slack')[0]).toBeInTheDocument();
expect(screen.queryByText('column_channel_edit')).not.toBeInTheDocument();

View File

@ -119,12 +119,7 @@ describe('Create Alert Channel', () => {
fireEvent.click(saveButton);
await waitFor(() =>
expect(errorNotification).toHaveBeenCalledWith({
description: 'Something went wrong',
message: 'Error',
}),
);
await waitFor(() => expect(errorNotification).toHaveBeenCalled());
});
it('Should check if clicking on Test button shows "An alert has been sent to this channel" success message if testing passes', async () => {
server.use(
@ -158,12 +153,7 @@ describe('Create Alert Channel', () => {
fireEvent.click(testButton);
await waitFor(() =>
expect(errorNotification).toHaveBeenCalledWith({
message: 'Error',
description: 'channel_test_failed',
}),
);
await waitFor(() => expect(errorNotification).toHaveBeenCalled());
});
});
describe('New Alert Channel Cascading Fields Based on Channel Type', () => {

View File

@ -6,12 +6,15 @@ import Spinner from 'components/Spinner';
import TextToolTip from 'components/TextToolTip';
import ROUTES from 'constants/routes';
import useComponentPermission from 'hooks/useComponentPermission';
import useFetch from 'hooks/useFetch';
import history from 'lib/history';
import { isUndefined } from 'lodash-es';
import { useAppContext } from 'providers/App/App';
import { useCallback, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { useQuery } from 'react-query';
import { SuccessResponseV2 } from 'types/api';
import { Channels } from 'types/api/channels/getAll';
import APIError from 'types/api/error';
import AlertChannelsComponent from './AlertChannels';
import { Button, ButtonContainer, RightActionContainer } from './styles';
@ -29,21 +32,26 @@ function AlertChannels(): JSX.Element {
history.push(ROUTES.CHANNELS_NEW);
}, []);
const { loading, payload, error, errorMessage } = useFetch(getAll);
const { isLoading, data, error } = useQuery<
SuccessResponseV2<Channels[]>,
APIError
>(['getChannels'], {
queryFn: () => getAll(),
});
useEffect(() => {
if (!isUndefined(payload)) {
if (!isUndefined(data?.data)) {
logEvent('Alert Channel: Channel list page visited', {
number: payload?.length,
number: data?.data?.length,
});
}
}, [payload]);
}, [data?.data]);
if (error) {
return <Typography>{errorMessage}</Typography>;
return <Typography>{error.getErrorMessage()}</Typography>;
}
if (loading || payload === undefined) {
if (isLoading || isUndefined(data?.data)) {
return <Spinner tip={t('loading_channels_message')} height="90vh" />;
}
@ -78,7 +86,7 @@ function AlertChannels(): JSX.Element {
</RightActionContainer>
</ButtonContainer>
<AlertChannelsComponent allChannels={payload} />
<AlertChannelsComponent allChannels={data?.data || []} />
</>
);
}

View File

@ -18,6 +18,7 @@ import { useNotifications } from 'hooks/useNotifications';
import history from 'lib/history';
import { useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import APIError from 'types/api/error';
import {
ChannelType,
@ -136,28 +137,17 @@ function CreateAlertChannels({
setSavingState(true);
try {
const response = await createSlackApi(prepareSlackRequest());
if (response.statusCode === 200) {
notifications.success({
message: 'Success',
description: t('channel_creation_done'),
});
history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_creation_done') };
}
notifications.error({
message: 'Error',
description: response.error || t('channel_creation_failed'),
await createSlackApi(prepareSlackRequest());
notifications.success({
message: 'Success',
description: t('channel_creation_done'),
});
return {
status: 'failed',
statusMessage: response.error || t('channel_creation_failed'),
};
history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_creation_done') };
} catch (error) {
notifications.error({
message: 'Error',
description: t('channel_creation_failed'),
message: (error as APIError).error.error.code,
description: (error as APIError).error.error.message,
});
return { status: 'failed', statusMessage: t('channel_creation_failed') };
} finally {
@ -204,27 +194,17 @@ function CreateAlertChannels({
setSavingState(true);
try {
const request = prepareWebhookRequest();
const response = await createWebhookApi(request);
if (response.statusCode === 200) {
notifications.success({
message: 'Success',
description: t('channel_creation_done'),
});
history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_creation_done') };
}
notifications.error({
message: 'Error',
description: response.error || t('channel_creation_failed'),
await createWebhookApi(request);
notifications.success({
message: 'Success',
description: t('channel_creation_done'),
});
return {
status: 'failed',
statusMessage: response.error || t('channel_creation_failed'),
};
history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_creation_done') };
} catch (error) {
notifications.error({
message: 'Error',
description: t('channel_creation_failed'),
message: (error as APIError).getErrorCode(),
description: (error as APIError).getErrorMessage(),
});
return { status: 'failed', statusMessage: t('channel_creation_failed') };
} finally {
@ -264,34 +244,19 @@ function CreateAlertChannels({
try {
if (request) {
const response = await createPagerApi(request);
if (response.statusCode === 200) {
notifications.success({
message: 'Success',
description: t('channel_creation_done'),
});
history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_creation_done') };
}
notifications.error({
message: 'Error',
description: response.error || t('channel_creation_failed'),
await createPagerApi(request);
notifications.success({
message: 'Success',
description: t('channel_creation_done'),
});
return {
status: 'failed',
statusMessage: response.error || t('channel_creation_failed'),
};
history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_creation_done') };
}
notifications.error({
message: 'Error',
description: t('channel_creation_failed'),
});
return { status: 'failed', statusMessage: t('channel_creation_failed') };
} catch (error) {
notifications.error({
message: 'Error',
description: t('channel_creation_failed'),
message: (error as APIError).getErrorCode(),
description: (error as APIError).getErrorMessage(),
});
return { status: 'failed', statusMessage: t('channel_creation_failed') };
} finally {
@ -313,30 +278,18 @@ function CreateAlertChannels({
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);
return { status: 'success', statusMessage: t('channel_creation_done') };
}
notifications.error({
message: 'Error',
description: response.error || t('channel_creation_failed'),
await createOpsgenie(prepareOpsgenieRequest());
notifications.success({
message: 'Success',
description: t('channel_creation_done'),
});
return {
status: 'failed',
statusMessage: response.error || t('channel_creation_failed'),
};
history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_creation_done') };
} catch (error) {
notifications.error({
message: 'Error',
description: t('channel_creation_failed'),
message: (error as APIError).getErrorCode(),
description: (error as APIError).getErrorMessage(),
});
return { status: 'failed', statusMessage: t('channel_creation_failed') };
} finally {
@ -359,27 +312,17 @@ function CreateAlertChannels({
setSavingState(true);
try {
const request = prepareEmailRequest();
const response = await createEmail(request);
if (response.statusCode === 200) {
notifications.success({
message: 'Success',
description: t('channel_creation_done'),
});
history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_creation_done') };
}
notifications.error({
message: 'Error',
description: response.error || t('channel_creation_failed'),
await createEmail(request);
notifications.success({
message: 'Success',
description: t('channel_creation_done'),
});
return {
status: 'failed',
statusMessage: response.error || t('channel_creation_failed'),
};
history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_creation_done') };
} catch (error) {
notifications.error({
message: 'Error',
description: t('channel_creation_failed'),
message: (error as APIError).getErrorCode(),
description: (error as APIError).getErrorMessage(),
});
return { status: 'failed', statusMessage: t('channel_creation_failed') };
} finally {
@ -402,28 +345,17 @@ function CreateAlertChannels({
setSavingState(true);
try {
const response = await createMsTeamsApi(prepareMsTeamsRequest());
if (response.statusCode === 200) {
notifications.success({
message: 'Success',
description: t('channel_creation_done'),
});
history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_creation_done') };
}
notifications.error({
message: 'Error',
description: response.error || t('channel_creation_failed'),
await createMsTeamsApi(prepareMsTeamsRequest());
notifications.success({
message: 'Success',
description: t('channel_creation_done'),
});
return {
status: 'failed',
statusMessage: response.error || t('channel_creation_failed'),
};
history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_creation_done') };
} catch (error) {
notifications.error({
message: 'Error',
description: t('channel_creation_failed'),
message: (error as APIError).getErrorCode(),
description: (error as APIError).getErrorMessage(),
});
return { status: 'failed', statusMessage: t('channel_creation_failed') };
} finally {
@ -481,31 +413,30 @@ function CreateAlertChannels({
setTestingState(true);
try {
let request;
let response;
switch (channelType) {
case ChannelType.Webhook:
request = prepareWebhookRequest();
response = await testWebhookApi(request);
await testWebhookApi(request);
break;
case ChannelType.Slack:
request = prepareSlackRequest();
response = await testSlackApi(request);
await testSlackApi(request);
break;
case ChannelType.Pagerduty:
request = preparePagerRequest();
if (request) response = await testPagerApi(request);
if (request) await testPagerApi(request);
break;
case ChannelType.MsTeams:
request = prepareMsTeamsRequest();
response = await testMsTeamsApi(request);
await testMsTeamsApi(request);
break;
case ChannelType.Opsgenie:
request = prepareOpsgenieRequest();
response = await testOpsGenie(request);
await testOpsGenie(request);
break;
case ChannelType.Email:
request = prepareEmailRequest();
response = await testEmail(request);
await testEmail(request);
break;
default:
notifications.error({
@ -516,30 +447,28 @@ function CreateAlertChannels({
return;
}
if (response && response.statusCode === 200) {
notifications.success({
message: 'Success',
description: t('channel_test_done'),
});
} else {
notifications.error({
message: 'Error',
description: t('channel_test_failed'),
});
}
notifications.success({
message: 'Success',
description: t('channel_test_done'),
});
logEvent('Alert Channel: Test notification', {
type: channelType,
sendResolvedAlert: selectedConfig?.send_resolved,
name: selectedConfig?.name,
new: 'true',
status:
response && response.statusCode === 200 ? 'Test success' : 'Test failed',
status: 'Test success',
});
} catch (error) {
notifications.error({
message: 'Error',
description: t('channel_test_unexpected'),
message: (error as APIError).error.error.code,
description: (error as APIError).error.error.message,
});
logEvent('Alert Channel: Test notification', {
type: channelType,
sendResolvedAlert: selectedConfig?.send_resolved,
name: selectedConfig?.name,
new: 'true',
status: 'Test failed',
});
}

View File

@ -29,6 +29,7 @@ import history from 'lib/history';
import { useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useParams } from 'react-router-dom';
import APIError from 'types/api/error';
function EditAlertChannels({
initialValue,
@ -93,9 +94,8 @@ function EditAlertChannels({
return { status: 'failed', statusMessage: t('webhook_url_required') };
}
const response = await editSlackApi(prepareSlackRequest());
if (response.statusCode === 200) {
try {
await editSlackApi(prepareSlackRequest());
notifications.success({
message: 'Success',
description: t('channel_edit_done'),
@ -103,16 +103,19 @@ function EditAlertChannels({
history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_edit_done') };
} catch (error) {
notifications.error({
message: (error as APIError).getErrorCode(),
description: (error as APIError).getErrorMessage(),
});
return {
status: 'failed',
statusMessage:
(error as APIError).getErrorMessage() || t('channel_edit_failed'),
};
} finally {
setSavingState(false);
}
notifications.error({
message: 'Error',
description: response.error || t('channel_edit_failed'),
});
setSavingState(false);
return {
status: 'failed',
statusMessage: response.error || t('channel_edit_failed'),
};
}, [prepareSlackRequest, t, notifications, selectedConfig]);
const prepareWebhookRequest = useCallback(() => {
@ -150,9 +153,8 @@ function EditAlertChannels({
return { status: 'failed', statusMessage: t('username_no_password') };
}
const response = await editWebhookApi(prepareWebhookRequest());
if (response.statusCode === 200) {
try {
await editWebhookApi(prepareWebhookRequest());
notifications.success({
message: 'Success',
description: t('channel_edit_done'),
@ -160,14 +162,19 @@ function EditAlertChannels({
history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_edit_done') };
} catch (error) {
notifications.error({
message: (error as APIError).getErrorCode(),
description: (error as APIError).getErrorMessage(),
});
return {
status: 'failed',
statusMessage:
(error as APIError).getErrorMessage() || t('channel_edit_failed'),
};
} finally {
setSavingState(false);
}
showError(response.error || t('channel_edit_failed'));
setSavingState(false);
return {
status: 'failed',
statusMessage: response.error || t('channel_edit_failed'),
};
}, [prepareWebhookRequest, t, notifications, selectedConfig]);
const prepareEmailRequest = useCallback(
@ -185,25 +192,28 @@ function EditAlertChannels({
const onEmailEditHandler = useCallback(async () => {
setSavingState(true);
const request = prepareEmailRequest();
const response = await editEmail(request);
if (response.statusCode === 200) {
try {
await editEmail(request);
notifications.success({
message: 'Success',
description: t('channel_edit_done'),
});
history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_edit_done') };
} catch (error) {
notifications.error({
message: (error as APIError).getErrorCode(),
description: (error as APIError).getErrorMessage(),
});
return {
status: 'failed',
statusMessage:
(error as APIError).getErrorMessage() || t('channel_edit_failed'),
};
} finally {
setSavingState(false);
}
notifications.error({
message: 'Error',
description: response.error || t('channel_edit_failed'),
});
setSavingState(false);
return {
status: 'failed',
statusMessage: response.error || t('channel_edit_failed'),
};
}, [prepareEmailRequest, t, notifications]);
const preparePagerRequest = useCallback(
@ -237,27 +247,28 @@ function EditAlertChannels({
setSavingState(false);
return { status: 'failed', statusMessage: validationError };
}
const response = await editPagerApi(preparePagerRequest());
if (response.statusCode === 200) {
try {
await editPagerApi(preparePagerRequest());
notifications.success({
message: 'Success',
description: t('channel_edit_done'),
});
history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_edit_done') };
} catch (error) {
notifications.error({
message: (error as APIError).getErrorCode(),
description: (error as APIError).getErrorMessage(),
});
return {
status: 'failed',
statusMessage:
(error as APIError).getErrorMessage() || t('channel_edit_failed'),
};
} finally {
setSavingState(false);
}
notifications.error({
message: 'Error',
description: response.error || t('channel_edit_failed'),
});
setSavingState(false);
return {
status: 'failed',
statusMessage: response.error || t('channel_edit_failed'),
};
}, [preparePagerRequest, notifications, selectedConfig, t]);
const prepareOpsgenieRequest = useCallback(
@ -284,28 +295,27 @@ function EditAlertChannels({
setSavingState(false);
return { status: 'failed', statusMessage: t('api_key_required') };
}
const response = await editOpsgenie(prepareOpsgenieRequest());
if (response.statusCode === 200) {
try {
await editOpsgenie(prepareOpsgenieRequest());
notifications.success({
message: 'Success',
description: t('channel_edit_done'),
});
history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_edit_done') };
} catch (error) {
notifications.error({
message: (error as APIError).getErrorCode(),
description: (error as APIError).getErrorMessage(),
});
return {
status: 'failed',
statusMessage:
(error as APIError).getErrorMessage() || t('channel_edit_failed'),
};
} finally {
setSavingState(false);
}
notifications.error({
message: 'Error',
description: response.error || t('channel_edit_failed'),
});
setSavingState(false);
return {
status: 'failed',
statusMessage: response.error || t('channel_edit_failed'),
};
}, [prepareOpsgenieRequest, t, notifications, selectedConfig]);
const prepareMsTeamsRequest = useCallback(
@ -332,27 +342,27 @@ function EditAlertChannels({
return { status: 'failed', statusMessage: t('webhook_url_required') };
}
const response = await editMsTeamsApi(prepareMsTeamsRequest());
if (response.statusCode === 200) {
try {
await editMsTeamsApi(prepareMsTeamsRequest());
notifications.success({
message: 'Success',
description: t('channel_edit_done'),
});
history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_edit_done') };
} catch (error) {
notifications.error({
message: (error as APIError).getErrorCode(),
description: (error as APIError).getErrorMessage(),
});
return {
status: 'failed',
statusMessage:
(error as APIError).getErrorMessage() || t('channel_edit_failed'),
};
} finally {
setSavingState(false);
}
notifications.error({
message: 'Error',
description: response.error || t('channel_edit_failed'),
});
setSavingState(false);
return {
status: 'failed',
statusMessage: response.error || t('channel_edit_failed'),
};
}, [prepareMsTeamsRequest, t, notifications, selectedConfig]);
const onSaveHandler = useCallback(
@ -396,31 +406,30 @@ function EditAlertChannels({
setTestingState(true);
try {
let request;
let response;
switch (channelType) {
case ChannelType.Webhook:
request = prepareWebhookRequest();
response = await testWebhookApi(request);
await testWebhookApi(request);
break;
case ChannelType.Slack:
request = prepareSlackRequest();
response = await testSlackApi(request);
await testSlackApi(request);
break;
case ChannelType.Pagerduty:
request = preparePagerRequest();
if (request) response = await testPagerApi(request);
if (request) await testPagerApi(request);
break;
case ChannelType.MsTeams:
request = prepareMsTeamsRequest();
if (request) response = await testMsTeamsApi(request);
if (request) await testMsTeamsApi(request);
break;
case ChannelType.Opsgenie:
request = prepareOpsgenieRequest();
if (request) response = await testOpsgenie(request);
if (request) await testOpsgenie(request);
break;
case ChannelType.Email:
request = prepareEmailRequest();
if (request) response = await testEmail(request);
if (request) await testEmail(request);
break;
default:
notifications.error({
@ -431,29 +440,28 @@ function EditAlertChannels({
return;
}
if (response && response.statusCode === 200) {
notifications.success({
message: 'Success',
description: t('channel_test_done'),
});
} else {
notifications.error({
message: 'Error',
description: t('channel_test_failed'),
});
}
notifications.success({
message: 'Success',
description: t('channel_test_done'),
});
logEvent('Alert Channel: Test notification', {
type: channelType,
sendResolvedAlert: selectedConfig?.send_resolved,
name: selectedConfig?.name,
new: 'false',
status:
response && response.statusCode === 200 ? 'Test success' : 'Test failed',
status: 'Test success',
});
} catch (error) {
notifications.error({
message: 'Error',
description: t('channel_test_failed'),
message: (error as APIError).getErrorCode(),
description: (error as APIError).getErrorMessage(),
});
logEvent('Alert Channel: Test notification', {
type: channelType,
sendResolvedAlert: selectedConfig?.send_resolved,
name: selectedConfig?.name,
new: 'false',
status: 'Test failed',
});
}
setTestingState(false);

View File

@ -2,17 +2,20 @@ 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 getAll from 'api/channels/getAll';
import logEvent from 'api/common/logEvent';
import { ALERTS_DATA_SOURCE_MAP } from 'constants/alerts';
import ROUTES from 'constants/routes';
import useComponentPermission from 'hooks/useComponentPermission';
import useFetch from 'hooks/useFetch';
import { useAppContext } from 'providers/App/App';
import { useCallback, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useQuery } from 'react-query';
import { SuccessResponseV2 } from 'types/api';
import { AlertTypes } from 'types/api/alerts/alertTypes';
import { AlertDef, Labels } from 'types/api/alerts/def';
import { Channels } from 'types/api/channels/getAll';
import APIError from 'types/api/error';
import { requireErrorMessage } from 'utils/form/requireErrorMessage';
import { popupContainer } from 'utils/selectPopupContainer';
@ -42,7 +45,13 @@ function BasicInfo({
}: BasicInfoProps): JSX.Element {
const { t } = useTranslation('alerts');
const channels = useFetch(getChannels);
const { isLoading, data, error, isError, refetch } = useQuery<
SuccessResponseV2<Channels[]>,
APIError
>(['getChannels'], {
queryFn: () => getAll(),
});
const { user } = useAppContext();
const [addNewChannelPermission] = useComponentPermission(
['add_new_channel'],
@ -72,7 +81,7 @@ function BasicInfo({
});
};
const noChannels = channels.payload?.length === 0;
const noChannels = data?.data?.length === 0;
const handleCreateNewChannels = useCallback(() => {
logEvent('Alert: Create notification channel button clicked', {
dataSource: ALERTS_DATA_SOURCE_MAP[alertDef?.alertType as AlertTypes],
@ -84,18 +93,18 @@ function BasicInfo({
const hasLoggedEvent = useRef(false);
useEffect(() => {
if (!channels.loading && isNewRule && !hasLoggedEvent.current) {
if (!isLoading && isNewRule && !hasLoggedEvent.current) {
logEvent('Alert: New alert creation page visited', {
dataSource: ALERTS_DATA_SOURCE_MAP[alertDef?.alertType as AlertTypes],
numberOfChannels: channels?.payload?.length,
numberOfChannels: data?.data?.length,
});
hasLoggedEvent.current = true;
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [channels.loading]);
}, [isLoading]);
const refetchChannels = async (): Promise<void> => {
await channels.refetch();
await refetch();
};
return (
@ -192,7 +201,7 @@ function BasicInfo({
<Switch
checked={shouldBroadCastToAllChannels}
onChange={handleBroadcastToAllChannels}
disabled={noChannels || !!channels.loading}
disabled={noChannels || !!isLoading}
data-testid="alert-broadcast-to-all-channels"
/>
</Tooltip>
@ -220,7 +229,10 @@ function BasicInfo({
disabled={shouldBroadCastToAllChannels}
currentValue={alertDef.preferredChannels}
handleCreateNewChannels={handleCreateNewChannels}
channels={channels}
channels={data?.data || []}
isLoading={isLoading}
hasError={isError}
error={error as APIError}
onSelectChannels={(preferredChannels): void => {
setAlertDef({
...alertDef,

View File

@ -1,12 +1,12 @@
import { PlusOutlined } from '@ant-design/icons';
import { Select, Spin } from 'antd';
import useComponentPermission from 'hooks/useComponentPermission';
import { State } from 'hooks/useFetch';
import { useNotifications } from 'hooks/useNotifications';
import { useAppContext } from 'providers/App/App';
import { ReactNode } from 'react';
import { useTranslation } from 'react-i18next';
import { PayloadProps } from 'types/api/channels/getAll';
import { Channels } from 'types/api/channels/getAll';
import APIError from 'types/api/error';
import { StyledCreateChannelOption, StyledSelect } from './styles';
@ -15,7 +15,10 @@ export interface ChannelSelectProps {
currentValue?: string[];
onSelectChannels: (s: string[]) => void;
onDropdownOpen: () => void;
channels: State<PayloadProps | undefined>;
isLoading: boolean;
channels: Channels[];
hasError: boolean;
error: APIError;
handleCreateNewChannels: () => void;
}
@ -25,6 +28,9 @@ function ChannelSelect({
onSelectChannels,
onDropdownOpen,
channels,
isLoading,
hasError,
error,
handleCreateNewChannels,
}: ChannelSelectProps): JSX.Element | null {
// init namespace for translations
@ -40,10 +46,10 @@ function ChannelSelect({
onSelectChannels(value);
};
if (channels.error && channels.errorMessage !== '') {
if (hasError) {
notifications.error({
message: 'Error',
description: channels.errorMessage,
message: error.getErrorCode(),
description: error.getErrorMessage(),
});
}
@ -56,7 +62,7 @@ function ChannelSelect({
const renderOptions = (): ReactNode[] => {
const children: ReactNode[] = [];
if (!channels.loading && addNewChannelPermission) {
if (!isLoading && addNewChannelPermission) {
children.push(
<Select.Option key="add-new-channel" value="add-new-channel">
<StyledCreateChannelOption>
@ -67,15 +73,11 @@ function ChannelSelect({
);
}
if (
channels.loading ||
channels.payload === undefined ||
channels.payload.length === 0
) {
if (isLoading || channels.length === 0) {
return children;
}
channels.payload.forEach((o) => {
channels.forEach((o) => {
children.push(
<Select.Option key={o.id} value={o.name}>
{o.name}
@ -89,13 +91,13 @@ function ChannelSelect({
return (
<StyledSelect
disabled={disabled}
status={channels.error ? 'error' : ''}
status={hasError ? 'error' : ''}
mode="multiple"
style={{ width: '100%' }}
placeholder={t('placeholder_channel_select')}
data-testid="alert-channel-select"
value={currentValue}
notFoundContent={channels.loading && <Spin size="small" />}
notFoundContent={isLoading && <Spin size="small" />}
onDropdownVisibleChange={(open): void => {
if (open) {
onDropdownOpen();

View File

@ -25,7 +25,7 @@ function DisplayName({ index, id: orgId }: DisplayNameProps): JSX.Element {
displayName,
orgId,
});
if (statusCode === 200) {
if (statusCode === 204) {
notifications.success({
message: t('success', {
ns: 'common',

View File

@ -237,8 +237,8 @@ export const handlers = [
(req, res, ctx) => res(ctx.status(200), ctx.json(traceDetailResponse)),
),
rest.post('http://localhost/api/v1//channels', (_, res, ctx) =>
res(ctx.status(200), ctx.json(allAlertChannels)),
rest.get('http://localhost/api/v1/channels', (_, res, ctx) =>
res(ctx.status(200), ctx.json({ data: allAlertChannels, status: 'success' })),
),
rest.delete('http://localhost/api/v1/channels/:id', (_, res, ctx) =>
res(

View File

@ -13,12 +13,18 @@ import EditAlertChannels from 'container/EditAlertChannels';
import { useTranslation } from 'react-i18next';
import { useQuery } from 'react-query';
import { useParams } from 'react-router-dom';
import { SuccessResponseV2 } from 'types/api';
import { Channels } from 'types/api/channels/getAll';
import APIError from 'types/api/error';
function ChannelsEdit(): JSX.Element {
const { id } = useParams<Params>();
const { t } = useTranslation();
const { isFetching, isError, data } = useQuery(['getChannel', id], {
const { isFetching, isError, data, error } = useQuery<
SuccessResponseV2<Channels>,
APIError
>(['getChannel', id], {
queryFn: () =>
get({
id,
@ -26,14 +32,18 @@ function ChannelsEdit(): JSX.Element {
});
if (isError) {
return <Typography>{data?.error || t('something_went_wrong')}</Typography>;
return (
<Typography>
{error?.getErrorMessage() || t('something_went_wrong')}
</Typography>
);
}
if (isFetching || !data?.payload) {
if (isFetching || !data?.data) {
return <Spinner tip="Loading Channels..." />;
}
const { data: ChannelData } = data.payload;
const { data: ChannelData } = data.data;
const value = JSON.parse(ChannelData);

View File

@ -4,4 +4,7 @@ export interface Props {
id: Channels['id'];
}
export type PayloadProps = Channels;
export type PayloadProps = {
data: Channels;
status: string;
};

View File

@ -1,4 +1,7 @@
export type PayloadProps = Channels[];
export type PayloadProps = {
data: Channels[];
status: string;
};
export interface Channels {
created_at: string;

View File

@ -13,6 +13,14 @@ class APIError extends Error {
getHttpStatusCode(): StatusCodes {
return this.error.httpStatusCode;
}
getErrorMessage(): string {
return this.error.error.message;
}
getErrorCode(): string {
return this.error.error.code;
}
}
export default APIError;

View File

@ -30,6 +30,11 @@ export interface ErrorV2 {
url: string;
errors: AdditionalErrors[];
}
export interface ErrorV2Resp {
error: ErrorV2;
}
export interface ErrorResponseV2 {
httpStatusCode: StatusCodes;
error: ErrorV2;