From 445ac2f12fdc1af856d46eee8510b3195723d37a Mon Sep 17 00:00:00 2001 From: Pete Harverson Date: Fri, 23 Nov 2018 14:45:39 +0000 Subject: [PATCH] [ML] Adds support for kuery to job wizards (#26094) * [ML] Adds support for kuery to job wizards * [ML] Pass combined query and filters to multi metric model mem calc * [ML] Edits following review --- .../__tests__/datavisualizer_controller.js | 27 +++-- .../datavisualizer_controller.js | 30 +++-- .../advanced/__tests__/new_job_controller.js | 19 ++-- .../new_job/advanced/new_job_controller.js | 6 +- .../bucket_span_estimator_directive.js | 3 +- .../__tests__/create_job_controller.js | 21 ++-- .../create_job/create_job_controller.js | 8 +- .../create_job/create_job_service.js | 7 +- .../__tests__/create_job_controller.js | 21 ++-- .../create_job/create_job_controller.js | 6 +- .../create_job/create_job_service.js | 7 +- .../__tests__/create_job_controller.js | 19 ++-- .../create_job/create_job_controller.js | 5 +- .../create_job/create_job_service.js | 4 +- .../__tests__/create_job_controller.js | 21 ++-- .../create_job/create_job_controller.js | 5 +- .../create_job/create_job_service.js | 7 +- .../jobs/new_job/utils/new_job_utils.js | 104 +++++++----------- .../job_type/__tests__/job_type_controller.js | 26 +++-- .../steps/job_type/job_type_controller.js | 7 +- 20 files changed, 163 insertions(+), 190 deletions(-) diff --git a/x-pack/plugins/ml/public/datavisualizer/__tests__/datavisualizer_controller.js b/x-pack/plugins/ml/public/datavisualizer/__tests__/datavisualizer_controller.js index 0a12a574f7949c..6b70395153598e 100644 --- a/x-pack/plugins/ml/public/datavisualizer/__tests__/datavisualizer_controller.js +++ b/x-pack/plugins/ml/public/datavisualizer/__tests__/datavisualizer_controller.js @@ -11,28 +11,35 @@ import expect from 'expect.js'; import sinon from 'sinon'; // Import this way to be able to stub/mock functions later on in the tests using sinon. -import * as newJobUtils from 'plugins/ml/jobs/new_job/utils/new_job_utils'; import * as indexUtils from 'plugins/ml/util/index_utils'; describe('ML - Data Visualizer View Fields Controller', () => { + + beforeEach(() => { ngMock.module('kibana'); }); it('Initialize Data Visualizer View Fields Controller', (done) => { - const stub1 = sinon.stub(newJobUtils, 'createSearchItems').callsFake(() => ({ - indexPattern: {}, - savedSearch: {}, - combinedQuery: {} - })); - const stub2 = sinon.stub(indexUtils, 'timeBasedIndexCheck').callsFake(() => false); - ngMock.inject(function ($rootScope, $controller) { + const stub = sinon.stub(indexUtils, 'timeBasedIndexCheck').callsFake(() => false); + ngMock.inject(function ($rootScope, $controller, $route) { + // Set up the $route current props required for the tests. + $route.current = { + locals: { + indexPattern: { + id: '' + }, + savedSearch: { + id: '' + } + } + }; + const scope = $rootScope.$new(); $controller('MlDataVisualizerViewFields', { $scope: scope }); expect(scope.metricCards).to.eql([]); - stub1.restore(); - stub2.restore(); + stub.restore(); done(); }); }); diff --git a/x-pack/plugins/ml/public/datavisualizer/datavisualizer_controller.js b/x-pack/plugins/ml/public/datavisualizer/datavisualizer_controller.js index 90af2c638a3eb0..4601e1adfa04d9 100644 --- a/x-pack/plugins/ml/public/datavisualizer/datavisualizer_controller.js +++ b/x-pack/plugins/ml/public/datavisualizer/datavisualizer_controller.js @@ -18,15 +18,15 @@ import 'plugins/ml/components/form_filter_input'; import chrome from 'ui/chrome'; import uiRoutes from 'ui/routes'; -import { notify } from 'ui/notify'; import { decorateQuery, luceneStringToDsl } from '@kbn/es-query'; +import { notify, toastNotifications } from 'ui/notify'; import { ML_JOB_FIELD_TYPES, KBN_FIELD_TYPES } from 'plugins/ml/../common/constants/field_types'; import { kbnTypeToMLJobType } from 'plugins/ml/util/field_types_utils'; import { IntervalHelperProvider } from 'plugins/ml/util/ml_time_buckets'; import { checkBasicLicense, isFullLicense } from 'plugins/ml/license/check_license'; import { checkGetJobsPrivilege } from 'plugins/ml/privilege/check_privilege'; -import { createSearchItems } from 'plugins/ml/jobs/new_job/utils/new_job_utils'; +import { SearchItemsProvider } from 'plugins/ml/jobs/new_job/utils/new_job_utils'; import { loadCurrentIndexPattern, loadCurrentSavedSearch, timeBasedIndexCheck } from 'plugins/ml/util/index_utils'; import { checkMlNodesAvailable } from 'plugins/ml/ml_nodes_check/check_ml_nodes'; import { ml } from 'plugins/ml/services/ml_api_service'; @@ -53,7 +53,6 @@ const module = uiModules.get('apps/ml'); module .controller('MlDataVisualizerViewFields', function ( $scope, - $route, $timeout, $window, Private, @@ -62,9 +61,12 @@ module timefilter.enableTimeRangeSelector(); timefilter.enableAutoRefreshSelector(); + + const createSearchItems = Private(SearchItemsProvider); const { indexPattern, - query } = createSearchItems($route); + query } = createSearchItems(); + timeBasedIndexCheck(indexPattern, true); // List of system fields we don't want to display. @@ -97,20 +99,16 @@ module $scope.showSidebar = isFullLicense(); // Check for a saved query in the AppState or via a savedSearchId in the URL. + // TODO - add in support for lucene queries with filters and Kuery. $scope.searchQueryText = ''; - if (_.has($scope.appState, 'query')) { - // Currently only support lucene syntax. - if (_.get($scope.appState, 'query.language') === 'lucene') { - $scope.searchQueryText = _.get($scope.appState, 'query.query', ''); - } + const queryBarQry = ($scope.appState.query !== undefined) ? ($scope.appState.query) : query; + if (queryBarQry.language === 'lucene') { + $scope.searchQueryText = _.get(queryBarQry, 'query', ''); } else { - // Use the query built from the savedSearchId supplied in the URL. - // If no savedSearchId, the query will default to '*'. - // TODO - when filtering is supported, use the filters part too. - const queryString = _.get(query, 'query_string.query', ''); - if (queryString !== '*') { - $scope.searchQueryText = queryString; - } + toastNotifications.addWarning({ + title: `${(queryBarQry.language !== undefined) ? queryBarQry.language : ''} syntax not supported`, + text: 'The Data Visualizer currently only supports queries using the lucene query syntax.', + }); } $scope.searchQuery = buildSearchQuery(); diff --git a/x-pack/plugins/ml/public/jobs/new_job/advanced/__tests__/new_job_controller.js b/x-pack/plugins/ml/public/jobs/new_job/advanced/__tests__/new_job_controller.js index 8f4f41968ab0fc..618823a01e9198 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/advanced/__tests__/new_job_controller.js +++ b/x-pack/plugins/ml/public/jobs/new_job/advanced/__tests__/new_job_controller.js @@ -7,10 +7,6 @@ import ngMock from 'ng_mock'; import expect from 'expect.js'; -import sinon from 'sinon'; - -// Import this way to be able to stub/mock `createSearchItems` later on in the test using sinon. -import * as newJobUtils from 'plugins/ml/jobs/new_job/utils/new_job_utils'; describe('ML - Advanced Job Wizard - New Job Controller', () => { beforeEach(() => { @@ -18,13 +14,15 @@ describe('ML - Advanced Job Wizard - New Job Controller', () => { }); it('Initialize New Job Controller', (done) => { - const stub = sinon.stub(newJobUtils, 'createSearchItems').callsFake(() => ({ - indexPattern: {}, - savedSearch: {}, - combinedQuery: {} - })); + ngMock.inject(function ($rootScope, $controller, $route) { + // Set up the $route current props required for the tests. + $route.current = { + locals: { + indexPattern: {}, + savedSearch: {} + } + }; - ngMock.inject(function ($rootScope, $controller) { const scope = $rootScope.$new(); $controller('MlNewJob', { $scope: scope }); @@ -32,7 +30,6 @@ describe('ML - Advanced Job Wizard - New Job Controller', () => { // all angularjs based dependencies get loaded without error. // This simple scope test is just a final sanity check. expect(scope.ui.pageTitle).to.be('Create a new job'); - stub.restore(); done(); }); }); diff --git a/x-pack/plugins/ml/public/jobs/new_job/advanced/new_job_controller.js b/x-pack/plugins/ml/public/jobs/new_job/advanced/new_job_controller.js index 3624c63d3a9481..db1a1426c47146 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/advanced/new_job_controller.js +++ b/x-pack/plugins/ml/public/jobs/new_job/advanced/new_job_controller.js @@ -19,7 +19,7 @@ import { checkCreateJobsPrivilege } from 'plugins/ml/privilege/check_privilege'; import template from './new_job.html'; import saveStatusTemplate from 'plugins/ml/jobs/new_job/advanced/save_status_modal/save_status_modal.html'; import { - createSearchItems, + SearchItemsProvider, createJobForSaving, checkCardinalitySuccess, getMinimalValidJob, @@ -76,6 +76,7 @@ module.controller('MlNewJob', $route, $location, $modal, + Private, mlDatafeedService, mlConfirmModalService) { @@ -614,10 +615,11 @@ module.controller('MlNewJob', // if an index pattern or saved search has been added to the url // populate those items in the form and datafeed config function populateFormFromUrl() { + const createSearchItems = Private(SearchItemsProvider); const { indexPattern, savedSearch, - combinedQuery } = createSearchItems($route); + combinedQuery } = createSearchItems(); if (indexPattern.id !== undefined) { timeBasedIndexCheck(indexPattern, true); diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/components/bucket_span_estimator/bucket_span_estimator_directive.js b/x-pack/plugins/ml/public/jobs/new_job/simple/components/bucket_span_estimator/bucket_span_estimator_directive.js index a4fa1979a62a9c..1c82530cd5809b 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/simple/components/bucket_span_estimator/bucket_span_estimator_directive.js +++ b/x-pack/plugins/ml/public/jobs/new_job/simple/components/bucket_span_estimator/bucket_span_estimator_directive.js @@ -8,7 +8,6 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { BucketSpanEstimator } from './bucket_span_estimator_view'; -import { getQueryFromSavedSearch } from 'plugins/ml/jobs/new_job/utils/new_job_utils'; import { EVENT_RATE_COUNT_FIELD } from 'plugins/ml/jobs/new_job/simple/components/constants/general'; import { ml } from 'plugins/ml/services/ml_api_service'; @@ -57,7 +56,7 @@ module.directive('mlBucketSpanEstimator', function () { fields: [], filters: $scope.formConfig.filters, index: $scope.formConfig.indexPattern.title, - query: getQueryFromSavedSearch($scope.formConfig), + query: $scope.formConfig.combinedQuery, splitField: $scope.formConfig.splitField && $scope.formConfig.splitField.name, timeField: $scope.formConfig.timeField }; diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/multi_metric/create_job/__tests__/create_job_controller.js b/x-pack/plugins/ml/public/jobs/new_job/simple/multi_metric/create_job/__tests__/create_job_controller.js index 74031afc7a7155..07bb4ce902dc2f 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/simple/multi_metric/create_job/__tests__/create_job_controller.js +++ b/x-pack/plugins/ml/public/jobs/new_job/simple/multi_metric/create_job/__tests__/create_job_controller.js @@ -11,7 +11,6 @@ import expect from 'expect.js'; import sinon from 'sinon'; // Import this way to be able to stub/mock functions later on in the tests using sinon. -import * as newJobUtils from 'plugins/ml/jobs/new_job/utils/new_job_utils'; import * as indexUtils from 'plugins/ml/util/index_utils'; import * as utils from 'plugins/ml/jobs/new_job/simple/components/utils/create_fields'; @@ -21,21 +20,23 @@ describe('ML - Multi Metric Wizard - Create Job Controller', () => { }); it('Initialize Create Job Controller', (done) => { - const stub1 = sinon.stub(newJobUtils, 'createSearchItems').callsFake(() => ({ - indexPattern: {}, - savedSearch: {}, - combinedQuery: {} - })); - const stub2 = sinon.stub(indexUtils, 'timeBasedIndexCheck').callsFake(() => false); - const stub3 = sinon.stub(utils, 'createFields').callsFake(() => false); - ngMock.inject(function ($rootScope, $controller) { + const stub1 = sinon.stub(indexUtils, 'timeBasedIndexCheck').callsFake(() => false); + const stub2 = sinon.stub(utils, 'createFields').callsFake(() => false); + ngMock.inject(function ($rootScope, $controller, $route) { + // Set up the $route current props required for the tests. + $route.current = { + locals: { + indexPattern: {}, + savedSearch: {} + } + }; + const scope = $rootScope.$new(); $controller('MlCreateMultiMetricJob', { $scope: scope }); expect(typeof scope.ui).to.eql('object'); stub1.restore(); stub2.restore(); - stub3.restore(); done(); }); }); diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/multi_metric/create_job/create_job_controller.js b/x-pack/plugins/ml/public/jobs/new_job/simple/multi_metric/create_job/create_job_controller.js index 8c93eee273eae4..681315856a104e 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/simple/multi_metric/create_job/create_job_controller.js +++ b/x-pack/plugins/ml/public/jobs/new_job/simple/multi_metric/create_job/create_job_controller.js @@ -30,7 +30,7 @@ import { checkMlNodesAvailable } from 'plugins/ml/ml_nodes_check/check_ml_nodes' import { loadNewJobDefaults } from 'plugins/ml/jobs/new_job/utils/new_job_defaults'; import { mlEscape } from 'plugins/ml/util/string_utils'; import { - createSearchItems, + SearchItemsProvider, addNewJobToRecentlyAccessed, moveToAdvancedJobCreationProvider, focusOnResultsLink } from 'plugins/ml/jobs/new_job/utils/new_job_utils'; @@ -64,7 +64,6 @@ const module = uiModules.get('apps/ml'); module .controller('MlCreateMultiMetricJob', function ( $scope, - $route, $timeout, Private, AppState) { @@ -109,12 +108,13 @@ module // flag to stop all results polling if the user navigates away from this page let globalForceStop = false; + const createSearchItems = Private(SearchItemsProvider); const { indexPattern, savedSearch, query, filters, - combinedQuery } = createSearchItems($route); + combinedQuery } = createSearchItems(); timeBasedIndexCheck(indexPattern, true); @@ -642,7 +642,7 @@ module ml.calculateModelMemoryLimit({ indexPattern: formConfig.indexPattern.title, splitFieldName: formConfig.splitField.name, - query: formConfig.query, + query: formConfig.combinedQuery, fieldNames: Object.keys(formConfig.fields), influencerNames: formConfig.influencerFields.map(f => f.name), timeFieldName: formConfig.timeField, diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/multi_metric/create_job/create_job_service.js b/x-pack/plugins/ml/public/jobs/new_job/simple/multi_metric/create_job/create_job_service.js index 66db8d98461c72..419d67cb11d5aa 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/simple/multi_metric/create_job/create_job_service.js +++ b/x-pack/plugins/ml/public/jobs/new_job/simple/multi_metric/create_job/create_job_service.js @@ -212,12 +212,7 @@ export function MultiMetricJobServiceProvider() { job.analysis_config.influencers = influencerFields; } - let query = { - match_all: {} - }; - if (formConfig.query.query_string.query !== '*' || formConfig.filters.length) { - query = formConfig.combinedQuery; - } + const query = formConfig.combinedQuery; job.analysis_config.bucket_span = formConfig.bucketSpan; diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/population/create_job/__tests__/create_job_controller.js b/x-pack/plugins/ml/public/jobs/new_job/simple/population/create_job/__tests__/create_job_controller.js index 9cedc38106e9c3..b0987aada5bd93 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/simple/population/create_job/__tests__/create_job_controller.js +++ b/x-pack/plugins/ml/public/jobs/new_job/simple/population/create_job/__tests__/create_job_controller.js @@ -11,7 +11,6 @@ import expect from 'expect.js'; import sinon from 'sinon'; // Import this way to be able to stub/mock functions later on in the tests using sinon. -import * as newJobUtils from 'plugins/ml/jobs/new_job/utils/new_job_utils'; import * as indexUtils from 'plugins/ml/util/index_utils'; import * as utils from 'plugins/ml/jobs/new_job/simple/components/utils/create_fields'; @@ -21,21 +20,23 @@ describe('ML - Population Wizard - Create Job Controller', () => { }); it('Initialize Create Job Controller', (done) => { - const stub1 = sinon.stub(newJobUtils, 'createSearchItems').callsFake(() => ({ - indexPattern: {}, - savedSearch: {}, - combinedQuery: {} - })); - const stub2 = sinon.stub(indexUtils, 'timeBasedIndexCheck').callsFake(() => false); - const stub3 = sinon.stub(utils, 'createFields').callsFake(() => false); - ngMock.inject(function ($rootScope, $controller) { + const stub1 = sinon.stub(indexUtils, 'timeBasedIndexCheck').callsFake(() => false); + const stub2 = sinon.stub(utils, 'createFields').callsFake(() => false); + ngMock.inject(function ($rootScope, $controller, $route) { + // Set up the $route current props required for the tests. + $route.current = { + locals: { + indexPattern: {}, + savedSearch: {} + } + }; + const scope = $rootScope.$new(); $controller('MlCreatePopulationJob', { $scope: scope }); expect(typeof scope.ui).to.eql('object'); stub1.restore(); stub2.restore(); - stub3.restore(); done(); }); }); diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/population/create_job/create_job_controller.js b/x-pack/plugins/ml/public/jobs/new_job/simple/population/create_job/create_job_controller.js index f72602946a2885..e52bda175a694f 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/simple/population/create_job/create_job_controller.js +++ b/x-pack/plugins/ml/public/jobs/new_job/simple/population/create_job/create_job_controller.js @@ -30,7 +30,7 @@ import { checkMlNodesAvailable } from 'plugins/ml/ml_nodes_check/check_ml_nodes' import { loadNewJobDefaults, newJobDefaults } from 'plugins/ml/jobs/new_job/utils/new_job_defaults'; import { mlEscape } from 'plugins/ml/util/string_utils'; import { - createSearchItems, + SearchItemsProvider, addNewJobToRecentlyAccessed, moveToAdvancedJobCreationProvider, focusOnResultsLink } from 'plugins/ml/jobs/new_job/utils/new_job_utils'; @@ -63,7 +63,6 @@ const module = uiModules.get('apps/ml'); module .controller('MlCreatePopulationJob', function ( $scope, - $route, $timeout, Private, AppState) { @@ -109,12 +108,13 @@ module // flag to stop all results polling if the user navigates away from this page let globalForceStop = false; + const createSearchItems = Private(SearchItemsProvider); const { indexPattern, savedSearch, query, filters, - combinedQuery } = createSearchItems($route); + combinedQuery } = createSearchItems(); timeBasedIndexCheck(indexPattern, true); diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/population/create_job/create_job_service.js b/x-pack/plugins/ml/public/jobs/new_job/simple/population/create_job/create_job_service.js index 4fa742533bc721..9ffc5ea8da65fe 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/simple/population/create_job/create_job_service.js +++ b/x-pack/plugins/ml/public/jobs/new_job/simple/population/create_job/create_job_service.js @@ -244,12 +244,7 @@ export function PopulationJobServiceProvider(Private) { job.analysis_config.influencers = influencerFields; } - let query = { - match_all: {} - }; - if (formConfig.query.query_string.query !== '*' || formConfig.filters.length) { - query = formConfig.combinedQuery; - } + const query = formConfig.combinedQuery; job.analysis_config.bucket_span = formConfig.bucketSpan; diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/recognize/create_job/__tests__/create_job_controller.js b/x-pack/plugins/ml/public/jobs/new_job/simple/recognize/create_job/__tests__/create_job_controller.js index 786d06afbc40e2..c52a06219b0a68 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/simple/recognize/create_job/__tests__/create_job_controller.js +++ b/x-pack/plugins/ml/public/jobs/new_job/simple/recognize/create_job/__tests__/create_job_controller.js @@ -8,10 +8,7 @@ import ngMock from 'ng_mock'; import expect from 'expect.js'; -import sinon from 'sinon'; -// Import this way to be able to stub/mock functions later on in the tests using sinon. -import * as newJobUtils from 'plugins/ml/jobs/new_job/utils/new_job_utils'; describe('ML - Recognize Wizard - Create Job Controller', () => { beforeEach(() => { @@ -19,12 +16,15 @@ describe('ML - Recognize Wizard - Create Job Controller', () => { }); it('Initialize Create Job Controller', (done) => { - const stub = sinon.stub(newJobUtils, 'createSearchItems').callsFake(() => ({ - indexPattern: {}, - savedSearch: {}, - combinedQuery: {} - })); - ngMock.inject(function ($rootScope, $controller) { + ngMock.inject(function ($rootScope, $controller, $route) { + // Set up the $route current props required for the tests. + $route.current = { + locals: { + indexPattern: {}, + savedSearch: {} + } + }; + const scope = $rootScope.$new(); $controller('MlCreateRecognizerJobs', { $route: { @@ -36,7 +36,6 @@ describe('ML - Recognize Wizard - Create Job Controller', () => { }); expect(scope.ui.formValid).to.eql(true); - stub.restore(); done(); }); }); diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/recognize/create_job/create_job_controller.js b/x-pack/plugins/ml/public/jobs/new_job/simple/recognize/create_job/create_job_controller.js index cf29ea5a4802ac..52cad3cc73ee48 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/simple/recognize/create_job/create_job_controller.js +++ b/x-pack/plugins/ml/public/jobs/new_job/simple/recognize/create_job/create_job_controller.js @@ -10,7 +10,7 @@ import _ from 'lodash'; import angular from 'angular'; import dateMath from '@kbn/datemath'; import { isJobIdValid, prefixDatafeedId } from 'plugins/ml/../common/util/job_utils'; -import { createSearchItems, addNewJobToRecentlyAccessed } from 'plugins/ml/jobs/new_job/utils/new_job_utils'; +import { SearchItemsProvider, addNewJobToRecentlyAccessed } from 'plugins/ml/jobs/new_job/utils/new_job_utils'; import uiRoutes from 'ui/routes'; @@ -81,11 +81,12 @@ module const moduleId = $route.current.params.id; $scope.moduleId = moduleId; + const createSearchItems = Private(SearchItemsProvider); const { indexPattern, savedSearch, query, - combinedQuery } = createSearchItems($route); + combinedQuery } = createSearchItems(); const pageTitle = (savedSearch.id !== undefined) ? `saved search ${savedSearch.title}` : `index pattern ${indexPattern.title}`; diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/recognize/create_job/create_job_service.js b/x-pack/plugins/ml/public/jobs/new_job/simple/recognize/create_job/create_job_service.js index 751d614a68b251..e0a5c3ef95df13 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/simple/recognize/create_job/create_job_service.js +++ b/x-pack/plugins/ml/public/jobs/new_job/simple/recognize/create_job/create_job_service.js @@ -5,8 +5,6 @@ */ - -import { getQueryFromSavedSearch } from 'plugins/ml/jobs/new_job/utils/new_job_utils'; import { SavedObjectsClientProvider } from 'ui/saved_objects'; import { mlJobService } from 'plugins/ml/services/job_service'; import { ml } from 'plugins/ml/services/ml_api_service'; @@ -41,7 +39,7 @@ export function CreateRecognizerJobsServiceProvider(Private) { } indexTimeRange(indexPattern, formConfig) { - const query = getQueryFromSavedSearch(formConfig); + const query = formConfig.combinedQuery; return ml.getTimeFieldRange({ index: indexPattern.title, timeFieldName: indexPattern.timeFieldName, diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/single_metric/create_job/__tests__/create_job_controller.js b/x-pack/plugins/ml/public/jobs/new_job/simple/single_metric/create_job/__tests__/create_job_controller.js index bc9ba3a250262d..0658c723126e06 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/simple/single_metric/create_job/__tests__/create_job_controller.js +++ b/x-pack/plugins/ml/public/jobs/new_job/simple/single_metric/create_job/__tests__/create_job_controller.js @@ -11,7 +11,6 @@ import expect from 'expect.js'; import sinon from 'sinon'; // Import this way to be able to stub/mock functions later on in the tests using sinon. -import * as newJobUtils from 'plugins/ml/jobs/new_job/utils/new_job_utils'; import * as indexUtils from 'plugins/ml/util/index_utils'; describe('ML - Single Metric Wizard - Create Job Controller', () => { @@ -20,13 +19,16 @@ describe('ML - Single Metric Wizard - Create Job Controller', () => { }); it('Initialize Create Job Controller', (done) => { - const stub1 = sinon.stub(newJobUtils, 'createSearchItems').callsFake(() => ({ - indexPattern: {}, - savedSearch: {}, - combinedQuery: {} - })); - const stub2 = sinon.stub(indexUtils, 'timeBasedIndexCheck').callsFake(() => false); - ngMock.inject(function ($rootScope, $controller) { + const stub = sinon.stub(indexUtils, 'timeBasedIndexCheck').callsFake(() => false); + ngMock.inject(function ($rootScope, $controller, $route) { + // Set up the $route current props required for the tests. + $route.current = { + locals: { + indexPattern: {}, + savedSearch: {} + } + }; + const scope = $rootScope.$new(); $controller('MlCreateSingleMetricJob', { $route: { @@ -38,8 +40,7 @@ describe('ML - Single Metric Wizard - Create Job Controller', () => { }); expect(scope.ui.showJobInput).to.eql(false); - stub1.restore(); - stub2.restore(); + stub.restore(); done(); }); }); diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/single_metric/create_job/create_job_controller.js b/x-pack/plugins/ml/public/jobs/new_job/simple/single_metric/create_job/create_job_controller.js index b6cfed211f01e2..2f2cfe2fa0443d 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/simple/single_metric/create_job/create_job_controller.js +++ b/x-pack/plugins/ml/public/jobs/new_job/simple/single_metric/create_job/create_job_controller.js @@ -30,7 +30,7 @@ import { loadCurrentIndexPattern, loadCurrentSavedSearch, timeBasedIndexCheck } import { checkMlNodesAvailable } from 'plugins/ml/ml_nodes_check/check_ml_nodes'; import { loadNewJobDefaults } from 'plugins/ml/jobs/new_job/utils/new_job_defaults'; import { - createSearchItems, + SearchItemsProvider, addNewJobToRecentlyAccessed, moveToAdvancedJobCreationProvider, focusOnResultsLink } from 'plugins/ml/jobs/new_job/utils/new_job_utils'; @@ -114,12 +114,13 @@ module // flag to stop all results polling if the user navigates away from this page let globalForceStop = false; + const createSearchItems = Private(SearchItemsProvider); const { indexPattern, savedSearch, query, filters, - combinedQuery } = createSearchItems($route); + combinedQuery } = createSearchItems(); timeBasedIndexCheck(indexPattern, true); diff --git a/x-pack/plugins/ml/public/jobs/new_job/simple/single_metric/create_job/create_job_service.js b/x-pack/plugins/ml/public/jobs/new_job/simple/single_metric/create_job/create_job_service.js index 8accd028ffd528..37d7ac1ebbd86a 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/simple/single_metric/create_job/create_job_service.js +++ b/x-pack/plugins/ml/public/jobs/new_job/simple/single_metric/create_job/create_job_service.js @@ -132,12 +132,7 @@ export function SingleMetricJobServiceProvider() { function: func }; - let query = { - match_all: {} - }; - if (formConfig.query.query_string.query !== '*' || formConfig.filters.length) { - query = formConfig.combinedQuery; - } + const query = formConfig.combinedQuery; if (formConfig.field && formConfig.field.id) { dtr.field_name = formConfig.field.id; diff --git a/x-pack/plugins/ml/public/jobs/new_job/utils/new_job_utils.js b/x-pack/plugins/ml/public/jobs/new_job/utils/new_job_utils.js index 7bc55750634c41..11132e10b6e88e 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/utils/new_job_utils.js +++ b/x-pack/plugins/ml/public/jobs/new_job/utils/new_job_utils.js @@ -8,85 +8,63 @@ import _ from 'lodash'; import $ from 'jquery'; -import { migrateFilter } from '@kbn/es-query'; +import { BuildESQueryProvider } from '@kbn/es-query'; import { addItemToRecentlyAccessed } from 'plugins/ml/util/recently_accessed'; import { mlJobService } from 'plugins/ml/services/job_service'; -export function getQueryFromSavedSearch(formConfig) { - const must = []; - const mustNot = []; - must.push(formConfig.query); +// Provider for creating the items used for searching and job creation. +// Uses the $route object to retrieve the indexPattern and savedSearch from the url +export function SearchItemsProvider(Private, $route) { - formConfig.filters.forEach((f) => { - let query = (f.query || f); - query = _.omit(query, ['meta', '$state']); - query = migrateFilter(query); + const buildESQuery = Private(BuildESQueryProvider); - if(f.meta.disabled === false) { - if(f.meta.negate) { - mustNot.push(query); - } else { - must.push(query); + function createSearchItems() { + let indexPattern = $route.current.locals.indexPattern; + + let query = { + query: '*', + language: 'lucene' + }; + + let combinedQuery = { + bool: { + must: [{ + query_string: { + analyze_wildcard: true, + query: '*' + } + }] } - } - }); + }; - return { - bool: { - must, - must_not: mustNot - } - }; -} + let filters = []; -// create items used for searching and job creation. -// takes the $route object to retrieve the indexPattern and savedSearch from the url -export function createSearchItems($route) { - let indexPattern = $route.current.locals.indexPattern; - const query = { - query_string: { - analyze_wildcard: true, - query: '*' - } - }; + const savedSearch = $route.current.locals.savedSearch; + if (indexPattern.id === undefined && savedSearch.id !== undefined) { + const searchSource = savedSearch.searchSource; + indexPattern = searchSource.getField('index'); + + query = searchSource.getField('query'); + const fs = searchSource.getField('filter'); - let filters = []; - const savedSearch = $route.current.locals.savedSearch; - const searchSource = savedSearch.searchSource; - - if (indexPattern.id === undefined && - savedSearch.id !== undefined) { - indexPattern = searchSource.getField('index'); - - // Extract the query from the searchSource - // Might be as a String in q.query, or - // nested inside q.query.query_string - const q = searchSource.getField('query'); - if (q !== undefined && q.language === 'lucene' && q.query !== undefined) { - if (typeof q.query === 'string' && q.query !== '') { - query.query_string.query = q.query; - } else if (typeof q.query === 'object' && - typeof q.query.query_string === 'object' && q.query.query_string.query !== '') { - query.query_string.query = q.query.query_string.query; + if (fs.length) { + filters = fs; } - } - const fs = searchSource.getField('filter'); - if (fs.length) { - filters = fs; + combinedQuery = buildESQuery(indexPattern, [query], filters); } + return { + indexPattern, + savedSearch, + filters, + query, + combinedQuery + }; } - const combinedQuery = getQueryFromSavedSearch({ query, filters }); - return { - indexPattern, - savedSearch, - filters, - query, - combinedQuery - }; + return createSearchItems; } export function createJobForSaving(job) { diff --git a/x-pack/plugins/ml/public/jobs/new_job/wizard/steps/job_type/__tests__/job_type_controller.js b/x-pack/plugins/ml/public/jobs/new_job/wizard/steps/job_type/__tests__/job_type_controller.js index 9786df1976c7c0..6bc48a5c602475 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/wizard/steps/job_type/__tests__/job_type_controller.js +++ b/x-pack/plugins/ml/public/jobs/new_job/wizard/steps/job_type/__tests__/job_type_controller.js @@ -11,7 +11,6 @@ import expect from 'expect.js'; import sinon from 'sinon'; // Import this way to be able to stub/mock functions later on in the tests using sinon. -import * as newJobUtils from 'plugins/ml/jobs/new_job/utils/new_job_utils'; import * as indexUtils from 'plugins/ml/util/index_utils'; describe('ML - Job Type Controller', () => { @@ -20,19 +19,24 @@ describe('ML - Job Type Controller', () => { }); it('Initialize Job Type Controller', (done) => { - const stub1 = sinon.stub(newJobUtils, 'createSearchItems').callsFake(() => ({ - indexPattern: {}, - savedSearch: {}, - combinedQuery: {} - })); - const stub2 = sinon.stub(indexUtils, 'timeBasedIndexCheck').callsFake(() => false); - ngMock.inject(function ($rootScope, $controller) { + const stub = sinon.stub(indexUtils, 'timeBasedIndexCheck').callsFake(() => false); + ngMock.inject(function ($rootScope, $controller, $route) { + // Set up the $route current props required for the tests. + $route.current = { + locals: { + indexPattern: { + id: 'test_id', + title: 'test_pattern' + }, + savedSearch: {} + } + }; + const scope = $rootScope.$new(); $controller('MlNewJobStepJobType', { $scope: scope }); - expect(scope.indexWarningTitle).to.eql('Index pattern undefined is not time based'); - stub1.restore(); - stub2.restore(); + expect(scope.indexWarningTitle).to.eql('Index pattern test_pattern is not time based'); + stub.restore(); done(); }); }); diff --git a/x-pack/plugins/ml/public/jobs/new_job/wizard/steps/job_type/job_type_controller.js b/x-pack/plugins/ml/public/jobs/new_job/wizard/steps/job_type/job_type_controller.js index 7cf771bbadedc3..87b0f266af4abf 100644 --- a/x-pack/plugins/ml/public/jobs/new_job/wizard/steps/job_type/job_type_controller.js +++ b/x-pack/plugins/ml/public/jobs/new_job/wizard/steps/job_type/job_type_controller.js @@ -14,7 +14,7 @@ import uiRoutes from 'ui/routes'; import { checkLicenseExpired } from 'plugins/ml/license/check_license'; import { checkCreateJobsPrivilege } from 'plugins/ml/privilege/check_privilege'; -import { createSearchItems } from 'plugins/ml/jobs/new_job/utils/new_job_utils'; +import { SearchItemsProvider } from 'plugins/ml/jobs/new_job/utils/new_job_utils'; import { loadCurrentIndexPattern, loadCurrentSavedSearch, timeBasedIndexCheck } from 'plugins/ml/util/index_utils'; import { addItemToRecentlyAccessed } from 'plugins/ml/util/recently_accessed'; import { checkMlNodesAvailable } from 'plugins/ml/ml_nodes_check/check_ml_nodes'; @@ -42,14 +42,15 @@ const module = uiModules.get('apps/ml'); module.controller('MlNewJobStepJobType', function ( $scope, - $route) { + Private) { timefilter.disableTimeRangeSelector(); // remove time picker from top of page timefilter.disableAutoRefreshSelector(); // remove time picker from top of page + const createSearchItems = Private(SearchItemsProvider); const { indexPattern, - savedSearch } = createSearchItems($route); + savedSearch } = createSearchItems(); // check to see that the index pattern is time based. // if it isn't, display a warning and disable all links