diff --git a/public/app/panels/table/table_model.ts b/public/app/core/table_model.ts similarity index 56% rename from public/app/panels/table/table_model.ts rename to public/app/core/table_model.ts index 1fa4007e6e3..7eb8d5ad92a 100644 --- a/public/app/panels/table/table_model.ts +++ b/public/app/core/table_model.ts @@ -1,12 +1,13 @@ -import {transformers} from './transformers'; -export class TableModel { +class TableModel { columns: any[]; rows: any[]; + type: string; constructor() { this.columns = []; this.rows = []; + this.type = 'table'; } sort(options) { @@ -33,20 +34,6 @@ export class TableModel { this.columns[options.col].desc = true; } } - - static transform(data, panel) { - var model = new TableModel(); - - if (!data || data.length === 0) { - return model; - } - - var transformer = transformers[panel.transform]; - if (!transformer) { - throw {message: 'Transformer ' + panel.transformer + ' not found'}; - } - - transformer.transform(data, panel, model); - return model; - } } + +export = TableModel; diff --git a/public/app/panels/table/controller.ts b/public/app/panels/table/controller.ts index 09e77108631..270e2f65a3d 100644 --- a/public/app/panels/table/controller.ts +++ b/public/app/panels/table/controller.ts @@ -5,7 +5,7 @@ import _ = require('lodash'); import moment = require('moment'); import PanelMeta = require('app/features/panel/panel_meta'); -import {TableModel} from './table_model'; +import {transformDataToTable} from './transformers'; export class TablePanelCtrl { @@ -104,7 +104,23 @@ export class TablePanelCtrl { }; $scope.render = function() { - $scope.table = TableModel.transform($scope.dataRaw, $scope.panel); + // automatically correct transform mode + // based on data + if ($scope.dataRaw && $scope.dataRaw.length) { + if ($scope.dataRaw[0].type === 'table') { + $scope.panel.transform = 'table'; + } else { + if ($scope.dataRaw[0].type === 'docs') { + $scope.panel.transform = 'json'; + } else { + if ($scope.panel.transform === 'table' || $scope.panel.transform === 'json') { + $scope.panel.transform = 'timeseries_to_rows'; + } + } + } + } + + $scope.table = transformDataToTable($scope.dataRaw, $scope.panel); $scope.table.sort($scope.panel.sort); panelHelper.broadcastRender($scope, $scope.table, $scope.dataRaw); }; diff --git a/public/app/panels/table/specs/renderer_specs.ts b/public/app/panels/table/specs/renderer_specs.ts index f8fdebb9ab0..f8af1baba17 100644 --- a/public/app/panels/table/specs/renderer_specs.ts +++ b/public/app/panels/table/specs/renderer_specs.ts @@ -1,6 +1,6 @@ import {describe, beforeEach, it, sinon, expect} from 'test/lib/common'; -import {TableModel} from '../table_model'; +import TableModel = require('app/core/table_model'); import {TableRenderer} from '../renderer'; describe('when rendering table', () => { diff --git a/public/app/panels/table/specs/transformers_specs.ts b/public/app/panels/table/specs/transformers_specs.ts index bb42b997d33..e3cdf44c8b2 100644 --- a/public/app/panels/table/specs/transformers_specs.ts +++ b/public/app/panels/table/specs/transformers_specs.ts @@ -1,7 +1,6 @@ import {describe, beforeEach, it, sinon, expect} from 'test/lib/common'; -import {TableModel} from '../table_model'; -import {transformers} from '../transformers'; +import {transformers, transformDataToTable} from '../transformers'; describe('when transforming time series table', () => { var table; @@ -26,7 +25,7 @@ describe('when transforming time series table', () => { }; beforeEach(() => { - table = TableModel.transform(timeSeries, panel); + table = transformDataToTable(timeSeries, panel); }); it('should return 3 rows', () => { @@ -51,7 +50,7 @@ describe('when transforming time series table', () => { }; beforeEach(() => { - table = TableModel.transform(timeSeries, panel); + table = transformDataToTable(timeSeries, panel); }); it ('should return 3 columns', () => { @@ -80,7 +79,7 @@ describe('when transforming time series table', () => { }; beforeEach(() => { - table = TableModel.transform(timeSeries, panel); + table = transformDataToTable(timeSeries, panel); }); it('should return 2 rows', () => { @@ -133,7 +132,7 @@ describe('when transforming time series table', () => { describe('transform', function() { beforeEach(() => { - table = TableModel.transform(rawData, panel); + table = transformDataToTable(rawData, panel); }); it ('should return 2 columns', () => { @@ -164,7 +163,7 @@ describe('when transforming time series table', () => { ]; beforeEach(() => { - table = TableModel.transform(rawData, panel); + table = transformDataToTable(rawData, panel); }); it ('should return 4 columns', () => { diff --git a/public/app/panels/table/transformers.ts b/public/app/panels/table/transformers.ts index a4d0d4395c5..843eb83c034 100644 --- a/public/app/panels/table/transformers.ts +++ b/public/app/panels/table/transformers.ts @@ -4,6 +4,7 @@ import moment = require('moment'); import _ = require('lodash'); import flatten = require('app/core/utils/flatten'); import TimeSeries = require('app/core/time_series'); +import TableModel = require('app/core/table_model'); var transformers = {}; @@ -136,6 +137,27 @@ transformers['annotations'] = { } }; +transformers['table'] = { + description: 'Table', + getColumns: function(data) { + if (!data || data.length === 0) { + return []; + } + }, + transform: function(data, panel, model) { + if (!data || data.length === 0) { + return; + } + + if (data[0].type !== 'table') { + throw {message: 'Query result is not in table format, try using another transform.'}; + } + + model.columns = data[0].columns; + model.rows = data[0].rows; + } +}; + transformers['json'] = { description: 'JSON Data', getColumns: function(data) { @@ -197,4 +219,20 @@ transformers['json'] = { } }; -export {transformers} +function transformDataToTable(data, panel) { + var model = new TableModel(); + + if (!data || data.length === 0) { + return model; + } + + var transformer = transformers[panel.transform]; + if (!transformer) { + throw {message: 'Transformer ' + panel.transformer + ' not found'}; + } + + transformer.transform(data, panel, model); + return model; +} + +export {transformers, transformDataToTable} diff --git a/public/app/plugins/datasource/influxdb/datasource.js b/public/app/plugins/datasource/influxdb/datasource.js index 9adabe9a83f..a23937cd74c 100644 --- a/public/app/plugins/datasource/influxdb/datasource.js +++ b/public/app/plugins/datasource/influxdb/datasource.js @@ -53,6 +53,7 @@ function (angular, _, dateMath, InfluxSeries, InfluxQuery) { // replace templated variables allQueries = templateSrv.replace(allQueries, options.scopedVars); + return this._seriesQuery(allQueries).then(function(data) { if (!data || !data.results) { return []; @@ -63,13 +64,26 @@ function (angular, _, dateMath, InfluxSeries, InfluxQuery) { var result = data.results[i]; if (!result || !result.series) { continue; } - var alias = (queryTargets[i] || {}).alias; + var target = queryTargets[i]; + var alias = target.alias; if (alias) { - alias = templateSrv.replace(alias, options.scopedVars); + alias = templateSrv.replace(target.alias, options.scopedVars); } - var targetSeries = new InfluxSeries({ series: data.results[i].series, alias: alias }).getTimeSeries(); - for (y = 0; y < targetSeries.length; y++) { - seriesList.push(targetSeries[y]); + + var influxSeries = new InfluxSeries({ series: data.results[i].series, alias: alias }); + + switch(target.resultFormat) { + case 'table': { + seriesList.push(influxSeries.getTable()); + break; + } + default: { + var timeSeries = influxSeries.getTimeSeries(); + for (y = 0; y < timeSeries.length; y++) { + seriesList.push(timeSeries[y]); + } + break; + } } } diff --git a/public/app/plugins/datasource/influxdb/influx_query.ts b/public/app/plugins/datasource/influxdb/influx_query.ts index 34b86e16930..f50627c7f89 100644 --- a/public/app/plugins/datasource/influxdb/influx_query.ts +++ b/public/app/plugins/datasource/influxdb/influx_query.ts @@ -12,6 +12,8 @@ class InfluxQuery { constructor(target) { this.target = target; + target.dsType = 'influxdb'; + target.resultFormat = target.resultFormat || 'time_series'; target.tags = target.tags || []; target.groupBy = target.groupBy || [ {type: 'time', params: ['$interval']}, diff --git a/public/app/plugins/datasource/influxdb/influx_series.js b/public/app/plugins/datasource/influxdb/influx_series.js index fff3536b5e8..63495ffb9b0 100644 --- a/public/app/plugins/datasource/influxdb/influx_series.js +++ b/public/app/plugins/datasource/influxdb/influx_series.js @@ -1,7 +1,8 @@ define([ 'lodash', + 'app/core/table_model', ], -function (_) { +function (_, TableModel) { 'use strict'; function InfluxSeries(options) { @@ -108,5 +109,44 @@ function (_) { return list; }; + p.getTable = function() { + var table = new TableModel(); + var self = this; + var i, j; + + if (self.series.length === 0) { + return table; + } + + _.each(self.series, function(series, seriesIndex) { + + if (seriesIndex === 0) { + table.columns.push({text: 'Time', type: 'time'}); + _.each(_.keys(series.tags), function(key) { + table.columns.push({text: key}); + }); + for (j = 1; j < series.columns.length; j++) { + table.columns.push({text: series.columns[j]}); + } + } + + if (series.values) { + for (i = 0; i < series.values.length; i++) { + var values = series.values[i]; + if (series.tags) { + for (var key in series.tags) { + if (series.tags.hasOwnProperty(key)) { + values.splice(1, 0, series.tags[key]); + } + } + } + table.rows.push(values); + } + } + }); + + return table; + }; + return InfluxSeries; }); diff --git a/public/app/plugins/datasource/influxdb/partials/query.editor.html b/public/app/plugins/datasource/influxdb/partials/query.editor.html index 0aeb8a44224..2b9f7e1a620 100644 --- a/public/app/plugins/datasource/influxdb/partials/query.editor.html +++ b/public/app/plugins/datasource/influxdb/partials/query.editor.html @@ -103,6 +103,12 @@