diff --git a/x-pack/plugins/stack_connectors/public/connector_types/tines/tines_params.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/tines/tines_params.test.tsx index 495a15c6a569c..72bc2e3ae891f 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/tines/tines_params.test.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/tines/tines_params.test.tsx @@ -467,6 +467,50 @@ describe('TinesParamsFields renders', () => { webhookUrl ); }); + + it('should render webhook url fallback when stories request has error', () => { + const errorMessage = 'something broke'; + mockUseSubActionStories.mockReturnValueOnce({ + isLoading: false, + response: { stories: [story] }, + error: new Error(errorMessage), + }); + + const wrapper = mountWithIntl( + + ); + + expect(wrapper.find('[data-test-subj="tines-fallbackCallout"]').exists()).toBe(true); + expect(wrapper.find('[data-test-subj="tines-webhookUrlInput"]').exists()).toBe(true); + }); + + it('should render webhook url fallback when webhooks request has error', () => { + const errorMessage = 'something broke'; + mockUseSubActionWebhooks.mockReturnValueOnce({ + isLoading: false, + response: { webhooks: [webhook] }, + error: new Error(errorMessage), + }); + + const wrapper = mountWithIntl( + + ); + + expect(wrapper.find('[data-test-subj="tines-fallbackCallout"]').exists()).toBe(true); + expect(wrapper.find('[data-test-subj="tines-webhookUrlInput"]').exists()).toBe(true); + }); }); describe('subActions error', () => { diff --git a/x-pack/plugins/stack_connectors/public/connector_types/tines/tines_params.tsx b/x-pack/plugins/stack_connectors/public/connector_types/tines/tines_params.tsx index 11249f9c8db3c..2726e0e3ec8a5 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/tines/tines_params.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/tines/tines_params.tsx @@ -137,7 +137,10 @@ const TinesParamsFields: React.FunctionComponent(() => { + const showFallbackFrom = useMemo<'Story' | 'Webhook' | 'any' | 'error' | null>(() => { + if (storiesError || webhooksError) { + return 'error'; + } if (incompleteStories && !selectedStoryOption) { return 'Story'; } @@ -150,7 +153,9 @@ const TinesParamsFields: React.FunctionComponent - {showFallbackFrom !== 'any' && ( + {showFallbackFrom === 'error' && ( + <> + + {i18n.WEBHOOK_URL_ERROR_FALLBACK} + + + + )} + {(showFallbackFrom === 'Story' || showFallbackFrom === 'Webhook') && ( <> values: { entity, limit: API_MAX_RESULTS }, defaultMessage: `Not possible to retrieve more than {limit} results from the Tines {entity} API. If your {entity} does not appear in the list, please fill the Webhook URL below`, }); + +export const WEBHOOK_URL_ERROR_FALLBACK_TITLE = i18n.translate( + 'xpack.stackConnectors.security.tines.params.webhookUrlErrorFallbackTitle', + { + defaultMessage: 'Error using Tines API', + } +); +export const WEBHOOK_URL_ERROR_FALLBACK = i18n.translate( + 'xpack.stackConnectors.security.tines.params.webhookUrlErrorFallback', + { + defaultMessage: + 'There seems to be an issue retrieving Stories or Webhooks using the Tines API. Alternatively, you can set the Tines Webhook URL in the input below', + } +); export const WEBHOOK_URL_HELP = i18n.translate( 'xpack.stackConnectors.security.tines.params.webhookUrlHelp', { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts index 6bbaad9b86a0c..299ac1c55bfc5 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import axios, { AxiosInstance } from 'axios'; +import axios, { AxiosError, AxiosInstance, AxiosResponse } from 'axios'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; @@ -150,6 +150,28 @@ describe('TinesConnector', () => { }); }); + describe('Error handling', () => { + let error: AxiosError; + + beforeEach(() => { + error = new AxiosError(); + }); + + it('should return status text api error', () => { + error.response = { status: 401, statusText: 'Unauthorized' } as AxiosResponse; + // @ts-expect-error protected method + const errorMessage = connector.getResponseErrorMessage(error); + expect(errorMessage).toEqual('API Error: Unauthorized'); + }); + + it('should return original error', () => { + error.toString = () => 'Network Error'; + // @ts-expect-error protected method + const errorMessage = connector.getResponseErrorMessage(error); + expect(errorMessage).toEqual('Network Error'); + }); + }); + describe('getWebhooks', () => { beforeAll(() => { mockRequest.mockReturnValue({ data: { agents: [webhookAgent], meta: { pages: 1 } } }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.ts b/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.ts index ed98ec382af86..f7e3f4bea1444 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.ts @@ -126,13 +126,10 @@ export class TinesConnector extends SubActionConnector