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);
} }
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
<div class="section gf-form-group"> <div class="section gf-form-group">
<h5 class="section-heading">Table Display</h5> <h5 class="section-heading">Table Display</h5>
<div class="gf-form-inline">
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label width-8">Rows per page</label> <label class="gf-form-label width-8">Rows per page</label>
<input type="number" class="gf-form-input width-6" <input type="number" class="gf-form-input width-6"
...@@ -38,10 +37,10 @@ ...@@ -38,10 +37,10 @@
ng-change="editor.render()" ng-change="editor.render()"
ng-model-onblur> ng-model-onblur>
</div> </div>
<gf-form-switch class="gf-form" label-class="width-4" label="Scroll" checked="editor.panel.scroll" on-change="editor.render()"></gf-form-switch> <gf-form-switch class="gf-form" label-class="width-8" switch-class="max-width-6" label="Scroll" checked="editor.panel.scroll" on-change="editor.render()"></gf-form-switch>
<div class="gf-form max-width-17"> <div class="gf-form max-width-17">
<label class="gf-form-label width-6">Font size</label> <label class="gf-form-label width-8">Font size</label>
<div class="gf-form-select-wrapper max-width-15"> <div class="gf-form-select-wrapper width-6">
<select class="gf-form-input" <select class="gf-form-input"
ng-model="editor.panel.fontSize" ng-model="editor.panel.fontSize"
ng-options="f for f in editor.fontSizes" ng-options="f for f in editor.fontSizes"
...@@ -49,70 +48,83 @@ ...@@ -49,70 +48,83 @@
</div> </div>
</div> </div>
</div> </div>
</div>
</div> </div>
<div class="editor-row"> <h5 class="section-heading">
<span style="padding-right: 10px;">Column Style Rules</span>
<button class="btn btn-secondary btn-small" ng-click="editor.addColumnStyle()">
<i class="fa fa-plus"></i>&nbsp;Add
</button>
</h5>
<div class="form-tabs-wrapper">
<ul class="gf-tabs">
<li class="gf-tabs-item" ng-repeat="style in editor.panel.styles">
<a class="gf-tabs-link" ng-click="editor.activeStyleIndex = $index" ng-class="{active: editor.activeStyleIndex === $index}">{{style.pattern || 'New rule'}}</a>
</li>
</ul>
</div>
<div class="form-tabs-content" ng-repeat="style in editor.panel.styles" ng-if="editor.activeStyleIndex === $index">
<div class="section gf-form-group"> <div class="section gf-form-group">
<h5 class="section-heading">Column Styles</h5> <h5 class="section-heading">Options</h5>
<div ng-repeat="style in editor.panel.styles">
<div class="gf-form-inline"> <div class="gf-form-inline">
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label">Name or regex</label> <label class="gf-form-label width-13">Apply to columns named</label>
<input type="text" class="gf-form-input" ng-model="style.pattern" bs-typeahead="editor.getColumnNames" ng-blur="editor.render()" data-min-length=0 data-items=100 ng-model-onblur> <input type="text" placeholder="Name or regex" class="gf-form-input width-13" ng-model="style.pattern" bs-tooltip="'Specify regex using /my.*regex/ syntax'" bs-typeahead="editor.getColumnNames" ng-blur="editor.render()" data-min-length=0 data-items=100 ng-model-onblur data-placement="right">
</div>
</div> </div>
<div class="gf-form" ng-if="style.type !== 'hidden'">
<label class="gf-form-label width-13">Column Header</label>
<input type="text" class="gf-form-input width-13" ng-model="style.alias" ng-change="editor.render()" ng-model-onblur placeholder="Override header label">
</div>
</div>
<div class="section gf-form-group">
<h5 class="section-heading">Type</h5>
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label">Type</label> <label class="gf-form-label width-8">Type</label>
<div class="gf-form-select-wrapper"> <div class="gf-form-select-wrapper width-12">
<select class="gf-form-input" ng-model="style.type" ng-options="c.value as c.text for c in editor.columnTypes" ng-change="editor.render()"></select> <select class="gf-form-input" ng-model="style.type" ng-options="c.value as c.text for c in editor.columnTypes" ng-change="editor.render()"></select>
</div> </div>
</div> </div>
<div class="gf-form" ng-if="style.type === 'date'"> <div class="gf-form" ng-if="style.type === 'date'">
<label class="gf-form-label">Format</label> <label class="gf-form-label width-8">Date Format</label>
<metric-segment-model property="style.dateFormat" options="editor.dateFormats" on-change="editor.render()" custom="true"></metric-segment-model> <metric-segment-model property="style.dateFormat" options="editor.dateFormats" on-change="editor.render()" custom="true"></metric-segment-model>
</div> </div>
<div ng-if="style.type === 'string'">
<gf-form-switch class="gf-form" label-class="width-8" ng-if="style.type === 'string'" label="Sanitize HTML" checked="style.sanitize" change="editor.render()"></gf-form-switch> <gf-form-switch class="gf-form" label-class="width-8" ng-if="style.type === 'string'" label="Sanitize HTML" checked="style.sanitize" change="editor.render()"></gf-form-switch>
<div class="gf-form gf-form--grow">
<div class="gf-form-label gf-form-label--grow"></div>
</div>
<div class="gf-form">
<label class="gf-form-label">
<a class="pointer" ng-click="editor.removeColumnStyle(style)">
<i class="fa fa-trash"></i>
</a>
</label>
</div>
</div> </div>
<div class="gf-form-inline" ng-if="style.type === 'number'"> <div ng-if="style.type === 'number'">
<div class="gf-form offset-width-8">
<label class="gf-form-label width-8">Unit</label>
</div>
<div class="gf-form"> <div class="gf-form">
<div class="gf-form-dropdown-typeahead" ng-model="style.unit" dropdown-typeahead2="editor.unitFormats" dropdown-typeahead-on-select="editor.setUnitFormat(style, $subItem)"></div> <label class="gf-form-label width-8">Unit</label>
<div class="gf-form-dropdown-typeahead width-12" ng-model="style.unit" dropdown-typeahead2="editor.unitFormats" dropdown-typeahead-on-select="editor.setUnitFormat(style, $subItem)"></div>
</div> </div>
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label">Decimals</label> <label class="gf-form-label width-8">Decimals</label>
<input type="number" class="gf-form-input width-4" data-placement="right" ng-model="style.decimals" ng-change="editor.render()" ng-model-onblur> <input type="number" class="gf-form-input width-4" data-placement="right" ng-model="style.decimals" ng-change="editor.render()" ng-model-onblur>
</div> </div>
<div class="gf-form">
<label class="gf-form-label">Coloring</label>
<div class="gf-form-select-wrapper">
<select class="gf-form-input" ng-model="style.colorMode" ng-options="c.value as c.text for c in editor.colorModes" ng-change="editor.render()"></select>
</div>
</div>
<div class="gf-form gf-form--grow">
<div class="gf-form-label gf-form-label--grow"></div>
</div> </div>
</div> </div>
<div class="gf-form-inline" ng-if="style.type === 'number'"> <div class="section gf-form-group" ng-if="style.type === 'number'">
<div class="gf-form offset-width-8"> <h5 class="section-heading">Thresholds</h5>
<div class="gf-form">
<label class="gf-form-label width-8">Thresholds<tip>Comma separated values</tip></label> <label class="gf-form-label width-8">Thresholds<tip>Comma separated values</tip></label>
<input type="text" class="gf-form-input width-10" ng-model="style.thresholds" placeholder="50,80" ng-blur="editor.render()" array-join ng-model-onblur> <input type="text" class="gf-form-input width-10" ng-model="style.thresholds" placeholder="50,80" ng-blur="editor.render()" array-join ng-model-onblur>
</div> </div>
<div class="gf-form"> <div class="gf-form">
<label class="gf-form-label width-5">Colors</label> <label class="gf-form-label width-8">Color Mode</label>
<div class="gf-form-select-wrapper width-10">
<select class="gf-form-input" ng-model="style.colorMode" ng-options="c.value as c.text for c in editor.colorModes" ng-change="editor.render()"></select>
</div>
</div>
<div class="gf-form">
<label class="gf-form-label width-8">Colors</label>
<span class="gf-form-label"> <span class="gf-form-label">
<spectrum-picker ng-model="style.colors[0]" ng-change="editor.render()"></spectrum-picker> <spectrum-picker ng-model="style.colors[0]" ng-change="editor.render()"></spectrum-picker>
</span> </span>
...@@ -122,19 +134,17 @@ ...@@ -122,19 +134,17 @@
<span class="gf-form-label"> <span class="gf-form-label">
<spectrum-picker ng-model="style.colors[2]" ng-change="editor.render()"></spectrum-picker> <spectrum-picker ng-model="style.colors[2]" ng-change="editor.render()"></spectrum-picker>
</span> </span>
</div> <div class="gf-form-label">
<div class="gf-form gf-form--grow">
<div class="gf-form-label gf-form-label--grow">
<a class="pointer" ng-click="editor.invertColorOrder($index)">Invert</a> <a class="pointer" ng-click="editor.invertColorOrder($index)">Invert</a>
</div> </div>
</div> </div>
</div> </div>
</div> <div class="clearfix"></div>
</div>
<div class="gf-form-button"> <button class="btn btn-danger btn-small" ng-click="editor.removeColumnStyle(style)">
<button class="btn btn-inverse" ng-click="editor.addColumnStyle()"> <i class="fa fa-trash"></i> Remove Rule
<i class="fa fa-plus"></i>&nbsp;Add column style rule
</button> </button>
</div> <br />
<br />
</div> </div>
...@@ -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