merge conflicts in x-pack/plugins/ml/public/util/ml_time_buckets.js (#20235)

This commit is contained in:
Nathan Reese 2018-06-26 12:45:54 -06:00 committed by GitHub
parent 9ff7ad3a9e
commit 7b0c5328ad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
118 changed files with 1374 additions and 1329 deletions

View file

@ -25,7 +25,7 @@ export function createSearchSource(kbnApi, initialState, indexPattern, aggs, use
searchSource.filter(() => { searchSource.filter(() => {
const activeFilters = [...filters]; const activeFilters = [...filters];
if (useTimeFilter) { if (useTimeFilter) {
activeFilters.push(kbnApi.timeFilter.get(indexPattern)); activeFilters.push(kbnApi.timeFilter.createFilter(indexPattern));
} }
return activeFilters; return activeFilters;
}); });

View file

@ -36,6 +36,7 @@ import {
LOADING_STATUS, LOADING_STATUS,
QueryActionsProvider, QueryActionsProvider,
} from './query'; } from './query';
import { timefilter } from 'ui/timefilter';
const module = uiModules.get('apps/context', [ const module = uiModules.get('apps/context', [
'elasticsearch', 'elasticsearch',
@ -66,7 +67,7 @@ module.directive('contextApp', function ContextApp() {
}; };
}); });
function ContextAppController($scope, config, Private, timefilter) { function ContextAppController($scope, config, Private) {
const queryParameterActions = Private(QueryParameterActionsProvider); const queryParameterActions = Private(QueryParameterActionsProvider);
const queryActions = Private(QueryActionsProvider); const queryActions = Private(QueryActionsProvider);

View file

@ -49,6 +49,7 @@ import { EmbeddableFactoriesRegistryProvider } from 'ui/embeddable/embeddable_fa
import { DashboardPanelActionsRegistryProvider } from 'ui/dashboard_panel_actions/dashboard_panel_actions_registry'; import { DashboardPanelActionsRegistryProvider } from 'ui/dashboard_panel_actions/dashboard_panel_actions_registry';
import { SavedObjectsClientProvider } from 'ui/saved_objects'; import { SavedObjectsClientProvider } from 'ui/saved_objects';
import { VisTypesRegistryProvider } from 'ui/registry/vis_types'; import { VisTypesRegistryProvider } from 'ui/registry/vis_types';
import { timefilter } from 'ui/timefilter';
import { DashboardViewportProvider } from './viewport/dashboard_viewport_provider'; import { DashboardViewportProvider } from './viewport/dashboard_viewport_provider';
@ -68,7 +69,6 @@ app.directive('dashboardViewportProvider', function (reactDirective) {
app.directive('dashboardApp', function ($injector) { app.directive('dashboardApp', function ($injector) {
const courier = $injector.get('courier'); const courier = $injector.get('courier');
const AppState = $injector.get('AppState'); const AppState = $injector.get('AppState');
const timefilter = $injector.get('timefilter');
const kbnUrl = $injector.get('kbnUrl'); const kbnUrl = $injector.get('kbnUrl');
const confirmModal = $injector.get('confirmModal'); const confirmModal = $injector.get('confirmModal');
const config = $injector.get('config'); const config = $injector.get('config');
@ -164,8 +164,7 @@ app.directive('dashboardApp', function ($injector) {
$rootScope.$broadcast('fetch'); $rootScope.$broadcast('fetch');
courier.fetch(...args); courier.fetch(...args);
}; };
$scope.timefilter = timefilter; dashboardStateManager.handleTimeChange(timefilter.getTime());
dashboardStateManager.handleTimeChange($scope.timefilter.time);
$scope.expandedPanel = null; $scope.expandedPanel = null;
$scope.dashboardViewMode = dashboardStateManager.getViewMode(); $scope.dashboardViewMode = dashboardStateManager.getViewMode();
@ -223,8 +222,8 @@ app.directive('dashboardApp', function ($injector) {
$scope.$watch('model.query', $scope.updateQueryAndFetch); $scope.$watch('model.query', $scope.updateQueryAndFetch);
$scope.$listen(timefilter, 'fetch', () => { $scope.$listenAndDigestAsync(timefilter, 'fetch', () => {
dashboardStateManager.handleTimeChange($scope.timefilter.time); dashboardStateManager.handleTimeChange(timefilter.getTime());
// Currently discover relies on this logic to re-fetch. We need to refactor it to rely instead on the // Currently discover relies on this logic to re-fetch. We need to refactor it to rely instead on the
// directly passed down time filter. Then we can get rid of this reliance on scope broadcasts. // directly passed down time filter. Then we can get rid of this reliance on scope broadcasts.
$scope.refresh(); $scope.refresh();

View file

@ -28,7 +28,10 @@ jest.mock('ui/chrome', () => ({ getKibanaVersion: () => '6.0.0' }), { virtual: t
describe('DashboardState', function () { describe('DashboardState', function () {
let dashboardState; let dashboardState;
const savedDashboard = getSavedDashboardMock(); const savedDashboard = getSavedDashboardMock();
const timefilter = { time: {} }; const mockTimefilter = {
time: {},
setTime: function (time) { this.time = time; },
};
const mockQuickTimeRanges = [{ from: 'now/w', to: 'now/w', display: 'This week', section: 0 }]; const mockQuickTimeRanges = [{ from: 'now/w', to: 'now/w', display: 'This week', section: 0 }];
const mockIndexPattern = { id: 'index1' }; const mockIndexPattern = { id: 'index1' };
@ -46,16 +49,16 @@ describe('DashboardState', function () {
savedDashboard.timeFrom = 'now/w'; savedDashboard.timeFrom = 'now/w';
savedDashboard.timeTo = 'now/w'; savedDashboard.timeTo = 'now/w';
timefilter.time.from = '2015-09-19 06:31:44.000'; mockTimefilter.time.from = '2015-09-19 06:31:44.000';
timefilter.time.to = '2015-09-29 06:31:44.000'; mockTimefilter.time.to = '2015-09-29 06:31:44.000';
timefilter.time.mode = 'absolute'; mockTimefilter.time.mode = 'absolute';
initDashboardState(); initDashboardState();
dashboardState.syncTimefilterWithDashboard(timefilter, mockQuickTimeRanges); dashboardState.syncTimefilterWithDashboard(mockTimefilter, mockQuickTimeRanges);
expect(timefilter.time.mode).toBe('quick'); expect(mockTimefilter.time.mode).toBe('quick');
expect(timefilter.time.to).toBe('now/w'); expect(mockTimefilter.time.to).toBe('now/w');
expect(timefilter.time.from).toBe('now/w'); expect(mockTimefilter.time.from).toBe('now/w');
}); });
test('syncs relative time', function () { test('syncs relative time', function () {
@ -63,16 +66,16 @@ describe('DashboardState', function () {
savedDashboard.timeFrom = 'now-13d'; savedDashboard.timeFrom = 'now-13d';
savedDashboard.timeTo = 'now'; savedDashboard.timeTo = 'now';
timefilter.time.from = '2015-09-19 06:31:44.000'; mockTimefilter.time.from = '2015-09-19 06:31:44.000';
timefilter.time.to = '2015-09-29 06:31:44.000'; mockTimefilter.time.to = '2015-09-29 06:31:44.000';
timefilter.time.mode = 'absolute'; mockTimefilter.time.mode = 'absolute';
initDashboardState(); initDashboardState();
dashboardState.syncTimefilterWithDashboard(timefilter, mockQuickTimeRanges); dashboardState.syncTimefilterWithDashboard(mockTimefilter, mockQuickTimeRanges);
expect(timefilter.time.mode).toBe('relative'); expect(mockTimefilter.time.mode).toBe('relative');
expect(timefilter.time.to).toBe('now'); expect(mockTimefilter.time.to).toBe('now');
expect(timefilter.time.from).toBe('now-13d'); expect(mockTimefilter.time.from).toBe('now-13d');
}); });
test('syncs absolute time', function () { test('syncs absolute time', function () {
@ -80,16 +83,16 @@ describe('DashboardState', function () {
savedDashboard.timeFrom = '2015-09-19 06:31:44.000'; savedDashboard.timeFrom = '2015-09-19 06:31:44.000';
savedDashboard.timeTo = '2015-09-29 06:31:44.000'; savedDashboard.timeTo = '2015-09-29 06:31:44.000';
timefilter.time.from = 'now/w'; mockTimefilter.time.from = 'now/w';
timefilter.time.to = 'now/w'; mockTimefilter.time.to = 'now/w';
timefilter.time.mode = 'quick'; mockTimefilter.time.mode = 'quick';
initDashboardState(); initDashboardState();
dashboardState.syncTimefilterWithDashboard(timefilter, mockQuickTimeRanges); dashboardState.syncTimefilterWithDashboard(mockTimefilter, mockQuickTimeRanges);
expect(timefilter.time.mode).toBe('absolute'); expect(mockTimefilter.time.mode).toBe('absolute');
expect(timefilter.time.to).toBe(savedDashboard.timeTo); expect(mockTimefilter.time.to).toBe(savedDashboard.timeTo);
expect(timefilter.time.from).toBe(savedDashboard.timeFrom); expect(mockTimefilter.time.from).toBe(savedDashboard.timeFrom);
}); });
}); });

View file

@ -142,12 +142,11 @@ export class DashboardStateManager {
* @param {String} newTimeFilter.mode * @param {String} newTimeFilter.mode
*/ */
handleTimeChange(newTimeFilter) { handleTimeChange(newTimeFilter) {
const timeFilter = { store.dispatch(updateTimeRange({
from: FilterUtils.convertTimeToUTCString(newTimeFilter.from), from: FilterUtils.convertTimeToUTCString(newTimeFilter.from),
to: FilterUtils.convertTimeToUTCString(newTimeFilter.to), to: FilterUtils.convertTimeToUTCString(newTimeFilter.to),
mode: newTimeFilter.mode, mode: newTimeFilter.mode,
}; }));
store.dispatch(updateTimeRange(timeFilter));
} }
/** /**
@ -433,8 +432,8 @@ export class DashboardStateManager {
*/ */
getTimeChanged(timeFilter) { getTimeChanged(timeFilter) {
return ( return (
!FilterUtils.areTimesEqual(this.lastSavedDashboardFilters.timeFrom, timeFilter.time.from) || !FilterUtils.areTimesEqual(this.lastSavedDashboardFilters.timeFrom, timeFilter.getTime().from) ||
!FilterUtils.areTimesEqual(this.lastSavedDashboardFilters.timeTo, timeFilter.time.to) !FilterUtils.areTimesEqual(this.lastSavedDashboardFilters.timeTo, timeFilter.getTime().to)
); );
} }
@ -536,7 +535,8 @@ export class DashboardStateManager {
/** /**
* Updates timeFilter to match the time saved with the dashboard. * Updates timeFilter to match the time saved with the dashboard.
* @param {Object} timeFilter * @param {Object} timeFilter
* @param {Object} timeFilter.time * @param {func} timeFilter.setTime
* @param {func} timeFilter.setRefreshInterval
* @param quickTimeRanges * @param quickTimeRanges
*/ */
syncTimefilterWithDashboard(timeFilter, quickTimeRanges) { syncTimefilterWithDashboard(timeFilter, quickTimeRanges) {
@ -544,20 +544,25 @@ export class DashboardStateManager {
throw new Error('The time is not saved with this dashboard so should not be synced.'); throw new Error('The time is not saved with this dashboard so should not be synced.');
} }
timeFilter.time.to = this.savedDashboard.timeTo; let mode;
timeFilter.time.from = this.savedDashboard.timeFrom;
const isMoment = moment(this.savedDashboard.timeTo).isValid(); const isMoment = moment(this.savedDashboard.timeTo).isValid();
if (isMoment) { if (isMoment) {
timeFilter.time.mode = 'absolute'; mode = 'absolute';
} else { } else {
const quickTime = _.find( const quickTime = _.find(
quickTimeRanges, quickTimeRanges,
(timeRange) => timeRange.from === this.savedDashboard.timeFrom && timeRange.to === this.savedDashboard.timeTo); (timeRange) => timeRange.from === this.savedDashboard.timeFrom && timeRange.to === this.savedDashboard.timeTo);
timeFilter.time.mode = quickTime ? 'quick' : 'relative'; mode = quickTime ? 'quick' : 'relative';
} }
timeFilter.setTime({
from: this.savedDashboard.timeFrom,
to: this.savedDashboard.timeTo,
mode
});
if (this.savedDashboard.refreshInterval) { if (this.savedDashboard.refreshInterval) {
timeFilter.refreshInterval = this.savedDashboard.refreshInterval; timeFilter.setRefreshInterval(this.savedDashboard.refreshInterval);
} }
} }

View file

@ -28,11 +28,11 @@ export function updateSavedDashboard(savedDashboard, appState, timeFilter, toJso
savedDashboard.optionsJSON = toJson(appState.options); savedDashboard.optionsJSON = toJson(appState.options);
savedDashboard.timeFrom = savedDashboard.timeRestore ? savedDashboard.timeFrom = savedDashboard.timeRestore ?
FilterUtils.convertTimeToUTCString(timeFilter.time.from) FilterUtils.convertTimeToUTCString(timeFilter.getTime().from)
: undefined; : undefined;
savedDashboard.timeTo = savedDashboard.timeRestore ? savedDashboard.timeTo = savedDashboard.timeRestore ?
FilterUtils.convertTimeToUTCString(timeFilter.time.to) FilterUtils.convertTimeToUTCString(timeFilter.getTime().to)
: undefined; : undefined;
const timeRestoreObj = _.pick(timeFilter.refreshInterval, ['display', 'pause', 'section', 'value']); const timeRestoreObj = _.pick(timeFilter.getRefreshInterval(), ['display', 'pause', 'section', 'value']);
savedDashboard.refreshInterval = savedDashboard.timeRestore ? timeRestoreObj : undefined; savedDashboard.refreshInterval = savedDashboard.timeRestore ? timeRestoreObj : undefined;
} }

View file

@ -31,7 +31,7 @@ import 'ui/filters/moment';
import 'ui/courier'; import 'ui/courier';
import 'ui/index_patterns'; import 'ui/index_patterns';
import 'ui/state_management/app_state'; import 'ui/state_management/app_state';
import 'ui/timefilter'; import { timefilter } from 'ui/timefilter';
import 'ui/share'; import 'ui/share';
import 'ui/query_bar'; import 'ui/query_bar';
import { toastNotifications, getPainlessError } from 'ui/notify'; import { toastNotifications, getPainlessError } from 'ui/notify';
@ -142,7 +142,6 @@ function discoverController(
config, config,
courier, courier,
kbnUrl, kbnUrl,
timefilter,
localStorage, localStorage,
) { ) {
@ -186,8 +185,6 @@ function discoverController(
template: require('plugins/kibana/discover/partials/share_search.html'), template: require('plugins/kibana/discover/partials/share_search.html'),
testId: 'discoverShareButton', testId: 'discoverShareButton',
}]; }];
$scope.timefilter = timefilter;
// the saved savedSearch // the saved savedSearch
const savedSearch = $route.current.locals.savedSearch; const savedSearch = $route.current.locals.savedSearch;
@ -204,7 +201,7 @@ function discoverController(
// searchSource which applies time range // searchSource which applies time range
const timeRangeSearchSource = savedSearch.searchSource.new(); const timeRangeSearchSource = savedSearch.searchSource.new();
timeRangeSearchSource.set('filter', () => { timeRangeSearchSource.set('filter', () => {
return timefilter.get($scope.indexPattern); return timefilter.createFilter($scope.indexPattern);
}); });
$scope.searchSource.inherits(timeRangeSearchSource); $scope.searchSource.inherits(timeRangeSearchSource);
@ -326,7 +323,6 @@ function discoverController(
timefield: $scope.indexPattern.timeFieldName, timefield: $scope.indexPattern.timeFieldName,
savedSearch: savedSearch, savedSearch: savedSearch,
indexPatternList: $route.current.locals.ip.list, indexPatternList: $route.current.locals.ip.list,
timefilter: $scope.timefilter
}; };
const init = _.once(function () { const init = _.once(function () {
@ -633,8 +629,8 @@ function discoverController(
$scope.updateTime = function () { $scope.updateTime = function () {
$scope.timeRange = { $scope.timeRange = {
from: dateMath.parse(timefilter.time.from), from: dateMath.parse(timefilter.getTime().from),
to: dateMath.parse(timefilter.time.to, { roundUp: true }) to: dateMath.parse(timefilter.getTime().to, { roundUp: true })
}; };
}; };
@ -739,7 +735,7 @@ function discoverController(
} }
$scope.vis.filters = { $scope.vis.filters = {
timeRange: timefilter.time timeRange: timefilter.getTime()
}; };
} }

View file

@ -22,10 +22,10 @@ import ngMock from 'ng_mock';
import expect from 'expect.js'; import expect from 'expect.js';
import '..'; import '..';
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
import { timefilter } from 'ui/timefilter';
let $scope; let $scope;
let createController; let createController;
let timefilter;
const init = function (index, type, id) { const init = function (index, type, id) {
@ -85,9 +85,8 @@ const init = function (index, type, id) {
}); });
// Create the scope // Create the scope
ngMock.inject(function ($rootScope, $controller, _timefilter_) { ngMock.inject(function ($rootScope, $controller) {
$scope = $rootScope.$new(); $scope = $rootScope.$new();
timefilter = _timefilter_;
createController = function () { createController = function () {
return $controller('doc', { return $controller('doc', {

View file

@ -24,6 +24,7 @@ import 'ui/index_patterns';
import html from '../index.html'; import html from '../index.html';
import uiRoutes from 'ui/routes'; import uiRoutes from 'ui/routes';
import { uiModules } from 'ui/modules'; import { uiModules } from 'ui/modules';
import { timefilter } from 'ui/timefilter';
const app = uiModules.get('apps/doc', [ const app = uiModules.get('apps/doc', [
@ -49,7 +50,7 @@ uiRoutes
resolve: resolveIndexPattern resolve: resolveIndexPattern
}); });
app.controller('doc', function ($scope, $route, es, timefilter) { app.controller('doc', function ($scope, $route, es) {
timefilter.disableAutoRefreshSelector(); timefilter.disableAutoRefreshSelector();
timefilter.disableTimeRangeSelector(); timefilter.disableTimeRangeSelector();

View file

@ -27,6 +27,7 @@ import appTemplate from './app.html';
import landingTemplate from './landing.html'; import landingTemplate from './landing.html';
import { management } from 'ui/management'; import { management } from 'ui/management';
import { FeatureCatalogueRegistryProvider, FeatureCatalogueCategory } from 'ui/registry/feature_catalogue'; import { FeatureCatalogueRegistryProvider, FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
import { timefilter } from 'ui/timefilter';
import 'ui/kbn_top_nav'; import 'ui/kbn_top_nav';
uiRoutes uiRoutes
@ -45,7 +46,7 @@ require('ui/index_patterns/route_setup/load_default')({
uiModules uiModules
.get('apps/management') .get('apps/management')
.directive('kbnManagementApp', function (Private, $location, timefilter) { .directive('kbnManagementApp', function (Private, $location) {
return { return {
restrict: 'E', restrict: 'E',
template: appTemplate, template: appTemplate,

View file

@ -40,6 +40,7 @@ import { KibanaParsedUrl } from 'ui/url/kibana_parsed_url';
import { absoluteToParsedUrl } from 'ui/url/absolute_to_parsed_url'; import { absoluteToParsedUrl } from 'ui/url/absolute_to_parsed_url';
import { migrateLegacyQuery } from 'ui/utils/migrateLegacyQuery'; import { migrateLegacyQuery } from 'ui/utils/migrateLegacyQuery';
import { recentlyAccessed } from 'ui/persisted_log'; import { recentlyAccessed } from 'ui/persisted_log';
import { timefilter } from 'ui/timefilter';
uiRoutes uiRoutes
.when(VisualizeConstants.CREATE_PATH, { .when(VisualizeConstants.CREATE_PATH, {
@ -96,7 +97,7 @@ uiModules
}; };
}); });
function VisEditor($scope, $route, timefilter, AppState, $window, kbnUrl, courier, Private, Promise, config, kbnBaseUrl, localStorage) { function VisEditor($scope, $route, AppState, $window, kbnUrl, courier, Private, Promise, config, kbnBaseUrl, localStorage) {
const docTitle = Private(DocTitleProvider); const docTitle = Private(DocTitleProvider);
const queryFilter = Private(FilterBarQueryFilterProvider); const queryFilter = Private(FilterBarQueryFilterProvider);
@ -221,9 +222,8 @@ function VisEditor($scope, $route, timefilter, AppState, $window, kbnUrl, courie
$scope.isAddToDashMode = () => addToDashMode; $scope.isAddToDashMode = () => addToDashMode;
$scope.timefilter = timefilter; $scope.timeRange = timefilter.getTime();
$scope.timeRange = timefilter.time; $scope.opts = _.pick($scope, 'doSave', 'savedVis', 'shareData', 'isAddToDashMode');
$scope.opts = _.pick($scope, 'doSave', 'savedVis', 'shareData', 'timefilter', 'isAddToDashMode');
stateMonitor = stateMonitorFactory.create($state, stateDefaults); stateMonitor = stateMonitorFactory.create($state, stateDefaults);
stateMonitor.ignoreProps([ 'vis.listeners' ]).onChange((status) => { stateMonitor.ignoreProps([ 'vis.listeners' ]).onChange((status) => {
@ -252,11 +252,11 @@ function VisEditor($scope, $route, timefilter, AppState, $window, kbnUrl, courie
}); });
const updateTimeRange = () => { const updateTimeRange = () => {
$scope.timeRange = timefilter.time; $scope.timeRange = timefilter.getTime();
}; };
timefilter.enableAutoRefreshSelector(); timefilter.enableAutoRefreshSelector();
timefilter.on('update', updateTimeRange); $scope.$listenAndDigestAsync(timefilter, 'timeUpdate', updateTimeRange);
// update the searchSource when filters update // update the searchSource when filters update
$scope.$listen(queryFilter, 'update', function () { $scope.$listen(queryFilter, 'update', function () {
@ -274,7 +274,6 @@ function VisEditor($scope, $route, timefilter, AppState, $window, kbnUrl, courie
$scope.$on('$destroy', function () { $scope.$on('$destroy', function () {
savedVis.destroy(); savedVis.destroy();
stateMonitor.destroy(); stateMonitor.destroy();
timefilter.off('update', updateTimeRange);
}); });
} }

View file

@ -21,6 +21,7 @@ import { SavedObjectRegistryProvider } from 'ui/saved_objects/saved_object_regis
import 'ui/pager_control'; import 'ui/pager_control';
import 'ui/pager'; import 'ui/pager';
import { uiModules } from 'ui/modules'; import { uiModules } from 'ui/modules';
import { timefilter } from 'ui/timefilter';
import { VisualizeListingTable } from './visualize_listing_table'; import { VisualizeListingTable } from './visualize_listing_table';
@ -32,7 +33,6 @@ app.directive('visualizeListingTable', function (reactDirective) {
export function VisualizeListingController($injector) { export function VisualizeListingController($injector) {
const Notifier = $injector.get('Notifier'); const Notifier = $injector.get('Notifier');
const Private = $injector.get('Private'); const Private = $injector.get('Private');
const timefilter = $injector.get('timefilter');
const config = $injector.get('config'); const config = $injector.get('config');
timefilter.disableAutoRefreshSelector(); timefilter.disableAutoRefreshSelector();

View file

@ -33,6 +33,7 @@ import { uiModules } from 'ui/modules';
import visualizeWizardStep1Template from './step_1.html'; import visualizeWizardStep1Template from './step_1.html';
import visualizeWizardStep2Template from './step_2.html'; import visualizeWizardStep2Template from './step_2.html';
import { SavedObjectsClientProvider } from 'ui/saved_objects'; import { SavedObjectsClientProvider } from 'ui/saved_objects';
import { timefilter } from 'ui/timefilter';
const module = uiModules.get('app/visualize', ['kibana/courier']); const module = uiModules.get('app/visualize', ['kibana/courier']);
@ -50,7 +51,7 @@ routes.when(VisualizeConstants.WIZARD_STEP_1_PAGE_PATH, {
controller: 'VisualizeWizardStep1', controller: 'VisualizeWizardStep1',
}); });
module.controller('VisualizeWizardStep1', function ($scope, $route, kbnUrl, timefilter, Private, config) { module.controller('VisualizeWizardStep1', function ($scope, $route, kbnUrl, Private, config) {
timefilter.disableAutoRefreshSelector(); timefilter.disableAutoRefreshSelector();
timefilter.disableTimeRangeSelector(); timefilter.disableTimeRangeSelector();
@ -220,7 +221,7 @@ routes.when(VisualizeConstants.WIZARD_STEP_2_PAGE_PATH, {
} }
}); });
module.controller('VisualizeWizardStep2', function ($route, $scope, timefilter, kbnUrl) { module.controller('VisualizeWizardStep2', function ($route, $scope, kbnUrl) {
const type = $route.current.params.type; const type = $route.current.params.type;
const addToDashMode = $route.current.params[DashboardConstants.ADD_VISUALIZATION_TO_DASHBOARD_MODE_PARAM]; const addToDashMode = $route.current.params[DashboardConstants.ADD_VISUALIZATION_TO_DASHBOARD_MODE_PARAM];
kbnUrl.removeParam(DashboardConstants.ADD_VISUALIZATION_TO_DASHBOARD_MODE_PARAM); kbnUrl.removeParam(DashboardConstants.ADD_VISUALIZATION_TO_DASHBOARD_MODE_PARAM);

View file

@ -20,8 +20,9 @@
import { validateInterval } from '../lib/validate_interval'; import { validateInterval } from '../lib/validate_interval';
import { dashboardContextProvider } from 'plugins/kibana/dashboard/dashboard_context'; import { dashboardContextProvider } from 'plugins/kibana/dashboard/dashboard_context';
import { timezoneProvider } from 'ui/vis/lib/timezone'; import { timezoneProvider } from 'ui/vis/lib/timezone';
import { timefilter } from 'ui/timefilter';
const MetricsRequestHandlerProvider = function (Private, Notifier, config, timefilter, $http) { const MetricsRequestHandlerProvider = function (Private, Notifier, config, $http) {
const dashboardContext = Private(dashboardContextProvider); const dashboardContext = Private(dashboardContextProvider);
const notify = new Notifier({ location: 'Metrics' }); const notify = new Notifier({ location: 'Metrics' });

View file

@ -22,21 +22,24 @@ import moment from 'moment';
import { expect } from 'chai'; import { expect } from 'chai';
describe('createBrushHandler', () => { describe('createBrushHandler', () => {
let timefilter; let mockTimefilter;
let fn; let onBrush;
let range; let range;
beforeEach(() => { beforeEach(() => {
timefilter = { time: {}, update: () => {} }; mockTimefilter = {
fn = createBrushHandler(timefilter); time: {},
range = { xaxis: { from: '2017-01-01T00:00:00Z', to: '2017-01-01T00:10:00Z' } }; setTime: function (time) { this.time = time; }
fn(range); };
onBrush = createBrushHandler(mockTimefilter);
}); });
it('returns brushHandler() that updates timefilter', () => { test('returns brushHandler() that updates timefilter', () => {
expect(timefilter.time.from).to.equal(moment(range.xaxis.from).toISOString()); range = { xaxis: { from: '2017-01-01T00:00:00Z', to: '2017-01-01T00:10:00Z' } };
expect(timefilter.time.to).to.equal(moment(range.xaxis.to).toISOString()); onBrush(range);
expect(timefilter.time.mode).to.equal('absolute'); expect(mockTimefilter.time.from).to.equal(moment(range.xaxis.from).toISOString());
expect(mockTimefilter.time.to).to.equal(moment(range.xaxis.to).toISOString());
expect(mockTimefilter.time.mode).to.equal('absolute');
}); });
}); });

View file

@ -19,10 +19,9 @@
import moment from 'moment'; import moment from 'moment';
export default (timefilter) => ranges => { export default (timefilter) => ranges => {
//$scope.$evalAsync(() => { timefilter.setTime({
timefilter.time.from = moment(ranges.xaxis.from).toISOString(); from: moment(ranges.xaxis.from).toISOString(),
timefilter.time.to = moment(ranges.xaxis.to).toISOString(); to: moment(ranges.xaxis.to).toISOString(),
timefilter.time.mode = 'absolute'; mode: 'absolute',
timefilter.update(); });
//});
}; };

View file

@ -25,6 +25,7 @@ import { SavedObjectRegistryProvider } from 'ui/saved_objects/saved_object_regis
import { notify, fatalError, toastNotifications } from 'ui/notify'; import { notify, fatalError, toastNotifications } from 'ui/notify';
import { timezoneProvider } from 'ui/vis/lib/timezone'; import { timezoneProvider } from 'ui/vis/lib/timezone';
import { recentlyAccessed } from 'ui/persisted_log'; import { recentlyAccessed } from 'ui/persisted_log';
import { timefilter } from 'ui/timefilter';
// import the uiExports that we want to "use" // import the uiExports that we want to "use"
import 'uiExports/fieldFormats'; import 'uiExports/fieldFormats';
@ -93,7 +94,6 @@ app.controller('timelion', function (
kbnUrl, kbnUrl,
Notifier, Notifier,
Private, Private,
timefilter
) { ) {
// Keeping this at app scope allows us to keep the current page when the user // Keeping this at app scope allows us to keep the current page when the user
@ -213,8 +213,9 @@ app.controller('timelion', function (
}; };
let refresher; let refresher;
$scope.$watchCollection('timefilter.refreshInterval', function (interval) { $scope.$listen(timefilter, 'refreshIntervalUpdate', function () {
if (refresher) $timeout.cancel(refresher); if (refresher) $timeout.cancel(refresher);
const interval = timefilter.getRefreshInterval();
if (interval.value > 0 && !interval.pause) { if (interval.value > 0 && !interval.pause) {
function startRefresh() { function startRefresh() {
refresher = $timeout(function () { refresher = $timeout(function () {
@ -254,7 +255,7 @@ app.controller('timelion', function (
const httpResult = $http.post('../api/timelion/run', { const httpResult = $http.post('../api/timelion/run', {
sheet: $scope.state.sheet, sheet: $scope.state.sheet,
time: _.extend(timefilter.time, { time: _.extend(timefilter.getTime(), {
interval: $scope.state.interval, interval: $scope.state.interval,
timezone: timezone timezone: timezone
}), }),

View file

@ -24,10 +24,11 @@ import $ from 'jquery';
import moment from 'moment-timezone'; import moment from 'moment-timezone';
import observeResize from '../../lib/observe_resize'; import observeResize from '../../lib/observe_resize';
import { calculateInterval, DEFAULT_TIME_FORMAT } from '../../../common/lib'; import { calculateInterval, DEFAULT_TIME_FORMAT } from '../../../common/lib';
import { timefilter } from 'ui/timefilter';
const DEBOUNCE_DELAY = 50; const DEBOUNCE_DELAY = 50;
export default function timechartFn(Private, config, $rootScope, timefilter, $compile) { export default function timechartFn(Private, config, $rootScope, $compile) {
return function () { return function () {
return { return {
help: 'Draw a timeseries chart', help: 'Draw a timeseries chart',
@ -173,10 +174,11 @@ export default function timechartFn(Private, config, $rootScope, timefilter, $co
}); });
$elem.on('plotselected', function (event, ranges) { $elem.on('plotselected', function (event, ranges) {
timefilter.time.from = moment(ranges.xaxis.from); timefilter.setTime({
timefilter.time.to = moment(ranges.xaxis.to); from: moment(ranges.xaxis.from),
timefilter.time.mode = 'absolute'; to: moment(ranges.xaxis.to),
$scope.$apply(); mode: 'absolute',
});
}); });
$elem.on('mouseleave', function () { $elem.on('mouseleave', function () {

View file

@ -21,8 +21,9 @@ import { VegaParser } from './data_model/vega_parser';
import { dashboardContextProvider } from 'plugins/kibana/dashboard/dashboard_context'; import { dashboardContextProvider } from 'plugins/kibana/dashboard/dashboard_context';
import { SearchCache } from './data_model/search_cache'; import { SearchCache } from './data_model/search_cache';
import { TimeCache } from './data_model/time_cache'; import { TimeCache } from './data_model/time_cache';
import { timefilter } from 'ui/timefilter';
export function VegaRequestHandlerProvider(Private, es, timefilter, serviceSettings) { export function VegaRequestHandlerProvider(Private, es, serviceSettings) {
const dashboardContext = Private(dashboardContextProvider); const dashboardContext = Private(dashboardContextProvider);
const searchCache = new SearchCache(es, { max: 10, maxAge: 4 * 1000 }); const searchCache = new SearchCache(es, { max: 10, maxAge: 4 * 1000 });

View file

@ -25,6 +25,7 @@ import AggParamWriterProvider from '../../agg_param_writer';
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
import { aggTypes } from '../../..'; import { aggTypes } from '../../..';
import { AggConfig } from '../../../../vis/agg_config'; import { AggConfig } from '../../../../vis/agg_config';
import { timefilter } from 'ui/timefilter';
describe('params', function () { describe('params', function () {
@ -35,10 +36,9 @@ describe('params', function () {
let timeField; let timeField;
beforeEach(ngMock.module('kibana')); beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject(function (Private, $injector) { beforeEach(ngMock.inject(function (Private) {
const AggParamWriter = Private(AggParamWriterProvider); const AggParamWriter = Private(AggParamWriterProvider);
const indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider); const indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
const timefilter = $injector.get('timefilter');
timeField = indexPattern.timeFieldName; timeField = indexPattern.timeFieldName;

View file

@ -24,7 +24,8 @@ import { metadata } from '../metadata';
import 'babel-polyfill'; import 'babel-polyfill';
import 'whatwg-fetch'; import 'whatwg-fetch';
import 'custom-event-polyfill'; import 'custom-event-polyfill';
import '../timefilter'; import '../state_management/global_state';
import '../config';
import '../notify'; import '../notify';
import '../private'; import '../private';
import '../promises'; import '../promises';

View file

@ -1,9 +1,9 @@
<kbn-timepicker <kbn-timepicker
from="timefilter.time.from" from="timefilterValues.time.from"
to="timefilter.time.to" to="timefilterValues.time.to"
mode="timefilter.time.mode" mode="timefilterValues.time.mode"
active-tab="'filter'" active-tab="'filter'"
interval="timefilter.refreshInterval" interval="timefilterValues.refreshInterval"
on-filter-select="updateFilter(from, to)" on-filter-select="updateFilter(from, to, mode)"
on-interval-select="updateInterval(interval)"> on-interval-select="updateInterval(interval)">
</kbn-timepicker> </kbn-timepicker>

View file

@ -1,9 +1,9 @@
<kbn-timepicker <kbn-timepicker
from="timefilter.time.from" from="timefilterValues.time.from"
to="timefilter.time.to" to="timefilterValues.time.to"
mode="timefilter.time.mode" mode="timefilterValues.time.mode"
active-tab="'interval'" active-tab="'interval'"
interval="timefilter.refreshInterval" interval="timefilterValues.refreshInterval"
on-filter-select="updateFilter(from, to)" on-filter-select="updateFilter(from, to, mode)"
on-interval-select="updateInterval(interval)"> on-interval-select="updateInterval(interval)">
</kbn-timepicker> </kbn-timepicker>

View file

@ -31,6 +31,7 @@ import { FetchSoonProvider } from './fetch';
import { SearchLooperProvider } from './looper/search'; import { SearchLooperProvider } from './looper/search';
import { SavedObjectProvider } from './saved_object'; import { SavedObjectProvider } from './saved_object';
import { RedirectWhenMissingProvider } from './_redirect_when_missing'; import { RedirectWhenMissingProvider } from './_redirect_when_missing';
import { timefilter } from 'ui/timefilter';
uiModules.get('kibana/courier') uiModules.get('kibana/courier')
@ -114,10 +115,9 @@ uiModules.get('kibana/courier')
} }
}; };
// Listen for refreshInterval changes $rootScope.$listen(timefilter, 'refreshIntervalUpdate', function () {
$rootScope.$watchCollection('timefilter.refreshInterval', function () { const refreshValue = _.get(timefilter.getRefreshInterval(), 'value');
const refreshValue = _.get($rootScope, 'timefilter.refreshInterval.value'); const refreshPause = _.get(timefilter.getRefreshInterval(), 'pause');
const refreshPause = _.get($rootScope, 'timefilter.refreshInterval.pause');
if (_.isNumber(refreshValue) && !refreshPause) { if (_.isNumber(refreshValue) && !refreshPause) {
self.fetchInterval(refreshValue); self.fetchInterval(refreshValue);
} else { } else {

View file

@ -18,8 +18,9 @@
*/ */
import { requestFetchParamsToBody } from './request_fetch_params_to_body'; import { requestFetchParamsToBody } from './request_fetch_params_to_body';
import { timefilter } from 'ui/timefilter';
export function RequestFetchParamsToBodyProvider(Promise, timefilter, kbnIndex, sessionId, config, esShardTimeout) { export function RequestFetchParamsToBodyProvider(Promise, kbnIndex, sessionId, config, esShardTimeout) {
return (requestsFetchParams) => ( return (requestsFetchParams) => (
requestFetchParamsToBody( requestFetchParamsToBody(
requestsFetchParams, requestsFetchParams,

View file

@ -22,8 +22,9 @@ import { Notifier } from '../../../notify';
import { SearchRequestProvider } from './search_request'; import { SearchRequestProvider } from './search_request';
import { SegmentedHandleProvider } from './segmented_handle'; import { SegmentedHandleProvider } from './segmented_handle';
import { pushAll } from '../../../utils/collection'; import { pushAll } from '../../../utils/collection';
import { timefilter } from 'ui/timefilter';
export function SegmentedRequestProvider(Private, timefilter, config) { export function SegmentedRequestProvider(Private, config) {
const SearchRequest = Private(SearchRequestProvider); const SearchRequest = Private(SearchRequestProvider);
const SegmentedHandle = Private(SegmentedHandleProvider); const SegmentedHandle = Private(SegmentedHandleProvider);

View file

@ -27,7 +27,7 @@ import { FilterBarLibMapAndFlattenFiltersProvider } from './lib/map_and_flatten_
import { FilterBarLibMapFlattenAndWrapFiltersProvider } from './lib/map_flatten_and_wrap_filters'; import { FilterBarLibMapFlattenAndWrapFiltersProvider } from './lib/map_flatten_and_wrap_filters';
import { FilterBarLibExtractTimeFilterProvider } from './lib/extract_time_filter'; import { FilterBarLibExtractTimeFilterProvider } from './lib/extract_time_filter';
import { FilterBarLibFilterOutTimeBasedFilterProvider } from './lib/filter_out_time_based_filter'; import { FilterBarLibFilterOutTimeBasedFilterProvider } from './lib/filter_out_time_based_filter';
import { FilterBarLibChangeTimeFilterProvider } from './lib/change_time_filter'; import { changeTimeFilter } from './lib/change_time_filter';
import { FilterBarQueryFilterProvider } from './query_filter'; import { FilterBarQueryFilterProvider } from './query_filter';
import { compareFilters } from './lib/compare_filters'; import { compareFilters } from './lib/compare_filters';
import { uiModules } from '../modules'; import { uiModules } from '../modules';
@ -42,7 +42,6 @@ module.directive('filterBar', function (Private, Promise, getAppState) {
const mapFlattenAndWrapFilters = Private(FilterBarLibMapFlattenAndWrapFiltersProvider); const mapFlattenAndWrapFilters = Private(FilterBarLibMapFlattenAndWrapFiltersProvider);
const extractTimeFilter = Private(FilterBarLibExtractTimeFilterProvider); const extractTimeFilter = Private(FilterBarLibExtractTimeFilterProvider);
const filterOutTimeBasedFilter = Private(FilterBarLibFilterOutTimeBasedFilterProvider); const filterOutTimeBasedFilter = Private(FilterBarLibFilterOutTimeBasedFilterProvider);
const changeTimeFilter = Private(FilterBarLibChangeTimeFilterProvider);
const queryFilter = Private(FilterBarQueryFilterProvider); const queryFilter = Private(FilterBarQueryFilterProvider);
return { return {

View file

@ -1,61 +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 moment from 'moment';
import ngMock from 'ng_mock';
import expect from 'expect.js';
import { FilterBarLibChangeTimeFilterProvider } from '../change_time_filter';
describe('Filter Bar Directive', function () {
describe('changeTimeFilter()', function () {
let changeTimeFilter;
let timefilter;
beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject(function (Private, _timefilter_) {
changeTimeFilter = Private(FilterBarLibChangeTimeFilterProvider);
timefilter = _timefilter_;
}));
it('should change the timefilter to match the range gt/lt', function () {
const filter = { range: { '@timestamp': { gt: 1388559600000, lt: 1388646000000 } } };
changeTimeFilter(filter);
expect(timefilter.time.mode).to.be('absolute');
expect(moment.isMoment(timefilter.time.to)).to.be(true);
expect(timefilter.time.to.isSame('2014-01-02'));
expect(moment.isMoment(timefilter.time.from)).to.be(true);
expect(timefilter.time.from.isSame('2014-01-01'));
});
it('should change the timefilter to match the range gte/lte', function () {
const filter = { range: { '@timestamp': { gte: 1388559600000, lte: 1388646000000 } } };
changeTimeFilter(filter);
expect(timefilter.time.mode).to.be('absolute');
expect(moment.isMoment(timefilter.time.to)).to.be(true);
expect(timefilter.time.to.isSame('2014-01-02'));
expect(moment.isMoment(timefilter.time.from)).to.be(true);
expect(timefilter.time.from.isSame('2014-01-01'));
});
});
});

View file

@ -0,0 +1,65 @@
/*
* 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.
*/
jest.mock('ui/chrome',
() => ({
getUiSettingsClient: () => {
return {
get: (key) => {
switch(key) {
case 'timepicker:timeDefaults':
return { from: 'now-15m', to: 'now', mode: 'quick' };
case 'timepicker:refreshIntervalDefaults':
return { display: 'Off', pause: false, value: 0 };
default:
throw new Error(`Unexpected config key: ${key}`);
}
}
};
},
}), { virtual: true });
import moment from 'moment';
import expect from 'expect.js';
import { changeTimeFilter } from '../change_time_filter';
import { timefilter } from 'ui/timefilter';
describe('changeTimeFilter()', function () {
test('should change the timefilter to match the range gt/lt', function () {
const filter = { range: { '@timestamp': { gt: 1388559600000, lt: 1388646000000 } } };
changeTimeFilter(filter);
expect(timefilter.getTime().mode).to.be('absolute');
expect(moment.isMoment(timefilter.getTime().to)).to.be(true);
expect(timefilter.getTime().to.isSame('2014-01-02'));
expect(moment.isMoment(timefilter.getTime().from)).to.be(true);
expect(timefilter.getTime().from.isSame('2014-01-01'));
});
test('should change the timefilter to match the range gte/lte', function () {
const filter = { range: { '@timestamp': { gte: 1388559600000, lte: 1388646000000 } } };
changeTimeFilter(filter);
expect(timefilter.getTime().mode).to.be('absolute');
expect(moment.isMoment(timefilter.getTime().to)).to.be(true);
expect(timefilter.getTime().to.isSame('2014-01-02'));
expect(moment.isMoment(timefilter.getTime().from)).to.be(true);
expect(timefilter.getTime().from.isSame('2014-01-01'));
});
});

View file

@ -19,13 +19,14 @@
import moment from 'moment'; import moment from 'moment';
import _ from 'lodash'; import _ from 'lodash';
import { timefilter } from 'ui/timefilter';
export function FilterBarLibChangeTimeFilterProvider(timefilter) { export function changeTimeFilter(filter) {
return function (filter) { const key = _.keys(filter.range)[0];
const key = _.keys(filter.range)[0]; const values = filter.range[key];
const values = filter.range[key]; timefilter.setTime({
timefilter.time.from = moment(values.gt || values.gte); from: moment(values.gt || values.gte),
timefilter.time.to = moment(values.lt || values.lte); to: moment(values.lt || values.lte),
timefilter.time.mode = 'absolute'; mode: 'absolute',
}; });
} }

View file

@ -21,8 +21,9 @@ import _ from 'lodash';
import moment from 'moment'; import moment from 'moment';
import { IndexedArray } from '../indexed_array'; import { IndexedArray } from '../indexed_array';
import { isNumeric } from '../utils/numeric'; import { isNumeric } from '../utils/numeric';
import { timefilter } from 'ui/timefilter';
export function IndexPatternsIntervalsProvider(timefilter) { export function IndexPatternsIntervalsProvider() {
const intervals = new IndexedArray({ const intervals = new IndexedArray({
index: ['name'], index: ['name'],

View file

@ -22,15 +22,15 @@ import { uiModules } from '../modules';
uiModules.get('kibana') uiModules.get('kibana')
.run(function ($rootScope) { .run(function ($rootScope) {
/** /**
* Helper that registers an event listener, and removes that listener when * Helper that registers an event listener, and removes that listener when
* the $scope is destroyed. * the $scope is destroyed.
* *
* @param {EventEmitter} emitter - the event emitter to listen to * @param {SimpleEmitter} emitter - the event emitter to listen to
* @param {string} eventName - the event name * @param {string} eventName - the event name
* @param {Function} handler - the event handler * @param {Function} handler - the event handler
* @return {undefined} * @return {undefined}
*/ */
$rootScope.constructor.prototype.$listen = function (emitter, eventName, handler) { $rootScope.constructor.prototype.$listen = function (emitter, eventName, handler) {
emitter.on(eventName, handler); emitter.on(eventName, handler);
this.$on('$destroy', function () { this.$on('$destroy', function () {
@ -38,4 +38,20 @@ uiModules.get('kibana')
}); });
}; };
/**
* Helper that registers an event listener, and removes that listener when
* the $scope is destroyed. Handler is executed inside $evalAsync, ensuring digest cycle is run after the handler
*
* @param {SimpleEmitter} emitter - the event emitter to listen to
* @param {string} eventName - the event name
* @param {Function} handler - the event handler
* @return {undefined}
*/
$rootScope.constructor.prototype.$listenAndDigestAsync = function (emitter, eventName, handler) {
const evalAsyncWrappedHandler = (...args) => {
this.$evalAsync(() => handler(args));
};
this.$listen(emitter, eventName, evalAsyncWrappedHandler);
};
}); });

View file

@ -1,84 +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 sinon from 'sinon';
import expect from 'expect.js';
import ngMock from 'ng_mock';
describe('Timefilter service', function () {
describe('calculateBounds', function () {
beforeEach(ngMock.module('kibana'));
const fifteenMinutesInMilliseconds = 15 * 60 * 1000;
const clockNowTicks = new Date(2000, 1, 1, 0, 0, 0, 0).valueOf();
let timefilter;
let $location;
let clock;
beforeEach(ngMock.inject(function (_timefilter_, _$location_) {
timefilter = _timefilter_;
$location = _$location_;
clock = sinon.useFakeTimers(clockNowTicks);
}));
afterEach(function () {
clock.restore();
});
it('uses clock time by default', function () {
const timeRange = {
from: 'now-15m',
to: 'now'
};
const result = timefilter.calculateBounds(timeRange);
expect(result.min.valueOf()).to.eql(clockNowTicks - fifteenMinutesInMilliseconds);
expect(result.max.valueOf()).to.eql(clockNowTicks);
});
it('uses forceNow string', function () {
const timeRange = {
from: 'now-15m',
to: 'now'
};
const forceNowString = '1999-01-01T00:00:00.000Z';
$location.search('forceNow', forceNowString);
const result = timefilter.calculateBounds(timeRange);
const forceNowTicks = Date.parse(forceNowString);
expect(result.min.valueOf()).to.eql(forceNowTicks - fifteenMinutesInMilliseconds);
expect(result.max.valueOf()).to.eql(forceNowTicks);
});
it(`throws Error if forceNow can't be parsed`, function () {
const timeRange = {
from: 'now-15m',
to: 'now'
};
$location.search('forceNow', 'malformed%20string');
expect(() => timefilter.calculateBounds(timeRange)).to.throwError();
});
});
});

View file

@ -17,4 +17,4 @@
* under the License. * under the License.
*/ */
import './timefilter'; export { timefilter, registerTimefilterWithGlobalState } from './timefilter';

View file

@ -1,36 +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 { areTimePickerValsDifferent } from './diff_time_picker_vals';
export function diffIntervalFactory(self) {
let oldRefreshInterval = _.clone(self.refreshInterval);
return function () {
if (areTimePickerValsDifferent(self.refreshInterval, oldRefreshInterval)) {
self.emit('update');
if (!self.refreshInterval.pause && self.refreshInterval.value !== 0) {
self.emit('fetch');
}
}
oldRefreshInterval = _.clone(self.refreshInterval);
};
}

View file

@ -1,95 +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 sinon from 'sinon';
import expect from 'expect.js';
import { diffIntervalFactory } from '../lib/diff_interval';
describe('Refresh interval diff watcher', () => {
let diffInterval;
let update;
let fetch;
let timefilter;
beforeEach(() => {
update = sinon.spy();
fetch = sinon.spy();
timefilter = {
refreshInterval: {
pause: false,
value: 0
},
emit: (eventType) => {
if (eventType === 'update') update();
if (eventType === 'fetch') fetch();
}
};
diffInterval = diffIntervalFactory(timefilter);
});
test('not emit anything if nothing has changed', () => {
timefilter.refreshInterval = { pause: false, value: 0 };
diffInterval();
expect(update.called).to.be(false);
expect(fetch.called).to.be(false);
});
test('emit only an update when paused', () => {
timefilter.refreshInterval = { pause: true, value: 5000 };
diffInterval();
expect(update.called).to.be(true);
expect(fetch.called).to.be(false);
});
test('emit update, not fetch, when switching to value: 0', () => {
timefilter.refreshInterval = { pause: false, value: 5000 };
diffInterval();
expect(update.calledOnce).to.be(true);
expect(fetch.calledOnce).to.be(true);
timefilter.refreshInterval = { pause: false, value: 0 };
diffInterval();
expect(update.calledTwice).to.be(true);
expect(fetch.calledTwice).to.be(false);
});
test('should emit update, not fetch, when moving from unpaused to paused', () => {
timefilter.refreshInterval = { pause: false, value: 5000 };
diffInterval();
expect(update.calledOnce).to.be(true);
expect(fetch.calledOnce).to.be(true);
timefilter.refreshInterval = { pause: true, value: 5000 };
diffInterval();
expect(update.calledTwice).to.be(true);
expect(fetch.calledTwice).to.be(false);
});
test('should emit update and fetch when unpaused', () => {
timefilter.refreshInterval = { pause: true, value: 5000 };
diffInterval();
expect(update.calledOnce).to.be(true);
expect(fetch.calledOnce).to.be(false);
timefilter.refreshInterval = { pause: false, value: 5000 };
diffInterval();
expect(update.calledTwice).to.be(true);
expect(fetch.calledOnce).to.be(true);
});
});

View file

@ -1,34 +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 { areTimePickerValsDifferent } from './diff_time_picker_vals';
import { timeHistory } from '../time_history';
export function diffTimeFactory(self) {
let oldTime = _.clone(self.time);
return function () {
if (areTimePickerValsDifferent(self.time, oldTime)) {
timeHistory.add(self.time);
self.emit('update');
self.emit('fetch');
}
oldTime = _.clone(self.time);
};
}

View file

@ -1,61 +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 sinon from 'sinon';
import expect from 'expect.js';
import { diffTimeFactory } from '../lib/diff_time';
describe('time diff watcher', () => {
let diffTime;
let update;
let fetch;
let timefilter;
beforeEach(() => {
update = sinon.spy();
fetch = sinon.spy();
timefilter = {
time: {
from: 0,
to: 1
},
emit: function (eventType) {
if (eventType === 'update') update();
if (eventType === 'fetch') fetch();
}
};
diffTime = diffTimeFactory(timefilter);
});
test('not emit anything if the time has not changed', () => {
timefilter.time = { from: 0, to: 1 };
diffTime();
expect(update.called).to.be(false);
expect(fetch.called).to.be(false);
});
test('emit update and fetch if the time has changed', () => {
timefilter.time = { from: 5, to: 10 };
diffTime();
expect(update.called).to.be(true);
expect(fetch.called).to.be(true);
});
});

View file

@ -17,11 +17,15 @@
* under the License. * under the License.
*/ */
import { uiModules } from '../../modules'; import qs from 'querystring';
uiModules.get('kibana').config(function ($provide) { export function parseQueryString() {
$provide.decorator('timefilter', function ($delegate) { // window.location.search is an empty string
$delegate.init(); // get search from href
return $delegate; const hrefSplit = window.location.href.split('?');
}); if (hrefSplit.length <= 1) {
}); return {};
}
return qs.parse(hrefSplit[1]);
}

View file

@ -20,142 +20,174 @@
import _ from 'lodash'; import _ from 'lodash';
import moment from 'moment'; import moment from 'moment';
import { calculateBounds, getTime } from './get_time'; import { calculateBounds, getTime } from './get_time';
import '../state_management/global_state'; import { parseQueryString } from 'ui/timefilter/lib/parse_querystring';
import '../config'; import { SimpleEmitter } from 'ui/utils/simple_emitter';
import { EventsProvider } from '../events';
import { diffTimeFactory } from './lib/diff_time';
import { diffIntervalFactory } from './lib/diff_interval';
import uiRoutes from '../routes'; import uiRoutes from '../routes';
import { uiModules } from '../modules'; import chrome from 'ui/chrome';
import { createLegacyClass } from '../utils/legacy_class'; import { areTimePickerValsDifferent } from './lib/diff_time_picker_vals';
import { timeHistory } from './time_history';
class Timefilter extends SimpleEmitter {
constructor() {
super();
this.isTimeRangeSelectorEnabled = false;
this.isAutoRefreshSelectorEnabled = false;
this._time = chrome.getUiSettingsClient().get('timepicker:timeDefaults');
this._refreshInterval = chrome.getUiSettingsClient().get('timepicker:refreshIntervalDefaults');
}
getTime = () => {
return _.clone(this._time);
}
/**
* Updates timefilter time.
* Emits 'timeUpdate' and 'fetch' events when time changes
* @param {Object} time
* @property {string|moment} time.from
* @property {string|moment} time.to
* @property {string} time.mode (quick | relative | absolute)
*/
setTime = (time) => {
// Object.assign used for partially composed updates
const newTime = Object.assign(this.getTime(), time);
if (areTimePickerValsDifferent(this.getTime(), newTime)) {
this._time = newTime;
timeHistory.add(newTime);
this.emit('timeUpdate');
this.emit('fetch');
}
}
getRefreshInterval = () => {
return _.clone(this._refreshInterval);
}
/**
* Set timefilter refresh interval.
* @param {Object} refreshInterval
* @property {number} time.value
* @property {boolean} time.pause
*/
setRefreshInterval = (refreshInterval) => {
// Object.assign used for partially composed updates
const newRefreshInterval = Object.assign(this.getRefreshInterval(), refreshInterval);
if (areTimePickerValsDifferent(this.getRefreshInterval(), newRefreshInterval)) {
this._refreshInterval = newRefreshInterval;
this.emit('refreshIntervalUpdate');
if (!newRefreshInterval.pause && newRefreshInterval.value !== 0) {
this.emit('fetch');
}
}
}
toggleRefresh = () => {
this.setRefreshInterval({ pause: !this._refreshInterval.pause });
}
createFilter = (indexPattern, timeRange) => {
return getTime(indexPattern, timeRange ? timeRange : this._time, this.getForceNow());
}
getBounds = () => {
return this.calculateBounds(this._time);
}
getForceNow = () => {
const forceNow = parseQueryString().forceNow;
if (!forceNow) {
return;
}
const ticks = Date.parse(forceNow);
if (isNaN(ticks)) {
throw new Error(`forceNow query parameter, ${forceNow}, can't be parsed by Date.parse`);
}
return new Date(ticks);
}
calculateBounds = (timeRange) => {
return calculateBounds(timeRange, { forceNow: this.getForceNow() });
}
getActiveBounds = () => {
if (this.isTimeRangeSelectorEnabled) {
return this.getBounds();
}
}
/**
* Show the time bounds selector part of the time filter
*/
enableTimeRangeSelector = () => {
this.isTimeRangeSelectorEnabled = true;
this.emit('enabledUpdated');
}
/**
* Hide the time bounds selector part of the time filter
*/
disableTimeRangeSelector = () => {
this.isTimeRangeSelectorEnabled = false;
this.emit('enabledUpdated');
}
/**
* Show the auto refresh part of the time filter
*/
enableAutoRefreshSelector = () => {
this.isAutoRefreshSelectorEnabled = true;
this.emit('enabledUpdated');
}
/**
* Hide the auto refresh part of the time filter
*/
disableAutoRefreshSelector = () => {
this.isAutoRefreshSelectorEnabled = false;
this.emit('enabledUpdated');
}
}
export const timefilter = new Timefilter();
// TODO
// remove everything underneath once globalState is no longer an angular service
// and listener can be registered without angular.
function convertISO8601(stringTime) {
const obj = moment(stringTime, 'YYYY-MM-DDTHH:mm:ss.SSSZ', true);
return obj.isValid() ? obj : stringTime;
}
// Currently some parts of Kibana (index patterns, timefilter) rely on addSetupWork in the uiRouter
// and require it to be executed to properly function.
// This function is exposed for applications that do not use uiRoutes like APM
// Kibana issue https://github.com/elastic/kibana/issues/19110 tracks the removal of this dependency on uiRouter
export const registerTimefilterWithGlobalState = _.once((globalState) => {
const uiSettings = chrome.getUiSettingsClient();
const timeDefaults = uiSettings.get('timepicker:timeDefaults');
const refreshIntervalDefaults = uiSettings.get('timepicker:refreshIntervalDefaults');
timefilter.setTime(_.defaults(globalState.time || {}, timeDefaults));
timefilter.setRefreshInterval(_.defaults(globalState.refreshInterval || {}, refreshIntervalDefaults));
globalState.on('fetch_with_changes', () => {
// clone and default to {} in one
const newTime = _.defaults({}, globalState.time, timeDefaults);
const newRefreshInterval = _.defaults({}, globalState.refreshInterval, refreshIntervalDefaults);
if (newTime) {
if (newTime.to) newTime.to = convertISO8601(newTime.to);
if (newTime.from) newTime.from = convertISO8601(newTime.from);
}
timefilter.setTime(newTime);
timefilter.setRefreshInterval(newRefreshInterval);
});
});
uiRoutes uiRoutes
.addSetupWork(function (timefilter) { .addSetupWork((globalState) => {
return timefilter.init(); return registerTimefilterWithGlobalState(globalState);
});
uiModules
.get('kibana')
.service('timefilter', function (Private, globalState, $rootScope, config, $location) {
const Events = Private(EventsProvider);
function convertISO8601(stringTime) {
const obj = moment(stringTime, 'YYYY-MM-DDTHH:mm:ss.SSSZ', true);
return obj.isValid() ? obj : stringTime;
}
createLegacyClass(Timefilter).inherits(Events);
function Timefilter() {
Timefilter.Super.call(this);
const self = this;
const diffTime = diffTimeFactory(self);
const diffInterval = diffIntervalFactory(self);
self.isTimeRangeSelectorEnabled = false;
self.isAutoRefreshSelectorEnabled = false;
self.init = _.once(function () {
const timeDefaults = config.get('timepicker:timeDefaults');
const refreshIntervalDefaults = config.get('timepicker:refreshIntervalDefaults');
// These can be date math strings or moments.
self.time = _.defaults(globalState.time || {}, timeDefaults);
self.refreshInterval = _.defaults(globalState.refreshInterval || {}, refreshIntervalDefaults);
globalState.on('fetch_with_changes', function () {
// clone and default to {} in one
const newTime = _.defaults({}, globalState.time, timeDefaults);
const newRefreshInterval = _.defaults({}, globalState.refreshInterval, refreshIntervalDefaults);
if (newTime) {
if (newTime.to) newTime.to = convertISO8601(newTime.to);
if (newTime.from) newTime.from = convertISO8601(newTime.from);
}
self.time = newTime;
self.refreshInterval = newRefreshInterval;
});
});
$rootScope.$$timefilter = self;
$rootScope.$watchMulti([
'$$timefilter.time',
'$$timefilter.time.from',
'$$timefilter.time.to',
'$$timefilter.time.mode'
], diffTime);
$rootScope.$watchMulti([
'$$timefilter.refreshInterval',
'$$timefilter.refreshInterval.pause',
'$$timefilter.refreshInterval.value'
], diffInterval);
}
Timefilter.prototype.update = function () {
$rootScope.$apply();
};
Timefilter.prototype.getForceNow = function () {
const query = $location.search().forceNow;
if (!query) {
return;
}
const ticks = Date.parse(query);
if (isNaN(ticks)) {
throw new Error(`forceNow query parameter can't be parsed`);
}
return new Date(ticks);
};
Timefilter.prototype.get = function (indexPattern, timeRange) {
return getTime(indexPattern, timeRange ? timeRange : this.time, this.getForceNow());
};
Timefilter.prototype.calculateBounds = function (timeRange) {
return calculateBounds(timeRange, { forceNow: this.getForceNow() });
};
Timefilter.prototype.getBounds = function () {
return this.calculateBounds(this.time);
};
Timefilter.prototype.getActiveBounds = function () {
if (this.isTimeRangeSelectorEnabled) {
return this.getBounds();
}
};
/**
* Show the time bounds selector part of the time filter
*/
Timefilter.prototype.enableTimeRangeSelector = function () {
this.isTimeRangeSelectorEnabled = true;
};
/**
* Hide the time bounds selector part of the time filter
*/
Timefilter.prototype.disableTimeRangeSelector = function () {
this.isTimeRangeSelectorEnabled = false;
};
/**
* Show the auto refresh part of the time filter
*/
Timefilter.prototype.enableAutoRefreshSelector = function () {
this.isAutoRefreshSelectorEnabled = true;
};
/**
* Hide the auto refresh part of the time filter
*/
Timefilter.prototype.disableAutoRefreshSelector = function () {
this.isAutoRefreshSelectorEnabled = false;
};
return new Timefilter();
}); });

View file

@ -0,0 +1,265 @@
/*
* 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.
*/
jest.mock('ui/chrome',
() => ({
getUiSettingsClient: () => {
return {
get: (key) => {
switch(key) {
case 'timepicker:timeDefaults':
return { from: 'now-15m', to: 'now', mode: 'quick' };
case 'timepicker:refreshIntervalDefaults':
return { pause: false, value: 0 };
default:
throw new Error(`Unexpected config key: ${key}`);
}
}
};
},
}), { virtual: true });
jest.mock('ui/timefilter/lib/parse_querystring',
() => ({
parseQueryString: () => {
return {
// Can not access local variable from within a mock
forceNow: global.nowTime
};
},
}), { virtual: true });
import sinon from 'sinon';
import expect from 'expect.js';
import { timefilter } from './timefilter';
function stubNowTime(nowTime) {
global.nowTime = nowTime;
}
function clearNowTimeStub() {
delete global.nowTime;
}
describe('setTime', () => {
let update;
let fetch;
beforeEach(() => {
update = sinon.spy();
fetch = sinon.spy();
timefilter.setTime({
from: 0,
to: 1,
mode: 'absolute'
});
timefilter.on('timeUpdate', update);
timefilter.on('fetch', fetch);
});
test('should update time', () => {
timefilter.setTime({ from: 5, to: 10, mode: 'absolute' });
expect(timefilter.getTime()).to.eql({ from: 5, to: 10, mode: 'absolute' });
});
test('should allow partial updates to time', () => {
timefilter.setTime({ from: 5, to: 10 });
expect(timefilter.getTime()).to.eql({ from: 5, to: 10, mode: 'absolute' });
});
test('not emit anything if the time has not changed', () => {
timefilter.setTime({ from: 0, to: 1 });
expect(update.called).to.be(false);
expect(fetch.called).to.be(false);
});
test('emit update and fetch if the time has changed', () => {
timefilter.setTime({ from: 5, to: 10 });
expect(update.called).to.be(true);
expect(fetch.called).to.be(true);
});
});
describe('setRefreshInterval', () => {
let update;
let fetch;
beforeEach(() => {
update = sinon.spy();
fetch = sinon.spy();
timefilter.setRefreshInterval({
pause: false,
value: 0
});
timefilter.on('refreshIntervalUpdate', update);
timefilter.on('fetch', fetch);
});
test('should update refresh interval', () => {
timefilter.setRefreshInterval({ pause: true, value: 10 });
expect(timefilter.getRefreshInterval()).to.eql({ pause: true, value: 10 });
});
test('should allow partial updates to refresh interval', () => {
timefilter.setRefreshInterval({ value: 10 });
expect(timefilter.getRefreshInterval()).to.eql({ pause: false, value: 10 });
});
test('not emit anything if nothing has changed', () => {
timefilter.setRefreshInterval({ pause: false, value: 0 });
expect(update.called).to.be(false);
expect(fetch.called).to.be(false);
});
test('emit only an update when paused', () => {
timefilter.setRefreshInterval({ pause: true, value: 5000 });
expect(update.called).to.be(true);
expect(fetch.called).to.be(false);
});
test('emit update, not fetch, when switching to value: 0', () => {
timefilter.setRefreshInterval({ pause: false, value: 5000 });
expect(update.calledOnce).to.be(true);
expect(fetch.calledOnce).to.be(true);
timefilter.setRefreshInterval({ pause: false, value: 0 });
expect(update.calledTwice).to.be(true);
expect(fetch.calledTwice).to.be(false);
});
test('should emit update, not fetch, when moving from unpaused to paused', () => {
timefilter.setRefreshInterval({ pause: false, value: 5000 });
expect(update.calledOnce).to.be(true);
expect(fetch.calledOnce).to.be(true);
timefilter.setRefreshInterval({ pause: true, value: 5000 });
expect(update.calledTwice).to.be(true);
expect(fetch.calledTwice).to.be(false);
});
test('should emit update and fetch when unpaused', () => {
timefilter.setRefreshInterval({ pause: true, value: 5000 });
expect(update.calledOnce).to.be(true);
expect(fetch.calledOnce).to.be(false);
timefilter.setRefreshInterval({ pause: false, value: 5000 });
expect(update.calledTwice).to.be(true);
expect(fetch.calledOnce).to.be(true);
});
});
describe('isTimeRangeSelectorEnabled', () => {
let update;
beforeEach(() => {
update = sinon.spy();
timefilter.on('enabledUpdated', update);
});
test('should emit updated when disabled', () => {
timefilter.disableTimeRangeSelector();
expect(timefilter.isTimeRangeSelectorEnabled).to.be(false);
expect(update.called).to.be(true);
});
test('should emit updated when enabled', () => {
timefilter.enableTimeRangeSelector();
expect(timefilter.isTimeRangeSelectorEnabled).to.be(true);
expect(update.called).to.be(true);
});
});
describe('isAutoRefreshSelectorEnabled', () => {
let update;
beforeEach(() => {
update = sinon.spy();
timefilter.on('enabledUpdated', update);
});
test('should emit updated when disabled', () => {
timefilter.disableAutoRefreshSelector();
expect(timefilter.isAutoRefreshSelectorEnabled).to.be(false);
expect(update.called).to.be(true);
});
test('should emit updated when enabled', () => {
timefilter.enableAutoRefreshSelector();
expect(timefilter.isAutoRefreshSelectorEnabled).to.be(true);
expect(update.called).to.be(true);
});
});
describe('calculateBounds', () => {
const fifteenMinutesInMilliseconds = 15 * 60 * 1000;
const clockNowTicks = new Date(2000, 1, 1, 0, 0, 0, 0).valueOf();
let clock;
beforeEach(() => {
clock = sinon.useFakeTimers(clockNowTicks);
});
afterEach(() => {
clock.restore();
clearNowTimeStub();
});
test('uses clock time by default', () => {
const timeRange = {
from: 'now-15m',
to: 'now'
};
stubNowTime(undefined);
const result = timefilter.calculateBounds(timeRange);
expect(result.min.valueOf()).to.eql(clockNowTicks - fifteenMinutesInMilliseconds);
expect(result.max.valueOf()).to.eql(clockNowTicks);
});
test('uses forceNow string', () => {
const timeRange = {
from: 'now-15m',
to: 'now'
};
const forceNowString = '1999-01-01T00:00:00.000Z';
stubNowTime(forceNowString);
const result = timefilter.calculateBounds(timeRange);
const forceNowTicks = Date.parse(forceNowString);
expect(result.min.valueOf()).to.eql(forceNowTicks - fifteenMinutesInMilliseconds);
expect(result.max.valueOf()).to.eql(forceNowTicks);
});
test(`throws Error if forceNow can't be parsed`, () => {
const timeRange = {
from: 'now-15m',
to: 'now'
};
stubNowTime('not_a_parsable_date');
expect(() => timefilter.calculateBounds(timeRange)).to.throwError();
});
});

View file

@ -17,27 +17,20 @@
* under the License. * under the License.
*/ */
import moment from 'moment';
import expect from 'expect.js'; import expect from 'expect.js';
import ngMock from 'ng_mock'; import ngMock from 'ng_mock';
import $ from 'jquery'; import $ from 'jquery';
import sinon from 'sinon'; import { timefilter } from 'ui/timefilter';
describe('kbnGlobalTimepicker', function () { describe('kbnGlobalTimepicker', function () {
const sandbox = sinon.createSandbox();
let compile; let compile;
let scope; let scope;
beforeEach(() => { beforeEach(() => {
ngMock.module('kibana'); ngMock.module('kibana');
ngMock.inject(($compile, $rootScope, timefilter) => { ngMock.inject(($compile, $rootScope) => {
scope = $rootScope.$new(); scope = $rootScope.$new();
compile = (timefilterStubProperties = {}) => { compile = () => {
Object.keys(timefilterStubProperties).forEach((key) => {
sandbox.stub(timefilter, key).value(timefilterStubProperties[key]);
});
const $el = $('<kbn-global-timepicker></kbn-global-timepicker>'); const $el = $('<kbn-global-timepicker></kbn-global-timepicker>');
$el.data('$kbnTopNavController', {}); // Mock the kbnTopNav $el.data('$kbnTopNavController', {}); // Mock the kbnTopNav
$compile($el)(scope); $compile($el)(scope);
@ -47,10 +40,6 @@ describe('kbnGlobalTimepicker', function () {
}); });
}); });
afterEach(() => {
sandbox.restore();
});
it('injects the timepicker into the DOM', () => { it('injects the timepicker into the DOM', () => {
const $el = compile(); const $el = compile();
expect($el.attr('data-test-subj')).to.be('globalTimepicker'); expect($el.attr('data-test-subj')).to.be('globalTimepicker');
@ -59,17 +48,16 @@ describe('kbnGlobalTimepicker', function () {
it('sets data-shared-timefilter-* using the timefilter when auto-refresh selector is enabled', function () { it('sets data-shared-timefilter-* using the timefilter when auto-refresh selector is enabled', function () {
const minString = '2000-01-01T00:00:00Z'; const minString = '2000-01-01T00:00:00Z';
const maxString = '2001-01-01T00:00:00Z'; const maxString = '2001-01-01T00:00:00Z';
const bounds = {
min: moment(minString),
max: moment(maxString),
};
const timefilter = {
isAutoRefreshSelectorEnabled: true,
isTimeRangeSelectorEnabled: false,
getBounds: () => bounds
};
const $el = compile(timefilter); timefilter.enableAutoRefreshSelector();
timefilter.disableTimeRangeSelector();
timefilter.setTime({
from: minString,
to: maxString,
mode: 'absolute'
});
const $el = compile();
expect($el.attr('data-shared-timefilter-from')).to.eql(minString); expect($el.attr('data-shared-timefilter-from')).to.eql(minString);
expect($el.attr('data-shared-timefilter-to')).to.eql(maxString); expect($el.attr('data-shared-timefilter-to')).to.eql(maxString);
@ -78,17 +66,16 @@ describe('kbnGlobalTimepicker', function () {
it('sets data-shared-timefilter-* using the timefilter when time range selector is enabled', function () { it('sets data-shared-timefilter-* using the timefilter when time range selector is enabled', function () {
const minString = '2000-01-01T00:00:00Z'; const minString = '2000-01-01T00:00:00Z';
const maxString = '2001-01-01T00:00:00Z'; const maxString = '2001-01-01T00:00:00Z';
const bounds = {
min: moment(minString),
max: moment(maxString),
};
const timefilter = {
isAutoRefreshSelectorEnabled: false,
isTimeRangeSelectorEnabled: true,
getBounds: () => bounds
};
const $el = compile(timefilter); timefilter.disableAutoRefreshSelector();
timefilter.enableTimeRangeSelector();
timefilter.setTime({
from: minString,
to: maxString,
mode: 'absolute'
});
const $el = compile();
expect($el.attr('data-shared-timefilter-from')).to.eql(minString); expect($el.attr('data-shared-timefilter-from')).to.eql(minString);
expect($el.attr('data-shared-timefilter-to')).to.eql(maxString); expect($el.attr('data-shared-timefilter-to')).to.eql(maxString);
@ -97,17 +84,16 @@ describe('kbnGlobalTimepicker', function () {
it(`doesn't set data-shared-timefilter-* when auto-refresh and time range selectors are both disabled`, function () { it(`doesn't set data-shared-timefilter-* when auto-refresh and time range selectors are both disabled`, function () {
const minString = '2000-01-01T00:00:00Z'; const minString = '2000-01-01T00:00:00Z';
const maxString = '2001-01-01T00:00:00Z'; const maxString = '2001-01-01T00:00:00Z';
const bounds = {
min: moment(minString),
max: moment(maxString),
};
const timefilter = {
isAutoRefreshSelectorEnabled: false,
isTimeRangeSelectorEnabled: false,
getBounds: () => bounds
};
const $el = compile(timefilter); timefilter.disableAutoRefreshSelector();
timefilter.disableTimeRangeSelector();
timefilter.setTime({
from: minString,
to: maxString,
mode: 'absolute'
});
const $el = compile();
expect($el.attr('data-shared-timefilter-from')).to.eql(''); expect($el.attr('data-shared-timefilter-from')).to.eql('');
expect($el.attr('data-shared-timefilter-to')).to.eql(''); expect($el.attr('data-shared-timefilter-to')).to.eql('');

View file

@ -1,5 +1,5 @@
<div <div
ng-show="timefilter.isAutoRefreshSelectorEnabled || timefilter.isTimeRangeSelectorEnabled" ng-show="timefilterValues.isAutoRefreshSelectorEnabled || timefilterValues.isTimeRangeSelectorEnabled"
data-shared-timefilter-from="{{ getSharedTimeFilterFromDate() }}" data-shared-timefilter-from="{{ getSharedTimeFilterFromDate() }}"
data-shared-timefilter-to="{{ getSharedTimeFilterToDate() }}" data-shared-timefilter-to="{{ getSharedTimeFilterToDate() }}"
class="kuiLocalMenu" class="kuiLocalMenu"
@ -7,39 +7,39 @@
> >
<button <button
class="kuiLocalMenuItem" class="kuiLocalMenuItem"
aria-label="{{ timefilter.refreshInterval.pause ? 'Resume refreshing data' : 'Pause refreshing data' }}" aria-label="{{ timefilterValues.refreshInterval.pause ? 'Resume refreshing data' : 'Pause refreshing data' }}"
ng-click="toggleRefresh()" ng-click="toggleRefresh()"
ng-show="timefilter.isAutoRefreshSelectorEnabled && (timefilter.refreshInterval.value > 0)" ng-show="timefilterValues.isAutoRefreshSelectorEnabled && (timefilterValues.refreshInterval.value > 0)"
data-test-subj="globalTimepickerAutoRefreshButton" data-test-subj="globalTimepickerAutoRefreshButton"
data-test-subj-state="{{ timefilter.refreshInterval.pause ? 'inactive' : 'active' }}" data-test-subj-state="{{ timefilterValues.refreshInterval.pause ? 'inactive' : 'active' }}"
> >
<span <span
class="kuiIcon" class="kuiIcon"
aria-hidden="true" aria-hidden="true"
ng-class="timefilter.refreshInterval.pause ? 'fa-play' : 'fa-pause'" ng-class="timefilterValues.refreshInterval.pause ? 'fa-play' : 'fa-pause'"
></span> ></span>
</button> </button>
<button <button
class="kuiLocalMenuItem navbar-timepicker-auto-refresh-desc" class="kuiLocalMenuItem navbar-timepicker-auto-refresh-desc"
ng-class="{'kuiLocalMenuItem-isSelected': kbnTopNav.isCurrent('interval') }" ng-class="{'kuiLocalMenuItem-isSelected': kbnTopNav.isCurrent('interval') }"
ng-show="timefilter.isAutoRefreshSelectorEnabled" ng-show="timefilterValues.isAutoRefreshSelectorEnabled"
ng-click="kbnTopNav.toggle('interval')" ng-click="kbnTopNav.toggle('interval')"
> >
<span ng-show="timefilter.refreshInterval.value === 0"> <span ng-show="timefilterValues.refreshInterval.value === 0">
<span aria-hidden="true" class="kuiIcon fa-repeat"></span> Auto-refresh <span aria-hidden="true" class="kuiIcon fa-repeat"></span> Auto-refresh
</span> </span>
<span <span
ng-show="timefilter.refreshInterval.value > 0" ng-show="timefilterValues.refreshInterval.value > 0"
aria-label="{{ 'Data will refresh every ' + timefilter.refreshInterval.display }}" aria-label="{{ 'Data will refresh every ' + timefilterValues.refreshInterval.display }}"
> >
{{ timefilter.refreshInterval.display }} {{ timefilterValues.refreshInterval.display }}
</span> </span>
</button> </button>
<button <button
ng-show="timefilter.isTimeRangeSelectorEnabled" ng-show="timefilterValues.isTimeRangeSelectorEnabled"
class="kuiLocalMenuItem" class="kuiLocalMenuItem"
ng-click="back()" ng-click="back()"
aria-label="Move backward in time" aria-label="Move backward in time"
@ -52,7 +52,7 @@
</button> </button>
<button <button
ng-show="timefilter.isTimeRangeSelectorEnabled" ng-show="timefilterValues.isTimeRangeSelectorEnabled"
data-test-subj="globalTimepickerButton" data-test-subj="globalTimepickerButton"
class="kuiLocalMenuItem navbar-timepicker-time-desc" class="kuiLocalMenuItem navbar-timepicker-time-desc"
ng-class="{'kuiLocalMenuItem-isSelected': kbnTopNav.isCurrent('filter')}" ng-class="{'kuiLocalMenuItem-isSelected': kbnTopNav.isCurrent('filter')}"
@ -62,14 +62,14 @@
> >
<span aria-hidden="true" class="kuiIcon fa-clock-o"></span> <span aria-hidden="true" class="kuiIcon fa-clock-o"></span>
<pretty-duration <pretty-duration
from="timefilter.time.from" from="timefilterValues.time.from"
to="timefilter.time.to" to="timefilterValues.time.to"
data-test-subj="globalTimepickerRange" data-test-subj="globalTimepickerRange"
></pretty-duration> ></pretty-duration>
</button> </button>
<button <button
ng-show="timefilter.isTimeRangeSelectorEnabled" ng-show="timefilterValues.isTimeRangeSelectorEnabled"
class="kuiLocalMenuItem" class="kuiLocalMenuItem"
ng-click="forward()" ng-click="forward()"
aria-label="Move forward in time" aria-label="Move forward in time"

View file

@ -18,50 +18,68 @@
*/ */
import { uiModules } from '../modules'; import { uiModules } from '../modules';
import { once, clone } from 'lodash';
import toggleHtml from './kbn_global_timepicker.html'; import toggleHtml from './kbn_global_timepicker.html';
import { timeNavigation } from './time_navigation'; import { timeNavigation } from './time_navigation';
import { timefilter } from 'ui/timefilter';
uiModules uiModules
.get('kibana') .get('kibana')
.directive('kbnGlobalTimepicker', (timefilter, globalState, $rootScope) => { .directive('kbnGlobalTimepicker', (globalState) => {
const listenForUpdates = once($scope => { const listenForUpdates = ($scope) => {
$scope.$listen(timefilter, 'update', () => { $scope.$listenAndDigestAsync(timefilter, 'refreshIntervalUpdate', () => {
globalState.time = clone(timefilter.time); globalState.refreshInterval = timefilter.getRefreshInterval();
globalState.refreshInterval = clone(timefilter.refreshInterval); globalState.time = timefilter.getTime();
globalState.save(); globalState.save();
setTimefilterValues($scope);
}); });
}); $scope.$listenAndDigestAsync(timefilter, 'timeUpdate', () => {
globalState.refreshInterval = timefilter.getRefreshInterval();
globalState.time = timefilter.getTime();
globalState.save();
setTimefilterValues($scope);
});
$scope.$listenAndDigestAsync(timefilter, 'enabledUpdated', () => {
setTimefilterValues($scope);
});
};
function setTimefilterValues($scope) {
$scope.timefilterValues = {
refreshInterval: timefilter.getRefreshInterval(),
time: timefilter.getTime(),
isAutoRefreshSelectorEnabled: timefilter.isAutoRefreshSelectorEnabled,
isTimeRangeSelectorEnabled: timefilter.isTimeRangeSelectorEnabled,
};
}
return { return {
template: toggleHtml, template: toggleHtml,
replace: true, replace: true,
require: '^kbnTopNav', require: '^kbnTopNav',
link: ($scope, element, attributes, kbnTopNav) => { link: ($scope, element, attributes, kbnTopNav) => {
listenForUpdates($rootScope); listenForUpdates($scope);
$rootScope.timefilter = timefilter; setTimefilterValues($scope);
$rootScope.toggleRefresh = () => { $scope.toggleRefresh = () => {
timefilter.refreshInterval.pause = !timefilter.refreshInterval.pause; timefilter.toggleRefresh();
}; };
$scope.forward = function () { $scope.forward = function () {
timefilter.time = timeNavigation.stepForward(timefilter.getBounds()); timefilter.setTime(timeNavigation.stepForward(timefilter.getBounds()));
}; };
$scope.back = function () { $scope.back = function () {
timefilter.time = timeNavigation.stepBackward(timefilter.getBounds()); timefilter.setTime(timeNavigation.stepBackward(timefilter.getBounds()));
}; };
$scope.updateFilter = function (from, to) { $scope.updateFilter = function (from, to, mode) {
timefilter.time.from = from; timefilter.setTime({ from, to, mode });
timefilter.time.to = to;
kbnTopNav.close('filter'); kbnTopNav.close('filter');
}; };
$scope.updateInterval = function (interval) { $scope.updateInterval = function (interval) {
timefilter.refreshInterval = interval; timefilter.setRefreshInterval(interval);
kbnTopNav.close('interval'); kbnTopNav.close('interval');
}; };

View file

@ -165,7 +165,7 @@ module.directive('kbnTimepicker', function (refreshIntervals) {
}; };
$scope.setQuick = function (from, to) { $scope.setQuick = function (from, to) {
$scope.onFilterSelect({ from, to }); $scope.onFilterSelect({ from, to, mode: TIME_MODES.QUICK });
}; };
$scope.setToNow = function (key) { $scope.setToNow = function (key) {
@ -203,7 +203,8 @@ module.directive('kbnTimepicker', function (refreshIntervals) {
$scope.applyRelative = function () { $scope.applyRelative = function () {
$scope.onFilterSelect({ $scope.onFilterSelect({
from: getRelativeString('from'), from: getRelativeString('from'),
to: getRelativeString('to') to: getRelativeString('to'),
mode: TIME_MODES.RELATIVE,
}); });
}; };
@ -224,7 +225,8 @@ module.directive('kbnTimepicker', function (refreshIntervals) {
$scope.applyAbsolute = function () { $scope.applyAbsolute = function () {
$scope.onFilterSelect({ $scope.onFilterSelect({
from: moment($scope.absolute.from), from: moment($scope.absolute.from),
to: moment($scope.absolute.to) to: moment($scope.absolute.to),
mode: TIME_MODES.ABSOLUTE,
}); });
}; };

View file

@ -1,254 +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 expect from 'expect.js';
import moment from 'moment';
import ngMock from 'ng_mock';
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
import { UtilsBrushEventProvider } from '../brush_event';
describe('brushEvent', function () {
const DAY_IN_MS = 24 * 60 * 60 * 1000;
const JAN_01_2014 = 1388559600000;
let brushEventFn;
let timefilter;
beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject(function (Private, $injector, _timefilter_) {
brushEventFn = Private(UtilsBrushEventProvider);
timefilter = _timefilter_;
}));
it('is a function that returns a function', function () {
expect(brushEventFn).to.be.a(Function);
expect(brushEventFn({})).to.be.a(Function);
});
describe('returned function', function () {
let $state;
let brushEvent;
const baseState = {
filters: [],
};
const baseEvent = {
data: {
fieldFormatter: _.constant({}),
},
};
beforeEach(ngMock.inject(function (Private) {
baseEvent.data.indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
$state = _.cloneDeep(baseState);
brushEvent = brushEventFn($state);
}));
it('should be a function', function () {
expect(brushEvent).to.be.a(Function);
});
it('ignores event when data.xAxisField not provided', function () {
const event = _.cloneDeep(baseEvent);
brushEvent(event);
expect($state)
.not.have.property('$newFilters');
});
describe('handles an event when the x-axis field is a date field', function () {
describe('date field is index pattern timefield', function () {
let dateEvent;
const dateField = {
name: 'time',
type: 'date'
};
beforeEach(ngMock.inject(function () {
dateEvent = _.cloneDeep(baseEvent);
dateEvent.data.xAxisField = dateField;
}));
it('by ignoring the event when range spans zero time', function () {
const event = _.cloneDeep(dateEvent);
event.range = [JAN_01_2014, JAN_01_2014];
brushEvent(event);
expect($state)
.not.have.property('$newFilters');
});
it('by updating the timefilter', function () {
const event = _.cloneDeep(dateEvent);
event.range = [JAN_01_2014, JAN_01_2014 + DAY_IN_MS];
brushEvent(event);
expect(timefilter.time.mode).to.be('absolute');
expect(moment.isMoment(timefilter.time.from))
.to.be(true);
// Set to a baseline timezone for comparison.
expect(timefilter.time.from.utcOffset(0).format('YYYY-MM-DD'))
.to.equal('2014-01-01');
expect(moment.isMoment(timefilter.time.to))
.to.be(true);
// Set to a baseline timezone for comparison.
expect(timefilter.time.to.utcOffset(0).format('YYYY-MM-DD'))
.to.equal('2014-01-02');
});
});
describe('date field is not index pattern timefield', function () {
let dateEvent;
const dateField = {
name: 'anotherTimeField',
type: 'date'
};
beforeEach(ngMock.inject(function () {
dateEvent = _.cloneDeep(baseEvent);
dateEvent.data.xAxisField = dateField;
}));
it('creates a new range filter', function () {
const event = _.cloneDeep(dateEvent);
const rangeBegin = JAN_01_2014;
const rangeEnd = rangeBegin + DAY_IN_MS;
event.range = [rangeBegin, rangeEnd];
brushEvent(event);
expect($state)
.to.have.property('$newFilters');
expect($state.filters.length)
.to.equal(0);
expect($state.$newFilters.length)
.to.equal(1);
expect($state.$newFilters[0].range.anotherTimeField.gte)
.to.equal(rangeBegin);
expect($state.$newFilters[0].range.anotherTimeField.lt)
.to.equal(rangeEnd);
expect($state.$newFilters[0].range.anotherTimeField).to.have.property('format');
expect($state.$newFilters[0].range.anotherTimeField.format)
.to.equal('epoch_millis');
});
it('converts Date fields to milliseconds', function () {
const event = _.cloneDeep(dateEvent);
const rangeBeginMs = JAN_01_2014;
const rangeEndMs = rangeBeginMs + DAY_IN_MS;
const rangeBegin = new Date(rangeBeginMs);
const rangeEnd = new Date(rangeEndMs);
event.range = [rangeBegin, rangeEnd];
brushEvent(event);
expect($state)
.to.have.property('$newFilters');
expect($state.filters.length)
.to.equal(0);
expect($state.$newFilters.length)
.to.equal(1);
expect($state.$newFilters[0].range.anotherTimeField.gte)
.to.equal(rangeBeginMs);
expect($state.$newFilters[0].range.anotherTimeField.lt)
.to.equal(rangeEndMs);
});
});
});
describe('handles an event when the x-axis field is a number', function () {
let numberEvent;
const numberField = {
name: 'numberField',
type: 'number'
};
beforeEach(ngMock.inject(function () {
numberEvent = _.cloneDeep(baseEvent);
numberEvent.data.xAxisField = numberField;
}));
it('by ignoring the event when range does not span at least 2 values', function () {
const event = _.cloneDeep(numberEvent);
event.range = [1];
brushEvent(event);
expect($state)
.not.have.property('$newFilters');
});
it('by creating a new filter', function () {
const event = _.cloneDeep(numberEvent);
event.range = [1, 2, 3, 4];
brushEvent(event);
expect($state)
.to.have.property('$newFilters');
expect($state.filters.length)
.to.equal(0);
expect($state.$newFilters.length)
.to.equal(1);
expect($state.$newFilters[0].range.numberField.gte)
.to.equal(1);
expect($state.$newFilters[0].range.numberField.lt)
.to.equal(4);
expect($state.$newFilters[0].range.numberField).not.to.have.property('format');
});
it('by updating the existing range filter', function () {
const event = _.cloneDeep(numberEvent);
event.range = [3, 7];
$state.filters.push({
meta: {
key: 'numberField'
},
range: { gte: 1, lt: 4 }
});
brushEvent(event);
expect($state)
.not.have.property('$newFilters');
expect($state.filters.length)
.to.equal(1);
expect($state.filters[0].range.numberField.gte)
.to.equal(3);
expect($state.filters[0].range.numberField.lt)
.to.equal(7);
});
it('by updating the existing scripted filter', function () {
const event = _.cloneDeep(numberEvent);
event.range = [3, 7];
$state.filters.push({
meta: {
key: 'numberField'
},
script: {
script: {
params: {
gte: 1,
lt: 4
}
}
}
});
brushEvent(event);
expect($state)
.not.have.property('$newFilters');
expect($state.filters.length)
.to.equal(1);
expect($state.filters[0].script.script.params.gte)
.to.equal(3);
expect($state.filters[0].script.script.params.lt)
.to.equal(7);
});
});
});
});

View file

@ -0,0 +1,256 @@
/*
* 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.
*/
jest.mock('ui/chrome',
() => ({
getUiSettingsClient: () => {
return {
get: (key) => {
switch(key) {
case 'timepicker:timeDefaults':
return { from: 'now-15m', to: 'now', mode: 'quick' };
case 'timepicker:refreshIntervalDefaults':
return { display: 'Off', pause: false, value: 0 };
default:
throw new Error(`Unexpected config key: ${key}`);
}
}
};
},
}), { virtual: true });
import _ from 'lodash';
import expect from 'expect.js';
import moment from 'moment';
import { onBrushEvent } from '../brush_event';
import { timefilter } from 'ui/timefilter';
describe('brushEvent', () => {
const DAY_IN_MS = 24 * 60 * 60 * 1000;
const JAN_01_2014 = 1388559600000;
let $state;
const baseState = {
filters: [],
};
const baseEvent = {
data: {
fieldFormatter: _.constant({}),
},
};
beforeEach(() => {
baseEvent.data.indexPattern = {
id: 'logstash-*',
timeFieldName: 'time'
};
$state = _.cloneDeep(baseState);
});
test('should be a function', () => {
expect(onBrushEvent).to.be.a(Function);
});
test('ignores event when data.xAxisField not provided', () => {
const event = _.cloneDeep(baseEvent);
onBrushEvent(event, $state);
expect($state)
.not.have.property('$newFilters');
});
describe('handles an event when the x-axis field is a date field', () => {
describe('date field is index pattern timefield', () => {
let dateEvent;
const dateField = {
name: 'time',
type: 'date'
};
beforeEach(() => {
dateEvent = _.cloneDeep(baseEvent);
dateEvent.data.xAxisField = dateField;
});
test('by ignoring the event when range spans zero time', () => {
const event = _.cloneDeep(dateEvent);
event.range = [JAN_01_2014, JAN_01_2014];
onBrushEvent(event, $state);
expect($state)
.not.have.property('$newFilters');
});
test('by updating the timefilter', () => {
const event = _.cloneDeep(dateEvent);
event.range = [JAN_01_2014, JAN_01_2014 + DAY_IN_MS];
onBrushEvent(event, $state);
expect(timefilter.getTime().mode).to.be('absolute');
expect(moment.isMoment(timefilter.getTime().from))
.to.be(true);
// Set to a baseline timezone for comparison.
expect(timefilter.getTime().from.utcOffset(0).format('YYYY-MM-DD'))
.to.equal('2014-01-01');
expect(moment.isMoment(timefilter.getTime().to))
.to.be(true);
// Set to a baseline timezone for comparison.
expect(timefilter.getTime().to.utcOffset(0).format('YYYY-MM-DD'))
.to.equal('2014-01-02');
});
});
describe('date field is not index pattern timefield', () => {
let dateEvent;
const dateField = {
name: 'anotherTimeField',
type: 'date'
};
beforeEach(() => {
dateEvent = _.cloneDeep(baseEvent);
dateEvent.data.xAxisField = dateField;
});
test('creates a new range filter', () => {
const event = _.cloneDeep(dateEvent);
const rangeBegin = JAN_01_2014;
const rangeEnd = rangeBegin + DAY_IN_MS;
event.range = [rangeBegin, rangeEnd];
onBrushEvent(event, $state);
expect($state)
.to.have.property('$newFilters');
expect($state.filters.length)
.to.equal(0);
expect($state.$newFilters.length)
.to.equal(1);
expect($state.$newFilters[0].range.anotherTimeField.gte)
.to.equal(rangeBegin);
expect($state.$newFilters[0].range.anotherTimeField.lt)
.to.equal(rangeEnd);
expect($state.$newFilters[0].range.anotherTimeField).to.have.property('format');
expect($state.$newFilters[0].range.anotherTimeField.format)
.to.equal('epoch_millis');
});
test('converts Date fields to milliseconds', () => {
const event = _.cloneDeep(dateEvent);
const rangeBeginMs = JAN_01_2014;
const rangeEndMs = rangeBeginMs + DAY_IN_MS;
const rangeBegin = new Date(rangeBeginMs);
const rangeEnd = new Date(rangeEndMs);
event.range = [rangeBegin, rangeEnd];
onBrushEvent(event, $state);
expect($state)
.to.have.property('$newFilters');
expect($state.filters.length)
.to.equal(0);
expect($state.$newFilters.length)
.to.equal(1);
expect($state.$newFilters[0].range.anotherTimeField.gte)
.to.equal(rangeBeginMs);
expect($state.$newFilters[0].range.anotherTimeField.lt)
.to.equal(rangeEndMs);
});
});
});
describe('handles an event when the x-axis field is a number', () => {
let numberEvent;
const numberField = {
name: 'numberField',
type: 'number'
};
beforeEach(() => {
numberEvent = _.cloneDeep(baseEvent);
numberEvent.data.xAxisField = numberField;
});
test('by ignoring the event when range does not span at least 2 values', () => {
const event = _.cloneDeep(numberEvent);
event.range = [1];
onBrushEvent(event, $state);
expect($state).not.have.property('$newFilters');
});
test('by creating a new filter', () => {
const event = _.cloneDeep(numberEvent);
event.range = [1, 2, 3, 4];
onBrushEvent(event, $state);
expect($state)
.to.have.property('$newFilters');
expect($state.filters.length)
.to.equal(0);
expect($state.$newFilters.length)
.to.equal(1);
expect($state.$newFilters[0].range.numberField.gte)
.to.equal(1);
expect($state.$newFilters[0].range.numberField.lt)
.to.equal(4);
expect($state.$newFilters[0].range.numberField).not.to.have.property('format');
});
test('by updating the existing range filter', () => {
const event = _.cloneDeep(numberEvent);
event.range = [3, 7];
$state.filters.push({
meta: {
key: 'numberField'
},
range: { gte: 1, lt: 4 }
});
onBrushEvent(event, $state);
expect($state)
.not.have.property('$newFilters');
expect($state.filters.length)
.to.equal(1);
expect($state.filters[0].range.numberField.gte)
.to.equal(3);
expect($state.filters[0].range.numberField.lt)
.to.equal(7);
});
test('by updating the existing scripted filter', () => {
const event = _.cloneDeep(numberEvent);
event.range = [3, 7];
$state.filters.push({
meta: {
key: 'numberField'
},
script: {
script: {
params: {
gte: 1,
lt: 4
}
}
}
});
onBrushEvent(event, $state);
expect($state)
.not.have.property('$newFilters');
expect($state.filters.length)
.to.equal(1);
expect($state.filters[0].script.script.params.gte)
.to.equal(3);
expect($state.filters[0].script.script.params.lt)
.to.equal(7);
});
});
});

View file

@ -20,73 +20,72 @@
import _ from 'lodash'; import _ from 'lodash';
import moment from 'moment'; import moment from 'moment';
import { buildRangeFilter } from '../filter_manager/lib/range'; import { buildRangeFilter } from '../filter_manager/lib/range';
import { timefilter } from 'ui/timefilter';
export function UtilsBrushEventProvider(timefilter) { export function onBrushEvent(event, $state) {
return $state => { if (!event.data.xAxisField) {
return event => { return;
if (!event.data.xAxisField) { }
return;
}
const isDate = event.data.xAxisField.type === 'date'; const isDate = event.data.xAxisField.type === 'date';
const isNumber = event.data.xAxisField.type === 'number'; const isNumber = event.data.xAxisField.type === 'number';
if (isDate && if (isDate &&
event.data.xAxisField.name === event.data.indexPattern.timeFieldName) { event.data.xAxisField.name === event.data.indexPattern.timeFieldName) {
setTimefilter(); setTimefilter();
} else if (isDate || isNumber) { } else if (isDate || isNumber) {
setRange(); setRange();
} }
function setTimefilter() { function setTimefilter() {
const from = moment(event.range[0]); const from = moment(event.range[0]);
const to = moment(event.range[1]); const to = moment(event.range[1]);
if (to - from === 0) return; if (to - from === 0) return;
timefilter.time.from = from; timefilter.setTime({
timefilter.time.to = to; from,
timefilter.time.mode = 'absolute'; to,
} mode: 'absolute'
});
}
function setRange() { function setRange() {
if (event.range.length <= 1) return; if (event.range.length <= 1) return;
const existingFilter = $state.filters.find(filter => ( const existingFilter = $state.filters.find(filter => (
filter.meta && filter.meta.key === event.data.xAxisField.name filter.meta && filter.meta.key === event.data.xAxisField.name
)); ));
const min = event.range[0]; const min = event.range[0];
const max = event.range[event.range.length - 1]; const max = event.range[event.range.length - 1];
let range; let range;
if (isDate) { if (isDate) {
range = { range = {
gte: moment(min).valueOf(), gte: moment(min).valueOf(),
lt: moment(max).valueOf(), lt: moment(max).valueOf(),
format: 'epoch_millis' format: 'epoch_millis'
}; };
} else { } else {
range = { range = {
gte: min, gte: min,
lt: max lt: max
}; };
} }
if (_.has(existingFilter, 'range')) { if (_.has(existingFilter, 'range')) {
existingFilter.range[event.data.xAxisField.name] = range; existingFilter.range[event.data.xAxisField.name] = range;
} else if (_.has(existingFilter, 'script.script.params.gte') } else if (_.has(existingFilter, 'script.script.params.gte')
&& _.has(existingFilter, 'script.script.params.lt')) { && _.has(existingFilter, 'script.script.params.lt')) {
existingFilter.script.script.params.gte = min; existingFilter.script.script.params.gte = min;
existingFilter.script.script.params.lt = max; existingFilter.script.script.params.lt = max;
} else { } else {
const newFilter = buildRangeFilter( const newFilter = buildRangeFilter(
event.data.xAxisField, event.data.xAxisField,
range, range,
event.data.indexPattern, event.data.indexPattern,
event.data.xAxisFormatter); event.data.xAxisFormatter);
$state.$newFilters = [newFilter]; $state.$newFilters = [newFilter];
} }
} }
};
};
} }

View file

@ -21,12 +21,13 @@ import _ from 'lodash';
import { SearchSourceProvider } from '../../courier/data_source/search_source'; import { SearchSourceProvider } from '../../courier/data_source/search_source';
import { VisRequestHandlersRegistryProvider } from '../../registry/vis_request_handlers'; import { VisRequestHandlersRegistryProvider } from '../../registry/vis_request_handlers';
import { calculateObjectHash } from '../lib/calculate_object_hash'; import { calculateObjectHash } from '../lib/calculate_object_hash';
import { timefilter } from 'ui/timefilter';
import { getRequestInspectorStats, getResponseInspectorStats } from '../../courier/utils/courier_inspector_utils'; import { getRequestInspectorStats, getResponseInspectorStats } from '../../courier/utils/courier_inspector_utils';
import { tabifyAggResponse } from '../../agg_response/tabify/tabify'; import { tabifyAggResponse } from '../../agg_response/tabify/tabify';
import { FormattedData } from '../../inspector/adapters'; import { FormattedData } from '../../inspector/adapters';
const CourierRequestHandlerProvider = function (Private, courier, timefilter) { const CourierRequestHandlerProvider = function (Private, courier) {
const SearchSource = Private(SearchSourceProvider); const SearchSource = Private(SearchSourceProvider);
/** /**
@ -105,7 +106,7 @@ const CourierRequestHandlerProvider = function (Private, courier, timefilter) {
}); });
timeFilterSearchSource.set('filter', () => { timeFilterSearchSource.set('filter', () => {
return timefilter.get(searchSource.get('index'), timeRange); return timefilter.createFilter(searchSource.get('index'), timeRange);
}); });
requestSearchSource.set('filter', filters); requestSearchSource.set('filter', filters);

View file

@ -32,13 +32,14 @@ import _ from 'lodash';
import { VisTypesRegistryProvider } from '../registry/vis_types'; import { VisTypesRegistryProvider } from '../registry/vis_types';
import { AggConfigs } from './agg_configs'; import { AggConfigs } from './agg_configs';
import { PersistedState } from '../persisted_state'; import { PersistedState } from '../persisted_state';
import { UtilsBrushEventProvider } from '../utils/brush_event'; import { onBrushEvent } from '../utils/brush_event';
import { FilterBarQueryFilterProvider } from '../filter_bar/query_filter'; import { FilterBarQueryFilterProvider } from '../filter_bar/query_filter';
import { FilterBarClickHandlerProvider } from '../filter_bar/filter_bar_click_handler'; import { FilterBarClickHandlerProvider } from '../filter_bar/filter_bar_click_handler';
import { updateVisualizationConfig } from './vis_update'; import { updateVisualizationConfig } from './vis_update';
import { queryManagerFactory } from '../query_manager'; import { queryManagerFactory } from '../query_manager';
import { SearchSourceProvider } from '../courier/data_source/search_source'; import { SearchSourceProvider } from '../courier/data_source/search_source';
import { SavedObjectsClientProvider } from '../saved_objects'; import { SavedObjectsClientProvider } from '../saved_objects';
import { timefilter } from 'ui/timefilter';
import { Inspector } from '../inspector'; import { Inspector } from '../inspector';
import { RequestAdapter, DataAdapter } from '../inspector/adapters'; import { RequestAdapter, DataAdapter } from '../inspector/adapters';
@ -55,9 +56,8 @@ const getTerms = (table, columnIndex, rowIndex) => {
}))]; }))];
}; };
export function VisProvider(Private, Promise, indexPatterns, timefilter, getAppState) { export function VisProvider(Private, Promise, indexPatterns, getAppState) {
const visTypes = Private(VisTypesRegistryProvider); const visTypes = Private(VisTypesRegistryProvider);
const brushEvent = Private(UtilsBrushEventProvider);
const queryFilter = Private(FilterBarQueryFilterProvider); const queryFilter = Private(FilterBarQueryFilterProvider);
const filterBarClickHandler = Private(FilterBarClickHandlerProvider); const filterBarClickHandler = Private(FilterBarClickHandlerProvider);
const SearchSource = Private(SearchSourceProvider); const SearchSource = Private(SearchSourceProvider);
@ -108,8 +108,7 @@ export function VisProvider(Private, Promise, indexPatterns, timefilter, getAppS
} }
queryFilter.addFilters(filter); queryFilter.addFilters(filter);
}, brush: (event) => { }, brush: (event) => {
const appState = getAppState(); onBrushEvent(event, getAppState());
brushEvent(appState)(event);
} }
}, },
createInheritedSearchSource: (parentSearchSource) => { createInheritedSearchSource: (parentSearchSource) => {

View file

@ -34,7 +34,7 @@ import {
uiModules uiModules
.get('kibana/directive', ['ngSanitize']) .get('kibana/directive', ['ngSanitize'])
.directive('visualize', function ($timeout, Notifier, Private, timefilter, getAppState, Promise) { .directive('visualize', function ($timeout, Notifier, Private, getAppState, Promise) {
const notify = new Notifier({ location: 'Visualize' }); const notify = new Notifier({ location: 'Visualize' });
const requestHandlers = Private(VisRequestHandlersRegistryProvider); const requestHandlers = Private(VisRequestHandlersRegistryProvider);
const responseHandlers = Private(VisResponseHandlersRegistryProvider); const responseHandlers = Private(VisResponseHandlersRegistryProvider);

View file

@ -4,6 +4,27 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
jest.mock(
'ui/chrome',
() => ({
getUiSettingsClient: () => {
return {
get: key => {
switch (key) {
case 'timepicker:timeDefaults':
return { from: 'now-15m', to: 'now', mode: 'quick' };
case 'timepicker:refreshIntervalDefaults':
return { display: 'Off', pause: false, value: 0 };
default:
throw new Error(`Unexpected config key: ${key}`);
}
}
};
}
}),
{ virtual: true }
);
import React from 'react'; import React from 'react';
import { mount } from 'enzyme'; import { mount } from 'enzyme';
import { MemoryRouter } from 'react-router-dom'; import { MemoryRouter } from 'react-router-dom';

View file

@ -4,6 +4,27 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
jest.mock(
'ui/chrome',
() => ({
getUiSettingsClient: () => {
return {
get: key => {
switch (key) {
case 'timepicker:timeDefaults':
return { from: 'now-15m', to: 'now', mode: 'quick' };
case 'timepicker:refreshIntervalDefaults':
return { display: 'Off', pause: false, value: 0 };
default:
throw new Error(`Unexpected config key: ${key}`);
}
}
};
}
}),
{ virtual: true }
);
import React from 'react'; import React from 'react';
import { shallow } from 'enzyme'; import { shallow } from 'enzyme';
import TransactionOverview from '../view'; import TransactionOverview from '../view';

View file

@ -7,10 +7,11 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import CustomPlot from '../CustomPlot'; import CustomPlot from '../CustomPlot';
import { getTimefilter } from '../../../../utils/timepicker';
import { asMillis, tpmUnit, asInteger } from '../../../../utils/formatters'; import { asMillis, tpmUnit, asInteger } from '../../../../utils/formatters';
import styled from 'styled-components'; import styled from 'styled-components';
import { units, unit, px } from '../../../../style/variables'; import { units, unit, px } from '../../../../style/variables';
import { timefilter } from 'ui/timefilter';
import moment from 'moment';
const ChartsWrapper = styled.div` const ChartsWrapper = styled.div`
display: flex; display: flex;
@ -42,9 +43,12 @@ export class Charts extends Component {
onHover = hoverIndex => this.setState({ hoverIndex }); onHover = hoverIndex => this.setState({ hoverIndex });
onMouseLeave = () => this.setState({ hoverIndex: null }); onMouseLeave = () => this.setState({ hoverIndex: null });
onSelectionEnd = selection => { onSelectionEnd = selection => {
const timefilter = getTimefilter();
this.setState({ hoverIndex: null }); this.setState({ hoverIndex: null });
timefilter.setTime(selection.start, selection.end); timefilter.setTime({
from: moment(selection.start).toISOString(),
to: moment(selection.end).toISOString(),
mode: 'absolute'
});
}; };
getResponseTimeTickFormatter = t => { getResponseTimeTickFormatter = t => {

View file

@ -4,13 +4,12 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
import moment from 'moment';
import { uiModules } from 'ui/modules'; import { uiModules } from 'ui/modules';
import chrome from 'ui/chrome'; import chrome from 'ui/chrome';
import 'ui/autoload/all'; import 'ui/autoload/all';
import { updateTimePicker } from '../../store/urlParams'; import { updateTimePicker } from '../../store/urlParams';
import { timefilter, registerTimefilterWithGlobalState } from 'ui/timefilter';
let globalTimefilter;
let currentInterval; let currentInterval;
// hack to wait for angular template to be ready // hack to wait for angular template to be ready
@ -37,7 +36,7 @@ export function initTimepicker(history, dispatch, callback) {
uiModules uiModules
.get('app/apm', []) .get('app/apm', [])
.controller('TimePickerController', ($scope, timefilter, globalState) => { .controller('TimePickerController', ($scope, globalState) => {
// Add APM feedback menu // Add APM feedback menu
// TODO: move this somewhere else // TODO: move this somewhere else
$scope.topNavMenu = []; $scope.topNavMenu = [];
@ -49,55 +48,41 @@ export function initTimepicker(history, dispatch, callback) {
}); });
history.listen(() => { history.listen(() => {
updateRefreshRate(dispatch, timefilter); updateRefreshRate(dispatch);
globalState.fetch(); globalState.fetch();
}); });
timefilter.setTime = (from, to) => {
timefilter.time.from = moment(from).toISOString();
timefilter.time.to = moment(to).toISOString();
$scope.$apply();
};
timefilter.enableTimeRangeSelector(); timefilter.enableTimeRangeSelector();
timefilter.enableAutoRefreshSelector(); timefilter.enableAutoRefreshSelector();
timefilter.init();
updateRefreshRate(dispatch, timefilter); updateRefreshRate(dispatch);
timefilter.on('update', () => dispatch(getAction(timefilter))); $scope.$listen(timefilter, 'timeUpdate', () =>
dispatch(updateTimePickerAction())
);
// hack to access timefilter outside Angular registerTimefilterWithGlobalState(globalState);
globalTimefilter = timefilter;
Promise.all([waitForAngularReady]).then(callback); Promise.all([waitForAngularReady]).then(callback);
}); });
} }
function getAction(timefilter) { function updateTimePickerAction() {
return updateTimePicker({ return updateTimePicker({
min: timefilter.getBounds().min.toISOString(), min: timefilter.getBounds().min.toISOString(),
max: timefilter.getBounds().max.toISOString() max: timefilter.getBounds().max.toISOString()
}); });
} }
function updateRefreshRate(dispatch, timefilter) { function updateRefreshRate(dispatch) {
const refreshInterval = timefilter.refreshInterval.value; const refreshInterval = timefilter.getRefreshInterval().value;
if (currentInterval) { if (currentInterval) {
clearInterval(currentInterval); clearInterval(currentInterval);
} }
if (refreshInterval > 0 && !timefilter.refreshInterval.pause) { if (refreshInterval > 0 && !timefilter.getRefreshInterval().pause) {
currentInterval = setInterval( currentInterval = setInterval(
() => dispatch(getAction(timefilter)), () => dispatch(updateTimePickerAction()),
refreshInterval refreshInterval
); );
} }
} }
export function getTimefilter() {
if (!globalTimefilter) {
throw new Error(
'Timepicker must be initialized before calling getTimefilter'
);
}
return globalTimefilter;
}

View file

@ -8,12 +8,12 @@
import 'ngreact'; import 'ngreact';
import { uiModules } from 'ui/modules'; import { uiModules } from 'ui/modules';
import { timefilter } from 'ui/timefilter';
const module = uiModules.get('apps/ml', ['react']); const module = uiModules.get('apps/ml', ['react']);
import { AnomaliesTable } from './anomalies_table'; import { AnomaliesTable } from './anomalies_table';
module.directive('mlAnomaliesTable', function ($injector) { module.directive('mlAnomaliesTable', function ($injector) {
const timefilter = $injector.get('timefilter');
const reactDirective = $injector.get('reactDirective'); const reactDirective = $injector.get('reactDirective');
return reactDirective( return reactDirective(

View file

@ -18,7 +18,6 @@ import {
EuiPopover EuiPopover
} from '@elastic/eui'; } from '@elastic/eui';
import 'ui/timefilter';
import chrome from 'ui/chrome'; import chrome from 'ui/chrome';
import { toastNotifications } from 'ui/notify'; import { toastNotifications } from 'ui/notify';

View file

@ -21,10 +21,10 @@ import { calculateTextWidth } from 'plugins/ml/util/string_utils';
import { IntervalHelperProvider } from 'plugins/ml/util/ml_time_buckets'; import { IntervalHelperProvider } from 'plugins/ml/util/ml_time_buckets';
import { uiModules } from 'ui/modules'; import { uiModules } from 'ui/modules';
import { timefilter } from 'ui/timefilter';
const module = uiModules.get('apps/ml'); const module = uiModules.get('apps/ml');
module.directive('mlDocumentCountChart', function ( module.directive('mlDocumentCountChart', function (
timefilter,
Private, Private,
mlChartTooltipService) { mlChartTooltipService) {

View file

@ -11,7 +11,9 @@ import moment from 'moment';
import { ml } from 'plugins/ml/services/ml_api_service'; import { ml } from 'plugins/ml/services/ml_api_service';
export function FullTimeRangeSelectorServiceProvider(timefilter, Notifier) { import { timefilter } from 'ui/timefilter';
export function FullTimeRangeSelectorServiceProvider(Notifier) {
const notify = new Notifier(); const notify = new Notifier();
function setFullTimeRange(indexPattern, query) { function setFullTimeRange(indexPattern, query) {
@ -22,8 +24,10 @@ export function FullTimeRangeSelectorServiceProvider(timefilter, Notifier) {
query query
}) })
.then((resp) => { .then((resp) => {
timefilter.time.from = moment(resp.start.epoch).toISOString(); timefilter.setTime({
timefilter.time.to = moment(resp.end.epoch).toISOString(); from: moment(resp.start.epoch).toISOString(),
to: moment(resp.end.epoch).toISOString()
});
}) })
.catch((resp) => { .catch((resp) => {
notify.error(resp); notify.error(resp);

View file

@ -21,10 +21,11 @@ import { isTimeSeriesViewJob } from 'plugins/ml/../common/util/job_utils';
import { mlJobService } from 'plugins/ml/services/job_service'; import { mlJobService } from 'plugins/ml/services/job_service';
import { JobSelectServiceProvider } from 'plugins/ml/components/job_select_list/job_select_service'; import { JobSelectServiceProvider } from 'plugins/ml/components/job_select_list/job_select_service';
import { timefilter } from 'ui/timefilter';
import { uiModules } from 'ui/modules'; import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml'); const module = uiModules.get('apps/ml');
module.directive('mlJobSelectList', function (Private, timefilter) { module.directive('mlJobSelectList', function (Private) {
return { return {
restrict: 'AE', restrict: 'AE',
replace: true, replace: true,
@ -254,8 +255,10 @@ module.directive('mlJobSelectList', function (Private, timefilter) {
if (times.length) { if (times.length) {
const min = _.min(times); const min = _.min(times);
const max = _.max(times); const max = _.max(times);
timefilter.time.from = moment(min).toISOString(); timefilter.setTime({
timefilter.time.to = moment(max).toISOString(); from: moment(min).toISOString(),
to: moment(max).toISOString()
});
} }
} }
mlJobSelectService.jobSelectListState.applyTimeRange = $scope.applyTimeRange; mlJobSelectService.jobSelectListState.applyTimeRange = $scope.applyTimeRange;
@ -360,8 +363,10 @@ module.directive('mlJobSelectList', function (Private, timefilter) {
} }
$scope.useTimeRange = function (job) { $scope.useTimeRange = function (job) {
timefilter.time.from = job.timeRange.fromMoment.toISOString(); timefilter.setTime({
timefilter.time.to = job.timeRange.toMoment.toISOString(); from: job.timeRange.fromMoment.toISOString(),
to: job.timeRange.toMoment.toISOString()
});
}; };
}, },
link: function (scope, element, attrs) { link: function (scope, element, attrs) {

View file

@ -49,6 +49,7 @@ uiRoutes
} }
}); });
import { timefilter } from 'ui/timefilter';
import { uiModules } from 'ui/modules'; import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml'); const module = uiModules.get('apps/ml');
@ -59,7 +60,6 @@ module
$timeout, $timeout,
$window, $window,
Private, Private,
timefilter,
AppState) { AppState) {
timefilter.enableTimeRangeSelector(); timefilter.enableTimeRangeSelector();
@ -143,7 +143,7 @@ module
// Refresh the data when the time range is altered. // Refresh the data when the time range is altered.
$scope.$listen(timefilter, 'fetch', function () { $scope.$listenAndDigestAsync(timefilter, 'fetch', function () {
$scope.earliest = timefilter.getActiveBounds().min.valueOf(); $scope.earliest = timefilter.getActiveBounds().min.valueOf();
$scope.latest = timefilter.getActiveBounds().max.valueOf(); $scope.latest = timefilter.getActiveBounds().max.valueOf();
loadOverallStats(); loadOverallStats();

View file

@ -19,13 +19,13 @@ import moment from 'moment';
import rison from 'rison-node'; import rison from 'rison-node';
import chrome from 'ui/chrome'; import chrome from 'ui/chrome';
import 'ui/timefilter'; import { timefilter } from 'ui/timefilter';
import template from './explorer_charts_container.html'; import template from './explorer_charts_container.html';
import { uiModules } from 'ui/modules'; import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml'); const module = uiModules.get('apps/ml');
module.directive('mlExplorerChartsContainer', function ($window, timefilter) { module.directive('mlExplorerChartsContainer', function ($window) {
function link(scope, element) { function link(scope, element) {
// Create a div for the tooltip. // Create a div for the tooltip.

View file

@ -39,6 +39,7 @@ import { mlJobService } from 'plugins/ml/services/job_service';
import { mlFieldFormatService } from 'plugins/ml/services/field_format_service'; import { mlFieldFormatService } from 'plugins/ml/services/field_format_service';
import { JobSelectServiceProvider } from 'plugins/ml/components/job_select_list/job_select_service'; import { JobSelectServiceProvider } from 'plugins/ml/components/job_select_list/job_select_service';
import { isTimeSeriesViewDetector } from 'plugins/ml/../common/util/job_utils'; import { isTimeSeriesViewDetector } from 'plugins/ml/../common/util/job_utils';
import { timefilter } from 'ui/timefilter';
uiRoutes uiRoutes
.when('/explorer/?', { .when('/explorer/?', {
@ -59,7 +60,6 @@ module.controller('MlExplorerController', function (
$timeout, $timeout,
AppState, AppState,
Private, Private,
timefilter,
mlCheckboxShowChartsService, mlCheckboxShowChartsService,
mlExplorerDashboardService, mlExplorerDashboardService,
mlSelectLimitService, mlSelectLimitService,
@ -246,7 +246,7 @@ module.controller('MlExplorerController', function (
}; };
// Refresh all the data when the time range is altered. // Refresh all the data when the time range is altered.
$scope.$listen(timefilter, 'fetch', () => { $scope.$listenAndDigestAsync(timefilter, 'fetch', () => {
loadOverallData(); loadOverallData();
clearSelectedAnomalies(); clearSelectedAnomalies();
}); });

View file

@ -18,6 +18,7 @@ import { isTimeSeriesViewJob } from 'plugins/ml/../common/util/job_utils';
import { toLocaleString, mlEscape } from 'plugins/ml/util/string_utils'; import { toLocaleString, mlEscape } from 'plugins/ml/util/string_utils';
import { copyTextToClipboard } from 'plugins/ml/util/clipboard_utils'; import { copyTextToClipboard } from 'plugins/ml/util/clipboard_utils';
import { timefilter } from 'ui/timefilter';
import uiRoutes from 'ui/routes'; import uiRoutes from 'ui/routes';
import { checkLicense } from 'plugins/ml/license/check_license'; import { checkLicense } from 'plugins/ml/license/check_license';
import { checkGetJobsPrivilege, checkPermission, createPermissionFailureMessage } from 'plugins/ml/privilege/check_privilege'; import { checkGetJobsPrivilege, checkPermission, createPermissionFailureMessage } from 'plugins/ml/privilege/check_privilege';
@ -60,7 +61,6 @@ module.controller('MlJobsList',
$timeout, $timeout,
$compile, $compile,
$modal, $modal,
timefilter,
kbnUrl, kbnUrl,
Private, Private,
mlDatafeedService) { mlDatafeedService) {

View file

@ -11,6 +11,7 @@ import angular from 'angular';
import 'ace'; import 'ace';
import { parseInterval } from 'ui/utils/parse_interval'; import { parseInterval } from 'ui/utils/parse_interval';
import { timefilter } from 'ui/timefilter';
import uiRoutes from 'ui/routes'; import uiRoutes from 'ui/routes';
import { checkLicense } from 'plugins/ml/license/check_license'; import { checkLicense } from 'plugins/ml/license/check_license';
@ -69,7 +70,6 @@ module.controller('MlNewJob',
$route, $route,
$location, $location,
$modal, $modal,
timefilter,
mlDatafeedService, mlDatafeedService,
mlConfirmModalService) { mlConfirmModalService) {

View file

@ -15,7 +15,6 @@ import $ from 'jquery';
import d3 from 'd3'; import d3 from 'd3';
import angular from 'angular'; import angular from 'angular';
import moment from 'moment'; import moment from 'moment';
import 'ui/timefilter';
import { TimeBuckets } from 'ui/time_buckets'; import { TimeBuckets } from 'ui/time_buckets';
import { numTicksForDateFormat } from 'plugins/ml/util/chart_utils'; import { numTicksForDateFormat } from 'plugins/ml/util/chart_utils';

View file

@ -13,8 +13,9 @@ import { IntervalHelperProvider } from 'plugins/ml/util/ml_time_buckets';
import { calculateTextWidth } from 'plugins/ml/util/string_utils'; import { calculateTextWidth } from 'plugins/ml/util/string_utils';
import { mlResultsService } from 'plugins/ml/services/results_service'; import { mlResultsService } from 'plugins/ml/services/results_service';
import { mlSimpleJobSearchService } from 'plugins/ml/jobs/new_job/simple/components/utils/search_service'; import { mlSimpleJobSearchService } from 'plugins/ml/jobs/new_job/simple/components/utils/search_service';
import { timefilter } from 'ui/timefilter';
export function ChartDataUtilsProvider(Private, timefilter) { export function ChartDataUtilsProvider(Private) {
const TimeBuckets = Private(IntervalHelperProvider); const TimeBuckets = Private(IntervalHelperProvider);
function loadDocCountData(formConfig, chartData) { function loadDocCountData(formConfig, chartData) {

View file

@ -43,6 +43,7 @@ import { mlMessageBarService } from 'plugins/ml/components/messagebar/messagebar
import { initPromise } from 'plugins/ml/util/promise'; import { initPromise } from 'plugins/ml/util/promise';
import { ml } from 'plugins/ml/services/ml_api_service'; import { ml } from 'plugins/ml/services/ml_api_service';
import template from './create_job.html'; import template from './create_job.html';
import { timefilter } from 'ui/timefilter';
uiRoutes uiRoutes
.when('/jobs/new_job/simple/multi_metric', { .when('/jobs/new_job/simple/multi_metric', {
@ -65,7 +66,6 @@ module
.controller('MlCreateMultiMetricJob', function ( .controller('MlCreateMultiMetricJob', function (
$scope, $scope,
$route, $route,
timefilter,
Private, Private,
AppState) { AppState) {
@ -251,8 +251,8 @@ module
function setTime() { function setTime() {
$scope.ui.bucketSpanValid = true; $scope.ui.bucketSpanValid = true;
$scope.formConfig.start = dateMath.parse(timefilter.time.from).valueOf(); $scope.formConfig.start = dateMath.parse(timefilter.getTime().from).valueOf();
$scope.formConfig.end = dateMath.parse(timefilter.time.to).valueOf(); $scope.formConfig.end = dateMath.parse(timefilter.getTime().to).valueOf();
$scope.formConfig.format = 'epoch_millis'; $scope.formConfig.format = 'epoch_millis';
const bucketSpanInterval = parseInterval($scope.formConfig.bucketSpan); const bucketSpanInterval = parseInterval($scope.formConfig.bucketSpan);
@ -689,7 +689,7 @@ module
populateAppStateSettings(appState, $scope); populateAppStateSettings(appState, $scope);
}); });
$scope.$listen(timefilter, 'fetch', () => { $scope.$listenAndDigestAsync(timefilter, 'fetch', () => {
$scope.loadVis(); $scope.loadVis();
if ($scope.formConfig.splitField !== undefined) { if ($scope.formConfig.splitField !== undefined) {
$scope.setModelMemoryLimit(); $scope.setModelMemoryLimit();

View file

@ -42,6 +42,7 @@ import { FullTimeRangeSelectorServiceProvider } from 'plugins/ml/components/full
import { mlMessageBarService } from 'plugins/ml/components/messagebar/messagebar_service'; import { mlMessageBarService } from 'plugins/ml/components/messagebar/messagebar_service';
import { initPromise } from 'plugins/ml/util/promise'; import { initPromise } from 'plugins/ml/util/promise';
import template from './create_job.html'; import template from './create_job.html';
import { timefilter } from 'ui/timefilter';
uiRoutes uiRoutes
.when('/jobs/new_job/simple/population', { .when('/jobs/new_job/simple/population', {
@ -65,7 +66,6 @@ module
$scope, $scope,
$route, $route,
$timeout, $timeout,
timefilter,
Private, Private,
AppState) { AppState) {
@ -265,8 +265,8 @@ module
function setTime() { function setTime() {
$scope.ui.bucketSpanValid = true; $scope.ui.bucketSpanValid = true;
$scope.formConfig.start = dateMath.parse(timefilter.time.from).valueOf(); $scope.formConfig.start = dateMath.parse(timefilter.getTime().from).valueOf();
$scope.formConfig.end = dateMath.parse(timefilter.time.to).valueOf(); $scope.formConfig.end = dateMath.parse(timefilter.getTime().to).valueOf();
$scope.formConfig.format = 'epoch_millis'; $scope.formConfig.format = 'epoch_millis';
const bucketSpanInterval = parseInterval($scope.formConfig.bucketSpan); const bucketSpanInterval = parseInterval($scope.formConfig.bucketSpan);
@ -695,7 +695,7 @@ module
populateAppStateSettings(appState, $scope); populateAppStateSettings(appState, $scope);
}); });
$scope.$listen(timefilter, 'fetch', $scope.loadVis); $scope.$listenAndDigestAsync(timefilter, 'fetch', $scope.loadVis);
angular.element(window).resize(() => { angular.element(window).resize(() => {
resize(); resize();

View file

@ -15,8 +15,9 @@ import { mlFieldFormatService } from 'plugins/ml/services/field_format_service';
import { mlJobService } from 'plugins/ml/services/job_service'; import { mlJobService } from 'plugins/ml/services/job_service';
import { createJobForSaving } from 'plugins/ml/jobs/new_job/utils/new_job_utils'; import { createJobForSaving } from 'plugins/ml/jobs/new_job/utils/new_job_utils';
import { ml } from 'plugins/ml/services/ml_api_service'; import { ml } from 'plugins/ml/services/ml_api_service';
import { timefilter } from 'ui/timefilter';
export function PopulationJobServiceProvider(timefilter, Private) { export function PopulationJobServiceProvider(Private) {
const TimeBuckets = Private(IntervalHelperProvider); const TimeBuckets = Private(IntervalHelperProvider);
const OVER_FIELD_EXAMPLES_COUNT = 40; const OVER_FIELD_EXAMPLES_COUNT = 40;

View file

@ -25,6 +25,7 @@ import { mlMessageBarService } from 'plugins/ml/components/messagebar/messagebar
import { ml } from 'plugins/ml/services/ml_api_service'; import { ml } from 'plugins/ml/services/ml_api_service';
import { initPromise } from 'plugins/ml/util/promise'; import { initPromise } from 'plugins/ml/util/promise';
import template from './create_job.html'; import template from './create_job.html';
import { timefilter } from 'ui/timefilter';
uiRoutes uiRoutes
.when('/jobs/new_job/simple/recognize', { .when('/jobs/new_job/simple/recognize', {
@ -47,13 +48,11 @@ module
$scope, $scope,
$window, $window,
$route, $route,
timefilter,
Private) { Private) {
const mlCreateRecognizerJobsService = Private(CreateRecognizerJobsServiceProvider); const mlCreateRecognizerJobsService = Private(CreateRecognizerJobsServiceProvider);
timefilter.disableTimeRangeSelector(); timefilter.disableTimeRangeSelector();
timefilter.disableAutoRefreshSelector(); timefilter.disableAutoRefreshSelector();
$scope.tt = timefilter;
const msgs = mlMessageBarService; const msgs = mlMessageBarService;
const SAVE_STATE = { const SAVE_STATE = {
@ -344,8 +343,8 @@ module
$scope.formConfig.start = resp.start.epoch; $scope.formConfig.start = resp.start.epoch;
$scope.formConfig.end = resp.end.epoch; $scope.formConfig.end = resp.end.epoch;
} else { } else {
$scope.formConfig.start = dateMath.parse(timefilter.time.from).valueOf(); $scope.formConfig.start = dateMath.parse(timefilter.getTime().from).valueOf();
$scope.formConfig.end = dateMath.parse(timefilter.time.to).valueOf(); $scope.formConfig.end = dateMath.parse(timefilter.getTime().to).valueOf();
} }
let jobsCounter = 0; let jobsCounter = 0;
let datafeedCounter = 0; let datafeedCounter = 0;

View file

@ -14,7 +14,6 @@ import $ from 'jquery';
import d3 from 'd3'; import d3 from 'd3';
import angular from 'angular'; import angular from 'angular';
import moment from 'moment'; import moment from 'moment';
import 'ui/timefilter';
import { TimeBuckets } from 'ui/time_buckets'; import { TimeBuckets } from 'ui/time_buckets';
import { drawLineChartDots, numTicksForDateFormat } from 'plugins/ml/util/chart_utils'; import { drawLineChartDots, numTicksForDateFormat } from 'plugins/ml/util/chart_utils';

View file

@ -44,6 +44,8 @@ import { initPromise } from 'plugins/ml/util/promise';
import template from './create_job.html'; import template from './create_job.html';
import { timefilter } from 'ui/timefilter';
uiRoutes uiRoutes
.when('/jobs/new_job/simple/single_metric', { .when('/jobs/new_job/simple/single_metric', {
template, template,
@ -66,7 +68,6 @@ module
$scope, $scope,
$route, $route,
$filter, $filter,
timefilter,
Private, Private,
AppState) { AppState) {
@ -245,8 +246,8 @@ module
function setTime() { function setTime() {
$scope.ui.bucketSpanValid = true; $scope.ui.bucketSpanValid = true;
$scope.formConfig.start = dateMath.parse(timefilter.time.from).valueOf(); $scope.formConfig.start = dateMath.parse(timefilter.getTime().from).valueOf();
$scope.formConfig.end = dateMath.parse(timefilter.time.to).valueOf(); $scope.formConfig.end = dateMath.parse(timefilter.getTime().to).valueOf();
$scope.formConfig.format = 'epoch_millis'; $scope.formConfig.format = 'epoch_millis';
const bucketSpanInterval = parseInterval($scope.formConfig.bucketSpan); const bucketSpanInterval = parseInterval($scope.formConfig.bucketSpan);
@ -566,7 +567,7 @@ module
mlFullTimeRangeSelectorService.setFullTimeRange($scope.ui.indexPattern, $scope.formConfig.combinedQuery); mlFullTimeRangeSelectorService.setFullTimeRange($scope.ui.indexPattern, $scope.formConfig.combinedQuery);
}; };
$scope.$listen(timefilter, 'fetch', $scope.loadVis); $scope.$listenAndDigestAsync(timefilter, 'fetch', $scope.loadVis);
$scope.$on('$destroy', () => { $scope.$on('$destroy', () => {
globalForceStop = true; globalForceStop = true;

View file

@ -19,6 +19,7 @@ import { loadIndexPatterns, getIndexPatterns } from 'plugins/ml/util/index_utils
import { checkMlNodesAvailable } from 'plugins/ml/ml_nodes_check/check_ml_nodes'; import { checkMlNodesAvailable } from 'plugins/ml/ml_nodes_check/check_ml_nodes';
import { initPromise } from 'plugins/ml/util/promise'; import { initPromise } from 'plugins/ml/util/promise';
import template from './index_or_search.html'; import template from './index_or_search.html';
import { timefilter } from 'ui/timefilter';
uiRoutes uiRoutes
.when('/jobs/new_job', { .when('/jobs/new_job', {
@ -42,10 +43,7 @@ import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml'); const module = uiModules.get('apps/ml');
module.controller('MlNewJobStepIndexOrSearch', module.controller('MlNewJobStepIndexOrSearch',
function ( function ($scope) {
$scope,
$route,
timefilter) {
timefilter.disableTimeRangeSelector(); // remove time picker from top of page timefilter.disableTimeRangeSelector(); // remove time picker from top of page
timefilter.disableAutoRefreshSelector(); // remove time picker from top of page timefilter.disableAutoRefreshSelector(); // remove time picker from top of page

View file

@ -21,6 +21,7 @@ import { addItemToRecentlyAccessed } from 'plugins/ml/util/recently_accessed';
import { checkMlNodesAvailable } from 'plugins/ml/ml_nodes_check/check_ml_nodes'; import { checkMlNodesAvailable } from 'plugins/ml/ml_nodes_check/check_ml_nodes';
import { initPromise } from 'plugins/ml/util/promise'; import { initPromise } from 'plugins/ml/util/promise';
import template from './job_type.html'; import template from './job_type.html';
import { timefilter } from 'ui/timefilter';
uiRoutes uiRoutes
.when('/jobs/new_job/step/job_type', { .when('/jobs/new_job/step/job_type', {
@ -42,8 +43,7 @@ const module = uiModules.get('apps/ml');
module.controller('MlNewJobStepJobType', module.controller('MlNewJobStepJobType',
function ( function (
$scope, $scope,
$route, $route) {
timefilter) {
timefilter.disableTimeRangeSelector(); // remove time picker from top of page timefilter.disableTimeRangeSelector(); // remove time picker from top of page
timefilter.disableAutoRefreshSelector(); // remove time picker from top of page timefilter.disableAutoRefreshSelector(); // remove time picker from top of page

View file

@ -22,6 +22,8 @@ import { initPromise } from 'plugins/ml/util/promise';
import template from './calendars_list.html'; import template from './calendars_list.html';
import { timefilter } from 'ui/timefilter';
uiRoutes uiRoutes
.when('/settings/calendars_list', { .when('/settings/calendars_list', {
template, template,
@ -43,7 +45,6 @@ module.controller('MlCalendarsList',
$route, $route,
$location, $location,
pagerFactory, pagerFactory,
timefilter,
mlConfirmModalService) { mlConfirmModalService) {
$scope.permissions = { $scope.permissions = {

View file

@ -14,6 +14,8 @@ import { initPromise } from 'plugins/ml/util/promise';
import template from './settings.html'; import template from './settings.html';
import { timefilter } from 'ui/timefilter';
uiRoutes uiRoutes
.when('/settings', { .when('/settings', {
template, template,
@ -29,9 +31,7 @@ import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml'); const module = uiModules.get('apps/ml');
module.controller('MlSettings', module.controller('MlSettings',
function ( function () {
$scope,
timefilter) {
timefilter.disableTimeRangeSelector(); // remove time picker from top of page timefilter.disableTimeRangeSelector(); // remove time picker from top of page
timefilter.disableAutoRefreshSelector(); // remove time picker from top of page timefilter.disableAutoRefreshSelector(); // remove time picker from top of page

View file

@ -22,8 +22,6 @@ import {
EuiToolTip EuiToolTip
} from '@elastic/eui'; } from '@elastic/eui';
import 'ui/timefilter';
// don't use something like plugins/ml/../common // don't use something like plugins/ml/../common
// because it won't work with the jest tests // because it won't work with the jest tests
import { FORECAST_REQUEST_STATE, JOB_STATE } from '../../../common/constants/states'; import { FORECAST_REQUEST_STATE, JOB_STATE } from '../../../common/constants/states';
@ -402,6 +400,7 @@ ForecastingModal.propTypes = {
detectorIndex: PropTypes.number, detectorIndex: PropTypes.number,
entities: PropTypes.array, entities: PropTypes.array,
loadForForecastId: PropTypes.func, loadForForecastId: PropTypes.func,
timefilter: PropTypes.object,
}; };
export { ForecastingModal }; export { ForecastingModal };

View file

@ -7,13 +7,13 @@
import 'ngreact'; import 'ngreact';
import { timefilter } from 'ui/timefilter';
import { uiModules } from 'ui/modules'; import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml', ['react']); const module = uiModules.get('apps/ml', ['react']);
import { ForecastingModal } from './forecasting_modal'; import { ForecastingModal } from './forecasting_modal';
module.directive('mlForecastingModal', function ($injector) { module.directive('mlForecastingModal', function ($injector) {
const timefilter = $injector.get('timefilter');
const reactDirective = $injector.get('reactDirective'); const reactDirective = $injector.get('reactDirective');
return reactDirective( return reactDirective(
ForecastingModal, ForecastingModal,

View file

@ -22,7 +22,6 @@ import {
} from '@elastic/eui'; } from '@elastic/eui';
import { formatDate } from '@elastic/eui/lib/services/format'; import { formatDate } from '@elastic/eui/lib/services/format';
import 'ui/timefilter';
const TIME_FORMAT = 'MMMM Do YYYY, HH:mm:ss'; const TIME_FORMAT = 'MMMM Do YYYY, HH:mm:ss';

View file

@ -16,7 +16,7 @@ import $ from 'jquery';
import angular from 'angular'; import angular from 'angular';
import d3 from 'd3'; import d3 from 'd3';
import moment from 'moment'; import moment from 'moment';
import 'ui/timefilter'; import { timefilter } from 'ui/timefilter';
import { ResizeChecker } from 'ui/resize_checker'; import { ResizeChecker } from 'ui/resize_checker';
@ -40,7 +40,6 @@ const module = uiModules.get('apps/ml');
module.directive('mlTimeseriesChart', function ( module.directive('mlTimeseriesChart', function (
$compile, $compile,
$timeout, $timeout,
timefilter,
Private, Private,
mlChartTooltipService) { mlChartTooltipService) {

View file

@ -20,7 +20,7 @@ import 'plugins/ml/components/controls';
import { notify } from 'ui/notify'; import { notify } from 'ui/notify';
import uiRoutes from 'ui/routes'; import uiRoutes from 'ui/routes';
import 'ui/timefilter'; import { timefilter } from 'ui/timefilter';
import { parseInterval } from 'ui/utils/parse_interval'; import { parseInterval } from 'ui/utils/parse_interval';
import { checkLicense } from 'plugins/ml/license/check_license'; import { checkLicense } from 'plugins/ml/license/check_license';
import { checkGetJobsPrivilege, checkPermission } from 'plugins/ml/privilege/check_privilege'; import { checkGetJobsPrivilege, checkPermission } from 'plugins/ml/privilege/check_privilege';
@ -70,7 +70,6 @@ module.controller('MlTimeSeriesExplorerController', function (
$route, $route,
$timeout, $timeout,
Private, Private,
timefilter,
AppState, AppState,
mlSelectIntervalService, mlSelectIntervalService,
mlSelectSeverityService) { mlSelectSeverityService) {
@ -505,8 +504,8 @@ module.controller('MlTimeSeriesExplorerController', function (
forecastId forecastId
).then((resp) => { ).then((resp) => {
const bounds = timefilter.getActiveBounds(); const bounds = timefilter.getActiveBounds();
const earliest = moment(resp.earliest || timefilter.time.from); const earliest = moment(resp.earliest || timefilter.getTime().from);
const latest = moment(resp.latest || timefilter.time.to); const latest = moment(resp.latest || timefilter.getTime().to);
// Store forecast ID in the appState. // Store forecast ID in the appState.
$scope.appState.mlTimeSeriesExplorer.forecastId = forecastId; $scope.appState.mlTimeSeriesExplorer.forecastId = forecastId;
@ -529,8 +528,10 @@ module.controller('MlTimeSeriesExplorerController', function (
if (earliest.isBefore(bounds.min) || latest.isAfter(bounds.max)) { if (earliest.isBefore(bounds.min) || latest.isAfter(bounds.max)) {
const earliestMs = Math.min(earliest.valueOf(), bounds.min.valueOf()); const earliestMs = Math.min(earliest.valueOf(), bounds.min.valueOf());
const latestMs = Math.max(latest.valueOf(), bounds.max.valueOf()); const latestMs = Math.max(latest.valueOf(), bounds.max.valueOf());
timefilter.time.from = moment(earliestMs).toISOString(); timefilter.setTime({
timefilter.time.to = moment(latestMs).toISOString(); from: moment(earliestMs).toISOString(),
to: moment(latestMs).toISOString()
});
} else { } else {
// Refresh to show the requested forecast data. // Refresh to show the requested forecast data.
$scope.refresh(); $scope.refresh();
@ -559,7 +560,7 @@ module.controller('MlTimeSeriesExplorerController', function (
}; };
// Refresh the data when the time range is altered. // Refresh the data when the time range is altered.
$scope.$listen(timefilter, 'fetch', $scope.refresh); $scope.$listenAndDigestAsync(timefilter, 'fetch', $scope.refresh);
// Add a watcher for auto-refresh of the time filter to refresh all the data. // Add a watcher for auto-refresh of the time filter to refresh all the data.
const refreshWatcher = Private(refreshIntervalWatcher); const refreshWatcher = Private(refreshIntervalWatcher);

View file

@ -22,7 +22,7 @@ const unitsDesc = dateMath.unitsDesc;
const largeMax = unitsDesc.indexOf('w'); // Multiple units of week or longer converted to days for ES intervals. const largeMax = unitsDesc.indexOf('w'); // Multiple units of week or longer converted to days for ES intervals.
import { TimeBuckets as KibanaTimeBuckets } from 'ui/time_buckets'; import { TimeBuckets as KibanaTimeBuckets } from 'ui/time_buckets';
export function IntervalHelperProvider(Private, timefilter, config) { export function IntervalHelperProvider(Private, config) {
const calcAuto = Private(TimeBucketsCalcAutoIntervalProvider); const calcAuto = Private(TimeBucketsCalcAutoIntervalProvider);

View file

@ -4,37 +4,42 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
import { timefilter } from 'ui/timefilter';
/* /*
* Watches for changes to the refresh interval of the page time filter, * Watches for changes to the refresh interval of the page time filter,
* so that listeners can be notified when the auto-refresh interval has elapsed. * so that listeners can be notified when the auto-refresh interval has elapsed.
*/ */
export function refreshIntervalWatcher($rootScope, $timeout) { export function refreshIntervalWatcher($timeout) {
let refresher; let refresher;
let listener;
function init(listener) { const onRefreshIntervalChange = () => {
if (refresher) {
$timeout.cancel(refresher);
}
const interval = timefilter.getRefreshInterval();
if (interval.value > 0 && !interval.pause) {
function startRefresh() {
refresher = $timeout(() => {
startRefresh();
listener();
}, interval.value);
}
startRefresh();
}
};
$rootScope.$watchCollection('timefilter.refreshInterval', (interval) => { function init(listenerCallback) {
if (refresher) { listener = listenerCallback;
$timeout.cancel(refresher); timefilter.on('refreshIntervalUpdate', onRefreshIntervalChange);
}
if (interval.value > 0 && !interval.pause) {
function startRefresh() {
refresher = $timeout(() => {
startRefresh();
listener();
}, interval.value);
}
startRefresh();
}
});
} }
function cancel() { function cancel() {
$timeout.cancel(refresher); $timeout.cancel(refresher);
timefilter.off('refreshIntervalUpdate', onRefreshIntervalChange);
} }
return { return {

View file

@ -9,9 +9,10 @@ import moment from 'moment';
import { render } from 'react-dom'; import { render } from 'react-dom';
import { uiModules } from 'ui/modules'; import { uiModules } from 'ui/modules';
import { Beat } from 'plugins/monitoring/components/beats/beat'; import { Beat } from 'plugins/monitoring/components/beats/beat';
import { timefilter } from 'ui/timefilter';
const uiModule = uiModules.get('monitoring/directives', []); const uiModule = uiModules.get('monitoring/directives', []);
uiModule.directive('monitoringBeatsBeat', (timefilter) => { uiModule.directive('monitoringBeatsBeat', () => {
return { return {
restrict: 'E', restrict: 'E',
scope: { scope: {
@ -20,10 +21,10 @@ uiModule.directive('monitoringBeatsBeat', (timefilter) => {
link(scope, $el) { link(scope, $el) {
function onBrush({ xaxis }) { function onBrush({ xaxis }) {
scope.$evalAsync(() => { timefilter.setTime({
timefilter.time.from = moment(xaxis.from); from: moment(xaxis.from),
timefilter.time.to = moment(xaxis.to); to: moment(xaxis.to),
timefilter.time.mode = 'absolute'; mode: 'absolute',
}); });
} }

View file

@ -9,9 +9,10 @@ import moment from 'moment';
import { render } from 'react-dom'; import { render } from 'react-dom';
import { uiModules } from 'ui/modules'; import { uiModules } from 'ui/modules';
import { BeatsOverview } from 'plugins/monitoring/components/beats/overview'; import { BeatsOverview } from 'plugins/monitoring/components/beats/overview';
import { timefilter } from 'ui/timefilter';
const uiModule = uiModules.get('monitoring/directives', []); const uiModule = uiModules.get('monitoring/directives', []);
uiModule.directive('monitoringBeatsOverview', (timefilter) => { uiModule.directive('monitoringBeatsOverview', () => {
return { return {
restrict: 'E', restrict: 'E',
scope: { scope: {
@ -20,10 +21,10 @@ uiModule.directive('monitoringBeatsOverview', (timefilter) => {
link(scope, $el) { link(scope, $el) {
function onBrush({ xaxis }) { function onBrush({ xaxis }) {
scope.$evalAsync(() => { timefilter.setTime({
timefilter.time.from = moment(xaxis.from); from: moment(xaxis.from),
timefilter.time.to = moment(xaxis.to); to: moment(xaxis.to),
timefilter.time.mode = 'absolute'; mode: 'absolute'
}); });
} }

View file

@ -17,9 +17,10 @@ import {
import { Tooltip } from 'pivotal-ui/react/tooltip'; import { Tooltip } from 'pivotal-ui/react/tooltip';
import { OverlayTrigger } from 'pivotal-ui/react/overlay-trigger'; import { OverlayTrigger } from 'pivotal-ui/react/overlay-trigger';
import { KuiInfoButton } from '@kbn/ui-framework/components'; import { KuiInfoButton } from '@kbn/ui-framework/components';
import { timefilter } from 'ui/timefilter';
const uiModule = uiModules.get('plugins/monitoring/directives', []); const uiModule = uiModules.get('plugins/monitoring/directives', []);
uiModule.directive('monitoringChart', (timefilter) => { uiModule.directive('monitoringChart', () => {
return { return {
restrict: 'E', restrict: 'E',
scope: { scope: {
@ -31,10 +32,10 @@ uiModule.directive('monitoringChart', (timefilter) => {
const units = getUnits(series); const units = getUnits(series);
function onBrush({ xaxis }) { function onBrush({ xaxis }) {
scope.$evalAsync(() => { timefilter.setTime({
timefilter.time.from = moment(xaxis.from); from: moment(xaxis.from),
timefilter.time.to = moment(xaxis.to); to: moment(xaxis.to),
timefilter.time.mode = 'absolute'; mode: 'absolute'
}); });
} }

View file

@ -23,6 +23,7 @@ import { MonitoringTable } from 'plugins/monitoring/components/table';
import { Sparkline } from 'plugins/monitoring/components/sparkline'; import { Sparkline } from 'plugins/monitoring/components/sparkline';
import { SORT_ASCENDING } from '../../../../common/constants'; import { SORT_ASCENDING } from '../../../../common/constants';
import { formatMetric } from '../../../lib/format_number'; import { formatMetric } from '../../../lib/format_number';
import { timefilter } from 'ui/timefilter';
const filterFields = [ 'id' ]; const filterFields = [ 'id' ];
const columns = [ const columns = [
@ -105,7 +106,6 @@ const pipelineRowFactory = (onPipelineClick, onBrush, tooltipXValueFormatter, to
const uiModule = uiModules.get('monitoring/directives', []); const uiModule = uiModules.get('monitoring/directives', []);
uiModule.directive('monitoringLogstashPipelineListing', ($injector) => { uiModule.directive('monitoringLogstashPipelineListing', ($injector) => {
const kbnUrl = $injector.get('kbnUrl'); const kbnUrl = $injector.get('kbnUrl');
const timefilter = $injector.get('timefilter');
const config = $injector.get('config'); const config = $injector.get('config');
const dateFormat = config.get('dateFormat'); const dateFormat = config.get('dateFormat');
@ -124,10 +124,10 @@ uiModule.directive('monitoringLogstashPipelineListing', ($injector) => {
link: function (scope, $el) { link: function (scope, $el) {
function onBrush(xaxis) { function onBrush(xaxis) {
scope.$evalAsync(() => { timefilter.setTime({
timefilter.time.from = moment(xaxis.from); from: moment(xaxis.from),
timefilter.time.to = moment(xaxis.to); to: moment(xaxis.to),
timefilter.time.mode = 'absolute'; mode: 'absolute'
}); });
} }

View file

@ -10,10 +10,10 @@ import { uiModules } from 'ui/modules';
import { Sparkline } from 'plugins/monitoring/components/sparkline'; import { Sparkline } from 'plugins/monitoring/components/sparkline';
import moment from 'moment'; import moment from 'moment';
import { formatMetric } from '../../lib/format_number'; import { formatMetric } from '../../lib/format_number';
import { timefilter } from 'ui/timefilter';
const uiModule = uiModules.get('plugins/monitoring/directives', []); const uiModule = uiModules.get('plugins/monitoring/directives', []);
uiModule.directive('sparkline', ($injector) => { uiModule.directive('sparkline', ($injector) => {
const timefilter = $injector.get('timefilter');
const config = $injector.get('config'); const config = $injector.get('config');
const dateFormat = config.get('dateFormat'); const dateFormat = config.get('dateFormat');
@ -27,10 +27,10 @@ uiModule.directive('sparkline', ($injector) => {
link(scope, $elem) { link(scope, $elem) {
function onBrush(xaxis) { function onBrush(xaxis) {
scope.$evalAsync(() => { timefilter.setTime({
timefilter.time.from = moment(xaxis.from); from: moment(xaxis.from),
timefilter.time.to = moment(xaxis.to); to: moment(xaxis.to),
timefilter.time.mode = 'absolute'; mode: 'absolute'
}); });
} }

View file

@ -5,11 +5,11 @@
*/ */
import { ajaxErrorHandlersProvider } from './ajax_error_handler'; import { ajaxErrorHandlersProvider } from './ajax_error_handler';
import { timefilter } from 'ui/timefilter';
export function getPageData($injector, api) { export function getPageData($injector, api) {
const $http = $injector.get('$http'); const $http = $injector.get('$http');
const globalState = $injector.get('globalState'); const globalState = $injector.get('globalState');
const timefilter = $injector.get('timefilter');
const timeBounds = timefilter.getBounds(); const timeBounds = timefilter.getBounds();
return $http return $http

View file

@ -4,104 +4,111 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
import ngMock from 'ng_mock';
import expect from 'expect.js'; import expect from 'expect.js';
import sinon from 'sinon'; import sinon from 'sinon';
import { executorProvider } from '../executor_provider'; import { executorProvider } from '../executor_provider';
import EventEmitter from 'events';
import Promise from 'bluebird'; import Promise from 'bluebird';
import { timefilter } from 'ui/timefilter';
describe('$executor service', () => { describe('$executor service', () => {
let scope;
let executor; let executor;
let timefilter;
let $timeout; let $timeout;
let onSpy;
let offSpy; beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject(function (_$rootScope_) {
scope = _$rootScope_.$new();
}));
beforeEach(() => { beforeEach(() => {
$timeout = sinon.spy(setTimeout); $timeout = sinon.spy(setTimeout);
$timeout.cancel = (id) => clearTimeout(id); $timeout.cancel = (id) => clearTimeout(id);
timefilter = new EventEmitter(); timefilter.setRefreshInterval({
onSpy = sinon.spy((...args) => timefilter.addListener(...args));
offSpy = sinon.spy((...args) => timefilter.removeListener(...args));
timefilter.on = onSpy;
timefilter.off = offSpy;
timefilter.refreshInterval = {
pause: false, pause: false,
value: 0 value: 0
}; });
executor = executorProvider(Promise, $timeout, timefilter);
executor = executorProvider(Promise, $timeout);
}); });
afterEach(() => executor.destroy()); afterEach(() => executor.destroy());
it('should register listener for fetch upon start', () => { it('should register listener for fetch upon start', () => {
executor.start(); executor.start(scope);
expect(onSpy.calledTwice).to.equal(true); const listeners = timefilter.listeners('fetch');
expect(onSpy.firstCall.args[0]).to.equal('fetch'); const handlerFunc = listeners.find(listener => {
expect(onSpy.firstCall.args[1].name).to.equal('reFetch'); return listener.name === 'reFetch';
});
expect(handlerFunc).to.not.be.null;
}); });
it('should register listener for update upon start', () => { it('should register listener for refreshIntervalUpdate upon start', () => {
executor.start(); executor.start(scope);
expect(onSpy.calledTwice).to.equal(true); const listeners = timefilter.listeners('refreshIntervalUpdate');
expect(onSpy.secondCall.args[0]).to.equal('update'); const handlerFunc = listeners.find(listener => {
expect(onSpy.secondCall.args[1].name).to.equal('killIfPaused'); return listener.name === 'killIfPaused';
});
expect(handlerFunc).to.not.be.null;
}); });
it('should not call $timeout if the timefilter is not paused and set to zero', () => { it('should not call $timeout if the timefilter is not paused and set to zero', () => {
executor.start(); executor.start(scope);
expect($timeout.callCount).to.equal(0); expect($timeout.callCount).to.equal(0);
}); });
it('should call $timeout if the timefilter is not paused and set to 1000ms', () => { it('should call $timeout if the timefilter is not paused and set to 1000ms', () => {
timefilter.refreshInterval.value = 1000; timefilter.setRefreshInterval({
executor.start(); value: 1000
});
executor.start(scope);
expect($timeout.callCount).to.equal(1); expect($timeout.callCount).to.equal(1);
}); });
it('should execute function if ingorePause is passed (interval set to 1000ms)', (done) => {
timefilter.refreshInterval.value = 1000;
executor.register({ execute: () => Promise.resolve().then(() => done(), done) });
executor.start({ ignorePaused: true });
});
it('should execute function if timefilter is not paused and interval set to 1000ms', (done) => { it('should execute function if timefilter is not paused and interval set to 1000ms', (done) => {
timefilter.refreshInterval.value = 1000; timefilter.setRefreshInterval({
value: 1000
});
executor.register({ execute: () => Promise.resolve().then(() => done(), done) }); executor.register({ execute: () => Promise.resolve().then(() => done(), done) });
executor.start(); executor.start(scope);
}); });
it('should execute function multiple times', (done) => { it('should execute function multiple times', (done) => {
let calls = 0; let calls = 0;
timefilter.refreshInterval.value = 10; timefilter.setRefreshInterval({
value: 10
});
executor.register({ execute: () => { executor.register({ execute: () => {
if (calls++ > 1) { done(); } if (calls++ > 1) { done(); }
return Promise.resolve(); return Promise.resolve();
} }); } });
executor.start(); executor.start(scope);
}); });
it('should call handleResponse', (done) => { it('should call handleResponse', (done) => {
timefilter.refreshInterval.value = 10; timefilter.setRefreshInterval({
value: 10
});
executor.register({ executor.register({
execute: () => Promise.resolve(), execute: () => Promise.resolve(),
handleResponse: () => done() handleResponse: () => done()
}); });
executor.start(); executor.start(scope);
}); });
it('should call handleError', (done) => { it('should call handleError', (done) => {
timefilter.refreshInterval.value = 10; timefilter.setRefreshInterval({
value: 10
});
executor.register({ executor.register({
execute: () => Promise.reject(new Error('reject test')), execute: () => Promise.reject(new Error('reject test')),
handleError: () => done() handleError: () => done()
}); });
executor.start(); executor.start(scope);
}); });
}); });

View file

@ -6,11 +6,11 @@
import { uiModules } from 'ui/modules'; import { uiModules } from 'ui/modules';
import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler';
import { timefilter } from 'ui/timefilter';
const uiModule = uiModules.get('monitoring/clusters'); const uiModule = uiModules.get('monitoring/clusters');
uiModule.service('monitoringClusters', ($injector) => { uiModule.service('monitoringClusters', ($injector) => {
return (clusterUuid, ccs) => { return (clusterUuid, ccs) => {
const timefilter = $injector.get('timefilter');
const { min, max } = timefilter.getBounds(); const { min, max } = timefilter.getBounds();
// append clusterUuid if the parameter is given // append clusterUuid if the parameter is given

View file

@ -4,8 +4,8 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
import { defaults } from 'lodash'; import { timefilter } from 'ui/timefilter';
export function executorProvider(Promise, $timeout, timefilter) { export function executorProvider(Promise, $timeout) {
const queue = []; const queue = [];
let executionTimer; let executionTimer;
@ -30,8 +30,6 @@ export function executorProvider(Promise, $timeout, timefilter) {
*/ */
function cancel() { function cancel() {
killTimer(); killTimer();
timefilter.off('update', killIfPaused);
timefilter.off('fetch', reFetch);
} }
/** /**
@ -73,7 +71,7 @@ export function executorProvider(Promise, $timeout, timefilter) {
} }
function killIfPaused() { function killIfPaused() {
if (timefilter.refreshInterval.pause) { if (timefilter.getRefreshInterval().pause) {
killTimer(); killTimer();
} }
} }
@ -83,10 +81,8 @@ export function executorProvider(Promise, $timeout, timefilter) {
* @returns {void} * @returns {void}
*/ */
function start() { function start() {
timefilter.on('fetch', reFetch); if ((ignorePaused || timefilter.getRefreshInterval().pause === false) && timefilter.getRefreshInterval().value > 0) {
timefilter.on('update', killIfPaused); executionTimer = $timeout(run, timefilter.getRefreshInterval().value);
if ((ignorePaused || timefilter.refreshInterval.pause === false) && timefilter.refreshInterval.value > 0) {
executionTimer = $timeout(run, timefilter.refreshInterval.value);
} }
} }
@ -95,17 +91,9 @@ export function executorProvider(Promise, $timeout, timefilter) {
*/ */
return { return {
register, register,
start(options = {}) { start($scope) {
options = defaults(options, { $scope.$listenAndDigestAsync(timefilter, 'fetch', reFetch);
ignorePaused: false, $scope.$listenAndDigestAsync(timefilter, 'refreshIntervalUpdate', killIfPaused);
now: false
});
if (options.now) {
return run();
}
if (options.ignorePaused) {
ignorePaused = options.ignorePaused;
}
start(); start();
}, },
run, run,

View file

@ -7,6 +7,7 @@
import { spy, stub } from 'sinon'; import { spy, stub } from 'sinon';
import expect from 'expect.js'; import expect from 'expect.js';
import { MonitoringViewBaseController } from '../'; import { MonitoringViewBaseController } from '../';
import { timefilter } from 'ui/timefilter';
/* /*
* Mostly copied from base_table_controller test, with modifications * Mostly copied from base_table_controller test, with modifications
@ -17,28 +18,10 @@ describe('MonitoringViewBaseController', function () {
let $injector; let $injector;
let $scope; let $scope;
let opts; let opts;
let timefilter;
let titleService; let titleService;
let executorService; let executorService;
let isTimeRangeSelectorEnabled;
let isAutoRefreshSelectorEnabled;
before(() => { before(() => {
timefilter = {
enableTimeRangeSelector: () => {
isTimeRangeSelectorEnabled = true;
},
enableAutoRefreshSelector: () => {
isAutoRefreshSelectorEnabled = true;
},
disableTimeRangeSelector: () => {
isTimeRangeSelectorEnabled = false;
},
disableAutoRefreshSelector: () => {
isAutoRefreshSelectorEnabled = false;
},
};
titleService = spy(); titleService = spy();
executorService = { executorService = {
register: spy(), register: spy(),
@ -47,7 +30,6 @@ describe('MonitoringViewBaseController', function () {
const injectorGetStub = stub(); const injectorGetStub = stub();
injectorGetStub.withArgs('title').returns(titleService); injectorGetStub.withArgs('title').returns(titleService);
injectorGetStub.withArgs('timefilter').returns(timefilter);
injectorGetStub.withArgs('$executor').returns(executorService); injectorGetStub.withArgs('$executor').returns(executorService);
injectorGetStub.withArgs('localStorage').throws('localStorage should not be used by this class'); injectorGetStub.withArgs('localStorage').throws('localStorage should not be used by this class');
$injector = { get: injectorGetStub }; $injector = { get: injectorGetStub };
@ -89,8 +71,8 @@ describe('MonitoringViewBaseController', function () {
describe('time filter', () => { describe('time filter', () => {
it('enables timepicker and auto refresh #1', () => { it('enables timepicker and auto refresh #1', () => {
expect(isTimeRangeSelectorEnabled).to.be(true); expect(timefilter.isTimeRangeSelectorEnabled).to.be(true);
expect(isAutoRefreshSelectorEnabled).to.be(true); expect(timefilter.isAutoRefreshSelectorEnabled).to.be(true);
}); });
it('enables timepicker and auto refresh #2', () => { it('enables timepicker and auto refresh #2', () => {
@ -100,8 +82,8 @@ describe('MonitoringViewBaseController', function () {
}; };
ctrl = new MonitoringViewBaseController(opts); ctrl = new MonitoringViewBaseController(opts);
expect(isTimeRangeSelectorEnabled).to.be(true); expect(timefilter.isTimeRangeSelectorEnabled).to.be(true);
expect(isAutoRefreshSelectorEnabled).to.be(true); expect(timefilter.isAutoRefreshSelectorEnabled).to.be(true);
}); });
it('disables timepicker and enables auto refresh', () => { it('disables timepicker and enables auto refresh', () => {
@ -111,8 +93,8 @@ describe('MonitoringViewBaseController', function () {
}; };
ctrl = new MonitoringViewBaseController(opts); ctrl = new MonitoringViewBaseController(opts);
expect(isTimeRangeSelectorEnabled).to.be(false); expect(timefilter.isTimeRangeSelectorEnabled).to.be(false);
expect(isAutoRefreshSelectorEnabled).to.be(true); expect(timefilter.isAutoRefreshSelectorEnabled).to.be(true);
}); });
it('enables timepicker and disables auto refresh', () => { it('enables timepicker and disables auto refresh', () => {
@ -122,8 +104,8 @@ describe('MonitoringViewBaseController', function () {
}; };
ctrl = new MonitoringViewBaseController(opts); ctrl = new MonitoringViewBaseController(opts);
expect(isTimeRangeSelectorEnabled).to.be(true); expect(timefilter.isTimeRangeSelectorEnabled).to.be(true);
expect(isAutoRefreshSelectorEnabled).to.be(false); expect(timefilter.isAutoRefreshSelectorEnabled).to.be(false);
}); });
it('disables timepicker and auto refresh', () => { it('disables timepicker and auto refresh', () => {
@ -136,8 +118,8 @@ describe('MonitoringViewBaseController', function () {
}; };
ctrl = new MonitoringViewBaseController(opts); ctrl = new MonitoringViewBaseController(opts);
expect(isTimeRangeSelectorEnabled).to.be(false); expect(timefilter.isTimeRangeSelectorEnabled).to.be(false);
expect(isAutoRefreshSelectorEnabled).to.be(false); expect(timefilter.isAutoRefreshSelectorEnabled).to.be(false);
}); });
}); });

View file

@ -10,10 +10,10 @@ import template from './index.html';
import { MonitoringViewBaseController } from 'plugins/monitoring/views'; import { MonitoringViewBaseController } from 'plugins/monitoring/views';
import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; import { routeInitProvider } from 'plugins/monitoring/lib/route_init';
import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler';
import { timefilter } from 'ui/timefilter';
function getPageData($injector) { function getPageData($injector) {
const globalState = $injector.get('globalState'); const globalState = $injector.get('globalState');
const timefilter = $injector.get('timefilter');
const $http = $injector.get('$http'); const $http = $injector.get('$http');
const Private = $injector.get('Private'); const Private = $injector.get('Private');
const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/alerts`; const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/alerts`;

View file

@ -9,6 +9,7 @@ import moment from 'moment';
import { render, unmountComponentAtNode } from 'react-dom'; import { render, unmountComponentAtNode } from 'react-dom';
import { getPageData } from '../lib/get_page_data'; import { getPageData } from '../lib/get_page_data';
import { PageLoading } from 'plugins/monitoring/components'; import { PageLoading } from 'plugins/monitoring/components';
import { timefilter } from 'ui/timefilter';
/** /**
* Class to manage common instantiation behaviors in a view controller * Class to manage common instantiation behaviors in a view controller
@ -69,7 +70,6 @@ export class MonitoringViewBaseController {
options = {} options = {}
}) { }) {
const titleService = $injector.get('title'); const titleService = $injector.get('title');
const timefilter = $injector.get('timefilter');
const $executor = $injector.get('$executor'); const $executor = $injector.get('$executor');
titleService($scope.cluster, title); titleService($scope.cluster, title);
@ -108,7 +108,7 @@ export class MonitoringViewBaseController {
$executor.register({ $executor.register({
execute: () => this.updateData() execute: () => this.updateData()
}); });
$executor.start(); $executor.start($scope);
$scope.$on('$destroy', () => { $scope.$on('$destroy', () => {
if (this.reactNodeId) { // WIP https://github.com/elastic/x-pack-kibana/issues/5198 if (this.reactNodeId) { // WIP https://github.com/elastic/x-pack-kibana/issues/5198
unmountComponentAtNode(document.getElementById(this.reactNodeId)); unmountComponentAtNode(document.getElementById(this.reactNodeId));
@ -119,10 +119,10 @@ export class MonitoringViewBaseController {
// needed for chart pages // needed for chart pages
this.onBrush = ({ xaxis }) => { this.onBrush = ({ xaxis }) => {
const { to, from } = xaxis; const { to, from } = xaxis;
$scope.$evalAsync(() => { timefilter.setTime({
timefilter.time.from = moment(from); from: moment(from),
timefilter.time.to = moment(to); to: moment(to),
timefilter.time.mode = 'absolute'; mode: 'absolute'
}); });
}; };
} }

View file

@ -5,13 +5,13 @@
*/ */
import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler';
import { timefilter } from 'ui/timefilter';
export function getPageData($injector) { export function getPageData($injector) {
const $http = $injector.get('$http'); const $http = $injector.get('$http');
const $route = $injector.get('$route'); const $route = $injector.get('$route');
const globalState = $injector.get('globalState'); const globalState = $injector.get('globalState');
const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/beats/beat/${$route.current.params.beatUuid}`; const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/beats/beat/${$route.current.params.beatUuid}`;
const timefilter = $injector.get('timefilter');
const timeBounds = timefilter.getBounds(); const timeBounds = timefilter.getBounds();
return $http.post(url, { return $http.post(url, {

View file

@ -5,11 +5,11 @@
*/ */
import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler';
import { timefilter } from 'ui/timefilter';
export function getPageData($injector) { export function getPageData($injector) {
const $http = $injector.get('$http'); const $http = $injector.get('$http');
const globalState = $injector.get('globalState'); const globalState = $injector.get('globalState');
const timefilter = $injector.get('timefilter');
const timeBounds = timefilter.getBounds(); const timeBounds = timefilter.getBounds();
const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/beats/beats`; const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/beats/beats`;

View file

@ -5,11 +5,11 @@
*/ */
import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler';
import { timefilter } from 'ui/timefilter';
export function getPageData($injector) { export function getPageData($injector) {
const $http = $injector.get('$http'); const $http = $injector.get('$http');
const globalState = $injector.get('globalState'); const globalState = $injector.get('globalState');
const timefilter = $injector.get('timefilter');
const timeBounds = timefilter.getBounds(); const timeBounds = timefilter.getBounds();
const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/beats`; const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/beats`;

View file

@ -7,6 +7,7 @@
import uiRoutes from 'ui/routes'; import uiRoutes from 'ui/routes';
import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; import { routeInitProvider } from 'plugins/monitoring/lib/route_init';
import template from './index.html'; import template from './index.html';
import { timefilter } from 'ui/timefilter';
uiRoutes.when('/overview', { uiRoutes.when('/overview', {
template, template,
@ -21,7 +22,6 @@ uiRoutes.when('/overview', {
} }
}, },
controller($injector, $scope) { controller($injector, $scope) {
const timefilter = $injector.get('timefilter');
timefilter.enableTimeRangeSelector(); timefilter.enableTimeRangeSelector();
timefilter.enableAutoRefreshSelector(); timefilter.enableAutoRefreshSelector();
@ -41,7 +41,7 @@ uiRoutes.when('/overview', {
} }
}); });
$executor.start(); $executor.start($scope);
$scope.$on('$destroy', $executor.destroy); $scope.$on('$destroy', $executor.destroy);
} }

Some files were not shown because too many files have changed in this diff Show more