diff --git a/setup/web_apply_field_style/odoo/addons/web_apply_field_style b/setup/web_apply_field_style/odoo/addons/web_apply_field_style new file mode 120000 index 000000000..5dc7be41e --- /dev/null +++ b/setup/web_apply_field_style/odoo/addons/web_apply_field_style @@ -0,0 +1 @@ +../../../../web_apply_field_style \ No newline at end of file diff --git a/setup/web_apply_field_style/setup.py b/setup/web_apply_field_style/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/web_apply_field_style/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/web_apply_field_style/README.rst b/web_apply_field_style/README.rst new file mode 100644 index 000000000..f798acd23 --- /dev/null +++ b/web_apply_field_style/README.rst @@ -0,0 +1,101 @@ +================= +Apply Field Style +================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:dec2135f450935a31305575e98d577ccafcc5e10e314dc396f4e0c2f15f9e691 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github + :target: https://github.com/OCA/web/tree/16.0/web_apply_field_style + :alt: OCA/web +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/web-16-0/web-16-0-web_apply_field_style + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/web&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Allow to set an additional css class to fields in form view. + +Use case : you may highlight some fields for training purpose + +.. figure:: https://raw.githubusercontent.com/OCA/web/16.0/web_apply_field_style/static/description/demo.png + :alt: Colored fields + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +Override _get_field_styles() with a dict of fields list per model + + +.. code-block:: python + + class Base(models.AbstractModel): + _inherit = "base" + + def _get_field_styles(self): + res = super()._get_field_styles() + res["product.product"] = { + "my-css-class1": ["field1", "field2"], + "my-css-class2": ["field3"], + } + return res + +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 to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Akretion + +Contributors +~~~~~~~~~~~~ + +* `Akretion `_: + * David BEAL + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +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. + +This module is part of the `OCA/web `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/web_apply_field_style/__init__.py b/web_apply_field_style/__init__.py new file mode 100644 index 000000000..ede0a44cb --- /dev/null +++ b/web_apply_field_style/__init__.py @@ -0,0 +1,6 @@ +from odoo.tools import config + +from . import models + +if not config.get("without_demo"): + from . import demo diff --git a/web_apply_field_style/__manifest__.py b/web_apply_field_style/__manifest__.py new file mode 100644 index 000000000..c49e67014 --- /dev/null +++ b/web_apply_field_style/__manifest__.py @@ -0,0 +1,15 @@ +{ + "name": "Apply Field Style", + "author": "Akretion,Odoo Community Association (OCA)", + "summary": "Apply css class style to fields from a dict parameters", + "version": "16.0.1.0.0", + "license": "AGPL-3", + "maintainer": ["bealdav"], + "website": "https://github.com/OCA/web", + "category": "web", + "depends": [ + "base", + ], + "data": [], + "installable": True, +} diff --git a/web_apply_field_style/demo/__init__.py b/web_apply_field_style/demo/__init__.py new file mode 100644 index 000000000..0e4444933 --- /dev/null +++ b/web_apply_field_style/demo/__init__.py @@ -0,0 +1 @@ +from . import base diff --git a/web_apply_field_style/demo/base.py b/web_apply_field_style/demo/base.py new file mode 100644 index 000000000..d334d21f0 --- /dev/null +++ b/web_apply_field_style/demo/base.py @@ -0,0 +1,30 @@ +# © 2023 David BEAL @ Akretion +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from odoo import models + +# R8180 rule asks for merging demo/base.py and models/base.py content +# We need to keep these class separated because of demo mode. +# pylint: disable=R8180 + + +class Base(models.AbstractModel): + _inherit = "base" + + def _get_field_styles(self): + res = super()._get_field_styles() + style = self.env.context.get("style") + if style == "nice": + # only this entry is correct + res["res.users"] = { + "bg-info": ["login", "type"], + "bg-warning": ["partner_id"], + } + elif style == "no_dict": + res = "any" + elif style == "no_field_list": + res["res.users"] = {"bg-info": "any"} + elif style == "empty_dict": + res["res.users"] = {} + elif style == "no_style": + res["res.users"] = False + return res diff --git a/web_apply_field_style/models/__init__.py b/web_apply_field_style/models/__init__.py new file mode 100644 index 000000000..0e4444933 --- /dev/null +++ b/web_apply_field_style/models/__init__.py @@ -0,0 +1 @@ +from . import base diff --git a/web_apply_field_style/models/base.py b/web_apply_field_style/models/base.py new file mode 100644 index 000000000..9c6cf435c --- /dev/null +++ b/web_apply_field_style/models/base.py @@ -0,0 +1,55 @@ +# © 2023 David BEAL @ Akretion +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import logging + +from odoo import api, exceptions, models + +logger = logging.getLogger(__name__) + + +class Base(models.AbstractModel): + _inherit = "base" + + @api.model + def _get_view(self, view_id=None, view_type="form", **options): + arch, view = super()._get_view(view_id, view_type, **options) + if view_type == "form": + self._update_css_class(arch) + return arch, view + + def _update_css_class(self, arch): + css = self._get_field_styles() + if css: + self._check_css_dict(css) + for style in css.get(self._name): + for field_name in css[self._name][style]: + for field in arch.xpath(f"//field[@name='{field_name}']"): + field.attrib[ + "class" + ] = f"{style} {field.attrib.get('class') or ''}".strip() + + def _get_field_styles(self): + """Inherit me with: + + res = super()._get_field_styles() + res.append({'my_model': {"css_class": ['field1', 'field2'], "bg-info": [...] }}) + return res + """ + return {} + + def _check_css_dict(self, css): + rtfm = "\n\nPlease have a look to the readme.\n\nThe rtfm team." + if not isinstance(css, dict): + raise exceptions.ValidationError( + f"_get_field_styles() should return a dict{rtfm}" + ) + model = self._name + if model in css: + if not isinstance(css[model], dict): + raise exceptions.ValidationError(f"{css[model]} should be a dict{rtfm}") + for vals in css[model].values(): + if not isinstance(vals, list): + raise exceptions.ValidationError( + f"{vals} should be a list of fields !{rtfm}" + ) diff --git a/web_apply_field_style/readme/CONFIGURE.rst b/web_apply_field_style/readme/CONFIGURE.rst new file mode 100644 index 000000000..675b2114b --- /dev/null +++ b/web_apply_field_style/readme/CONFIGURE.rst @@ -0,0 +1,15 @@ +Override _get_field_styles() with a dict of fields list per model + + +.. code-block:: python + + class Base(models.AbstractModel): + _inherit = "base" + + def _get_field_styles(self): + res = super()._get_field_styles() + res["product.product"] = { + "my-css-class1": ["field1", "field2"], + "my-css-class2": ["field3"], + } + return res diff --git a/web_apply_field_style/readme/CONTRIBUTORS.rst b/web_apply_field_style/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..957db5f01 --- /dev/null +++ b/web_apply_field_style/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* `Akretion `_: + * David BEAL diff --git a/web_apply_field_style/readme/DESCRIPTION.rst b/web_apply_field_style/readme/DESCRIPTION.rst new file mode 100644 index 000000000..7145b7c13 --- /dev/null +++ b/web_apply_field_style/readme/DESCRIPTION.rst @@ -0,0 +1,6 @@ +Allow to set an additional css class to fields in form view. + +Use case : you may highlight some fields for training purpose + +.. figure:: ../static/description/demo.png + :alt: Colored fields diff --git a/web_apply_field_style/static/description/demo.png b/web_apply_field_style/static/description/demo.png new file mode 100644 index 000000000..27c2aaa45 Binary files /dev/null and b/web_apply_field_style/static/description/demo.png differ diff --git a/web_apply_field_style/static/description/icon.png b/web_apply_field_style/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/web_apply_field_style/static/description/icon.png differ diff --git a/web_apply_field_style/static/description/index.html b/web_apply_field_style/static/description/index.html new file mode 100644 index 000000000..f60550b40 --- /dev/null +++ b/web_apply_field_style/static/description/index.html @@ -0,0 +1,449 @@ + + + + + + +Apply Field Style + + + +
+

