From 6c9b9b360ab08cdc645ee19abe8c2b3e28f52ccb Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Mon, 25 Mar 2019 23:51:10 +0700 Subject: [PATCH] fix(dashboard): time regions spanning across midnight (#16201) Fixes #14590 --- .../panel_tests_graph_time_regions.json | 129 ++++++++++++++---- .../graph/specs/time_region_manager.test.ts | 27 ++++ .../panel/graph/time_region_manager.ts | 107 +++++++-------- 3 files changed, 172 insertions(+), 91 deletions(-) diff --git a/devenv/dev-dashboards/panel_tests_graph_time_regions.json b/devenv/dev-dashboards/panel_tests_graph_time_regions.json index 8d0bae1221c..7803303c9b2 100644 --- a/devenv/dev-dashboards/panel_tests_graph_time_regions.json +++ b/devenv/dev-dashboards/panel_tests_graph_time_regions.json @@ -463,15 +463,105 @@ "align": false, "alignLevel": null } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "gdev-testdata", + "fill": 1, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [ + { + "colorMode": "gray", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.12)", + "from": "22:00", + "line": false, + "lineColor": "rgba(237, 46, 24, 0.60)", + "op": "time", + "to": "00:30" + } + ], + "timeShift": null, + "title": "From 22:00 to 00:30 (crossing midnight)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } } ], "refresh": false, - "schemaVersion": 16, + "schemaVersion": 18, "style": "dark", - "tags": [ - "gdev", - "panel-tests" - ], + "tags": ["gdev", "panel-tests"], "templating": { "list": [] }, @@ -480,32 +570,11 @@ "to": "now" }, "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] }, "timezone": "browser", "title": "Panel Tests - Graph (Time Regions)", "uid": "XMjIZPmik", - "version": 1 -} \ No newline at end of file + "version": 9 +} diff --git a/public/app/plugins/panel/graph/specs/time_region_manager.test.ts b/public/app/plugins/panel/graph/specs/time_region_manager.test.ts index 691247a0f75..266838ce9b0 100644 --- a/public/app/plugins/panel/graph/specs/time_region_manager.test.ts +++ b/public/app/plugins/panel/graph/specs/time_region_manager.test.ts @@ -176,6 +176,33 @@ describe('TimeRegionManager', () => { }); }); + plotOptionsScenario('for time from/to region crossing midnight', ctx => { + const regions = [{ from: '22:00', to: '00:30', fill: true, colorMode: 'red' }]; + const from = moment('2018-12-01T12:00+01:00'); + const to = moment('2018-12-04T08:00+01:00'); + ctx.setup(regions, from, to); + + it('should add 3 markings', () => { + expect(ctx.options.grid.markings.length).toBe(3); + }); + + it('should add one fill between 22:00 and 00:30 each day', () => { + const markings = ctx.options.grid.markings; + + expect(moment(markings[0].xaxis.from).format()).toBe(moment('2018-12-01T23:00:00+01:00').format()); + expect(moment(markings[0].xaxis.to).format()).toBe(moment('2018-12-02T01:30:00+01:00').format()); + expect(markings[0].color).toBe(colorModes.red.color.fill); + + expect(moment(markings[1].xaxis.from).format()).toBe(moment('2018-12-02T23:00:00+01:00').format()); + expect(moment(markings[1].xaxis.to).format()).toBe(moment('2018-12-03T01:30:00+01:00').format()); + expect(markings[1].color).toBe(colorModes.red.color.fill); + + expect(moment(markings[2].xaxis.from).format()).toBe(moment('2018-12-03T23:00:00+01:00').format()); + expect(moment(markings[2].xaxis.to).format()).toBe(moment('2018-12-04T01:30:00+01:00').format()); + expect(markings[2].color).toBe(colorModes.red.color.fill); + }); + }); + plotOptionsScenario('for day of week from/to region', ctx => { const regions = [{ fromDayOfWeek: 7, toDayOfWeek: 7, fill: true, colorMode: 'red' }]; const from = moment('2018-01-01T18:45:05+01:00'); diff --git a/public/app/plugins/panel/graph/time_region_manager.ts b/public/app/plugins/panel/graph/time_region_manager.ts index ea39927bf57..a04096bc371 100644 --- a/public/app/plugins/panel/graph/time_region_manager.ts +++ b/public/app/plugins/panel/graph/time_region_manager.ts @@ -143,70 +143,55 @@ export class TimeRegionManager { regions = []; - if ( - hRange.from.h >= tRange.from.hour() && - hRange.from.h <= tRange.from.hour() && - hRange.from.m >= tRange.from.minute() && - hRange.from.m <= tRange.from.minute() && - hRange.to.h >= tRange.to.hour() && - hRange.to.h <= tRange.to.hour() && - hRange.to.m >= tRange.to.minute() && - hRange.to.m <= tRange.to.minute() - ) { - regions.push({ from: tRange.from.valueOf(), to: tRange.to.startOf('hour').valueOf() }); - } else { - fromStart = moment(tRange.from); - fromStart.set('hour', 0); - fromStart.set('minute', 0); - fromStart.set('second', 0); - fromStart.add(hRange.from.h, 'hours'); - fromStart.add(hRange.from.m, 'minutes'); - fromStart.add(hRange.from.s, 'seconds'); - - while (fromStart.unix() <= tRange.to.unix()) { - while (hRange.from.dayOfWeek && hRange.from.dayOfWeek !== fromStart.isoWeekday()) { - fromStart.add(24, 'hours'); - } - - if (fromStart.unix() > tRange.to.unix()) { - break; - } - - fromEnd = moment(fromStart); - - if (hRange.from.h <= hRange.to.h) { - fromEnd.add(hRange.to.h - hRange.from.h, 'hours'); - } else if (hRange.from.h + hRange.to.h < 23) { - fromEnd.add(hRange.to.h, 'hours'); - - while (fromEnd.hour() !== hRange.to.h) { - fromEnd.add(-1, 'hours'); - } - } else { - fromEnd.add(24 - hRange.from.h, 'hours'); - - while (fromEnd.hour() !== hRange.to.h) { - fromEnd.add(1, 'hours'); - } - } - - fromEnd.set('minute', hRange.to.m); - fromEnd.set('second', hRange.to.s); - - while (hRange.to.dayOfWeek && hRange.to.dayOfWeek !== fromEnd.isoWeekday()) { - fromEnd.add(24, 'hours'); - } - - const outsideRange = - (fromStart.unix() < tRange.from.unix() && fromEnd.unix() < tRange.from.unix()) || - (fromStart.unix() > tRange.to.unix() && fromEnd.unix() > tRange.to.unix()); - - if (!outsideRange) { - regions.push({ from: fromStart.valueOf(), to: fromEnd.valueOf() }); - } + fromStart = moment(tRange.from); + fromStart.set('hour', 0); + fromStart.set('minute', 0); + fromStart.set('second', 0); + fromStart.add(hRange.from.h, 'hours'); + fromStart.add(hRange.from.m, 'minutes'); + fromStart.add(hRange.from.s, 'seconds'); + while (fromStart.unix() <= tRange.to.unix()) { + while (hRange.from.dayOfWeek && hRange.from.dayOfWeek !== fromStart.isoWeekday()) { fromStart.add(24, 'hours'); } + + if (fromStart.unix() > tRange.to.unix()) { + break; + } + + fromEnd = moment(fromStart); + + if (hRange.from.h <= hRange.to.h) { + fromEnd.add(hRange.to.h - hRange.from.h, 'hours'); + } else if (hRange.from.h > hRange.to.h) { + while (fromEnd.hour() !== hRange.to.h) { + fromEnd.add(1, 'hours'); + } + } else { + fromEnd.add(24 - hRange.from.h, 'hours'); + + while (fromEnd.hour() !== hRange.to.h) { + fromEnd.add(1, 'hours'); + } + } + + fromEnd.set('minute', hRange.to.m); + fromEnd.set('second', hRange.to.s); + + while (hRange.to.dayOfWeek && hRange.to.dayOfWeek !== fromEnd.isoWeekday()) { + fromEnd.add(24, 'hours'); + } + + const outsideRange = + (fromStart.unix() < tRange.from.unix() && fromEnd.unix() < tRange.from.unix()) || + (fromStart.unix() > tRange.to.unix() && fromEnd.unix() > tRange.to.unix()); + + if (!outsideRange) { + regions.push({ from: fromStart.valueOf(), to: fromEnd.valueOf() }); + } + + fromStart.add(24, 'hours'); } timeRegionColor = getColor(timeRegion, this.theme);