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

View File

@ -1,14 +1,14 @@
import axios from 'api'; import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api'; import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createEmail'; import { PayloadProps, Props } from 'types/api/channels/createEmail';
const create = async ( const create = async (
props: Props, props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => { ): Promise<SuccessResponseV2<PayloadProps>> => {
try { try {
const response = await axios.post('/channels', { const response = await axios.post<PayloadProps>('/channels', {
name: props.name, name: props.name,
email_configs: [ email_configs: [
{ {
@ -21,13 +21,12 @@ const create = async (
}); });
return { return {
statusCode: 200, httpStatusCode: response.status,
error: null, data: response.data,
message: 'Success',
payload: response.data.data,
}; };
} catch (error) { } 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 axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api'; import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createMsTeams'; import { PayloadProps, Props } from 'types/api/channels/createMsTeams';
const create = async ( const create = async (
props: Props, props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => { ): Promise<SuccessResponseV2<PayloadProps>> => {
try { try {
const response = await axios.post('/channels', { const response = await axios.post<PayloadProps>('/channels', {
name: props.name, name: props.name,
msteamsv2_configs: [ msteamsv2_configs: [
{ {
@ -21,13 +21,12 @@ const create = async (
}); });
return { return {
statusCode: 200, httpStatusCode: response.status,
error: null, data: response.data,
message: 'Success',
payload: response.data.data,
}; };
} catch (error) { } 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 axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api'; import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createOpsgenie'; import { PayloadProps, Props } from 'types/api/channels/createOpsgenie';
const create = async ( const create = async (
props: Props, props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => { ): Promise<SuccessResponseV2<PayloadProps>> => {
try { try {
const response = await axios.post('/channels', { const response = await axios.post<PayloadProps>('/channels', {
name: props.name, name: props.name,
opsgenie_configs: [ opsgenie_configs: [
{ {
@ -24,13 +24,12 @@ const create = async (
}); });
return { return {
statusCode: 200, httpStatusCode: response.status,
error: null, data: response.data,
message: 'Success',
payload: response.data.data,
}; };
} catch (error) { } 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 axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api'; import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createPager'; import { PayloadProps, Props } from 'types/api/channels/createPager';
const create = async ( const create = async (
props: Props, props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => { ): Promise<SuccessResponseV2<PayloadProps>> => {
try { try {
const response = await axios.post('/channels', { const response = await axios.post<PayloadProps>('/channels', {
name: props.name, name: props.name,
pagerduty_configs: [ pagerduty_configs: [
{ {
@ -29,13 +29,12 @@ const create = async (
}); });
return { return {
statusCode: 200, httpStatusCode: response.status,
error: null, data: response.data,
message: 'Success',
payload: response.data.data,
}; };
} catch (error) { } 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 axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api'; import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createSlack'; import { PayloadProps, Props } from 'types/api/channels/createSlack';
const create = async ( const create = async (
props: Props, props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => { ): Promise<SuccessResponseV2<PayloadProps>> => {
try { try {
const response = await axios.post('/channels', { const response = await axios.post<PayloadProps>('/channels', {
name: props.name, name: props.name,
slack_configs: [ slack_configs: [
{ {
@ -22,13 +22,12 @@ const create = async (
}); });
return { return {
statusCode: 200, httpStatusCode: response.status,
error: null, data: response.data,
message: 'Success',
payload: response.data.data,
}; };
} catch (error) { } 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 axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api'; import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createWebhook'; import { PayloadProps, Props } from 'types/api/channels/createWebhook';
const create = async ( const create = async (
props: Props, props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => { ): Promise<SuccessResponseV2<PayloadProps>> => {
try { try {
let httpConfig = {}; let httpConfig = {};
const username = props.username ? props.username.trim() : ''; 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, name: props.name,
webhook_configs: [ webhook_configs: [
{ {
@ -40,13 +40,12 @@ const create = async (
}); });
return { return {
statusCode: 200, httpStatusCode: response.status,
error: null, data: response.data,
message: 'Success',
payload: response.data.data,
}; };
} catch (error) { } 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 axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api'; import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/delete'; import { PayloadProps, Props } from 'types/api/channels/delete';
const deleteChannel = async ( const deleteChannel = async (
props: Props, props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => { ): Promise<SuccessResponseV2<PayloadProps>> => {
try { try {
const response = await axios.delete(`/channels/${props.id}`); const response = await axios.delete<PayloadProps>(`/channels/${props.id}`);
return { return {
statusCode: 200, httpStatusCode: response.status,
error: null, data: response.data,
message: 'Success',
payload: response.data.data,
}; };
} catch (error) { } 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 axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api'; import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/editEmail'; import { PayloadProps, Props } from 'types/api/channels/editEmail';
const editEmail = async ( const editEmail = async (
props: Props, props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => { ): Promise<SuccessResponseV2<PayloadProps>> => {
try { try {
const response = await axios.put(`/channels/${props.id}`, { const response = await axios.put<PayloadProps>(`/channels/${props.id}`, {
name: props.name, name: props.name,
email_configs: [ email_configs: [
{ {
@ -21,13 +21,12 @@ const editEmail = async (
}); });
return { return {
statusCode: 200, httpStatusCode: response.status,
error: null, data: response.data,
message: 'Success',
payload: response.data.data,
}; };
} catch (error) { } 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 axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api'; import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/editMsTeams'; import { PayloadProps, Props } from 'types/api/channels/editMsTeams';
const editMsTeams = async ( const editMsTeams = async (
props: Props, props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => { ): Promise<SuccessResponseV2<PayloadProps>> => {
try { try {
const response = await axios.put(`/channels/${props.id}`, { const response = await axios.put<PayloadProps>(`/channels/${props.id}`, {
name: props.name, name: props.name,
msteamsv2_configs: [ msteamsv2_configs: [
{ {
@ -21,13 +21,12 @@ const editMsTeams = async (
}); });
return { return {
statusCode: 200, httpStatusCode: response.status,
error: null, data: response.data,
message: 'Success',
payload: response.data.data,
}; };
} catch (error) { } 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 axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios'; 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'; import { PayloadProps, Props } from 'types/api/channels/editOpsgenie';
const editOpsgenie = async ( const editOpsgenie = async (
props: Props, props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => { ): Promise<SuccessResponseV2<PayloadProps> | ErrorResponse> => {
try { try {
const response = await axios.put(`/channels/${props.id}`, { const response = await axios.put<PayloadProps>(`/channels/${props.id}`, {
name: props.name, name: props.name,
opsgenie_configs: [ opsgenie_configs: [
{ {
@ -25,13 +25,12 @@ const editOpsgenie = async (
}); });
return { return {
statusCode: 200, httpStatusCode: response.status,
error: null, data: response.data,
message: 'Success',
payload: response.data.data,
}; };
} catch (error) { } 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 axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api'; import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/editPager'; import { PayloadProps, Props } from 'types/api/channels/editPager';
const editPager = async ( const editPager = async (
props: Props, props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => { ): Promise<SuccessResponseV2<PayloadProps>> => {
try { try {
const response = await axios.put(`/channels/${props.id}`, { const response = await axios.put<PayloadProps>(`/channels/${props.id}`, {
name: props.name, name: props.name,
pagerduty_configs: [ pagerduty_configs: [
{ {
@ -29,13 +29,12 @@ const editPager = async (
}); });
return { return {
statusCode: 200, httpStatusCode: response.status,
error: null, data: response.data,
message: 'Success',
payload: response.data.data,
}; };
} catch (error) { } 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 axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api'; import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/editSlack'; import { PayloadProps, Props } from 'types/api/channels/editSlack';
const editSlack = async ( const editSlack = async (
props: Props, props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => { ): Promise<SuccessResponseV2<PayloadProps>> => {
try { try {
const response = await axios.put(`/channels/${props.id}`, { const response = await axios.put<PayloadProps>(`/channels/${props.id}`, {
name: props.name, name: props.name,
slack_configs: [ slack_configs: [
{ {
@ -22,13 +22,12 @@ const editSlack = async (
}); });
return { return {
statusCode: 200, httpStatusCode: response.status,
error: null, data: response.data,
message: 'Success',
payload: response.data.data,
}; };
} catch (error) { } 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 axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api'; import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/editWebhook'; import { PayloadProps, Props } from 'types/api/channels/editWebhook';
const editWebhook = async ( const editWebhook = async (
props: Props, props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => { ): Promise<SuccessResponseV2<PayloadProps>> => {
try { try {
let httpConfig = {}; let httpConfig = {};
const username = props.username ? props.username.trim() : ''; 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, name: props.name,
webhook_configs: [ webhook_configs: [
{ {
@ -40,13 +40,12 @@ const editWebhook = async (
}); });
return { return {
statusCode: 200, httpStatusCode: response.status,
error: null, data: response.data,
message: 'Success',
payload: response.data.data,
}; };
} catch (error) { } 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 axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios'; 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 { PayloadProps, Props } from 'types/api/channels/get';
import { Channels } from 'types/api/channels/getAll';
const get = async ( const get = async (props: Props): Promise<SuccessResponseV2<Channels>> => {
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try { try {
const response = await axios.get(`/channels/${props.id}`); const response = await axios.get<PayloadProps>(`/channels/${props.id}`);
return { return {
statusCode: 200, httpStatusCode: response.status,
error: null, data: response.data.data,
message: 'Success',
payload: response.data.data,
}; };
} catch (error) { } 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 axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api'; import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps } from 'types/api/channels/getAll'; import { Channels, PayloadProps } from 'types/api/channels/getAll';
const getAll = async (): Promise< const getAll = async (): Promise<SuccessResponseV2<Channels[]>> => {
SuccessResponse<PayloadProps> | ErrorResponse
> => {
try { try {
const response = await axios.get('/channels'); const response = await axios.get<PayloadProps>('/channels');
return { return {
statusCode: 200, httpStatusCode: response.status,
error: null, data: response.data.data,
message: 'Success',
payload: response.data.data,
}; };
} catch (error) { } 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 axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api'; import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createEmail'; import { PayloadProps, Props } from 'types/api/channels/createEmail';
const testEmail = async ( const testEmail = async (
props: Props, props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => { ): Promise<SuccessResponseV2<PayloadProps>> => {
try { try {
const response = await axios.post('/testChannel', { const response = await axios.post<PayloadProps>('/testChannel', {
name: props.name, name: props.name,
email_configs: [ email_configs: [
{ {
@ -21,13 +21,12 @@ const testEmail = async (
}); });
return { return {
statusCode: 200, httpStatusCode: response.status,
error: null, data: response.data,
message: 'Success',
payload: response.data.data,
}; };
} catch (error) { } 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 axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api'; import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createMsTeams'; import { PayloadProps, Props } from 'types/api/channels/createMsTeams';
const testMsTeams = async ( const testMsTeams = async (
props: Props, props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => { ): Promise<SuccessResponseV2<PayloadProps>> => {
try { try {
const response = await axios.post('/testChannel', { const response = await axios.post<PayloadProps>('/testChannel', {
name: props.name, name: props.name,
msteamsv2_configs: [ msteamsv2_configs: [
{ {
@ -21,13 +21,12 @@ const testMsTeams = async (
}); });
return { return {
statusCode: 200, httpStatusCode: response.status,
error: null, data: response.data,
message: 'Success',
payload: response.data.data,
}; };
} catch (error) { } 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 axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api'; import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createOpsgenie'; import { PayloadProps, Props } from 'types/api/channels/createOpsgenie';
const testOpsgenie = async ( const testOpsgenie = async (
props: Props, props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => { ): Promise<SuccessResponseV2<PayloadProps>> => {
try { try {
const response = await axios.post('/testChannel', { const response = await axios.post<PayloadProps>('/testChannel', {
name: props.name, name: props.name,
opsgenie_configs: [ opsgenie_configs: [
{ {
@ -24,13 +24,12 @@ const testOpsgenie = async (
}); });
return { return {
statusCode: 200, httpStatusCode: response.status,
error: null, data: response.data,
message: 'Success',
payload: response.data.data,
}; };
} catch (error) { } 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 axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api'; import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createPager'; import { PayloadProps, Props } from 'types/api/channels/createPager';
const testPager = async ( const testPager = async (
props: Props, props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => { ): Promise<SuccessResponseV2<PayloadProps>> => {
try { try {
const response = await axios.post('/testChannel', { const response = await axios.post<PayloadProps>('/testChannel', {
name: props.name, name: props.name,
pagerduty_configs: [ pagerduty_configs: [
{ {
@ -29,13 +29,12 @@ const testPager = async (
}); });
return { return {
statusCode: 200, httpStatusCode: response.status,
error: null, data: response.data,
message: 'Success',
payload: response.data.data,
}; };
} catch (error) { } 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 axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api'; import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createSlack'; import { PayloadProps, Props } from 'types/api/channels/createSlack';
const testSlack = async ( const testSlack = async (
props: Props, props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => { ): Promise<SuccessResponseV2<PayloadProps>> => {
try { try {
const response = await axios.post('/testChannel', { const response = await axios.post<PayloadProps>('/testChannel', {
name: props.name, name: props.name,
slack_configs: [ slack_configs: [
{ {
@ -22,13 +22,12 @@ const testSlack = async (
}); });
return { return {
statusCode: 200, httpStatusCode: response.status,
error: null, data: response.data,
message: 'Success',
payload: response.data.data,
}; };
} catch (error) { } 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 axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api'; import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createWebhook'; import { PayloadProps, Props } from 'types/api/channels/createWebhook';
const testWebhook = async ( const testWebhook = async (
props: Props, props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => { ): Promise<SuccessResponseV2<PayloadProps>> => {
try { try {
let httpConfig = {}; let httpConfig = {};
const username = props.username ? props.username.trim() : ''; 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, name: props.name,
webhook_configs: [ webhook_configs: [
{ {
@ -40,13 +40,12 @@ const testWebhook = async (
}); });
return { return {
statusCode: 200, httpStatusCode: response.status,
error: null, data: response.data,
message: 'Success',
payload: response.data.data,
}; };
} catch (error) { } 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 axios from 'api';
import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2'; import { ErrorResponseHandlerV2 } from 'api/ErrorResponseHandlerV2';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { ErrorV2, SuccessResponseV2 } from 'types/api'; import { ErrorV2Resp, SuccessResponseV2 } from 'types/api';
import { PayloadProps, Props } from 'types/api/user/login'; import { PayloadProps, Props } from 'types/api/user/login';
const login = async ( const login = async (
@ -17,7 +17,7 @@ const login = async (
data: response.data, data: response.data,
}; };
} catch (error) { } 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 // this line is never reached but ts isn't detecting the never type properly for the ErrorResponseHandlerV2
throw error; throw error;
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -119,12 +119,7 @@ describe('Create Alert Channel', () => {
fireEvent.click(saveButton); fireEvent.click(saveButton);
await waitFor(() => await waitFor(() => expect(errorNotification).toHaveBeenCalled());
expect(errorNotification).toHaveBeenCalledWith({
description: 'Something went wrong',
message: 'Error',
}),
);
}); });
it('Should check if clicking on Test button shows "An alert has been sent to this channel" success message if testing passes', async () => { 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( server.use(
@ -158,12 +153,7 @@ describe('Create Alert Channel', () => {
fireEvent.click(testButton); fireEvent.click(testButton);
await waitFor(() => await waitFor(() => expect(errorNotification).toHaveBeenCalled());
expect(errorNotification).toHaveBeenCalledWith({
message: 'Error',
description: 'channel_test_failed',
}),
);
}); });
}); });
describe('New Alert Channel Cascading Fields Based on Channel Type', () => { 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 TextToolTip from 'components/TextToolTip';
import ROUTES from 'constants/routes'; import ROUTES from 'constants/routes';
import useComponentPermission from 'hooks/useComponentPermission'; import useComponentPermission from 'hooks/useComponentPermission';
import useFetch from 'hooks/useFetch';
import history from 'lib/history'; import history from 'lib/history';
import { isUndefined } from 'lodash-es'; import { isUndefined } from 'lodash-es';
import { useAppContext } from 'providers/App/App'; import { useAppContext } from 'providers/App/App';
import { useCallback, useEffect } from 'react'; import { useCallback, useEffect } from 'react';
import { useTranslation } from 'react-i18next'; 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 AlertChannelsComponent from './AlertChannels';
import { Button, ButtonContainer, RightActionContainer } from './styles'; import { Button, ButtonContainer, RightActionContainer } from './styles';
@ -29,21 +32,26 @@ function AlertChannels(): JSX.Element {
history.push(ROUTES.CHANNELS_NEW); history.push(ROUTES.CHANNELS_NEW);
}, []); }, []);
const { loading, payload, error, errorMessage } = useFetch(getAll); const { isLoading, data, error } = useQuery<
SuccessResponseV2<Channels[]>,
APIError
>(['getChannels'], {
queryFn: () => getAll(),
});
useEffect(() => { useEffect(() => {
if (!isUndefined(payload)) { if (!isUndefined(data?.data)) {
logEvent('Alert Channel: Channel list page visited', { logEvent('Alert Channel: Channel list page visited', {
number: payload?.length, number: data?.data?.length,
}); });
} }
}, [payload]); }, [data?.data]);
if (error) { 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" />; return <Spinner tip={t('loading_channels_message')} height="90vh" />;
} }
@ -78,7 +86,7 @@ function AlertChannels(): JSX.Element {
</RightActionContainer> </RightActionContainer>
</ButtonContainer> </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 history from 'lib/history';
import { useCallback, useEffect, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import APIError from 'types/api/error';
import { import {
ChannelType, ChannelType,
@ -136,28 +137,17 @@ function CreateAlertChannels({
setSavingState(true); setSavingState(true);
try { try {
const response = await createSlackApi(prepareSlackRequest()); await createSlackApi(prepareSlackRequest());
if (response.statusCode === 200) {
notifications.success({ notifications.success({
message: 'Success', message: 'Success',
description: t('channel_creation_done'), description: t('channel_creation_done'),
}); });
history.replace(ROUTES.ALL_CHANNELS); history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_creation_done') }; return { status: 'success', statusMessage: t('channel_creation_done') };
}
notifications.error({
message: 'Error',
description: response.error || t('channel_creation_failed'),
});
return {
status: 'failed',
statusMessage: response.error || t('channel_creation_failed'),
};
} catch (error) { } catch (error) {
notifications.error({ notifications.error({
message: 'Error', message: (error as APIError).error.error.code,
description: t('channel_creation_failed'), description: (error as APIError).error.error.message,
}); });
return { status: 'failed', statusMessage: t('channel_creation_failed') }; return { status: 'failed', statusMessage: t('channel_creation_failed') };
} finally { } finally {
@ -204,27 +194,17 @@ function CreateAlertChannels({
setSavingState(true); setSavingState(true);
try { try {
const request = prepareWebhookRequest(); const request = prepareWebhookRequest();
const response = await createWebhookApi(request); await createWebhookApi(request);
if (response.statusCode === 200) {
notifications.success({ notifications.success({
message: 'Success', message: 'Success',
description: t('channel_creation_done'), description: t('channel_creation_done'),
}); });
history.replace(ROUTES.ALL_CHANNELS); history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_creation_done') }; return { status: 'success', statusMessage: t('channel_creation_done') };
}
notifications.error({
message: 'Error',
description: response.error || t('channel_creation_failed'),
});
return {
status: 'failed',
statusMessage: response.error || t('channel_creation_failed'),
};
} catch (error) { } catch (error) {
notifications.error({ notifications.error({
message: 'Error', message: (error as APIError).getErrorCode(),
description: t('channel_creation_failed'), description: (error as APIError).getErrorMessage(),
}); });
return { status: 'failed', statusMessage: t('channel_creation_failed') }; return { status: 'failed', statusMessage: t('channel_creation_failed') };
} finally { } finally {
@ -264,9 +244,7 @@ function CreateAlertChannels({
try { try {
if (request) { if (request) {
const response = await createPagerApi(request); await createPagerApi(request);
if (response.statusCode === 200) {
notifications.success({ notifications.success({
message: 'Success', message: 'Success',
description: t('channel_creation_done'), description: t('channel_creation_done'),
@ -274,24 +252,11 @@ function CreateAlertChannels({
history.replace(ROUTES.ALL_CHANNELS); history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_creation_done') }; return { status: 'success', statusMessage: t('channel_creation_done') };
} }
notifications.error({
message: 'Error',
description: response.error || t('channel_creation_failed'),
});
return {
status: 'failed',
statusMessage: response.error || t('channel_creation_failed'),
};
}
notifications.error({
message: 'Error',
description: t('channel_creation_failed'),
});
return { status: 'failed', statusMessage: t('channel_creation_failed') }; return { status: 'failed', statusMessage: t('channel_creation_failed') };
} catch (error) { } catch (error) {
notifications.error({ notifications.error({
message: 'Error', message: (error as APIError).getErrorCode(),
description: t('channel_creation_failed'), description: (error as APIError).getErrorMessage(),
}); });
return { status: 'failed', statusMessage: t('channel_creation_failed') }; return { status: 'failed', statusMessage: t('channel_creation_failed') };
} finally { } finally {
@ -313,30 +278,18 @@ function CreateAlertChannels({
const onOpsgenieHandler = useCallback(async () => { const onOpsgenieHandler = useCallback(async () => {
setSavingState(true); setSavingState(true);
try { try {
const response = await createOpsgenie(prepareOpsgenieRequest()); await createOpsgenie(prepareOpsgenieRequest());
if (response.statusCode === 200) {
notifications.success({ notifications.success({
message: 'Success', message: 'Success',
description: t('channel_creation_done'), description: t('channel_creation_done'),
}); });
history.replace(ROUTES.ALL_CHANNELS); history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_creation_done') }; return { status: 'success', statusMessage: t('channel_creation_done') };
}
notifications.error({
message: 'Error',
description: response.error || t('channel_creation_failed'),
});
return {
status: 'failed',
statusMessage: response.error || t('channel_creation_failed'),
};
} catch (error) { } catch (error) {
notifications.error({ notifications.error({
message: 'Error', message: (error as APIError).getErrorCode(),
description: t('channel_creation_failed'), description: (error as APIError).getErrorMessage(),
}); });
return { status: 'failed', statusMessage: t('channel_creation_failed') }; return { status: 'failed', statusMessage: t('channel_creation_failed') };
} finally { } finally {
@ -359,27 +312,17 @@ function CreateAlertChannels({
setSavingState(true); setSavingState(true);
try { try {
const request = prepareEmailRequest(); const request = prepareEmailRequest();
const response = await createEmail(request); await createEmail(request);
if (response.statusCode === 200) {
notifications.success({ notifications.success({
message: 'Success', message: 'Success',
description: t('channel_creation_done'), description: t('channel_creation_done'),
}); });
history.replace(ROUTES.ALL_CHANNELS); history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_creation_done') }; return { status: 'success', statusMessage: t('channel_creation_done') };
}
notifications.error({
message: 'Error',
description: response.error || t('channel_creation_failed'),
});
return {
status: 'failed',
statusMessage: response.error || t('channel_creation_failed'),
};
} catch (error) { } catch (error) {
notifications.error({ notifications.error({
message: 'Error', message: (error as APIError).getErrorCode(),
description: t('channel_creation_failed'), description: (error as APIError).getErrorMessage(),
}); });
return { status: 'failed', statusMessage: t('channel_creation_failed') }; return { status: 'failed', statusMessage: t('channel_creation_failed') };
} finally { } finally {
@ -402,28 +345,17 @@ function CreateAlertChannels({
setSavingState(true); setSavingState(true);
try { try {
const response = await createMsTeamsApi(prepareMsTeamsRequest()); await createMsTeamsApi(prepareMsTeamsRequest());
if (response.statusCode === 200) {
notifications.success({ notifications.success({
message: 'Success', message: 'Success',
description: t('channel_creation_done'), description: t('channel_creation_done'),
}); });
history.replace(ROUTES.ALL_CHANNELS); history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_creation_done') }; return { status: 'success', statusMessage: t('channel_creation_done') };
}
notifications.error({
message: 'Error',
description: response.error || t('channel_creation_failed'),
});
return {
status: 'failed',
statusMessage: response.error || t('channel_creation_failed'),
};
} catch (error) { } catch (error) {
notifications.error({ notifications.error({
message: 'Error', message: (error as APIError).getErrorCode(),
description: t('channel_creation_failed'), description: (error as APIError).getErrorMessage(),
}); });
return { status: 'failed', statusMessage: t('channel_creation_failed') }; return { status: 'failed', statusMessage: t('channel_creation_failed') };
} finally { } finally {
@ -481,31 +413,30 @@ function CreateAlertChannels({
setTestingState(true); setTestingState(true);
try { try {
let request; let request;
let response;
switch (channelType) { switch (channelType) {
case ChannelType.Webhook: case ChannelType.Webhook:
request = prepareWebhookRequest(); request = prepareWebhookRequest();
response = await testWebhookApi(request); await testWebhookApi(request);
break; break;
case ChannelType.Slack: case ChannelType.Slack:
request = prepareSlackRequest(); request = prepareSlackRequest();
response = await testSlackApi(request); await testSlackApi(request);
break; break;
case ChannelType.Pagerduty: case ChannelType.Pagerduty:
request = preparePagerRequest(); request = preparePagerRequest();
if (request) response = await testPagerApi(request); if (request) await testPagerApi(request);
break; break;
case ChannelType.MsTeams: case ChannelType.MsTeams:
request = prepareMsTeamsRequest(); request = prepareMsTeamsRequest();
response = await testMsTeamsApi(request); await testMsTeamsApi(request);
break; break;
case ChannelType.Opsgenie: case ChannelType.Opsgenie:
request = prepareOpsgenieRequest(); request = prepareOpsgenieRequest();
response = await testOpsGenie(request); await testOpsGenie(request);
break; break;
case ChannelType.Email: case ChannelType.Email:
request = prepareEmailRequest(); request = prepareEmailRequest();
response = await testEmail(request); await testEmail(request);
break; break;
default: default:
notifications.error({ notifications.error({
@ -516,30 +447,28 @@ function CreateAlertChannels({
return; return;
} }
if (response && response.statusCode === 200) {
notifications.success({ notifications.success({
message: 'Success', message: 'Success',
description: t('channel_test_done'), description: t('channel_test_done'),
}); });
} else {
notifications.error({
message: 'Error',
description: t('channel_test_failed'),
});
}
logEvent('Alert Channel: Test notification', { logEvent('Alert Channel: Test notification', {
type: channelType, type: channelType,
sendResolvedAlert: selectedConfig?.send_resolved, sendResolvedAlert: selectedConfig?.send_resolved,
name: selectedConfig?.name, name: selectedConfig?.name,
new: 'true', new: 'true',
status: status: 'Test success',
response && response.statusCode === 200 ? 'Test success' : 'Test failed',
}); });
} catch (error) { } catch (error) {
notifications.error({ notifications.error({
message: 'Error', message: (error as APIError).error.error.code,
description: t('channel_test_unexpected'), 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 { useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import APIError from 'types/api/error';
function EditAlertChannels({ function EditAlertChannels({
initialValue, initialValue,
@ -93,9 +94,8 @@ function EditAlertChannels({
return { status: 'failed', statusMessage: t('webhook_url_required') }; return { status: 'failed', statusMessage: t('webhook_url_required') };
} }
const response = await editSlackApi(prepareSlackRequest()); try {
await editSlackApi(prepareSlackRequest());
if (response.statusCode === 200) {
notifications.success({ notifications.success({
message: 'Success', message: 'Success',
description: t('channel_edit_done'), description: t('channel_edit_done'),
@ -103,16 +103,19 @@ function EditAlertChannels({
history.replace(ROUTES.ALL_CHANNELS); history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_edit_done') }; return { status: 'success', statusMessage: t('channel_edit_done') };
} } catch (error) {
notifications.error({ notifications.error({
message: 'Error', message: (error as APIError).getErrorCode(),
description: response.error || t('channel_edit_failed'), description: (error as APIError).getErrorMessage(),
}); });
setSavingState(false);
return { return {
status: 'failed', status: 'failed',
statusMessage: response.error || t('channel_edit_failed'), statusMessage:
(error as APIError).getErrorMessage() || t('channel_edit_failed'),
}; };
} finally {
setSavingState(false);
}
}, [prepareSlackRequest, t, notifications, selectedConfig]); }, [prepareSlackRequest, t, notifications, selectedConfig]);
const prepareWebhookRequest = useCallback(() => { const prepareWebhookRequest = useCallback(() => {
@ -150,9 +153,8 @@ function EditAlertChannels({
return { status: 'failed', statusMessage: t('username_no_password') }; return { status: 'failed', statusMessage: t('username_no_password') };
} }
const response = await editWebhookApi(prepareWebhookRequest()); try {
await editWebhookApi(prepareWebhookRequest());
if (response.statusCode === 200) {
notifications.success({ notifications.success({
message: 'Success', message: 'Success',
description: t('channel_edit_done'), description: t('channel_edit_done'),
@ -160,14 +162,19 @@ function EditAlertChannels({
history.replace(ROUTES.ALL_CHANNELS); history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_edit_done') }; return { status: 'success', statusMessage: t('channel_edit_done') };
} } catch (error) {
showError(response.error || t('channel_edit_failed')); notifications.error({
message: (error as APIError).getErrorCode(),
setSavingState(false); description: (error as APIError).getErrorMessage(),
});
return { return {
status: 'failed', status: 'failed',
statusMessage: response.error || t('channel_edit_failed'), statusMessage:
(error as APIError).getErrorMessage() || t('channel_edit_failed'),
}; };
} finally {
setSavingState(false);
}
}, [prepareWebhookRequest, t, notifications, selectedConfig]); }, [prepareWebhookRequest, t, notifications, selectedConfig]);
const prepareEmailRequest = useCallback( const prepareEmailRequest = useCallback(
@ -185,25 +192,28 @@ function EditAlertChannels({
const onEmailEditHandler = useCallback(async () => { const onEmailEditHandler = useCallback(async () => {
setSavingState(true); setSavingState(true);
const request = prepareEmailRequest(); const request = prepareEmailRequest();
const response = await editEmail(request);
if (response.statusCode === 200) { try {
await editEmail(request);
notifications.success({ notifications.success({
message: 'Success', message: 'Success',
description: t('channel_edit_done'), description: t('channel_edit_done'),
}); });
history.replace(ROUTES.ALL_CHANNELS); history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_edit_done') }; return { status: 'success', statusMessage: t('channel_edit_done') };
} } catch (error) {
notifications.error({ notifications.error({
message: 'Error', message: (error as APIError).getErrorCode(),
description: response.error || t('channel_edit_failed'), description: (error as APIError).getErrorMessage(),
}); });
setSavingState(false);
return { return {
status: 'failed', status: 'failed',
statusMessage: response.error || t('channel_edit_failed'), statusMessage:
(error as APIError).getErrorMessage() || t('channel_edit_failed'),
}; };
} finally {
setSavingState(false);
}
}, [prepareEmailRequest, t, notifications]); }, [prepareEmailRequest, t, notifications]);
const preparePagerRequest = useCallback( const preparePagerRequest = useCallback(
@ -237,27 +247,28 @@ function EditAlertChannels({
setSavingState(false); setSavingState(false);
return { status: 'failed', statusMessage: validationError }; return { status: 'failed', statusMessage: validationError };
} }
const response = await editPagerApi(preparePagerRequest());
if (response.statusCode === 200) { try {
await editPagerApi(preparePagerRequest());
notifications.success({ notifications.success({
message: 'Success', message: 'Success',
description: t('channel_edit_done'), description: t('channel_edit_done'),
}); });
history.replace(ROUTES.ALL_CHANNELS); history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_edit_done') }; return { status: 'success', statusMessage: t('channel_edit_done') };
} } catch (error) {
notifications.error({ notifications.error({
message: 'Error', message: (error as APIError).getErrorCode(),
description: response.error || t('channel_edit_failed'), description: (error as APIError).getErrorMessage(),
}); });
setSavingState(false);
return { return {
status: 'failed', status: 'failed',
statusMessage: response.error || t('channel_edit_failed'), statusMessage:
(error as APIError).getErrorMessage() || t('channel_edit_failed'),
}; };
} finally {
setSavingState(false);
}
}, [preparePagerRequest, notifications, selectedConfig, t]); }, [preparePagerRequest, notifications, selectedConfig, t]);
const prepareOpsgenieRequest = useCallback( const prepareOpsgenieRequest = useCallback(
@ -284,28 +295,27 @@ function EditAlertChannels({
setSavingState(false); setSavingState(false);
return { status: 'failed', statusMessage: t('api_key_required') }; return { status: 'failed', statusMessage: t('api_key_required') };
} }
try {
const response = await editOpsgenie(prepareOpsgenieRequest()); await editOpsgenie(prepareOpsgenieRequest());
if (response.statusCode === 200) {
notifications.success({ notifications.success({
message: 'Success', message: 'Success',
description: t('channel_edit_done'), description: t('channel_edit_done'),
}); });
history.replace(ROUTES.ALL_CHANNELS); history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_edit_done') }; return { status: 'success', statusMessage: t('channel_edit_done') };
} } catch (error) {
notifications.error({ notifications.error({
message: 'Error', message: (error as APIError).getErrorCode(),
description: response.error || t('channel_edit_failed'), description: (error as APIError).getErrorMessage(),
}); });
setSavingState(false);
return { return {
status: 'failed', status: 'failed',
statusMessage: response.error || t('channel_edit_failed'), statusMessage:
(error as APIError).getErrorMessage() || t('channel_edit_failed'),
}; };
} finally {
setSavingState(false);
}
}, [prepareOpsgenieRequest, t, notifications, selectedConfig]); }, [prepareOpsgenieRequest, t, notifications, selectedConfig]);
const prepareMsTeamsRequest = useCallback( const prepareMsTeamsRequest = useCallback(
@ -332,27 +342,27 @@ function EditAlertChannels({
return { status: 'failed', statusMessage: t('webhook_url_required') }; return { status: 'failed', statusMessage: t('webhook_url_required') };
} }
const response = await editMsTeamsApi(prepareMsTeamsRequest()); try {
await editMsTeamsApi(prepareMsTeamsRequest());
if (response.statusCode === 200) {
notifications.success({ notifications.success({
message: 'Success', message: 'Success',
description: t('channel_edit_done'), description: t('channel_edit_done'),
}); });
history.replace(ROUTES.ALL_CHANNELS); history.replace(ROUTES.ALL_CHANNELS);
return { status: 'success', statusMessage: t('channel_edit_done') }; return { status: 'success', statusMessage: t('channel_edit_done') };
} } catch (error) {
notifications.error({ notifications.error({
message: 'Error', message: (error as APIError).getErrorCode(),
description: response.error || t('channel_edit_failed'), description: (error as APIError).getErrorMessage(),
}); });
setSavingState(false);
return { return {
status: 'failed', status: 'failed',
statusMessage: response.error || t('channel_edit_failed'), statusMessage:
(error as APIError).getErrorMessage() || t('channel_edit_failed'),
}; };
} finally {
setSavingState(false);
}
}, [prepareMsTeamsRequest, t, notifications, selectedConfig]); }, [prepareMsTeamsRequest, t, notifications, selectedConfig]);
const onSaveHandler = useCallback( const onSaveHandler = useCallback(
@ -396,31 +406,30 @@ function EditAlertChannels({
setTestingState(true); setTestingState(true);
try { try {
let request; let request;
let response;
switch (channelType) { switch (channelType) {
case ChannelType.Webhook: case ChannelType.Webhook:
request = prepareWebhookRequest(); request = prepareWebhookRequest();
response = await testWebhookApi(request); await testWebhookApi(request);
break; break;
case ChannelType.Slack: case ChannelType.Slack:
request = prepareSlackRequest(); request = prepareSlackRequest();
response = await testSlackApi(request); await testSlackApi(request);
break; break;
case ChannelType.Pagerduty: case ChannelType.Pagerduty:
request = preparePagerRequest(); request = preparePagerRequest();
if (request) response = await testPagerApi(request); if (request) await testPagerApi(request);
break; break;
case ChannelType.MsTeams: case ChannelType.MsTeams:
request = prepareMsTeamsRequest(); request = prepareMsTeamsRequest();
if (request) response = await testMsTeamsApi(request); if (request) await testMsTeamsApi(request);
break; break;
case ChannelType.Opsgenie: case ChannelType.Opsgenie:
request = prepareOpsgenieRequest(); request = prepareOpsgenieRequest();
if (request) response = await testOpsgenie(request); if (request) await testOpsgenie(request);
break; break;
case ChannelType.Email: case ChannelType.Email:
request = prepareEmailRequest(); request = prepareEmailRequest();
if (request) response = await testEmail(request); if (request) await testEmail(request);
break; break;
default: default:
notifications.error({ notifications.error({
@ -431,29 +440,28 @@ function EditAlertChannels({
return; return;
} }
if (response && response.statusCode === 200) {
notifications.success({ notifications.success({
message: 'Success', message: 'Success',
description: t('channel_test_done'), description: t('channel_test_done'),
}); });
} else {
notifications.error({
message: 'Error',
description: t('channel_test_failed'),
});
}
logEvent('Alert Channel: Test notification', { logEvent('Alert Channel: Test notification', {
type: channelType, type: channelType,
sendResolvedAlert: selectedConfig?.send_resolved, sendResolvedAlert: selectedConfig?.send_resolved,
name: selectedConfig?.name, name: selectedConfig?.name,
new: 'false', new: 'false',
status: status: 'Test success',
response && response.statusCode === 200 ? 'Test success' : 'Test failed',
}); });
} catch (error) { } catch (error) {
notifications.error({ notifications.error({
message: 'Error', message: (error as APIError).getErrorCode(),
description: t('channel_test_failed'), 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); setTestingState(false);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,4 +4,7 @@ export interface Props {
id: Channels['id']; 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 { export interface Channels {
created_at: string; created_at: string;

View File

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

View File

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