Apply Field Style

+ + +

Beta License: AGPL-3 OCA/web Translate me on Weblate Try me on Runboat

+

Allow to set an additional css class to fields in form view.

+

Use case : you may highlight some fields for training purpose

+
+Colored fields +
+

Table of contents

+ +
+

Configuration

+

Override _get_field_styles() with a dict of fields list per model

+
+class Base(models.AbstractModel):
+    _inherit = "base"
+
+    def _get_field_styles(self):
+        res = super()._get_field_styles()
+        res["product.product"] = {
+            "my-css-class1": ["field1", "field2"],
+            "my-css-class2": ["field3"],
+        }
+        return res
+
+
+
+

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 to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Akretion
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

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.

+

This module is part of the OCA/web project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/web_apply_field_style/tests/__init__.py b/web_apply_field_style/tests/__init__.py new file mode 100644 index 000000000..d9b96c4fa --- /dev/null +++ b/web_apply_field_style/tests/__init__.py @@ -0,0 +1 @@ +from . import test_module diff --git a/web_apply_field_style/tests/test_module.py b/web_apply_field_style/tests/test_module.py new file mode 100644 index 000000000..178521280 --- /dev/null +++ b/web_apply_field_style/tests/test_module.py @@ -0,0 +1,54 @@ +# © 2023 David BEAL @ Akretion +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo.exceptions import ValidationError +from odoo.tests import common + + +class Test(common.TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.user_view = cls.env.ref("base.view_users_form") + + def test_nice(self): + arch, view = ( + self.env["res.users"] + .with_context(style="nice") + ._get_view(view_id=self.user_view.id) + ) + for field in arch.xpath("//field[@name='partner_id']"): + self.assertEqual(field.attrib.get("class"), "bg-warning") + + def test_no_dict(self): + with self.assertRaisesRegex(ValidationError, "_get_field_styles().*"): + arch, view = ( + self.env["res.users"] + .with_context(style="no_dict") + ._get_view(view_id=self.user_view.id) + ) + + def test_no_field_list(self): + with self.assertRaisesRegex(ValidationError, ".*should be a list of fields.*"): + arch, view = ( + self.env["res.users"] + .with_context(style="no_field_list") + ._get_view(view_id=self.user_view.id) + ) + + def test_empty_dict(self): + # No effect but no broken code + arch, view = ( + self.env["res.users"] + .with_context(style="empty_dict") + ._get_view(view_id=self.user_view.id) + ) + + def test_no_style(self): + with self.assertRaisesRegex(ValidationError, ".*should be a dict.*"): + arch, view = ( + self.env["res.users"] + .with_context(style="no_style") + ._get_view(view_id=self.user_view.id) + )