mirror of
https://github.com/grafana/grafana.git
synced 2024-11-26 02:40:26 -06:00
feat(tablepanel): work on table panel
This commit is contained in:
parent
da9c792ca2
commit
867b838053
@ -63,7 +63,7 @@
|
||||
<div class="editor-row">
|
||||
<div class="section">
|
||||
<h5>Series specific overrides <tip>Regex match example: /server[0-3]/i </tip></h5>
|
||||
<div>
|
||||
<div class="tight-form-container">
|
||||
<div class="tight-form" ng-repeat="override in panel.seriesOverrides" ng-controller="SeriesOverridesCtrl">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item">
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
58
public/app/panels/table/options.html
Normal file
58
public/app/panels/table/options.html
Normal file
@ -0,0 +1,58 @@
|
||||
<div class="editor-row">
|
||||
<div class="tight-form-section">
|
||||
<h5>Data Table</h5>
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item" style="width: 170px">
|
||||
Data to Table Transform
|
||||
</li>
|
||||
<li>
|
||||
<select class="input-xlarge tight-form-input"
|
||||
ng-model="panel.transform"
|
||||
ng-options="k as v.description for (k, v) in transformers"
|
||||
ng-change="render()"></select>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="editor-row">
|
||||
<div class="tight-form-section">
|
||||
<h5>Table Display</h5>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="editor-row">
|
||||
<div class="tight-form-section">
|
||||
<h5>Column Styles</h5>
|
||||
|
||||
<div class="tight-form-container">
|
||||
<div class="tight-form" ng-repeat="column panel.columns">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item">
|
||||
<i class="fa fa-remove pointer" ng-click="removeSeriesOverride(override)"></i>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item">
|
||||
alias or regex
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<input type="text" ng-model="override.alias" bs-typeahead="getColumnNames" ng-blur="render()" data-min-length=0 data-items=100 class="input-medium tight-form-input" >
|
||||
</li>
|
||||
|
||||
<li class="dropdown" dropdown-typeahead="overrideMenu" dropdown-typeahead-on-select="setOverride($item, $subItem)">
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-inverse" style="margin-top: 20px" ng-click="addSeriesOverride()">
|
||||
Add column display rule
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -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');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
.gf-table-panel {
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user