diff --git a/x-pack/plugins/cases/common/utils/index.ts b/x-pack/plugins/cases/common/utils/index.ts new file mode 100644 index 000000000000..072c2b10dc22 --- /dev/null +++ b/x-pack/plugins/cases/common/utils/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './connectors_api'; diff --git a/x-pack/plugins/cases/public/components/connectors/jira/api.test.ts b/x-pack/plugins/cases/public/components/connectors/jira/api.test.ts index af4883ab4ba9..593e5fa5497f 100644 --- a/x-pack/plugins/cases/public/components/connectors/jira/api.test.ts +++ b/x-pack/plugins/cases/public/components/connectors/jira/api.test.ts @@ -74,13 +74,33 @@ const fieldsResponse = { }, }; -const issueResponse = { +const issue = { id: '10267', key: 'RJ-107', - fields: { summary: 'Test title' }, + title: 'test title', }; -const issuesResponse = [issueResponse]; +const issueResponse = { + status: 'ok' as const, + connector_id: '1', + data: issue, +}; + +const issuesResponse = { + ...issueResponse, + data: [issue], +}; + +const camelCasedIssueResponse = { + status: 'ok' as const, + actionId: '1', + data: issue, +}; + +const camelCasedIssuesResponse = { + ...camelCasedIssueResponse, + data: [issue], +}; describe('Jira API', () => { const http = httpServiceMock.createStartContract(); @@ -131,7 +151,7 @@ describe('Jira API', () => { title: 'test issue', }); - expect(res).toEqual(issuesResponse); + expect(res).toEqual(camelCasedIssuesResponse); expect(http.post).toHaveBeenCalledWith('/api/actions/connector/test/_execute', { body: '{"params":{"subAction":"issues","subActionParams":{"title":"test issue"}}}', signal: abortCtrl.signal, @@ -142,7 +162,7 @@ describe('Jira API', () => { describe('getIssue', () => { test('should call get fields API', async () => { const abortCtrl = new AbortController(); - http.post.mockResolvedValueOnce(issuesResponse); + http.post.mockResolvedValueOnce(issueResponse); const res = await getIssue({ http, signal: abortCtrl.signal, @@ -150,7 +170,7 @@ describe('Jira API', () => { id: 'RJ-107', }); - expect(res).toEqual(issuesResponse); + expect(res).toEqual(camelCasedIssueResponse); expect(http.post).toHaveBeenCalledWith('/api/actions/connector/test/_execute', { body: '{"params":{"subAction":"issue","subActionParams":{"id":"RJ-107"}}}', signal: abortCtrl.signal, diff --git a/x-pack/plugins/cases/public/components/connectors/jira/api.ts b/x-pack/plugins/cases/public/components/connectors/jira/api.ts index 109d8a6794c5..b4bbec156f04 100644 --- a/x-pack/plugins/cases/public/components/connectors/jira/api.ts +++ b/x-pack/plugins/cases/public/components/connectors/jira/api.ts @@ -7,7 +7,11 @@ import { HttpSetup } from 'kibana/public'; import { ActionTypeExecutorResult } from '../../../../../actions/common'; -import { getExecuteConnectorUrl } from '../../../../common/utils/connectors_api'; +import { getExecuteConnectorUrl } from '../../../../common/utils'; +import { + ConnectorExecutorResult, + rewriteResponseToCamelCase, +} from '../rewrite_response_to_camel_case'; import { IssueTypes, Fields, Issues, Issue } from './types'; export interface GetIssueTypesProps { @@ -17,12 +21,17 @@ export interface GetIssueTypesProps { } export async function getIssueTypes({ http, signal, connectorId }: GetIssueTypesProps) { - return http.post>(getExecuteConnectorUrl(connectorId), { - body: JSON.stringify({ - params: { subAction: 'issueTypes', subActionParams: {} }, - }), - signal, - }); + const res = await http.post>( + getExecuteConnectorUrl(connectorId), + { + body: JSON.stringify({ + params: { subAction: 'issueTypes', subActionParams: {} }, + }), + signal, + } + ); + + return rewriteResponseToCamelCase(res); } export interface GetFieldsByIssueTypeProps { @@ -38,12 +47,16 @@ export async function getFieldsByIssueType({ connectorId, id, }: GetFieldsByIssueTypeProps): Promise> { - return http.post(getExecuteConnectorUrl(connectorId), { - body: JSON.stringify({ - params: { subAction: 'fieldsByIssueType', subActionParams: { id } }, - }), - signal, - }); + const res = await http.post>( + getExecuteConnectorUrl(connectorId), + { + body: JSON.stringify({ + params: { subAction: 'fieldsByIssueType', subActionParams: { id } }, + }), + signal, + } + ); + return rewriteResponseToCamelCase(res); } export interface GetIssuesTypeProps { @@ -59,12 +72,16 @@ export async function getIssues({ connectorId, title, }: GetIssuesTypeProps): Promise> { - return http.post(getExecuteConnectorUrl(connectorId), { - body: JSON.stringify({ - params: { subAction: 'issues', subActionParams: { title } }, - }), - signal, - }); + const res = await http.post>( + getExecuteConnectorUrl(connectorId), + { + body: JSON.stringify({ + params: { subAction: 'issues', subActionParams: { title } }, + }), + signal, + } + ); + return rewriteResponseToCamelCase(res); } export interface GetIssueTypeProps { @@ -80,10 +97,11 @@ export async function getIssue({ connectorId, id, }: GetIssueTypeProps): Promise> { - return http.post(getExecuteConnectorUrl(connectorId), { + const res = await http.post>(getExecuteConnectorUrl(connectorId), { body: JSON.stringify({ params: { subAction: 'issue', subActionParams: { id } }, }), signal, }); + return rewriteResponseToCamelCase(res); } diff --git a/x-pack/plugins/cases/public/components/connectors/jira/use_get_fields_by_issue_type.tsx b/x-pack/plugins/cases/public/components/connectors/jira/use_get_fields_by_issue_type.tsx index 686df1022a0d..d762c9d3aaf2 100644 --- a/x-pack/plugins/cases/public/components/connectors/jira/use_get_fields_by_issue_type.tsx +++ b/x-pack/plugins/cases/public/components/connectors/jira/use_get_fields_by_issue_type.tsx @@ -6,7 +6,7 @@ */ import { useState, useEffect, useRef } from 'react'; -import { HttpSetup, ToastsApi } from 'kibana/public'; +import { HttpSetup, IToasts } from 'kibana/public'; import { ActionConnector } from '../../../../common'; import { getFieldsByIssueType } from './api'; import { Fields } from './types'; @@ -14,10 +14,7 @@ import * as i18n from './translations'; interface Props { http: HttpSetup; - toastNotifications: Pick< - ToastsApi, - 'get$' | 'add' | 'remove' | 'addSuccess' | 'addWarning' | 'addDanger' | 'addError' - >; + toastNotifications: IToasts; issueType: string | null; connector?: ActionConnector; } diff --git a/x-pack/plugins/cases/public/components/connectors/jira/use_get_issue_types.tsx b/x-pack/plugins/cases/public/components/connectors/jira/use_get_issue_types.tsx index 0d7073f3bf2d..6f409f1ddef8 100644 --- a/x-pack/plugins/cases/public/components/connectors/jira/use_get_issue_types.tsx +++ b/x-pack/plugins/cases/public/components/connectors/jira/use_get_issue_types.tsx @@ -6,7 +6,7 @@ */ import { useState, useEffect, useRef } from 'react'; -import { HttpSetup, ToastsApi } from 'kibana/public'; +import { HttpSetup, IToasts } from 'kibana/public'; import { ActionConnector } from '../../../../common'; import { getIssueTypes } from './api'; import { IssueTypes } from './types'; @@ -14,10 +14,7 @@ import * as i18n from './translations'; interface Props { http: HttpSetup; - toastNotifications: Pick< - ToastsApi, - 'get$' | 'add' | 'remove' | 'addSuccess' | 'addWarning' | 'addDanger' | 'addError' - >; + toastNotifications: IToasts; connector?: ActionConnector; handleIssueType: (options: Array<{ value: string; text: string }>) => void; } diff --git a/x-pack/plugins/cases/public/components/connectors/resilient/api.ts b/x-pack/plugins/cases/public/components/connectors/resilient/api.ts index 301d29866d30..6d803b6fbe54 100644 --- a/x-pack/plugins/cases/public/components/connectors/resilient/api.ts +++ b/x-pack/plugins/cases/public/components/connectors/resilient/api.ts @@ -6,8 +6,11 @@ */ import { HttpSetup } from 'kibana/public'; -import { ActionTypeExecutorResult } from '../../../../../actions/common'; import { getExecuteConnectorUrl } from '../../../../common/utils/connectors_api'; +import { + ConnectorExecutorResult, + rewriteResponseToCamelCase, +} from '../rewrite_response_to_camel_case'; import { ResilientIncidentTypes, ResilientSeverity } from './types'; export const BASE_ACTION_API_PATH = '/api/actions'; @@ -19,7 +22,7 @@ export interface Props { } export async function getIncidentTypes({ http, signal, connectorId }: Props) { - return http.post>( + const res = await http.post>( getExecuteConnectorUrl(connectorId), { body: JSON.stringify({ @@ -28,10 +31,12 @@ export async function getIncidentTypes({ http, signal, connectorId }: Props) { signal, } ); + + return rewriteResponseToCamelCase(res); } export async function getSeverity({ http, signal, connectorId }: Props) { - return http.post>( + const res = await http.post>( getExecuteConnectorUrl(connectorId), { body: JSON.stringify({ @@ -40,4 +45,6 @@ export async function getSeverity({ http, signal, connectorId }: Props) { signal, } ); + + return rewriteResponseToCamelCase(res); } diff --git a/x-pack/plugins/cases/public/components/connectors/rewrite_response_to_camel_case.test.ts b/x-pack/plugins/cases/public/components/connectors/rewrite_response_to_camel_case.test.ts new file mode 100644 index 000000000000..28f901076759 --- /dev/null +++ b/x-pack/plugins/cases/public/components/connectors/rewrite_response_to_camel_case.test.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + ConnectorExecutorResult, + rewriteResponseToCamelCase, +} from './rewrite_response_to_camel_case'; + +const responseWithSnakeCasedFields: ConnectorExecutorResult<{}> = { + service_message: 'oh noooooo', + connector_id: '1213', + data: {}, + status: 'ok', +}; + +describe('rewriteResponseToCamelCase works correctly', () => { + it('correctly transforms snake case to camel case for ActionTypeExecuteResults', () => { + const camelCasedData = rewriteResponseToCamelCase(responseWithSnakeCasedFields); + + expect(camelCasedData).toEqual({ + serviceMessage: 'oh noooooo', + actionId: '1213', + data: {}, + status: 'ok', + }); + }); +}); diff --git a/x-pack/plugins/cases/public/components/connectors/rewrite_response_to_camel_case.ts b/x-pack/plugins/cases/public/components/connectors/rewrite_response_to_camel_case.ts new file mode 100644 index 000000000000..e73488257d9d --- /dev/null +++ b/x-pack/plugins/cases/public/components/connectors/rewrite_response_to_camel_case.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ActionTypeExecutorResult, RewriteResponseCase } from '../../../../actions/common'; + +export type ConnectorExecutorResult = ReturnType< + RewriteResponseCase> +>; + +export const rewriteResponseToCamelCase = ({ + connector_id: actionId, + service_message: serviceMessage, + ...data +}: ConnectorExecutorResult): ActionTypeExecutorResult => ({ + ...data, + actionId, + ...(serviceMessage && { serviceMessage }), +}); diff --git a/x-pack/plugins/cases/public/components/connectors/servicenow/api.ts b/x-pack/plugins/cases/public/components/connectors/servicenow/api.ts index 3d9211caa9b9..de3ea1f16c35 100644 --- a/x-pack/plugins/cases/public/components/connectors/servicenow/api.ts +++ b/x-pack/plugins/cases/public/components/connectors/servicenow/api.ts @@ -6,8 +6,11 @@ */ import { HttpSetup } from 'kibana/public'; -import { ActionTypeExecutorResult } from '../../../../../actions/common'; import { getExecuteConnectorUrl } from '../../../../common/utils/connectors_api'; +import { + ConnectorExecutorResult, + rewriteResponseToCamelCase, +} from '../rewrite_response_to_camel_case'; import { Choice } from './types'; export const BASE_ACTION_API_PATH = '/api/actions'; @@ -20,10 +23,14 @@ export interface GetChoicesProps { } export async function getChoices({ http, signal, connectorId, fields }: GetChoicesProps) { - return http.post>(getExecuteConnectorUrl(connectorId), { - body: JSON.stringify({ - params: { subAction: 'getChoices', subActionParams: { fields } }, - }), - signal, - }); + const res = await http.post>( + getExecuteConnectorUrl(connectorId), + { + body: JSON.stringify({ + params: { subAction: 'getChoices', subActionParams: { fields } }, + }), + signal, + } + ); + return rewriteResponseToCamelCase(res); } diff --git a/x-pack/plugins/cases/public/components/connectors/servicenow/use_get_choices.tsx b/x-pack/plugins/cases/public/components/connectors/servicenow/use_get_choices.tsx index 4edf740a6001..2c6181dd08eb 100644 --- a/x-pack/plugins/cases/public/components/connectors/servicenow/use_get_choices.tsx +++ b/x-pack/plugins/cases/public/components/connectors/servicenow/use_get_choices.tsx @@ -6,7 +6,7 @@ */ import { useState, useEffect, useRef } from 'react'; -import { HttpSetup, ToastsApi } from 'kibana/public'; +import { HttpSetup, IToasts } from 'kibana/public'; import { ActionConnector } from '../../../../common'; import { getChoices } from './api'; import { Choice } from './types'; @@ -14,10 +14,7 @@ import * as i18n from './translations'; export interface UseGetChoicesProps { http: HttpSetup; - toastNotifications: Pick< - ToastsApi, - 'get$' | 'add' | 'remove' | 'addSuccess' | 'addWarning' | 'addDanger' | 'addError' - >; + toastNotifications: IToasts; connector?: ActionConnector; fields: string[]; onSuccess?: (choices: Choice[]) => void; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/api.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/api.test.ts index 38d65b923b37..91b4f1e343bc 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/api.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/api.test.ts @@ -8,87 +8,96 @@ import { httpServiceMock } from '../../../../../../../../src/core/public/mocks'; import { getIssueTypes, getFieldsByIssueType, getIssues, getIssue } from './api'; -const issueTypesResponse = { - status: 'ok', - data: { - projects: [ - { - issuetypes: [ - { - id: '10006', - name: 'Task', - }, - { - id: '10007', - name: 'Bug', - }, - ], - }, - ], - }, - actionId: 'test', +const issueTypesData = { + projects: [ + { + issuetypes: [ + { + id: '10006', + name: 'Task', + }, + { + id: '10007', + name: 'Bug', + }, + ], + }, + ], }; -const fieldsResponse = { - status: 'ok', - data: { - projects: [ - { - issuetypes: [ - { - id: '10006', - name: 'Task', - fields: { - summary: { fieldId: 'summary' }, - priority: { - fieldId: 'priority', - allowedValues: [ - { - name: 'Highest', - id: '1', - }, - { - name: 'High', - id: '2', - }, - { - name: 'Medium', - id: '3', - }, - { - name: 'Low', - id: '4', - }, - { - name: 'Lowest', - id: '5', - }, - ], - defaultValue: { +const fieldData = { + projects: [ + { + issuetypes: [ + { + id: '10006', + name: 'Task', + fields: { + summary: { fieldId: 'summary' }, + priority: { + fieldId: 'priority', + allowedValues: [ + { + name: 'Highest', + id: '1', + }, + { + name: 'High', + id: '2', + }, + { name: 'Medium', id: '3', }, + { + name: 'Low', + id: '4', + }, + { + name: 'Lowest', + id: '5', + }, + ], + defaultValue: { + name: 'Medium', + id: '3', }, }, }, - ], - }, - ], - actionId: 'test', - }, + }, + ], + }, + ], +}; + +const issueTypesResponse = { + status: 'ok' as const, + connector_id: 'test', + data: issueTypesData, +}; + +const fieldsResponse = { + status: 'ok' as const, + data: fieldData, + connector_id: 'test', +}; + +const singleIssue = { + id: '10267', + key: 'RJ-107', + title: 'some title', }; const issueResponse = { - status: 'ok', - data: { - id: '10267', - key: 'RJ-107', - fields: { summary: 'Test title' }, - }, - actionId: 'test', + status: 'ok' as const, + data: singleIssue, + connector_id: 'test', }; -const issuesResponse = [issueResponse]; +const issuesResponse = { + ...issueResponse, + data: [singleIssue], +}; describe('Jira API', () => { const http = httpServiceMock.createStartContract(); @@ -100,8 +109,11 @@ describe('Jira API', () => { const abortCtrl = new AbortController(); http.post.mockResolvedValueOnce(issueTypesResponse); const res = await getIssueTypes({ http, signal: abortCtrl.signal, connectorId: 'te/st' }); - - expect(res).toEqual(issueTypesResponse); + expect(res).toEqual({ + status: 'ok' as const, + actionId: 'test', + data: issueTypesData, + }); expect(http.post).toHaveBeenCalledWith('/api/actions/connector/te%2Fst/_execute', { body: '{"params":{"subAction":"issueTypes","subActionParams":{}}}', signal: abortCtrl.signal, @@ -120,7 +132,7 @@ describe('Jira API', () => { id: '10006', }); - expect(res).toEqual(fieldsResponse); + expect(res).toEqual({ status: 'ok', data: fieldData, actionId: 'test' }); expect(http.post).toHaveBeenCalledWith('/api/actions/connector/te%2Fst/_execute', { body: '{"params":{"subAction":"fieldsByIssueType","subActionParams":{"id":"10006"}}}', signal: abortCtrl.signal, @@ -139,7 +151,11 @@ describe('Jira API', () => { title: 'test issue', }); - expect(res).toEqual(issuesResponse); + expect(res).toEqual({ + status: 'ok', + data: [singleIssue], + actionId: 'test', + }); expect(http.post).toHaveBeenCalledWith('/api/actions/connector/te%2Fst/_execute', { body: '{"params":{"subAction":"issues","subActionParams":{"title":"test issue"}}}', signal: abortCtrl.signal, @@ -150,7 +166,7 @@ describe('Jira API', () => { describe('getIssue', () => { test('should call get fields API', async () => { const abortCtrl = new AbortController(); - http.post.mockResolvedValueOnce(issuesResponse); + http.post.mockResolvedValueOnce(issueResponse); const res = await getIssue({ http, signal: abortCtrl.signal, @@ -158,7 +174,11 @@ describe('Jira API', () => { id: 'RJ-107', }); - expect(res).toEqual(issuesResponse); + expect(res).toEqual({ + status: 'ok', + data: singleIssue, + actionId: 'test', + }); expect(http.post).toHaveBeenCalledWith('/api/actions/connector/te%2Fst/_execute', { body: '{"params":{"subAction":"issue","subActionParams":{"id":"RJ-107"}}}', signal: abortCtrl.signal, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/api.ts b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/api.ts index 83e126ea9d2f..e9cc583ee44a 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/api.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/api.ts @@ -6,7 +6,10 @@ */ import { HttpSetup } from 'kibana/public'; +import { ActionTypeExecutorResult } from '../../../../../../actions/common'; import { BASE_ACTION_API_PATH } from '../../../constants'; +import { ConnectorExecutorResult, rewriteResponseToCamelCase } from '../rewrite_response_body'; +import { Fields, Issue, IssueTypes } from './types'; export async function getIssueTypes({ http, @@ -16,8 +19,8 @@ export async function getIssueTypes({ http: HttpSetup; signal: AbortSignal; connectorId: string; -}): Promise> { - return await http.post( +}): Promise> { + const res = await http.post>( `${BASE_ACTION_API_PATH}/connector/${encodeURIComponent(connectorId)}/_execute`, { body: JSON.stringify({ @@ -26,6 +29,7 @@ export async function getIssueTypes({ signal, } ); + return rewriteResponseToCamelCase(res); } export async function getFieldsByIssueType({ @@ -38,8 +42,8 @@ export async function getFieldsByIssueType({ signal: AbortSignal; connectorId: string; id: string; -}): Promise> { - return await http.post( +}): Promise> { + const res = await http.post>( `${BASE_ACTION_API_PATH}/connector/${encodeURIComponent(connectorId)}/_execute`, { body: JSON.stringify({ @@ -48,6 +52,7 @@ export async function getFieldsByIssueType({ signal, } ); + return rewriteResponseToCamelCase(res); } export async function getIssues({ @@ -60,8 +65,8 @@ export async function getIssues({ signal: AbortSignal; connectorId: string; title: string; -}): Promise> { - return await http.post( +}): Promise> { + const res = await http.post>( `${BASE_ACTION_API_PATH}/connector/${encodeURIComponent(connectorId)}/_execute`, { body: JSON.stringify({ @@ -70,6 +75,7 @@ export async function getIssues({ signal, } ); + return rewriteResponseToCamelCase(res); } export async function getIssue({ @@ -82,8 +88,8 @@ export async function getIssue({ signal: AbortSignal; connectorId: string; id: string; -}): Promise> { - return await http.post( +}): Promise> { + const res = await http.post>( `${BASE_ACTION_API_PATH}/connector/${encodeURIComponent(connectorId)}/_execute`, { body: JSON.stringify({ @@ -92,4 +98,5 @@ export async function getIssue({ signal, } ); + return rewriteResponseToCamelCase(res); } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/search_issues.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/search_issues.tsx index 1090414104c2..38aed2cfc6f8 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/search_issues.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/search_issues.tsx @@ -8,7 +8,7 @@ import React, { useMemo, useEffect, useCallback, useState, memo } from 'react'; import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui'; -import { HttpSetup, ToastsApi } from 'kibana/public'; +import { HttpSetup, IToasts } from 'kibana/public'; import { ActionConnector } from '../../../../types'; import { useGetIssues } from './use_get_issues'; import { useGetSingleIssue } from './use_get_single_issue'; @@ -17,10 +17,7 @@ import * as i18n from './translations'; interface Props { selectedValue?: string | null; http: HttpSetup; - toastNotifications: Pick< - ToastsApi, - 'get$' | 'add' | 'remove' | 'addSuccess' | 'addWarning' | 'addDanger' | 'addError' - >; + toastNotifications: IToasts; actionConnector?: ActionConnector; onChange: (parentIssueKey: string) => void; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/types.ts b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/types.ts index 01165147a7c0..6073971912ac 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/types.ts @@ -24,3 +24,18 @@ export interface JiraSecrets { email: string; apiToken: string; } + +export type IssueTypes = Array<{ id: string; name: string }>; + +export interface Issue { + id: string; + key: string; + title: string; +} + +export interface Fields { + [key: string]: { + allowedValues: Array<{ name: string; id: string }> | []; + defaultValue: { name: string; id: string } | {}; + }; +} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/use_get_fields_by_issue_type.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/use_get_fields_by_issue_type.tsx index 61db73c129db..71dafef4dca2 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/use_get_fields_by_issue_type.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/use_get_fields_by_issue_type.tsx @@ -6,24 +6,15 @@ */ import { useState, useEffect, useRef } from 'react'; -import { HttpSetup, ToastsApi } from 'kibana/public'; +import { HttpSetup, IToasts } from 'kibana/public'; import { ActionConnector } from '../../../../types'; +import { Fields } from './types'; import { getFieldsByIssueType } from './api'; import * as i18n from './translations'; -interface Fields { - [key: string]: { - allowedValues: Array<{ name: string; id: string }> | []; - defaultValue: { name: string; id: string } | {}; - }; -} - interface Props { http: HttpSetup; - toastNotifications: Pick< - ToastsApi, - 'get$' | 'add' | 'remove' | 'addSuccess' | 'addWarning' | 'addDanger' | 'addError' - >; + toastNotifications: IToasts; issueType: string | undefined; actionConnector?: ActionConnector; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/use_get_issue_types.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/use_get_issue_types.tsx index 11430c4c372d..09ed90b296d0 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/use_get_issue_types.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/use_get_issue_types.tsx @@ -6,19 +6,16 @@ */ import { useState, useEffect, useRef } from 'react'; -import { HttpSetup, ToastsApi } from 'kibana/public'; +import { HttpSetup, IToasts } from 'kibana/public'; + import { ActionConnector } from '../../../../types'; +import { IssueTypes } from './types'; import { getIssueTypes } from './api'; import * as i18n from './translations'; -type IssueTypes = Array<{ id: string; name: string }>; - interface Props { http: HttpSetup; - toastNotifications: Pick< - ToastsApi, - 'get$' | 'add' | 'remove' | 'addSuccess' | 'addWarning' | 'addDanger' | 'addError' - >; + toastNotifications: IToasts; actionConnector?: ActionConnector; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/use_get_issues.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/use_get_issues.tsx index e0423304325a..3ad67709f82f 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/use_get_issues.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/use_get_issues.tsx @@ -7,25 +7,21 @@ import { isEmpty, debounce } from 'lodash/fp'; import { useState, useEffect, useRef } from 'react'; -import { HttpSetup, ToastsApi } from 'kibana/public'; +import { HttpSetup, IToasts } from 'kibana/public'; import { ActionConnector } from '../../../../types'; +import { Issue } from './types'; import { getIssues } from './api'; import * as i18n from './translations'; -type Issues = Array<{ id: string; key: string; title: string }>; - interface Props { http: HttpSetup; - toastNotifications: Pick< - ToastsApi, - 'get$' | 'add' | 'remove' | 'addSuccess' | 'addWarning' | 'addDanger' | 'addError' - >; + toastNotifications: IToasts; actionConnector?: ActionConnector; query: string | null; } export interface UseGetIssues { - issues: Issues; + issues: Issue[]; isLoading: boolean; } @@ -36,7 +32,7 @@ export const useGetIssues = ({ query, }: Props): UseGetIssues => { const [isLoading, setIsLoading] = useState(false); - const [issues, setIssues] = useState([]); + const [issues, setIssues] = useState([]); const abortCtrl = useRef(new AbortController()); useEffect(() => { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/use_get_single_issue.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/use_get_single_issue.tsx index e0099e24f2c5..62ddb8b6e362 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/use_get_single_issue.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/use_get_single_issue.tsx @@ -6,23 +6,15 @@ */ import { useState, useEffect, useRef } from 'react'; -import { HttpSetup, ToastsApi } from 'kibana/public'; +import { HttpSetup, IToasts } from 'kibana/public'; import { ActionConnector } from '../../../../types'; +import { Issue } from './types'; import { getIssue } from './api'; import * as i18n from './translations'; -interface Issue { - id: string; - key: string; - title: string; -} - interface Props { http: HttpSetup; - toastNotifications: Pick< - ToastsApi, - 'get$' | 'add' | 'remove' | 'addSuccess' | 'addWarning' | 'addDanger' | 'addError' - >; + toastNotifications: IToasts; id?: string | null; actionConnector?: ActionConnector; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/api.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/api.test.ts index 0d4bf9148a92..a345a9c81beb 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/api.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/api.test.ts @@ -32,7 +32,6 @@ const incidentTypesResponse = { { id: 16, name: 'TBD / Unknown' }, { id: 15, name: 'Vendor / 3rd party error' }, ], - actionId: 'te/st', }; const severityResponse = { @@ -42,7 +41,6 @@ const severityResponse = { { id: 5, name: 'Medium' }, { id: 6, name: 'High' }, ], - actionId: 'te/st', }; describe('Resilient API', () => { @@ -53,14 +51,14 @@ describe('Resilient API', () => { describe('getIncidentTypes', () => { test('should call get choices API', async () => { const abortCtrl = new AbortController(); - http.post.mockResolvedValueOnce(incidentTypesResponse); + http.post.mockResolvedValueOnce({ ...incidentTypesResponse, connector_id: 'te/st' }); const res = await getIncidentTypes({ http, signal: abortCtrl.signal, connectorId: 'te/st', }); - expect(res).toEqual(incidentTypesResponse); + expect(res).toEqual({ ...incidentTypesResponse, actionId: 'te/st' }); expect(http.post).toHaveBeenCalledWith('/api/actions/connector/te%2Fst/_execute', { body: '{"params":{"subAction":"incidentTypes","subActionParams":{}}}', signal: abortCtrl.signal, @@ -71,14 +69,15 @@ describe('Resilient API', () => { describe('getSeverity', () => { test('should call get choices API', async () => { const abortCtrl = new AbortController(); - http.post.mockResolvedValueOnce(severityResponse); + http.post.mockResolvedValueOnce({ ...severityResponse, connector_id: 'te/st' }); const res = await getSeverity({ http, signal: abortCtrl.signal, connectorId: 'te/st', }); - expect(res).toEqual(severityResponse); + expect(res).toEqual({ ...severityResponse, actionId: 'te/st' }); + expect(http.post).toHaveBeenCalledWith('/api/actions/connector/te%2Fst/_execute', { body: '{"params":{"subAction":"severity","subActionParams":{}}}', signal: abortCtrl.signal, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/api.ts b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/api.ts index 6bd9c43105cf..e3a46c5a875c 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/api.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/resilient/api.ts @@ -7,6 +7,7 @@ import { HttpSetup } from 'kibana/public'; import { BASE_ACTION_API_PATH } from '../../../constants'; +import { rewriteResponseToCamelCase } from '../rewrite_response_body'; export async function getIncidentTypes({ http, @@ -17,7 +18,7 @@ export async function getIncidentTypes({ signal: AbortSignal; connectorId: string; }): Promise> { - return await http.post( + const res = await http.post( `${BASE_ACTION_API_PATH}/connector/${encodeURIComponent(connectorId)}/_execute`, { body: JSON.stringify({ @@ -26,6 +27,7 @@ export async function getIncidentTypes({ signal, } ); + return rewriteResponseToCamelCase(res); } export async function getSeverity({ @@ -37,7 +39,7 @@ export async function getSeverity({ signal: AbortSignal; connectorId: string; }): Promise> { - return await http.post( + const res = await http.post( `${BASE_ACTION_API_PATH}/connector/${encodeURIComponent(connectorId)}/_execute`, { body: JSON.stringify({ @@ -46,4 +48,5 @@ export async function getSeverity({ signal, } ); + return rewriteResponseToCamelCase(res); } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/rewrite_response_body.ts b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/rewrite_response_body.ts new file mode 100644 index 000000000000..d9bf48c4ab85 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/rewrite_response_body.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ActionTypeExecutorResult, RewriteResponseCase } from '../../../../../actions/common'; + +export type ConnectorExecutorResult = ReturnType< + RewriteResponseCase> +>; + +export const rewriteResponseToCamelCase = ({ + connector_id: actionId, + service_message: serviceMessage, + ...data +}: ConnectorExecutorResult): ActionTypeExecutorResult => ({ + ...data, + actionId, + ...(serviceMessage && { serviceMessage }), +}); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/api.ts b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/api.ts index 32a2d0296d4c..13cd3e531316 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/api.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/api.ts @@ -6,11 +6,15 @@ */ import { HttpSetup } from 'kibana/public'; + // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { snExternalServiceConfig } from '../../../../../../actions/server/builtin_action_types/servicenow/config'; import { BASE_ACTION_API_PATH } from '../../../constants'; import { API_INFO_ERROR } from './translations'; import { AppInfo, RESTApiError } from './types'; +import { ConnectorExecutorResult, rewriteResponseToCamelCase } from '../rewrite_response_body'; +import { ActionTypeExecutorResult } from '../../../../../../actions/common'; +import { Choice } from './types'; export async function getChoices({ http, @@ -22,8 +26,8 @@ export async function getChoices({ signal: AbortSignal; connectorId: string; fields: string[]; -}): Promise> { - return await http.post( +}): Promise> { + const res = await http.post>( `${BASE_ACTION_API_PATH}/connector/${encodeURIComponent(connectorId)}/_execute`, { body: JSON.stringify({ @@ -32,6 +36,7 @@ export async function getChoices({ signal, } ); + return rewriteResponseToCamelCase(res); } /** diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/use_choices.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/use_choices.test.tsx index 48c0fb2109f5..175a80c63d4b 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/use_choices.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/use_choices.test.tsx @@ -122,7 +122,7 @@ describe('UseChoices', () => { it('it displays an error when service fails', async () => { getChoicesMock.mockResolvedValue({ status: 'error', - service_message: 'An error occurred', + serviceMessage: 'An error occurred', }); const { waitForNextUpdate } = renderHook(() => diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/use_choices.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/use_choices.tsx index 5493fdaee8bf..bfad678f9b24 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/use_choices.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/use_choices.tsx @@ -6,7 +6,7 @@ */ import { useCallback, useMemo, useState } from 'react'; -import { HttpSetup, ToastsApi } from 'kibana/public'; +import { HttpSetup, IToasts } from 'kibana/public'; import { ActionConnector } from '../../../../types'; import { Choice, Fields } from './types'; @@ -14,10 +14,7 @@ import { useGetChoices } from './use_get_choices'; export interface UseChoicesProps { http: HttpSetup; - toastNotifications: Pick< - ToastsApi, - 'get$' | 'add' | 'remove' | 'addSuccess' | 'addWarning' | 'addDanger' | 'addError' - >; + toastNotifications: IToasts; actionConnector?: ActionConnector; fields: string[]; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/use_get_choices.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/use_get_choices.test.tsx index 532789385e8b..ecbc9512a4d3 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/use_get_choices.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/use_get_choices.test.tsx @@ -121,7 +121,7 @@ describe('useGetChoices', () => { it('it displays an error when service fails', async () => { getChoicesMock.mockResolvedValue({ status: 'error', - service_message: 'An error occurred', + serviceMessage: 'An error occurred', }); const { waitForNextUpdate } = renderHook(() => diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/use_get_choices.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/use_get_choices.tsx index f4c881c633cd..b115c84562ae 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/use_get_choices.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/use_get_choices.tsx @@ -6,7 +6,7 @@ */ import { useState, useEffect, useRef, useCallback } from 'react'; -import { HttpSetup, ToastsApi } from 'kibana/public'; +import { HttpSetup, IToasts } from 'kibana/public'; import { ActionConnector } from '../../../../types'; import { getChoices } from './api'; import { Choice } from './types'; @@ -14,10 +14,7 @@ import * as i18n from './translations'; export interface UseGetChoicesProps { http: HttpSetup; - toastNotifications: Pick< - ToastsApi, - 'get$' | 'add' | 'remove' | 'addSuccess' | 'addWarning' | 'addDanger' | 'addError' - >; + toastNotifications: IToasts; actionConnector?: ActionConnector; fields: string[]; onSuccess?: (choices: Choice[]) => void; @@ -66,7 +63,7 @@ export const useGetChoices = ({ if (res.status && res.status === 'error') { toastNotifications.addDanger({ title: i18n.CHOICES_API_ERROR, - text: `${res.service_message ?? res.message}`, + text: `${res.serviceMessage ?? res.message}`, }); } else if (onSuccess) { onSuccess(data);