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'); + }); }); });