diff --git a/public/app/features/dashboard/rowCtrl.js b/public/app/features/dashboard/rowCtrl.js index ece5ebdfbf7..5607f1eecac 100644 --- a/public/app/features/dashboard/rowCtrl.js +++ b/public/app/features/dashboard/rowCtrl.js @@ -30,11 +30,6 @@ function (angular, _, config) { $scope.toggleRow = function(row) { row.collapse = row.collapse ? false : true; - if (!row.collapse) { - $timeout(function() { - $scope.$broadcast('render'); - }); - } }; $scope.addPanel = function(panel) { diff --git a/public/app/features/panel/metrics_panel_ctrl.ts b/public/app/features/panel/metrics_panel_ctrl.ts index a2c80ff8b8e..b36c389d9a8 100644 --- a/public/app/features/panel/metrics_panel_ctrl.ts +++ b/public/app/features/panel/metrics_panel_ctrl.ts @@ -53,21 +53,14 @@ class MetricsPanelCtrl extends PanelCtrl { this.datasources = this.datasourceSrv.getMetricSources(); } - loadSnapshot(data) { - // null op - return data; - } - refresh() { // ignore fetching data if another panel is in fullscreen if (this.otherPanelInFullscreenMode()) { return; } // if we have snapshot data use that if (this.panel.snapshotData) { - if (this.loadSnapshot) { - this.updateTimeRange(); - this.loadSnapshot(this.panel.snapshotData); - } + this.updateTimeRange(); + this.events.emit('load-snapshot', this.panel.snapshotData); return; } @@ -83,15 +76,13 @@ class MetricsPanelCtrl extends PanelCtrl { // load datasource service this.datasourceSrv.get(this.panel.datasource) .then(this.issueQueries.bind(this)) - .then(() => { - this.loading = false; - }).catch(err => { - console.log('Panel data error:', err); + .then(this.handleQueryResult.bind(this)) + .catch(err => { this.loading = false; this.error = err.message || "Timeseries data request error"; this.inspector = {error: err}; - this.events.emit('data-error', err); + console.log('Panel data error:', err); }); } @@ -184,29 +175,24 @@ class MetricsPanelCtrl extends PanelCtrl { }; this.setTimeQueryStart(); - try { - return datasource.query(metricsQuery).then(results => { - this.setTimeQueryEnd(); - - // check for if data source returns subject - if (results && results.subscribe) { - this.handleDataStream(results); - return; - } - - if (this.dashboard.snapshot) { - this.panel.snapshotData = results; - } - - return this.events.emit('data-received', results); - }); - } catch (err) { - return this.$q.reject(err); - } + return datasource.query(metricsQuery); } - dataHandler(data) { - return data; + handleQueryResult(result) { + this.setTimeQueryEnd(); + this.loading = false; + + // check for if data source returns subject + if (result && result.subscribe) { + this.handleDataStream(result); + return; + } + + if (this.dashboard.snapshot) { + this.panel.snapshotData = result; + } + + return this.events.emit('data-received', result.data); } handleDataStream(stream) { diff --git a/public/app/features/panel/panel_directive.ts b/public/app/features/panel/panel_directive.ts index addbdf94d53..a9bb75760f5 100644 --- a/public/app/features/panel/panel_directive.ts +++ b/public/app/features/panel/panel_directive.ts @@ -121,7 +121,7 @@ module.directive('panelResizer', function($rootScope) { } scope.$apply(function() { - ctrl.broadcastRender(); + ctrl.render(); }); } diff --git a/public/app/plugins/datasource/graphite/datasource.ts b/public/app/plugins/datasource/graphite/datasource.ts index c5074b275fd..615f0e9eee6 100644 --- a/public/app/plugins/datasource/graphite/datasource.ts +++ b/public/app/plugins/datasource/graphite/datasource.ts @@ -16,38 +16,34 @@ export function GraphiteDatasource(instanceSettings, $q, backendSrv, templateSrv this.render_method = instanceSettings.render_method || 'POST'; this.query = function(options) { - try { - var graphOptions = { - from: this.translateTime(options.rangeRaw.from, false), - until: this.translateTime(options.rangeRaw.to, true), - targets: options.targets, - format: options.format, - cacheTimeout: options.cacheTimeout || this.cacheTimeout, - maxDataPoints: options.maxDataPoints, - }; + var graphOptions = { + from: this.translateTime(options.rangeRaw.from, false), + until: this.translateTime(options.rangeRaw.to, true), + targets: options.targets, + format: options.format, + cacheTimeout: options.cacheTimeout || this.cacheTimeout, + maxDataPoints: options.maxDataPoints, + }; - var params = this.buildGraphiteParams(graphOptions, options.scopedVars); - if (params.length === 0) { - return $q.when([]); - } - - if (options.format === 'png') { - return $q.when(this.url + '/render' + '?' + params.join('&')); - } - - var httpOptions: any = {method: this.render_method, url: '/render'}; - - if (httpOptions.method === 'GET') { - httpOptions.url = httpOptions.url + '?' + params.join('&'); - } else { - httpOptions.data = params.join('&'); - httpOptions.headers = { 'Content-Type': 'application/x-www-form-urlencoded' }; - } - - return this.doGraphiteRequest(httpOptions).then(this.convertDataPointsToMs); - } catch (err) { - return $q.reject(err); + var params = this.buildGraphiteParams(graphOptions, options.scopedVars); + if (params.length === 0) { + return $q.when([]); } + + if (options.format === 'png') { + return $q.when(this.url + '/render' + '?' + params.join('&')); + } + + var httpOptions: any = {method: this.render_method, url: '/render'}; + + if (httpOptions.method === 'GET') { + httpOptions.url = httpOptions.url + '?' + params.join('&'); + } else { + httpOptions.data = params.join('&'); + httpOptions.headers = { 'Content-Type': 'application/x-www-form-urlencoded' }; + } + + return this.doGraphiteRequest(httpOptions).then(this.convertDataPointsToMs); }; this.convertDataPointsToMs = function(result) { diff --git a/public/app/plugins/panel/graph/module.ts b/public/app/plugins/panel/graph/module.ts index 1974f743aa3..8ae79827900 100644 --- a/public/app/plugins/panel/graph/module.ts +++ b/public/app/plugins/panel/graph/module.ts @@ -160,17 +160,17 @@ class GraphCtrl extends MetricsPanelCtrl { this.render([]); } - onDataReceived(results) { + onDataReceived(dataList) { // png renderer returns just a url - if (_.isString(results)) { - this.render(results); + if (_.isString(dataList)) { + this.render(dataList); return; } this.datapointsWarning = false; this.datapointsCount = 0; this.datapointsOutside = false; - this.seriesList = _.map(results.data, (series, i) => this.seriesHandler(series, i)); + this.seriesList = dataList.map(this.seriesHandler.bind(this)); this.datapointsWarning = this.datapointsCount === 0 || this.datapointsOutside; this.annotationsPromise.then(annotations => { diff --git a/public/app/plugins/panel/graph/specs/graph_ctrl_specs.ts b/public/app/plugins/panel/graph/specs/graph_ctrl_specs.ts index e46459e2249..dfce4031772 100644 --- a/public/app/plugins/panel/graph/specs/graph_ctrl_specs.ts +++ b/public/app/plugins/panel/graph/specs/graph_ctrl_specs.ts @@ -14,47 +14,19 @@ describe('GraphCtrl', function() { beforeEach(ctx.providePhase()); beforeEach(ctx.createPanelController(GraphCtrl)); - - describe('get_data with 2 series', function() { - beforeEach(function() { - ctx.annotationsSrv.getAnnotations = sinon.stub().returns(ctx.$q.when([])); - ctx.datasource.query = sinon.stub().returns(ctx.$q.when({ - data: [ - { target: 'test.cpu1', datapoints: [[1, 10]]}, - { target: 'test.cpu2', datapoints: [[1, 10]]} - ] - })); - ctx.ctrl.render = sinon.spy(); - ctx.ctrl.refreshData(ctx.datasource); - ctx.scope.$digest(); - }); - - it('should send time series to render', function() { - var data = ctx.ctrl.render.getCall(0).args[0]; - expect(data.length).to.be(2); - }); - - describe('get_data failure following success', function() { - beforeEach(function() { - ctx.datasource.query = sinon.stub().returns(ctx.$q.reject('Datasource Error')); - ctx.ctrl.refreshData(ctx.datasource); - ctx.scope.$digest(); - }); - - }); + beforeEach(() => { + ctx.ctrl.annotationsPromise = Promise.resolve({}); + ctx.ctrl.updateTimeRange(); }); describe('msResolution with second resolution timestamps', function() { beforeEach(function() { - ctx.datasource.query = sinon.stub().returns(ctx.$q.when({ - data: [ - { target: 'test.cpu1', datapoints: [[1234567890, 45], [1234567899, 60]]}, - { target: 'test.cpu2', datapoints: [[1236547890, 55], [1234456709, 90]]} - ] - })); + var data = [ + { target: 'test.cpu1', datapoints: [[1234567890, 45], [1234567899, 60]]}, + { target: 'test.cpu2', datapoints: [[1236547890, 55], [1234456709, 90]]} + ]; ctx.ctrl.panel.tooltip.msResolution = false; - ctx.ctrl.refreshData(ctx.datasource); - ctx.scope.$digest(); + ctx.ctrl.onDataReceived(data); }); it('should not show millisecond resolution tooltip', function() { @@ -64,15 +36,12 @@ describe('GraphCtrl', function() { describe('msResolution with millisecond resolution timestamps', function() { beforeEach(function() { - ctx.datasource.query = sinon.stub().returns(ctx.$q.when({ - data: [ - { target: 'test.cpu1', datapoints: [[1234567890000, 45], [1234567899000, 60]]}, - { target: 'test.cpu2', datapoints: [[1236547890001, 55], [1234456709000, 90]]} - ] - })); + var data = [ + { target: 'test.cpu1', datapoints: [[1234567890000, 45], [1234567899000, 60]]}, + { target: 'test.cpu2', datapoints: [[1236547890001, 55], [1234456709000, 90]]} + ]; ctx.ctrl.panel.tooltip.msResolution = false; - ctx.ctrl.refreshData(ctx.datasource); - ctx.scope.$digest(); + ctx.ctrl.onDataReceived(data); }); it('should show millisecond resolution tooltip', function() { @@ -82,15 +51,12 @@ describe('GraphCtrl', function() { describe('msResolution with millisecond resolution timestamps but with trailing zeroes', function() { beforeEach(function() { - ctx.datasource.query = sinon.stub().returns(ctx.$q.when({ - data: [ - { target: 'test.cpu1', datapoints: [[1234567890000, 45], [1234567899000, 60]]}, - { target: 'test.cpu2', datapoints: [[1236547890000, 55], [1234456709000, 90]]} - ] - })); + var data = [ + { target: 'test.cpu1', datapoints: [[1234567890000, 45], [1234567899000, 60]]}, + { target: 'test.cpu2', datapoints: [[1236547890000, 55], [1234456709000, 90]]} + ]; ctx.ctrl.panel.tooltip.msResolution = false; - ctx.ctrl.refreshData(ctx.datasource); - ctx.scope.$digest(); + ctx.ctrl.onDataReceived(data); }); it('should not show millisecond resolution tooltip', function() { @@ -100,16 +66,13 @@ describe('GraphCtrl', function() { describe('msResolution with millisecond resolution timestamps in one of the series', function() { beforeEach(function() { - ctx.datasource.query = sinon.stub().returns(ctx.$q.when({ - data: [ - { target: 'test.cpu1', datapoints: [[1234567890000, 45], [1234567899000, 60]]}, - { target: 'test.cpu2', datapoints: [[1236547890010, 55], [1234456709000, 90]]}, - { target: 'test.cpu3', datapoints: [[1236547890000, 65], [1234456709000, 120]]} - ] - })); + var data = [ + { target: 'test.cpu1', datapoints: [[1234567890000, 45], [1234567899000, 60]]}, + { target: 'test.cpu2', datapoints: [[1236547890010, 55], [1234456709000, 90]]}, + { target: 'test.cpu3', datapoints: [[1236547890000, 65], [1234456709000, 120]]} + ]; ctx.ctrl.panel.tooltip.msResolution = false; - ctx.ctrl.refreshData(ctx.datasource); - ctx.scope.$digest(); + ctx.ctrl.onDataReceived(data); }); it('should show millisecond resolution tooltip', function() { diff --git a/public/app/plugins/panel/singlestat/module.ts b/public/app/plugins/panel/singlestat/module.ts index 175f49c9ff5..1baee54e973 100644 --- a/public/app/plugins/panel/singlestat/module.ts +++ b/public/app/plugins/panel/singlestat/module.ts @@ -45,7 +45,7 @@ class SingleStatCtrl extends MetricsPanelCtrl { static templateUrl = 'module.html'; series: any[]; - data: any[]; + data: any; fontSizes: any[]; unitFormats: any[]; @@ -53,6 +53,9 @@ class SingleStatCtrl extends MetricsPanelCtrl { constructor($scope, $injector, private $location, private linkSrv) { super($scope, $injector); _.defaults(this.panel, panelDefaults); + + this.events.on('data-received', this.onDataReceived.bind(this)); + this.events.on('data-error', this.onDataError.bind(this)); } initEditMode() { @@ -68,23 +71,27 @@ class SingleStatCtrl extends MetricsPanelCtrl { this.render(); } - refreshData(datasource) { - return this.issueQueries(datasource) - .then(this.dataHandler.bind(this)) - .catch(err => { - this.series = []; - this.render(); - throw err; - }); - } - loadSnapshot(snapshotData) { // give element time to get attached and get dimensions this.$timeout(() => this.dataHandler(snapshotData), 50); } - dataHandler(results) { - this.series = _.map(results.data, this.seriesHandler.bind(this)); + onDataError(err) { + this.onDataReceived({data: []}); + } + + onDataReceived(dataList) { + this.series = dataList.map(this.seriesHandler.bind(this)); + + var data: any = {}; + this.setValues(data); + + data.thresholds = this.panel.thresholds.split(',').map(function(strVale) { + return Number(strVale.trim()); + }); + + data.colorMap = this.panel.colors; + this.data = data; this.render(); } @@ -155,20 +162,6 @@ class SingleStatCtrl extends MetricsPanelCtrl { return result; } - render() { - var data: any = {}; - this.setValues(data); - - data.thresholds = this.panel.thresholds.split(',').map(function(strVale) { - return Number(strVale.trim()); - }); - - data.colorMap = this.panel.colors; - - this.data = data; - this.broadcastRender(); - } - setValues(data) { data.flotpairs = []; diff --git a/public/app/plugins/panel/singlestat/specs/singlestat-specs.ts b/public/app/plugins/panel/singlestat/specs/singlestat-specs.ts index 90bd5339737..dc85454b64a 100644 --- a/public/app/plugins/panel/singlestat/specs/singlestat-specs.ts +++ b/public/app/plugins/panel/singlestat/specs/singlestat-specs.ts @@ -23,12 +23,11 @@ describe('SingleStatCtrl', function() { beforeEach(function() { setupFunc(); - ctx.datasource.query = sinon.stub().returns(ctx.$q.when({ - data: [{target: 'test.cpu1', datapoints: ctx.datapoints}] - })); + var data = [ + {target: 'test.cpu1', datapoints: ctx.datapoints} + ]; - ctx.ctrl.refreshData(ctx.datasource); - ctx.scope.$digest(); + ctx.ctrl.onDataReceived(data); ctx.data = ctx.ctrl.data; }); }; diff --git a/public/app/plugins/panel/table/module.ts b/public/app/plugins/panel/table/module.ts index 7887e210d7a..81e850bc813 100644 --- a/public/app/plugins/panel/table/module.ts +++ b/public/app/plugins/panel/table/module.ts @@ -57,6 +57,9 @@ class TablePanelCtrl extends MetricsPanelCtrl { } _.defaults(this.panel, panelDefaults); + + this.events.on('data-received', this.onDataReceived.bind(this)); + this.events.on('data-error', this.onDataError.bind(this)); } initEditMode() { @@ -70,7 +73,7 @@ class TablePanelCtrl extends MetricsPanelCtrl { return menu; } - refreshData(datasource) { + issueQueries(datasource) { this.pageIndex = 0; if (this.panel.transform === 'annotations') { @@ -80,36 +83,19 @@ class TablePanelCtrl extends MetricsPanelCtrl { }); } - return this.issueQueries(datasource).catch(err => { - this.render(); - throw err; - }); + return super.issueQueries(datasource); } - toggleColumnSort(col, colIndex) { - if (this.panel.sort.col === colIndex) { - if (this.panel.sort.desc) { - this.panel.sort.desc = false; - } else { - this.panel.sort.col = null; - } - } else { - this.panel.sort.col = colIndex; - this.panel.sort.desc = true; - } - + onDataError(err) { + this.dataRaw = []; this.render(); } - dataHandler(results) { - this.dataRaw = results.data; + onDataReceived(dataList) { + this.dataRaw = dataList; this.pageIndex = 0; - this.render(); - } - render() { - // automatically correct transform mode - // based on data + // automatically correct transform mode based on data if (this.dataRaw && this.dataRaw.length) { if (this.dataRaw[0].type === 'table') { this.panel.transform = 'table'; @@ -126,7 +112,22 @@ class TablePanelCtrl extends MetricsPanelCtrl { this.table = transformDataToTable(this.dataRaw, this.panel); this.table.sort(this.panel.sort); - this.broadcastRender(this.table); + this.render(this.table); + } + + toggleColumnSort(col, colIndex) { + if (this.panel.sort.col === colIndex) { + if (this.panel.sort.desc) { + this.panel.sort.desc = false; + } else { + this.panel.sort.col = null; + } + } else { + this.panel.sort.col = colIndex; + this.panel.sort.desc = true; + } + + this.render(); } exportCsv() {