mirror of
https://github.com/grafana/grafana.git
synced 2025-02-13 17:15:40 -06:00
fix(browser history): fixes and enhancements to browser history, it now works properly again AND it can restore previous time ranges in dashboards, closes #7259
This commit is contained in:
parent
60a2041065
commit
49fe74228b
@ -5,6 +5,7 @@
|
||||
* **Templating**: Make $__interval and $__interval_ms global built in variables that can be used in by any datasource (in panel queries), closes [#7190](https://github.com/grafana/grafana/issues/7190), closes [#6582](https://github.com/grafana/grafana/issues/6582)
|
||||
* **S3 Image Store**: External s3 image store (used in alert notifications) now support AWS IAM Roles, closes [#6985](https://github.com/grafana/grafana/issues/6985), [#7058](https://github.com/grafana/grafana/issues/7058) thx [@mtanda](https://github.com/mtanda)
|
||||
* **Optimzation**: Never issue refresh event when Grafana tab is not visible [#7218](https://github.com/grafana/grafana/issues/7218), thx [@mtanda](https://github.com/mtanda)
|
||||
* **Browser History**: Browser back/forward now works time ranges / zoom, [#7259](https://github.com/grafana/grafana/issues/7259)
|
||||
|
||||
# 4.1.1 (2017-01-11)
|
||||
|
||||
|
@ -22,7 +22,7 @@ function (angular, _, coreModule) {
|
||||
$timeout.cancel(promise);
|
||||
};
|
||||
|
||||
this.cancel_all = function() {
|
||||
this.cancelAll = function() {
|
||||
_.each(timers, function(t) {
|
||||
$timeout.cancel(t);
|
||||
});
|
||||
|
@ -9,7 +9,7 @@ define([
|
||||
'./shareSnapshotCtrl',
|
||||
'./dashboard_srv',
|
||||
'./viewStateSrv',
|
||||
'./timeSrv',
|
||||
'./time_srv',
|
||||
'./unsavedChangesSrv',
|
||||
'./timepicker/timepicker',
|
||||
'./graphiteImportCtrl',
|
||||
|
110
public/app/features/dashboard/specs/time_srv_specs.ts
Normal file
110
public/app/features/dashboard/specs/time_srv_specs.ts
Normal file
@ -0,0 +1,110 @@
|
||||
import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common';
|
||||
|
||||
import helpers from 'test/specs/helpers';
|
||||
import _ from 'lodash';
|
||||
import TimeSrv from '../time_srv';
|
||||
import moment from 'moment';
|
||||
|
||||
describe('timeSrv', function() {
|
||||
var ctx = new helpers.ServiceTestContext();
|
||||
var _dashboard: any = {
|
||||
time: {from: 'now-6h', to: 'now'},
|
||||
};
|
||||
|
||||
beforeEach(angularMocks.module('grafana.core'));
|
||||
beforeEach(angularMocks.module('grafana.services'));
|
||||
beforeEach(ctx.createService('timeSrv'));
|
||||
|
||||
beforeEach(function() {
|
||||
ctx.service.init(_dashboard);
|
||||
});
|
||||
|
||||
describe('timeRange', function() {
|
||||
it('should return unparsed when parse is false', function() {
|
||||
ctx.service.setTime({from: 'now', to: 'now-1h' });
|
||||
var time = ctx.service.timeRange();
|
||||
expect(time.raw.from).to.be('now');
|
||||
expect(time.raw.to).to.be('now-1h');
|
||||
});
|
||||
|
||||
it('should return parsed when parse is true', function() {
|
||||
ctx.service.setTime({from: 'now', to: 'now-1h' });
|
||||
var time = ctx.service.timeRange();
|
||||
expect(moment.isMoment(time.from)).to.be(true);
|
||||
expect(moment.isMoment(time.to)).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('init time from url', function() {
|
||||
it('should handle relative times', function() {
|
||||
ctx.$location.search({from: 'now-2d', to: 'now'});
|
||||
ctx.service.init(_dashboard);
|
||||
var time = ctx.service.timeRange();
|
||||
expect(time.raw.from).to.be('now-2d');
|
||||
expect(time.raw.to).to.be('now');
|
||||
});
|
||||
|
||||
it('should handle formated dates', function() {
|
||||
ctx.$location.search({from: '20140410T052010', to: '20140520T031022'});
|
||||
ctx.service.init(_dashboard);
|
||||
var time = ctx.service.timeRange(true);
|
||||
expect(time.from.valueOf()).to.equal(new Date("2014-04-10T05:20:10Z").getTime());
|
||||
expect(time.to.valueOf()).to.equal(new Date("2014-05-20T03:10:22Z").getTime());
|
||||
});
|
||||
|
||||
it('should handle formated dates without time', function() {
|
||||
ctx.$location.search({from: '20140410', to: '20140520'});
|
||||
ctx.service.init(_dashboard);
|
||||
var time = ctx.service.timeRange(true);
|
||||
expect(time.from.valueOf()).to.equal(new Date("2014-04-10T00:00:00Z").getTime());
|
||||
expect(time.to.valueOf()).to.equal(new Date("2014-05-20T00:00:00Z").getTime());
|
||||
});
|
||||
|
||||
it('should handle epochs', function() {
|
||||
ctx.$location.search({from: '1410337646373', to: '1410337665699'});
|
||||
ctx.service.init(_dashboard);
|
||||
var time = ctx.service.timeRange(true);
|
||||
expect(time.from.valueOf()).to.equal(1410337646373);
|
||||
expect(time.to.valueOf()).to.equal(1410337665699);
|
||||
});
|
||||
|
||||
it('should handle bad dates', function() {
|
||||
ctx.$location.search({from: '20151126T00010%3C%2Fp%3E%3Cspan%20class', to: 'now'});
|
||||
_dashboard.time.from = 'now-6h';
|
||||
ctx.service.init(_dashboard);
|
||||
expect(ctx.service.time.from).to.equal('now-6h');
|
||||
expect(ctx.service.time.to).to.equal('now');
|
||||
});
|
||||
});
|
||||
|
||||
describe('setTime', function() {
|
||||
it('should return disable refresh if refresh is disabled for any range', function() {
|
||||
_dashboard.refresh = false;
|
||||
|
||||
ctx.service.setTime({from: '2011-01-01', to: '2015-01-01' });
|
||||
expect(_dashboard.refresh).to.be(false);
|
||||
});
|
||||
|
||||
it('should restore refresh for absolute time range', function() {
|
||||
_dashboard.refresh = '30s';
|
||||
|
||||
ctx.service.setTime({from: '2011-01-01', to: '2015-01-01' });
|
||||
expect(_dashboard.refresh).to.be('30s');
|
||||
});
|
||||
|
||||
it('should restore refresh after relative time range is set', function() {
|
||||
_dashboard.refresh = '10s';
|
||||
ctx.service.setTime({from: moment([2011,1,1]), to: moment([2015,1,1])});
|
||||
expect(_dashboard.refresh).to.be(false);
|
||||
ctx.service.setTime({from: '2011-01-01', to: 'now' });
|
||||
expect(_dashboard.refresh).to.be('10s');
|
||||
});
|
||||
|
||||
it('should keep refresh after relative time range is changed and now delay exists', function() {
|
||||
_dashboard.refresh = '10s';
|
||||
ctx.service.setTime({from: 'now-1h', to: 'now-10s' });
|
||||
expect(_dashboard.refresh).to.be('10s');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
@ -1,170 +0,0 @@
|
||||
define([
|
||||
'angular',
|
||||
'lodash',
|
||||
'moment',
|
||||
'app/core/config',
|
||||
'app/core/utils/kbn',
|
||||
'app/core/utils/datemath'
|
||||
], function (angular, _, moment, config, kbn, dateMath) {
|
||||
'use strict';
|
||||
|
||||
var module = angular.module('grafana.services');
|
||||
|
||||
module.service('timeSrv', function($rootScope, $timeout, $routeParams, timer, contextSrv) {
|
||||
var self = this;
|
||||
|
||||
// default time
|
||||
this.time = {from: '6h', to: 'now'};
|
||||
|
||||
$rootScope.$on('zoom-out', function(e, factor) { self.zoomOut(factor); });
|
||||
|
||||
this.init = function(dashboard) {
|
||||
timer.cancel_all();
|
||||
|
||||
this.dashboard = dashboard;
|
||||
this.time = dashboard.time;
|
||||
this.refresh = dashboard.refresh;
|
||||
|
||||
this._initTimeFromUrl();
|
||||
this._parseTime();
|
||||
|
||||
if(this.refresh) {
|
||||
this.setAutoRefresh(this.refresh);
|
||||
}
|
||||
};
|
||||
|
||||
this._parseTime = function() {
|
||||
// when absolute time is saved in json it is turned to a string
|
||||
if (_.isString(this.time.from) && this.time.from.indexOf('Z') >= 0) {
|
||||
this.time.from = moment(this.time.from).utc();
|
||||
}
|
||||
if (_.isString(this.time.to) && this.time.to.indexOf('Z') >= 0) {
|
||||
this.time.to = moment(this.time.to).utc();
|
||||
}
|
||||
};
|
||||
|
||||
this._parseUrlParam = function(value) {
|
||||
if (value.indexOf('now') !== -1) {
|
||||
return value;
|
||||
}
|
||||
if (value.length === 8) {
|
||||
return moment.utc(value, 'YYYYMMDD');
|
||||
}
|
||||
if (value.length === 15) {
|
||||
return moment.utc(value, 'YYYYMMDDTHHmmss');
|
||||
}
|
||||
|
||||
if (!isNaN(value)) {
|
||||
var epoch = parseInt(value);
|
||||
return moment.utc(epoch);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
this._initTimeFromUrl = function() {
|
||||
if ($routeParams.from) {
|
||||
this.time.from = this._parseUrlParam($routeParams.from) || this.time.from;
|
||||
}
|
||||
if ($routeParams.to) {
|
||||
this.time.to = this._parseUrlParam($routeParams.to) || this.time.to;
|
||||
}
|
||||
if ($routeParams.refresh) {
|
||||
this.refresh = $routeParams.refresh || this.refresh;
|
||||
}
|
||||
};
|
||||
|
||||
this.setAutoRefresh = function (interval) {
|
||||
this.dashboard.refresh = interval;
|
||||
if (interval) {
|
||||
var interval_ms = kbn.interval_to_ms(interval);
|
||||
$timeout(function () {
|
||||
self.start_scheduled_refresh(interval_ms);
|
||||
self.refreshDashboard();
|
||||
}, interval_ms);
|
||||
} else {
|
||||
this.cancel_scheduled_refresh();
|
||||
}
|
||||
};
|
||||
|
||||
this.refreshDashboard = function() {
|
||||
$rootScope.$broadcast('refresh');
|
||||
};
|
||||
|
||||
this.start_scheduled_refresh = function (after_ms) {
|
||||
self.cancel_scheduled_refresh();
|
||||
self.refresh_timer = timer.register($timeout(function () {
|
||||
self.start_scheduled_refresh(after_ms);
|
||||
if (contextSrv.isGrafanaVisible()) {
|
||||
self.refreshDashboard();
|
||||
}
|
||||
}, after_ms));
|
||||
};
|
||||
|
||||
this.cancel_scheduled_refresh = function () {
|
||||
timer.cancel(this.refresh_timer);
|
||||
};
|
||||
|
||||
this.setTime = function(time, enableRefresh) {
|
||||
_.extend(this.time, time);
|
||||
|
||||
// disable refresh if zoom in or zoom out
|
||||
if (!enableRefresh && moment.isMoment(time.to)) {
|
||||
this.old_refresh = this.dashboard.refresh || this.old_refresh;
|
||||
this.setAutoRefresh(false);
|
||||
}
|
||||
else if (this.old_refresh && this.old_refresh !== this.dashboard.refresh) {
|
||||
this.setAutoRefresh(this.old_refresh);
|
||||
this.old_refresh = null;
|
||||
}
|
||||
|
||||
$rootScope.appEvent('time-range-changed', this.time);
|
||||
$timeout(this.refreshDashboard, 0);
|
||||
};
|
||||
|
||||
this.timeRangeForUrl = function() {
|
||||
var range = this.timeRange().raw;
|
||||
|
||||
if (moment.isMoment(range.from)) { range.from = range.from.valueOf(); }
|
||||
if (moment.isMoment(range.to)) { range.to = range.to.valueOf(); }
|
||||
|
||||
return range;
|
||||
};
|
||||
|
||||
this.timeRange = function() {
|
||||
// make copies if they are moment (do not want to return out internal moment, because they are mutable!)
|
||||
var range = {
|
||||
from: moment.isMoment(this.time.from) ? moment(this.time.from) : this.time.from,
|
||||
to: moment.isMoment(this.time.to) ? moment(this.time.to) : this.time.to,
|
||||
};
|
||||
|
||||
range = {
|
||||
from: dateMath.parse(range.from, false),
|
||||
to: dateMath.parse(range.to, true),
|
||||
raw: range
|
||||
};
|
||||
|
||||
return range;
|
||||
};
|
||||
|
||||
this.zoomOut = function(factor) {
|
||||
var range = this.timeRange();
|
||||
|
||||
var timespan = (range.to.valueOf() - range.from.valueOf());
|
||||
var center = range.to.valueOf() - timespan/2;
|
||||
|
||||
var to = (center + (timespan*factor)/2);
|
||||
var from = (center - (timespan*factor)/2);
|
||||
|
||||
if (to > Date.now() && range.to <= Date.now()) {
|
||||
var offset = to - Date.now();
|
||||
from = from - offset;
|
||||
to = Date.now();
|
||||
}
|
||||
|
||||
this.setTime({from: moment.utc(from), to: moment.utc(to) });
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
});
|
204
public/app/features/dashboard/time_srv.ts
Normal file
204
public/app/features/dashboard/time_srv.ts
Normal file
@ -0,0 +1,204 @@
|
||||
///<reference path="../../headers/common.d.ts" />
|
||||
|
||||
import config from 'app/core/config';
|
||||
import angular from 'angular';
|
||||
import moment from 'moment';
|
||||
import _ from 'lodash';
|
||||
import coreModule from 'app/core/core_module';
|
||||
import kbn from 'app/core/utils/kbn';
|
||||
import * as dateMath from 'app/core/utils/datemath';
|
||||
|
||||
class TimeSrv {
|
||||
time: any;
|
||||
refreshTimer: any;
|
||||
refresh: boolean;
|
||||
oldRefresh: boolean;
|
||||
dashboard: any;
|
||||
timeAtLoad: any;
|
||||
|
||||
/** @ngInject **/
|
||||
constructor(private $rootScope, private $timeout, private $location, private timer, private contextSrv) {
|
||||
// default time
|
||||
this.time = {from: '6h', to: 'now'};
|
||||
|
||||
$rootScope.$on('zoom-out', this.zoomOut.bind(this));
|
||||
$rootScope.$on('$routeUpdate', this.routeUpdated.bind(this));
|
||||
}
|
||||
|
||||
init(dashboard) {
|
||||
this.timer.cancelAll();
|
||||
|
||||
this.dashboard = dashboard;
|
||||
this.time = dashboard.time;
|
||||
this.refresh = dashboard.refresh;
|
||||
|
||||
this.initTimeFromUrl();
|
||||
this.parseTime();
|
||||
|
||||
// remember time at load so we can go back to it
|
||||
this.timeAtLoad = _.cloneDeep(this.time);
|
||||
|
||||
if (this.refresh) {
|
||||
this.setAutoRefresh(this.refresh);
|
||||
}
|
||||
}
|
||||
|
||||
private parseTime() {
|
||||
// when absolute time is saved in json it is turned to a string
|
||||
if (_.isString(this.time.from) && this.time.from.indexOf('Z') >= 0) {
|
||||
this.time.from = moment(this.time.from).utc();
|
||||
}
|
||||
if (_.isString(this.time.to) && this.time.to.indexOf('Z') >= 0) {
|
||||
this.time.to = moment(this.time.to).utc();
|
||||
}
|
||||
};
|
||||
|
||||
private parseUrlParam(value) {
|
||||
if (value.indexOf('now') !== -1) {
|
||||
return value;
|
||||
}
|
||||
if (value.length === 8) {
|
||||
return moment.utc(value, 'YYYYMMDD');
|
||||
}
|
||||
if (value.length === 15) {
|
||||
return moment.utc(value, 'YYYYMMDDTHHmmss');
|
||||
}
|
||||
|
||||
if (!isNaN(value)) {
|
||||
var epoch = parseInt(value);
|
||||
return moment.utc(epoch);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private initTimeFromUrl() {
|
||||
var params = this.$location.search();
|
||||
if (params.from) {
|
||||
this.time.from = this.parseUrlParam(params.from) || this.time.from;
|
||||
}
|
||||
if (params.to) {
|
||||
this.time.to = this.parseUrlParam(params.to) || this.time.to;
|
||||
}
|
||||
if (params.refresh) {
|
||||
this.refresh = params.refresh || this.refresh;
|
||||
}
|
||||
};
|
||||
|
||||
private routeUpdated() {
|
||||
var params = this.$location.search();
|
||||
var urlRange = this.timeRangeForUrl();
|
||||
// check if url has time range
|
||||
if (params.from && params.to) {
|
||||
// is it different from what our current time range?
|
||||
if (params.from !== urlRange.from || params.to !== urlRange.to) {
|
||||
// issue update
|
||||
this.initTimeFromUrl();
|
||||
this.setTime(this.time, true);
|
||||
}
|
||||
} else {
|
||||
this.setTime(this.timeAtLoad, true);
|
||||
}
|
||||
}
|
||||
|
||||
setAutoRefresh(interval) {
|
||||
this.dashboard.refresh = interval;
|
||||
if (interval) {
|
||||
var intervalMs = kbn.interval_to_ms(interval);
|
||||
|
||||
this.$timeout(() => {
|
||||
this.startNextRefreshTimer(intervalMs);
|
||||
this.refreshDashboard();
|
||||
}, intervalMs);
|
||||
|
||||
} else {
|
||||
this.cancelNextRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
refreshDashboard() {
|
||||
this.$rootScope.$broadcast('refresh');
|
||||
}
|
||||
|
||||
private startNextRefreshTimer(afterMs) {
|
||||
this.cancelNextRefresh();
|
||||
this.refreshTimer = this.timer.register(this.$timeout(() => {
|
||||
this.startNextRefreshTimer(afterMs);
|
||||
if (this.contextSrv.isGrafanaVisible()) {
|
||||
this.refreshDashboard();
|
||||
}
|
||||
}, afterMs));
|
||||
}
|
||||
|
||||
private cancelNextRefresh() {
|
||||
this.timer.cancel(this.refreshTimer);
|
||||
};
|
||||
|
||||
setTime(time, fromRouteUpdate?) {
|
||||
_.extend(this.time, time);
|
||||
|
||||
// disable refresh if zoom in or zoom out
|
||||
if (moment.isMoment(time.to)) {
|
||||
this.oldRefresh = this.dashboard.refresh || this.oldRefresh;
|
||||
this.setAutoRefresh(false);
|
||||
} else if (this.oldRefresh && this.oldRefresh !== this.dashboard.refresh) {
|
||||
this.setAutoRefresh(this.oldRefresh);
|
||||
this.oldRefresh = null;
|
||||
}
|
||||
|
||||
// update url
|
||||
if (fromRouteUpdate !== true) {
|
||||
var urlRange = this.timeRangeForUrl();
|
||||
var urlParams = this.$location.search();
|
||||
urlParams.from = urlRange.from;
|
||||
urlParams.to = urlRange.to;
|
||||
this.$location.search(urlParams);
|
||||
}
|
||||
|
||||
this.$rootScope.appEvent('time-range-changed', this.time);
|
||||
this.$timeout(this.refreshDashboard.bind(this), 0);
|
||||
}
|
||||
|
||||
timeRangeForUrl() {
|
||||
var range = this.timeRange().raw;
|
||||
|
||||
if (moment.isMoment(range.from)) { range.from = range.from.valueOf(); }
|
||||
if (moment.isMoment(range.to)) { range.to = range.to.valueOf(); }
|
||||
|
||||
return range;
|
||||
}
|
||||
|
||||
timeRange() {
|
||||
// make copies if they are moment (do not want to return out internal moment, because they are mutable!)
|
||||
var raw = {
|
||||
from: moment.isMoment(this.time.from) ? moment(this.time.from) : this.time.from,
|
||||
to: moment.isMoment(this.time.to) ? moment(this.time.to) : this.time.to,
|
||||
};
|
||||
|
||||
return {
|
||||
from: dateMath.parse(raw.from, false),
|
||||
to: dateMath.parse(raw.to, true),
|
||||
raw: raw
|
||||
};
|
||||
}
|
||||
|
||||
zoomOut(e, factor) {
|
||||
var range = this.timeRange();
|
||||
|
||||
var timespan = (range.to.valueOf() - range.from.valueOf());
|
||||
var center = range.to.valueOf() - timespan/2;
|
||||
|
||||
var to = (center + (timespan*factor)/2);
|
||||
var from = (center - (timespan*factor)/2);
|
||||
|
||||
if (to > Date.now() && range.to <= Date.now()) {
|
||||
var offset = to - Date.now();
|
||||
from = from - offset;
|
||||
to = Date.now();
|
||||
}
|
||||
|
||||
this.setTime({from: moment.utc(from), to: moment.utc(to)});
|
||||
}
|
||||
}
|
||||
|
||||
coreModule.service('timeSrv', TimeSrv);
|
@ -97,8 +97,7 @@ export class TimePickerCtrl {
|
||||
from = range.from.valueOf();
|
||||
}
|
||||
|
||||
this.timeSrv.setTime({from: moment.utc(from), to: moment.utc(to) });
|
||||
|
||||
this.timeSrv.setTime({from: moment.utc(from), to: moment.utc(to)});
|
||||
}
|
||||
|
||||
openDropdown() {
|
||||
@ -126,7 +125,7 @@ export class TimePickerCtrl {
|
||||
this.timeSrv.setAutoRefresh(this.refresh.value);
|
||||
}
|
||||
|
||||
this.timeSrv.setTime(this.timeRaw, true);
|
||||
this.timeSrv.setTime(this.timeRaw);
|
||||
this.$rootScope.appEvent('hide-dash-editor');
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ function (angular, _, $) {
|
||||
|
||||
var module = angular.module('grafana.services');
|
||||
|
||||
module.factory('dashboardViewStateSrv', function($location, $timeout, templateSrv, contextSrv, timeSrv) {
|
||||
module.factory('dashboardViewStateSrv', function($location, $timeout) {
|
||||
|
||||
// represents the transient view state
|
||||
// like fullscreen panel & edit
|
||||
@ -25,15 +25,6 @@ function (angular, _, $) {
|
||||
}
|
||||
};
|
||||
|
||||
// update url on time range change
|
||||
$scope.onAppEvent('time-range-changed', function() {
|
||||
var urlParams = $location.search();
|
||||
var urlRange = timeSrv.timeRangeForUrl();
|
||||
urlParams.from = urlRange.from;
|
||||
urlParams.to = urlRange.to;
|
||||
$location.search(urlParams);
|
||||
});
|
||||
|
||||
$scope.onAppEvent('$routeUpdate', function() {
|
||||
var urlState = self.getQueryStringState();
|
||||
if (self.needsSync(urlState)) {
|
||||
@ -82,7 +73,7 @@ function (angular, _, $) {
|
||||
return urlState;
|
||||
};
|
||||
|
||||
DashboardViewState.prototype.update = function(state) {
|
||||
DashboardViewState.prototype.update = function(state, fromRouteUpdated) {
|
||||
// implement toggle logic
|
||||
if (state.toggle) {
|
||||
delete state.toggle;
|
||||
@ -113,7 +104,12 @@ function (angular, _, $) {
|
||||
delete this.state.tab;
|
||||
}
|
||||
|
||||
$location.search(this.serializeToUrl());
|
||||
// do not update url params if we are here
|
||||
// from routeUpdated event
|
||||
if (fromRouteUpdated !== true) {
|
||||
$location.search(this.serializeToUrl());
|
||||
}
|
||||
|
||||
this.syncState();
|
||||
};
|
||||
|
||||
|
@ -8,6 +8,9 @@ describe('templateSrv', function() {
|
||||
|
||||
beforeEach(angularMocks.module('grafana.core'));
|
||||
beforeEach(angularMocks.module('grafana.services'));
|
||||
beforeEach(angularMocks.module($provide => {
|
||||
$provide.value('timeSrv', {});
|
||||
}));
|
||||
|
||||
beforeEach(angularMocks.inject(function(variableSrv, templateSrv) {
|
||||
_templateSrv = templateSrv;
|
||||
|
@ -11,7 +11,7 @@ describe('ElasticDatasource', function() {
|
||||
|
||||
beforeEach(angularMocks.module('grafana.core'));
|
||||
beforeEach(angularMocks.module('grafana.services'));
|
||||
beforeEach(ctx.providePhase(['templateSrv', 'backendSrv']));
|
||||
beforeEach(ctx.providePhase(['templateSrv', 'backendSrv', 'timeSrv']));
|
||||
|
||||
beforeEach(angularMocks.inject(function($q, $rootScope, $httpBackend, $injector) {
|
||||
ctx.$q = $q;
|
||||
|
@ -9,6 +9,8 @@ describe('PrometheusDatasource', function() {
|
||||
|
||||
beforeEach(angularMocks.module('grafana.core'));
|
||||
beforeEach(angularMocks.module('grafana.services'));
|
||||
beforeEach(ctx.providePhase(['timeSrv']));
|
||||
|
||||
beforeEach(angularMocks.inject(function($q, $rootScope, $httpBackend, $injector) {
|
||||
ctx.$q = $q;
|
||||
ctx.$httpBackend = $httpBackend;
|
||||
|
@ -92,7 +92,6 @@ define([
|
||||
self.timeSrv = new TimeSrvStub();
|
||||
self.datasourceSrv = {};
|
||||
self.backendSrv = {};
|
||||
self.$location = {};
|
||||
self.$routeParams = {};
|
||||
|
||||
this.providePhase = function(mocks) {
|
||||
@ -104,10 +103,11 @@ define([
|
||||
};
|
||||
|
||||
this.createService = function(name) {
|
||||
return inject(function($q, $rootScope, $httpBackend, $injector) {
|
||||
return inject(function($q, $rootScope, $httpBackend, $injector, $location) {
|
||||
self.$q = $q;
|
||||
self.$rootScope = $rootScope;
|
||||
self.$httpBackend = $httpBackend;
|
||||
self.$location = $location;
|
||||
|
||||
self.$rootScope.onAppEvent = function() {};
|
||||
self.$rootScope.appEvent = function() {};
|
||||
|
@ -1,5 +1,6 @@
|
||||
define([
|
||||
'lodash',
|
||||
'app/features/dashboard/all',
|
||||
'app/features/panellinks/linkSrv'
|
||||
], function(_) {
|
||||
'use strict';
|
||||
|
@ -1,120 +0,0 @@
|
||||
define([
|
||||
'test/mocks/dashboard-mock',
|
||||
'test/specs/helpers',
|
||||
'lodash',
|
||||
'moment',
|
||||
'app/core/services/timer',
|
||||
'app/features/dashboard/timeSrv'
|
||||
], function(dashboardMock, helpers, _, moment) {
|
||||
'use strict';
|
||||
|
||||
describe('timeSrv', function() {
|
||||
var ctx = new helpers.ServiceTestContext();
|
||||
var _dashboard;
|
||||
|
||||
beforeEach(module('grafana.core'));
|
||||
beforeEach(module('grafana.services'));
|
||||
beforeEach(ctx.providePhase(['$routeParams']));
|
||||
beforeEach(ctx.createService('timeSrv'));
|
||||
|
||||
beforeEach(function() {
|
||||
_dashboard = dashboardMock.create();
|
||||
ctx.service.init(_dashboard);
|
||||
});
|
||||
|
||||
describe('timeRange', function() {
|
||||
it('should return unparsed when parse is false', function() {
|
||||
ctx.service.setTime({from: 'now', to: 'now-1h' });
|
||||
var time = ctx.service.timeRange();
|
||||
expect(time.raw.from).to.be('now');
|
||||
expect(time.raw.to).to.be('now-1h');
|
||||
});
|
||||
|
||||
it('should return parsed when parse is true', function() {
|
||||
ctx.service.setTime({from: 'now', to: 'now-1h' });
|
||||
var time = ctx.service.timeRange();
|
||||
expect(moment.isMoment(time.from)).to.be(true);
|
||||
expect(moment.isMoment(time.to)).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('init time from url', function() {
|
||||
it('should handle relative times', function() {
|
||||
ctx.$routeParams.from = 'now-2d';
|
||||
ctx.$routeParams.to = 'now';
|
||||
ctx.service.init(_dashboard);
|
||||
var time = ctx.service.timeRange();
|
||||
expect(time.raw.from).to.be('now-2d');
|
||||
expect(time.raw.to).to.be('now');
|
||||
});
|
||||
|
||||
it('should handle formated dates', function() {
|
||||
ctx.$routeParams.from = '20140410T052010';
|
||||
ctx.$routeParams.to = '20140520T031022';
|
||||
ctx.service.init(_dashboard);
|
||||
var time = ctx.service.timeRange(true);
|
||||
expect(time.from.valueOf()).to.equal(new Date("2014-04-10T05:20:10Z").getTime());
|
||||
expect(time.to.valueOf()).to.equal(new Date("2014-05-20T03:10:22Z").getTime());
|
||||
});
|
||||
|
||||
it('should handle formated dates without time', function() {
|
||||
ctx.$routeParams.from = '20140410';
|
||||
ctx.$routeParams.to = '20140520';
|
||||
ctx.service.init(_dashboard);
|
||||
var time = ctx.service.timeRange(true);
|
||||
expect(time.from.valueOf()).to.equal(new Date("2014-04-10T00:00:00Z").getTime());
|
||||
expect(time.to.valueOf()).to.equal(new Date("2014-05-20T00:00:00Z").getTime());
|
||||
});
|
||||
|
||||
it('should handle epochs', function() {
|
||||
ctx.$routeParams.from = '1410337646373';
|
||||
ctx.$routeParams.to = '1410337665699';
|
||||
ctx.service.init(_dashboard);
|
||||
var time = ctx.service.timeRange(true);
|
||||
expect(time.from.valueOf()).to.equal(1410337646373);
|
||||
expect(time.to.valueOf()).to.equal(1410337665699);
|
||||
});
|
||||
|
||||
it('should handle bad dates', function() {
|
||||
ctx.$routeParams.from = '20151126T00010%3C%2Fp%3E%3Cspan%20class';
|
||||
ctx.$routeParams.to = 'now';
|
||||
_dashboard.time.from = 'now-6h';
|
||||
ctx.service.init(_dashboard);
|
||||
expect(ctx.service.time.from).to.equal('now-6h');
|
||||
expect(ctx.service.time.to).to.equal('now');
|
||||
});
|
||||
});
|
||||
|
||||
describe('setTime', function() {
|
||||
it('should return disable refresh if refresh is disabled for any range', function() {
|
||||
_dashboard.refresh = false;
|
||||
|
||||
ctx.service.setTime({from: '2011-01-01', to: '2015-01-01' });
|
||||
expect(_dashboard.refresh).to.be(false);
|
||||
});
|
||||
|
||||
it('should restore refresh for absolute time range', function() {
|
||||
_dashboard.refresh = '30s';
|
||||
|
||||
ctx.service.setTime({from: '2011-01-01', to: '2015-01-01' });
|
||||
expect(_dashboard.refresh).to.be('30s');
|
||||
});
|
||||
|
||||
it('should restore refresh after relative time range is set', function() {
|
||||
_dashboard.refresh = '10s';
|
||||
ctx.service.setTime({from: moment([2011,1,1]), to: moment([2015,1,1])});
|
||||
expect(_dashboard.refresh).to.be(false);
|
||||
ctx.service.setTime({from: '2011-01-01', to: 'now' });
|
||||
expect(_dashboard.refresh).to.be('10s');
|
||||
});
|
||||
|
||||
it('should keep refresh after relative time range is changed and now delay exists', function() {
|
||||
_dashboard.refresh = '10s';
|
||||
ctx.service.setTime({from: 'now-1h', to: 'now-10s' });
|
||||
expect(_dashboard.refresh).to.be('10s');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
Loading…
Reference in New Issue
Block a user