diff --git a/pkg/api/api.go b/pkg/api/api.go index 6c56e6aa9f1..309c0bf42b6 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -17,7 +17,7 @@ func Register(r *macaron.Macaron) { bind := binding.Bind // not logged in views - r.Get("/", reqSignedIn, Index) + r.Get("/", reqSignedIn, Index) r.Get("/logout", Logout) r.Post("/login", bind(dtos.LoginCommand{}), wrap(LoginPost)) r.Get("/login/:name", OAuthLogin) diff --git a/public/app/directives/all.js b/public/app/directives/all.js index bcf5bd5fa27..d9fd1b748cb 100644 --- a/public/app/directives/all.js +++ b/public/app/directives/all.js @@ -1,6 +1,5 @@ define([ './dashUpload', - './grafanaSimplePanel', './dashEditLink', './ngModelOnBlur', './misc', diff --git a/public/app/features/dashboard/dashboardSrv.js b/public/app/features/dashboard/dashboardSrv.js index b7a9e1dbbab..3767ba05176 100644 --- a/public/app/features/dashboard/dashboardSrv.js +++ b/public/app/features/dashboard/dashboardSrv.js @@ -31,8 +31,8 @@ function (angular, $, kbn, _, moment) { this.hideControls = data.hideControls || false; this.sharedCrosshair = data.sharedCrosshair || false; this.rows = data.rows || []; - this.timepicker = data.timepicker || {}; this.time = data.time || { from: 'now-6h', to: 'now' }; + this.timepicker = data.timepicker || {}; this.templating = this._ensureListExist(data.templating); this.annotations = this._ensureListExist(data.annotations); this.refresh = data.refresh; diff --git a/public/app/features/dashboard/timepicker/custom.html b/public/app/features/dashboard/timepicker/custom.html new file mode 100644 index 00000000000..587ee973b8f --- /dev/null +++ b/public/app/features/dashboard/timepicker/custom.html @@ -0,0 +1,81 @@ +
+
+ + Custom time range +
+ +
+ +
+ + +
+
+ +
+ +
+ @ + : + : + . + +
+
+ +
+ + + +
+
+ @ + : + : + . + +
+   Right Now +
+
+ +
+ + Invalid date or range +
+
+
diff --git a/public/app/features/dashboard/timepicker/timepicker.html b/public/app/features/dashboard/timepicker/timepicker.html index f202c1ed27e..cc916dc4a9d 100644 --- a/public/app/features/dashboard/timepicker/timepicker.html +++ b/public/app/features/dashboard/timepicker/timepicker.html @@ -19,7 +19,7 @@ -
  • Custom
  • +
  • Custom
  • diff --git a/public/app/features/dashboard/timepicker/timepicker.ts b/public/app/features/dashboard/timepicker/timepicker.ts index 72de01db29b..e16f0a6090d 100644 --- a/public/app/features/dashboard/timepicker/timepicker.ts +++ b/public/app/features/dashboard/timepicker/timepicker.ts @@ -7,224 +7,192 @@ import kbn = require('kbn'); export class TimePickerCtrl { - constructor($scope : any, $rootScope, timeSrv) { - $scope.panelMeta = { - status : "Stable", - description : "" - }; + static defaults = { + status : "Stable", + time_options : ['5m','15m','1h','6h','12h','24h','today', '2d','7d','30d'], + refresh_intervals : ['5s','10s','30s','1m','5m','15m','30m','1h','2h','1d'], + }; - // Set and populate defaults - var _d = { - status : "Stable", - time_options : ['5m','15m','1h','6h','12h','24h','2d','7d','30d'], - refresh_intervals : ['5s','10s','30s','1m','5m','15m','30m','1h','2h','1d'], - }; - - // ng-pattern regexs - $scope.patterns = { + static patterns = { date: /^[0-9]{2}\/[0-9]{2}\/[0-9]{4}$/, hour: /^([01]?[0-9]|2[0-3])$/, minute: /^[0-5][0-9]$/, second: /^[0-5][0-9]$/, millisecond: /^[0-9]*$/ - }; + }; + constructor(private $scope : any, private $rootScope, private timeSrv) { + $scope.patterns = TimePickerCtrl.patterns; $scope.timeSrv = timeSrv; + $scope.ctrl = this; - $scope.$on('refresh', function() { - $scope.init(); + $scope.$on('refresh', () => this.init()); + + this.init(); + } + + init() { + this.$scope.panel = this.$scope.dashboard.timepicker; + + _.defaults(this.$scope.panel, TimePickerCtrl.defaults); + + var time = this.timeSrv.timeRange(true); + this.$scope.panel.now = false; + + var unparsed = this.timeSrv.timeRange(false); + if (_.isString(unparsed.to) && unparsed.to.indexOf('now') === 0) { + this.$scope.panel.now = true; + } + + this.$scope.time = this.getScopeTimeObj(time.from, time.to); + + this.$scope.onAppEvent('zoom-out', function() { + this.$scope.zoom(2); }); + } - $scope.init = function() { - $scope.panel = $scope.dashboard.timepicker; + pad(n: number, width: number, z = 0): string { + var str = n.toString(); + return str.length >= width ? str : new Array(width - str.length + 1).join(z.toString()) + str; + } - _.defaults($scope.panel, _d); - - var time = timeSrv.timeRange(true); - $scope.panel.now = false; - - var unparsed = timeSrv.timeRange(false); - if (_.isString(unparsed.to) && unparsed.to.indexOf('now') === 0) { - $scope.panel.now = true; - } - - $scope.time = getScopeTimeObj(time.from, time.to); - - $scope.onAppEvent('zoom-out', function() { - $scope.zoom(2); - }); + getTimeObj(date): any { + return { + date: new Date(date), + hour: this.pad(date.getHours(), 2), + minute: this.pad(date.getMinutes(), 2), + second: this.pad(date.getSeconds(), 2), + millisecond: this.pad(date.getMilliseconds(), 3) }; + }; - $scope.loadTimeOptions = function() { - $scope.time_options = _.map($scope.panel.time_options, function(str) { - return kbn.getRelativeTimeInfo(str); - }); + getScopeTimeObj(from, to) { + var model : any = {from: this.getTimeObj(from), to: this.getTimeObj(to)}; - $scope.refreshMenuLeftSide = $scope.time.rangeString.length < 10; - }; + if (model.from.date) { + model.tooltip = this.$scope.dashboard.formatDate(model.from.date) + '
    to
    '; + model.tooltip += this.$scope.dashboard.formatDate(model.to.date); + } + else { + model.tooltip = 'Click to set time filter'; + } - $scope.customTime = function() { - // Assume the form is valid since we're setting it to something valid - $scope.input.$setValidity("dummy", true); - $scope.temptime = cloneTime($scope.time); - $scope.temptime.now = $scope.panel.now; - - $scope.temptime.from.date.setHours(0, 0, 0, 0); - $scope.temptime.to.date.setHours(0, 0, 0, 0); - - // Date picker needs the date to be at the start of the day - if (new Date().getTimezoneOffset() < 0) { - $scope.temptime.from.date = moment($scope.temptime.from.date).add(1, 'days').toDate(); - $scope.temptime.to.date = moment($scope.temptime.to.date).add(1, 'days').toDate(); - } - - $scope.appEvent('show-dash-editor', {src: 'app/panels/timepicker/custom.html', scope: $scope }); - }; - - // Constantly validate the input of the fields. This function does not change any date variables - // outside of its own scope - $scope.validate = function(time) : any { - // Assume the form is valid. There is a hidden dummy input for invalidating it programatically. - $scope.input.$setValidity("dummy", true); - - var _from = datepickerToLocal(time.from.date), - _to = datepickerToLocal(time.to.date), - _t = time; - - if ($scope.input.$valid) { - - _from.setHours(_t.from.hour, _t.from.minute, _t.from.second, _t.from.millisecond); - _to.setHours(_t.to.hour, _t.to.minute, _t.to.second, _t.to.millisecond); - - // Check that the objects are valid and to is after from - if (isNaN(_from.getTime()) || isNaN(_to.getTime()) || _from.getTime() >= _to.getTime()) { - $scope.input.$setValidity("dummy", false); - return false; + if (this.timeSrv.time) { + if (this.$scope.panel.now) { + if (this.timeSrv.time.from === 'today') { + model.rangeString = 'Today'; + } else { + model.rangeString = moment(model.from.date).fromNow() + ' to ' + + moment(model.to.date).fromNow(); } - } else { - return false; - } - - return { from: _from, to: _to, now: time.now }; - }; - - $scope.setNow = function() { - $scope.time.to = getTimeObj(new Date()); - }; - - $scope.setAbsoluteTimeFilter = function (time) { - // Create filter object - var _filter = _.clone(time); - - if (time.now) { - _filter.to = "now"; - } - - // Update our representation - $scope.time = getScopeTimeObj(time.from, time.to); - - timeSrv.setTime(_filter); - }; - - $scope.setRelativeFilter = function(timespan) { - $scope.panel.now = true; - - var range = {from: timespan.from, to: timespan.to}; - - if ($scope.panel.nowDelay) { - range.to = 'now-' + $scope.panel.nowDelay; - } - - timeSrv.setTime(range); - - $scope.time = getScopeTimeObj(kbn.parseDate(range.from), new Date()); - }; - - var pad : any = function(n, width, z) { - z = z || '0'; - n = n.toString(); - return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n; - }; - - var cloneTime = function(time) { - var _n = { - from: _.clone(time.from), - to: _.clone(time.to) - }; - // Create new dates as _.clone is shallow. - _n.from.date = new Date(_n.from.date); - _n.to.date = new Date(_n.to.date); - return _n; - }; - - var getScopeTimeObj = function(from, to) { - var model : any = {from: getTimeObj(from), to: getTimeObj(to)}; - - if (model.from.date) { - model.tooltip = $scope.dashboard.formatDate(model.from.date) + '
    to
    '; - model.tooltip += $scope.dashboard.formatDate(model.to.date); } else { - model.tooltip = 'Click to set time filter'; + model.rangeString = this.$scope.dashboard.formatDate(model.from.date, 'MMM D, YYYY HH:mm:ss') + ' to ' + + this.$scope.dashboard.formatDate(model.to.date, 'MMM D, YYYY HH:mm:ss'); } + } - if (timeSrv.time) { - if ($scope.panel.now) { - if (timeSrv.time.from === 'today') { - model.rangeString = 'Today'; - } else { - model.rangeString = moment(model.from.date).fromNow() + ' to ' + - moment(model.to.date).fromNow(); - } - } - else { - model.rangeString = $scope.dashboard.formatDate(model.from.date, 'MMM D, YYYY HH:mm:ss') + ' to ' + - $scope.dashboard.formatDate(model.to.date, 'MMM D, YYYY HH:mm:ss'); - } - } - - return model; - }; - - var getTimeObj = function(date) { - return { - date: new Date(date), - hour: pad(date.getHours(), 2), - minute: pad(date.getMinutes(), 2), - second: pad(date.getSeconds(), 2), - millisecond: pad(date.getMilliseconds(), 3) - }; - }; - - // Do not use the results of this function unless you plan to use setHour/Minutes/etc on the result - var datepickerToLocal = function(date) { - date = moment(date).clone().toDate(); - return moment(new Date(date.getTime() + date.getTimezoneOffset() * 60000)).toDate(); - }; - - $scope.zoom = function(factor) { - var range = timeSrv.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(); - } - - timeSrv.setTime({ - from: moment.utc(from).toDate(), - to: moment.utc(to).toDate(), - }); - }; - - $scope.init(); + return model; } + + loadTimeOptions() { + this.$scope.time_options = _.map(this.$scope.panel.time_options, function(str) { + return kbn.getRelativeTimeInfo(str); + }); + + this.$scope.refreshMenuLeftSide = this.$scope.time.rangeString.length < 10; + } + + cloneTime(time) { + var _n = { from: _.clone(time.from), to: _.clone(time.to) }; + + // Create new dates as _.clone is shallow. + _n.from.date = new Date(_n.from.date); + _n.to.date = new Date(_n.to.date); + return _n; + } + + customTime() { + // Assume the form is valid since we're setting it to something valid + this.$scope.input.$setValidity("dummy", true); + this.$scope.temptime = this.cloneTime(this.$scope.time); + this.$scope.temptime.now = this.$scope.panel.now; + + this.$scope.temptime.from.date.setHours(0, 0, 0, 0); + this.$scope.temptime.to.date.setHours(0, 0, 0, 0); + + // Date picker needs the date to be at the start of the day + if (new Date().getTimezoneOffset() < 0) { + this.$scope.temptime.from.date = moment(this.$scope.temptime.from.date).add(1, 'days').toDate(); + this.$scope.temptime.to.date = moment(this.$scope.temptime.to.date).add(1, 'days').toDate(); + } + + this.$scope.appEvent('show-dash-editor', { + src: 'app/features/dashboard/timepicker/custom.html', + scope: this.$scope + }); + } + + setNow() { + this.$scope.time.to = this.getTimeObj(new Date()); + } + + setAbsoluteTimeFilter(time) { + // Create filter object + var _filter = _.clone(time); + + if (time.now) { + _filter.to = "now"; + } + + // Update our representation + this.$scope.time = this.getScopeTimeObj(time.from, time.to); + this.timeSrv.setTime(_filter); + } + + setRelativeFilter(timespan) { + this.$scope.panel.now = true; + + var range = {from: timespan.from, to: timespan.to}; + + if (this.$scope.panel.nowDelay) { + range.to = 'now-' + this.$scope.panel.nowDelay; + } + + this.timeSrv.setTime(range); + + this.$scope.time = this.getScopeTimeObj(kbn.parseDate(range.from), new Date()); + } + + validate(time): any { + // Assume the form is valid. There is a hidden dummy input for invalidating it programatically. + this.$scope.input.$setValidity("dummy", true); + + var _from = this.datepickerToLocal(time.from.date); + var _to = this.datepickerToLocal(time.to.date); + var _t = time; + + if (this.$scope.input.$valid) { + _from.setHours(_t.from.hour, _t.from.minute, _t.from.second, _t.from.millisecond); + _to.setHours(_t.to.hour, _t.to.minute, _t.to.second, _t.to.millisecond); + + // Check that the objects are valid and to is after from + if (isNaN(_from.getTime()) || isNaN(_to.getTime()) || _from.getTime() >= _to.getTime()) { + this.$scope.input.$setValidity("dummy", false); + return false; + } + } else { + return false; + } + + return { from: _from, to: _to, now: time.now }; + } + + datepickerToLocal(date) { + date = moment(date).clone().toDate(); + return moment(new Date(date.getTime() + date.getTimezoneOffset() * 60000)).toDate(); + } + } export function settingsDirective() { diff --git a/public/test/specs/dashboardSrv-specs.js b/public/test/specs/dashboardSrv-specs.js index d3857ad8d82..7db18d2cb8e 100644 --- a/public/test/specs/dashboardSrv-specs.js +++ b/public/test/specs/dashboardSrv-specs.js @@ -31,7 +31,6 @@ define([ it('should have default properties', function() { expect(model.rows.length).to.be(0); }); - }); describe('when getting next panel id', function() {