From b4dfbdb67006d028c8fdbe0dfd2305273fa6df0d Mon Sep 17 00:00:00 2001 From: Tim Roes Date: Wed, 16 Nov 2022 13:25:43 +0100 Subject: [PATCH] Show an error when OAuth credentials are missing (#19466) --- .../src/hooks/services/useConnectorAuth.tsx | 64 ++++++++++++++----- airbyte-webapp/src/locales/en.json | 1 + 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/airbyte-webapp/src/hooks/services/useConnectorAuth.tsx b/airbyte-webapp/src/hooks/services/useConnectorAuth.tsx index a6be466a919..8e52c24b194 100644 --- a/airbyte-webapp/src/hooks/services/useConnectorAuth.tsx +++ b/airbyte-webapp/src/hooks/services/useConnectorAuth.tsx @@ -1,4 +1,5 @@ import { useCallback, useMemo, useRef } from "react"; +import { useIntl } from "react-intl"; import { useAsyncFn, useEffectOnce, useEvent } from "react-use"; import { useConfig } from "config"; @@ -7,10 +8,13 @@ import { DestinationAuthService } from "core/domain/connector/DestinationAuthSer import { isSourceDefinitionSpecification } from "core/domain/connector/source"; import { SourceAuthService } from "core/domain/connector/SourceAuthService"; import { DestinationOauthConsentRequest, SourceOauthConsentRequest } from "core/request/AirbyteClient"; +import { isCommonRequestError } from "core/request/CommonRequestError"; import { useConnectorForm } from "views/Connector/ConnectorForm/connectorFormContext"; import { useDefaultRequestMiddlewares } from "../../services/useDefaultRequestMiddlewares"; import { useQuery } from "../useQuery"; +import { useAppMonitoringService } from "./AppMonitoringService"; +import { useNotificationService } from "./Notification"; import { useCurrentWorkspace } from "./useWorkspace"; let windowObjectReference: Window | null = null; // global variable @@ -46,8 +50,11 @@ export function useConnectorAuth(): { queryParams: Record ) => Promise>; } { + const { formatMessage } = useIntl(); + const { trackError } = useAppMonitoringService(); const { workspaceId } = useCurrentWorkspace(); const { apiUrl, oauthRedirectUrl } = useConfig(); + const notificationService = useNotificationService(); const { connectorId } = useConnectorForm(); // TODO: move to separate initFacade and use refs instead @@ -70,28 +77,55 @@ export function useConnectorAuth(): { payload: SourceOauthConsentRequest | DestinationOauthConsentRequest; consentUrl: string; }> => { - if (isSourceDefinitionSpecification(connector)) { - const payload: SourceOauthConsentRequest = { + try { + if (isSourceDefinitionSpecification(connector)) { + const payload: SourceOauthConsentRequest = { + workspaceId, + sourceDefinitionId: ConnectorSpecification.id(connector), + redirectUrl: `${oauthRedirectUrl}/auth_flow`, + oAuthInputConfiguration, + sourceId: connectorId, + }; + const response = await sourceAuthService.getConsentUrl(payload); + + return { consentUrl: response.consentUrl, payload }; + } + const payload: DestinationOauthConsentRequest = { workspaceId, - sourceDefinitionId: ConnectorSpecification.id(connector), + destinationDefinitionId: ConnectorSpecification.id(connector), redirectUrl: `${oauthRedirectUrl}/auth_flow`, oAuthInputConfiguration, - sourceId: connectorId, + destinationId: connectorId, }; - const response = await sourceAuthService.getConsentUrl(payload); + const response = await destinationAuthService.getConsentUrl(payload); return { consentUrl: response.consentUrl, payload }; + } catch (e) { + // If this API returns a 404 the OAuth credentials have not been added to the database. + if (isCommonRequestError(e) && e.status === 404) { + if (process.env.NODE_ENV === "development") { + notificationService.registerNotification({ + id: "oauthConnector.credentialsMissing", + // Since it's dev only we don't need i18n on this string + title: "OAuth is not enabled for this connector on this environment.", + }); + } else { + // Log error to our monitoring, this should never happen and means OAuth credentials + // where missed + trackError(e, { + id: "oauthConnector.credentialsMissing", + connectorSpecId: ConnectorSpecification.id(connector), + workspaceId, + }); + notificationService.registerNotification({ + id: "oauthConnector.credentialsMissing", + title: formatMessage({ id: "connector.oauthCredentialsMissing" }), + isError: true, + }); + } + } + throw e; } - const payload: DestinationOauthConsentRequest = { - workspaceId, - destinationDefinitionId: ConnectorSpecification.id(connector), - redirectUrl: `${oauthRedirectUrl}/auth_flow`, - oAuthInputConfiguration, - destinationId: connectorId, - }; - const response = await destinationAuthService.getConsentUrl(payload); - - return { consentUrl: response.consentUrl, payload }; }, completeOauthRequest: async ( params: SourceOauthConsentRequest | DestinationOauthConsentRequest, diff --git a/airbyte-webapp/src/locales/en.json b/airbyte-webapp/src/locales/en.json index 084257867e2..24dc7d94f18 100644 --- a/airbyte-webapp/src/locales/en.json +++ b/airbyte-webapp/src/locales/en.json @@ -551,6 +551,7 @@ "connector.setupGuide": "Setup Guide", "connector.setupGuide.notFound": "No Setup Guide found for this connector.", "connector.exampleValues": "Example {count, plural, one {value} other {values}}", + "connector.oauthCredentialsMissing": "OAuth login is temporarily unavailable for this connector. Please try again later.", "credits.credits": "Credits", "credits.whatAreCredits": "What are credits?",