mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
table panel: additional fixes for value to text mapping
Make the value to text mapping more similar to singlestat solution. Adds more tests. Also, allows string to be mapped to other string besides numeric values.
This commit is contained in:
parent
67f0382222
commit
f673ec16d1
@ -70,7 +70,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="section gf-form-group" ng-if="style.type === 'string'">
|
<div class="section gf-form-group" ng-if="style.type === 'string'">
|
||||||
<h5 class="section-heading">Mapping</h5>
|
<h5 class="section-heading">Value Mappings</h5>
|
||||||
<div class="editor-row">
|
<div class="editor-row">
|
||||||
<div class="gf-form-group">
|
<div class="gf-form-group">
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
@ -83,38 +83,37 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form-group" ng-if="style.mappingType==1">
|
<div class="gf-form-group" ng-if="style.mappingType==1">
|
||||||
<div class="gf-form" ng-repeat="mapping in style.valueMappings">
|
<div class="gf-form" ng-repeat="map in style.valueMaps">
|
||||||
<input type="text" class="gf-form-input width-8" ng-model="mapping.value" placeholder="Value" ng-blur="editor.render()" array-join>
|
<span class="gf-form-label">
|
||||||
<label class="gf-form-label width-3">=></label>
|
<i class="fa fa-remove pointer" ng-click="editor.removeValueMap(style, $index)"></i>
|
||||||
<input type="text" class="gf-form-input width-9" ng-model="mapping.text" placeholder="Text" ng-blur="editor.render()" array-join>
|
</span>
|
||||||
|
<input type="text" class="gf-form-input max-width-6" ng-model="map.value" placeholder="Value" ng-blur="editor.render()">
|
||||||
<label class="gf-form-label">
|
<label class="gf-form-label">
|
||||||
<a class="pointer" tabindex="1" ng-click="editor.removeValueMapping(style, $index)">
|
<i class="fa fa-arrow-right"></i>
|
||||||
<i class="fa fa-trash"></i>
|
|
||||||
</a>
|
|
||||||
</label>
|
</label>
|
||||||
|
<input type="text" class="gf-form-input max-width-8" ng-model="map.text" placeholder="Text" ng-blur="editor.render()">
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label">
|
<label class="gf-form-label">
|
||||||
<a class="pointer" ng-click="editor.addValueMapping(style)"><i class="fa fa-plus"></i></a>
|
<a class="pointer" ng-click="editor.addValueMap(style)"><i class="fa fa-plus"></i></a>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form-group" ng-if="style.mappingType==2">
|
<div class="gf-form-group" ng-if="style.mappingType==2">
|
||||||
<div class="gf-form" ng-repeat="mapping in style.rangeMappings">
|
<div class="gf-form" ng-repeat="rangeMap in style.rangeMaps">
|
||||||
<input type="text" class="gf-form-input width-5" ng-model="mapping.from" placeholder="From" ng-blur="editor.render()" array-join>
|
<span class="gf-form-label">
|
||||||
<label class="gf-form-label width-2">-</label>
|
<i class="fa fa-remove pointer" ng-click="editor.removeRangeMap(style, $index)"></i>
|
||||||
<input type="text" class="gf-form-input width-5" ng-model="mapping.to" placeholder="To" ng-blur="editor.render()" array-join>
|
</span>
|
||||||
<label class="gf-form-label width-3">=></label>
|
<span class="gf-form-label">From</span>
|
||||||
<input type="text" class="gf-form-input width-5" ng-model="mapping.text" placeholder="Text" ng-blur="editor.render()" array-join>
|
<input type="text" ng-model="rangeMap.from" class="gf-form-input max-width-6" ng-blur="editor.render()">
|
||||||
<label class="gf-form-label">
|
<span class="gf-form-label">To</span>
|
||||||
<a class="pointer" tabindex="1" ng-click="editor.removeRangeMapping(style, $index)">
|
<input type="text" ng-model="rangeMap.to" class="gf-form-input max-width-6" ng-blur="editor.render()">
|
||||||
<i class="fa fa-trash"></i>
|
<span class="gf-form-label">Text</span>
|
||||||
</a>
|
<input type="text" ng-model="rangeMap.text" class="gf-form-input max-width-8" ng-blur="editor.render()">
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label">
|
<label class="gf-form-label">
|
||||||
<a class="pointer" ng-click="editor.addRangeMapping(style)"><i class="fa fa-plus"></i></a>
|
<a class="pointer" ng-click="editor.addRangeMap(style)"><i class="fa fa-plus"></i></a>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -113,29 +113,30 @@ export class ColumnOptionsCtrl {
|
|||||||
this.render();
|
this.render();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
addValueMapping(style) {
|
|
||||||
if (!style.valueMappings) {
|
addValueMap(style) {
|
||||||
style.valueMappings = [];
|
if (!style.valueMaps) {
|
||||||
|
style.valueMaps = [];
|
||||||
}
|
}
|
||||||
style.valueMappings.push({ value: '', text: '' });
|
style.valueMaps.push({ value: '', text: '' });
|
||||||
this.panelCtrl.render();
|
this.panelCtrl.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
removeValueMapping(style, index) {
|
removeValueMap(style, index) {
|
||||||
style.valueMappings.splice(index, 1);
|
style.valueMaps.splice(index, 1);
|
||||||
this.panelCtrl.render();
|
this.panelCtrl.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
removeRangeMapping(style, index) {
|
addRangeMap(style) {
|
||||||
style.rangeMappings.splice(index, 1);
|
if (!style.rangeMaps) {
|
||||||
this.panelCtrl.render();
|
style.rangeMaps = [];
|
||||||
}
|
|
||||||
|
|
||||||
addRangeMapping(style) {
|
|
||||||
if (!style.rangeMappings) {
|
|
||||||
style.rangeMappings = [];
|
|
||||||
}
|
}
|
||||||
style.rangeMappings.push({ from: '', to: '', text: '' });
|
style.rangeMaps.push({ from: '', to: '', text: '' });
|
||||||
|
this.panelCtrl.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
removeRangeMap(style, index) {
|
||||||
|
style.rangeMaps.splice(index, 1);
|
||||||
this.panelCtrl.render();
|
this.panelCtrl.render();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,6 @@ export class TableRenderer {
|
|||||||
if (!style.thresholds) {
|
if (!style.thresholds) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
value = Number(value);
|
|
||||||
for (var i = style.thresholds.length; i > 0; i--) {
|
for (var i = style.thresholds.length; i > 0; i--) {
|
||||||
if (value >= style.thresholds[i - 1]) {
|
if (value >= style.thresholds[i - 1]) {
|
||||||
return style.colors[i];
|
return style.colors[i];
|
||||||
@ -102,54 +101,54 @@ export class TableRenderer {
|
|||||||
|
|
||||||
if (column.style.type === 'string') {
|
if (column.style.type === 'string') {
|
||||||
return v => {
|
return v => {
|
||||||
if (column.style.valueMappings && column.style.mappingType && column.style.mappingType === 1) {
|
if (_.isArray(v)) {
|
||||||
for (let i = 0; i < column.style.valueMappings.length; i++) {
|
v = v.join(', ');
|
||||||
let mapping = column.style.valueMappings[i];
|
}
|
||||||
var value = Number(mapping.value);
|
|
||||||
if (v === null && mapping.value[0] === 'null') {
|
const mappingType = column.style.mappingType || 0;
|
||||||
return mapping.text;
|
|
||||||
}
|
if (mappingType === 1 && column.style.valueMaps) {
|
||||||
if (v !== null && !_.isArray(v)) {
|
for (let i = 0; i < column.style.valueMaps.length; i++) {
|
||||||
if (Number(v) === value) {
|
const map = column.style.valueMaps[i];
|
||||||
if (!_.isString(v) && !_.isArray(v)) {
|
|
||||||
this.colorState[column.style.colorMode] = this.getColorForValue(v, column.style);
|
if (v === null) {
|
||||||
}
|
if (map.value === 'null') {
|
||||||
return this.defaultCellFormatter(mapping.text, column.style);
|
return map.text;
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow both numeric and string values to be mapped
|
||||||
|
if ((!_.isString(v) && Number(map.value) === Number(v)) || map.value === v) {
|
||||||
|
this.setColorState(v, column.style);
|
||||||
|
return this.defaultCellFormatter(map.text, column.style);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (v !== null && v !== void 0 && !_.isString(v) && !_.isArray(v)) {
|
|
||||||
this.colorState[column.style.colorMode] = this.getColorForValue(v, column.style);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (column.style.rangeMappings && column.style.mappingType && column.style.mappingType === 2) {
|
|
||||||
for (let i = 0; i < column.style.rangeMappings.length; i++) {
|
if (mappingType === 2 && column.style.rangeMaps) {
|
||||||
let mapping = column.style.rangeMappings[i];
|
for (let i = 0; i < column.style.rangeMaps.length; i++) {
|
||||||
var from = mapping.from;
|
const map = column.style.rangeMaps[i];
|
||||||
var to = mapping.to;
|
|
||||||
if (v === null && mapping.from[0] === 'null' && mapping.to[0] === 'null') {
|
if (v === null) {
|
||||||
return mapping.text;
|
if (map.from === 'null' && map.to === 'null') {
|
||||||
|
return map.text;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (
|
|
||||||
v !== null &&
|
if (Number(map.from) <= Number(v) && Number(map.to) >= Number(v)) {
|
||||||
!_.isString(v) &&
|
this.setColorState(v, column.style);
|
||||||
!_.isArray(v) &&
|
return this.defaultCellFormatter(map.text, column.style);
|
||||||
from !== '' &&
|
|
||||||
to !== '' &&
|
|
||||||
Number(from[0]) <= v &&
|
|
||||||
Number(to[0]) >= v
|
|
||||||
) {
|
|
||||||
this.colorState[column.style.colorMode] = this.getColorForValue(v, column.style);
|
|
||||||
return this.defaultCellFormatter(mapping.text, column.style);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (v !== null && v !== void 0 && !_.isString(v) && !_.isArray(v)) {
|
|
||||||
this.colorState[column.style.colorMode] = this.getColorForValue(v, column.style);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (v === null) {
|
|
||||||
|
if (v === null || v === void 0) {
|
||||||
return '-';
|
return '-';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.setColorState(v, column.style);
|
||||||
return this.defaultCellFormatter(v, column.style);
|
return this.defaultCellFormatter(v, column.style);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -166,10 +165,7 @@ export class TableRenderer {
|
|||||||
return this.defaultCellFormatter(v, column.style);
|
return this.defaultCellFormatter(v, column.style);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (column.style.colorMode) {
|
this.setColorState(v, column.style);
|
||||||
this.colorState[column.style.colorMode] = this.getColorForValue(v, column.style);
|
|
||||||
}
|
|
||||||
|
|
||||||
return valueFormatter(v, column.style.decimals, null);
|
return valueFormatter(v, column.style.decimals, null);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -179,6 +175,23 @@ export class TableRenderer {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setColorState(value, style) {
|
||||||
|
if (!style.colorMode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value === null || value === void 0 || _.isArray(value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var numericValue = Number(value);
|
||||||
|
if (numericValue === NaN) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.colorState[style.colorMode] = this.getColorForValue(numericValue, style);
|
||||||
|
}
|
||||||
|
|
||||||
renderRowVariables(rowIndex) {
|
renderRowVariables(rowIndex) {
|
||||||
let scopedVars = {};
|
let scopedVars = {};
|
||||||
let cell_variable;
|
let cell_variable;
|
||||||
|
@ -3,7 +3,7 @@ import TableModel from 'app/core/table_model';
|
|||||||
import { TableRenderer } from '../renderer';
|
import { TableRenderer } from '../renderer';
|
||||||
|
|
||||||
describe('when rendering table', () => {
|
describe('when rendering table', () => {
|
||||||
describe('given 2 columns', () => {
|
describe('given 13 columns', () => {
|
||||||
var table = new TableModel();
|
var table = new TableModel();
|
||||||
table.columns = [
|
table.columns = [
|
||||||
{ text: 'Time' },
|
{ text: 'Time' },
|
||||||
@ -17,8 +17,12 @@ describe('when rendering table', () => {
|
|||||||
{ text: 'Array' },
|
{ text: 'Array' },
|
||||||
{ text: 'Mapping' },
|
{ text: 'Mapping' },
|
||||||
{ text: 'RangeMapping' },
|
{ text: 'RangeMapping' },
|
||||||
|
{ text: 'MappingColored' },
|
||||||
|
{ text: 'RangeMappingColored' },
|
||||||
|
];
|
||||||
|
table.rows = [
|
||||||
|
[1388556366666, 1230, 40, undefined, '', '', 'my.host.com', 'host1', ['value1', 'value2'], 1, 2, 1, 2],
|
||||||
];
|
];
|
||||||
table.rows = [[1388556366666, 1230, 40, undefined, '', '', 'my.host.com', 'host1', ['value1', 'value2'], 1, 2]];
|
|
||||||
|
|
||||||
var panel = {
|
var panel = {
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
@ -82,7 +86,7 @@ describe('when rendering table', () => {
|
|||||||
pattern: 'Mapping',
|
pattern: 'Mapping',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
mappingType: 1,
|
mappingType: 1,
|
||||||
valueMappings: [
|
valueMaps: [
|
||||||
{
|
{
|
||||||
value: '1',
|
value: '1',
|
||||||
text: 'on',
|
text: 'on',
|
||||||
@ -91,13 +95,21 @@ describe('when rendering table', () => {
|
|||||||
value: '0',
|
value: '0',
|
||||||
text: 'off',
|
text: 'off',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
value: 'HELLO WORLD',
|
||||||
|
text: 'HELLO GRAFANA',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'value1, value2',
|
||||||
|
text: 'value3, value4',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
pattern: 'RangeMapping',
|
pattern: 'RangeMapping',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
mappingType: 2,
|
mappingType: 2,
|
||||||
rangeMappings: [
|
rangeMaps: [
|
||||||
{
|
{
|
||||||
from: '1',
|
from: '1',
|
||||||
to: '3',
|
to: '3',
|
||||||
@ -110,6 +122,44 @@ describe('when rendering table', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
pattern: 'MappingColored',
|
||||||
|
type: 'string',
|
||||||
|
mappingType: 1,
|
||||||
|
valueMaps: [
|
||||||
|
{
|
||||||
|
value: '1',
|
||||||
|
text: 'on',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: '0',
|
||||||
|
text: 'off',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
colorMode: 'value',
|
||||||
|
thresholds: [1, 2],
|
||||||
|
colors: ['green', 'orange', 'red'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: 'RangeMappingColored',
|
||||||
|
type: 'string',
|
||||||
|
mappingType: 2,
|
||||||
|
rangeMaps: [
|
||||||
|
{
|
||||||
|
from: '1',
|
||||||
|
to: '3',
|
||||||
|
text: 'on',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: '3',
|
||||||
|
to: '6',
|
||||||
|
text: 'off',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
colorMode: 'value',
|
||||||
|
thresholds: [2, 5],
|
||||||
|
colors: ['green', 'orange', 'red'],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -231,25 +281,85 @@ describe('when rendering table', () => {
|
|||||||
expect(html).toBe('<td>value1, value2</td>');
|
expect(html).toBe('<td>value1, value2</td>');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('value should be mapped to text', () => {
|
it('numeric value should be mapped to text', () => {
|
||||||
var html = renderer.renderCell(9, 0, 1);
|
var html = renderer.renderCell(9, 0, 1);
|
||||||
expect(html).toBe('<td>on</td>');
|
expect(html).toBe('<td>on</td>');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('value should be mapped to text', () => {
|
it('string numeric value should be mapped to text', () => {
|
||||||
var html = renderer.renderCell(9, 0, 0);
|
var html = renderer.renderCell(9, 0, '0');
|
||||||
expect(html).toBe('<td>off</td>');
|
expect(html).toBe('<td>off</td>');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('value should be mapped to text(range)', () => {
|
it('string value should be mapped to text', () => {
|
||||||
|
var html = renderer.renderCell(9, 0, 'HELLO WORLD');
|
||||||
|
expect(html).toBe('<td>HELLO GRAFANA</td>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('array column value should be mapped to text', () => {
|
||||||
|
var html = renderer.renderCell(9, 0, ['value1', 'value2']);
|
||||||
|
expect(html).toBe('<td>value3, value4</td>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('value should be mapped to text (range)', () => {
|
||||||
var html = renderer.renderCell(10, 0, 2);
|
var html = renderer.renderCell(10, 0, 2);
|
||||||
expect(html).toBe('<td>on</td>');
|
expect(html).toBe('<td>on</td>');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('value should be mapped to text(range)', () => {
|
it('value should be mapped to text (range)', () => {
|
||||||
var html = renderer.renderCell(10, 0, 5);
|
var html = renderer.renderCell(10, 0, 5);
|
||||||
expect(html).toBe('<td>off</td>');
|
expect(html).toBe('<td>off</td>');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('array column value should not be mapped to text', () => {
|
||||||
|
var html = renderer.renderCell(10, 0, ['value1', 'value2']);
|
||||||
|
expect(html).toBe('<td>value1, value2</td>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('value should be mapped to text and colored cell should have style', () => {
|
||||||
|
var html = renderer.renderCell(11, 0, 1);
|
||||||
|
expect(html).toBe('<td style="color:orange">on</td>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('value should be mapped to text and colored cell should have style', () => {
|
||||||
|
var html = renderer.renderCell(11, 0, '1');
|
||||||
|
expect(html).toBe('<td style="color:orange">on</td>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('value should be mapped to text and colored cell should have style', () => {
|
||||||
|
var html = renderer.renderCell(11, 0, 0);
|
||||||
|
expect(html).toBe('<td style="color:green">off</td>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('value should be mapped to text and colored cell should have style', () => {
|
||||||
|
var html = renderer.renderCell(11, 0, '0');
|
||||||
|
expect(html).toBe('<td style="color:green">off</td>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('value should be mapped to text and colored cell should have style', () => {
|
||||||
|
var html = renderer.renderCell(11, 0, '2.1');
|
||||||
|
expect(html).toBe('<td style="color:red">2.1</td>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('value should be mapped to text (range) and colored cell should have style', () => {
|
||||||
|
var html = renderer.renderCell(12, 0, 0);
|
||||||
|
expect(html).toBe('<td style="color:green">0</td>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('value should be mapped to text (range) and colored cell should have style', () => {
|
||||||
|
var html = renderer.renderCell(12, 0, 1);
|
||||||
|
expect(html).toBe('<td style="color:green">on</td>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('value should be mapped to text (range) and colored cell should have style', () => {
|
||||||
|
var html = renderer.renderCell(12, 0, 4);
|
||||||
|
expect(html).toBe('<td style="color:orange">off</td>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('value should be mapped to text (range) and colored cell should have style', () => {
|
||||||
|
var html = renderer.renderCell(12, 0, '7.1');
|
||||||
|
expect(html).toBe('<td style="color:red">7.1</td>');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user