diff --git a/web_tree_dynamic_colored_field/README.rst b/web_tree_dynamic_colored_field/README.rst new file mode 100644 index 00000000..cd3242cb --- /dev/null +++ b/web_tree_dynamic_colored_field/README.rst @@ -0,0 +1,133 @@ +.. image:: https://img.shields.io/badge/license-AGPL--3-blue.png + :target: https://www.gnu.org/licenses/agpl + :alt: License: AGPL-3 + +============================ +Colorize field in tree views +============================ + +This module aims to add support for dynamically coloring fields in tree view +according to data in the record. + +It provides attributes on fields with the similar syntax as the ``colors`` attribute +in tree tags. + +Further, it provides a ``color_field`` attribute on tree tags's ``colors`` to use +a field's value as color. + +Features +======== + +* Add attribute ``bg_color`` on field's ``options`` to color background of a cell in tree view +* Add attribute ``fg_color`` on field's ``options`` to change text color of a cell in tree view +* Add attribute ``color_field`` on the tree element's ``colors`` to use as color + +Usage +===== + +* In the tree view declaration, put ``options='{"bg_color": "red: customer==True"}`` attribute in the ``field`` tag:: + + ... + + + ... + + ... + + + ... + + With this example, column which renders 'name' field will have its background colored in red. + +* In the tree view declaration, put ``options='{"fg_color": "white:customer == True"}'`` attribute in the ``field`` tag:: + + ... + + + ... + + ... + + + ... + + With this example, column which renders 'name' field will have its text colored in white on a customer records. + +* In the tree view declaration, use ``options='"color_field": "my_color"'`` attribute in the ``tree`` tag:: + + ... + + + ... + + ... + + + ... + +* If you want to use more than one color, you can split the attributes using ';': + +.. code:: + + options='{"fg_color": "red:red_color == True; green:green_color == True"}' + +Example: + +.. code:: xml + + ... + + + ... + + ... + + + ... + + With this example, the content of the field named `my_color` will be used to + populate the `my_color` CSS value. Use a function field to return whichever + color you want depending on the other record values. Note that this + overrides the rest of `colors` attributes, and that you need the tree + to load your field in the first place by adding it as invisible field. + +**Note that you should always use single quotes for fields' ``options`` and wrap nested values in double quotes since ``options`` is a JSON object.** + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues +`_. In case of trouble, please +check there if your issue has already been reported. If you spotted it first, +help us smash it by providing detailed and welcomed feedback. + +Credits +======= + +Images +------ + +* Odoo Community Association: `Icon `_. + +Contributors +------------ + +* Damien Crier +* Holger Brunn +* Artem Kostyuk +* Guewen Baconnier + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit https://odoo-community.org. diff --git a/web_tree_dynamic_colored_field/__init__.py b/web_tree_dynamic_colored_field/__init__.py new file mode 100644 index 00000000..6d4f4bde --- /dev/null +++ b/web_tree_dynamic_colored_field/__init__.py @@ -0,0 +1 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). diff --git a/web_tree_dynamic_colored_field/__manifest__.py b/web_tree_dynamic_colored_field/__manifest__.py new file mode 100644 index 00000000..13e207f1 --- /dev/null +++ b/web_tree_dynamic_colored_field/__manifest__.py @@ -0,0 +1,19 @@ +# Copyright 2015-2018 Camptocamp SA, Damien Crier +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +{ + 'name': 'Colorize field in tree views', + 'summary': 'Allows you to dynamically color fields on tree views', + 'category': 'Hidden/Dependency', + 'version': '12.0.1.0.0', + 'depends': ['web'], + 'author': "Camptocamp, Therp BV, Odoo Community Association (OCA)", + 'license': 'AGPL-3', + 'website': 'https://github.com/OCA/web', + 'demo': [ + "demo/res_users.xml", + ], + 'data': [ + 'views/web_tree_dynamic_colored_field.xml', + ], + 'installable': True, +} diff --git a/web_tree_dynamic_colored_field/demo/res_users.xml b/web_tree_dynamic_colored_field/demo/res_users.xml new file mode 100644 index 00000000..ef364722 --- /dev/null +++ b/web_tree_dynamic_colored_field/demo/res_users.xml @@ -0,0 +1,24 @@ + + + + res.users + + + + color_field: lang + + + { + "bg_color": "#9e1635: login_date == False", + "fg_color": "white: login_date == False" + } + + + { + "bg_color": "blue; #653b5b: login == 'admin'", + "fg_color": "white" + } + + + + diff --git a/web_tree_dynamic_colored_field/i18n/web_tree_dynamic_colored_field.pot b/web_tree_dynamic_colored_field/i18n/web_tree_dynamic_colored_field.pot new file mode 100644 index 00000000..447d3bb3 --- /dev/null +++ b/web_tree_dynamic_colored_field/i18n/web_tree_dynamic_colored_field.pot @@ -0,0 +1,14 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 11.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + diff --git a/web_tree_dynamic_colored_field/readme/CONTRIBUTORS.rst b/web_tree_dynamic_colored_field/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000..a1e31ed6 --- /dev/null +++ b/web_tree_dynamic_colored_field/readme/CONTRIBUTORS.rst @@ -0,0 +1,4 @@ +* Damien Crier +* Holger Brunn +* Artem Kostyuk +* Guewen Baconnier diff --git a/web_tree_dynamic_colored_field/readme/DESCRIPTION.rst b/web_tree_dynamic_colored_field/readme/DESCRIPTION.rst new file mode 100644 index 00000000..c3f632ca --- /dev/null +++ b/web_tree_dynamic_colored_field/readme/DESCRIPTION.rst @@ -0,0 +1,15 @@ +This module aims to add support for dynamically coloring fields in tree view +according to data in the record. + +It provides attributes on fields with the similar syntax as the ``colors`` attribute +in tree tags. + +Further, it provides a ``color_field`` attribute on tree tags's ``colors`` to use +a field's value as color. + +Features +======== + +* Add attribute ``bg_color`` on field's ``options`` to color background of a cell in tree view +* Add attribute ``fg_color`` on field's ``options`` to change text color of a cell in tree view +* Add attribute ``color_field`` on the tree element's ``colors`` to use as color diff --git a/web_tree_dynamic_colored_field/readme/USAGE.rst b/web_tree_dynamic_colored_field/readme/USAGE.rst new file mode 100644 index 00000000..921a3262 --- /dev/null +++ b/web_tree_dynamic_colored_field/readme/USAGE.rst @@ -0,0 +1,67 @@ +* In the tree view declaration, put ``options='{"bg_color": "red: customer==True"}`` attribute in the ``field`` tag:: + + ... + + + ... + + ... + + + ... + + With this example, column which renders 'name' field will have its background colored in red. + +* In the tree view declaration, put ``options='{"fg_color": "white:customer == True"}'`` attribute in the ``field`` tag:: + + ... + + + ... + + ... + + + ... + + With this example, column which renders 'name' field will have its text colored in white on a customer records. + +* In the tree view declaration, use ``options='"color_field": "my_color"'`` attribute in the ``tree`` tag:: + + ... + + + ... + + ... + + + ... + +* If you want to use more than one color, you can split the attributes using ';': + +.. code:: + + options='{"fg_color": "red:red_color == True; green:green_color == True"}' + +Example: + +.. code:: xml + + ... + + + ... + + ... + + + ... + + With this example, the content of the field named `my_color` will be used to + populate the `my_color` CSS value. Use a function field to return whichever + color you want depending on the other record values. Note that this + overrides the rest of `colors` attributes, and that you need the tree + to load your field in the first place by adding it as invisible field. + +**Note that you should always use single quotes for fields' ``options`` and wrap nested values in double quotes since ``options`` is a JSON object.** diff --git a/web_tree_dynamic_colored_field/static/description/icon.png b/web_tree_dynamic_colored_field/static/description/icon.png new file mode 100644 index 00000000..3a0328b5 Binary files /dev/null and b/web_tree_dynamic_colored_field/static/description/icon.png differ diff --git a/web_tree_dynamic_colored_field/static/src/js/web_tree_dynamic_colored_field.js b/web_tree_dynamic_colored_field/static/src/js/web_tree_dynamic_colored_field.js new file mode 100644 index 00000000..b1aa0407 --- /dev/null +++ b/web_tree_dynamic_colored_field/static/src/js/web_tree_dynamic_colored_field.js @@ -0,0 +1,130 @@ +odoo.define('web_tree_dynamic_colored_field', function (require) { + 'use strict'; + + var ListRenderer = require('web.ListRenderer'); + var pyUtils = require("web.py_utils"); + + ListRenderer.include({ + /** + * Look up for a `color_field` parameter in tree `colors` attribute + * + * @override + */ + _renderBody: function () { + if (this.arch.attrs.colors) { + var colorAttr = this.arch.attrs.colors.split(';'); + if (colorAttr.length > 0) { + var colorField = colorAttr[0].split(':')[1].trim(); + // validate the presence of that field in tree view + if (this.state.data.length && colorField in this.state.data[0].data) { + this.colorField = colorField; + } else { + console.warn( + "No field named '" + colorField + "' present in view." + ); + } + } + } + return this._super(); + }, + /** + * Colorize a cell during it's render + * + * @override + */ + _renderBodyCell: function (record, node, colIndex, options) { + var $td = this._super.apply(this, arguments); + var ctx = this.getEvalContext(record); + this.applyColorize($td, record, node, ctx); + return $td; + }, + + /** + * Colorize the current cell depending on expressions provided. + * + * @param {Query Node} $td a tag inside a table representing a list view + * @param {Object} node an XML node (must be a ) + */ + applyColorize: function ($td, record, node, ctx) { + // safely resolve value of `color_field` given in + var treeColor = record.data[this.colorField]; + if (treeColor) { + $td.css('color', treeColor); + } + // apply 's own `options` + if (!node.attrs.options) { return; } + if (node.tag !== 'field') { return; } + var nodeOptions = node.attrs.options; + if (!_.isObject(nodeOptions)) { + nodeOptions = pyUtils.py_eval(nodeOptions); + } + this.applyColorizeHelper($td, nodeOptions, node, 'fg_color', 'color', ctx); + this.applyColorizeHelper($td, nodeOptions, node, 'bg_color', 'background-color', ctx); + }, + /** + * @param {Object} nodeOptions a mapping of nodeOptions parameters to the color itself + * @param {Object} node an XML node (must be a ) + * @param {string} nodeAttribute an attribute of a node to apply a style onto + * @param {string} cssAttribute a real CSS-compatible attribute + */ + applyColorizeHelper: function ($td, nodeOptions, node, nodeAttribute, cssAttribute, ctx) { + if (nodeOptions[nodeAttribute]) { + var colors = _(nodeOptions[nodeAttribute].split(';')) + .chain() + .map(this.pairColors) + .value() + .filter(function CheckUndefined(value, index, ar) { + return value !== undefined; + }); + for (var i=0, len=colors.length; i: ` forms to + * evaluable expressions + * + * @param {string} pairColor `color: expression` pair + */ + pairColors: function (pairColor) { + if (pairColor !== "") { + var pairList = pairColor.split(':'), + color = pairList[0], + // if one passes a bare color instead of an expression, + // then we consider that color is to be shown in any case + expression = pairList[1]? pairList[1] : 'True'; + return [color, py.parse(py.tokenize(expression)), expression]; + } + return undefined; + }, + /** + * Construct domain evaluation context, mostly by passing + * record's fields's values to local scope. + * + * @param {Object} record a record to build a context from + */ + getEvalContext: function (record) { + var ctx = _.extend( + {}, + record.data, + pyUtils.context() + ); + for (var key in ctx) { + var value = ctx[key]; + if (ctx[key] instanceof moment) { + // date/datetime fields are represented w/ Moment objects + // docs: https://momentjs.com/ + ctx[key] = value.format('YYYY-MM-DD hh:mm:ss'); + } + } + return ctx; + } + }); +}); diff --git a/web_tree_dynamic_colored_field/views/web_tree_dynamic_colored_field.xml b/web_tree_dynamic_colored_field/views/web_tree_dynamic_colored_field.xml new file mode 100644 index 00000000..116b37db --- /dev/null +++ b/web_tree_dynamic_colored_field/views/web_tree_dynamic_colored_field.xml @@ -0,0 +1,8 @@ + + +