diff --git a/package.json b/package.json index aa89702149f31..4ea5353bcb243 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "@spalger/ui-ace": "0.2.3", "angular": "1.2.28", "angular-bindonce": "0.3.1", + "angular-bootstrap-colorpicker": "3.0.19", "angular-elastic": "2.5.0", "angular-route": "1.2.28", "ansicolors": "0.3.2", diff --git a/src/ui/public/field_editor/field_editor.js b/src/ui/public/field_editor/field_editor.js index 415e4b2b10edf..f62ea74ef1e0a 100644 --- a/src/ui/public/field_editor/field_editor.js +++ b/src/ui/public/field_editor/field_editor.js @@ -1,9 +1,11 @@ define(function (require) { require('ui/field_format_editor'); + require('angular-bootstrap-colorpicker'); + require('angular-bootstrap-colorpicker/css/colorpicker.css'); require('ui/modules') - .get('kibana') + .get('kibana', ['colorpicker.module']) .directive('fieldEditor', function (Private, $sce) { var _ = require('lodash'); var fieldFormats = Private(require('ui/registry/field_formats')); @@ -78,7 +80,7 @@ define(function (require) { if (!changedFormat || !missingFormat) return; // reset to the defaults, but make sure it's an object - self.formatParams = _.assign({}, getFieldFormatType().paramDefaults); + self.formatParams = _.assign({}, _.cloneDeep(getFieldFormatType().paramDefaults)); }); $scope.$watch('editor.formatParams', function () { diff --git a/src/ui/public/stringify/__tests__/_color.js b/src/ui/public/stringify/__tests__/_color.js new file mode 100644 index 0000000000000..b8093ab75a3c6 --- /dev/null +++ b/src/ui/public/stringify/__tests__/_color.js @@ -0,0 +1,38 @@ +describe('Color Format', function () { + var fieldFormats; + var ColorFormat; + var expect = require('expect.js'); + var ngMock = require('ngMock'); + + beforeEach(ngMock.module('kibana')); + beforeEach(ngMock.inject(function (Private) { + fieldFormats = Private(require('ui/registry/field_formats')); + ColorFormat = fieldFormats.getType('color'); + + })); + + it('should add colors if the value is in range', function () { + var colorer = new ColorFormat({ + colors: [{ + range: '100:150', + text: 'blue', + background: 'yellow' + }] + }); + expect(colorer.convert(99, 'html')).to.eql('99'); + expect(colorer.convert(100, 'html')).to.eql('100'); + expect(colorer.convert(150, 'html')).to.eql('150'); + expect(colorer.convert(151, 'html')).to.eql('151'); + }); + + it('should not convert invalid ranges', function () { + var colorer = new ColorFormat({ + colors: [{ + range: '100150', + text: 'blue', + background: 'yellow' + }] + }); + expect(colorer.convert(99, 'html')).to.eql('99'); + }); +}); diff --git a/src/ui/public/stringify/__tests__/_conformance.js b/src/ui/public/stringify/__tests__/_conformance.js index d2488bb89725d..f2be1b24308d8 100644 --- a/src/ui/public/stringify/__tests__/_conformance.js +++ b/src/ui/public/stringify/__tests__/_conformance.js @@ -12,6 +12,7 @@ var formatIds = [ 'ip', 'number', 'percent', + 'color', 'string', 'url', '_source' diff --git a/src/ui/public/stringify/__tests__/index.js b/src/ui/public/stringify/__tests__/index.js index e299349e95b7a..5d848800765fc 100644 --- a/src/ui/public/stringify/__tests__/index.js +++ b/src/ui/public/stringify/__tests__/index.js @@ -4,5 +4,6 @@ describe('Stringify Component', function () { require('./_source'); require('./_string'); require('./_url'); + require('./_color'); require('./_date'); }); diff --git a/src/ui/public/stringify/editors/color.html b/src/ui/public/stringify/editors/color.html new file mode 100644 index 0000000000000..a01a2ea665339 --- /dev/null +++ b/src/ui/public/stringify/editors/color.html @@ -0,0 +1,51 @@ +
+
+
+ +
+ + +
+
+ + +
+
+ + +
+
+ +
+ 123456 +
+
+ +
+
+
+ + + +
diff --git a/src/ui/public/stringify/editors/color.less b/src/ui/public/stringify/editors/color.less new file mode 100644 index 0000000000000..e434e853573bb --- /dev/null +++ b/src/ui/public/stringify/editors/color.less @@ -0,0 +1,17 @@ +.editor-color { + display: flex; + position: relative; + > .form-group { + flex: 1 1 1%; + padding-right: 5px; + &:last-child { + padding-right: 0; + } + } +} + +.editor-color-remove { + position: absolute; + right: 0; + top: -10px; +} diff --git a/src/ui/public/stringify/register.js b/src/ui/public/stringify/register.js index 678217e8b5ce7..242b5052b16be 100644 --- a/src/ui/public/stringify/register.js +++ b/src/ui/public/stringify/register.js @@ -8,4 +8,5 @@ define(function (require) { fieldFormats.register(require('ui/stringify/types/Percent')); fieldFormats.register(require('ui/stringify/types/String')); fieldFormats.register(require('ui/stringify/types/Source')); + fieldFormats.register(require('ui/stringify/types/Color')); }); diff --git a/src/ui/public/stringify/types/Color.js b/src/ui/public/stringify/types/Color.js new file mode 100644 index 0000000000000..7578d6218c2e2 --- /dev/null +++ b/src/ui/public/stringify/types/Color.js @@ -0,0 +1,60 @@ +define(function (require) { + return function _StringProvider(Private) { + require('ui/stringify/editors/color.less'); + + const _ = require('lodash'); + const FieldFormat = Private(require('ui/index_patterns/_field_format/FieldFormat')); + const DEFAULT_COLOR = { + range: `${Number.NEGATIVE_INFINITY}:${Number.POSITIVE_INFINITY}`, + text: '#000000', + background: '#ffffff' + }; + + _.class(_Color).inherits(FieldFormat); + function _Color(params) { + _Color.Super.call(this, params); + } + + _Color.id = 'color'; + _Color.title = 'Color'; + _Color.fieldType = [ + 'number' + ]; + + _Color.editor = { + template: require('ui/stringify/editors/color.html'), + controller($scope) { + $scope.addColor = function () { + $scope.editor.formatParams.colors.push(_.cloneDeep(DEFAULT_COLOR)); + }; + + $scope.removeColor = function (index) { + $scope.editor.formatParams.colors.splice(index, 1); + }; + } + }; + + + _Color.paramDefaults = { + colors: [_.cloneDeep(DEFAULT_COLOR)] + }; + + _Color.prototype._convert = { + html(val) { + const color = _.findLast(this.param('colors'), ({ range }) => { + if (!range) return; + const [start, end] = range.split(':'); + return val >= Number(start) && val <= Number(end); + }); + + if (!color) return _.asPrettyString(val); + + const styleColor = color.text ? `color: ${color.text};` : ''; + const styleBackgroundColor = color.background ? `background-color: ${color.background};` : ''; + return `${_.escape(val)}`; + } + }; + + return _Color; + }; +});