From f673ec16d1ebeecb1a6484d3b0283d1cae111310 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Tue, 27 Mar 2018 19:04:45 +0200 Subject: [PATCH] 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. --- .../plugins/panel/table/column_options.html | 41 +++--- .../app/plugins/panel/table/column_options.ts | 31 +++-- public/app/plugins/panel/table/renderer.ts | 99 ++++++++------ .../panel/table/specs/renderer.jest.ts | 128 ++++++++++++++++-- 4 files changed, 211 insertions(+), 88 deletions(-) diff --git a/public/app/plugins/panel/table/column_options.html b/public/app/plugins/panel/table/column_options.html index ad0c2a3eb1c..9e8e4b404ae 100644 --- a/public/app/plugins/panel/table/column_options.html +++ b/public/app/plugins/panel/table/column_options.html @@ -70,7 +70,7 @@
-
Mapping
+
Value Mappings
@@ -83,38 +83,37 @@
-
- - - +
+ + + + +
-
- - - - - - +
+ + + + From + + To + + Text +
diff --git a/public/app/plugins/panel/table/column_options.ts b/public/app/plugins/panel/table/column_options.ts index b272309c011..463ab5d77a8 100644 --- a/public/app/plugins/panel/table/column_options.ts +++ b/public/app/plugins/panel/table/column_options.ts @@ -113,29 +113,30 @@ export class ColumnOptionsCtrl { this.render(); }; } - addValueMapping(style) { - if (!style.valueMappings) { - style.valueMappings = []; + + addValueMap(style) { + if (!style.valueMaps) { + style.valueMaps = []; } - style.valueMappings.push({ value: '', text: '' }); + style.valueMaps.push({ value: '', text: '' }); this.panelCtrl.render(); } - removeValueMapping(style, index) { - style.valueMappings.splice(index, 1); + removeValueMap(style, index) { + style.valueMaps.splice(index, 1); this.panelCtrl.render(); } - removeRangeMapping(style, index) { - style.rangeMappings.splice(index, 1); - this.panelCtrl.render(); - } - - addRangeMapping(style) { - if (!style.rangeMappings) { - style.rangeMappings = []; + addRangeMap(style) { + if (!style.rangeMaps) { + style.rangeMaps = []; } - 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(); } } diff --git a/public/app/plugins/panel/table/renderer.ts b/public/app/plugins/panel/table/renderer.ts index 149fd2a72f3..78f224d723f 100644 --- a/public/app/plugins/panel/table/renderer.ts +++ b/public/app/plugins/panel/table/renderer.ts @@ -47,7 +47,6 @@ export class TableRenderer { if (!style.thresholds) { return null; } - value = Number(value); for (var i = style.thresholds.length; i > 0; i--) { if (value >= style.thresholds[i - 1]) { return style.colors[i]; @@ -102,54 +101,54 @@ export class TableRenderer { if (column.style.type === 'string') { return v => { - if (column.style.valueMappings && column.style.mappingType && column.style.mappingType === 1) { - for (let i = 0; i < column.style.valueMappings.length; i++) { - let mapping = column.style.valueMappings[i]; - var value = Number(mapping.value); - if (v === null && mapping.value[0] === 'null') { - return mapping.text; - } - if (v !== null && !_.isArray(v)) { - if (Number(v) === value) { - if (!_.isString(v) && !_.isArray(v)) { - this.colorState[column.style.colorMode] = this.getColorForValue(v, column.style); - } - return this.defaultCellFormatter(mapping.text, column.style); + if (_.isArray(v)) { + v = v.join(', '); + } + + const mappingType = column.style.mappingType || 0; + + if (mappingType === 1 && column.style.valueMaps) { + for (let i = 0; i < column.style.valueMaps.length; i++) { + const map = column.style.valueMaps[i]; + + if (v === null) { + if (map.value === 'null') { + 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++) { - let mapping = column.style.rangeMappings[i]; - var from = mapping.from; - var to = mapping.to; - if (v === null && mapping.from[0] === 'null' && mapping.to[0] === 'null') { - return mapping.text; + + if (mappingType === 2 && column.style.rangeMaps) { + for (let i = 0; i < column.style.rangeMaps.length; i++) { + const map = column.style.rangeMaps[i]; + + if (v === null) { + if (map.from === 'null' && map.to === 'null') { + return map.text; + } + continue; } - if ( - v !== null && - !_.isString(v) && - !_.isArray(v) && - 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 (Number(map.from) <= Number(v) && Number(map.to) >= Number(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 (v === null) { + + if (v === null || v === void 0) { return '-'; } + + this.setColorState(v, column.style); return this.defaultCellFormatter(v, column.style); }; } @@ -166,10 +165,7 @@ export class TableRenderer { return this.defaultCellFormatter(v, column.style); } - if (column.style.colorMode) { - this.colorState[column.style.colorMode] = this.getColorForValue(v, column.style); - } - + this.setColorState(v, column.style); 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) { let scopedVars = {}; let cell_variable; diff --git a/public/app/plugins/panel/table/specs/renderer.jest.ts b/public/app/plugins/panel/table/specs/renderer.jest.ts index bd35699f6e5..22957d1aa66 100644 --- a/public/app/plugins/panel/table/specs/renderer.jest.ts +++ b/public/app/plugins/panel/table/specs/renderer.jest.ts @@ -3,7 +3,7 @@ import TableModel from 'app/core/table_model'; import { TableRenderer } from '../renderer'; describe('when rendering table', () => { - describe('given 2 columns', () => { + describe('given 13 columns', () => { var table = new TableModel(); table.columns = [ { text: 'Time' }, @@ -17,8 +17,12 @@ describe('when rendering table', () => { { text: 'Array' }, { text: 'Mapping' }, { 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 = { pageSize: 10, @@ -82,7 +86,7 @@ describe('when rendering table', () => { pattern: 'Mapping', type: 'string', mappingType: 1, - valueMappings: [ + valueMaps: [ { value: '1', text: 'on', @@ -91,13 +95,21 @@ describe('when rendering table', () => { value: '0', text: 'off', }, + { + value: 'HELLO WORLD', + text: 'HELLO GRAFANA', + }, + { + value: 'value1, value2', + text: 'value3, value4', + }, ], }, { pattern: 'RangeMapping', type: 'string', mappingType: 2, - rangeMappings: [ + rangeMaps: [ { from: '1', 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('value1, value2'); }); - it('value should be mapped to text', () => { + it('numeric value should be mapped to text', () => { var html = renderer.renderCell(9, 0, 1); expect(html).toBe('on'); }); - it('value should be mapped to text', () => { - var html = renderer.renderCell(9, 0, 0); + it('string numeric value should be mapped to text', () => { + var html = renderer.renderCell(9, 0, '0'); expect(html).toBe('off'); }); - 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('HELLO GRAFANA'); + }); + + it('array column value should be mapped to text', () => { + var html = renderer.renderCell(9, 0, ['value1', 'value2']); + expect(html).toBe('value3, value4'); + }); + + it('value should be mapped to text (range)', () => { var html = renderer.renderCell(10, 0, 2); expect(html).toBe('on'); }); - it('value should be mapped to text(range)', () => { + it('value should be mapped to text (range)', () => { var html = renderer.renderCell(10, 0, 5); expect(html).toBe('off'); }); + + it('array column value should not be mapped to text', () => { + var html = renderer.renderCell(10, 0, ['value1', 'value2']); + expect(html).toBe('value1, value2'); + }); + + it('value should be mapped to text and colored cell should have style', () => { + var html = renderer.renderCell(11, 0, 1); + expect(html).toBe('on'); + }); + + it('value should be mapped to text and colored cell should have style', () => { + var html = renderer.renderCell(11, 0, '1'); + expect(html).toBe('on'); + }); + + it('value should be mapped to text and colored cell should have style', () => { + var html = renderer.renderCell(11, 0, 0); + expect(html).toBe('off'); + }); + + it('value should be mapped to text and colored cell should have style', () => { + var html = renderer.renderCell(11, 0, '0'); + expect(html).toBe('off'); + }); + + it('value should be mapped to text and colored cell should have style', () => { + var html = renderer.renderCell(11, 0, '2.1'); + expect(html).toBe('2.1'); + }); + + it('value should be mapped to text (range) and colored cell should have style', () => { + var html = renderer.renderCell(12, 0, 0); + expect(html).toBe('0'); + }); + + it('value should be mapped to text (range) and colored cell should have style', () => { + var html = renderer.renderCell(12, 0, 1); + expect(html).toBe('on'); + }); + + it('value should be mapped to text (range) and colored cell should have style', () => { + var html = renderer.renderCell(12, 0, 4); + expect(html).toBe('off'); + }); + + 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('7.1'); + }); }); });