Commit 79120a0b by Torkel Ödegaard

Merge branch 'master' of github.com:grafana/grafana

parents 8d072de5 fdc97010
...@@ -85,8 +85,9 @@ The column styles allow you control how dates and numbers are formatted. ...@@ -85,8 +85,9 @@ The column styles allow you control how dates and numbers are formatted.
1. `Name or regex`: The Name or Regex field controls what columns the rule should be applied to. The regex or name filter will be matched against the column name not against column values. 1. `Name or regex`: The Name or Regex field controls what columns the rule should be applied to. The regex or name filter will be matched against the column name not against column values.
2. `Type`: The three supported types of types are `Number`, `String` and `Date`. 2. `Type`: The three supported types of types are `Number`, `String` and `Date`.
3. `Format`: Specify date format. Only available when `Type` is set to `Date`. 3. `Title`: Title for the column, when using a Regex the title can include replacement strings like `$1`.
4. `Coloring` and `Thresholds`: Specify color mode and thresholds limits. 4. `Format`: Specify date format. Only available when `Type` is set to `Date`.
5. `Unit` and `Decimals`: Specify unit and decimal precision for numbers. 5. `Coloring` and `Thresholds`: Specify color mode and thresholds limits.
6. `Add column style rule`: Add new column rule. 6. `Unit` and `Decimals`: Specify unit and decimal precision for numbers.
7. `Add column style rule`: Add new column rule.
...@@ -77,7 +77,7 @@ function (_, $, coreModule) { ...@@ -77,7 +77,7 @@ function (_, $, coreModule) {
$scope.source = function(query, callback) { $scope.source = function(query, callback) {
$scope.$apply(function() { $scope.$apply(function() {
$scope.getOptions({ measurementFilter: query }).then(function(altSegments) { $scope.getOptions({ $query: query }).then(function(altSegments) {
$scope.altSegments = altSegments; $scope.altSegments = altSegments;
options = _.map($scope.altSegments, function(alt) { return alt.value; }); options = _.map($scope.altSegments, function(alt) { return alt.value; });
......
...@@ -53,7 +53,7 @@ export function exportTableDataToCsv(table) { ...@@ -53,7 +53,7 @@ export function exportTableDataToCsv(table) {
var text = 'sep=;\n'; var text = 'sep=;\n';
// add header // add header
_.each(table.columns, function(column) { _.each(table.columns, function(column) {
text += column.text + ';'; text += (column.title || column.text) + ';';
}); });
text += '\n'; text += '\n';
// process data // process data
......
...@@ -119,7 +119,7 @@ function (queryDef) { ...@@ -119,7 +119,7 @@ function (queryDef) {
} }
query.script_fields = {}, query.script_fields = {},
query.fielddata_fields = [this.timeField]; query.docvalue_fields = [this.timeField];
return query; return query;
}; };
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
<label class="gf-form-label query-keyword width-7">FROM</label> <label class="gf-form-label query-keyword width-7">FROM</label>
<metric-segment segment="ctrl.policySegment" get-options="ctrl.getPolicySegments()" on-change="ctrl.policyChanged()"></metric-segment> <metric-segment segment="ctrl.policySegment" get-options="ctrl.getPolicySegments()" on-change="ctrl.policyChanged()"></metric-segment>
<metric-segment segment="ctrl.measurementSegment" get-options="ctrl.getMeasurements(measurementFilter)" on-change="ctrl.measurementChanged()"></metric-segment> <metric-segment segment="ctrl.measurementSegment" get-options="ctrl.getMeasurements($query)" on-change="ctrl.measurementChanged()"></metric-segment>
</div> </div>
<div class="gf-form"> <div class="gf-form">
......
...@@ -81,8 +81,8 @@ describe('grafanaHeatmap', function () { ...@@ -81,8 +81,8 @@ describe('grafanaHeatmap', function () {
getTimezone: sinon.stub().returns('utc') getTimezone: sinon.stub().returns('utc')
}, },
range: { range: {
from: moment.utc("01 Mar 2017 10:00:00"), from: moment.utc("01 Mar 2017 10:00:00", 'DD MMM YYYY HH:mm:ss'),
to: moment.utc("01 Mar 2017 11:00:00"), to: moment.utc("01 Mar 2017 11:00:00", 'DD MMM YYYY HH:mm:ss'),
}, },
}; };
...@@ -263,5 +263,5 @@ function getTicks(element, axisSelector) { ...@@ -263,5 +263,5 @@ function getTicks(element, axisSelector) {
function formatLocalTime(timeStr) { function formatLocalTime(timeStr) {
let format = "HH:mm"; let format = "HH:mm";
return moment.utc(timeStr).local().format(format); return moment.utc(timeStr, 'DD MMM YYYY HH:mm:ss').local().format(format);
} }
...@@ -21,10 +21,12 @@ export class TablePanelEditorCtrl { ...@@ -21,10 +21,12 @@ export class TablePanelEditorCtrl {
addColumnSegment: any; addColumnSegment: any;
unitFormats: any; unitFormats: any;
getColumnNames: any; getColumnNames: any;
activeStyleIndex: number;
/** @ngInject */ /** @ngInject */
constructor($scope, private $q, private uiSegmentSrv) { constructor($scope, private $q, private uiSegmentSrv) {
$scope.editor = this; $scope.editor = this;
this.activeStyleIndex = 0;
this.panelCtrl = $scope.ctrl; this.panelCtrl = $scope.ctrl;
this.panel = this.panelCtrl.panel; this.panel = this.panelCtrl.panel;
this.transformers = transformers; this.transformers = transformers;
...@@ -104,18 +106,32 @@ export class TablePanelEditorCtrl { ...@@ -104,18 +106,32 @@ export class TablePanelEditorCtrl {
} }
addColumnStyle() { addColumnStyle() {
var columnStyleDefaults = { var newStyleRule = {
unit: 'short', unit: 'short',
type: 'number', type: 'number',
alias: '',
decimals: 2, decimals: 2,
colors: ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], colors: ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"],
colorMode: null, colorMode: null,
pattern: '/.*/', pattern: '',
dateFormat: 'YYYY-MM-DD HH:mm:ss', dateFormat: 'YYYY-MM-DD HH:mm:ss',
thresholds: [], thresholds: [],
}; };
this.panel.styles.push(angular.copy(columnStyleDefaults)); var styles = this.panel.styles;
var stylesCount = styles.length;
var indexToInsert = stylesCount;
// check if last is a catch all rule, then add it before that one
if (stylesCount > 0) {
var last = styles[stylesCount-1];
if (last.pattern === '/.*/') {
indexToInsert = stylesCount-1;
}
}
styles.splice(indexToInsert, 0, newStyleRule);
this.activeStyleIndex = indexToInsert;
} }
removeColumnStyle(style) { removeColumnStyle(style) {
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
<tr> <tr>
<th ng-repeat="col in ctrl.table.columns" ng-hide="col.hidden"> <th ng-repeat="col in ctrl.table.columns" ng-hide="col.hidden">
<div class="table-panel-table-header-inner pointer" ng-click="ctrl.toggleColumnSort(col, $index)"> <div class="table-panel-table-header-inner pointer" ng-click="ctrl.toggleColumnSort(col, $index)">
{{col.text}} {{col.title}}
<span class="table-panel-table-header-controls" ng-if="col.sort"> <span class="table-panel-table-header-controls" ng-if="col.sort">
<i class="fa fa-caret-down" ng-show="col.desc"></i> <i class="fa fa-caret-down" ng-show="col.desc"></i>
<i class="fa fa-caret-up" ng-hide="col.desc"></i> <i class="fa fa-caret-up" ng-hide="col.desc"></i>
......
...@@ -16,6 +16,7 @@ class TablePanelCtrl extends MetricsPanelCtrl { ...@@ -16,6 +16,7 @@ class TablePanelCtrl extends MetricsPanelCtrl {
pageIndex: number; pageIndex: number;
dataRaw: any; dataRaw: any;
table: any; table: any;
renderer: any;
panelDefaults = { panelDefaults = {
targets: [{}], targets: [{}],
...@@ -26,11 +27,13 @@ class TablePanelCtrl extends MetricsPanelCtrl { ...@@ -26,11 +27,13 @@ class TablePanelCtrl extends MetricsPanelCtrl {
{ {
type: 'date', type: 'date',
pattern: 'Time', pattern: 'Time',
alias: 'Time',
dateFormat: 'YYYY-MM-DD HH:mm:ss', dateFormat: 'YYYY-MM-DD HH:mm:ss',
}, },
{ {
unit: 'short', unit: 'short',
type: 'number', type: 'number',
alias: '',
decimals: 2, decimals: 2,
colors: ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], colors: ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"],
colorMode: null, colorMode: null,
...@@ -118,6 +121,9 @@ class TablePanelCtrl extends MetricsPanelCtrl { ...@@ -118,6 +121,9 @@ class TablePanelCtrl extends MetricsPanelCtrl {
render() { render() {
this.table = transformDataToTable(this.dataRaw, this.panel); this.table = transformDataToTable(this.dataRaw, this.panel);
this.table.sort(this.panel.sort); this.table.sort(this.panel.sort);
this.renderer = new TableRenderer(this.panel, this.table, this.dashboard.isTimezoneUtc(), this.$sanitize);
return super.render(this.table); return super.render(this.table);
} }
...@@ -141,8 +147,7 @@ class TablePanelCtrl extends MetricsPanelCtrl { ...@@ -141,8 +147,7 @@ class TablePanelCtrl extends MetricsPanelCtrl {
} }
exportCsv() { exportCsv() {
var renderer = new TableRenderer(this.panel, this.table, this.dashboard.isTimezoneUtc(), this.$sanitize); FileExport.exportTableDataToCsv(this.renderer.render_values());
FileExport.exportTableDataToCsv(renderer.render_values());
} }
link(scope, elem, attrs, ctrl) { link(scope, elem, attrs, ctrl) {
...@@ -162,9 +167,9 @@ class TablePanelCtrl extends MetricsPanelCtrl { ...@@ -162,9 +167,9 @@ class TablePanelCtrl extends MetricsPanelCtrl {
} }
function appendTableRows(tbodyElem) { function appendTableRows(tbodyElem) {
var renderer = new TableRenderer(panel, data, ctrl.dashboard.isTimezoneUtc(), ctrl.$sanitize); ctrl.renderer.setTable(data);
tbodyElem.empty(); tbodyElem.empty();
tbodyElem.html(renderer.render(ctrl.pageIndex)); tbodyElem.html(ctrl.renderer.render(ctrl.pageIndex));
} }
function switchPage(e) { function switchPage(e) {
......
...@@ -5,12 +5,44 @@ import moment from 'moment'; ...@@ -5,12 +5,44 @@ import moment from 'moment';
import kbn from 'app/core/utils/kbn'; import kbn from 'app/core/utils/kbn';
export class TableRenderer { export class TableRenderer {
formaters: any[]; formatters: any[];
colorState: any; colorState: any;
constructor(private panel, private table, private isUtc, private sanitize) { constructor(private panel, private table, private isUtc, private sanitize) {
this.formaters = []; this.initColumns();
}
setTable(table) {
this.table = table;
this.initColumns();
}
initColumns() {
this.formatters = [];
this.colorState = {}; this.colorState = {};
for (let colIndex = 0; colIndex < this.table.columns.length; colIndex++) {
let column = this.table.columns[colIndex];
column.title = column.text;
for (let i = 0; i < this.panel.styles.length; i++) {
let style = this.panel.styles[i];
var regex = kbn.stringToJsRegex(style.pattern);
if (column.text.match(regex)) {
column.style = style;
if (style.alias) {
column.title = column.text.replace(regex, style.alias);
}
break;
}
}
this.formatters[colIndex] = this.createColumnFormatter(column);
}
} }
getColorForValue(value, style) { getColorForValue(value, style) {
...@@ -24,7 +56,7 @@ export class TableRenderer { ...@@ -24,7 +56,7 @@ export class TableRenderer {
return _.first(style.colors); return _.first(style.colors);
} }
defaultCellFormater(v, style) { defaultCellFormatter(v, style) {
if (v === null || v === void 0 || v === undefined) { if (v === null || v === void 0 || v === undefined) {
return ''; return '';
} }
...@@ -40,18 +72,18 @@ export class TableRenderer { ...@@ -40,18 +72,18 @@ export class TableRenderer {
} }
} }
createColumnFormater(style, column) { createColumnFormatter(column) {
if (!style) { if (!column.style) {
return this.defaultCellFormater; return this.defaultCellFormatter;
} }
if (style.type === 'hidden') { if (column.style.type === 'hidden') {
return v => { return v => {
return undefined; return undefined;
}; };
} }
if (style.type === 'date') { if (column.style.type === 'date') {
return v => { return v => {
if (v === undefined || v === null) { if (v === undefined || v === null) {
return '-'; return '-';
...@@ -62,12 +94,12 @@ export class TableRenderer { ...@@ -62,12 +94,12 @@ export class TableRenderer {
if (this.isUtc) { if (this.isUtc) {
date = date.utc(); date = date.utc();
} }
return date.format(style.dateFormat); return date.format(column.style.dateFormat);
}; };
} }
if (style.type === 'number') { if (column.style.type === 'number') {
let valueFormater = kbn.valueFormats[column.unit || style.unit]; let valueFormatter = kbn.valueFormats[column.unit || column.style.unit];
return v => { return v => {
if (v === null || v === void 0) { if (v === null || v === void 0) {
...@@ -75,39 +107,24 @@ export class TableRenderer { ...@@ -75,39 +107,24 @@ export class TableRenderer {
} }
if (_.isString(v)) { if (_.isString(v)) {
return this.defaultCellFormater(v, style); return this.defaultCellFormatter(v, column.style);
} }
if (style.colorMode) { if (column.style.colorMode) {
this.colorState[style.colorMode] = this.getColorForValue(v, style); this.colorState[column.style.colorMode] = this.getColorForValue(v, column.style);
} }
return valueFormater(v, style.decimals, null); return valueFormatter(v, column.style.decimals, null);
}; };
} }
return (value) => { return (value) => {
return this.defaultCellFormater(value, style); return this.defaultCellFormatter(value, column.style);
}; };
} }
formatColumnValue(colIndex, value) { formatColumnValue(colIndex, value) {
if (this.formaters[colIndex]) { return this.formatters[colIndex] ? this.formatters[colIndex](value) : value;
return this.formaters[colIndex](value);
}
for (let i = 0; i < this.panel.styles.length; i++) {
let style = this.panel.styles[i];
let column = this.table.columns[colIndex];
var regex = kbn.stringToJsRegex(style.pattern);
if (column.text.match(regex)) {
this.formaters[colIndex] = this.createColumnFormater(style, column);
return this.formaters[colIndex](value);
}
}
this.formaters[colIndex] = this.defaultCellFormater;
return this.formaters[colIndex](value);
} }
renderCell(columnIndex, value, addWidthHack = false) { renderCell(columnIndex, value, addWidthHack = false) {
...@@ -126,7 +143,7 @@ export class TableRenderer { ...@@ -126,7 +143,7 @@ export class TableRenderer {
// this hack adds header content to cell (not visible) // this hack adds header content to cell (not visible)
var widthHack = ''; var widthHack = '';
if (addWidthHack) { if (addWidthHack) {
widthHack = '<div class="table-panel-width-hack">' + this.table.columns[columnIndex].text + '</div>'; widthHack = '<div class="table-panel-width-hack">' + this.table.columns[columnIndex].title + '</div>';
} }
if (value === undefined) { if (value === undefined) {
......
...@@ -22,13 +22,15 @@ describe('when rendering table', () => { ...@@ -22,13 +22,15 @@ describe('when rendering table', () => {
{ {
pattern: 'Time', pattern: 'Time',
type: 'date', type: 'date',
format: 'LLL' format: 'LLL',
alias: 'Timestamp'
}, },
{ {
pattern: 'Value', pattern: '/(Val)ue/',
type: 'number', type: 'number',
unit: 'ms', unit: 'ms',
decimals: 3, decimals: 3,
alias: '$1'
}, },
{ {
pattern: 'Colored', pattern: 'Colored',
...@@ -132,6 +134,18 @@ describe('when rendering table', () => { ...@@ -132,6 +134,18 @@ describe('when rendering table', () => {
var html = renderer.renderCell(6, 'text <a href="http://google.com">link</a>'); var html = renderer.renderCell(6, 'text <a href="http://google.com">link</a>');
expect(html).to.be('<td>sanitized</td>'); expect(html).to.be('<td>sanitized</td>');
}); });
it('Time column title should be Timestamp', () => {
expect(table.columns[0].title).to.be('Timestamp');
});
it('Value column title should be Val', () => {
expect(table.columns[1].title).to.be('Val');
});
it('Colored column title should be Colored', () => {
expect(table.columns[2].title).to.be('Colored');
});
}); });
}); });
......
...@@ -229,7 +229,7 @@ function transformDataToTable(data, panel) { ...@@ -229,7 +229,7 @@ function transformDataToTable(data, panel) {
var transformer = transformers[panel.transform]; var transformer = transformers[panel.transform];
if (!transformer) { if (!transformer) {
throw {message: 'Transformer ' + panel.transformer + ' not found'}; throw {message: 'Transformer ' + panel.transform + ' not found'};
} }
if (panel.filterNull) { if (panel.filterNull) {
...@@ -239,6 +239,7 @@ function transformDataToTable(data, panel) { ...@@ -239,6 +239,7 @@ function transformDataToTable(data, panel) {
} }
transformer.transform(copyData, panel, model); transformer.transform(copyData, panel, model);
return model; return model;
} }
......
...@@ -68,3 +68,12 @@ ...@@ -68,3 +68,12 @@
top: 1px; top: 1px;
} }
} }
.form-tabs-wrapper {
@include brand-bottom-border();
@include clearfix();
}
.form-tabs-content {
padding: $spacer*2 $spacer;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment