mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Security Solution] Webhook - Case Management Connector Follow Ups (#137227)
This commit is contained in:
parent
bebec37f04
commit
2d3d930756
35 changed files with 861 additions and 453 deletions
|
@ -31,7 +31,7 @@ describe('api', () => {
|
|||
id: 'incident-1',
|
||||
title: 'CK-1',
|
||||
pushedDate: '2020-04-27T10:59:46.202Z',
|
||||
url: 'https://siem-kibana.atlassian.net/browse/CK-1',
|
||||
url: 'https://coolsite.net/browse/CK-1',
|
||||
comments: [
|
||||
{
|
||||
commentId: 'case-comment-1',
|
||||
|
@ -57,7 +57,7 @@ describe('api', () => {
|
|||
id: 'incident-1',
|
||||
title: 'CK-1',
|
||||
pushedDate: '2020-04-27T10:59:46.202Z',
|
||||
url: 'https://siem-kibana.atlassian.net/browse/CK-1',
|
||||
url: 'https://coolsite.net/browse/CK-1',
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -109,7 +109,7 @@ describe('api', () => {
|
|||
id: 'incident-1',
|
||||
title: 'CK-1',
|
||||
pushedDate: '2020-04-27T10:59:46.202Z',
|
||||
url: 'https://siem-kibana.atlassian.net/browse/CK-1',
|
||||
url: 'https://coolsite.net/browse/CK-1',
|
||||
comments: [
|
||||
{
|
||||
commentId: 'case-comment-1',
|
||||
|
@ -135,7 +135,7 @@ describe('api', () => {
|
|||
id: 'incident-1',
|
||||
title: 'CK-1',
|
||||
pushedDate: '2020-04-27T10:59:46.202Z',
|
||||
url: 'https://siem-kibana.atlassian.net/browse/CK-1',
|
||||
url: 'https://coolsite.net/browse/CK-1',
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ const createMock = (): jest.Mocked<ExternalService> => {
|
|||
id: 'incident-1',
|
||||
title: 'CK-1',
|
||||
pushedDate: '2020-04-27T10:59:46.202Z',
|
||||
url: 'https://siem-kibana.atlassian.net/browse/CK-1',
|
||||
url: 'https://coolsite.net/browse/CK-1',
|
||||
})
|
||||
),
|
||||
updateIncident: jest.fn().mockImplementation(() =>
|
||||
|
@ -32,7 +32,7 @@ const createMock = (): jest.Mocked<ExternalService> => {
|
|||
id: 'incident-1',
|
||||
title: 'CK-1',
|
||||
pushedDate: '2020-04-27T10:59:46.202Z',
|
||||
url: 'https://siem-kibana.atlassian.net/browse/CK-1',
|
||||
url: 'https://coolsite.net/browse/CK-1',
|
||||
})
|
||||
),
|
||||
createComment: jest.fn(),
|
||||
|
|
|
@ -25,7 +25,7 @@ export const ExternalIncidentServiceConfiguration = {
|
|||
getIncidentResponseCreatedDateKey: schema.string(),
|
||||
getIncidentResponseExternalTitleKey: schema.string(),
|
||||
getIncidentResponseUpdatedDateKey: schema.string(),
|
||||
incidentViewUrl: schema.string(),
|
||||
viewIncidentUrl: schema.string(),
|
||||
updateIncidentUrl: schema.string(),
|
||||
updateIncidentMethod: schema.oneOf(
|
||||
[
|
||||
|
|
|
@ -30,24 +30,23 @@ const configurationUtilities = actionsConfigMock.create();
|
|||
const config: CasesWebhookPublicConfigurationType = {
|
||||
createCommentJson: '{"body":{{{case.comment}}}}',
|
||||
createCommentMethod: CasesWebhookMethods.POST,
|
||||
createCommentUrl:
|
||||
'https://siem-kibana.atlassian.net/rest/api/2/issue/{{{external.system.id}}}/comment',
|
||||
createCommentUrl: 'https://coolsite.net/issue/{{{external.system.id}}}/comment',
|
||||
createIncidentJson:
|
||||
'{"fields":{"title":{{{case.title}}},"description":{{{case.description}}},"tags":{{{case.tags}}},"project":{"key":"ROC"},"issuetype":{"id":"10024"}}}',
|
||||
createIncidentMethod: CasesWebhookMethods.POST,
|
||||
createIncidentResponseKey: 'id',
|
||||
createIncidentUrl: 'https://siem-kibana.atlassian.net/rest/api/2/issue',
|
||||
createIncidentUrl: 'https://coolsite.net/issue',
|
||||
getIncidentResponseCreatedDateKey: 'fields.created',
|
||||
getIncidentResponseExternalTitleKey: 'key',
|
||||
getIncidentResponseUpdatedDateKey: 'fields.updated',
|
||||
hasAuth: true,
|
||||
headers: { ['content-type']: 'application/json' },
|
||||
incidentViewUrl: 'https://siem-kibana.atlassian.net/browse/{{{external.system.title}}}',
|
||||
getIncidentUrl: 'https://siem-kibana.atlassian.net/rest/api/2/issue/{{{external.system.id}}}',
|
||||
viewIncidentUrl: 'https://coolsite.net/browse/{{{external.system.title}}}',
|
||||
getIncidentUrl: 'https://coolsite.net/issue/{{{external.system.id}}}',
|
||||
updateIncidentJson:
|
||||
'{"fields":{"title":{{{case.title}}},"description":{{{case.description}}},"tags":{{{case.tags}}},"project":{"key":"ROC"},"issuetype":{"id":"10024"}}}',
|
||||
updateIncidentMethod: CasesWebhookMethods.PUT,
|
||||
updateIncidentUrl: 'https://siem-kibana.atlassian.net/rest/api/2/issue/{{{external.system.id}}}',
|
||||
updateIncidentUrl: 'https://coolsite.net/issue/{{{external.system.id}}}',
|
||||
};
|
||||
const secrets = {
|
||||
user: 'user',
|
||||
|
@ -76,7 +75,7 @@ describe('Cases webhook service', () => {
|
|||
describe('createExternalService', () => {
|
||||
const requiredUrls = [
|
||||
'createIncidentUrl',
|
||||
'incidentViewUrl',
|
||||
'viewIncidentUrl',
|
||||
'getIncidentUrl',
|
||||
'updateIncidentUrl',
|
||||
];
|
||||
|
@ -154,7 +153,7 @@ describe('Cases webhook service', () => {
|
|||
await service.getIncident('1');
|
||||
expect(requestMock).toHaveBeenCalledWith({
|
||||
axios,
|
||||
url: 'https://siem-kibana.atlassian.net/rest/api/2/issue/1',
|
||||
url: 'https://coolsite.net/issue/1',
|
||||
logger,
|
||||
configurationUtilities,
|
||||
});
|
||||
|
@ -231,7 +230,7 @@ describe('Cases webhook service', () => {
|
|||
title: 'CK-1',
|
||||
id: '1',
|
||||
pushedDate: '2020-04-27T10:59:46.202Z',
|
||||
url: 'https://siem-kibana.atlassian.net/browse/CK-1',
|
||||
url: 'https://coolsite.net/browse/CK-1',
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -260,7 +259,7 @@ describe('Cases webhook service', () => {
|
|||
|
||||
expect(requestMock.mock.calls[0][0]).toEqual({
|
||||
axios,
|
||||
url: 'https://siem-kibana.atlassian.net/rest/api/2/issue',
|
||||
url: 'https://coolsite.net/issue',
|
||||
logger,
|
||||
method: CasesWebhookMethods.POST,
|
||||
configurationUtilities,
|
||||
|
@ -326,7 +325,7 @@ describe('Cases webhook service', () => {
|
|||
title: 'CK-1',
|
||||
id: '1',
|
||||
pushedDate: '2020-04-27T10:59:46.202Z',
|
||||
url: 'https://siem-kibana.atlassian.net/browse/CK-1',
|
||||
url: 'https://coolsite.net/browse/CK-1',
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -348,7 +347,7 @@ describe('Cases webhook service', () => {
|
|||
logger,
|
||||
method: CasesWebhookMethods.PUT,
|
||||
configurationUtilities,
|
||||
url: 'https://siem-kibana.atlassian.net/rest/api/2/issue/1',
|
||||
url: 'https://coolsite.net/issue/1',
|
||||
data: JSON.stringify({
|
||||
fields: {
|
||||
title: 'title',
|
||||
|
@ -426,7 +425,7 @@ describe('Cases webhook service', () => {
|
|||
logger,
|
||||
method: CasesWebhookMethods.POST,
|
||||
configurationUtilities,
|
||||
url: 'https://siem-kibana.atlassian.net/rest/api/2/issue/1/comment',
|
||||
url: 'https://coolsite.net/issue/1/comment',
|
||||
data: `{"body":"comment"}`,
|
||||
});
|
||||
});
|
||||
|
@ -664,7 +663,7 @@ describe('Cases webhook service', () => {
|
|||
test('getIncident- escapes url', async () => {
|
||||
await service.getIncident('../../malicious-app/malicious-endpoint/');
|
||||
expect(requestMock.mock.calls[0][0].url).toEqual(
|
||||
'https://siem-kibana.atlassian.net/rest/api/2/issue/..%2F..%2Fmalicious-app%2Fmalicious-endpoint%2F'
|
||||
'https://coolsite.net/issue/..%2F..%2Fmalicious-app%2Fmalicious-endpoint%2F'
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -681,7 +680,7 @@ describe('Cases webhook service', () => {
|
|||
};
|
||||
const res = await service.createIncident(incident);
|
||||
expect(res.url).toEqual(
|
||||
'https://siem-kibana.atlassian.net/browse/..%2F..%2Fmalicious-app%2Fmalicious-endpoint%2F'
|
||||
'https://coolsite.net/browse/..%2F..%2Fmalicious-app%2Fmalicious-endpoint%2F'
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -700,7 +699,7 @@ describe('Cases webhook service', () => {
|
|||
|
||||
await service.updateIncident(incident);
|
||||
expect(requestMock.mock.calls[0][0].url).toEqual(
|
||||
'https://siem-kibana.atlassian.net/rest/api/2/issue/..%2F..%2Fmalicious-app%2Fmalicious-endpoint%2F'
|
||||
'https://coolsite.net/issue/..%2F..%2Fmalicious-app%2Fmalicious-endpoint%2F'
|
||||
);
|
||||
});
|
||||
test('createComment- escapes url', async () => {
|
||||
|
@ -714,7 +713,7 @@ describe('Cases webhook service', () => {
|
|||
|
||||
await service.createComment(commentReq);
|
||||
expect(requestMock.mock.calls[0][0].url).toEqual(
|
||||
'https://siem-kibana.atlassian.net/rest/api/2/issue/..%2F..%2Fmalicious-app%2Fmalicious-endpoint%2F/comment'
|
||||
'https://coolsite.net/issue/..%2F..%2Fmalicious-app%2Fmalicious-endpoint%2F/comment'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -55,7 +55,7 @@ export const createExternalService = (
|
|||
getIncidentUrl,
|
||||
hasAuth,
|
||||
headers,
|
||||
incidentViewUrl,
|
||||
viewIncidentUrl,
|
||||
updateIncidentJson,
|
||||
updateIncidentMethod,
|
||||
updateIncidentUrl,
|
||||
|
@ -64,7 +64,7 @@ export const createExternalService = (
|
|||
if (
|
||||
!getIncidentUrl ||
|
||||
!createIncidentUrlConfig ||
|
||||
!incidentViewUrl ||
|
||||
!viewIncidentUrl ||
|
||||
!updateIncidentUrl ||
|
||||
(hasAuth && (!password || !user))
|
||||
) {
|
||||
|
@ -163,7 +163,7 @@ export const createExternalService = (
|
|||
|
||||
logger.debug(`response from webhook action "${actionId}": [HTTP ${status}] ${statusText}`);
|
||||
|
||||
const viewUrl = renderMustacheStringNoEscape(incidentViewUrl, {
|
||||
const viewUrl = renderMustacheStringNoEscape(viewIncidentUrl, {
|
||||
external: {
|
||||
system: {
|
||||
id: encodeURIComponent(externalId),
|
||||
|
@ -233,7 +233,7 @@ export const createExternalService = (
|
|||
res,
|
||||
});
|
||||
const updatedIncident = await getIncident(incidentId as string);
|
||||
const viewUrl = renderMustacheStringNoEscape(incidentViewUrl, {
|
||||
const viewUrl = renderMustacheStringNoEscape(viewIncidentUrl, {
|
||||
external: {
|
||||
system: {
|
||||
id: encodeURIComponent(incidentId),
|
||||
|
|
|
@ -20,7 +20,7 @@ const validateConfig = (
|
|||
const {
|
||||
createCommentUrl,
|
||||
createIncidentUrl,
|
||||
incidentViewUrl,
|
||||
viewIncidentUrl,
|
||||
getIncidentUrl,
|
||||
updateIncidentUrl,
|
||||
} = configObject;
|
||||
|
@ -28,7 +28,7 @@ const validateConfig = (
|
|||
const urls = [
|
||||
createIncidentUrl,
|
||||
createCommentUrl,
|
||||
incidentViewUrl,
|
||||
viewIncidentUrl,
|
||||
getIncidentUrl,
|
||||
updateIncidentUrl,
|
||||
];
|
||||
|
|
|
@ -31,7 +31,7 @@ describe('api', () => {
|
|||
id: 'incident-1',
|
||||
title: 'CK-1',
|
||||
pushedDate: '2020-04-27T10:59:46.202Z',
|
||||
url: 'https://siem-kibana.atlassian.net/browse/CK-1',
|
||||
url: 'https://coolsite.net/browse/CK-1',
|
||||
comments: [
|
||||
{
|
||||
commentId: 'case-comment-1',
|
||||
|
@ -57,7 +57,7 @@ describe('api', () => {
|
|||
id: 'incident-1',
|
||||
title: 'CK-1',
|
||||
pushedDate: '2020-04-27T10:59:46.202Z',
|
||||
url: 'https://siem-kibana.atlassian.net/browse/CK-1',
|
||||
url: 'https://coolsite.net/browse/CK-1',
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -150,7 +150,7 @@ describe('api', () => {
|
|||
id: 'incident-1',
|
||||
title: 'CK-1',
|
||||
pushedDate: '2020-04-27T10:59:46.202Z',
|
||||
url: 'https://siem-kibana.atlassian.net/browse/CK-1',
|
||||
url: 'https://coolsite.net/browse/CK-1',
|
||||
comments: [
|
||||
{
|
||||
commentId: 'case-comment-1',
|
||||
|
@ -176,7 +176,7 @@ describe('api', () => {
|
|||
id: 'incident-1',
|
||||
title: 'CK-1',
|
||||
pushedDate: '2020-04-27T10:59:46.202Z',
|
||||
url: 'https://siem-kibana.atlassian.net/browse/CK-1',
|
||||
url: 'https://coolsite.net/browse/CK-1',
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ const createMock = (): jest.Mocked<ExternalService> => {
|
|||
id: 'incident-1',
|
||||
title: 'CK-1',
|
||||
pushedDate: '2020-04-27T10:59:46.202Z',
|
||||
url: 'https://siem-kibana.atlassian.net/browse/CK-1',
|
||||
url: 'https://coolsite.net/browse/CK-1',
|
||||
})
|
||||
),
|
||||
updateIncident: jest.fn().mockImplementation(() =>
|
||||
|
@ -32,7 +32,7 @@ const createMock = (): jest.Mocked<ExternalService> => {
|
|||
id: 'incident-1',
|
||||
title: 'CK-1',
|
||||
pushedDate: '2020-04-27T10:59:46.202Z',
|
||||
url: 'https://siem-kibana.atlassian.net/browse/CK-1',
|
||||
url: 'https://coolsite.net/browse/CK-1',
|
||||
})
|
||||
),
|
||||
createComment: jest.fn(),
|
||||
|
|
|
@ -114,9 +114,8 @@ const mockNewAPI = () =>
|
|||
data: {
|
||||
capabilities: {
|
||||
'list-project-issuetypes':
|
||||
'https://siem-kibana.atlassian.net/rest/capabilities/list-project-issuetypes',
|
||||
'list-issuetype-fields':
|
||||
'https://siem-kibana.atlassian.net/rest/capabilities/list-issuetype-fields',
|
||||
'https://coolsite.net/rest/capabilities/list-project-issuetypes',
|
||||
'list-issuetype-fields': 'https://coolsite.net/rest/capabilities/list-issuetype-fields',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
@ -127,7 +126,7 @@ const mockOldAPI = () =>
|
|||
createAxiosResponse({
|
||||
data: {
|
||||
capabilities: {
|
||||
navigation: 'https://siem-kibana.atlassian.net/rest/capabilities/navigation',
|
||||
navigation: 'https://coolsite.net/rest/capabilities/navigation',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
@ -141,7 +140,7 @@ describe('Jira service', () => {
|
|||
{
|
||||
// The trailing slash at the end of the url is intended.
|
||||
// All API calls need to have the trailing slash removed.
|
||||
config: { apiUrl: 'https://siem-kibana.atlassian.net/', projectKey: 'CK' },
|
||||
config: { apiUrl: 'https://coolsite.net/', projectKey: 'CK' },
|
||||
secrets: { apiToken: 'token', email: 'elastic@elastic.com' },
|
||||
},
|
||||
logger,
|
||||
|
@ -240,7 +239,7 @@ describe('Jira service', () => {
|
|||
await service.getIncident('1');
|
||||
expect(requestMock).toHaveBeenCalledWith({
|
||||
axios,
|
||||
url: 'https://siem-kibana.atlassian.net/rest/api/2/issue/1',
|
||||
url: 'https://coolsite.net/rest/api/2/issue/1',
|
||||
logger,
|
||||
configurationUtilities,
|
||||
});
|
||||
|
@ -313,7 +312,7 @@ describe('Jira service', () => {
|
|||
title: 'CK-1',
|
||||
id: '1',
|
||||
pushedDate: '2020-04-27T10:59:46.202Z',
|
||||
url: 'https://siem-kibana.atlassian.net/browse/CK-1',
|
||||
url: 'https://coolsite.net/browse/CK-1',
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -329,7 +328,7 @@ describe('Jira service', () => {
|
|||
createAxiosResponse({
|
||||
data: {
|
||||
capabilities: {
|
||||
navigation: 'https://siem-kibana.atlassian.net/rest/capabilities/navigation',
|
||||
navigation: 'https://coolsite.net/rest/capabilities/navigation',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
@ -365,12 +364,12 @@ describe('Jira service', () => {
|
|||
title: 'CK-1',
|
||||
id: '1',
|
||||
pushedDate: '2020-04-27T10:59:46.202Z',
|
||||
url: 'https://siem-kibana.atlassian.net/browse/CK-1',
|
||||
url: 'https://coolsite.net/browse/CK-1',
|
||||
});
|
||||
|
||||
expect(requestMock).toHaveBeenCalledWith({
|
||||
axios,
|
||||
url: 'https://siem-kibana.atlassian.net/rest/api/2/issue',
|
||||
url: 'https://coolsite.net/rest/api/2/issue',
|
||||
logger,
|
||||
method: 'post',
|
||||
configurationUtilities,
|
||||
|
@ -392,7 +391,7 @@ describe('Jira service', () => {
|
|||
createAxiosResponse({
|
||||
data: {
|
||||
capabilities: {
|
||||
navigation: 'https://siem-kibana.atlassian.net/rest/capabilities/navigation',
|
||||
navigation: 'https://coolsite.net/rest/capabilities/navigation',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
@ -427,7 +426,7 @@ describe('Jira service', () => {
|
|||
|
||||
expect(requestMock).toHaveBeenCalledWith({
|
||||
axios,
|
||||
url: 'https://siem-kibana.atlassian.net/rest/api/2/issue',
|
||||
url: 'https://coolsite.net/rest/api/2/issue',
|
||||
logger,
|
||||
method: 'post',
|
||||
configurationUtilities,
|
||||
|
@ -459,7 +458,7 @@ describe('Jira service', () => {
|
|||
|
||||
expect(requestMock).toHaveBeenCalledWith({
|
||||
axios,
|
||||
url: 'https://siem-kibana.atlassian.net/rest/api/2/issue',
|
||||
url: 'https://coolsite.net/rest/api/2/issue',
|
||||
logger,
|
||||
method: 'post',
|
||||
configurationUtilities,
|
||||
|
@ -538,7 +537,7 @@ describe('Jira service', () => {
|
|||
title: 'CK-1',
|
||||
id: '1',
|
||||
pushedDate: '2020-04-27T10:59:46.202Z',
|
||||
url: 'https://siem-kibana.atlassian.net/browse/CK-1',
|
||||
url: 'https://coolsite.net/browse/CK-1',
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -560,7 +559,7 @@ describe('Jira service', () => {
|
|||
logger,
|
||||
method: 'put',
|
||||
configurationUtilities,
|
||||
url: 'https://siem-kibana.atlassian.net/rest/api/2/issue/1',
|
||||
url: 'https://coolsite.net/rest/api/2/issue/1',
|
||||
data: {
|
||||
fields: {
|
||||
summary: 'title',
|
||||
|
@ -644,7 +643,7 @@ describe('Jira service', () => {
|
|||
logger,
|
||||
method: 'post',
|
||||
configurationUtilities,
|
||||
url: 'https://siem-kibana.atlassian.net/rest/api/2/issue/1/comment',
|
||||
url: 'https://coolsite.net/rest/api/2/issue/1/comment',
|
||||
data: { body: 'comment' },
|
||||
});
|
||||
});
|
||||
|
@ -686,7 +685,7 @@ describe('Jira service', () => {
|
|||
const res = await service.getCapabilities();
|
||||
expect(res).toEqual({
|
||||
capabilities: {
|
||||
navigation: 'https://siem-kibana.atlassian.net/rest/capabilities/navigation',
|
||||
navigation: 'https://coolsite.net/rest/capabilities/navigation',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
@ -701,7 +700,7 @@ describe('Jira service', () => {
|
|||
logger,
|
||||
method: 'get',
|
||||
configurationUtilities,
|
||||
url: 'https://siem-kibana.atlassian.net/rest/capabilities',
|
||||
url: 'https://coolsite.net/rest/capabilities',
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -782,7 +781,7 @@ describe('Jira service', () => {
|
|||
logger,
|
||||
method: 'get',
|
||||
configurationUtilities,
|
||||
url: 'https://siem-kibana.atlassian.net/rest/api/2/issue/createmeta?projectKeys=CK&expand=projects.issuetypes.fields',
|
||||
url: 'https://coolsite.net/rest/api/2/issue/createmeta?projectKeys=CK&expand=projects.issuetypes.fields',
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -856,7 +855,7 @@ describe('Jira service', () => {
|
|||
logger,
|
||||
method: 'get',
|
||||
configurationUtilities,
|
||||
url: 'https://siem-kibana.atlassian.net/rest/api/2/issue/createmeta/CK/issuetypes',
|
||||
url: 'https://coolsite.net/rest/api/2/issue/createmeta/CK/issuetypes',
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -931,7 +930,7 @@ describe('Jira service', () => {
|
|||
logger,
|
||||
method: 'get',
|
||||
configurationUtilities,
|
||||
url: 'https://siem-kibana.atlassian.net/rest/api/2/issue/createmeta?projectKeys=CK&issuetypeIds=10006&expand=projects.issuetypes.fields',
|
||||
url: 'https://coolsite.net/rest/api/2/issue/createmeta?projectKeys=CK&issuetypeIds=10006&expand=projects.issuetypes.fields',
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1044,7 +1043,7 @@ describe('Jira service', () => {
|
|||
logger,
|
||||
method: 'get',
|
||||
configurationUtilities,
|
||||
url: 'https://siem-kibana.atlassian.net/rest/api/2/issue/createmeta/CK/issuetypes/10006',
|
||||
url: 'https://coolsite.net/rest/api/2/issue/createmeta/CK/issuetypes/10006',
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1112,7 +1111,7 @@ describe('Jira service', () => {
|
|||
logger,
|
||||
method: 'get',
|
||||
configurationUtilities,
|
||||
url: `https://siem-kibana.atlassian.net/rest/api/2/search?jql=project%3D%22CK%22%20and%20summary%20~%22Test%20title%22`,
|
||||
url: `https://coolsite.net/rest/api/2/search?jql=project%3D%22CK%22%20and%20summary%20~%22Test%20title%22`,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1171,7 +1170,7 @@ describe('Jira service', () => {
|
|||
logger,
|
||||
method: 'get',
|
||||
configurationUtilities,
|
||||
url: `https://siem-kibana.atlassian.net/rest/api/2/issue/RJ-107`,
|
||||
url: `https://coolsite.net/rest/api/2/issue/RJ-107`,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1206,9 +1205,9 @@ describe('Jira service', () => {
|
|||
data: {
|
||||
capabilities: {
|
||||
'list-project-issuetypes':
|
||||
'https://siem-kibana.atlassian.net/rest/capabilities/list-project-issuetypes',
|
||||
'https://coolsite.net/rest/capabilities/list-project-issuetypes',
|
||||
'list-issuetype-fields':
|
||||
'https://siem-kibana.atlassian.net/rest/capabilities/list-issuetype-fields',
|
||||
'https://coolsite.net/rest/capabilities/list-issuetype-fields',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
@ -1225,9 +1224,9 @@ describe('Jira service', () => {
|
|||
data: {
|
||||
capabilities: {
|
||||
'list-project-issuetypes':
|
||||
'https://siem-kibana.atlassian.net/rest/capabilities/list-project-issuetypes',
|
||||
'https://coolsite.net/rest/capabilities/list-project-issuetypes',
|
||||
'list-issuetype-fields':
|
||||
'https://siem-kibana.atlassian.net/rest/capabilities/list-issuetype-fields',
|
||||
'https://coolsite.net/rest/capabilities/list-issuetype-fields',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
@ -1237,9 +1236,9 @@ describe('Jira service', () => {
|
|||
data: {
|
||||
capabilities: {
|
||||
'list-project-issuetypes':
|
||||
'https://siem-kibana.atlassian.net/rest/capabilities/list-project-issuetypes',
|
||||
'https://coolsite.net/rest/capabilities/list-project-issuetypes',
|
||||
'list-issuetype-fields':
|
||||
'https://siem-kibana.atlassian.net/rest/capabilities/list-issuetype-fields',
|
||||
'https://coolsite.net/rest/capabilities/list-issuetype-fields',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
@ -1289,12 +1288,12 @@ describe('Jira service', () => {
|
|||
callMocks();
|
||||
await service.getFields();
|
||||
const callUrls = [
|
||||
'https://siem-kibana.atlassian.net/rest/capabilities',
|
||||
'https://siem-kibana.atlassian.net/rest/api/2/issue/createmeta/CK/issuetypes',
|
||||
'https://siem-kibana.atlassian.net/rest/capabilities',
|
||||
'https://siem-kibana.atlassian.net/rest/capabilities',
|
||||
'https://siem-kibana.atlassian.net/rest/api/2/issue/createmeta/CK/issuetypes/10006',
|
||||
'https://siem-kibana.atlassian.net/rest/api/2/issue/createmeta/CK/issuetypes/10007',
|
||||
'https://coolsite.net/rest/capabilities',
|
||||
'https://coolsite.net/rest/api/2/issue/createmeta/CK/issuetypes',
|
||||
'https://coolsite.net/rest/capabilities',
|
||||
'https://coolsite.net/rest/capabilities',
|
||||
'https://coolsite.net/rest/api/2/issue/createmeta/CK/issuetypes/10006',
|
||||
'https://coolsite.net/rest/api/2/issue/createmeta/CK/issuetypes/10007',
|
||||
];
|
||||
requestMock.mock.calls.forEach((call, i) => {
|
||||
expect(call[0].url).toEqual(callUrls[i]);
|
||||
|
|
|
@ -131,7 +131,7 @@ describe('mustache_renderer', () => {
|
|||
const summary = 'A cool good summary';
|
||||
const description = 'A cool good description';
|
||||
const tags = ['cool', 'neat', 'nice'];
|
||||
const str = 'https://siem-kibana.atlassian.net/browse/{{{external.system.title}}}';
|
||||
const str = 'https://coolsite.net/browse/{{{external.system.title}}}';
|
||||
|
||||
const objStr =
|
||||
'{\n' +
|
||||
|
@ -177,7 +177,7 @@ describe('mustache_renderer', () => {
|
|||
},
|
||||
};
|
||||
expect(renderMustacheStringNoEscape(str, urlVariables)).toBe(
|
||||
`https://siem-kibana.atlassian.net/browse/cool_title`
|
||||
`https://coolsite.net/browse/cool_title`
|
||||
);
|
||||
});
|
||||
it('Inserts variables into url with quotes whens stringified', () => {
|
||||
|
@ -190,7 +190,7 @@ describe('mustache_renderer', () => {
|
|||
},
|
||||
};
|
||||
expect(renderMustacheStringNoEscape(str, urlVariablesStr)).toBe(
|
||||
`https://siem-kibana.atlassian.net/browse/"cool_title"`
|
||||
`https://coolsite.net/browse/"cool_title"`
|
||||
);
|
||||
});
|
||||
it('Inserts variables into JSON non-escaped when triple brackets and JSON.stringified variables', () => {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{"attributes":{"actionTypeId":".jira","config":{"apiUrl":"https://siem-kibana.atlassian.net/","projectKey":"CASES"},"isMissingSecrets":true,"name":"Jira test"},"coreMigrationVersion":"7.16.0","id":"018d0110-46d1-11ec-a89e-8339c89698d8","migrationVersion":{"action":"7.16.0"},"references":[],"type":"action","updated_at":"2021-11-16T11:33:22.994Z","version":"WzIwNjYsMV0="}
|
||||
{"attributes":{"actionTypeId":".jira","config":{"apiUrl":"https://coolsite.net/","projectKey":"CASES"},"isMissingSecrets":true,"name":"Jira test"},"coreMigrationVersion":"7.16.0","id":"018d0110-46d1-11ec-a89e-8339c89698d8","migrationVersion":{"action":"7.16.0"},"references":[],"type":"action","updated_at":"2021-11-16T11:33:22.994Z","version":"WzIwNjYsMV0="}
|
||||
{"attributes":{"closed_at":null,"closed_by":null,"connector":{"fields":[{"key":"issueType","value":"10001"},{"key":"parent","value":null},{"key":"priority","value":null}],"name":"Jira test","type":".jira"},"created_at":"2021-11-16T11:21:19.242Z","created_by":{"email":null,"full_name":"glo@test.co","username":"glo"},"description":"This is the description of the 7.16 case that I'm going to import in future versions.","external_service":null,"owner":"securitySolution","settings":{"syncAlerts":false},"status":"in-progress","tags":["export case"],"title":"7.16 case to export","type":"individual","updated_at":"2021-11-16T11:33:44.787Z","updated_by":{"email":"","full_name":"","username":"test"}},"coreMigrationVersion":"7.16.0","id":"5228e870-46cf-11ec-a89e-8339c89698d8","migrationVersion":{"cases":"7.15.0"},"references":[{"id":"018d0110-46d1-11ec-a89e-8339c89698d8","name":"connectorId","type":"action"}],"type":"cases","updated_at":"2021-11-16T11:33:44.788Z","version":"WzIwNzMsMV0="}
|
||||
{"attributes":{"action":"update","action_at":"2021-11-16T11:33:44.787Z","action_by":{"email":"","full_name":"","username":"test"},"action_field":["connector"],"new_value":"{\"name\":\"Jira test\",\"type\":\".jira\",\"fields\":{\"issueType\":\"10001\",\"parent\":null,\"priority\":null}}","old_value":"{\"name\":\"none\",\"type\":\".none\",\"fields\":null}","owner":"securitySolution"},"coreMigrationVersion":"7.16.0","id":"0ef96fa0-46d1-11ec-a89e-8339c89698d8","migrationVersion":{"cases-user-actions":"7.16.0"},"references":[{"id":"5228e870-46cf-11ec-a89e-8339c89698d8","name":"associated-cases","type":"cases"},{"id":"018d0110-46d1-11ec-a89e-8339c89698d8","name":"connectorId","type":"action"}],"score":null,"sort":[1637062424787,4305],"type":"cases-user-actions","updated_at":"2021-11-16T11:33:45.498Z","version":"WzIwNzQsMV0="}
|
||||
{"attributes":{"action":"create","action_at":"2021-11-16T11:21:19.242Z","action_by":{"email":null,"full_name":"glo@test.co","username":"glo"},"action_field":["description","status","tags","title","connector","settings","owner"],"new_value":"{\"type\":\"individual\",\"title\":\"7.16 case to export\",\"tags\":[\"export case\"],\"description\":\"This is the description of the 7.16 case that I'm going to import in future versions.\",\"connector\":{\"name\":\"none\",\"type\":\".none\",\"fields\":null},\"settings\":{\"syncAlerts\":false},\"owner\":\"securitySolution\"}","old_value":null,"owner":"securitySolution"},"coreMigrationVersion":"7.16.0","id":"52b87e40-46cf-11ec-a89e-8339c89698d8","migrationVersion":{"cases-user-actions":"7.16.0"},"references":[{"id":"5228e870-46cf-11ec-a89e-8339c89698d8","name":"associated-cases","type":"cases"}],"score":null,"sort":[1637061679242,4228],"type":"cases-user-actions","updated_at":"2021-11-16T11:21:20.164Z","version":"WzE5MjMsMV0="}
|
||||
|
@ -12,4 +12,4 @@
|
|||
{"attributes":{"action":"create","action_at":"2021-11-16T11:24:09.128Z","action_by":{"email":null,"full_name":"glo@test.co","username":"glo"},"action_field":["comment"],"new_value":"{\"comment\":\"!{lens{\\\"timeRange\\\":{\\\"from\\\":\\\"now-7d\\\",\\\"to\\\":\\\"now\\\",\\\"mode\\\":\\\"relative\\\"},\\\"attributes\\\":{\\\"title\\\":\\\"\\\",\\\"description\\\":\\\"Events acknowledged by the output (includes events dropped by the output). (From beat.stats.libbeat.output.events.acked)\\\",\\\"visualizationType\\\":\\\"lnsXY\\\",\\\"type\\\":\\\"lens\\\",\\\"references\\\":[{\\\"type\\\":\\\"index-pattern\\\",\\\"id\\\":\\\"92888d80-46cf-11ec-a89e-8339c89698d8\\\",\\\"name\\\":\\\"indexpattern-datasource-current-indexpattern\\\"},{\\\"type\\\":\\\"index-pattern\\\",\\\"id\\\":\\\"92888d80-46cf-11ec-a89e-8339c89698d8\\\",\\\"name\\\":\\\"indexpattern-datasource-layer-03c31209-08e8-4917-b7d5-9d77ecf40dd1\\\"}],\\\"state\\\":{\\\"visualization\\\":{\\\"legend\\\":{\\\"isVisible\\\":true,\\\"position\\\":\\\"right\\\"},\\\"valueLabels\\\":\\\"hide\\\",\\\"fittingFunction\\\":\\\"None\\\",\\\"yLeftExtent\\\":{\\\"mode\\\":\\\"full\\\"},\\\"yRightExtent\\\":{\\\"mode\\\":\\\"full\\\"},\\\"axisTitlesVisibilitySettings\\\":{\\\"x\\\":true,\\\"yRight\\\":true,\\\"yLeft\\\":true},\\\"tickLabelsVisibilitySettings\\\":{\\\"x\\\":true,\\\"yRight\\\":true,\\\"yLeft\\\":true},\\\"labelsOrientation\\\":{\\\"x\\\":0,\\\"yRight\\\":0,\\\"yLeft\\\":0},\\\"gridlinesVisibilitySettings\\\":{\\\"x\\\":true,\\\"yRight\\\":true,\\\"yLeft\\\":true},\\\"preferredSeriesType\\\":\\\"line\\\",\\\"layers\\\":[{\\\"layerId\\\":\\\"03c31209-08e8-4917-b7d5-9d77ecf40dd1\\\",\\\"seriesType\\\":\\\"line\\\",\\\"xAccessor\\\":\\\"bd01502a-3d64-470e-8277-928d6a9399e2\\\",\\\"accessors\\\":[\\\"97dfd130-3c4d-477a-8e24-adc95b5a5e86\\\"],\\\"layerType\\\":\\\"data\\\"}]},\\\"query\\\":{\\\"query\\\":\\\"\\\",\\\"language\\\":\\\"kuery\\\"},\\\"filters\\\":[],\\\"datasourceStates\\\":{\\\"indexpattern\\\":{\\\"layers\\\":{\\\"03c31209-08e8-4917-b7d5-9d77ecf40dd1\\\":{\\\"columns\\\":{\\\"bd01502a-3d64-470e-8277-928d6a9399e2\\\":{\\\"label\\\":\\\"@timestamp\\\",\\\"dataType\\\":\\\"date\\\",\\\"operationType\\\":\\\"date_histogram\\\",\\\"sourceField\\\":\\\"@timestamp\\\",\\\"isBucketed\\\":true,\\\"scale\\\":\\\"interval\\\",\\\"params\\\":{\\\"interval\\\":\\\"auto\\\"}},\\\"97dfd130-3c4d-477a-8e24-adc95b5a5e86\\\":{\\\"label\\\":\\\"Count of records\\\",\\\"dataType\\\":\\\"number\\\",\\\"operationType\\\":\\\"count\\\",\\\"isBucketed\\\":false,\\\"scale\\\":\\\"ratio\\\",\\\"sourceField\\\":\\\"Records\\\"}},\\\"columnOrder\\\":[\\\"bd01502a-3d64-470e-8277-928d6a9399e2\\\",\\\"97dfd130-3c4d-477a-8e24-adc95b5a5e86\\\"],\\\"incompleteColumns\\\":{}}}}}}}}}\",\"type\":\"user\",\"owner\":\"securitySolution\"}","old_value":null,"owner":"securitySolution"},"coreMigrationVersion":"7.16.0","id":"b8076630-46cf-11ec-a89e-8339c89698d8","migrationVersion":{"cases-user-actions":"7.16.0"},"references":[{"id":"5228e870-46cf-11ec-a89e-8339c89698d8","name":"associated-cases","type":"cases"},{"id":"b76d4910-46cf-11ec-a89e-8339c89698d8","name":"associated-cases-comments","type":"cases-comments"}],"score":null,"sort":[1637061849128,4260],"type":"cases-user-actions","updated_at":"2021-11-16T11:24:10.131Z","version":"WzE5ODcsMV0="}
|
||||
{"attributes":{"alertId":"f339b9b0e9763b98bcdb7c4a65a10701aaa97a99e232cfd2dab2d8680f7c6c3a","associationType":"case","created_at":"2021-11-16T11:24:42.043Z","created_by":{"email":null,"full_name":"glo@test.co","username":"glo"},"index":".siem-signals-default-000001","owner":"securitySolution","pushed_at":null,"pushed_by":null,"rule":{"id":"f45fd050-46ce-11ec-a89e-8339c89698d8","name":"This is a test"},"type":"alert","updated_at":null,"updated_by":null},"coreMigrationVersion":"7.16.0","id":"cb0acce0-46cf-11ec-a89e-8339c89698d8","migrationVersion":{"cases-comments":"7.16.0"},"references":[{"id":"5228e870-46cf-11ec-a89e-8339c89698d8","name":"associated-cases","type":"cases"}],"score":null,"sort":[1637061882043,6107],"type":"cases-comments","updated_at":"2021-11-16T11:24:42.048Z","version":"WzE5OTYsMV0="}
|
||||
{"attributes":{"action":"create","action_at":"2021-11-16T11:24:42.043Z","action_by":{"email":null,"full_name":"glo@test.co","username":"glo"},"action_field":["comment"],"new_value":"{\"type\":\"alert\",\"alertId\":\"f339b9b0e9763b98bcdb7c4a65a10701aaa97a99e232cfd2dab2d8680f7c6c3a\",\"index\":\".siem-signals-default-000001\",\"rule\":{\"id\":\"f45fd050-46ce-11ec-a89e-8339c89698d8\",\"name\":\"This is a test\"},\"owner\":\"securitySolution\"}","old_value":null,"owner":"securitySolution"},"coreMigrationVersion":"7.16.0","id":"cb634d20-46cf-11ec-a89e-8339c89698d8","migrationVersion":{"cases-user-actions":"7.16.0"},"references":[{"id":"5228e870-46cf-11ec-a89e-8339c89698d8","name":"associated-cases","type":"cases"},{"id":"cb0acce0-46cf-11ec-a89e-8339c89698d8","name":"associated-cases-comments","type":"cases-comments"}],"score":null,"sort":[1637061882043,4263],"type":"cases-user-actions","updated_at":"2021-11-16T11:24:42.610Z","version":"WzE5OTgsMV0="}
|
||||
{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":14,"missingRefCount":0,"missingReferences":[]}
|
||||
{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":14,"missingRefCount":0,"missingReferences":[]}
|
||||
|
|
|
@ -106,7 +106,7 @@ export const getMockConnectorsResponse = () => [
|
|||
actionTypeId: '.jira',
|
||||
name: 'Jira',
|
||||
config: {
|
||||
apiUrl: 'https://siem-kibana.atlassian.net',
|
||||
apiUrl: 'https://coolsite.net',
|
||||
projectKey: 'RJ',
|
||||
},
|
||||
isPreconfigured: false,
|
||||
|
@ -235,11 +235,11 @@ export const getExecuteResponses = () => ({
|
|||
issuetype: {
|
||||
allowedValues: [
|
||||
{
|
||||
self: 'https://siem-kibana.atlassian.net/rest/api/2/issuetype/10006',
|
||||
self: 'https://coolsite.net/rest/api/2/issuetype/10006',
|
||||
id: '10006',
|
||||
description: 'A small, distinct piece of work.',
|
||||
iconUrl:
|
||||
'https://siem-kibana.atlassian.net/secure/viewavatar?size=medium&avatarId=10318&avatarType=issuetype',
|
||||
'https://coolsite.net/secure/viewavatar?size=medium&avatarId=10318&avatarType=issuetype',
|
||||
name: 'Task',
|
||||
subtask: false,
|
||||
avatarId: 10318,
|
||||
|
@ -253,21 +253,20 @@ export const getExecuteResponses = () => ({
|
|||
project: {
|
||||
allowedValues: [
|
||||
{
|
||||
self: 'https://siem-kibana.atlassian.net/rest/api/2/project/10011',
|
||||
self: 'https://coolsite.net/rest/api/2/project/10011',
|
||||
id: '10011',
|
||||
key: 'RJ',
|
||||
name: 'Refactor Jira',
|
||||
projectTypeKey: 'business',
|
||||
simplified: false,
|
||||
avatarUrls: {
|
||||
'48x48':
|
||||
'https://siem-kibana.atlassian.net/secure/projectavatar?pid=10011&avatarId=10423',
|
||||
'48x48': 'https://coolsite.net/secure/projectavatar?pid=10011&avatarId=10423',
|
||||
'24x24':
|
||||
'https://siem-kibana.atlassian.net/secure/projectavatar?size=small&s=small&pid=10011&avatarId=10423',
|
||||
'https://coolsite.net/secure/projectavatar?size=small&s=small&pid=10011&avatarId=10423',
|
||||
'16x16':
|
||||
'https://siem-kibana.atlassian.net/secure/projectavatar?size=xsmall&s=xsmall&pid=10011&avatarId=10423',
|
||||
'https://coolsite.net/secure/projectavatar?size=xsmall&s=xsmall&pid=10011&avatarId=10423',
|
||||
'32x32':
|
||||
'https://siem-kibana.atlassian.net/secure/projectavatar?size=medium&s=medium&pid=10011&avatarId=10423',
|
||||
'https://coolsite.net/secure/projectavatar?size=medium&s=medium&pid=10011&avatarId=10423',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
@ -277,39 +276,39 @@ export const getExecuteResponses = () => ({
|
|||
priority: {
|
||||
allowedValues: [
|
||||
{
|
||||
self: 'https://siem-kibana.atlassian.net/rest/api/2/priority/1',
|
||||
iconUrl: 'https://siem-kibana.atlassian.net/images/icons/priorities/highest.svg',
|
||||
self: 'https://coolsite.net/rest/api/2/priority/1',
|
||||
iconUrl: 'https://coolsite.net/images/icons/priorities/highest.svg',
|
||||
name: 'Highest',
|
||||
id: '1',
|
||||
},
|
||||
{
|
||||
self: 'https://siem-kibana.atlassian.net/rest/api/2/priority/2',
|
||||
iconUrl: 'https://siem-kibana.atlassian.net/images/icons/priorities/high.svg',
|
||||
self: 'https://coolsite.net/rest/api/2/priority/2',
|
||||
iconUrl: 'https://coolsite.net/images/icons/priorities/high.svg',
|
||||
name: 'High',
|
||||
id: '2',
|
||||
},
|
||||
{
|
||||
self: 'https://siem-kibana.atlassian.net/rest/api/2/priority/3',
|
||||
iconUrl: 'https://siem-kibana.atlassian.net/images/icons/priorities/medium.svg',
|
||||
self: 'https://coolsite.net/rest/api/2/priority/3',
|
||||
iconUrl: 'https://coolsite.net/images/icons/priorities/medium.svg',
|
||||
name: 'Medium',
|
||||
id: '3',
|
||||
},
|
||||
{
|
||||
self: 'https://siem-kibana.atlassian.net/rest/api/2/priority/4',
|
||||
iconUrl: 'https://siem-kibana.atlassian.net/images/icons/priorities/low.svg',
|
||||
self: 'https://coolsite.net/rest/api/2/priority/4',
|
||||
iconUrl: 'https://coolsite.net/images/icons/priorities/low.svg',
|
||||
name: 'Low',
|
||||
id: '4',
|
||||
},
|
||||
{
|
||||
self: 'https://siem-kibana.atlassian.net/rest/api/2/priority/5',
|
||||
iconUrl: 'https://siem-kibana.atlassian.net/images/icons/priorities/lowest.svg',
|
||||
self: 'https://coolsite.net/rest/api/2/priority/5',
|
||||
iconUrl: 'https://coolsite.net/images/icons/priorities/lowest.svg',
|
||||
name: 'Lowest',
|
||||
id: '5',
|
||||
},
|
||||
],
|
||||
defaultValue: {
|
||||
self: 'https://siem-kibana.atlassian.net/rest/api/2/priority/3',
|
||||
iconUrl: 'https://siem-kibana.atlassian.net/images/icons/priorities/medium.svg',
|
||||
self: 'https://coolsite.net/rest/api/2/priority/3',
|
||||
iconUrl: 'https://coolsite.net/images/icons/priorities/medium.svg',
|
||||
name: 'Medium',
|
||||
id: '3',
|
||||
},
|
||||
|
|
|
@ -121,7 +121,7 @@ export const GetStep: FunctionComponent<Props> = ({ display, readOnly }) => (
|
|||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<UseField
|
||||
path="config.incidentViewUrl"
|
||||
path="config.viewIncidentUrl"
|
||||
config={{
|
||||
label: i18n.EXTERNAL_INCIDENT_VIEW_URL,
|
||||
validations: [
|
||||
|
@ -136,9 +136,9 @@ export const GetStep: FunctionComponent<Props> = ({ display, readOnly }) => (
|
|||
componentProps={{
|
||||
euiFieldProps: {
|
||||
readOnly,
|
||||
'data-test-subj': 'incidentViewUrlText',
|
||||
'data-test-subj': 'viewIncidentUrlText',
|
||||
messageVariables: urlVarsExt,
|
||||
paramsProperty: 'incidentViewUrl',
|
||||
paramsProperty: 'viewIncidentUrl',
|
||||
buttonTitle: i18n.ADD_CASES_VARIABLE,
|
||||
showButtonTitle: true,
|
||||
},
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* 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 { css } from '@emotion/react';
|
||||
|
||||
export const styles = {
|
||||
method: css`
|
||||
.euiFormRow__labelWrapper {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
`,
|
||||
};
|
|
@ -15,6 +15,7 @@ import { MustacheTextFieldWrapper } from '../../../mustache_text_field_wrapper';
|
|||
import { casesVars, commentVars, urlVars } from '../action_variables';
|
||||
import { JsonFieldWrapper } from '../../../json_field_wrapper';
|
||||
import { HTTP_VERBS } from '../webhook_connectors';
|
||||
import { styles } from './update.styles';
|
||||
import * as i18n from '../translations';
|
||||
const { emptyField, urlField } = fieldValidators;
|
||||
|
||||
|
@ -47,6 +48,7 @@ export const UpdateStep: FunctionComponent<Props> = ({ display, readOnly }) => (
|
|||
},
|
||||
],
|
||||
}}
|
||||
css={styles.method}
|
||||
componentProps={{
|
||||
euiFieldProps: {
|
||||
'data-test-subj': 'webhookUpdateMethodSelect',
|
||||
|
@ -137,6 +139,7 @@ export const UpdateStep: FunctionComponent<Props> = ({ display, readOnly }) => (
|
|||
},
|
||||
],
|
||||
}}
|
||||
css={styles.method}
|
||||
componentProps={{
|
||||
euiFieldProps: {
|
||||
'data-test-subj': 'webhookCreateCommentMethodSelect',
|
||||
|
|
|
@ -275,13 +275,13 @@ export const GET_INCIDENT_UPDATED_KEY_HELP = i18n.translate(
|
|||
);
|
||||
|
||||
export const EXTERNAL_INCIDENT_VIEW_URL = i18n.translate(
|
||||
'xpack.triggersActionsUI.components.builtinActionTypes.casesWebhookAction.incidentViewUrlTextFieldLabel',
|
||||
'xpack.triggersActionsUI.components.builtinActionTypes.casesWebhookAction.viewIncidentUrlTextFieldLabel',
|
||||
{
|
||||
defaultMessage: 'External Case View URL',
|
||||
}
|
||||
);
|
||||
export const EXTERNAL_INCIDENT_VIEW_URL_HELP = i18n.translate(
|
||||
'xpack.triggersActionsUI.components.builtinActionTypes.casesWebhookAction.incidentViewUrlHelp',
|
||||
'xpack.triggersActionsUI.components.builtinActionTypes.casesWebhookAction.viewIncidentUrlHelp',
|
||||
{
|
||||
defaultMessage:
|
||||
'URL to view case in external system. Use the variable selector to add external system id or external system title to the url.',
|
||||
|
|
|
@ -41,24 +41,23 @@ const invalidJsonBoth = `{"fields":{"summary":"wrong","description":"wrong","pro
|
|||
const config = {
|
||||
createCommentJson: '{"body":{{{case.comment}}}}',
|
||||
createCommentMethod: 'post',
|
||||
createCommentUrl:
|
||||
'https://siem-kibana.atlassian.net/rest/api/2/issue/{{{external.system.id}}}/comment',
|
||||
createCommentUrl: 'https://coolsite.net/rest/api/2/issue/{{{external.system.id}}}/comment',
|
||||
createIncidentJson:
|
||||
'{"fields":{"summary":{{{case.title}}},"description":{{{case.description}}},"project":{"key":"ROC"},"issuetype":{"id":"10024"}}}',
|
||||
createIncidentMethod: 'post',
|
||||
createIncidentResponseKey: 'id',
|
||||
createIncidentUrl: 'https://siem-kibana.atlassian.net/rest/api/2/issue',
|
||||
createIncidentUrl: 'https://coolsite.net/rest/api/2/issue',
|
||||
getIncidentResponseCreatedDateKey: 'fields.created',
|
||||
getIncidentResponseExternalTitleKey: 'key',
|
||||
getIncidentResponseUpdatedDateKey: 'fields.updated',
|
||||
hasAuth: true,
|
||||
headers: [{ key: 'content-type', value: 'text' }],
|
||||
incidentViewUrl: 'https://siem-kibana.atlassian.net/browse/{{{external.system.title}}}',
|
||||
getIncidentUrl: 'https://siem-kibana.atlassian.net/rest/api/2/issue/{{{external.system.id}}}',
|
||||
viewIncidentUrl: 'https://coolsite.net/browse/{{{external.system.title}}}',
|
||||
getIncidentUrl: 'https://coolsite.net/rest/api/2/issue/{{{external.system.id}}}',
|
||||
updateIncidentJson:
|
||||
'{"fields":{"summary":{{{case.title}}},"description":{{{case.description}}},"project":{"key":"ROC"},"issuetype":{"id":"10024"}}}',
|
||||
updateIncidentMethod: 'put',
|
||||
updateIncidentUrl: 'https://siem-kibana.atlassian.net/rest/api/2/issue/{{{external.system.id}}}',
|
||||
updateIncidentUrl: 'https://coolsite.net/rest/api/2/issue/{{{external.system.id}}}',
|
||||
};
|
||||
const actionConnector = {
|
||||
secrets: {
|
||||
|
@ -97,7 +96,7 @@ describe('CasesWebhookActionConnectorFields renders', () => {
|
|||
expect(getByTestId('getIncidentResponseExternalTitleKeyText')).toBeInTheDocument();
|
||||
expect(getByTestId('getIncidentResponseCreatedDateKeyText')).toBeInTheDocument();
|
||||
expect(getByTestId('getIncidentResponseUpdatedDateKeyText')).toBeInTheDocument();
|
||||
expect(getByTestId('incidentViewUrlInput')).toBeInTheDocument();
|
||||
expect(getByTestId('viewIncidentUrlInput')).toBeInTheDocument();
|
||||
expect(getByTestId('webhookUpdateMethodSelect')).toBeInTheDocument();
|
||||
expect(getByTestId('updateIncidentUrlInput')).toBeInTheDocument();
|
||||
expect(getByTestId('webhookUpdateIncidentJson')).toBeInTheDocument();
|
||||
|
@ -340,7 +339,7 @@ describe('CasesWebhookActionConnectorFields renders', () => {
|
|||
['webhookCreateUrlText', 'not-valid'],
|
||||
['webhookUserInput', ''],
|
||||
['webhookPasswordInput', ''],
|
||||
['incidentViewUrlInput', 'https://missingexternalid.com'],
|
||||
['viewIncidentUrlInput', 'https://missingexternalid.com'],
|
||||
['createIncidentResponseKeyText', ''],
|
||||
['getIncidentUrlInput', 'https://missingexternalid.com'],
|
||||
['getIncidentResponseExternalTitleKeyText', ''],
|
||||
|
@ -357,7 +356,7 @@ describe('CasesWebhookActionConnectorFields renders', () => {
|
|||
['updateIncidentJson', invalidJsonBoth, ['{{{case.title}}}', '{{{case.description}}}']],
|
||||
['createCommentJson', invalidJsonBoth, ['{{{case.comment}}}']],
|
||||
[
|
||||
'incidentViewUrl',
|
||||
'viewIncidentUrl',
|
||||
'https://missingexternalid.com',
|
||||
['{{{external.system.id}}}', '{{{external.system.title}}}'],
|
||||
],
|
||||
|
|
|
@ -42,7 +42,7 @@ const fields = {
|
|||
'config.getIncidentResponseExternalTitleKey',
|
||||
'config.getIncidentResponseCreatedDateKey',
|
||||
'config.getIncidentResponseUpdatedDateKey',
|
||||
'config.incidentViewUrl',
|
||||
'config.viewIncidentUrl',
|
||||
],
|
||||
step4: [
|
||||
'config.updateIncidentMethod',
|
||||
|
|
|
@ -180,173 +180,181 @@ describe('action_form', () => {
|
|||
|
||||
const useKibanaMock = useKibana as jest.Mocked<typeof useKibana>;
|
||||
|
||||
describe('action_form in alert', () => {
|
||||
async function setup(customActions?: RuleAction[], customRecoveredActionGroup?: string) {
|
||||
const actionTypeRegistry = actionTypeRegistryMock.create();
|
||||
async function setup(
|
||||
customActions?: RuleAction[],
|
||||
customRecoveredActionGroup?: string,
|
||||
isExperimental?: boolean
|
||||
) {
|
||||
const actionTypeRegistry = actionTypeRegistryMock.create();
|
||||
|
||||
const { loadAllActions } = jest.requireMock('../../lib/action_connector_api');
|
||||
loadAllActions.mockResolvedValueOnce(allActions);
|
||||
const mocks = coreMock.createSetup();
|
||||
const [
|
||||
{
|
||||
application: { capabilities },
|
||||
},
|
||||
] = await mocks.getStartServices();
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
useKibanaMock().services.application.capabilities = {
|
||||
...capabilities,
|
||||
actions: {
|
||||
show: true,
|
||||
save: true,
|
||||
delete: true,
|
||||
},
|
||||
};
|
||||
actionTypeRegistry.list.mockReturnValue([
|
||||
actionType,
|
||||
disabledByConfigActionType,
|
||||
disabledByLicenseActionType,
|
||||
disabledByActionType,
|
||||
preconfiguredOnly,
|
||||
]);
|
||||
actionTypeRegistry.has.mockReturnValue(true);
|
||||
actionTypeRegistry.get.mockReturnValue(actionType);
|
||||
const initialAlert = {
|
||||
name: 'test',
|
||||
params: {},
|
||||
consumer: 'alerts',
|
||||
alertTypeId: alertType.id,
|
||||
schedule: {
|
||||
interval: '1m',
|
||||
},
|
||||
actions: customActions
|
||||
? customActions
|
||||
: [
|
||||
{
|
||||
group: 'default',
|
||||
id: 'test',
|
||||
actionTypeId: actionType.id,
|
||||
params: {
|
||||
message: '',
|
||||
},
|
||||
},
|
||||
],
|
||||
tags: [],
|
||||
muteAll: false,
|
||||
enabled: false,
|
||||
mutedInstanceIds: [],
|
||||
} as unknown as Rule;
|
||||
|
||||
loadActionTypes.mockResolvedValue([
|
||||
{
|
||||
id: actionType.id,
|
||||
name: 'Test',
|
||||
enabled: true,
|
||||
enabledInConfig: true,
|
||||
enabledInLicense: true,
|
||||
minimumLicenseRequired: 'basic',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
},
|
||||
{
|
||||
id: '.index',
|
||||
name: 'Index',
|
||||
enabled: true,
|
||||
enabledInConfig: true,
|
||||
enabledInLicense: true,
|
||||
minimumLicenseRequired: 'basic',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
},
|
||||
{
|
||||
id: 'preconfigured',
|
||||
name: 'Preconfigured only',
|
||||
enabled: true,
|
||||
enabledInConfig: false,
|
||||
enabledInLicense: true,
|
||||
minimumLicenseRequired: 'basic',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
},
|
||||
{
|
||||
id: 'disabled-by-config',
|
||||
name: 'Disabled by config',
|
||||
enabled: false,
|
||||
enabledInConfig: false,
|
||||
enabledInLicense: true,
|
||||
minimumLicenseRequired: 'gold',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
},
|
||||
{
|
||||
id: 'disabled-by-license',
|
||||
name: 'Disabled by license',
|
||||
enabled: false,
|
||||
enabledInConfig: true,
|
||||
enabledInLicense: false,
|
||||
minimumLicenseRequired: 'gold',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
},
|
||||
{
|
||||
id: '.jira',
|
||||
name: 'Disabled by action type',
|
||||
enabled: true,
|
||||
enabledInConfig: true,
|
||||
enabledInLicense: true,
|
||||
minimumLicenseRequired: 'basic',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
},
|
||||
]);
|
||||
|
||||
const defaultActionMessage = 'Alert [{{context.metadata.name}}] has exceeded the threshold';
|
||||
const wrapper = mountWithIntl(
|
||||
<ActionForm
|
||||
actions={initialAlert.actions}
|
||||
messageVariables={{
|
||||
params: [
|
||||
{ name: 'testVar1', description: 'test var1' },
|
||||
{ name: 'testVar2', description: 'test var2' },
|
||||
],
|
||||
state: [],
|
||||
context: [{ name: 'contextVar', description: 'context var1' }],
|
||||
}}
|
||||
featureId="alerting"
|
||||
defaultActionGroupId={'default'}
|
||||
isActionGroupDisabledForActionType={(actionGroupId: string, actionTypeId: string) => {
|
||||
const recoveryActionGroupId = customRecoveredActionGroup
|
||||
? customRecoveredActionGroup
|
||||
: 'recovered';
|
||||
return isActionGroupDisabledForActionTypeId(
|
||||
actionGroupId === recoveryActionGroupId ? RecoveredActionGroup.id : actionGroupId,
|
||||
actionTypeId
|
||||
);
|
||||
}}
|
||||
setActionIdByIndex={(id: string, index: number) => {
|
||||
initialAlert.actions[index].id = id;
|
||||
}}
|
||||
actionGroups={[
|
||||
{ id: 'default', name: 'Default', defaultActionMessage },
|
||||
const { loadAllActions } = jest.requireMock('../../lib/action_connector_api');
|
||||
loadAllActions.mockResolvedValueOnce(allActions);
|
||||
const mocks = coreMock.createSetup();
|
||||
const [
|
||||
{
|
||||
application: { capabilities },
|
||||
},
|
||||
] = await mocks.getStartServices();
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
useKibanaMock().services.application.capabilities = {
|
||||
...capabilities,
|
||||
actions: {
|
||||
show: true,
|
||||
save: true,
|
||||
delete: true,
|
||||
},
|
||||
};
|
||||
const newActionType = {
|
||||
...actionType,
|
||||
isExperimental,
|
||||
};
|
||||
actionTypeRegistry.list.mockReturnValue([
|
||||
newActionType,
|
||||
disabledByConfigActionType,
|
||||
disabledByLicenseActionType,
|
||||
disabledByActionType,
|
||||
preconfiguredOnly,
|
||||
]);
|
||||
actionTypeRegistry.has.mockReturnValue(true);
|
||||
actionTypeRegistry.get.mockReturnValue(newActionType);
|
||||
const initialAlert = {
|
||||
name: 'test',
|
||||
params: {},
|
||||
consumer: 'alerts',
|
||||
alertTypeId: alertType.id,
|
||||
schedule: {
|
||||
interval: '1m',
|
||||
},
|
||||
actions: customActions
|
||||
? customActions
|
||||
: [
|
||||
{
|
||||
id: customRecoveredActionGroup ? customRecoveredActionGroup : 'recovered',
|
||||
name: customRecoveredActionGroup ? 'I feel better' : 'Recovered',
|
||||
group: 'default',
|
||||
id: 'test',
|
||||
actionTypeId: newActionType.id,
|
||||
params: {
|
||||
message: '',
|
||||
},
|
||||
},
|
||||
]}
|
||||
setActionGroupIdByIndex={(group: string, index: number) => {
|
||||
initialAlert.actions[index].group = group;
|
||||
}}
|
||||
setActions={(_updatedActions: RuleAction[]) => {}}
|
||||
setActionParamsProperty={(key: string, value: any, index: number) =>
|
||||
(initialAlert.actions[index] = { ...initialAlert.actions[index], [key]: value })
|
||||
}
|
||||
actionTypeRegistry={actionTypeRegistry}
|
||||
setHasActionsWithBrokenConnector={setHasActionsWithBrokenConnector}
|
||||
/>
|
||||
);
|
||||
],
|
||||
tags: [],
|
||||
muteAll: false,
|
||||
enabled: false,
|
||||
mutedInstanceIds: [],
|
||||
} as unknown as Rule;
|
||||
|
||||
// Wait for active space to resolve before requesting the component to update
|
||||
await act(async () => {
|
||||
await nextTick();
|
||||
wrapper.update();
|
||||
});
|
||||
loadActionTypes.mockResolvedValue([
|
||||
{
|
||||
id: newActionType.id,
|
||||
name: 'Test',
|
||||
enabled: true,
|
||||
enabledInConfig: true,
|
||||
enabledInLicense: true,
|
||||
minimumLicenseRequired: 'basic',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
},
|
||||
{
|
||||
id: '.index',
|
||||
name: 'Index',
|
||||
enabled: true,
|
||||
enabledInConfig: true,
|
||||
enabledInLicense: true,
|
||||
minimumLicenseRequired: 'basic',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
},
|
||||
{
|
||||
id: 'preconfigured',
|
||||
name: 'Preconfigured only',
|
||||
enabled: true,
|
||||
enabledInConfig: false,
|
||||
enabledInLicense: true,
|
||||
minimumLicenseRequired: 'basic',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
},
|
||||
{
|
||||
id: 'disabled-by-config',
|
||||
name: 'Disabled by config',
|
||||
enabled: false,
|
||||
enabledInConfig: false,
|
||||
enabledInLicense: true,
|
||||
minimumLicenseRequired: 'gold',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
},
|
||||
{
|
||||
id: 'disabled-by-license',
|
||||
name: 'Disabled by license',
|
||||
enabled: false,
|
||||
enabledInConfig: true,
|
||||
enabledInLicense: false,
|
||||
minimumLicenseRequired: 'gold',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
},
|
||||
{
|
||||
id: '.jira',
|
||||
name: 'Disabled by action type',
|
||||
enabled: true,
|
||||
enabledInConfig: true,
|
||||
enabledInLicense: true,
|
||||
minimumLicenseRequired: 'basic',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
},
|
||||
]);
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
const defaultActionMessage = 'Alert [{{context.metadata.name}}] has exceeded the threshold';
|
||||
const wrapper = mountWithIntl(
|
||||
<ActionForm
|
||||
actions={initialAlert.actions}
|
||||
messageVariables={{
|
||||
params: [
|
||||
{ name: 'testVar1', description: 'test var1' },
|
||||
{ name: 'testVar2', description: 'test var2' },
|
||||
],
|
||||
state: [],
|
||||
context: [{ name: 'contextVar', description: 'context var1' }],
|
||||
}}
|
||||
featureId="alerting"
|
||||
defaultActionGroupId={'default'}
|
||||
isActionGroupDisabledForActionType={(actionGroupId: string, actionTypeId: string) => {
|
||||
const recoveryActionGroupId = customRecoveredActionGroup
|
||||
? customRecoveredActionGroup
|
||||
: 'recovered';
|
||||
return isActionGroupDisabledForActionTypeId(
|
||||
actionGroupId === recoveryActionGroupId ? RecoveredActionGroup.id : actionGroupId,
|
||||
actionTypeId
|
||||
);
|
||||
}}
|
||||
setActionIdByIndex={(id: string, index: number) => {
|
||||
initialAlert.actions[index].id = id;
|
||||
}}
|
||||
actionGroups={[
|
||||
{ id: 'default', name: 'Default', defaultActionMessage },
|
||||
{
|
||||
id: customRecoveredActionGroup ? customRecoveredActionGroup : 'recovered',
|
||||
name: customRecoveredActionGroup ? 'I feel better' : 'Recovered',
|
||||
},
|
||||
]}
|
||||
setActionGroupIdByIndex={(group: string, index: number) => {
|
||||
initialAlert.actions[index].group = group;
|
||||
}}
|
||||
setActions={(_updatedActions: RuleAction[]) => {}}
|
||||
setActionParamsProperty={(key: string, value: any, index: number) =>
|
||||
(initialAlert.actions[index] = { ...initialAlert.actions[index], [key]: value })
|
||||
}
|
||||
actionTypeRegistry={actionTypeRegistry}
|
||||
setHasActionsWithBrokenConnector={setHasActionsWithBrokenConnector}
|
||||
/>
|
||||
);
|
||||
|
||||
// Wait for active space to resolve before requesting the component to update
|
||||
await act(async () => {
|
||||
await nextTick();
|
||||
wrapper.update();
|
||||
});
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
describe('action_form in alert', () => {
|
||||
it('renders available action cards', async () => {
|
||||
const wrapper = await setup();
|
||||
const actionOption = wrapper.find(
|
||||
|
@ -605,4 +613,28 @@ describe('action_form', () => {
|
|||
).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('beta badge (action_type_form)', () => {
|
||||
it(`does not render beta badge when isExperimental=undefined`, async () => {
|
||||
const wrapper = await setup();
|
||||
expect(wrapper.find('EuiKeyPadMenuItem EuiBetaBadge').exists()).toBeFalsy();
|
||||
expect(
|
||||
wrapper.find('EuiBetaBadge[data-test-subj="action-type-form-beta-badge"]').exists()
|
||||
).toBeFalsy();
|
||||
});
|
||||
it(`does not render beta badge when isExperimental=false`, async () => {
|
||||
const wrapper = await setup(undefined, undefined, false);
|
||||
expect(wrapper.find('EuiKeyPadMenuItem EuiBetaBadge').exists()).toBeFalsy();
|
||||
expect(
|
||||
wrapper.find('EuiBetaBadge[data-test-subj="action-type-form-beta-badge"]').exists()
|
||||
).toBeFalsy();
|
||||
});
|
||||
it(`renders beta badge when isExperimental=true`, async () => {
|
||||
const wrapper = await setup(undefined, undefined, true);
|
||||
expect(wrapper.find('EuiKeyPadMenuItem EuiBetaBadge').exists()).toBeTruthy();
|
||||
expect(
|
||||
wrapper.find('EuiBetaBadge[data-test-subj="action-type-form-beta-badge"]').exists()
|
||||
).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -20,6 +20,7 @@ import {
|
|||
EuiLink,
|
||||
} from '@elastic/eui';
|
||||
import { ActionGroup, RuleActionParam } from '@kbn/alerting-plugin/common';
|
||||
import { betaBadgeProps } from './beta_badge_props';
|
||||
import { loadActionTypes, loadAllActions as loadConnectors } from '../../lib/action_connector_api';
|
||||
import {
|
||||
ActionTypeModel,
|
||||
|
@ -256,6 +257,10 @@ export const ActionForm = ({
|
|||
isDisabled={!checkEnabledResult.isEnabled}
|
||||
data-test-subj={`${item.id}-${featureId}-ActionTypeSelectOption`}
|
||||
label={actionTypesIndex[item.id].name}
|
||||
betaBadgeLabel={item.isExperimental ? betaBadgeProps.label : undefined}
|
||||
betaBadgeTooltipContent={
|
||||
item.isExperimental ? betaBadgeProps.tooltipContent : undefined
|
||||
}
|
||||
onClick={() => addActionType(item)}
|
||||
>
|
||||
<EuiIcon
|
||||
|
|
|
@ -24,9 +24,11 @@ import {
|
|||
EuiBadge,
|
||||
EuiErrorBoundary,
|
||||
EuiToolTip,
|
||||
EuiBetaBadge,
|
||||
} from '@elastic/eui';
|
||||
import { isEmpty, partition, some } from 'lodash';
|
||||
import { ActionVariable, RuleActionParam } from '@kbn/alerting-plugin/common';
|
||||
import { betaBadgeProps } from './beta_badge_props';
|
||||
import {
|
||||
IErrorObject,
|
||||
RuleAction,
|
||||
|
@ -341,6 +343,15 @@ export const ActionTypeForm = ({
|
|||
</div>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
{actionTypeRegistered && actionTypeRegistered.isExperimental && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiBetaBadge
|
||||
data-test-subj="action-type-form-beta-badge"
|
||||
label={betaBadgeProps.label}
|
||||
tooltipContent={betaBadgeProps.tooltipContent}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
}
|
||||
extraAction={
|
||||
|
|
|
@ -41,121 +41,255 @@ describe('connector_add_flyout', () => {
|
|||
},
|
||||
};
|
||||
});
|
||||
|
||||
it('renders action type menu with proper EuiCards for registered action types', async () => {
|
||||
const onActionTypeChange = jest.fn();
|
||||
const actionType = actionTypeRegistryMock.createMockActionTypeModel({
|
||||
id: 'my-action-type',
|
||||
iconClass: 'test',
|
||||
selectMessage: 'test',
|
||||
validateParams: (): Promise<GenericValidationResult<unknown>> => {
|
||||
const validationResult = { errors: {} };
|
||||
return Promise.resolve(validationResult);
|
||||
},
|
||||
actionConnectorFields: null,
|
||||
});
|
||||
actionTypeRegistry.get.mockReturnValueOnce(actionType);
|
||||
loadActionTypes.mockResolvedValueOnce([
|
||||
{
|
||||
id: actionType.id,
|
||||
enabled: true,
|
||||
name: 'Test',
|
||||
enabledInConfig: true,
|
||||
enabledInLicense: true,
|
||||
minimumLicenseRequired: 'basic',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
},
|
||||
]);
|
||||
|
||||
const wrapper = mountWithIntl(
|
||||
<ActionTypeMenu
|
||||
onActionTypeChange={onActionTypeChange}
|
||||
actionTypeRegistry={actionTypeRegistry}
|
||||
/>
|
||||
);
|
||||
await act(async () => {
|
||||
await nextTick();
|
||||
wrapper.update();
|
||||
});
|
||||
|
||||
expect(wrapper.find('[data-test-subj="my-action-type-card"]').exists()).toBeTruthy();
|
||||
afterEach(() => {
|
||||
actionTypeRegistry.get.mockReset();
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it(`doesn't renders action types that are disabled via config`, async () => {
|
||||
const onActionTypeChange = jest.fn();
|
||||
const actionType = actionTypeRegistryMock.createMockActionTypeModel({
|
||||
id: 'my-action-type',
|
||||
iconClass: 'test',
|
||||
selectMessage: 'test',
|
||||
validateParams: (): Promise<GenericValidationResult<unknown>> => {
|
||||
const validationResult = { errors: {} };
|
||||
return Promise.resolve(validationResult);
|
||||
},
|
||||
actionConnectorFields: null,
|
||||
});
|
||||
actionTypeRegistry.get.mockReturnValueOnce(actionType);
|
||||
loadActionTypes.mockResolvedValueOnce([
|
||||
{
|
||||
id: actionType.id,
|
||||
enabled: false,
|
||||
name: 'Test',
|
||||
enabledInConfig: false,
|
||||
enabledInLicense: true,
|
||||
minimumLicenseRequired: 'gold',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
},
|
||||
]);
|
||||
describe('rendering', () => {
|
||||
it('renders action type menu with proper EuiCards for registered action types', async () => {
|
||||
const onActionTypeChange = jest.fn();
|
||||
const actionType = actionTypeRegistryMock.createMockActionTypeModel({
|
||||
id: 'my-action-type',
|
||||
iconClass: 'test',
|
||||
selectMessage: 'test',
|
||||
validateParams: (): Promise<GenericValidationResult<unknown>> => {
|
||||
const validationResult = { errors: {} };
|
||||
return Promise.resolve(validationResult);
|
||||
},
|
||||
actionConnectorFields: null,
|
||||
});
|
||||
actionTypeRegistry.get.mockReturnValueOnce(actionType);
|
||||
loadActionTypes.mockResolvedValueOnce([
|
||||
{
|
||||
id: actionType.id,
|
||||
enabled: true,
|
||||
name: 'Test',
|
||||
enabledInConfig: true,
|
||||
enabledInLicense: true,
|
||||
minimumLicenseRequired: 'basic',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
},
|
||||
]);
|
||||
|
||||
const wrapper = mountWithIntl(
|
||||
<ActionTypeMenu
|
||||
onActionTypeChange={onActionTypeChange}
|
||||
actionTypeRegistry={actionTypeRegistry}
|
||||
/>
|
||||
);
|
||||
await act(async () => {
|
||||
await nextTick();
|
||||
wrapper.update();
|
||||
const wrapper = mountWithIntl(
|
||||
<ActionTypeMenu
|
||||
onActionTypeChange={onActionTypeChange}
|
||||
actionTypeRegistry={actionTypeRegistry}
|
||||
/>
|
||||
);
|
||||
await act(async () => {
|
||||
await nextTick();
|
||||
wrapper.update();
|
||||
});
|
||||
|
||||
expect(wrapper.find('[data-test-subj="my-action-type-card"]').exists()).toBeTruthy();
|
||||
});
|
||||
|
||||
expect(wrapper.find('[data-test-subj="my-action-type-card"]').exists()).toBeFalsy();
|
||||
it(`doesn't renders action types that are disabled via config`, async () => {
|
||||
const onActionTypeChange = jest.fn();
|
||||
const actionType = actionTypeRegistryMock.createMockActionTypeModel({
|
||||
id: 'my-action-type',
|
||||
iconClass: 'test',
|
||||
selectMessage: 'test',
|
||||
validateParams: (): Promise<GenericValidationResult<unknown>> => {
|
||||
const validationResult = { errors: {} };
|
||||
return Promise.resolve(validationResult);
|
||||
},
|
||||
actionConnectorFields: null,
|
||||
});
|
||||
actionTypeRegistry.get.mockReturnValueOnce(actionType);
|
||||
loadActionTypes.mockResolvedValueOnce([
|
||||
{
|
||||
id: actionType.id,
|
||||
enabled: false,
|
||||
name: 'Test',
|
||||
enabledInConfig: false,
|
||||
enabledInLicense: true,
|
||||
minimumLicenseRequired: 'gold',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
},
|
||||
]);
|
||||
|
||||
const wrapper = mountWithIntl(
|
||||
<ActionTypeMenu
|
||||
onActionTypeChange={onActionTypeChange}
|
||||
actionTypeRegistry={actionTypeRegistry}
|
||||
/>
|
||||
);
|
||||
await act(async () => {
|
||||
await nextTick();
|
||||
wrapper.update();
|
||||
});
|
||||
|
||||
expect(wrapper.find('[data-test-subj="my-action-type-card"]').exists()).toBeFalsy();
|
||||
});
|
||||
|
||||
it(`renders action types as disabled when disabled by license`, async () => {
|
||||
const onActionTypeChange = jest.fn();
|
||||
const actionType = actionTypeRegistryMock.createMockActionTypeModel({
|
||||
id: 'my-action-type',
|
||||
iconClass: 'test',
|
||||
selectMessage: 'test',
|
||||
validateParams: (): Promise<GenericValidationResult<unknown>> => {
|
||||
const validationResult = { errors: {} };
|
||||
return Promise.resolve(validationResult);
|
||||
},
|
||||
actionConnectorFields: null,
|
||||
});
|
||||
actionTypeRegistry.get.mockReturnValueOnce(actionType);
|
||||
loadActionTypes.mockResolvedValueOnce([
|
||||
{
|
||||
id: actionType.id,
|
||||
enabled: false,
|
||||
name: 'Test',
|
||||
enabledInConfig: true,
|
||||
enabledInLicense: false,
|
||||
minimumLicenseRequired: 'gold',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
},
|
||||
]);
|
||||
|
||||
const wrapper = mountWithIntl(
|
||||
<ActionTypeMenu
|
||||
onActionTypeChange={onActionTypeChange}
|
||||
actionTypeRegistry={actionTypeRegistry}
|
||||
/>
|
||||
);
|
||||
await act(async () => {
|
||||
await nextTick();
|
||||
wrapper.update();
|
||||
});
|
||||
|
||||
expect(
|
||||
wrapper.find('EuiToolTip [data-test-subj="my-action-type-card"]').exists()
|
||||
).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
it(`renders action types as disabled when disabled by license`, async () => {
|
||||
const onActionTypeChange = jest.fn();
|
||||
const actionType = actionTypeRegistryMock.createMockActionTypeModel({
|
||||
id: 'my-action-type',
|
||||
iconClass: 'test',
|
||||
selectMessage: 'test',
|
||||
validateParams: (): Promise<GenericValidationResult<unknown>> => {
|
||||
const validationResult = { errors: {} };
|
||||
return Promise.resolve(validationResult);
|
||||
},
|
||||
actionConnectorFields: null,
|
||||
});
|
||||
actionTypeRegistry.get.mockReturnValueOnce(actionType);
|
||||
loadActionTypes.mockResolvedValueOnce([
|
||||
{
|
||||
id: actionType.id,
|
||||
enabled: false,
|
||||
name: 'Test',
|
||||
enabledInConfig: true,
|
||||
enabledInLicense: false,
|
||||
minimumLicenseRequired: 'gold',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
},
|
||||
]);
|
||||
describe('beta badge', () => {
|
||||
it(`does not render beta badge when isExperimental=undefined`, async () => {
|
||||
const onActionTypeChange = jest.fn();
|
||||
const actionType = actionTypeRegistryMock.createMockActionTypeModel({
|
||||
id: 'my-action-type',
|
||||
iconClass: 'test',
|
||||
selectMessage: 'test',
|
||||
validateParams: (): Promise<GenericValidationResult<unknown>> => {
|
||||
const validationResult = { errors: {} };
|
||||
return Promise.resolve(validationResult);
|
||||
},
|
||||
actionConnectorFields: null,
|
||||
});
|
||||
actionTypeRegistry.get.mockReturnValueOnce(actionType);
|
||||
loadActionTypes.mockResolvedValueOnce([
|
||||
{
|
||||
id: actionType.id,
|
||||
enabled: false,
|
||||
name: 'Test',
|
||||
enabledInConfig: true,
|
||||
enabledInLicense: false,
|
||||
minimumLicenseRequired: 'gold',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
},
|
||||
]);
|
||||
|
||||
const wrapper = mountWithIntl(
|
||||
<ActionTypeMenu
|
||||
onActionTypeChange={onActionTypeChange}
|
||||
actionTypeRegistry={actionTypeRegistry}
|
||||
/>
|
||||
);
|
||||
await act(async () => {
|
||||
await nextTick();
|
||||
wrapper.update();
|
||||
const wrapper = mountWithIntl(
|
||||
<ActionTypeMenu
|
||||
onActionTypeChange={onActionTypeChange}
|
||||
actionTypeRegistry={actionTypeRegistry}
|
||||
/>
|
||||
);
|
||||
await act(async () => {
|
||||
await nextTick();
|
||||
wrapper.update();
|
||||
});
|
||||
|
||||
expect(
|
||||
wrapper.find('EuiToolTip [data-test-subj="my-action-type-card"] EuiBetaBadge').exists()
|
||||
).toBeFalsy();
|
||||
});
|
||||
it(`does not render beta badge when isExperimental=false`, async () => {
|
||||
const onActionTypeChange = jest.fn();
|
||||
const actionType = actionTypeRegistryMock.createMockActionTypeModel({
|
||||
id: 'my-action-type',
|
||||
iconClass: 'test',
|
||||
selectMessage: 'test',
|
||||
validateParams: (): Promise<GenericValidationResult<unknown>> => {
|
||||
const validationResult = { errors: {} };
|
||||
return Promise.resolve(validationResult);
|
||||
},
|
||||
actionConnectorFields: null,
|
||||
isExperimental: false,
|
||||
});
|
||||
actionTypeRegistry.get.mockReturnValueOnce(actionType);
|
||||
loadActionTypes.mockResolvedValueOnce([
|
||||
{
|
||||
id: actionType.id,
|
||||
enabled: false,
|
||||
name: 'Test',
|
||||
enabledInConfig: true,
|
||||
enabledInLicense: false,
|
||||
minimumLicenseRequired: 'gold',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
},
|
||||
]);
|
||||
|
||||
const wrapper = mountWithIntl(
|
||||
<ActionTypeMenu
|
||||
onActionTypeChange={onActionTypeChange}
|
||||
actionTypeRegistry={actionTypeRegistry}
|
||||
/>
|
||||
);
|
||||
await act(async () => {
|
||||
await nextTick();
|
||||
wrapper.update();
|
||||
});
|
||||
|
||||
expect(
|
||||
wrapper.find('EuiToolTip [data-test-subj="my-action-type-card"] EuiBetaBadge').exists()
|
||||
).toBeFalsy();
|
||||
});
|
||||
|
||||
expect(wrapper.find('EuiToolTip [data-test-subj="my-action-type-card"]').exists()).toBeTruthy();
|
||||
it(`renders beta badge when isExperimental=true`, async () => {
|
||||
const onActionTypeChange = jest.fn();
|
||||
const actionType = actionTypeRegistryMock.createMockActionTypeModel({
|
||||
id: 'my-action-type',
|
||||
iconClass: 'test',
|
||||
selectMessage: 'test',
|
||||
validateParams: (): Promise<GenericValidationResult<unknown>> => {
|
||||
const validationResult = { errors: {} };
|
||||
return Promise.resolve(validationResult);
|
||||
},
|
||||
actionConnectorFields: null,
|
||||
isExperimental: true,
|
||||
});
|
||||
actionTypeRegistry.get.mockReturnValueOnce(actionType);
|
||||
loadActionTypes.mockResolvedValueOnce([
|
||||
{
|
||||
id: actionType.id,
|
||||
enabled: false,
|
||||
name: 'Test',
|
||||
enabledInConfig: true,
|
||||
enabledInLicense: false,
|
||||
minimumLicenseRequired: 'gold',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
},
|
||||
]);
|
||||
|
||||
const wrapper = mountWithIntl(
|
||||
<ActionTypeMenu
|
||||
onActionTypeChange={onActionTypeChange}
|
||||
actionTypeRegistry={actionTypeRegistry}
|
||||
/>
|
||||
);
|
||||
await act(async () => {
|
||||
await nextTick();
|
||||
wrapper.update();
|
||||
});
|
||||
|
||||
expect(
|
||||
wrapper.find('EuiToolTip [data-test-subj="my-action-type-card"] EuiBetaBadge').exists()
|
||||
).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -22,7 +22,9 @@ import {
|
|||
EuiFormRow,
|
||||
EuiButtonEmpty,
|
||||
EuiIconTip,
|
||||
EuiBetaBadge,
|
||||
} from '@elastic/eui';
|
||||
import { betaBadgeProps } from './beta_badge_props';
|
||||
import { RuleAction, ActionTypeIndex, ActionConnector } from '../../../types';
|
||||
import { hasSaveActionsCapability } from '../../lib/capabilities';
|
||||
import { ActionAccordionFormProps } from './action_form';
|
||||
|
@ -179,6 +181,14 @@ export const AddConnectorInline = ({
|
|||
/>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
{actionTypeRegistered && actionTypeRegistered.isExperimental && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiBetaBadge
|
||||
label={betaBadgeProps.label}
|
||||
tooltipContent={betaBadgeProps.tooltipContent}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
}
|
||||
extraAction={
|
||||
|
|
|
@ -75,4 +75,84 @@ describe('connector_add_modal', () => {
|
|||
expect(wrapper.exists('.euiModalHeader')).toBeTruthy();
|
||||
expect(wrapper.exists('[data-test-subj="saveActionButtonModal"]')).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('beta badge', () => {
|
||||
it(`does not render beta badge when isExperimental=false`, async () => {
|
||||
const actionTypeModel = actionTypeRegistryMock.createMockActionTypeModel({
|
||||
id: 'my-action-type',
|
||||
iconClass: 'test',
|
||||
isExperimental: false,
|
||||
selectMessage: 'test',
|
||||
validateParams: (): Promise<GenericValidationResult<unknown>> => {
|
||||
const validationResult = { errors: {} };
|
||||
return Promise.resolve(validationResult);
|
||||
},
|
||||
actionConnectorFields: null,
|
||||
});
|
||||
actionTypeRegistry.get.mockReturnValue(actionTypeModel);
|
||||
actionTypeRegistry.has.mockReturnValue(true);
|
||||
|
||||
const actionType: ActionType = {
|
||||
id: 'my-action-type',
|
||||
name: 'test',
|
||||
enabled: true,
|
||||
enabledInConfig: true,
|
||||
enabledInLicense: true,
|
||||
minimumLicenseRequired: 'basic',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
};
|
||||
const wrapper = mountWithIntl(
|
||||
<ConnectorAddModal
|
||||
onClose={() => {}}
|
||||
actionType={actionType}
|
||||
actionTypeRegistry={actionTypeRegistry}
|
||||
/>
|
||||
);
|
||||
await act(async () => {
|
||||
await nextTick();
|
||||
wrapper.update();
|
||||
});
|
||||
|
||||
expect(wrapper.find('EuiBetaBadge').exists()).toBeFalsy();
|
||||
});
|
||||
|
||||
it(`renders beta badge when isExperimental=true`, async () => {
|
||||
const actionTypeModel = actionTypeRegistryMock.createMockActionTypeModel({
|
||||
id: 'my-action-type',
|
||||
iconClass: 'test',
|
||||
isExperimental: true,
|
||||
selectMessage: 'test',
|
||||
validateParams: (): Promise<GenericValidationResult<unknown>> => {
|
||||
const validationResult = { errors: {} };
|
||||
return Promise.resolve(validationResult);
|
||||
},
|
||||
actionConnectorFields: null,
|
||||
});
|
||||
actionTypeRegistry.get.mockReturnValue(actionTypeModel);
|
||||
actionTypeRegistry.has.mockReturnValue(true);
|
||||
|
||||
const actionType: ActionType = {
|
||||
id: 'my-action-type',
|
||||
name: 'test',
|
||||
enabled: true,
|
||||
enabledInConfig: true,
|
||||
enabledInLicense: true,
|
||||
minimumLicenseRequired: 'basic',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
};
|
||||
const wrapper = mountWithIntl(
|
||||
<ConnectorAddModal
|
||||
onClose={() => {}}
|
||||
actionType={actionType}
|
||||
actionTypeRegistry={actionTypeRegistry}
|
||||
/>
|
||||
);
|
||||
await act(async () => {
|
||||
await nextTick();
|
||||
wrapper.update();
|
||||
});
|
||||
|
||||
expect(wrapper.find('EuiBetaBadge').exists()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -19,9 +19,11 @@ import {
|
|||
EuiFlexItem,
|
||||
EuiIcon,
|
||||
EuiFlexGroup,
|
||||
EuiBetaBadge,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import './connector_add_modal.scss';
|
||||
import { betaBadgeProps } from './beta_badge_props';
|
||||
import { hasSaveActionsCapability } from '../../lib/capabilities';
|
||||
import { ActionType, ActionConnector, ActionTypeRegistryContract } from '../../../types';
|
||||
import { useKibana } from '../../../common/lib/kibana';
|
||||
|
@ -140,18 +142,30 @@ const ConnectorAddModal = ({
|
|||
<EuiIcon type={actionTypeModel.iconClass} size="xl" />
|
||||
</EuiFlexItem>
|
||||
) : null}
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="s">
|
||||
<h3 id="flyoutTitle">
|
||||
<FormattedMessage
|
||||
defaultMessage="{actionTypeName} connector"
|
||||
id="xpack.triggersActionsUI.sections.addModalConnectorForm.flyoutTitle"
|
||||
values={{
|
||||
actionTypeName: actionType.name,
|
||||
}}
|
||||
/>
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup gutterSize="s" justifyContent="center" alignItems="center">
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="s">
|
||||
<h3 id="flyoutTitle">
|
||||
<FormattedMessage
|
||||
defaultMessage="{actionTypeName} connector"
|
||||
id="xpack.triggersActionsUI.sections.addModalConnectorForm.flyoutTitle"
|
||||
values={{
|
||||
actionTypeName: actionType.name,
|
||||
}}
|
||||
/>
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
{actionTypeModel && actionTypeModel.isExperimental && (
|
||||
<EuiFlexItem className="betaBadgeFlexItem" grow={false}>
|
||||
<EuiBetaBadge
|
||||
label={betaBadgeProps.label}
|
||||
tooltipContent={betaBadgeProps.tooltipContent}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiModalHeaderTitle>
|
||||
|
|
|
@ -45,20 +45,32 @@ const FlyoutHeaderComponent: React.FC<Props> = ({
|
|||
<EuiIcon type={icon} size="xl" />
|
||||
</EuiFlexItem>
|
||||
) : null}
|
||||
<EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
{actionTypeName && actionTypeMessage ? (
|
||||
<>
|
||||
<EuiTitle size="s">
|
||||
<h3 id="flyoutTitle">
|
||||
<FormattedMessage
|
||||
defaultMessage="{actionTypeName} connector"
|
||||
id="xpack.triggersActionsUI.sections.addConnectorForm.flyoutTitle"
|
||||
values={{
|
||||
actionTypeName,
|
||||
}}
|
||||
/>
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
<EuiFlexGroup gutterSize="s" justifyContent="center" alignItems="center">
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="s">
|
||||
<h3 id="flyoutTitle">
|
||||
<FormattedMessage
|
||||
defaultMessage="{actionTypeName} connector"
|
||||
id="xpack.triggersActionsUI.sections.addConnectorForm.flyoutTitle"
|
||||
values={{
|
||||
actionTypeName,
|
||||
}}
|
||||
/>
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
{actionTypeName && isExperimental && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiBetaBadge
|
||||
label={betaBadgeProps.label}
|
||||
tooltipContent={betaBadgeProps.tooltipContent}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
<EuiText size="s" color="subdued">
|
||||
{actionTypeMessage}
|
||||
</EuiText>
|
||||
|
@ -96,14 +108,6 @@ const FlyoutHeaderComponent: React.FC<Props> = ({
|
|||
</EuiTitle>
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
{actionTypeName && isExperimental && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiBetaBadge
|
||||
label={betaBadgeProps.label}
|
||||
tooltipContent={betaBadgeProps.tooltipContent}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
</EuiFlyoutHeader>
|
||||
);
|
||||
|
|
|
@ -16,6 +16,7 @@ import {
|
|||
createAppMockRenderer,
|
||||
} from '../../../components/builtin_action_types/test_utils';
|
||||
import CreateConnectorFlyout from '.';
|
||||
import { betaBadgeProps } from '../beta_badge_props';
|
||||
|
||||
jest.mock('../../../lib/action_connector_api', () => ({
|
||||
...(jest.requireActual('../../../lib/action_connector_api') as any),
|
||||
|
@ -79,6 +80,7 @@ describe('CreateConnectorFlyout', () => {
|
|||
onTestConnector={onTestConnector}
|
||||
/>
|
||||
);
|
||||
await act(() => Promise.resolve());
|
||||
|
||||
expect(getByTestId('create-connector-flyout')).toBeInTheDocument();
|
||||
expect(getByTestId('create-connector-flyout-header')).toBeInTheDocument();
|
||||
|
@ -294,6 +296,47 @@ describe('CreateConnectorFlyout', () => {
|
|||
expect(getByText('Test connector')).toBeInTheDocument();
|
||||
expect(getByText(`selectMessage-${actionTypeModel.id}`)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not show beta badge when isExperimental is undefined', async () => {
|
||||
const { queryByText } = appMockRenderer.render(
|
||||
<CreateConnectorFlyout
|
||||
actionTypeRegistry={actionTypeRegistry}
|
||||
onClose={onClose}
|
||||
onConnectorCreated={onConnectorCreated}
|
||||
onTestConnector={onTestConnector}
|
||||
/>
|
||||
);
|
||||
await act(() => Promise.resolve());
|
||||
expect(queryByText(betaBadgeProps.label)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not show beta badge when isExperimental is false', async () => {
|
||||
actionTypeRegistry.get.mockReturnValue({ ...actionTypeModel, isExperimental: false });
|
||||
const { queryByText } = appMockRenderer.render(
|
||||
<CreateConnectorFlyout
|
||||
actionTypeRegistry={actionTypeRegistry}
|
||||
onClose={onClose}
|
||||
onConnectorCreated={onConnectorCreated}
|
||||
onTestConnector={onTestConnector}
|
||||
/>
|
||||
);
|
||||
await act(() => Promise.resolve());
|
||||
expect(queryByText(betaBadgeProps.label)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows beta badge when isExperimental is true', async () => {
|
||||
actionTypeRegistry.get.mockReturnValue({ ...actionTypeModel, isExperimental: true });
|
||||
const { getByText } = appMockRenderer.render(
|
||||
<CreateConnectorFlyout
|
||||
actionTypeRegistry={actionTypeRegistry}
|
||||
onClose={onClose}
|
||||
onConnectorCreated={onConnectorCreated}
|
||||
onTestConnector={onTestConnector}
|
||||
/>
|
||||
);
|
||||
await act(() => Promise.resolve());
|
||||
expect(getByText(betaBadgeProps.label)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Submitting', () => {
|
||||
|
|
|
@ -22,16 +22,26 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { betaBadgeProps } from '../beta_badge_props';
|
||||
import { EditConnectorTabs } from '../../../../types';
|
||||
|
||||
const FlyoutHeaderComponent: React.FC<{
|
||||
isExperimental?: boolean;
|
||||
isPreconfigured: boolean;
|
||||
connectorName: string;
|
||||
connectorTypeDesc: string;
|
||||
selectedTab: EditConnectorTabs;
|
||||
setTab: () => void;
|
||||
icon?: IconType | null;
|
||||
}> = ({ icon, isPreconfigured, connectorName, connectorTypeDesc, selectedTab, setTab }) => {
|
||||
}> = ({
|
||||
icon,
|
||||
isExperimental = false,
|
||||
isPreconfigured,
|
||||
connectorName,
|
||||
connectorTypeDesc,
|
||||
selectedTab,
|
||||
setTab,
|
||||
}) => {
|
||||
const { euiTheme } = useEuiTheme();
|
||||
|
||||
return (
|
||||
|
@ -42,17 +52,22 @@ const FlyoutHeaderComponent: React.FC<{
|
|||
<EuiIcon type={icon} size="m" data-test-subj="edit-connector-flyout-header-icon" />
|
||||
</EuiFlexItem>
|
||||
) : null}
|
||||
<EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
{isPreconfigured ? (
|
||||
<>
|
||||
<EuiTitle size="s">
|
||||
<h3 id="flyoutTitle">
|
||||
<FormattedMessage
|
||||
defaultMessage="{connectorName}"
|
||||
id="xpack.triggersActionsUI.sections.preconfiguredConnectorForm.flyoutTitle"
|
||||
values={{ connectorName }}
|
||||
/>
|
||||
 
|
||||
<EuiFlexGroup gutterSize="s" justifyContent="center" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiTitle size="s">
|
||||
<h3 id="flyoutTitle">
|
||||
<FormattedMessage
|
||||
defaultMessage="{connectorName}"
|
||||
id="xpack.triggersActionsUI.sections.preconfiguredConnectorForm.flyoutTitle"
|
||||
values={{ connectorName }}
|
||||
/>
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiBetaBadge
|
||||
label="Preconfigured"
|
||||
data-test-subj="preconfiguredBadge"
|
||||
|
@ -63,8 +78,16 @@ const FlyoutHeaderComponent: React.FC<{
|
|||
}
|
||||
)}
|
||||
/>
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
{isExperimental && (
|
||||
<EuiBetaBadge
|
||||
label={betaBadgeProps.label}
|
||||
tooltipContent={betaBadgeProps.tooltipContent}
|
||||
/>
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiText size="s">
|
||||
<FormattedMessage
|
||||
defaultMessage="{connectorTypeDesc}"
|
||||
|
@ -74,14 +97,26 @@ const FlyoutHeaderComponent: React.FC<{
|
|||
</EuiText>
|
||||
</>
|
||||
) : (
|
||||
<EuiTitle size="s">
|
||||
<h3 id="flyoutTitle">
|
||||
<FormattedMessage
|
||||
defaultMessage="Edit connector"
|
||||
id="xpack.triggersActionsUI.sections.editConnectorForm.flyoutPreconfiguredTitle"
|
||||
/>
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
<EuiFlexGroup gutterSize="s" justifyContent="center" alignItems="center">
|
||||
<EuiFlexItem>
|
||||
<EuiTitle size="s">
|
||||
<h3 id="flyoutTitle">
|
||||
<FormattedMessage
|
||||
defaultMessage="Edit connector"
|
||||
id="xpack.triggersActionsUI.sections.editConnectorForm.flyoutPreconfiguredTitle"
|
||||
/>
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
{isExperimental && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiBetaBadge
|
||||
label={betaBadgeProps.label}
|
||||
tooltipContent={betaBadgeProps.tooltipContent}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
|
|
@ -17,6 +17,7 @@ import {
|
|||
} from '../../../components/builtin_action_types/test_utils';
|
||||
import EditConnectorFlyout from '.';
|
||||
import { ActionConnector, EditConnectorTabs, GenericValidationResult } from '../../../../types';
|
||||
import { betaBadgeProps } from '../beta_badge_props';
|
||||
|
||||
const updateConnectorResponse = {
|
||||
connector_type_id: 'test',
|
||||
|
@ -191,6 +192,33 @@ describe('EditConnectorFlyout', () => {
|
|||
|
||||
expect(getByTestId('preconfiguredBadge')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not show beta badge when isExperimental is false', async () => {
|
||||
const { queryByText } = appMockRenderer.render(
|
||||
<EditConnectorFlyout
|
||||
actionTypeRegistry={actionTypeRegistry}
|
||||
onClose={onClose}
|
||||
connector={{ ...connector, isPreconfigured: true }}
|
||||
onConnectorUpdated={onConnectorUpdated}
|
||||
/>
|
||||
);
|
||||
await act(() => Promise.resolve());
|
||||
expect(queryByText(betaBadgeProps.label)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows beta badge when isExperimental is true', async () => {
|
||||
actionTypeRegistry.get.mockReturnValue({ ...actionTypeModel, isExperimental: true });
|
||||
const { getByText } = appMockRenderer.render(
|
||||
<EditConnectorFlyout
|
||||
actionTypeRegistry={actionTypeRegistry}
|
||||
onClose={onClose}
|
||||
connector={{ ...connector, isPreconfigured: true }}
|
||||
onConnectorUpdated={onConnectorUpdated}
|
||||
/>
|
||||
);
|
||||
await act(() => Promise.resolve());
|
||||
expect(getByText(betaBadgeProps.label)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Tabs', () => {
|
||||
|
|
|
@ -246,6 +246,7 @@ const EditConnectorFlyoutComponent: React.FC<EditConnectorFlyoutProps> = ({
|
|||
setTab={handleSetTab}
|
||||
selectedTab={selectedTab}
|
||||
icon={actionTypeModel?.iconClass}
|
||||
isExperimental={actionTypeModel?.isExperimental}
|
||||
/>
|
||||
<EuiFlyoutBody>
|
||||
{selectedTab === EditConnectorTabs.Configuration ? (
|
||||
|
|
|
@ -20,25 +20,23 @@ export default function casesWebhookTest({ getService }: FtrProviderContext) {
|
|||
const config = {
|
||||
createCommentJson: '{"body":{{{case.comment}}}}',
|
||||
createCommentMethod: 'post',
|
||||
createCommentUrl:
|
||||
'https://siem-kibana.atlassian.net/rest/api/2/issue/{{{external.system.id}}}/comment',
|
||||
createCommentUrl: 'https://coolsite.net/rest/api/2/issue/{{{external.system.id}}}/comment',
|
||||
createIncidentJson:
|
||||
'{"fields":{"summary":{{{case.title}}},"description":{{{case.description}}},"labels":{{{case.tags}}},"project":{"key":"ROC"},"issuetype":{"id":"10024"}}}',
|
||||
createIncidentMethod: 'post',
|
||||
createIncidentResponseKey: 'id',
|
||||
createIncidentUrl: 'https://siem-kibana.atlassian.net/rest/api/2/issue',
|
||||
createIncidentUrl: 'https://coolsite.net/rest/api/2/issue',
|
||||
getIncidentResponseCreatedDateKey: 'fields.created',
|
||||
getIncidentResponseExternalTitleKey: 'key',
|
||||
getIncidentResponseUpdatedDateKey: 'fields.updated',
|
||||
hasAuth: true,
|
||||
headers: { ['content-type']: 'application/json' },
|
||||
incidentViewUrl: 'https://siem-kibana.atlassian.net/browse/{{{external.system.title}}}',
|
||||
getIncidentUrl: 'https://siem-kibana.atlassian.net/rest/api/2/issue/{{{external.system.id}}}',
|
||||
viewIncidentUrl: 'https://coolsite.net/browse/{{{external.system.title}}}',
|
||||
getIncidentUrl: 'https://coolsite.net/rest/api/2/issue/{{{external.system.id}}}',
|
||||
updateIncidentJson:
|
||||
'{"fields":{"summary":{{{case.title}}},"description":{{{case.description}}},"labels":{{{case.tags}}},"project":{"key":"ROC"},"issuetype":{"id":"10024"}}}',
|
||||
updateIncidentMethod: 'put',
|
||||
updateIncidentUrl:
|
||||
'https://siem-kibana.atlassian.net/rest/api/2/issue/{{{external.system.id}}}',
|
||||
updateIncidentUrl: 'https://coolsite.net/rest/api/2/issue/{{{external.system.id}}}',
|
||||
};
|
||||
|
||||
const mockCasesWebhook = {
|
||||
|
@ -81,7 +79,7 @@ export default function casesWebhookTest({ getService }: FtrProviderContext) {
|
|||
...config,
|
||||
createCommentUrl: `${casesWebhookSimulatorURL}/{{{external.system.id}}}/comments`,
|
||||
createIncidentUrl: casesWebhookSimulatorURL,
|
||||
incidentViewUrl: `${casesWebhookSimulatorURL}/{{{external.system.title}}}`,
|
||||
viewIncidentUrl: `${casesWebhookSimulatorURL}/{{{external.system.title}}}`,
|
||||
getIncidentUrl: `${casesWebhookSimulatorURL}/{{{external.system.id}}}`,
|
||||
updateIncidentUrl: `${casesWebhookSimulatorURL}/{{{external.system.id}}}`,
|
||||
},
|
||||
|
|
|
@ -24,25 +24,23 @@ export default function casesWebhookTest({ getService }: FtrProviderContext) {
|
|||
const config = {
|
||||
createCommentJson: '{"body":{{{case.comment}}}}',
|
||||
createCommentMethod: 'post',
|
||||
createCommentUrl:
|
||||
'https://siem-kibana.atlassian.net/rest/api/2/issue/{{{external.system.id}}}/comment',
|
||||
createCommentUrl: 'https://coolsite.net/rest/api/2/issue/{{{external.system.id}}}/comment',
|
||||
createIncidentJson:
|
||||
'{"fields":{"summary":{{{case.title}}},"description":{{{case.description}}},"labels":{{{case.tags}}},"project":{"key":"ROC"},"issuetype":{"id":"10024"}}}',
|
||||
createIncidentMethod: 'post',
|
||||
createIncidentResponseKey: 'id',
|
||||
createIncidentUrl: 'https://siem-kibana.atlassian.net/rest/api/2/issue',
|
||||
createIncidentUrl: 'https://coolsite.net/rest/api/2/issue',
|
||||
getIncidentResponseCreatedDateKey: 'fields.created',
|
||||
getIncidentResponseExternalTitleKey: 'key',
|
||||
getIncidentResponseUpdatedDateKey: 'fields.updated',
|
||||
hasAuth: true,
|
||||
headers: { ['content-type']: 'application/json', ['kbn-xsrf']: 'abcd' },
|
||||
incidentViewUrl: 'https://siem-kibana.atlassian.net/browse/{{{external.system.title}}}',
|
||||
getIncidentUrl: 'https://siem-kibana.atlassian.net/rest/api/2/issue/{{{external.system.id}}}',
|
||||
viewIncidentUrl: 'https://coolsite.net/browse/{{{external.system.title}}}',
|
||||
getIncidentUrl: 'https://coolsite.net/rest/api/2/issue/{{{external.system.id}}}',
|
||||
updateIncidentJson:
|
||||
'{"fields":{"summary":{{{case.title}}},"description":{{{case.description}}},"labels":{{{case.tags}}},"project":{"key":"ROC"},"issuetype":{"id":"10024"}}}',
|
||||
updateIncidentMethod: 'put',
|
||||
updateIncidentUrl:
|
||||
'https://siem-kibana.atlassian.net/rest/api/2/issue/{{{external.system.id}}}',
|
||||
updateIncidentUrl: 'https://coolsite.net/rest/api/2/issue/{{{external.system.id}}}',
|
||||
};
|
||||
const requiredFields = [
|
||||
'createIncidentJson',
|
||||
|
@ -51,7 +49,7 @@ export default function casesWebhookTest({ getService }: FtrProviderContext) {
|
|||
'getIncidentResponseCreatedDateKey',
|
||||
'getIncidentResponseExternalTitleKey',
|
||||
'getIncidentResponseUpdatedDateKey',
|
||||
'incidentViewUrl',
|
||||
'viewIncidentUrl',
|
||||
'getIncidentUrl',
|
||||
'updateIncidentJson',
|
||||
'updateIncidentUrl',
|
||||
|
@ -94,7 +92,7 @@ export default function casesWebhookTest({ getService }: FtrProviderContext) {
|
|||
...mockCasesWebhook.config,
|
||||
createCommentUrl: `${casesWebhookSimulatorURL}/rest/api/2/issue/{{{external.system.id}}}/comment`,
|
||||
createIncidentUrl: `${casesWebhookSimulatorURL}/rest/api/2/issue`,
|
||||
incidentViewUrl: `${casesWebhookSimulatorURL}/browse/{{{external.system.title}}}`,
|
||||
viewIncidentUrl: `${casesWebhookSimulatorURL}/browse/{{{external.system.title}}}`,
|
||||
getIncidentUrl: `${casesWebhookSimulatorURL}/rest/api/2/issue/{{{external.system.id}}}`,
|
||||
updateIncidentUrl: `${casesWebhookSimulatorURL}/rest/api/2/issue/{{{external.system.id}}}`,
|
||||
};
|
||||
|
@ -174,7 +172,7 @@ export default function casesWebhookTest({ getService }: FtrProviderContext) {
|
|||
...mockCasesWebhook.config,
|
||||
createCommentUrl: `${badUrl}/{{{external.system.id}}}/comments`,
|
||||
createIncidentUrl: badUrl,
|
||||
incidentViewUrl: `${badUrl}/{{{external.system.title}}}`,
|
||||
viewIncidentUrl: `${badUrl}/{{{external.system.title}}}`,
|
||||
getIncidentUrl: `${badUrl}/{{{external.system.id}}}`,
|
||||
updateIncidentUrl: `${badUrl}/{{{external.system.id}}}`,
|
||||
},
|
||||
|
|
|
@ -271,7 +271,7 @@ export const getCasesWebhookConnector = () => ({
|
|||
getIncidentResponseUpdatedDateKey: 'fields.updated',
|
||||
hasAuth: true,
|
||||
headers: { [`content-type`]: 'application/json' },
|
||||
incidentViewUrl: 'http://some.non.existent.com/browse/{{{external.system.title}}}',
|
||||
viewIncidentUrl: 'http://some.non.existent.com/browse/{{{external.system.title}}}',
|
||||
getIncidentUrl: 'http://some.non.existent.com/{{{external.system.id}}}',
|
||||
updateIncidentJson:
|
||||
'{"fields":{"summary":{{{case.title}}},"description":{{{case.description}}},"project":{"key":"ROC"},"issuetype":{"id":"10024"}}}',
|
||||
|
|
|
@ -76,7 +76,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
getIncidentResponseUpdatedDateKey: 'fields.updated',
|
||||
hasAuth: true,
|
||||
headers: { [`content-type`]: 'application/json' },
|
||||
incidentViewUrl: 'http://some.non.existent.com/browse/{{{external.system.title}}}',
|
||||
viewIncidentUrl: 'http://some.non.existent.com/browse/{{{external.system.title}}}',
|
||||
getIncidentUrl: 'http://some.non.existent.com/{{{external.system.id}}}',
|
||||
updateIncidentJson:
|
||||
'{"fields":{"summary":{{{case.title}}},"description":{{{case.description}}},"project":{"key":"ROC"},"issuetype":{"id":"10024"}}}',
|
||||
|
|
|
@ -110,7 +110,7 @@ export default ({ getService }: FtrProviderContext): void => {
|
|||
getIncidentResponseUpdatedDateKey: 'fields.updated',
|
||||
hasAuth: true,
|
||||
headers: { [`content-type`]: 'application/json' },
|
||||
incidentViewUrl: 'http://some.non.existent.com/browse/{{{external.system.title}}}',
|
||||
viewIncidentUrl: 'http://some.non.existent.com/browse/{{{external.system.title}}}',
|
||||
getIncidentUrl: 'http://some.non.existent.com/{{{external.system.id}}}',
|
||||
updateIncidentJson:
|
||||
'{"fields":{"summary":{{{case.title}}},"description":{{{case.description}}},"project":{"key":"ROC"},"issuetype":{"id":"10024"}}}',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue