Simplify Courier interface and organize internals (#20060)

**Interface changes**

There are two goals behind the interface changes:

* Make it clearer which courier modules are meant for public consumption by exporting them from the top level.
* Simplify the courier object by removing responsibilities and focusing its responsibility solely on scheduling search requests via the fetch method and timefilter.refreshInterval Angular event.

I did this by taking the following steps:

* Removing redirectWhenMissing, indexPatterns, SearchSource, and SavedObject from the courier object. I also removed some unused methods from its interface.
* redirectWhenMissing is now a service registered on the kibana/url Angular module.
* indexPatterns is now a service registered on the kibana/index_patterns Angular module.
* SearchSourceProvider and SavedObjectProvider are now top-level exports of ui/courier.
* migrateFilter, decorateQuery, buildQueryFromFilters, and luceneStringToDsl are now top-level exports of ui/courier.

**Internal changes**

I also made some internal changes in an effort to organize the code clearly and reduce unnecessary complexity.

* I refactored the async code in CallClient to appear sync with async/await and encapsulated chunks of logic in helper functions. I also used an isAborted flag instead of overwriting the esPromise var with an enum.
* I combined Looper and SearchLooper into a single class and deleted unused functions.
* I reorganized the courier/fetch/request code into SearchRequest, SegmentedSearchRequest, and serializeFetchParams modules.
* Renamed various other methods and variables to improve clarity.
This commit is contained in:
CJ Cenizal 2018-06-27 16:58:19 -07:00 committed by GitHub
parent c8185cfef5
commit 3ea4c3e0bc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
100 changed files with 632 additions and 605 deletions

View file

@ -19,15 +19,13 @@
import sinon from 'sinon';
export function createCourierStub() {
export function createIndexPatternsStub() {
return {
indexPatterns: {
get: sinon.spy(indexPatternId =>
Promise.resolve({
id: indexPatternId,
})
),
},
get: sinon.spy(indexPatternId =>
Promise.resolve({
id: indexPatternId,
})
),
};
}

View file

@ -21,8 +21,8 @@ import expect from 'expect.js';
import ngMock from 'ng_mock';
import sinon from 'sinon';
import { createCourierStub } from './_stubs';
import { SearchSourceProvider } from 'ui/courier/data_source/search_source';
import { createIndexPatternsStub } from './_stubs';
import { SearchSourceProvider } from 'ui/courier';
import { fetchAnchorProvider } from '../anchor';
@ -35,7 +35,7 @@ describe('context app', function () {
let SearchSourceStub;
beforeEach(ngMock.module(function createServiceStubs($provide) {
$provide.value('courier', createCourierStub());
$provide.value('indexPatterns', createIndexPatternsStub());
}));
beforeEach(ngMock.inject(function createPrivateStubs(Private) {

View file

@ -21,8 +21,8 @@ import expect from 'expect.js';
import ngMock from 'ng_mock';
import * as _ from 'lodash';
import { createCourierStub, createSearchSourceStubProvider } from './_stubs';
import { SearchSourceProvider } from 'ui/courier/data_source/search_source';
import { createIndexPatternsStub, createSearchSourceStubProvider } from './_stubs';
import { SearchSourceProvider } from 'ui/courier';
import { fetchContextProvider } from '../context';
@ -36,7 +36,7 @@ describe('context app', function () {
let getSearchSourceStub;
beforeEach(ngMock.module(function createServiceStubs($provide) {
$provide.value('courier', createCourierStub());
$provide.value('indexPatterns', createIndexPatternsStub());
}));
beforeEach(ngMock.inject(function createPrivateStubs(Private) {

View file

@ -21,8 +21,8 @@ import expect from 'expect.js';
import ngMock from 'ng_mock';
import * as _ from 'lodash';
import { createCourierStub, createSearchSourceStubProvider } from './_stubs';
import { SearchSourceProvider } from 'ui/courier/data_source/search_source';
import { createIndexPatternsStub, createSearchSourceStubProvider } from './_stubs';
import { SearchSourceProvider } from 'ui/courier';
import { fetchContextProvider } from '../context';
@ -36,7 +36,7 @@ describe('context app', function () {
let getSearchSourceStub;
beforeEach(ngMock.module(function createServiceStubs($provide) {
$provide.value('courier', createCourierStub());
$provide.value('indexPatterns', createIndexPatternsStub());
}));
beforeEach(ngMock.inject(function createPrivateStubs(Private) {

View file

@ -19,9 +19,9 @@
import _ from 'lodash';
import { SearchSourceProvider } from 'ui/courier/data_source/search_source';
import { SearchSourceProvider } from 'ui/courier';
export function fetchAnchorProvider(courier, Private) {
export function fetchAnchorProvider(indexPatterns, Private) {
const SearchSource = Private(SearchSourceProvider);
return async function fetchAnchor(
@ -30,8 +30,7 @@ export function fetchAnchorProvider(courier, Private) {
anchorId,
sort
) {
const indexPattern = await courier.indexPatterns.get(indexPatternId);
const indexPattern = await indexPatterns.get(indexPatternId);
const searchSource = new SearchSource()
.inherits(false)
.set('index', indexPattern)

View file

@ -20,7 +20,7 @@
// @ts-ignore
import { SearchSourceProvider } from 'ui/courier/data_source/search_source';
import { SearchSourceProvider } from 'ui/courier';
import { reverseSortDirection } from './utils/sorting';
@ -46,7 +46,7 @@ const DAY_MILLIS = 24 * 60 * 60 * 1000;
// look from 1 day up to 10000 days into the past and future
const LOOKUP_OFFSETS = [0, 1, 7, 30, 365, 10000].map((days) => days * DAY_MILLIS);
function fetchContextProvider(courier, Private) {
function fetchContextProvider(indexPatterns, Private) {
/**
* @type {{new(): SearchSourceT}}
*/
@ -159,7 +159,7 @@ function fetchContextProvider(courier, Private) {
* @returns {Promise<Object>}
*/
async function createSearchSource(indexPatternId, filters) {
const indexPattern = await courier.indexPatterns.get(indexPatternId);
const indexPattern = await indexPatterns.get(indexPatternId);
return new SearchSource()
.inherits(false)

View file

@ -31,8 +31,8 @@ uiRoutes
controller: ContextAppRouteController,
controllerAs: 'contextAppRoute',
resolve: {
indexPattern: function ($route, courier) {
return courier.indexPatterns.get($route.current.params.indexPatternId);
indexPattern: function ($route, indexPatterns) {
return indexPatterns.get($route.current.params.indexPatternId);
},
},
template: contextAppRouteTemplate,

View file

@ -27,7 +27,7 @@ import {
} from './constants';
export function QueryParameterActionsProvider(courier, Private) {
export function QueryParameterActionsProvider(indexPatterns, Private) {
const filterManager = Private(FilterManagerProvider);
const setPredecessorCount = (state) => (predecessorCount) => (
@ -68,7 +68,7 @@ export function QueryParameterActionsProvider(courier, Private) {
const addFilter = (state) => async (field, values, operation) => {
const indexPatternId = state.queryParameters.indexPatternId;
filterManager.add(field, values, operation, indexPatternId);
const indexPattern = await courier.indexPatterns.get(indexPatternId);
const indexPattern = await indexPatterns.get(indexPatternId);
indexPattern.popularizeField(field.name, 1);
};

View file

@ -21,8 +21,7 @@
import _ from 'lodash';
import { FilterBarQueryFilterProvider } from 'ui/filter_bar/query_filter';
import 'ui/state_management/app_state';
import { luceneStringToDsl } from '../../../../ui/public/courier/data_source/build_query/lucene_string_to_dsl';
import { migrateFilter } from 'ui/courier/data_source/_migrate_filter';
import { luceneStringToDsl, migrateFilter } from 'ui/courier';
export function dashboardContextProvider(Private, getAppState) {
return () => {

View file

@ -66,7 +66,7 @@ uiRoutes
$scope.initialFilter = ($location.search()).filter || EMPTY_FILTER;
},
resolve: {
dash: function ($route, Private, courier, kbnUrl) {
dash: function ($route, Private, redirectWhenMissing, kbnUrl) {
const savedObjectsClient = Private(SavedObjectsClientProvider);
const title = $route.current.params.title;
if (title) {
@ -84,7 +84,7 @@ uiRoutes
kbnUrl.redirect(`${DashboardConstants.LANDING_PAGE_PATH}?filter="${title}"`);
}
throw uiRoutes.WAIT_FOR_URL_CHANGE_TOKEN;
}).catch(courier.redirectWhenMissing({
}).catch(redirectWhenMissing({
'dashboard': DashboardConstants.LANDING_PAGE_PATH
}));
}
@ -94,9 +94,9 @@ uiRoutes
.when(DashboardConstants.CREATE_NEW_DASHBOARD_URL, {
template: dashboardTemplate,
resolve: {
dash: function (savedDashboards, courier) {
dash: function (savedDashboards, redirectWhenMissing) {
return savedDashboards.get()
.catch(courier.redirectWhenMissing({
.catch(redirectWhenMissing({
'dashboard': DashboardConstants.LANDING_PAGE_PATH
}));
}
@ -105,7 +105,7 @@ uiRoutes
.when(createDashboardEditUrl(':id'), {
template: dashboardTemplate,
resolve: {
dash: function (savedDashboards, Notifier, $route, $location, courier, kbnUrl, AppState) {
dash: function (savedDashboards, Notifier, $route, $location, redirectWhenMissing, kbnUrl, AppState) {
const id = $route.current.params.id;
return savedDashboards.get(id)
@ -124,7 +124,7 @@ uiRoutes
throw error;
}
})
.catch(courier.redirectWhenMissing({
.catch(redirectWhenMissing({
'dashboard': DashboardConstants.LANDING_PAGE_PATH
}));
}

View file

@ -21,14 +21,16 @@ import angular from 'angular';
import { uiModules } from 'ui/modules';
import { createDashboardEditUrl } from '../dashboard_constants';
import { createLegacyClass } from 'ui/utils/legacy_class';
import { SavedObjectProvider } from 'ui/courier';
const module = uiModules.get('app/dashboard');
// Used only by the savedDashboards service, usually no reason to change this
module.factory('SavedDashboard', function (courier, config) {
module.factory('SavedDashboard', function (Private, config) {
// SavedDashboard constructor. Usually you'd interact with an instance of this.
// ID is option, without it one will be generated on save.
createLegacyClass(SavedDashboard).inherits(courier.SavedObject);
const SavedObject = Private(SavedObjectProvider);
createLegacyClass(SavedDashboard).inherits(SavedObject);
function SavedDashboard(id) {
// Gives our SavedDashboard the properties of a SavedObject
SavedDashboard.Super.call(this, {

View file

@ -57,6 +57,7 @@ import '../components/fetch_error';
const app = uiModules.get('apps/discover', [
'kibana/notify',
'kibana/courier',
'kibana/url',
'kibana/index_patterns'
]);
@ -68,7 +69,7 @@ uiRoutes
template: indexTemplate,
reloadOnSearch: false,
resolve: {
ip: function (Promise, courier, config, $location, Private) {
ip: function (Promise, indexPatterns, config, $location, Private) {
const State = Private(StateProvider);
const savedObjectsClient = Private(SavedObjectsClientProvider);
@ -96,13 +97,13 @@ uiRoutes
return Promise.props({
list: savedObjects,
loaded: courier.indexPatterns.get(id),
loaded: indexPatterns.get(id),
stateVal: state.index,
stateValFound: specified && exists
});
});
},
savedSearch: function (courier, savedSearches, $route) {
savedSearch: function (redirectWhenMissing, savedSearches, $route) {
const savedSearchId = $route.current.params.id;
return savedSearches.get(savedSearchId)
.then((savedSearch) => {
@ -114,7 +115,7 @@ uiRoutes
}
return savedSearch;
})
.catch(courier.redirectWhenMissing({
.catch(redirectWhenMissing({
'search': '/discover',
'index-pattern': '/management/kibana/objects/savedSearches/' + $route.current.params.id
}));

View file

@ -20,16 +20,18 @@
import 'ui/notify';
import { uiModules } from 'ui/modules';
import { createLegacyClass } from 'ui/utils/legacy_class';
import { SavedObjectProvider } from 'ui/courier';
const module = uiModules.get('discover/saved_searches', [
'kibana/notify',
'kibana/courier'
]);
module.factory('SavedSearch', function (courier) {
createLegacyClass(SavedSearch).inherits(courier.SavedObject);
module.factory('SavedSearch', function (Private) {
const SavedObject = Private(SavedObjectProvider);
createLegacyClass(SavedSearch).inherits(SavedObject);
function SavedSearch(id) {
courier.SavedObject.call(this, {
SavedObject.call(this, {
type: SavedSearch.type,
mapping: SavedSearch.mapping,
searchSource: SavedSearch.searchSource,

View file

@ -35,8 +35,8 @@ const app = uiModules.get('apps/doc', [
const resolveIndexPattern = {
indexPattern: function (courier, savedSearches, $route) {
return courier.indexPatterns.get($route.current.params.indexPattern);
indexPattern: function (indexPatterns, savedSearches, $route) {
return indexPatterns.get($route.current.params.indexPattern);
}
};

View file

@ -147,10 +147,10 @@ uiRoutes
.when('/management/kibana/indices/:indexPatternId', {
template,
resolve: {
indexPattern: function ($route, courier) {
return courier.indexPatterns
indexPattern: function ($route, redirectWhenMissing, indexPatterns) {
return indexPatterns
.get($route.current.params.indexPatternId)
.catch(courier.redirectWhenMissing('/management/kibana/index'));
.catch(redirectWhenMissing('/management/kibana/index'));
}
}
});
@ -173,7 +173,7 @@ uiRoutes
uiModules.get('apps/management')
.controller('managementIndicesEdit', function (
$scope, $location, $route, config, courier, Notifier, Private, AppState, docTitle, confirmModal) {
$scope, $location, $route, config, indexPatterns, Notifier, Private, AppState, docTitle, confirmModal) {
const notify = new Notifier();
const $state = $scope.state = new AppState();
const { fieldWildcardMatcher } = Private(FieldWildcardProvider);
@ -257,7 +257,7 @@ uiModules.get('apps/management')
}
}
courier.indexPatterns.delete($scope.indexPattern)
indexPatterns.delete($scope.indexPattern)
.then(function () {
$location.url('/management/kibana/index');
})

View file

@ -43,9 +43,9 @@ uiRoutes
});
},
resolve: {
indexPattern: function ($route, courier) {
return courier.indexPatterns.get($route.current.params.indexPatternId)
.catch(courier.redirectWhenMissing('/management/kibana/indices'));
indexPattern: function ($route, redirectWhenMissing, indexPatterns) {
return indexPatterns.get($route.current.params.indexPatternId)
.catch(redirectWhenMissing('/management/kibana/indices'));
}
},
controllerAs: 'fieldSettings',

View file

@ -46,7 +46,7 @@ uiRoutes
.when(VisualizeConstants.CREATE_PATH, {
template: editorTemplate,
resolve: {
savedVis: function (savedVisualizations, courier, $route, Private) {
savedVis: function (savedVisualizations, redirectWhenMissing, $route, Private) {
const visTypes = Private(VisTypesRegistryProvider);
const visType = _.find(visTypes, { name: $route.current.params.type });
const shouldHaveIndex = visType.requiresSearch && visType.options.showIndexSelection;
@ -56,7 +56,7 @@ uiRoutes
}
return savedVisualizations.get($route.current.params)
.catch(courier.redirectWhenMissing({
.catch(redirectWhenMissing({
'*': '/visualize'
}));
}
@ -65,7 +65,7 @@ uiRoutes
.when(`${VisualizeConstants.EDIT_PATH}/:id`, {
template: editorTemplate,
resolve: {
savedVis: function (savedVisualizations, courier, $route) {
savedVis: function (savedVisualizations, redirectWhenMissing, $route) {
return savedVisualizations.get($route.current.params.id)
.then((savedVis) => {
recentlyAccessed.add(
@ -74,7 +74,7 @@ uiRoutes
savedVis.id);
return savedVis;
})
.catch(courier.redirectWhenMissing({
.catch(redirectWhenMissing({
'visualization': '/visualize',
'search': '/management/kibana/objects/savedVisualizations/' + $route.current.params.id,
'index-pattern': '/management/kibana/objects/savedVisualizations/' + $route.current.params.id,
@ -87,7 +87,7 @@ uiRoutes
uiModules
.get('app/visualize', [
'kibana/notify',
'kibana/courier'
'kibana/url'
])
.directive('visualizeApp', function () {
return {
@ -97,7 +97,19 @@ uiModules
};
});
function VisEditor($scope, $route, AppState, $window, kbnUrl, courier, Private, Promise, config, kbnBaseUrl, localStorage) {
function VisEditor(
$scope,
$route,
AppState,
$window,
kbnUrl,
redirectWhenMissing,
Private,
Promise,
config,
kbnBaseUrl,
localStorage
) {
const docTitle = Private(DocTitleProvider);
const queryFilter = Private(FilterBarQueryFilterProvider);
@ -198,7 +210,7 @@ function VisEditor($scope, $route, AppState, $window, kbnUrl, courier, Private,
Promise.try(function () {
vis.setState(appState.vis);
})
.catch(courier.redirectWhenMissing({
.catch(redirectWhenMissing({
'index-pattern-field': '/visualize'
}));
}

View file

@ -30,13 +30,14 @@ import { uiModules } from 'ui/modules';
import { updateOldState } from 'ui/vis/vis_update_state';
import { VisualizeConstants } from '../visualize_constants';
import { createLegacyClass } from 'ui/utils/legacy_class';
import { SavedObjectProvider } from 'ui/courier';
uiModules
.get('app/visualize')
.factory('SavedVis', function (config, $injector, courier, Promise, savedSearches, Private) {
.factory('SavedVis', function (config, $injector, Promise, savedSearches, Private) {
const Vis = Private(VisProvider);
createLegacyClass(SavedVis).inherits(courier.SavedObject);
const SavedObject = Private(SavedObjectProvider);
createLegacyClass(SavedVis).inherits(SavedObject);
function SavedVis(opts) {
const self = this;
opts = opts || {};

View file

@ -61,7 +61,7 @@ require('ui/routes')
template: require('plugins/timelion/index.html'),
reloadOnSearch: false,
resolve: {
savedSheet: function (courier, savedSheets, $route) {
savedSheet: function (redirectWhenMissing, savedSheets, $route) {
return savedSheets.get($route.current.params.id)
.then((savedSheet) => {
if ($route.current.params.id) {
@ -72,7 +72,7 @@ require('ui/routes')
}
return savedSheet;
})
.catch(courier.redirectWhenMissing({
.catch(redirectWhenMissing({
'search': '/'
}));
}

View file

@ -19,17 +19,19 @@
import { uiModules } from 'ui/modules';
import { createLegacyClass } from 'ui/utils/legacy_class';
import { SavedObjectProvider } from 'ui/courier';
const module = uiModules.get('app/timelion');
// Used only by the savedSheets service, usually no reason to change this
module.factory('SavedSheet', function (courier, config) {
module.factory('SavedSheet', function (Private, config) {
// SavedSheet constructor. Usually you'd interact with an instance of this.
// ID is option, without it one will be generated on save.
createLegacyClass(SavedSheet).inherits(courier.SavedObject);
const SavedObject = Private(SavedObjectProvider);
createLegacyClass(SavedSheet).inherits(SavedObject);
function SavedSheet(id) {
// Gives our SavedSheet the properties of a SavedObject
courier.SavedObject.call(this, {
SavedObject.call(this, {
type: SavedSheet.type,
mapping: SavedSheet.mapping,

View file

@ -25,10 +25,7 @@ export default function (Private, Promise) {
const getIndexPatternStub = sinon.stub()
.returns(Promise.resolve(indexPatterns));
const courier = {
indexPatterns: { get: getIndexPatternStub },
getStub: getIndexPatternStub
return {
get: getIndexPatternStub,
};
return courier;
}

View file

@ -21,7 +21,7 @@ import _ from 'lodash';
import { AggConfig } from '../../vis/agg_config';
import { buildExistsFilter } from '../../filter_manager/lib/exists';
import { buildPhrasesFilter } from '../../filter_manager/lib/phrases';
import { buildQueryFromFilters } from '../../courier/data_source/build_query/from_filters';
import { buildQueryFromFilters } from '../../courier';
/**
* walks the aggregation DSL and returns DSL starting at aggregation with id of startFromAggId

View file

@ -19,11 +19,10 @@
import _ from 'lodash';
import angular from 'angular';
import { luceneStringToDsl } from '../../courier/data_source/build_query/lucene_string_to_dsl.js';
import { BucketAggType } from './_bucket_agg_type';
import { createFilterFilters } from './create_filter/filters';
import { decorateQuery } from '../../courier/data_source/_decorate_query';
import { decorateQuery, luceneStringToDsl } from '../../courier';
import filtersTemplate from '../controls/filters.html';
export const filtersBucketAgg = new BucketAggType({

View file

@ -19,93 +19,41 @@
import _ from 'lodash';
import { timefilter } from 'ui/timefilter';
import '../es';
import '../promises';
import '../index_patterns';
import { uiModules } from '../modules';
import { addFatalErrorCallback } from '../notify';
import '../promises';
import { SearchSourceProvider } from './data_source/search_source';
import { requestQueue } from './_request_queue';
import { FetchSoonProvider } from './fetch';
import { SearchLooperProvider } from './looper/search';
import { SavedObjectProvider } from './saved_object';
import { RedirectWhenMissingProvider } from './_redirect_when_missing';
import { timefilter } from 'ui/timefilter';
import { SearchLooperProvider } from './search_looper';
uiModules.get('kibana/courier').service('courier', ($rootScope, Private) => {
const fetchSoon = Private(FetchSoonProvider);
uiModules.get('kibana/courier')
.service('courier', function ($rootScope, Private, indexPatterns) {
function Courier() {
const self = this;
const SearchSource = Private(SearchSourceProvider);
const fetchSoon = Private(FetchSoonProvider);
const searchLooper = self.searchLooper = Private(SearchLooperProvider);
// This manages the doc fetch interval.
const searchLooper = Private(SearchLooperProvider);
self.SavedObject = Private(SavedObjectProvider);
self.indexPatterns = indexPatterns;
self.redirectWhenMissing = Private(RedirectWhenMissingProvider);
class Courier {
constructor() {
// Listen for refreshInterval changes
$rootScope.$listen(timefilter, 'refreshIntervalUpdate', function () {
const refreshValue = _.get(timefilter.getRefreshInterval(), 'value');
const refreshPause = _.get(timefilter.getRefreshInterval(), 'pause');
self.SearchSource = SearchSource;
// Update the time between automatic search requests.
if (_.isNumber(refreshValue) && !refreshPause) {
searchLooper.setIntervalInMs(refreshValue);
} else {
searchLooper.setIntervalInMs(0);
}
});
/**
* update the time between automatic search requests
*
* @chainable
*/
self.fetchInterval = function (ms) {
searchLooper.ms(ms);
return this;
};
/**
* Start fetching search requests on an interval
* @chainable
*/
self.start = function () {
searchLooper.start();
return this;
};
/**
* Process the pending request queue right now, returns
* a promise that resembles the success of the fetch completing,
* individual errors are routed to their respective requests.
*/
self.fetch = function () {
fetchSoon.fetchQueued().then(function () {
searchLooper.restart();
});
};
/**
* is the courier currently fetching search
* results automatically?
*
* @return {boolean}
*/
self.started = function () {
return searchLooper.started();
};
/**
* stop the courier from fetching more search
* results, does not stop validating docs.
*
* @chainable
*/
self.stop = function () {
searchLooper.stop();
return this;
};
/**
* Abort all pending requests
* @return {[type]} [description]
*/
self.close = function () {
// Abort all pending requests if there's a fatal error.
const closeOnFatal = _.once(() => {
searchLooper.stop();
_.invoke(requestQueue, 'abort');
@ -113,21 +61,22 @@ uiModules.get('kibana/courier')
if (requestQueue.length) {
throw new Error('Aborting all pending requests failed.');
}
};
$rootScope.$listen(timefilter, 'refreshIntervalUpdate', function () {
const refreshValue = _.get(timefilter.getRefreshInterval(), 'value');
const refreshPause = _.get(timefilter.getRefreshInterval(), 'pause');
if (_.isNumber(refreshValue) && !refreshPause) {
self.fetchInterval(refreshValue);
} else {
self.fetchInterval(0);
}
});
const closeOnFatal = _.once(self.close);
addFatalErrorCallback(closeOnFatal);
}
return new Courier();
});
/**
* Process the pending request queue right now, returns
* a promise that resembles the success of the fetch completing,
* individual errors are routed to their respective requests.
*/
fetch = () => {
fetchSoon.fetchQueued().then(() => {
searchLooper.restart();
});
};
}
return new Courier();
});

View file

@ -23,13 +23,13 @@ import { ErrorAllowExplicitIndexProvider } from '../../error_allow_explicit_inde
import { IsRequestProvider } from './is_request';
import { MergeDuplicatesRequestProvider } from './merge_duplicate_requests';
import { RequestStatus } from './req_status';
import { RequestFetchParamsToBodyProvider } from './request/request_fetch_params_to_body_provider';
import { SerializeFetchParamsProvider } from './request/serialize_fetch_params';
export function CallClientProvider(Private, Promise, es) {
const errorAllowExplicitIndex = Private(ErrorAllowExplicitIndexProvider);
const isRequest = Private(IsRequestProvider);
const mergeDuplicateRequests = Private(MergeDuplicatesRequestProvider);
const requestFetchParamsToBody = Private(RequestFetchParamsToBodyProvider);
const serializeFetchParams = Private(SerializeFetchParamsProvider);
const ABORTED = RequestStatus.ABORTED;
const DUPLICATE = RequestStatus.DUPLICATE;
@ -45,7 +45,8 @@ export function CallClientProvider(Private, Promise, es) {
if (!execCount) return Promise.resolve([]);
// resolved by respond()
let esPromise;
let esPromise = undefined;
let isRequestAborted = false;
const defer = Promise.defer();
// for each respond with either the response or ABORTED
@ -72,7 +73,6 @@ export function CallClientProvider(Private, Promise, es) {
);
};
// handle a request being aborted while being fetched
const requestWasAborted = Promise.method(function (req, i) {
if (statuses[i] === ABORTED) {
@ -89,12 +89,12 @@ export function CallClientProvider(Private, Promise, es) {
esPromise.abort();
}
esPromise = ABORTED;
esPromise = undefined;
isRequestAborted = true;
return respond();
});
// attach abort handlers, close over request index
statuses.forEach(function (req, i) {
if (!isRequest(req)) return;
@ -103,63 +103,81 @@ export function CallClientProvider(Private, Promise, es) {
});
});
// Now that all of THAT^^^ is out of the way, lets actually
// call out to elasticsearch
Promise.map(requestsToFetch, function (request) {
return Promise.try(request.getFetchParams, void 0, request)
.then(function (fetchParams) {
return (request.fetchParams = fetchParams);
})
.then(value => ({ resolved: value }))
.catch(error => ({ rejected: error }));
})
.then(function (results) {
const requestsWithFetchParams = [];
// Gather the fetch param responses from all the successful requests.
results.forEach((result, index) => {
if (result.resolved) {
requestsWithFetchParams.push(result.resolved);
} else {
const request = requestsToFetch[index];
request.handleFailure(result.rejected);
requestsToFetch[index] = undefined;
}
});
// The index of the request inside requestsToFetch determines which response is mapped to it. If a request
// won't generate a response, since it already failed, we need to remove the request
// from the requestsToFetch array so the indexes will continue to match up to the responses correctly.
requestsToFetch = requestsToFetch.filter(request => request !== undefined);
return requestFetchParamsToBody(requestsWithFetchParams);
})
.then(function (body) {
// while the strategy was converting, our request was aborted
if (esPromise === ABORTED) {
// We're going to create a new async context here, so that the logic within it can execute
// asynchronously after we've returned a reference to defer.promise.
Promise.resolve().then(async () => {
// Flatten the searchSource within each searchRequest to get the fetch params,
// e.g. body, filters, index pattern, query.
const allFetchParams = await getAllFetchParams(requestsToFetch);
// Serialize the fetch params into a format suitable for the body of an ES query.
const serializedFetchParams = await serializeAllFetchParams(allFetchParams, requestsToFetch);
// The index of the request inside requestsToFetch determines which response is mapped to it.
// If a request won't generate a response, since it already failed, we need to remove the
// request from the requestsToFetch array so the indexes will continue to match up to the
// responses correctly.
requestsToFetch = requestsToFetch.filter(request => request !== undefined);
try {
// The request was aborted while we were doing the above logic.
if (isRequestAborted) {
throw ABORTED;
}
return (esPromise = es.msearch({ body }));
})
.then((clientResponse => respond(clientResponse.responses)))
.catch(function (error) {
esPromise = es.msearch({ body: serializedFetchParams });
const clientResponse = await esPromise;
await respond(clientResponse.responses);
} catch(error) {
if (error === ABORTED) {
return await respond();
}
if (errorAllowExplicitIndex.test(error)) {
return errorAllowExplicitIndex.takeover();
}
if (error === ABORTED) respond();
else defer.reject(error);
});
defer.reject(error);
}
});
// return our promise, but catch any errors we create and
// send them to the requests
return defer.promise
.catch(function (err) {
requests.forEach(function (req, i) {
if (statuses[i] !== ABORTED) {
.catch((err) => {
requests.forEach((req, index) => {
if (statuses[index] !== ABORTED) {
req.handleFailure(err);
}
});
});
}
function getAllFetchParams(requests) {
return Promise.map(requests, (request) => {
return Promise.try(request.getFetchParams, void 0, request)
.then((fetchParams) => {
return (request.fetchParams = fetchParams);
})
.then(value => ({ resolved: value }))
.catch(error => ({ rejected: error }));
});
}
function serializeAllFetchParams(fetchParams, requestsToFetch) {
const requestsWithFetchParams = [];
// Gather the fetch param responses from all the successful requests.
fetchParams.forEach((result, index) => {
if (result.resolved) {
requestsWithFetchParams.push(result.resolved);
} else {
const request = requestsToFetch[index];
request.handleFailure(result.rejected);
requestsToFetch[index] = undefined;
}
});
return serializeFetchParams(requestsWithFetchParams);
}
return callClient;

View file

@ -47,13 +47,13 @@ export function FetchSoonProvider(Private, Promise) {
* @param {array} requests - the requests to fetch
* @async
*/
this.these = (requests) => {
this.fetchSearchRequests = (requests) => {
requests.forEach(req => req._setFetchRequested());
debouncedFetchNow();
return Promise.all(requests.map(req => req.getCompletePromise()));
};
this.fetchQueued = () => {
return this.these(requestQueue.getStartable());
return this.fetchSearchRequests(requestQueue.getStartable());
};
}

View file

@ -22,7 +22,7 @@ import sinon from 'sinon';
import expect from 'expect.js';
import { SearchRequestProvider } from '../search_request';
import { requestQueue } from '../../../_request_queue';
import { requestQueue } from '../../../../_request_queue';
describe('ui/courier/fetch search request', () => {
beforeEach(ngMock.module('kibana'));

View file

@ -0,0 +1,20 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
export { SearchRequestProvider } from './search_request';

View file

@ -20,7 +20,7 @@
import _ from 'lodash';
import moment from 'moment';
import { requestQueue } from '../../_request_queue';
import { requestQueue } from '../../../_request_queue';
export function SearchRequestProvider(Promise) {
class SearchRequest {

View file

@ -23,11 +23,11 @@ import ngMock from 'ng_mock';
import StubbedSearchSourceProvider from 'fixtures/stubbed_search_source';
import { SegmentedRequestProvider } from '../segmented';
import { SegmentedSearchRequestProvider } from '../segmented_search_request';
describe('ui/courier/fetch/request/segmented/_createQueue', () => {
describe('SegmentedSearchRequest _createQueue', () => {
let Promise;
let SegmentedReq;
let SegmentedSearchRequest;
let MockSource;
require('test_utils/no_digest_promises').activateForSuite();
@ -35,7 +35,7 @@ describe('ui/courier/fetch/request/segmented/_createQueue', () => {
beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject((Private, $injector) => {
Promise = $injector.get('Promise');
SegmentedReq = Private(SegmentedRequestProvider);
SegmentedSearchRequest = Private(SegmentedSearchRequestProvider);
MockSource = class {
constructor() {
@ -45,7 +45,7 @@ describe('ui/courier/fetch/request/segmented/_createQueue', () => {
}));
it('manages the req._queueCreated flag', async function () {
const req = new SegmentedReq({ source: new MockSource(), errorHandler: () => {} });
const req = new SegmentedSearchRequest({ source: new MockSource(), errorHandler: () => {} });
req._queueCreated = null;
const promise = req._createQueue();
@ -60,7 +60,7 @@ describe('ui/courier/fetch/request/segmented/_createQueue', () => {
const indices = [1, 2, 3];
sinon.stub(ip, 'toDetailedIndexList').returns(Promise.resolve(indices));
const req = new SegmentedReq({ source, errorHandler: () => {} });
const req = new SegmentedSearchRequest({ source, errorHandler: () => {} });
const output = await req._createQueue();
expect(output).to.equal(indices);
});
@ -68,7 +68,7 @@ describe('ui/courier/fetch/request/segmented/_createQueue', () => {
it('tells the index pattern its direction', async function () {
const source = new MockSource();
const ip = source.get('index');
const req = new SegmentedReq({ source, errorHandler: () => {} });
const req = new SegmentedSearchRequest({ source, errorHandler: () => {} });
sinon.stub(ip, 'toDetailedIndexList').returns(Promise.resolve([1, 2, 3]));
req.setDirection('asc');

View file

@ -26,11 +26,11 @@ import HitSortFnProv from 'plugins/kibana/discover/_hit_sort_fn';
import NoDigestPromises from 'test_utils/no_digest_promises';
import StubbedSearchSourceProvider from 'fixtures/stubbed_search_source';
import { SegmentedRequestProvider } from '../segmented';
import { SegmentedSearchRequestProvider } from '../segmented_search_request';
describe('Segmented Request Index Selection', function () {
describe('SegmentedSearchRequest index selection', function () {
let Promise;
let SegmentedReq;
let SegmentedSearchRequest;
let MockSource;
let HitSortFn;
@ -40,7 +40,7 @@ describe('Segmented Request Index Selection', function () {
beforeEach(ngMock.inject((Private, $injector) => {
Promise = $injector.get('Promise');
HitSortFn = Private(HitSortFnProv);
SegmentedReq = Private(SegmentedRequestProvider);
SegmentedSearchRequest = Private(SegmentedSearchRequestProvider);
MockSource = class {
constructor() {
@ -60,7 +60,7 @@ describe('Segmented Request Index Selection', function () {
{ index: 'five', min: 0, max: 1 },
]));
const req = new SegmentedReq({ source: search, errorHandler: () => {} });
const req = new SegmentedSearchRequest({ source: search, errorHandler: () => {} });
req._handle.setDirection('desc');
req._handle.setSortFn(new HitSortFn('desc'));
req._handle.setSize(500);
@ -111,7 +111,7 @@ describe('Segmented Request Index Selection', function () {
{ index: 'five', min: 5, max: 50 },
]));
const req = new SegmentedReq({ source: search, errorHandler: () => {} });
const req = new SegmentedSearchRequest({ source: search, errorHandler: () => {} });
req._handle.setDirection('desc');
req._handle.setSortFn(new HitSortFn('desc'));
req._handle.setSize(10);

View file

@ -21,12 +21,12 @@ import sinon from 'sinon';
import expect from 'expect.js';
import ngMock from 'ng_mock';
import { SegmentedRequestProvider } from '../segmented';
import { SearchRequestProvider } from '../search_request';
import { SegmentedSearchRequestProvider } from '../segmented_search_request';
import { SearchRequestProvider } from '../../search_request';
describe('SegmentedRequestProvider', () => {
describe('SegmentedSearchRequest', () => {
let Promise;
let SegmentedReq;
let SegmentedSearchRequest;
let segmentedReq;
let abstractReqStart;
@ -34,7 +34,7 @@ describe('SegmentedRequestProvider', () => {
beforeEach(ngMock.inject((Private, $injector) => {
Promise = $injector.get('Promise');
SegmentedReq = Private(SegmentedRequestProvider);
SegmentedSearchRequest = Private(SegmentedSearchRequestProvider);
const SearchRequest = Private(SearchRequestProvider);
abstractReqStart = sinon.stub(SearchRequest.prototype, 'start').callsFake(() => {
@ -67,7 +67,7 @@ describe('SegmentedRequestProvider', () => {
});
function init() {
segmentedReq = new SegmentedReq({ source: mockSource(), errorHandler: () => {} });
segmentedReq = new SegmentedSearchRequest({ source: mockSource(), errorHandler: () => {} });
}
function mockSource() {

View file

@ -24,10 +24,10 @@ import HitSortFnProv from 'plugins/kibana/discover/_hit_sort_fn';
import NoDigestPromises from 'test_utils/no_digest_promises';
import StubbedSearchSourceProvider from 'fixtures/stubbed_search_source';
import { SegmentedRequestProvider } from '../segmented';
import { SegmentedSearchRequestProvider } from '../segmented_search_request';
describe('Segmented Request Size Picking', function () {
let SegmentedReq;
describe('SegmentedSearchRequest size picking', function () {
let SegmentedSearchRequest;
let MockSource;
let HitSortFn;
@ -36,7 +36,7 @@ describe('Segmented Request Size Picking', function () {
beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject((Private, $injector) => {
HitSortFn = Private(HitSortFnProv);
SegmentedReq = Private(SegmentedRequestProvider);
SegmentedSearchRequest = Private(SegmentedSearchRequestProvider);
MockSource = class {
constructor() {
@ -47,7 +47,7 @@ describe('Segmented Request Size Picking', function () {
describe('without a size', function () {
it('does not set the request size', async function () {
const req = new SegmentedReq({ source: new MockSource(), errorHandler: () => {} });
const req = new SegmentedSearchRequest({ source: new MockSource(), errorHandler: () => {} });
req._handle.setDirection('desc');
req._handle.setSortFn(new HitSortFn('desc'));
await req.start();
@ -58,7 +58,7 @@ describe('Segmented Request Size Picking', function () {
describe('with a size', function () {
it('sets the request size to the entire desired size', async function () {
const req = new SegmentedReq({ source: new MockSource(), errorHandler: () => {} });
const req = new SegmentedSearchRequest({ source: new MockSource(), errorHandler: () => {} });
req._handle.setDirection('desc');
req._handle.setSize(555);
req._handle.setSortFn(new HitSortFn('desc'));

View file

@ -0,0 +1,20 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
export { SegmentedSearchRequestProvider } from './segmented_search_request';

View file

@ -17,7 +17,7 @@
* under the License.
*/
import { EventsProvider } from '../../../events';
import { EventsProvider } from '../../../../events';
export function SegmentedHandleProvider(Private) {
const Events = Private(EventsProvider);
@ -26,13 +26,13 @@ export function SegmentedHandleProvider(Private) {
/**
* Simple class for creating an object to send to the
* requester of a SegmentedRequest. Since the SegmentedRequest
* requester of a SegmentedSearchRequest. Since the SegmentedSearchRequest
* extends AbstractRequest, it wasn't able to be the event
* emitter it was born to be. This provides a channel for
* setting values on the segmented request, and an event
* emitter for the request to speak outwardly
*
* @param {SegmentedRequest} - req - the request this handle relates to
* @param {SegmentedSearchRequest} - req - the request this handle relates to
*/
return class SegmentedHandle extends Events {
constructor(req) {

View file

@ -18,13 +18,13 @@
*/
import _ from 'lodash';
import { Notifier } from '../../../notify';
import { SearchRequestProvider } from './search_request';
import { SegmentedHandleProvider } from './segmented_handle';
import { pushAll } from '../../../utils/collection';
import { timefilter } from 'ui/timefilter';
import { SearchRequestProvider } from '../search_request';
import { SegmentedHandleProvider } from './segmented_handle';
import { Notifier } from '../../../../notify';
import { pushAll } from '../../../../utils/collection';
export function SegmentedRequestProvider(Private, config) {
export function SegmentedSearchRequestProvider(Private, config) {
const SearchRequest = Private(SearchRequestProvider);
const SegmentedHandle = Private(SegmentedHandleProvider);
@ -32,7 +32,7 @@ export function SegmentedRequestProvider(Private, config) {
location: 'Segmented Fetch'
});
class SegmentedReq extends SearchRequest {
class SegmentedSearchRequest extends SearchRequest {
constructor({ source, defer, errorHandler, initFn }) {
super({ source, defer, errorHandler });
@ -136,7 +136,7 @@ export function SegmentedRequestProvider(Private, config) {
}
clone() {
return new SegmentedReq(this.source, this.defer, this._initFn);
return new SegmentedSearchRequest(this.source, this.defer, this._initFn);
}
complete() {
@ -146,7 +146,7 @@ export function SegmentedRequestProvider(Private, config) {
}
/*********
** SegmentedReq specific methods
** SegmentedSearchRequest specific methods
*********/
@ -349,7 +349,7 @@ export function SegmentedRequestProvider(Private, config) {
}
}
SegmentedReq.prototype.mergedSegment = notify.timed('merge response segment', SegmentedReq.prototype.mergedSegment);
SegmentedSearchRequest.prototype.mergedSegment = notify.timed('merge response segment', SegmentedSearchRequest.prototype.mergedSegment);
return SegmentedReq;
return SegmentedSearchRequest;
}

View file

@ -22,17 +22,17 @@ import expect from 'expect.js';
import StubIndexPatternProvider from 'test_utils/stub_index_pattern';
import { RequestFetchParamsToBodyProvider } from '../request_fetch_params_to_body_provider';
import { SerializeFetchParamsProvider } from '../serialize_fetch_params_provider';
describe('RequestFetchParamsToBodyProvider', () => {
let requestFetchParamsToBody;
describe('SerializeFetchParamsProvider', () => {
let serializeFetchParams;
let IndexPattern;
require('test_utils/no_digest_promises').activateForSuite();
beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject((Private) => {
requestFetchParamsToBody = Private(RequestFetchParamsToBodyProvider);
serializeFetchParams = Private(SerializeFetchParamsProvider);
IndexPattern = Private(StubIndexPatternProvider);
}));
@ -60,7 +60,7 @@ describe('RequestFetchParamsToBodyProvider', () => {
body: { foo: 'saturn' }
}
];
return requestFetchParamsToBody(reqsFetchParams).then(value => {
return serializeFetchParams(reqsFetchParams).then(value => {
const indexLineMatch = value.match(/"index":\[".kibana"\]/g);
expect(indexLineMatch).to.not.be(null);
expect(indexLineMatch.length).to.be(2);

View file

@ -0,0 +1,20 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
export { SerializeFetchParamsProvider } from './serialize_fetch_params_provider';

View file

@ -18,7 +18,7 @@
*/
import _ from 'lodash';
import { toJson } from '../../../../../core_plugins/kibana/common/utils/aggressive_parse';
import { toJson } from '../../../../../../core_plugins/kibana/common/utils/aggressive_parse';
function emptySearch() {
return {
@ -44,7 +44,7 @@ function emptySearch() {
* @param sessionId
* @return {Promise.<string>}
*/
export function requestFetchParamsToBody(
export function serializeFetchParams(
requestsFetchParams,
Promise,
timeFilter,

View file

@ -17,12 +17,12 @@
* under the License.
*/
import { requestFetchParamsToBody } from './request_fetch_params_to_body';
import { serializeFetchParams } from './serialize_fetch_params';
import _ from 'lodash';
const DEFAULT_SESSION_ID = '1';
function requestFetchParamsToBodyWithDefaults(paramOverrides) {
function serializeFetchParamsWithDefaults(paramOverrides) {
const paramDefaults = {
requestFetchParams: [],
Promise,
@ -39,7 +39,7 @@ function requestFetchParamsToBodyWithDefaults(paramOverrides) {
};
const params = { ...paramDefaults, ...paramOverrides };
return requestFetchParamsToBody(
return serializeFetchParams(
params.requestFetchParams,
Promise,
params.timeFilter,
@ -58,7 +58,7 @@ test('filters out any body properties that begin with $', () => {
body: { foo: 'bar', $foo: 'bar' }
}
];
return requestFetchParamsToBodyWithDefaults({ requestFetchParams }).then(value => {
return serializeFetchParamsWithDefaults({ requestFetchParams }).then(value => {
expect(_.includes(value, 'foo')).toBe(true);
expect(_.includes(value, '$foo')).toBe(false);
});
@ -74,7 +74,7 @@ describe('when indexList is not empty', () => {
body: { foo: 'bar', $foo: 'bar' }
}
];
return requestFetchParamsToBodyWithDefaults({ requestFetchParams }).then(value => {
return serializeFetchParamsWithDefaults({ requestFetchParams }).then(value => {
expect(_.includes(value, '"index":["logstash-123"]')).toBe(true);
});
});
@ -101,7 +101,7 @@ describe('when indexList is empty', () => {
];
test('queries the kibana index (.kibana) with a must_not match_all boolean', () => {
return requestFetchParamsToBodyWithDefaults({ requestFetchParams }).then(value => {
return serializeFetchParamsWithDefaults({ requestFetchParams }).then(value => {
expect(_.includes(value, '"index":[".kibana"]')).toBe(true);
expect(_.includes(value, emptyMustNotQuery)).toBe(true);
});
@ -120,7 +120,7 @@ describe('headers', () => {
];
const getHeader = async (paramOverrides) => {
const request = await requestFetchParamsToBodyWithDefaults(paramOverrides);
const request = await serializeFetchParamsWithDefaults(paramOverrides);
const requestParts = request.split('\n');
if (requestParts.length < 2) {
throw new Error('fetch Body does not contain expected format header newline body.');

View file

@ -17,13 +17,13 @@
* under the License.
*/
import { requestFetchParamsToBody } from './request_fetch_params_to_body';
import { serializeFetchParams } from './serialize_fetch_params';
import { timefilter } from 'ui/timefilter';
export function RequestFetchParamsToBodyProvider(Promise, kbnIndex, sessionId, config, esShardTimeout) {
return (requestsFetchParams) => (
requestFetchParamsToBody(
requestsFetchParams,
export function SerializeFetchParamsProvider(Promise, kbnIndex, sessionId, config, esShardTimeout) {
return (fetchParams) => (
serializeFetchParams(
fetchParams,
Promise,
timefilter,
kbnIndex,

View file

@ -18,3 +18,11 @@
*/
import './courier';
export { SavedObjectProvider } from './saved_object';
export {
SearchSourceProvider,
migrateFilter,
decorateQuery,
buildQueryFromFilters,
luceneStringToDsl,
} from './search_source';

View file

@ -1,204 +0,0 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import _ from 'lodash';
import '../../promises';
import { fatalError } from '../../notify';
export function LooperProvider($timeout, Promise) {
function Looper(ms, fn) {
this._fn = fn;
this._ms = ms === void 0 ? 1500 : ms;
this._timer = null;
this._started = false;
this._loopTheLoop = _.bind(this._loopTheLoop, this);
}
/**
* Set the number of milliseconds between
* each loop
*
* @param {integer} ms
* @chainable
*/
Looper.prototype.ms = function (ms) {
this._ms = _.parseInt(ms) || 0;
if (!this._started) return;
if (this._ms) {
this.start(false);
} else {
this._unScheduleLoop();
}
return this;
};
/**
* Cancels the current looper while keeping internal
* state as started
*
* @chainable
*/
Looper.prototype.pause = function () {
this._unScheduleLoop();
return this;
};
/**
* Start the looping madness
*
* @chainable
*/
Looper.prototype.start = function (loopOver) {
if (loopOver == null) loopOver = true;
if (!this._started) {
this._started = true;
} else {
this._unScheduleLoop();
}
if (loopOver) {
this._loopTheLoop();
} else {
this._scheduleLoop();
}
return this;
};
/**
* ...
*
* @chainable
*/
Looper.prototype.stop = function () {
this._unScheduleLoop();
this._started = false;
return this;
};
/**
* Restart the looper only if it is already started.
* Called automatically when ms is changed
*
* @chainable
*/
Looper.prototype.restart = function () {
this.start(false);
return this;
};
/**
* Is the looper currently started/running/scheduled/going to execute
*
* @return {boolean}
*/
Looper.prototype.started = function () {
return !!this._started;
};
/**
* Returns the current loop interval
*
* @return {number}
*/
Looper.prototype.loopInterval = function () {
return this._ms;
};
/**
* Called when the loop is executed before the previous
* run has completed.
*
* @override
* @return {undefined}
*/
Looper.prototype.onHastyLoop = function () {
// override this in subclasses
};
/**
* Wraps this._fn so that this._fn can be changed
* without rescheduling and schedules
* the next iteration
*
* @private
* @return {undefined}
*/
Looper.prototype._loopTheLoop = function () {
const self = this;
if (self.active) {
self.onHastyLoop();
return;
}
self.active = Promise
.try(this._fn)
.then(function () {
self._scheduleLoop();
})
.catch(function (err) {
self.stop();
fatalError(err);
})
.finally(function () {
self.active = null;
});
};
/**
* Schedule the next iteration of the loop
*
* @private
* @return {number} - the timer promise
*/
Looper.prototype._scheduleLoop = function () {
this._unScheduleLoop();
this._timer = this._ms ? $timeout(this._loopTheLoop, this._ms) : null;
return this._timer;
};
/**
* Cancel the next iteration of the loop
*
* @private
* @return {number} - the timer promise
*/
Looper.prototype._unScheduleLoop = function () {
if (this._timer) {
$timeout.cancel(this._timer);
this._timer = null;
}
};
/**
* execute the this._fn, and restart the timer
*/
Looper.prototype.run = function () {
this.start();
};
return Looper;
}

View file

@ -1,56 +0,0 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { FetchSoonProvider } from '../fetch';
import { requestQueue } from '../_request_queue';
import { LooperProvider } from './_looper';
export function SearchLooperProvider(Private, Promise, $rootScope) {
const fetchSoon = Private(FetchSoonProvider);
const Looper = Private(LooperProvider);
/**
* The Looper which will manage the doc fetch interval
* @type {Looper}
*/
const searchLooper = new Looper(null, function () {
$rootScope.$broadcast('courier:searchRefresh');
const requests = requestQueue.getInactive();
// promise returned from fetch.these() only resolves when
// the requests complete, but we want to continue even if
// the requests abort so we make our own
fetchSoon.these(requests);
return Promise.all(requests.map(request => request.getCompleteOrAbortedPromise()));
});
searchLooper.onHastyLoop = function () {
if (searchLooper.afterHastyQueued) return;
searchLooper.afterHastyQueued = Promise.resolve(searchLooper.active)
.then(function () {
return searchLooper._loopTheLoop();
})
.finally(function () {
searchLooper.afterHastyQueued = null;
});
};
return searchLooper;
}

View file

@ -34,7 +34,7 @@ import _ from 'lodash';
import { SavedObjectNotFound } from '../../errors';
import MappingSetupProvider from '../../utils/mapping_setup';
import { SearchSourceProvider } from '../data_source/search_source';
import { SearchSourceProvider } from '../search_source';
import { SavedObjectsClientProvider, findObjectByTitle } from '../../saved_objects';
import { migrateLegacyQuery } from '../../utils/migrateLegacyQuery.js';
import { recentlyAccessed } from '../../persisted_log';

View file

@ -17,4 +17,4 @@
* under the License.
*/
export { BuildESQueryProvider } from './build_es_query';
export { SearchLooperProvider } from './search_looper';

View file

@ -0,0 +1,190 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import _ from 'lodash';
import { fatalError } from '../../notify';
import '../../promises';
import { requestQueue } from '../_request_queue';
import { FetchSoonProvider } from '../fetch';
export function SearchLooperProvider(Private, Promise, $timeout, $rootScope) {
const fetchSoon = Private(FetchSoonProvider);
class SearchLooper {
constructor() {
this._intervalInMs = undefined;
this._timer = null;
this._started = false;
}
/**
* Set the number of milliseconds between
* each loop
*
* @param {integer} intervalInMs
*/
setIntervalInMs = intervalInMs => {
this._intervalInMs = _.parseInt(intervalInMs) || 0;
if (!this._started) {
return;
}
if (this._intervalInMs) {
this.start(false);
} else {
this._unscheduleLoop();
}
};
start = loopOver => {
if (loopOver == null) {
loopOver = true;
}
if (!this._started) {
this._started = true;
} else {
this._unscheduleLoop();
}
if (loopOver) {
this._executeLoop();
} else {
this._scheduleLoop();
}
};
stop = () => {
this._unscheduleLoop();
this._started = false;
};
/**
* Restart the looper only if it is already started.
* Called automatically when ms is changed
*/
restart = () => {
this.start(false);
};
/**
* Is the looper currently started/running/scheduled/going to execute
*
* @return {boolean}
*/
started = () => {
return !!this._started;
};
/**
* Called when the loop is executed before the previous
* run has completed.
*
* @override
* @return {undefined}
*/
_onHastyLoop = () => {
if (this.afterHastyQueued) {
return;
}
this.afterHastyQueued = Promise.resolve(this.active)
.then(() => {
return this._executeLoop();
})
.finally(() => {
this.afterHastyQueued = null;
});
};
/**
* Wraps this._fn so that this._fn can be changed
* without rescheduling and schedules
* the next iteration
*
* @private
* @return {undefined}
*/
_executeLoop = () => {
if (this.active) {
this._onHastyLoop();
return;
}
this.active = Promise.try(this._executeLoopAction)
.then(() => {
this._scheduleLoop();
})
.catch(err => {
this.stop();
fatalError(err);
})
.finally(() => {
this.active = null;
});
};
_executeLoopAction = () => {
$rootScope.$broadcast('courier:searchRefresh');
const requests = requestQueue.getInactive();
// promise returned from fetch.fetchSearchRequests() only resolves when
// the requests complete, but we want to continue even if
// the requests abort so we make our own
fetchSoon.fetchSearchRequests(requests);
return Promise.all(
requests.map(request => request.getCompleteOrAbortedPromise())
);
};
/**
* Schedule the next iteration of the loop
*
* @private
* @return {number} - the timer promise
*/
_scheduleLoop = () => {
this._unscheduleLoop();
this._timer = this._intervalInMs
? $timeout(this._executeLoop, this._intervalInMs)
: null;
return this._timer;
};
/**
* Cancel the next iteration of the loop
*
* @private
* @return {number} - the timer promise
*/
_unscheduleLoop = () => {
if (this._timer) {
$timeout.cancel(this._timer);
this._timer = null;
}
};
}
return new SearchLooper();
}

View file

@ -19,7 +19,7 @@
import expect from 'expect.js';
import _ from 'lodash';
import { migrateFilter } from '../_migrate_filter';
import { migrateFilter } from '../migrate_filter';
describe('migrateFilter', function () {

View file

@ -19,7 +19,7 @@
import expect from 'expect.js';
import chrome from '../../../chrome';
import { decorateQuery } from '../_decorate_query';
import { decorateQuery } from '../decorate_query';
const config = chrome.getUiSettingsClient();
describe('Query decorator', function () {

View file

@ -23,7 +23,7 @@ import ngMock from 'ng_mock';
import { expectDeepEqual } from '../../../../../../test_utils/expect_deep_equal.js';
import { fromKueryExpression, toElasticsearchQuery } from '../../../../kuery';
import { luceneStringToDsl } from '../lucene_string_to_dsl';
import { decorateQuery } from '../../_decorate_query';
import { decorateQuery } from '../../decorate_query';
let indexPattern;
let buildEsQuery;

View file

@ -18,8 +18,8 @@
*/
import { buildQueryFromLucene } from '../from_lucene';
import { decorateQuery } from '../../_decorate_query.js';
import { expectDeepEqual } from '../../../../../../test_utils/expect_deep_equal.js';
import { decorateQuery } from '../../decorate_query';
import { expectDeepEqual } from '../../../../../../test_utils/expect_deep_equal';
import { luceneStringToDsl } from '../lucene_string_to_dsl';

View file

@ -18,7 +18,7 @@
*/
import { groupBy, has } from 'lodash';
import { decorateQuery } from '../_decorate_query';
import { decorateQuery } from '../decorate_query';
import { buildQueryFromKuery } from './from_kuery';
import { buildQueryFromFilters } from './from_filters';
import { buildQueryFromLucene } from './from_lucene';

View file

@ -18,7 +18,7 @@
*/
import _ from 'lodash';
import { migrateFilter } from '../_migrate_filter';
import { migrateFilter } from '../migrate_filter';
/**
* Create a filter that can be reversed for filters with negate set

View file

@ -0,0 +1,22 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
export { BuildESQueryProvider } from './build_es_query';
export { buildQueryFromFilters } from './from_filters';
export { luceneStringToDsl } from './lucene_string_to_dsl';

View file

@ -0,0 +1,23 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
export { SearchSourceProvider } from './search_source';
export { migrateFilter } from './migrate_filter';
export { decorateQuery } from './decorate_query';
export { buildQueryFromFilters, luceneStringToDsl } from './build_query';

View file

@ -76,7 +76,7 @@ import '../../promises';
import { NormalizeSortRequestProvider } from './_normalize_sort_request';
import { SearchRequestProvider } from '../fetch/request';
import { SegmentedRequestProvider } from '../fetch/request/segmented';
import { SegmentedSearchRequestProvider } from '../fetch/request/segmented_search_request';
import { requestQueue } from '../_request_queue';
import { FetchSoonProvider } from '../fetch';
@ -100,7 +100,7 @@ function isIndexPattern(val) {
export function SearchSourceProvider(Promise, Private, config) {
const SearchRequest = Private(SearchRequestProvider);
const SegmentedRequest = Private(SegmentedRequestProvider);
const SegmentedSearchRequest = Private(SegmentedSearchRequestProvider);
const normalizeSortRequest = Private(NormalizeSortRequestProvider);
const fetchSoon = Private(FetchSoonProvider);
const buildESQuery = Private(BuildESQueryProvider);
@ -253,7 +253,7 @@ export function SearchSourceProvider(Promise, Private, config) {
reject(error);
request.abort();
};
const req = new SegmentedRequest({ source: self, defer, errorHandler, initFn: initFunction });
const req = new SegmentedSearchRequest({ source: self, defer, errorHandler, initFn: initFunction });
// Return promises created by the completion handler so that
// errors will bubble properly
@ -404,18 +404,16 @@ export function SearchSourceProvider(Promise, Private, config) {
req = self._createRequest({ errorHandler });
}
fetchSoon.these([req]);
fetchSoon.fetchSearchRequests([req]);
return req.getCompletePromise();
}
/**
* Fetch all pending requests for this source ASAP
* @async
*/
fetchQueued() {
return fetchSoon.these(this._myStartableQueued());
return fetchSoon.fetchSearchRequests(this._myStartableQueued());
}
/**

View file

@ -35,7 +35,7 @@ describe('doc table filter actions', function () {
'kibana',
'kibana/courier',
function ($provide) {
$provide.service('courier', require('fixtures/mock_courier'));
$provide.service('indexPatterns', require('fixtures/mock_index_patterns'));
}
));

View file

@ -36,7 +36,7 @@ describe('add filters', function () {
'kibana/courier',
'kibana/global_state',
function ($provide) {
$provide.service('courier', require('fixtures/mock_courier'));
$provide.service('indexPatterns', require('fixtures/mock_index_patterns'));
appState = new MockState({ filters: [] });
$provide.service('getAppState', function () {

View file

@ -36,7 +36,7 @@ describe('invert filters', function () {
'kibana/courier',
'kibana/global_state',
function ($provide) {
$provide.service('courier', require('fixtures/mock_courier'));
$provide.service('indexPatterns', require('fixtures/mock_index_patterns'));
appState = new MockState({ filters: [] });
$provide.service('getAppState', function () {

View file

@ -36,7 +36,7 @@ describe('pin filters', function () {
'kibana/courier',
'kibana/global_state',
function ($provide) {
$provide.service('courier', require('fixtures/mock_courier'));
$provide.service('indexPatterns', require('fixtures/mock_index_patterns'));
appState = new MockState({ filters: [] });
$provide.service('getAppState', function () {

View file

@ -36,7 +36,7 @@ describe('remove filters', function () {
'kibana/courier',
'kibana/global_state',
function ($provide) {
$provide.service('courier', require('fixtures/mock_courier'));
$provide.service('indexPatterns', require('fixtures/mock_index_patterns'));
appState = new MockState({ filters: [] });
$provide.service('getAppState', function () {

View file

@ -36,7 +36,7 @@ describe('toggle filters', function () {
'kibana/courier',
'kibana/global_state',
function ($provide) {
$provide.service('courier', require('fixtures/mock_courier'));
$provide.service('indexPatterns', require('fixtures/mock_index_patterns'));
appState = new MockState({ filters: [] });
$provide.service('getAppState', function () {

View file

@ -48,7 +48,7 @@ describe('Filter Bar Directive', function () {
ngMock.module('kibana');
ngMock.module('kibana/courier', function ($provide) {
$provide.service('courier', require('fixtures/mock_courier'));
$provide.service('indexPatterns', require('fixtures/mock_index_patterns'));
});
ngMock.inject(function (Private, $injector, _$rootScope_, _$compile_) {

View file

@ -30,7 +30,7 @@ describe('Filter Bar Directive', function () {
'kibana',
'kibana/courier',
function ($provide) {
$provide.service('courier', require('fixtures/mock_courier'));
$provide.service('indexPatterns', require('fixtures/mock_index_patterns'));
}
));

View file

@ -31,7 +31,7 @@ describe('Filter Bar Directive', function () {
'kibana',
'kibana/courier',
function ($provide) {
$provide.service('courier', require('fixtures/mock_courier'));
$provide.service('indexPatterns', require('fixtures/mock_index_patterns'));
}
));

View file

@ -30,7 +30,7 @@ describe('Filter Bar Directive', function () {
'kibana',
'kibana/courier',
function ($provide) {
$provide.service('courier', require('fixtures/mock_courier'));
$provide.service('indexPatterns', require('fixtures/mock_index_patterns'));
}
));

View file

@ -30,7 +30,7 @@ describe('Filter Bar Directive', function () {
'kibana',
'kibana/courier',
function ($provide) {
$provide.service('courier', require('fixtures/mock_courier'));
$provide.service('indexPatterns', require('fixtures/mock_index_patterns'));
}
));

View file

@ -32,7 +32,7 @@ describe('Filter Bar Directive', function () {
'kibana',
'kibana/courier',
function ($provide) {
$provide.service('courier', require('fixtures/mock_courier'));
$provide.service('indexPatterns', require('fixtures/mock_index_patterns'));
}
));

View file

@ -30,7 +30,7 @@ describe('Filter Bar Directive', function () {
'kibana',
'kibana/courier',
function ($provide) {
$provide.service('courier', require('fixtures/mock_courier'));
$provide.service('indexPatterns', require('fixtures/mock_index_patterns'));
}
));

View file

@ -30,7 +30,7 @@ describe('Filter Bar Directive', function () {
'kibana',
'kibana/courier',
function ($provide) {
$provide.service('courier', require('fixtures/mock_courier'));
$provide.service('indexPatterns', require('fixtures/mock_index_patterns'));
}
));

View file

@ -30,7 +30,7 @@ describe('Filter Bar Directive', function () {
'kibana',
'kibana/courier',
function ($provide) {
$provide.service('courier', require('fixtures/mock_courier'));
$provide.service('indexPatterns', require('fixtures/mock_index_patterns'));
}
));

View file

@ -30,7 +30,7 @@ describe('Filter Bar Directive', function () {
'kibana',
'kibana/courier',
function ($provide) {
$provide.service('courier', require('fixtures/mock_courier'));
$provide.service('indexPatterns', require('fixtures/mock_index_patterns'));
}
));

View file

@ -19,14 +19,14 @@
import _ from 'lodash';
export function FilterBarLibExtractTimeFilterProvider(courier, Promise) {
export function FilterBarLibExtractTimeFilterProvider(indexPatterns, Promise) {
return Promise.method(function (filters) {
// Assume all the index patterns are the same since they will be added
// from the same visualization.
const id = _.get(filters, '[0].meta.index');
if (id == null) return;
return courier.indexPatterns.get(id).then(function (indexPattern) {
return indexPatterns.get(id).then(function (indexPattern) {
const filter = _.find(filters, function (obj) {
const key = _.keys(obj.range)[0];
return key === indexPattern.timeFieldName;

View file

@ -19,12 +19,12 @@
import _ from 'lodash';
export function FilterBarLibFilterOutTimeBasedFilterProvider(courier, Promise) {
export function FilterBarLibFilterOutTimeBasedFilterProvider(indexPatterns, Promise) {
return Promise.method(function (filters) {
const id = _.get(filters, '[0].meta.index');
if (id == null) return;
return courier.indexPatterns.get(id).then(function (indexPattern) {
return indexPatterns.get(id).then(function (indexPattern) {
return _.filter(filters, function (filter) {
return !(filter.range && filter.range[indexPattern.timeFieldName]);
});

View file

@ -20,7 +20,7 @@
import _ from 'lodash';
import { SavedObjectNotFound } from '../../errors';
export function FilterBarLibMapGeoBoundingBoxProvider(Promise, courier) {
export function FilterBarLibMapGeoBoundingBoxProvider(Promise, indexPatterns) {
return function (filter) {
if (filter.geo_bounding_box) {
function getParams(indexPattern) {
@ -43,8 +43,7 @@ export function FilterBarLibMapGeoBoundingBoxProvider(Promise, courier) {
return { type, key, value, params };
}
return courier
.indexPatterns
return indexPatterns
.get(filter.meta.index)
.then(getParams)
.catch((error) => {

View file

@ -20,7 +20,7 @@
import _ from 'lodash';
import { SavedObjectNotFound } from '../../errors';
export function FilterBarLibMapGeoPolygonProvider(Promise, courier) {
export function FilterBarLibMapGeoPolygonProvider(Promise, indexPatterns) {
return function (filter) {
if (filter.geo_polygon) {
function getParams(indexPattern) {
@ -42,8 +42,7 @@ export function FilterBarLibMapGeoPolygonProvider(Promise, courier) {
return { type, key, value, params };
}
return courier
.indexPatterns
return indexPatterns
.get(filter.meta.index)
.then(getParams)
.catch((error) => {

View file

@ -20,7 +20,7 @@
import _ from 'lodash';
import { SavedObjectNotFound } from '../../errors';
export function FilterBarLibMapPhraseProvider(Promise, courier) {
export function FilterBarLibMapPhraseProvider(Promise, indexPatterns) {
return function (filter) {
const isScriptedPhraseFilter = isScriptedPhrase(filter);
if (!_.has(filter, ['query', 'match']) && !isScriptedPhraseFilter) {
@ -41,8 +41,7 @@ export function FilterBarLibMapPhraseProvider(Promise, courier) {
return { type, key, value, params };
}
return courier
.indexPatterns
return indexPatterns
.get(filter.meta.index)
.then(getParams)
.catch((error) => {

View file

@ -20,7 +20,7 @@
import { has, get } from 'lodash';
import { SavedObjectNotFound } from '../../errors';
export function FilterBarLibMapRangeProvider(Promise, courier) {
export function FilterBarLibMapRangeProvider(Promise, indexPatterns) {
return function (filter) {
const isScriptedRangeFilter = isScriptedRange(filter);
if (!filter.range && !isScriptedRangeFilter) {
@ -51,8 +51,7 @@ export function FilterBarLibMapRangeProvider(Promise, courier) {
return { type, key, value, params };
}
return courier
.indexPatterns
return indexPatterns
.get(filter.meta.index)
.then(getParams)
.catch((error) => {

View file

@ -46,7 +46,7 @@ describe('Filter Manager', function () {
'kibana/courier',
'kibana/global_state',
function ($provide) {
$provide.service('courier', require('fixtures/mock_courier'));
$provide.service('indexPatterns', require('fixtures/mock_index_patterns'));
appState = new MockState({ filters: [] });
$provide.service('getAppState', function () {

View file

@ -18,4 +18,5 @@
*/
export { KbnUrlProvider } from './url';
export { RedirectWhenMissingProvider } from './redirect_when_missing';
export { modifyUrl } from './modify_url';

View file

@ -17,7 +17,12 @@
* under the License.
*/
import { SavedObjectNotFound } from '../errors';
import { uiModules } from '../modules';
uiModules.get('kibana/url')
.service('redirectWhenMissing', function (Private) { return Private(RedirectWhenMissingProvider); });
export function RedirectWhenMissingProvider($location, kbnUrl, Notifier, Promise) {
const notify = new Notifier();
@ -39,8 +44,11 @@ export function RedirectWhenMissingProvider($location, kbnUrl, Notifier, Promise
// if this error is not "404", rethrow
const savedObjectNotFound = err instanceof SavedObjectNotFound;
const unknownVisType = err.message.indexOf('Invalid type') === 0;
if (unknownVisType) err.savedObjectType = 'visualization';
else if (!savedObjectNotFound) throw err;
if (unknownVisType) {
err.savedObjectType = 'visualization';
} else if (!savedObjectNotFound) {
throw err;
}
let url = mapping[err.savedObjectType] || mapping['*'];
if (!url) url = '/';

View file

@ -18,6 +18,7 @@
*/
import _ from 'lodash';
import { VisRequestHandlersRegistryProvider } from '../../registry/vis_request_handlers';
import { calculateObjectHash } from '../lib/calculate_object_hash';
import { getRequestInspectorStats, getResponseInspectorStats } from '../../courier/utils/courier_inspector_utils';

View file

@ -36,7 +36,7 @@ import { onBrushEvent } from '../utils/brush_event';
import { FilterBarQueryFilterProvider } from '../filter_bar/query_filter';
import { FilterBarClickHandlerProvider } from '../filter_bar/filter_bar_click_handler';
import { updateVisualizationConfig } from './vis_update';
import { SearchSourceProvider } from '../courier/data_source/search_source';
import { SearchSourceProvider } from '../courier/search_source';
import { SavedObjectsClientProvider } from '../saved_objects';
import { timefilter } from 'ui/timefilter';

View file

@ -527,6 +527,7 @@ export function DashboardPageProvider({ getService, getPageObjects }) {
if (sliceValue) {
await testSubjects.click(`pieSlice-${sliceValue}`);
} else {
// If no pie slice has been provided, find the first one available.
await retry.try(async () => {
const slices = await find.allByCssSelector('svg > g > g.arcs > path.slice');
log.debug('Slices found:' + slices.length);

View file

@ -5,13 +5,15 @@
*/
import { uiModules } from 'ui/modules';
import { SavedObjectProvider } from 'ui/courier';
const module = uiModules.get('app/dashboard');
export function SavedWorkspaceProvider(courier) {
export function SavedWorkspaceProvider(Private) {
// SavedWorkspace constructor. Usually you'd interact with an instance of this.
// ID is option, without it one will be generated on save.
class SavedWorkspace extends courier.SavedObject {
const SavedObject = Private(SavedObjectProvider);
class SavedWorkspace extends SavedObject {
constructor(id) {
// Gives our SavedWorkspace the properties of a SavedObject
super ({

View file

@ -17,12 +17,10 @@ import rison from 'rison-node';
import 'plugins/kibana/visualize/styles/main.less';
import 'plugins/ml/components/form_filter_input';
import 'ui/courier';
import chrome from 'ui/chrome';
import uiRoutes from 'ui/routes';
import { notify } from 'ui/notify';
import { luceneStringToDsl } from 'ui/courier/data_source/build_query/lucene_string_to_dsl.js';
import { decorateQuery } from 'ui/courier/data_source/_decorate_query';
import { decorateQuery, luceneStringToDsl } from 'ui/courier';
import { ML_JOB_FIELD_TYPES, KBN_FIELD_TYPES } from 'plugins/ml/../common/constants/field_types';
import { kbnTypeToMLJobType } from 'plugins/ml/util/field_types_utils';

View file

@ -472,7 +472,7 @@ module.controller('MlNewJob',
// mappings should be fully set up, but the Kibana mappings then
// need to be refreshed to reflect the Elasticsearch mappings for
// any new analytical fields that have been configured in the job.
//courier.indexPatterns.get('.ml-anomalies-*')
//indexPatterns.get('.ml-anomalies-*')
//.then((indexPattern) => {
// indexPattern.refreshFields()
// .then(() => {

View file

@ -8,7 +8,7 @@
import _ from 'lodash';
import moment from 'moment';
import { migrateFilter } from 'ui/courier/data_source/_migrate_filter.js';
import { migrateFilter } from 'ui/courier';
import { addItemToRecentlyAccessed } from 'plugins/ml/util/recently_accessed';
import { mlJobService } from 'plugins/ml/services/job_service';

View file

@ -9,39 +9,39 @@
import { notify } from 'ui/notify';
import { SavedObjectsClientProvider } from 'ui/saved_objects';
let indexPatterns = [];
let indexPatternCache = [];
let fullIndexPatterns = [];
let currentIndexPattern = null;
let currentSavedSearch = null;
export function loadIndexPatterns(Private, courier) {
fullIndexPatterns = courier.indexPatterns;
export function loadIndexPatterns(Private, indexPatterns) {
fullIndexPatterns = indexPatterns;
const savedObjectsClient = Private(SavedObjectsClientProvider);
return savedObjectsClient.find({
type: 'index-pattern',
fields: ['title'],
perPage: 10000
}).then((response) => {
indexPatterns = response.savedObjects;
return indexPatterns;
indexPatternCache = response.savedObjects;
return indexPatternCache;
});
}
export function getIndexPatterns() {
return indexPatterns;
return indexPatternCache;
}
export function getIndexPatternIdFromName(name) {
for (let j = 0; j < indexPatterns.length; j++) {
if (indexPatterns[j].get('title') === name) {
return indexPatterns[j].id;
for (let j = 0; j < indexPatternCache.length; j++) {
if (indexPatternCache[j].get('title') === name) {
return indexPatternCache[j].id;
}
}
return name;
}
export function loadCurrentIndexPattern(courier, $route) {
fullIndexPatterns = courier.indexPatterns;
export function loadCurrentIndexPattern(indexPatterns, $route) {
fullIndexPatterns = indexPatterns;
currentIndexPattern = fullIndexPatterns.get($route.current.params.index);
return currentIndexPattern;
}
@ -50,7 +50,7 @@ export function getIndexPatternById(id) {
return fullIndexPatterns.get(id);
}
export function loadCurrentSavedSearch(courier, $route, savedSearches) {
export function loadCurrentSavedSearch($route, savedSearches) {
currentSavedSearch = savedSearches.get($route.current.params.savedSearchId);
return currentSavedSearch;
}