mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
* [105264] Fix error not surfacing bug for Jira * [105264] Fix ServiceNow errors not surfacing to UI * Fix tests with updated functon * Fix PR errors Co-authored-by: Kristof-Pierre Cummings <kristofpierre.cummings@elastic.co> Co-authored-by: Kristof C <kpac.ja@gmail.com> Co-authored-by: Kristof-Pierre Cummings <kristofpierre.cummings@elastic.co>
This commit is contained in:
parent
9fc68bb1b6
commit
468bc21f95
26 changed files with 342 additions and 200 deletions
8
x-pack/plugins/cases/common/utils/index.ts
Normal file
8
x-pack/plugins/cases/common/utils/index.ts
Normal file
|
@ -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';
|
|
@ -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,
|
||||
|
|
|
@ -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<ActionTypeExecutorResult<IssueTypes>>(getExecuteConnectorUrl(connectorId), {
|
||||
body: JSON.stringify({
|
||||
params: { subAction: 'issueTypes', subActionParams: {} },
|
||||
}),
|
||||
signal,
|
||||
});
|
||||
const res = await http.post<ConnectorExecutorResult<IssueTypes>>(
|
||||
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<ActionTypeExecutorResult<Fields>> {
|
||||
return http.post(getExecuteConnectorUrl(connectorId), {
|
||||
body: JSON.stringify({
|
||||
params: { subAction: 'fieldsByIssueType', subActionParams: { id } },
|
||||
}),
|
||||
signal,
|
||||
});
|
||||
const res = await http.post<ConnectorExecutorResult<Fields>>(
|
||||
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<ActionTypeExecutorResult<Issues>> {
|
||||
return http.post(getExecuteConnectorUrl(connectorId), {
|
||||
body: JSON.stringify({
|
||||
params: { subAction: 'issues', subActionParams: { title } },
|
||||
}),
|
||||
signal,
|
||||
});
|
||||
const res = await http.post<ConnectorExecutorResult<Issues>>(
|
||||
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<ActionTypeExecutorResult<Issue>> {
|
||||
return http.post(getExecuteConnectorUrl(connectorId), {
|
||||
const res = await http.post<ConnectorExecutorResult<Issue>>(getExecuteConnectorUrl(connectorId), {
|
||||
body: JSON.stringify({
|
||||
params: { subAction: 'issue', subActionParams: { id } },
|
||||
}),
|
||||
signal,
|
||||
});
|
||||
return rewriteResponseToCamelCase(res);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<ActionTypeExecutorResult<ResilientIncidentTypes>>(
|
||||
const res = await http.post<ConnectorExecutorResult<ResilientIncidentTypes>>(
|
||||
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<ActionTypeExecutorResult<ResilientSeverity>>(
|
||||
const res = await http.post<ConnectorExecutorResult<ResilientSeverity>>(
|
||||
getExecuteConnectorUrl(connectorId),
|
||||
{
|
||||
body: JSON.stringify({
|
||||
|
@ -40,4 +45,6 @@ export async function getSeverity({ http, signal, connectorId }: Props) {
|
|||
signal,
|
||||
}
|
||||
);
|
||||
|
||||
return rewriteResponseToCamelCase(res);
|
||||
}
|
||||
|
|
|
@ -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',
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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<T> = ReturnType<
|
||||
RewriteResponseCase<ActionTypeExecutorResult<T>>
|
||||
>;
|
||||
|
||||
export const rewriteResponseToCamelCase = <T>({
|
||||
connector_id: actionId,
|
||||
service_message: serviceMessage,
|
||||
...data
|
||||
}: ConnectorExecutorResult<T>): ActionTypeExecutorResult<T> => ({
|
||||
...data,
|
||||
actionId,
|
||||
...(serviceMessage && { serviceMessage }),
|
||||
});
|
|
@ -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<ActionTypeExecutorResult<Choice[]>>(getExecuteConnectorUrl(connectorId), {
|
||||
body: JSON.stringify({
|
||||
params: { subAction: 'getChoices', subActionParams: { fields } },
|
||||
}),
|
||||
signal,
|
||||
});
|
||||
const res = await http.post<ConnectorExecutorResult<Choice[]>>(
|
||||
getExecuteConnectorUrl(connectorId),
|
||||
{
|
||||
body: JSON.stringify({
|
||||
params: { subAction: 'getChoices', subActionParams: { fields } },
|
||||
}),
|
||||
signal,
|
||||
}
|
||||
);
|
||||
return rewriteResponseToCamelCase(res);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<Record<string, any>> {
|
||||
return await http.post(
|
||||
}): Promise<ActionTypeExecutorResult<IssueTypes>> {
|
||||
const res = await http.post<ConnectorExecutorResult<IssueTypes>>(
|
||||
`${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<Record<string, any>> {
|
||||
return await http.post(
|
||||
}): Promise<ActionTypeExecutorResult<Fields>> {
|
||||
const res = await http.post<ConnectorExecutorResult<Fields>>(
|
||||
`${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<Record<string, any>> {
|
||||
return await http.post(
|
||||
}): Promise<ActionTypeExecutorResult<Issue[]>> {
|
||||
const res = await http.post<ConnectorExecutorResult<Issue[]>>(
|
||||
`${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<Record<string, any>> {
|
||||
return await http.post(
|
||||
}): Promise<ActionTypeExecutorResult<Issue>> {
|
||||
const res = await http.post<ConnectorExecutorResult<Issue>>(
|
||||
`${BASE_ACTION_API_PATH}/connector/${encodeURIComponent(connectorId)}/_execute`,
|
||||
{
|
||||
body: JSON.stringify({
|
||||
|
@ -92,4 +98,5 @@ export async function getIssue({
|
|||
signal,
|
||||
}
|
||||
);
|
||||
return rewriteResponseToCamelCase(res);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 } | {};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<Issues>([]);
|
||||
const [issues, setIssues] = useState<Issue[]>([]);
|
||||
const abortCtrl = useRef(new AbortController());
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<Record<string, any>> {
|
||||
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<Record<string, any>> {
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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<T> = ReturnType<
|
||||
RewriteResponseCase<ActionTypeExecutorResult<T>>
|
||||
>;
|
||||
|
||||
export const rewriteResponseToCamelCase = <T>({
|
||||
connector_id: actionId,
|
||||
service_message: serviceMessage,
|
||||
...data
|
||||
}: ConnectorExecutorResult<T>): ActionTypeExecutorResult<T> => ({
|
||||
...data,
|
||||
actionId,
|
||||
...(serviceMessage && { serviceMessage }),
|
||||
});
|
|
@ -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<Record<string, any>> {
|
||||
return await http.post(
|
||||
}): Promise<ActionTypeExecutorResult<Choice[]>> {
|
||||
const res = await http.post<ConnectorExecutorResult<Choice[]>>(
|
||||
`${BASE_ACTION_API_PATH}/connector/${encodeURIComponent(connectorId)}/_execute`,
|
||||
{
|
||||
body: JSON.stringify({
|
||||
|
@ -32,6 +36,7 @@ export async function getChoices({
|
|||
signal,
|
||||
}
|
||||
);
|
||||
return rewriteResponseToCamelCase(res);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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<UseChoicesProps, UseChoices>(() =>
|
||||
|
|
|
@ -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[];
|
||||
}
|
||||
|
|
|
@ -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<UseGetChoicesProps, UseGetChoices>(() =>
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue