Commit ef0b7bda by Marcus Efraimsson Committed by Torkel Ödegaard

singlestat: render time of last point based on dashboard timezone (#11425)

* singlestat: render time of last point based on dashboard timezone

* changelog: add note for #10338
parent e52aceea
......@@ -56,6 +56,7 @@
* **Cloudwatch**: Add dimension filtering to CloudWatch `dimension_values()` [#10029](https://github.com/grafana/grafana/issues/10029), thx [@willyhutw](https://github.com/willyhutw)
* **Units**: Second to HH:mm:ss formatter [#11107](https://github.com/grafana/grafana/issues/11107), thx [@gladdiologist](https://github.com/gladdiologist)
* **Singlestat**: Add color to prefix and postfix in singlestat panel [#11143](https://github.com/grafana/grafana/pull/11143), thx [@ApsOps](https://github.com/ApsOps)
* **Singlestat**: Fix "time of last point" shows local time when dashboard timezone set to UTC [#10338](https://github.com/grafana/grafana/issues/10338)
* **Dashboards**: Version cleanup fails on old databases with many entries [#11278](https://github.com/grafana/grafana/issues/11278)
* **Server**: Adjust permissions of unix socket [#11343](https://github.com/grafana/grafana/pull/11343), thx [@corny](https://github.com/corny)
* **Shortcuts**: Add shortcut for duplicate panel [#11102](https://github.com/grafana/grafana/issues/11102)
......
......@@ -101,38 +101,88 @@ describeValueFormat('d', 245, 100, 0, '35 week');
describeValueFormat('d', 2456, 10, 0, '6.73 year');
describe('date time formats', function() {
const epoch = 1505634997920;
const utcTime = moment.utc(epoch);
const browserTime = moment(epoch);
it('should format as iso date', function() {
var str = kbn.valueFormats.dateTimeAsIso(1505634997920, 1);
expect(str).toBe(moment(1505634997920).format('YYYY-MM-DD HH:mm:ss'));
var expected = browserTime.format('YYYY-MM-DD HH:mm:ss');
var actual = kbn.valueFormats.dateTimeAsIso(epoch);
expect(actual).toBe(expected);
});
it('should format as iso date (in UTC)', function() {
var expected = utcTime.format('YYYY-MM-DD HH:mm:ss');
var actual = kbn.valueFormats.dateTimeAsIso(epoch, true);
expect(actual).toBe(expected);
});
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).toBe(now.format('HH:mm:ss'));
var expected = now.format('HH:mm:ss');
var actual = kbn.valueFormats.dateTimeAsIso(now.valueOf(), false);
expect(actual).toBe(expected);
});
it('should format as iso date (in UTC) and skip date when today', function() {
var now = moment.utc();
var expected = now.format('HH:mm:ss');
var actual = kbn.valueFormats.dateTimeAsIso(now.valueOf(), true);
expect(actual).toBe(expected);
});
it('should format as US date', function() {
var str = kbn.valueFormats.dateTimeAsUS(1505634997920, 1);
expect(str).toBe(moment(1505634997920).format('MM/DD/YYYY h:mm:ss a'));
var expected = browserTime.format('MM/DD/YYYY h:mm:ss a');
var actual = kbn.valueFormats.dateTimeAsUS(epoch, false);
expect(actual).toBe(expected);
});
it('should format as US date (in UTC)', function() {
var expected = utcTime.format('MM/DD/YYYY h:mm:ss a');
var actual = kbn.valueFormats.dateTimeAsUS(epoch, true);
expect(actual).toBe(expected);
});
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).toBe(now.format('h:mm:ss a'));
var expected = now.format('h:mm:ss a');
var actual = kbn.valueFormats.dateTimeAsUS(now.valueOf(), false);
expect(actual).toBe(expected);
});
it('should format as US date (in UTC) and skip date when today', function() {
var now = moment.utc();
var expected = now.format('h:mm:ss a');
var actual = kbn.valueFormats.dateTimeAsUS(now.valueOf(), true);
expect(actual).toBe(expected);
});
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).toBe('7 days ago');
var expected = '7 days ago';
var actual = kbn.valueFormats.dateTimeFromNow(daysAgo.valueOf(), false);
expect(actual).toBe(expected);
});
it('should format as from now with days (in UTC)', function() {
var daysAgo = moment.utc().add(-7, 'd');
var expected = '7 days ago';
var actual = kbn.valueFormats.dateTimeFromNow(daysAgo.valueOf(), true);
expect(actual).toBe(expected);
});
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).toBe('2 minutes ago');
var expected = '2 minutes ago';
var actual = kbn.valueFormats.dateTimeFromNow(daysAgo.valueOf(), false);
expect(actual).toBe(expected);
});
it('should format as from now with minutes (in UTC)', function() {
var daysAgo = moment.utc().add(-2, 'm');
var expected = '2 minutes ago';
var actual = kbn.valueFormats.dateTimeFromNow(daysAgo.valueOf(), true);
expect(actual).toBe(expected);
});
});
......
......@@ -816,8 +816,8 @@ kbn.valueFormats.timeticks = function(size, decimals, scaledDecimals) {
return kbn.valueFormats.s(size / 100, decimals, scaledDecimals);
};
kbn.valueFormats.dateTimeAsIso = function(epoch) {
var time = moment(epoch);
kbn.valueFormats.dateTimeAsIso = function(epoch, isUtc) {
var time = isUtc ? moment.utc(epoch) : moment(epoch);
if (moment().isSame(epoch, 'day')) {
return time.format('HH:mm:ss');
......@@ -825,8 +825,8 @@ kbn.valueFormats.dateTimeAsIso = function(epoch) {
return time.format('YYYY-MM-DD HH:mm:ss');
};
kbn.valueFormats.dateTimeAsUS = function(epoch) {
var time = moment(epoch);
kbn.valueFormats.dateTimeAsUS = function(epoch, isUtc) {
var time = isUtc ? moment.utc(epoch) : moment(epoch);
if (moment().isSame(epoch, 'day')) {
return time.format('h:mm:ss a');
......@@ -834,8 +834,9 @@ kbn.valueFormats.dateTimeAsUS = function(epoch) {
return time.format('MM/DD/YYYY h:mm:ss a');
};
kbn.valueFormats.dateTimeFromNow = function(epoch) {
return moment(epoch).fromNow();
kbn.valueFormats.dateTimeFromNow = function(epoch, isUtc) {
var time = isUtc ? moment.utc(epoch) : moment(epoch);
return time.fromNow();
};
///// FORMAT MENU /////
......
......@@ -308,7 +308,7 @@ class SingleStatCtrl extends MetricsPanelCtrl {
let formatFunc = kbn.valueFormats[this.panel.format];
data.value = lastPoint[1];
data.valueRounded = data.value;
data.valueFormatted = formatFunc(data.value, 0, 0);
data.valueFormatted = formatFunc(data.value, this.dashboard.isTimezoneUtc());
} else {
data.value = this.series[0].stats[this.panel.valueName];
data.flotpairs = this.series[0].flotpairs;
......
......@@ -82,6 +82,19 @@ describe('SingleStatCtrl', function() {
});
});
singleStatScenario('showing last iso time instead of value (in UTC)', 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';
ctx.setIsUtc(true);
});
it('should set formatted value', function() {
expect(ctx.data.valueFormatted).to.be(moment.utc(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]] }];
......@@ -99,6 +112,19 @@ describe('SingleStatCtrl', function() {
});
});
singleStatScenario('showing last us time instead of value (in UTC)', 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';
ctx.setIsUtc(true);
});
it('should set formatted value', function() {
expect(ctx.data.valueFormatted).to.be(moment.utc(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);
......@@ -124,6 +150,27 @@ describe('SingleStatCtrl', function() {
});
});
singleStatScenario('showing last time from now instead of value (in UTC)', 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';
ctx.setIsUtc(true);
});
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
) {
......
......@@ -23,6 +23,7 @@ export function ControllerTestContext() {
};
},
};
this.isUtc = false;
this.providePhase = function(mocks) {
return angularMocks.module(function($provide) {
......@@ -46,6 +47,10 @@ export function ControllerTestContext() {
self.$q = $q;
self.panel = new PanelModel({ type: 'test' });
self.dashboard = { meta: {} };
self.isUtc = false;
self.dashboard.isTimezoneUtc = function() {
return self.isUtc;
};
$rootScope.appEvent = sinon.spy();
$rootScope.onAppEvent = sinon.spy();
......@@ -93,6 +98,10 @@ export function ControllerTestContext() {
});
});
};
this.setIsUtc = function(isUtc = false) {
self.isUtc = isUtc;
};
}
export function ServiceTestContext() {
......
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