diff --git a/x-pack/plugins/ml/public/jobs/components/custom_url_editor/__snapshots__/editor.test.js.snap b/x-pack/plugins/ml/public/jobs/components/custom_url_editor/__snapshots__/editor.test.js.snap
new file mode 100644
index 0000000000000..d4c1003a21885
--- /dev/null
+++ b/x-pack/plugins/ml/public/jobs/components/custom_url_editor/__snapshots__/editor.test.js.snap
@@ -0,0 +1,883 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`CustomUrlEditor renders the editor for a dashboard type URL with a label 1`] = `
+
+
+
+ Create new custom URL
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`CustomUrlEditor renders the editor for a discover type URL with an entity and empty time range interval 1`] = `
+
+
+
+ Create new custom URL
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`CustomUrlEditor renders the editor for a discover type URL with valid time range interval 1`] = `
+
+
+
+ Create new custom URL
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`CustomUrlEditor renders the editor for a new dashboard type URL with no label 1`] = `
+
+
+
+ Create new custom URL
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`CustomUrlEditor renders the editor for other type of URL with duplicate label 1`] = `
+
+
+
+ Create new custom URL
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`CustomUrlEditor renders the editor for other type of URL with unique label 1`] = `
+
+
+
+ Create new custom URL
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/x-pack/plugins/ml/public/jobs/components/custom_url_editor/__snapshots__/list.test.js.snap b/x-pack/plugins/ml/public/jobs/components/custom_url_editor/__snapshots__/list.test.js.snap
new file mode 100644
index 0000000000000..2ba3152f91806
--- /dev/null
+++ b/x-pack/plugins/ml/public/jobs/components/custom_url_editor/__snapshots__/list.test.js.snap
@@ -0,0 +1,387 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`CustomUrlList renders a list of custom URLs 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/x-pack/plugins/ml/public/jobs/components/custom_url_editor/editor.js b/x-pack/plugins/ml/public/jobs/components/custom_url_editor/editor.js
index 84f0890ce7ed8..863887ac8ddb7 100644
--- a/x-pack/plugins/ml/public/jobs/components/custom_url_editor/editor.js
+++ b/x-pack/plugins/ml/public/jobs/components/custom_url_editor/editor.js
@@ -175,9 +175,9 @@ export class CustomUrlEditor extends Component {
});
const entityOptions = queryEntityFieldNames.map(fieldName => ({ label: fieldName }));
- const queryFieldNames = kibanaSettings.queryFieldNames;
let selectedEntityOptions = [];
- if (queryFieldNames !== undefined) {
+ if (kibanaSettings !== undefined && kibanaSettings.queryFieldNames !== undefined) {
+ const queryFieldNames = kibanaSettings.queryFieldNames;
selectedEntityOptions = queryFieldNames.map(fieldName => ({ label: fieldName }));
}
@@ -197,7 +197,7 @@ export class CustomUrlEditor extends Component {
Create new custom URL
-
+
'mlJobService');
+
+import { shallow } from 'enzyme';
+import React from 'react';
+
+import { CustomUrlEditor } from './editor';
+import {
+ TIME_RANGE_TYPE,
+ URL_TYPE
+} from './constants';
+
+function prepareTest(customUrl, setEditCustomUrlFn) {
+
+ const savedCustomUrls = [
+ {
+ url_name: 'Show data',
+ time_range: 'auto',
+ url_value: 'kibana#/discover?_g=(time:(from:\'$earliest$\',mode:absolute,to:\'$latest$\'))&_a=' +
+ '(index:e532ba80-b76f-11e8-a9dc-37914a458883,query:(language:lucene,query:\'airline:"$airline$"\'))'
+ },
+ {
+ url_name: 'Show dashboard',
+ time_range: '1h',
+ url_value: 'kibana#/dashboard/52ea8840-bbef-11e8-a04d-b1701b2b977e?_g=' +
+ '(time:(from:\'$earliest$\',mode:absolute,to:\'$latest$\'))&' +
+ '_a=(filters:!(),query:(language:lucene,query:\'airline:"$airline$"\'))'
+ },
+ {
+ url_name: 'Show airline',
+ time_range: 'auto',
+ url_value: 'http://airlinecodes.info/airline-code-$airline$'
+ },
+
+ ];
+
+ const dashboards = [
+ { id: 'dash1', title: 'Dashboard 1' },
+ { id: 'dash2', title: 'Dashboard 2' },
+ ];
+
+ const indexPatterns = [
+ { id: 'pattern1', title: 'Index Pattern 1' },
+ { id: 'pattern2', title: 'Index Pattern 2' },
+ ];
+
+ const queryEntityFieldNames = ['airline'];
+
+ const props = {
+ customUrl,
+ setEditCustomUrl: setEditCustomUrlFn,
+ savedCustomUrls,
+ dashboards,
+ indexPatterns,
+ queryEntityFieldNames,
+ };
+
+ const wrapper = shallow(
+
+ );
+
+ return wrapper;
+}
+
+
+describe('CustomUrlEditor', () => {
+
+ const setEditCustomUrl = jest.fn(() => {});
+ const dashboardUrl = {
+ label: '',
+ timeRange: {
+ type: TIME_RANGE_TYPE.AUTO,
+ interval: ''
+ },
+ type: URL_TYPE.KIBANA_DASHBOARD,
+ kibanaSettings: {
+ queryFieldNames: [],
+ dashboardId: 'dash1',
+ },
+ };
+
+ const discoverUrl = {
+ label: 'Open Discover',
+ timeRange: {
+ type: TIME_RANGE_TYPE.INTERVAL,
+ interval: ''
+ },
+ type: URL_TYPE.KIBANA_DISCOVER,
+ kibanaSettings: {
+ queryFieldNames: ['airline'],
+ discoverIndexPatternId: 'pattern1',
+ },
+ };
+
+ const otherUrl = {
+ label: 'Show airline',
+ timeRange: {
+ type: TIME_RANGE_TYPE.AUTO,
+ interval: ''
+ },
+ type: URL_TYPE.OTHER,
+ otherUrlSettings: {
+ urlValue: 'https://www.google.co.uk/search?q=airline+code+$airline$'
+ }
+ };
+
+ test('renders the editor for a new dashboard type URL with no label', () => {
+ const wrapper = prepareTest(dashboardUrl, setEditCustomUrl);
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ test('renders the editor for a dashboard type URL with a label', () => {
+ const dashboardUrlEdit = {
+ ...dashboardUrl,
+ label: 'Open Dashboard 1'
+ };
+ const wrapper = prepareTest(dashboardUrlEdit, setEditCustomUrl);
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ test('renders the editor for a discover type URL with an entity and empty time range interval', () => {
+ const wrapper = prepareTest(discoverUrl, setEditCustomUrl);
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ test('renders the editor for a discover type URL with valid time range interval', () => {
+ const discoverUrlEdit = {
+ ...discoverUrl,
+ timeRange: {
+ type: TIME_RANGE_TYPE.INTERVAL,
+ interval: '1h'
+ }
+ };
+ const wrapper = prepareTest(discoverUrlEdit, setEditCustomUrl);
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ test('renders the editor for other type of URL with duplicate label', () => {
+ const wrapper = prepareTest(otherUrl, setEditCustomUrl);
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ test('renders the editor for other type of URL with unique label', () => {
+ const otherUrlEdit = {
+ ...otherUrl,
+ label: 'View airline'
+ };
+ const wrapper = prepareTest(otherUrlEdit, setEditCustomUrl);
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ test('calls setEditCustomUrl on updating a custom URL field', () => {
+ const wrapper = prepareTest(dashboardUrl, setEditCustomUrl);
+ const labelInput = wrapper.find('EuiFieldText').first();
+ labelInput.simulate('change', { target: { value: 'Edit' } });
+ wrapper.update();
+ expect(setEditCustomUrl).toHaveBeenCalled();
+ });
+
+});
diff --git a/x-pack/plugins/ml/public/jobs/components/custom_url_editor/list.test.js b/x-pack/plugins/ml/public/jobs/components/custom_url_editor/list.test.js
new file mode 100644
index 0000000000000..f831c84078728
--- /dev/null
+++ b/x-pack/plugins/ml/public/jobs/components/custom_url_editor/list.test.js
@@ -0,0 +1,70 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+// Mock the mlJobService that is used for testing custom URLs.
+jest.mock('../../../services/job_service.js', () => 'mlJobService');
+
+import { shallow } from 'enzyme';
+import React from 'react';
+
+import { CustomUrlList } from './list';
+
+function prepareTest(setCustomUrlsFn) {
+
+ const customUrls = [
+ {
+ url_name: 'Show data',
+ time_range: 'auto',
+ url_value: 'kibana#/discover?_g=(time:(from:\'$earliest$\',mode:absolute,to:\'$latest$\'))&_a=' +
+ '(index:e532ba80-b76f-11e8-a9dc-37914a458883,query:(language:lucene,query:\'airline:"$airline$"\'))'
+ },
+ {
+ url_name: 'Show dashboard',
+ time_range: '1h',
+ url_value: 'kibana#/dashboard/52ea8840-bbef-11e8-a04d-b1701b2b977e?_g=' +
+ '(time:(from:\'$earliest$\',mode:absolute,to:\'$latest$\'))&' +
+ '_a=(filters:!(),query:(language:lucene,query:\'airline:"$airline$"\'))'
+ },
+ {
+ url_name: 'Show airline',
+ time_range: 'auto',
+ url_value: 'http://airlinecodes.info/airline-code-$airline$'
+ },
+
+ ];
+
+ const props = {
+ job: {},
+ customUrls,
+ setCustomUrls: setCustomUrlsFn,
+ };
+
+ const wrapper = shallow(
+
+ );
+
+ return wrapper;
+}
+
+
+describe('CustomUrlList', () => {
+
+ const setCustomUrls = jest.fn(() => {});
+
+ test('renders a list of custom URLs', () => {
+ const wrapper = prepareTest(setCustomUrls);
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ test('calls setCustomUrls on updating a custom URL field', () => {
+ const wrapper = prepareTest(setCustomUrls);
+ const url1LabelInput = wrapper.find('EuiFieldText').first();
+ url1LabelInput.simulate('change', { target: { value: 'Edit' } });
+ wrapper.update();
+ expect(setCustomUrls).toHaveBeenCalled();
+ });
+
+});
diff --git a/x-pack/plugins/ml/public/jobs/components/custom_url_editor/styles/main.less b/x-pack/plugins/ml/public/jobs/components/custom_url_editor/styles/main.less
index d29cda20d779f..0a853ce2bfc1e 100644
--- a/x-pack/plugins/ml/public/jobs/components/custom_url_editor/styles/main.less
+++ b/x-pack/plugins/ml/public/jobs/components/custom_url_editor/styles/main.less
@@ -1,4 +1,4 @@
-.ml-custom-url-editor {
+.ml-edit-url-form {
.url-label {
width: 250px;
}
diff --git a/x-pack/plugins/ml/public/jobs/jobs_list/components/edit_job_flyout/edit_job_flyout.js b/x-pack/plugins/ml/public/jobs/jobs_list/components/edit_job_flyout/edit_job_flyout.js
index a0bba700b21b3..b4acd33e57b7a 100644
--- a/x-pack/plugins/ml/public/jobs/jobs_list/components/edit_job_flyout/edit_job_flyout.js
+++ b/x-pack/plugins/ml/public/jobs/jobs_list/components/edit_job_flyout/edit_job_flyout.js
@@ -23,6 +23,8 @@ import {
EuiTabbedContent,
} from '@elastic/eui';
+import './styles/main.less';
+
import { JobDetails, Detectors, Datafeed, CustomUrls } from './tabs';
import { saveJob } from './edit_utils';
import { loadFullJob } from '../utils';
diff --git a/x-pack/plugins/ml/public/jobs/jobs_list/components/edit_job_flyout/styles/main.less b/x-pack/plugins/ml/public/jobs/jobs_list/components/edit_job_flyout/styles/main.less
index e69de29bb2d1d..38343aed2985c 100644
--- a/x-pack/plugins/ml/public/jobs/jobs_list/components/edit_job_flyout/styles/main.less
+++ b/x-pack/plugins/ml/public/jobs/jobs_list/components/edit_job_flyout/styles/main.less
@@ -0,0 +1,8 @@
+.edit-custom-url-panel {
+ .close-editor-button {
+ position: relative;
+ float: right;
+ top: -5px;
+ right: 0px;
+ }
+}
diff --git a/x-pack/plugins/ml/public/jobs/jobs_list/components/edit_job_flyout/tabs/custom_urls.js b/x-pack/plugins/ml/public/jobs/jobs_list/components/edit_job_flyout/tabs/custom_urls.js
index 5d7895281ee6a..ec732c6ae8300 100644
--- a/x-pack/plugins/ml/public/jobs/jobs_list/components/edit_job_flyout/tabs/custom_urls.js
+++ b/x-pack/plugins/ml/public/jobs/jobs_list/components/edit_job_flyout/tabs/custom_urls.js
@@ -12,6 +12,7 @@ import React, {
import {
EuiButton,
EuiButtonEmpty,
+ EuiButtonIcon,
EuiFlexGroup,
EuiFlexItem,
EuiPanel,
@@ -135,6 +136,10 @@ export class CustomUrls extends Component {
});
}
+ closeEditor = () => {
+ this.setState({ editorOpen: false });
+ }
+
render() {
const {
customUrls,
@@ -151,22 +156,25 @@ export class CustomUrls extends Component {
return (
-
-
{editorOpen === false ? (
- this.editNewCustomUrl()}
- >
- Add custom URL
-
+
+ this.editNewCustomUrl()}
+ >
+ Add custom URL
+
+
) : (
-
-
+
+ this.closeEditor()}
+ iconType="cross"
+ aria-label="Close custom URL editor"
+ className="close-editor-button"
+ />
)}
+
+
);