diff --git a/frontend/app/components/Client/Integrations/Backend/DatadogForm/DatadogFormModal.tsx b/frontend/app/components/Client/Integrations/Backend/DatadogForm/DatadogFormModal.tsx index 64dde0560..2910621d0 100644 --- a/frontend/app/components/Client/Integrations/Backend/DatadogForm/DatadogFormModal.tsx +++ b/frontend/app/components/Client/Integrations/Backend/DatadogForm/DatadogFormModal.tsx @@ -10,7 +10,6 @@ import IntegrationModalCard from 'Components/Client/Integrations/IntegrationModa import { Loader } from 'UI'; import DocLink from 'Shared/DocLink/DocLink'; -import { toast } from ".store/react-toastify-virtual-9dd0f3eae1/package"; interface DatadogConfig { site: string; diff --git a/frontend/app/components/Client/Integrations/Backend/DynatraceForm/DynatraceFormModal.tsx b/frontend/app/components/Client/Integrations/Backend/DynatraceForm/DynatraceFormModal.tsx index 40bfe2e8a..325fd6079 100644 --- a/frontend/app/components/Client/Integrations/Backend/DynatraceForm/DynatraceFormModal.tsx +++ b/frontend/app/components/Client/Integrations/Backend/DynatraceForm/DynatraceFormModal.tsx @@ -10,7 +10,6 @@ import IntegrationModalCard from 'Components/Client/Integrations/IntegrationModa import { Loader } from 'UI'; import DocLink from 'Shared/DocLink/DocLink'; -import { toast } from ".store/react-toastify-virtual-9dd0f3eae1/package"; interface DynatraceConfig { environment: string; diff --git a/frontend/app/components/Client/Integrations/Backend/ElasticForm/ElasticFormModal.tsx b/frontend/app/components/Client/Integrations/Backend/ElasticForm/ElasticFormModal.tsx index 94cd2f0e0..f86dfbd79 100644 --- a/frontend/app/components/Client/Integrations/Backend/ElasticForm/ElasticFormModal.tsx +++ b/frontend/app/components/Client/Integrations/Backend/ElasticForm/ElasticFormModal.tsx @@ -10,7 +10,6 @@ import IntegrationModalCard from 'Components/Client/Integrations/IntegrationModa import { Loader } from 'UI'; import DocLink from 'Shared/DocLink/DocLink'; -import { toast } from ".store/react-toastify-virtual-9dd0f3eae1/package"; interface ElasticConfig { url: string; diff --git a/frontend/app/components/Client/Integrations/Teams/TeamsAddForm.tsx b/frontend/app/components/Client/Integrations/Teams/TeamsAddForm.tsx index e45d6d7b1..0f4b2fb1d 100644 --- a/frontend/app/components/Client/Integrations/Teams/TeamsAddForm.tsx +++ b/frontend/app/components/Client/Integrations/Teams/TeamsAddForm.tsx @@ -26,9 +26,13 @@ function TeamsAddForm({ onClose }: Props) { const save = () => { if (instance?.exists()) { - void update(); + update().then(() => { + void onClose(); + }); } else { - void onSave(); + void onSave().then(() => { + void onClose(); + }); } }; @@ -37,16 +41,16 @@ function TeamsAddForm({ onClose }: Props) { await confirm({ header: 'Confirm', confirmButton: 'Yes, delete', - confirmation: `Are you sure you want to permanently delete this channel?`, + confirmation: `Are you sure you want to permanently delete this channel?` }) ) { - void onRemove(id); + void onRemove(id).then(onClose); } }; const write = ({ - target: { name, value }, - }: { + target: { name, value } + }: { target: { name: string; value: string }; }) => edit({ [name]: value }); diff --git a/frontend/app/mstore/integrationsStore.ts b/frontend/app/mstore/integrationsStore.ts index 14806ed58..e37ffc45f 100644 --- a/frontend/app/mstore/integrationsStore.ts +++ b/frontend/app/mstore/integrationsStore.ts @@ -10,9 +10,10 @@ import { Integration, IssueTracker, JiraInt, - SentryInt, + SentryInt } from './types/integrations/services'; import { serviceNames } from 'App/components/Client/Integrations/apiMethods'; +import { toast } from 'react-toastify'; class GenericIntegrationsStore { list: any[] = []; @@ -82,15 +83,15 @@ class NamedIntegrationStore { setList = (list: T[]): void => { this.list = list; - } + }; setFetched = (fetched: boolean): void => { this.fetched = fetched; - } + }; setIssuesFetched = (issuesFetched: boolean): void => { this.issuesFetched = issuesFetched; - } + }; fetchIntegrations = async (): Promise => { this.setLoading(true); @@ -134,23 +135,23 @@ class NamedIntegrationStore { siteId ); return; - } + }; edit = (data: T): void => { if (!this.instance) { this.instance = this.namedTypeCreator({}); } this.instance.edit(data); - } + }; deleteIntegration = async (siteId?: string) => { if (!this.instance) return; return integrationsService.removeIntegration(this.name, siteId); - } + }; init = (config: Record): void => { this.instance = this.namedTypeCreator(config); - } + }; } class MessengerIntegrationStore { @@ -185,19 +186,22 @@ class MessengerIntegrationStore { }; saveIntegration = async (): Promise => { - // redux todo: errors if (!this.instance) return; this.setLoading(true); try { - await integrationsService.saveIntegration( + const response = await integrationsService.saveIntegration( this.mName, this.instance.toData(), undefined ); + if (response.errors) { + toast.error(response.errors[0] || 'Couldn\'t process the request: check your data.'); + return response; + } + this.instance.edit({ webhookId: response.data.webhookId }); this.setList([...this.list, this.instance]); } catch (e) { - console.log(e); - this.setErrors(["Couldn't process the request: check your data."]); + toast.error('Couldn\'t process the request: check your data.'); } finally { this.setLoading(false); } @@ -214,11 +218,11 @@ class MessengerIntegrationStore { }; sendMessage = ({ - integrationId, - entity, - entityId, - data, - }: { + integrationId, + entity, + entityId, + data + }: { integrationId: string; entity: string; entityId: string; @@ -250,21 +254,31 @@ class MessengerIntegrationStore { }; update = async () => { - // redux todo: errors if (!this.instance) return; this.setLoading(true); - await integrationsService.updateMessengerInt( - this.mName, - this.instance.toData() - ); - this.setList( - this.list.map((int) => - int.webhookId === this.instance?.webhookId ? this.instance : int - ) - ); - this.setLoading(false); + try { + const response = await integrationsService.updateMessengerInt( + this.mName, + this.instance.toData() + ); + + if (response.errors) { + toast.error(response.errors[0] || 'Couldn\'t process the request: check your data.'); + return response; + } + this.setList( + this.list.map((int) => + int.webhookId === this.instance?.webhookId ? this.instance : int + ) + ); + } catch (e) { + toast.error('Couldn\'t process the request: check your data.'); + } finally { + this.setLoading(false); + } }; } + export type namedStore = 'sentry' | 'datadog' | 'stackdriver' @@ -277,6 +291,7 @@ export type namedStore = 'sentry' | 'jira' | 'github' | 'issues' + export class IntegrationsStore { sentry = new NamedIntegrationStore('sentry', (d) => new SentryInt(d)); datadog = new NamedIntegrationStore('datadog', (d) => new DatadogInt(d)); diff --git a/frontend/app/services/IntegrationsService.ts b/frontend/app/services/IntegrationsService.ts index b07e50df9..7fcdc1bd1 100644 --- a/frontend/app/services/IntegrationsService.ts +++ b/frontend/app/services/IntegrationsService.ts @@ -1,63 +1,76 @@ -import BaseService from "./BaseService"; +import BaseService from './BaseService'; export default class IntegrationsService extends BaseService { fetchList = async (name?: string, siteId?: string) => { - const r = await this.client.get(`${siteId ? `/${siteId}` : ''}/integrations${name ? `/${name}` : ''}`) - const data = await r.json() + const r = await this.client.get(`${siteId ? `/${siteId}` : ''}/integrations${name ? `/${name}` : ''}`); + const data = await r.json(); - return data - } + return data; + }; fetchIntegration = async (name: string, siteId: string) => { - const url = siteId && name !== 'github' && name !== 'jira' ? `/${siteId}/integrations/${name}` : `/integrations/${name}` - const r = await this.client.get(url) - const data = await r.json() + const url = siteId && name !== 'github' && name !== 'jira' ? `/${siteId}/integrations/${name}` : `/integrations/${name}`; + const r = await this.client.get(url); + const data = await r.json(); - return data - } + return data; + }; saveIntegration = async (name: string, data: any, siteId?: string) => { - const url = (siteId ? `/${siteId}` : '') + `/integrations/${name}` - const r = await this.client.post(url, data) - const res = await r.json() - - return res - } + try { + const url = (siteId ? `/${siteId}` : '') + `/integrations/${name}`; + const r = await this.client.post(url, data); + return await r.json(); + } catch (e: any) { + if (e.response) { + const errorData = await e.response.json(); + return { errors: errorData.errors }; + } + return { errors: ['An unexpected error occurred.'] }; + } + }; removeIntegration = async (name: string, siteId?: string) => { - const url = (siteId ? `/${siteId}` : '') + `/integrations/${name}` - const r = await this.client.delete(url) + const url = (siteId ? `/${siteId}` : '') + `/integrations/${name}`; + const r = await this.client.delete(url); - return await r.json() - } + return await r.json(); + }; fetchMessengerChannels = async (name: string) => { - const r = await this.client.get(`/integrations/${name}/channels`) + const r = await this.client.get(`/integrations/${name}/channels`); - return await r.json() - } + return await r.json(); + }; updateMessengerInt = async (name: string, data: any) => { - const r = await this.client.put(`/integrations/${name}/${data.webhookId}`, data) - - return await r.json() - } + try { + const r = await this.client.post(`/integrations/${name}/${data.webhookId}`, data); + return await r.json(); + } catch (e: any) { + if (e.response) { + const errorData = await e.response.json(); + return { errors: errorData.errors }; + } + return { errors: ['An unexpected error occurred.'] }; + } + }; removeMessengerInt = async (name: string, webhookId: string) => { - const r = await this.client.delete(`/integrations/${name}/${webhookId}`) + const r = await this.client.delete(`/integrations/${name}/${webhookId}`); - return await r.json() - } + return await r.json(); + }; sendMsg = async (integrationId, entity, entityId, name, data) => { - const r = await this.client.post(`/integrations/${name}/notify/${integrationId}/${entity}/${entityId}`, data) + const r = await this.client.post(`/integrations/${name}/notify/${integrationId}/${entity}/${entityId}`, data); - return await r.json() - } + return await r.json(); + }; testElastic = async (data: any) => { - const r = await this.client.post('/integrations/elasticsearch/test', data) + const r = await this.client.post('/integrations/elasticsearch/test', data); return r.json(); - } + }; }