Commit de17dcf3 by Patrick O'Carroll Committed by Torkel Ödegaard

Singlestat time (#9298)

* Added a timestamp option to single stat

* can now choose last time as value

* Finished last_time so it formats correctly, updated value stat

* fixed som issues, but still issue with testing

* Clean up after fake clock in test

* timezone-issue fix, fake time for from now test

* fix for timedifference
parent f1036a93
define([
'jquery',
'lodash'
'lodash',
'moment'
],
function($, _) {
function($, _, moment) {
'use strict';
var kbn = {};
......@@ -702,6 +703,28 @@ function($, _) {
return kbn.toDuration(size, decimals, 'second');
};
kbn.valueFormats.dateTimeAsIso = function(epoch) {
var time = moment(epoch);
if (moment().isSame(epoch, 'day')) {
return time.format('HH:mm:ss');
}
return time.format('YYYY-MM-DD HH:mm:ss');
};
kbn.valueFormats.dateTimeAsUS = function(epoch) {
var time = moment(epoch);
if (moment().isSame(epoch, 'day')) {
return time.format('h:mm:ss a');
}
return time.format('MM/DD/YYYY h:mm:ss a');
};
kbn.valueFormats.dateTimeFromNow = function(epoch) {
return moment(epoch).fromNow();
};
///// FORMAT MENU /////
kbn.getUnitFormats = function() {
......@@ -745,7 +768,15 @@ function($, _) {
{text: 'hours (h)', value: 'h' },
{text: 'days (d)', value: 'd' },
{text: 'duration (ms)', value: 'dtdurationms' },
{text: 'duration (s)', value: 'dtdurations' }
{text: 'duration (s)', value: 'dtdurations' },
]
},
{
text: 'date & time',
submenu: [
{text: 'YYYY-MM-DD HH:mm:ss', value: 'dateTimeAsIso' },
{text: 'DD/MM/YYYY h:mm:ss a', value: 'dateTimeAsUS' },
{text: 'from now', value: 'dateTimeFromNow' },
]
},
{
......
......@@ -6,7 +6,7 @@
<div class="gf-form" ng-show="ctrl.dataType === 'timeseries'">
<label class="gf-form-label width-6">Stat</label>
<div class="gf-form-select-wrapper width-7">
<select class="gf-form-input" ng-model="ctrl.panel.valueName" ng-options="f for f in ctrl.valueNameOptions" ng-change="ctrl.render()"></select>
<select class="gf-form-input" ng-model="ctrl.panel.valueName" ng-options="f.value as f.text for f in ctrl.valueNameOptions" ng-change="ctrl.refresh()"></select>
</div>
</div>
<div class="gf-form" ng-show="ctrl.dataType === 'table'">
......
......@@ -5,6 +5,7 @@ import _ from 'lodash';
import $ from 'jquery';
import 'jquery.flot';
import 'jquery.flot.gauge';
import moment from 'moment';
import kbn from 'app/core/utils/kbn';
import config from 'app/core/config';
......@@ -22,7 +23,19 @@ class SingleStatCtrl extends MetricsPanelCtrl {
invalidGaugeRange: boolean;
panel: any;
events: any;
valueNameOptions: any[] = ['min','max','avg', 'current', 'total', 'name', 'first', 'delta', 'diff', 'range'];
valueNameOptions: any[] = [
{value : 'min', text: 'Min'},
{value : 'max', text: 'Max'},
{value : 'avg', text: 'Average'},
{value : 'current', text: 'Current'},
{value : 'total', text: 'Total'},
{value : 'name', text: 'Name'},
{value : 'first', text: 'First'},
{value : 'delta', text: 'Delta'},
{value : 'diff', text: 'Difference'},
{value : 'range', text: 'Range'},
{value : 'last_time', text: 'Time of last point'}
];
tableColumnOptions: any;
// Set and populate defaults
......@@ -93,7 +106,7 @@ class SingleStatCtrl extends MetricsPanelCtrl {
setUnitFormat(subItem) {
this.panel.format = subItem.value;
this.render();
this.refresh();
}
onDataError(err) {
......@@ -257,8 +270,8 @@ class SingleStatCtrl extends MetricsPanelCtrl {
}
if (this.series && this.series.length > 0) {
var lastPoint = _.last(this.series[0].datapoints);
var lastValue = _.isArray(lastPoint) ? lastPoint[0] : null;
let lastPoint = _.last(this.series[0].datapoints);
let lastValue = _.isArray(lastPoint) ? lastPoint[0] : null;
if (this.panel.valueName === 'name') {
data.value = 0;
......@@ -268,12 +281,17 @@ class SingleStatCtrl extends MetricsPanelCtrl {
data.value = 0;
data.valueFormatted = _.escape(lastValue);
data.valueRounded = 0;
} else if (this.panel.valueName === 'last_time') {
let formatFunc = kbn.valueFormats[this.panel.format];
data.value = lastPoint[1];
data.valueRounded = data.value;
data.valueFormatted = formatFunc(data.value, 0, 0);
} else {
data.value = this.series[0].stats[this.panel.valueName];
data.flotpairs = this.series[0].flotpairs;
var decimalInfo = this.getDecimalsForValue(data.value);
var formatFunc = kbn.valueFormats[this.panel.format];
let decimalInfo = this.getDecimalsForValue(data.value);
let formatFunc = kbn.valueFormats[this.panel.format];
data.valueFormatted = formatFunc(data.value, decimalInfo.decimals, decimalInfo.scaledDecimals);
data.valueRounded = kbn.roundValue(data.value, decimalInfo.decimals);
}
......
///<reference path="../../../../headers/common.d.ts" />
import {describe, beforeEach, it, sinon, expect, angularMocks} from '../../../../../test/lib/common';
import {describe, beforeEach, afterEach, it, sinon, expect, angularMocks} from '../../../../../test/lib/common';
import angular from 'angular';
import helpers from '../../../../../test/specs/helpers';
import {SingleStatCtrl} from '../module';
import moment from 'moment';
describe('SingleStatCtrl', function() {
var ctx = new helpers.ControllerTestContext();
var epoch = 1505826363746;
var clock;
function singleStatScenario(desc, func) {
......@@ -70,6 +73,72 @@ describe('SingleStatCtrl', function() {
});
});
singleStatScenario('showing last iso time instead of value', function(ctx) {
ctx.setup(function() {
ctx.data = [
{target: 'test.cpu1', datapoints: [[10, 12], [20,1505634997920]]}
];
ctx.ctrl.panel.valueName = 'last_time';
ctx.ctrl.panel.format = 'dateTimeAsIso';
});
it('Should use time instead of value', function() {
expect(ctx.data.value).to.be(1505634997920);
expect(ctx.data.valueRounded).to.be(1505634997920);
});
it('should set formatted value', function() {
expect(ctx.data.valueFormatted).to.be(moment(1505634997920).format('YYYY-MM-DD HH:mm:ss'));
});
});
singleStatScenario('showing last us time instead of value', function(ctx) {
ctx.setup(function() {
ctx.data = [
{target: 'test.cpu1', datapoints: [[10, 12], [20,1505634997920]]}
];
ctx.ctrl.panel.valueName = 'last_time';
ctx.ctrl.panel.format = 'dateTimeAsUS';
});
it('Should use time instead of value', function() {
expect(ctx.data.value).to.be(1505634997920);
expect(ctx.data.valueRounded).to.be(1505634997920);
});
it('should set formatted value', function() {
expect(ctx.data.valueFormatted).to.be(moment(1505634997920).format('MM/DD/YYYY H:mm:ss a'));
});
});
singleStatScenario('showing last time from now instead of value', function(ctx) {
beforeEach(() => {
clock = sinon.useFakeTimers(epoch);
});
ctx.setup(function() {
ctx.data = [
{target: 'test.cpu1', datapoints: [[10, 12], [20,1505634997920]]}
];
ctx.ctrl.panel.valueName = 'last_time';
ctx.ctrl.panel.format = 'dateTimeFromNow';
});
it('Should use time instead of value', function() {
expect(ctx.data.value).to.be(1505634997920);
expect(ctx.data.valueRounded).to.be(1505634997920);
});
it('should set formatted value', function() {
expect(ctx.data.valueFormatted).to.be('2 days ago');
});
afterEach(() => {
clock.restore();
});
});
singleStatScenario('MainValue should use same number for decimals as displayed when checking thresholds', function(ctx) {
ctx.setup(function() {
ctx.data = [
......
import {describe, beforeEach, it, sinon, expect} from 'test/lib/common';
import {describe, beforeEach, afterEach, it, sinon, expect} from 'test/lib/common';
import * as dateMath from 'app/core/utils/datemath';
import moment from 'moment';
......@@ -68,6 +68,10 @@ describe("DateMath", () => {
expect(dateMath.parse(thenEx).format(format)).to.eql(anchored.subtract(5, span).format(format));
});
});
afterEach(() => {
clock.restore();
});
});
describe('rounding', () => {
......@@ -89,6 +93,10 @@ describe("DateMath", () => {
expect(dateMath.parse('now/' + span, true).format(format)).to.eql(now.endOf(span).format(format));
});
});
afterEach(() => {
clock.restore();
});
});
describe('isValid', () => {
......
define([
'app/core/utils/kbn',
'app/core/utils/datemath'
], function(kbn, dateMath) {
'app/core/utils/datemath',
'moment'
], function(kbn, dateMath, moment) {
'use strict';
describe('unit format menu', function() {
......@@ -94,6 +95,42 @@ define([
describeValueFormat('d', 245, 100, 0, '35 week');
describeValueFormat('d', 2456, 10, 0, '6.73 year');
describe('date time formats', function() {
it('should format as iso date', function() {
var str = kbn.valueFormats.dateTimeAsIso(1505634997920, 1);
expect(str).to.be(moment(1505634997920).format('YYYY-MM-DD HH:mm:ss'));
});
it('should format as iso date and skip date when today', function() {
var now = moment();
var str = kbn.valueFormats.dateTimeAsIso(now.valueOf(), 1);
expect(str).to.be(now.format("HH:mm:ss"));
});
it('should format as US date', function() {
var str = kbn.valueFormats.dateTimeAsUS(1505634997920, 1);
expect(str).to.be(moment(1505634997920).format('MM/DD/YYYY H:mm:ss a'));
});
it('should format as US date and skip date when today', function() {
var now = moment();
var str = kbn.valueFormats.dateTimeAsUS(now.valueOf(), 1);
expect(str).to.be(now.format("h:mm:ss a"));
});
it('should format as from now with days', function() {
var daysAgo = moment().add(-7, 'd');
var str = kbn.valueFormats.dateTimeFromNow(daysAgo.valueOf(), 1);
expect(str).to.be('7 days ago');
});
it('should format as from now with minutes', function() {
var daysAgo = moment().add(-2, 'm');
var str = kbn.valueFormats.dateTimeFromNow(daysAgo.valueOf(), 1);
expect(str).to.be('2 minutes ago');
});
});
describe('kbn.toFixed and negative decimals', function() {
it('should treat as zero decimals', function() {
var str = kbn.toFixed(186.123, -2);
......
......@@ -2,6 +2,7 @@
var _global = <any>(window);
var beforeEach = _global.beforeEach;
var afterEach = _global.afterEach;
var before = _global.before;
var describe = _global.describe;
var it = _global.it;
......@@ -15,6 +16,7 @@ var angularMocks = {
export {
beforeEach,
afterEach,
before,
describe,
it,
......
......@@ -23,6 +23,7 @@ module.exports = function(config, grunt) {
gaze([
config.srcDir + '/app/**/*',
config.srcDir + '/test/**/*',
config.srcDir + '/sass/**/*',
], function(err, watcher) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment