diff --git a/public/app/panels/graph/styleEditor.html b/public/app/panels/graph/styleEditor.html index 5d5f2fd7401..f692328a0fd 100644 --- a/public/app/panels/graph/styleEditor.html +++ b/public/app/panels/graph/styleEditor.html @@ -63,7 +63,7 @@
Series specific overrides Regex match example: /server[0-3]/i
-
+
  • diff --git a/public/app/panels/table/module.ts b/public/app/panels/table/module.ts index 22b087bdfa4..8cb46d6cc46 100644 --- a/public/app/panels/table/module.ts +++ b/public/app/panels/table/module.ts @@ -6,16 +6,13 @@ import _ = require('lodash'); import moment = require('moment'); import PanelMeta = require('app/features/panel/panel_meta'); import TimeSeries = require('app/core/time_series'); -import {TableModel} from './table_model'; - -var panelDefaults = { - targets: [{}], -}; +import {TableModel, transformers} from './table_model'; export class TablePanelCtrl { constructor($scope, $rootScope, $q, panelSrv, panelHelper) { $scope.ctrl = this; + $scope.transformers = transformers; $scope.panelMeta = new PanelMeta({ panelName: 'Table', @@ -27,21 +24,31 @@ export class TablePanelCtrl { $scope.panelMeta.addEditorTab('Options', 'app/panels/table/options.html'); $scope.panelMeta.addEditorTab('Time range', 'app/features/panel/partials/panelTime.html'); + var panelDefaults = { + targets: [{}], + transform: 'timeseries_to_rows' + }; + _.defaults($scope.panel, panelDefaults); $scope.refreshData = function(datasource) { panelHelper.updateTimeRange($scope); return panelHelper.issueMetricQuery($scope, datasource) - .then($scope.dataHandler, function(err) { - $scope.seriesList = []; - $scope.render([]); - throw err; - }); + .then($scope.dataHandler, function(err) { + $scope.seriesList = []; + $scope.render([]); + throw err; + }); }; $scope.dataHandler = function(results) { - $scope.tableModel = TableModel.transform(results.data, $scope.panel); + $scope.dataRaw = results.data; + $scope.render(); + }; + + $scope.render = function() { + $scope.tableModel = TableModel.transform($scope.dataRaw, $scope.panel); panelHelper.broadcastRender($scope, $scope.tableModel); }; diff --git a/public/app/panels/table/options.html b/public/app/panels/table/options.html new file mode 100644 index 00000000000..7f1332b6e18 --- /dev/null +++ b/public/app/panels/table/options.html @@ -0,0 +1,58 @@ +
    +
    +
    Data Table
    +
    +
      +
    • + Data to Table Transform +
    • +
    • + +
    • +
    +
    +
    +
    +
    + +
    +
    +
    Table Display
    +
    +
    + +
    +
    +
    Column Styles
    + +
    +
    +
      +
    • + +
    • + +
    • + alias or regex +
    • + +
    • + +
    • + + +
    +
    +
    +
    + + +
    +
    + diff --git a/public/app/panels/table/specs/table_model_specs.ts b/public/app/panels/table/specs/table_model_specs.ts index 7cb9575eb86..04106100392 100644 --- a/public/app/panels/table/specs/table_model_specs.ts +++ b/public/app/panels/table/specs/table_model_specs.ts @@ -4,25 +4,62 @@ import {TableModel} from '../table_model'; describe('when getting tableData', () => { - describe('simple time series', () => { + describe('timeseries_to_rows', () => { var panel = { + transform: 'timeseries_to_rows' }; - it ('should return 2 columns', () => { + it ('should return 2 rows', () => { var data = TableModel.transform([ { - target: 'test', + target: 'series1', + datapoints: [[12.12, new Date().getTime()]], + }, + { + target: 'series2', datapoints: [[12.12, new Date().getTime()]], } ], panel); - expect(data.columns.length).to.be(2); + expect(data.columns.length).to.be(3); + expect(data.rows.length).to.be(2); + + expect(data.columns[0].text).to.be('Time'); + expect(data.columns[1].text).to.be('Series'); + expect(data.columns[2].text).to.be('Value'); + expect(data.rows[0][1]).to.be('series1'); + expect(data.rows[0][2]).to.be('12.12'); + + expect(data.rows[1][1]).to.be('series2'); + }); + }); + + describe('timeseries_to_rows', () => { + var panel = { + transform: 'timeseries_to_columns' + }; + + it ('should return 3 columns', () => { + var data = TableModel.transform([ + { + target: 'series1', + datapoints: [[12.12, new Date().getTime()]], + }, + { + target: 'series2', + datapoints: [[16.12, new Date().getTime()]], + } + ], panel); + + expect(data.columns.length).to.be(3); expect(data.rows.length).to.be(1); expect(data.columns[0].text).to.be('Time'); - expect(data.columns[1].text).to.be('Value'); + expect(data.columns[1].text).to.be('series1'); + expect(data.columns[2].text).to.be('series2'); + expect(data.rows[0][1]).to.be('12.12'); + expect(data.rows[0][2]).to.be('16.12'); }); - }); }); diff --git a/public/app/panels/table/table_model.ts b/public/app/panels/table/table_model.ts index 0351f30b33b..9410c36badf 100644 --- a/public/app/panels/table/table_model.ts +++ b/public/app/panels/table/table_model.ts @@ -3,21 +3,17 @@ import moment = require('moment'); import _ = require('lodash'); -export class TableModel { - columns: any[]; - rows: any[]; - - static transform(data, panel) { - var model = new TableModel(); - - if (!data || data.length === 0) { - return model; - } +var transformers = {}; +transformers['timeseries_to_rows'] = { + description: 'Time series to rows', + transform: function(data, panel, model) { model.columns = [ {text: 'Time'}, + {text: 'Series'}, {text: 'Value'}, ]; + model.rows = []; for (var i = 0; i < data.length; i++) { @@ -32,12 +28,71 @@ export class TableModel { value = value.toFixed(2); } - model.rows.push([time, value]); + model.rows.push([time, series.target, value]); + } + } + }, +}; + +transformers['timeseries_to_columns'] = { + description: 'Time series to columns', + transform: function(data, panel, model) { + model.columns = [{text: 'Time'}]; + model.rows = []; + + var points = {}; + + for (var i = 0; i < data.length; i++) { + var series = data[i]; + model.columns.push({text: series.target}); + + for (var y = 0; y < series.datapoints.length; y++) { + var dp = series.datapoints[y]; + var time = dp[1]; + if (!points[time]) { + points[time] = {}; + points[time][i] = [dp[0]]; + } + else { + points[time][i] = dp[0]; + } } } + for (var time in points) { + var point = points[time]; + var values = [time]; + + for (var i = 0; i < data.length; i++) { + if (point[i] !== undefined) { + values.push(point[i]); + } + } + + model.rows.push(values); + } + } +}; + +export {transformers} + +export class TableModel { + columns: any[]; + rows: any[]; + + 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; } } - - diff --git a/public/less/panel_table.less b/public/less/panel_table.less index 8cd62cbb76b..8f7dea39f9a 100644 --- a/public/less/panel_table.less +++ b/public/less/panel_table.less @@ -17,7 +17,6 @@ .gf-table-panel { width: 100%; - table-layout: fixed; border-collapse: collapse; }