diff --git a/README.md b/README.md index ed294c44e2cc..e2760db4e67a 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,21 @@ Available addons ---------------- addon | version | maintainers | summary --- | --- | --- | --- +[web_calendar_slot_duration](web_calendar_slot_duration/) | 19.0.1.0.0 | Yajo | Customizable calendar slot durations +[web_dark_mode](web_dark_mode/) | 19.0.1.0.0 | | Enabled Dark Mode for the Odoo Backend +[web_dialog_size](web_dialog_size/) | 19.0.1.0.0 | | A module that lets the user expand a dialog box to the full screen width. [web_environment_ribbon](web_environment_ribbon/) | 19.0.1.0.0 | | Web Environment Ribbon [web_favicon](web_favicon/) | 19.0.1.0.0 | | Allows to set a custom shortcut icon (aka favicon) -[web_responsive](web_responsive/) | 19.0.1.0.0 | Tardo SplashS | Responsive web client, community-supported +[web_group_expand](web_group_expand/) | 19.0.1.0.0 | | Group Expand Buttons +[web_ir_actions_act_window_message](web_ir_actions_act_window_message/) | 19.0.1.0.0 | hbrunn | Show a message box to users +[web_m2x_options](web_m2x_options/) | 19.0.1.0.0 | | web_m2x_options +[web_pwa_customize](web_pwa_customize/) | 19.0.1.0.0 | victoralmau | Web Pwa Customize +[web_refresher](web_refresher/) | 19.0.1.0.0 | | Web Refresher +[web_remember_tree_column_width](web_remember_tree_column_width/) | 19.0.1.0.0 | frahikLV luisg123v cuongnmtm | Remember the tree columns' widths across sessions. +[web_responsive](web_responsive/) | 19.0.1.0.1 | Tardo SplashS | Responsive web client, community-supported +[web_search_with_and](web_search_with_and/) | 19.0.1.0.0 | | Use AND conditions on omnibar search +[web_tree_many2one_clickable](web_tree_many2one_clickable/) | 19.0.1.0.0 | | Open the linked resource when clicking on their name +[web_widget_bokeh_chart](web_widget_bokeh_chart/) | 19.0.1.0.1 | LoisRForgeFlow JasminSForgeFlow | This widget allows to display charts using Bokeh library. [//]: # (end addons) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000000..63ae7d8d4fda --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +# generated from manifests external_dependencies +bokeh==3.9.0 diff --git a/setup/_metapackage/pyproject.toml b/setup/_metapackage/pyproject.toml index e77e29fd3baa..6a6876f9aefc 100644 --- a/setup/_metapackage/pyproject.toml +++ b/setup/_metapackage/pyproject.toml @@ -1,10 +1,22 @@ [project] name = "odoo-addons-oca-web" -version = "19.0.20251105.0" +version = "19.0.20260422.0" dependencies = [ + "odoo-addon-web_calendar_slot_duration==19.0.*", + "odoo-addon-web_dark_mode==19.0.*", + "odoo-addon-web_dialog_size==19.0.*", "odoo-addon-web_environment_ribbon==19.0.*", "odoo-addon-web_favicon==19.0.*", + "odoo-addon-web_group_expand==19.0.*", + "odoo-addon-web_ir_actions_act_window_message==19.0.*", + "odoo-addon-web_m2x_options==19.0.*", + "odoo-addon-web_pwa_customize==19.0.*", + "odoo-addon-web_refresher==19.0.*", + "odoo-addon-web_remember_tree_column_width==19.0.*", "odoo-addon-web_responsive==19.0.*", + "odoo-addon-web_search_with_and==19.0.*", + "odoo-addon-web_tree_many2one_clickable==19.0.*", + "odoo-addon-web_widget_bokeh_chart==19.0.*", ] classifiers=[ "Programming Language :: Python", diff --git a/web_calendar_slot_duration/README.rst b/web_calendar_slot_duration/README.rst new file mode 100644 index 000000000000..a5f8267ffcd3 --- /dev/null +++ b/web_calendar_slot_duration/README.rst @@ -0,0 +1,130 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +====================== +Calendar slot duration +====================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:22f61857644d74f1c6f650fc637c82547dfd5279aa91a5c78b8b1e98774dedae + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png + :target: https://odoo-community.org/page/development-status + :alt: Production/Stable +.. |badge2| image:: https://img.shields.io/badge/license-LGPL--3-blue.png + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github + :target: https://github.com/OCA/web/tree/19.0/web_calendar_slot_duration + :alt: OCA/web +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/web-19-0/web-19-0-web_calendar_slot_duration + :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=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module extends the functionality of backend calendars to support +custom slot durations and to allow you to provide more specific UX +regarding event duration and snapping. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +This documentation is for developers. + +If you want to configure your calendar view's snap duration, make sure +that your window action includes a context similar to this (example is +the default value): + +:: + + {"calendar_slot_duration": "00:30:00"} + +It can be added in actions defined on python or as +``ir.actions.act_window`` records. + +|edit action settings| + +|result| + +.. |edit action settings| image:: https://raw.githubusercontent.com/OCA/web/19.0/web_calendar_slot_duration/static/description/edit_action.png +.. |result| image:: https://raw.githubusercontent.com/OCA/web/19.0/web_calendar_slot_duration/static/description/calendar_result.png + +Usage +===== + +To use this module, you need to install some other addon that uses it, +as it doesn't provide any end-user functionality. + +As demo data, this module modifies the "Scheduled Actions" calendar to +have slots of 10 minutes as feature demonstration. + +Known issues / Roadmap +====================== + +- Drop module if/when https://github.com/odoo/odoo/pull/66739 is merged. + +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 +------- + +* Tecnativa + +Contributors +------------ + +- `Tecnativa `__: + + - Jairo Llopis + - Stefan Ungureanu + +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. + +.. |maintainer-Yajo| image:: https://github.com/Yajo.png?size=40px + :target: https://github.com/Yajo + :alt: Yajo + +Current `maintainer `__: + +|maintainer-Yajo| + +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_calendar_slot_duration/__init__.py b/web_calendar_slot_duration/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web_calendar_slot_duration/__manifest__.py b/web_calendar_slot_duration/__manifest__.py new file mode 100644 index 000000000000..bec6f8885e02 --- /dev/null +++ b/web_calendar_slot_duration/__manifest__.py @@ -0,0 +1,23 @@ +# Copyright 2021 Tecnativa - Jairo Llopis +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). +{ + "name": "Calendar slot duration", + "summary": "Customizable calendar slot durations", + "version": "19.0.1.0.0", + "development_status": "Production/Stable", + "category": "Extra Tools", + "website": "https://github.com/OCA/web", + "author": "Tecnativa, Odoo Community Association (OCA)", + "maintainers": ["Yajo"], + "license": "LGPL-3", + "application": False, + "installable": True, + "assets": { + "web.assets_backend": [ + "web_calendar_slot_duration/static/src/js/calendar_common_renderer.esm.js", + "web_calendar_slot_duration/static/src/js/calendar_model.esm.js", + ] + }, + "data": ["demo/scheduled_actions.xml"], + "depends": ["web"], +} diff --git a/web_calendar_slot_duration/demo/scheduled_actions.xml b/web_calendar_slot_duration/demo/scheduled_actions.xml new file mode 100644 index 000000000000..1570adc25909 --- /dev/null +++ b/web_calendar_slot_duration/demo/scheduled_actions.xml @@ -0,0 +1,8 @@ + + + + {'search_default_all': 1, "calendar_slot_duration": "00:10:00"} + + diff --git a/web_calendar_slot_duration/i18n/de.po b/web_calendar_slot_duration/i18n/de.po new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web_calendar_slot_duration/i18n/it.po b/web_calendar_slot_duration/i18n/it.po new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web_calendar_slot_duration/i18n/pt_BR.po b/web_calendar_slot_duration/i18n/pt_BR.po new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web_calendar_slot_duration/i18n/web_calendar_slot_duration.pot b/web_calendar_slot_duration/i18n/web_calendar_slot_duration.pot new file mode 100644 index 000000000000..73e76416e0ee --- /dev/null +++ b/web_calendar_slot_duration/i18n/web_calendar_slot_duration.pot @@ -0,0 +1 @@ +# No translations. diff --git a/web_calendar_slot_duration/pyproject.toml b/web_calendar_slot_duration/pyproject.toml new file mode 100644 index 000000000000..4231d0cccb3d --- /dev/null +++ b/web_calendar_slot_duration/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/web_calendar_slot_duration/readme/CONFIGURE.md b/web_calendar_slot_duration/readme/CONFIGURE.md new file mode 100644 index 000000000000..05195bff039d --- /dev/null +++ b/web_calendar_slot_duration/readme/CONFIGURE.md @@ -0,0 +1,14 @@ +This documentation is for developers. + +If you want to configure your calendar view's snap duration, make sure +that your window action includes a context similar to this (example is the +default value): + + {"calendar_slot_duration": "00:30:00"} + +It can be added in actions defined on python or as +`ir.actions.act_window` records. + +![edit action settings](../static/description/edit_action.png) + +![result](../static/description/calendar_result.png) diff --git a/web_calendar_slot_duration/readme/CONTRIBUTORS.md b/web_calendar_slot_duration/readme/CONTRIBUTORS.md new file mode 100644 index 000000000000..3541fd95f37f --- /dev/null +++ b/web_calendar_slot_duration/readme/CONTRIBUTORS.md @@ -0,0 +1,3 @@ +- [Tecnativa](https://www.tecnativa.com): + - Jairo Llopis + - Stefan Ungureanu diff --git a/web_calendar_slot_duration/readme/DESCRIPTION.md b/web_calendar_slot_duration/readme/DESCRIPTION.md new file mode 100644 index 000000000000..400326b7726f --- /dev/null +++ b/web_calendar_slot_duration/readme/DESCRIPTION.md @@ -0,0 +1,3 @@ +This module extends the functionality of backend calendars to support +custom slot durations and to allow you to provide more specific UX +regarding event duration and snapping. diff --git a/web_calendar_slot_duration/readme/ROADMAP.md b/web_calendar_slot_duration/readme/ROADMAP.md new file mode 100644 index 000000000000..027c78daea3d --- /dev/null +++ b/web_calendar_slot_duration/readme/ROADMAP.md @@ -0,0 +1,2 @@ +- Drop module if/when is + merged. diff --git a/web_calendar_slot_duration/readme/USAGE.md b/web_calendar_slot_duration/readme/USAGE.md new file mode 100644 index 000000000000..698cd24be750 --- /dev/null +++ b/web_calendar_slot_duration/readme/USAGE.md @@ -0,0 +1,4 @@ +To use this module, you need to install some other addon that uses it, +as it doesn't provide any end-user functionality. + +As demo data, this module modifies the "Scheduled Actions" calendar to have slots of 10 minutes as feature demonstration. \ No newline at end of file diff --git a/web_calendar_slot_duration/static/description/calendar_result.png b/web_calendar_slot_duration/static/description/calendar_result.png new file mode 100644 index 000000000000..0f651aef8ae9 Binary files /dev/null and b/web_calendar_slot_duration/static/description/calendar_result.png differ diff --git a/web_calendar_slot_duration/static/description/edit_action.png b/web_calendar_slot_duration/static/description/edit_action.png new file mode 100644 index 000000000000..d2fb48a41fa7 Binary files /dev/null and b/web_calendar_slot_duration/static/description/edit_action.png differ diff --git a/web_calendar_slot_duration/static/description/icon.png b/web_calendar_slot_duration/static/description/icon.png new file mode 100644 index 000000000000..3a0328b516c4 Binary files /dev/null and b/web_calendar_slot_duration/static/description/icon.png differ diff --git a/web_calendar_slot_duration/static/description/index.html b/web_calendar_slot_duration/static/description/index.html new file mode 100644 index 000000000000..0ce6fe69733e --- /dev/null +++ b/web_calendar_slot_duration/static/description/index.html @@ -0,0 +1,467 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Calendar slot duration

+ +

Production/Stable License: LGPL-3 OCA/web Translate me on Weblate Try me on Runboat

+

This module extends the functionality of backend calendars to support +custom slot durations and to allow you to provide more specific UX +regarding event duration and snapping.

+

Table of contents

+ +
+

Configuration

+

This documentation is for developers.

+

If you want to configure your calendar view’s snap duration, make sure +that your window action includes a context similar to this (example is +the default value):

+
+{"calendar_slot_duration": "00:30:00"}
+
+

It can be added in actions defined on python or as +ir.actions.act_window records.

+

edit action settings

+

result

+
+
+

Usage

+

To use this module, you need to install some other addon that uses it, +as it doesn’t provide any end-user functionality.

+

As demo data, this module modifies the “Scheduled Actions” calendar to +have slots of 10 minutes as feature demonstration.

+
+
+

Known issues / Roadmap

+ +
+
+

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

+
    +
  • Tecnativa
  • +
+
+
+

Contributors

+
    +
  • Tecnativa:
      +
    • Jairo Llopis
    • +
    • Stefan Ungureanu
    • +
    +
  • +
+
+
+

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.

+

Current maintainer:

+

Yajo

+

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_calendar_slot_duration/static/src/js/calendar_common_renderer.esm.js b/web_calendar_slot_duration/static/src/js/calendar_common_renderer.esm.js new file mode 100644 index 000000000000..f2b103f4329f --- /dev/null +++ b/web_calendar_slot_duration/static/src/js/calendar_common_renderer.esm.js @@ -0,0 +1,15 @@ +/* Copyright 2023 Tecnativa - Stefan Ungureanu + * License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). */ + +import {CalendarCommonRenderer} from "@web/views/calendar/calendar_common/calendar_common_renderer"; +import {patch} from "@web/core/utils/patch"; + +patch(CalendarCommonRenderer.prototype, { + get options() { + const options = super.options; + if (this.env.searchModel.context.calendar_slot_duration) { + options.slotDuration = this.env.searchModel.context.calendar_slot_duration; + } + return options; + }, +}); diff --git a/web_calendar_slot_duration/static/src/js/calendar_model.esm.js b/web_calendar_slot_duration/static/src/js/calendar_model.esm.js new file mode 100644 index 000000000000..af828c1b8b2d --- /dev/null +++ b/web_calendar_slot_duration/static/src/js/calendar_model.esm.js @@ -0,0 +1,24 @@ +/* Copyright 2023 Tecnativa - Stefan Ungureanu + + * License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). */ + +import {CalendarModel} from "@web/views/calendar/calendar_model"; +import {patch} from "@web/core/utils/patch"; + +patch(CalendarModel.prototype, { + buildRawRecord(partialRecord, options = {}) { + if ( + !partialRecord.end && + this.env.searchModel.context.calendar_slot_duration && + !partialRecord.isAllDay + ) { + const slot_duration = this.env.searchModel.context.calendar_slot_duration; + const [hours, minutes, seconds] = slot_duration + .match(/(\d+):(\d+):(\d+)/) + .slice(1, 4); + const durationFloat = hours + minutes / 60 + seconds / 3600; + partialRecord.end = partialRecord.start.plus({hours: durationFloat}); + } + return super.buildRawRecord(partialRecord, options); + }, +}); diff --git a/web_dark_mode/README.rst b/web_dark_mode/README.rst new file mode 100644 index 000000000000..a3f54aed5f94 --- /dev/null +++ b/web_dark_mode/README.rst @@ -0,0 +1,89 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +========= +Dark Mode +========= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:580b2e147b76f5568dd7e8712bd8d242c834623cce0c7556f90a9123b6a2bd65 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/license-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/19.0/web_dark_mode + :alt: OCA/web +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/web-19-0/web-19-0-web_dark_mode + :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=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This modules offers the dark mode for Odoo CE. The dark mode can be +activated by every user in the user menu in the top right. + +**Table of contents** + +.. contents:: + :local: + +Known issues / Roadmap +====================== + +- Implement dark mode for PoS with a glue module + +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 +------- + +* initOS GmbH + +Contributors +------------ + +- Florian Kantelberg +- `Pyxiris `__ + + - `Liam Noonan `__ + +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_dark_mode/__init__.py b/web_dark_mode/__init__.py new file mode 100644 index 000000000000..1d408a8a039e --- /dev/null +++ b/web_dark_mode/__init__.py @@ -0,0 +1,4 @@ +# © 2022 Florian Kantelberg - initOS GmbH +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import models diff --git a/web_dark_mode/__manifest__.py b/web_dark_mode/__manifest__.py new file mode 100644 index 000000000000..9912281fa140 --- /dev/null +++ b/web_dark_mode/__manifest__.py @@ -0,0 +1,60 @@ +# © 2022 Florian Kantelberg - initOS GmbH +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Dark Mode", + "summary": "Enabled Dark Mode for the Odoo Backend", + "license": "AGPL-3", + "version": "19.0.1.0.0", + "website": "https://github.com/OCA/web", + "author": "initOS GmbH, Odoo Community Association (OCA)", + "depends": ["web"], + "excludes": ["web_enterprise"], + "installable": True, + "assets": { + "web.assets_backend": [ + "web_dark_mode/static/src/js/switch_item.esm.js", + ], + "web.assets_backend_lazy_dark": [ + ("include", "web.assets_variables_dark"), + ("include", "web.assets_backend_helpers_dark"), + ], + "web.assets_variables_dark": [ + ( + "before", + "web/static/src/scss/primary_variables.scss", + "web_dark_mode/static/src/scss/primary_variables.dark.scss", + ), + ( + "before", + "web/static/src/scss/secondary_variables.scss", + "web_dark_mode/static/src/scss/secondary_variables.dark.scss", + ), + ( + "before", + "web/static/src/**/*.variables.scss", + "web_dark_mode/static/src/**/*.variables.dark.scss", + ), + ], + "web.assets_backend_helpers_dark": [ + ( + "before", + "web/static/src/scss/bootstrap_overridden.scss", + "web_dark_mode/static/src/scss/bootstrap_overridden.dark.scss", + ), + ( + "after", + "web/static/lib/bootstrap/scss/_functions.scss", + "web_dark_mode/static/src/scss/bs_functions_overrides.dark.scss", + ), + ], + "web.assets_web_dark": [ + ("include", "web.assets_variables_dark"), + ("include", "web.assets_backend_helpers_dark"), + "web_dark_mode/static/src/**/*.dark.scss", + ], + }, + "data": [ + "views/res_users_views.xml", + ], +} diff --git a/web_dark_mode/i18n/es.po b/web_dark_mode/i18n/es.po new file mode 100644 index 000000000000..903638c864d5 --- /dev/null +++ b/web_dark_mode/i18n/es.po @@ -0,0 +1,40 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_dark_mode +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-09-02 20:35+0000\n" +"Last-Translator: Ivorra78 \n" +"Language-Team: none\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: web_dark_mode +#. odoo-javascript +#: code:addons/web_dark_mode/static/src/js/switch_item.esm.js:0 +#: model:ir.model.fields,field_description:web_dark_mode.field_res_users__dark_mode +#, python-format +msgid "Dark Mode" +msgstr "Modo Oscuro" + +#. module: web_dark_mode +#: model:ir.model.fields,field_description:web_dark_mode.field_res_users__dark_mode_device_dependent +msgid "Device Dependent Dark Mode" +msgstr "Modo Oscuro en Función del Dispositivo" + +#. module: web_dark_mode +#: model:ir.model,name:web_dark_mode.model_ir_http +msgid "HTTP Routing" +msgstr "Enrutamiento HTTP" + +#. module: web_dark_mode +#: model:ir.model,name:web_dark_mode.model_res_users +msgid "User" +msgstr "Usuario" diff --git a/web_dark_mode/i18n/es_AR.po b/web_dark_mode/i18n/es_AR.po new file mode 100644 index 000000000000..1ad2d1f79e73 --- /dev/null +++ b/web_dark_mode/i18n/es_AR.po @@ -0,0 +1,40 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_dark_mode +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-01-01 21:45+0000\n" +"Last-Translator: Ignacio Buioli \n" +"Language-Team: none\n" +"Language: es_AR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.14.1\n" + +#. module: web_dark_mode +#. odoo-javascript +#: code:addons/web_dark_mode/static/src/js/switch_item.esm.js:0 +#: model:ir.model.fields,field_description:web_dark_mode.field_res_users__dark_mode +#, python-format +msgid "Dark Mode" +msgstr "Modo Oscuro" + +#. module: web_dark_mode +#: model:ir.model.fields,field_description:web_dark_mode.field_res_users__dark_mode_device_dependent +msgid "Device Dependent Dark Mode" +msgstr "Dispositivo que Depende del Modo Oscuro" + +#. module: web_dark_mode +#: model:ir.model,name:web_dark_mode.model_ir_http +msgid "HTTP Routing" +msgstr "Ruteo HTTP" + +#. module: web_dark_mode +#: model:ir.model,name:web_dark_mode.model_res_users +msgid "User" +msgstr "Usuario" diff --git a/web_dark_mode/i18n/fr.po b/web_dark_mode/i18n/fr.po new file mode 100644 index 000000000000..3333b16a9660 --- /dev/null +++ b/web_dark_mode/i18n/fr.po @@ -0,0 +1,40 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_dark_mode +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-10-23 18:56+0000\n" +"Last-Translator: Grégory Moka Tourisme \n" +"Language-Team: none\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: web_dark_mode +#. odoo-javascript +#: code:addons/web_dark_mode/static/src/js/switch_item.esm.js:0 +#: model:ir.model.fields,field_description:web_dark_mode.field_res_users__dark_mode +#, python-format +msgid "Dark Mode" +msgstr "Mode sombre" + +#. module: web_dark_mode +#: model:ir.model.fields,field_description:web_dark_mode.field_res_users__dark_mode_device_dependent +msgid "Device Dependent Dark Mode" +msgstr "" + +#. module: web_dark_mode +#: model:ir.model,name:web_dark_mode.model_ir_http +msgid "HTTP Routing" +msgstr "" + +#. module: web_dark_mode +#: model:ir.model,name:web_dark_mode.model_res_users +msgid "User" +msgstr "Utilisateur" diff --git a/web_dark_mode/i18n/hr.po b/web_dark_mode/i18n/hr.po new file mode 100644 index 000000000000..21e8842000f7 --- /dev/null +++ b/web_dark_mode/i18n/hr.po @@ -0,0 +1,41 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_dark_mode +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-02-16 14:23+0000\n" +"Last-Translator: Bole \n" +"Language-Team: none\n" +"Language: hr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Weblate 4.14.1\n" + +#. module: web_dark_mode +#. odoo-javascript +#: code:addons/web_dark_mode/static/src/js/switch_item.esm.js:0 +#: model:ir.model.fields,field_description:web_dark_mode.field_res_users__dark_mode +#, python-format +msgid "Dark Mode" +msgstr "Tamni način" + +#. module: web_dark_mode +#: model:ir.model.fields,field_description:web_dark_mode.field_res_users__dark_mode_device_dependent +msgid "Device Dependent Dark Mode" +msgstr "Tamni način zavisi od uređaja" + +#. module: web_dark_mode +#: model:ir.model,name:web_dark_mode.model_ir_http +msgid "HTTP Routing" +msgstr "HTTP Routing" + +#. module: web_dark_mode +#: model:ir.model,name:web_dark_mode.model_res_users +msgid "User" +msgstr "Korisnik" diff --git a/web_dark_mode/i18n/it.po b/web_dark_mode/i18n/it.po new file mode 100644 index 000000000000..e14a675b293c --- /dev/null +++ b/web_dark_mode/i18n/it.po @@ -0,0 +1,40 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_dark_mode +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-11-27 11:34+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: web_dark_mode +#. odoo-javascript +#: code:addons/web_dark_mode/static/src/js/switch_item.esm.js:0 +#: model:ir.model.fields,field_description:web_dark_mode.field_res_users__dark_mode +#, python-format +msgid "Dark Mode" +msgstr "Dark mode" + +#. module: web_dark_mode +#: model:ir.model.fields,field_description:web_dark_mode.field_res_users__dark_mode_device_dependent +msgid "Device Dependent Dark Mode" +msgstr "Dark mode dipendente dal dispositivo" + +#. module: web_dark_mode +#: model:ir.model,name:web_dark_mode.model_ir_http +msgid "HTTP Routing" +msgstr "Instradamento HTTP" + +#. module: web_dark_mode +#: model:ir.model,name:web_dark_mode.model_res_users +msgid "User" +msgstr "Utente" diff --git a/web_dark_mode/i18n/tr.po b/web_dark_mode/i18n/tr.po new file mode 100644 index 000000000000..0cd019cf46af --- /dev/null +++ b/web_dark_mode/i18n/tr.po @@ -0,0 +1,40 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_dark_mode +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-03-06 20:08+0000\n" +"Last-Translator: Ediz Duman \n" +"Language-Team: none\n" +"Language: tr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.14.1\n" + +#. module: web_dark_mode +#. odoo-javascript +#: code:addons/web_dark_mode/static/src/js/switch_item.esm.js:0 +#: model:ir.model.fields,field_description:web_dark_mode.field_res_users__dark_mode +#, python-format +msgid "Dark Mode" +msgstr "Koyu Mod" + +#. module: web_dark_mode +#: model:ir.model.fields,field_description:web_dark_mode.field_res_users__dark_mode_device_dependent +msgid "Device Dependent Dark Mode" +msgstr "Cihaza Bağlı Karanlık Mod" + +#. module: web_dark_mode +#: model:ir.model,name:web_dark_mode.model_ir_http +msgid "HTTP Routing" +msgstr "HTTP Yönlendirme" + +#. module: web_dark_mode +#: model:ir.model,name:web_dark_mode.model_res_users +msgid "User" +msgstr "Kullanıcı" diff --git a/web_dark_mode/i18n/web_dark_mode.pot b/web_dark_mode/i18n/web_dark_mode.pot new file mode 100644 index 000000000000..631f365188cc --- /dev/null +++ b/web_dark_mode/i18n/web_dark_mode.pot @@ -0,0 +1,61 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_dark_mode +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 19.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" + +#. module: web_dark_mode +#. odoo-javascript +#: code:addons/web_dark_mode/static/src/js/switch_item.esm.js:0 +#: model:ir.model.fields,field_description:web_dark_mode.field_res_users__dark_mode +#: model:ir.model.fields,field_description:web_dark_mode.field_res_users_settings__dark_mode +msgid "Dark Mode" +msgstr "" + +#. module: web_dark_mode +#: model:ir.model.fields,field_description:web_dark_mode.field_res_users_settings__dark_mode_device_dependent +msgid "Dark Mode Device Dependent" +msgstr "" + +#. module: web_dark_mode +#: model:ir.model.fields,field_description:web_dark_mode.field_res_users__dark_mode_device_dependent +msgid "Device Dependent Dark Mode" +msgstr "" + +#. module: web_dark_mode +#: model:ir.model.fields,field_description:web_dark_mode.field_ir_http__display_name +#: model:ir.model.fields,field_description:web_dark_mode.field_res_users__display_name +#: model:ir.model.fields,field_description:web_dark_mode.field_res_users_settings__display_name +msgid "Display Name" +msgstr "" + +#. module: web_dark_mode +#: model:ir.model,name:web_dark_mode.model_ir_http +msgid "HTTP Routing" +msgstr "" + +#. module: web_dark_mode +#: model:ir.model.fields,field_description:web_dark_mode.field_ir_http__id +#: model:ir.model.fields,field_description:web_dark_mode.field_res_users__id +#: model:ir.model.fields,field_description:web_dark_mode.field_res_users_settings__id +msgid "ID" +msgstr "" + +#. module: web_dark_mode +#: model:ir.model,name:web_dark_mode.model_res_users +msgid "User" +msgstr "" + +#. module: web_dark_mode +#: model:ir.model,name:web_dark_mode.model_res_users_settings +msgid "User Settings" +msgstr "" diff --git a/web_dark_mode/i18n/zh.po b/web_dark_mode/i18n/zh.po new file mode 100644 index 000000000000..ad8461437429 --- /dev/null +++ b/web_dark_mode/i18n/zh.po @@ -0,0 +1,38 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_dark_mode +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#. module: web_dark_mode +#. odoo-javascript +#: code:addons/web_dark_mode/static/src/js/switch_item.esm.js:0 +#: model:ir.model.fields,field_description:web_dark_mode.field_res_users__dark_mode +#, python-format +msgid "Dark Mode" +msgstr "" + +#. module: web_dark_mode +#: model:ir.model.fields,field_description:web_dark_mode.field_res_users__dark_mode_device_dependent +msgid "Device Dependent Dark Mode" +msgstr "" + +#. module: web_dark_mode +#: model:ir.model,name:web_dark_mode.model_ir_http +msgid "HTTP Routing" +msgstr "" + +#. module: web_dark_mode +#: model:ir.model,name:web_dark_mode.model_res_users +msgid "User" +msgstr "" diff --git a/web_dark_mode/models/__init__.py b/web_dark_mode/models/__init__.py new file mode 100644 index 000000000000..b15df3d10a44 --- /dev/null +++ b/web_dark_mode/models/__init__.py @@ -0,0 +1,4 @@ +# © 2022 Florian Kantelberg - initOS GmbH +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import ir_http, res_users, res_users_settings diff --git a/web_dark_mode/models/ir_http.py b/web_dark_mode/models/ir_http.py new file mode 100644 index 000000000000..367caf88b476 --- /dev/null +++ b/web_dark_mode/models/ir_http.py @@ -0,0 +1,64 @@ +# © 2022 Florian Kantelberg - initOS GmbH +# © 2026 Liam Noonan - Pyxiris +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import models +from odoo.http import request + + +class IrHttp(models.AbstractModel): + _inherit = "ir.http" + + def color_scheme(self): + target_scheme, existing_scheme = self._get_color_scheme() + if target_scheme: + return target_scheme + elif existing_scheme: + return existing_scheme + else: + return super().color_scheme() + + @classmethod + def _get_color_scheme(cls): + user = request.env.user + existing_scheme_cookie = None + target_scheme = None + + if user and user._is_internal(): + # Existing + existing_scheme_cookie = request.httprequest.cookies.get("color_scheme") + browser_preference_header = request.httprequest.headers.get( + "Sec-CH-Prefers-Color-Scheme" + ) + browser_scheme = ( + browser_preference_header + if browser_preference_header in ("dark", "light") + else None + ) + # User preference + user_scheme = "dark" if getattr(user, "dark_mode", None) else "light" + user_device_dependant_scheme = getattr( + user, "dark_mode_device_dependent", None + ) + + if user_device_dependant_scheme: + if browser_scheme and existing_scheme_cookie != browser_scheme: + target_scheme = browser_scheme + + elif existing_scheme_cookie != user_scheme: + target_scheme = user_scheme + + return target_scheme, existing_scheme_cookie + + @classmethod + def _set_color_scheme(cls, response): + target_scheme, _ = cls._get_color_scheme() + if target_scheme: + response.set_cookie("color_scheme", target_scheme) + + @classmethod + def _post_dispatch(cls, response): + cls._set_color_scheme(response) + response.headers.add("Vary", "Sec-CH-Prefers-Color-Scheme") + response.headers.add("Accept-CH", "Sec-CH-Prefers-Color-Scheme") + return super()._post_dispatch(response) diff --git a/web_dark_mode/models/res_users.py b/web_dark_mode/models/res_users.py new file mode 100644 index 000000000000..77459d0090a3 --- /dev/null +++ b/web_dark_mode/models/res_users.py @@ -0,0 +1,33 @@ +# © 2022 Florian Kantelberg - initOS GmbH +# © 2026 Liam Noonan - Pyxiris +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +from odoo import fields, models + + +class ResUsers(models.Model): + _inherit = "res.users" + + dark_mode = fields.Boolean( + related="res_users_settings_id.dark_mode", readonly=False + ) + dark_mode_device_dependent = fields.Boolean( + related="res_users_settings_id.dark_mode_device_dependent", + readonly=False, + string="Device Dependent Dark Mode", + ) + + @property + def SELF_READABLE_FIELDS(self): + return super().SELF_READABLE_FIELDS + [ + "dark_mode_device_dependent", + "dark_mode", + ] + + @property + def SELF_WRITEABLE_FIELDS(self): + return super().SELF_WRITEABLE_FIELDS + [ + "dark_mode_device_dependent", + "dark_mode", + ] diff --git a/web_dark_mode/models/res_users_settings.py b/web_dark_mode/models/res_users_settings.py new file mode 100644 index 000000000000..97a54da14852 --- /dev/null +++ b/web_dark_mode/models/res_users_settings.py @@ -0,0 +1,14 @@ +# © 2022 Florian Kantelberg - initOS GmbH +# © 2026 Liam Noonan - Pyxiris +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResUsersSettings(models.Model): + _inherit = "res.users.settings" + + # These fields should be here in order to be accessible via in js + # as user.settings.dark_mode, etc. + dark_mode = fields.Boolean() + dark_mode_device_dependent = fields.Boolean() diff --git a/web_dark_mode/pyproject.toml b/web_dark_mode/pyproject.toml new file mode 100644 index 000000000000..4231d0cccb3d --- /dev/null +++ b/web_dark_mode/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/web_dark_mode/readme/CONTRIBUTORS.md b/web_dark_mode/readme/CONTRIBUTORS.md new file mode 100644 index 000000000000..38be6e4844f8 --- /dev/null +++ b/web_dark_mode/readme/CONTRIBUTORS.md @@ -0,0 +1,3 @@ +- Florian Kantelberg \ +- [Pyxiris](https://github.com/Pyxiris) + - [Liam Noonan](https://github.com/ljmnoonan) diff --git a/web_dark_mode/readme/DESCRIPTION.md b/web_dark_mode/readme/DESCRIPTION.md new file mode 100644 index 000000000000..7d90c04edb1d --- /dev/null +++ b/web_dark_mode/readme/DESCRIPTION.md @@ -0,0 +1,2 @@ +This modules offers the dark mode for Odoo CE. The dark mode can be +activated by every user in the user menu in the top right. diff --git a/web_dark_mode/readme/ROADMAP.md b/web_dark_mode/readme/ROADMAP.md new file mode 100644 index 000000000000..b1437e5f398e --- /dev/null +++ b/web_dark_mode/readme/ROADMAP.md @@ -0,0 +1 @@ +- Implement dark mode for PoS with a glue module diff --git a/web_dark_mode/static/description/icon.png b/web_dark_mode/static/description/icon.png new file mode 100644 index 000000000000..3a0328b516c4 Binary files /dev/null and b/web_dark_mode/static/description/icon.png differ diff --git a/web_dark_mode/static/description/index.html b/web_dark_mode/static/description/index.html new file mode 100644 index 000000000000..76812ec01139 --- /dev/null +++ b/web_dark_mode/static/description/index.html @@ -0,0 +1,441 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Dark Mode

+ +

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

+

This modules offers the dark mode for Odoo CE. The dark mode can be +activated by every user in the user menu in the top right.

+

Table of contents

+ +
+

Known issues / Roadmap

+
    +
  • Implement dark mode for PoS with a glue module
  • +
+
+
+

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

+
    +
  • initOS GmbH
  • +
+
+ +
+

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_dark_mode/static/src/core/badge/badge.dark.scss b/web_dark_mode/static/src/core/badge/badge.dark.scss new file mode 100644 index 000000000000..6338c6705427 --- /dev/null +++ b/web_dark_mode/static/src/core/badge/badge.dark.scss @@ -0,0 +1,17 @@ +// Use the same formula from web_dark_mode/static/src/core/tags_list/tags_list.dark.scss +.badge { + @for $size from 1 through length($o-colors) { + &.o_badge_color_#{$size - 1} { + background-color: mix( + nth($o-colors, $size), + $o-view-background-color, + 25% + ) !important; + color: scale-color( + nth($o-colors, $size), + $lightness: 70%, + $saturation: 100% + ) !important; + } + } +} diff --git a/web_dark_mode/static/src/core/bottom_sheet/bottom_sheet.dark.scss b/web_dark_mode/static/src/core/bottom_sheet/bottom_sheet.dark.scss new file mode 100644 index 000000000000..8a80561d1d82 --- /dev/null +++ b/web_dark_mode/static/src/core/bottom_sheet/bottom_sheet.dark.scss @@ -0,0 +1,3 @@ +.o_bottom_sheet .o_bottom_sheet_sheet { + border-top: $border-width solid $o-enterprise-color; +} diff --git a/web_dark_mode/static/src/core/colorlist/colorlist.dark.scss b/web_dark_mode/static/src/core/colorlist/colorlist.dark.scss new file mode 100644 index 000000000000..20158c991f8e --- /dev/null +++ b/web_dark_mode/static/src/core/colorlist/colorlist.dark.scss @@ -0,0 +1,12 @@ +.o_colorlist > button { + @for $size from 2 through length($o-colors) { + &.o_colorlist_item_color_#{$size - 1} { + --background-color: #{mix( + nth($o-colors, $size), + $o-view-background-color, + 95% + )}; + --color: #{color-contrast(nth($o-colors, $size))}; + } + } +} diff --git a/web_dark_mode/static/src/core/notebook/notebook.dark.scss b/web_dark_mode/static/src/core/notebook/notebook.dark.scss new file mode 100644 index 000000000000..044b220482eb --- /dev/null +++ b/web_dark_mode/static/src/core/notebook/notebook.dark.scss @@ -0,0 +1,4 @@ +.o_notebook { + --Notebook__link-border-color--hover: #{$border-color}; + --Notebook__link-border-top-color--active: #{$o-action}; +} diff --git a/web_dark_mode/static/src/core/tags_list/tags_list.dark.scss b/web_dark_mode/static/src/core/tags_list/tags_list.dark.scss new file mode 100644 index 000000000000..3f9611bb05cc --- /dev/null +++ b/web_dark_mode/static/src/core/tags_list/tags_list.dark.scss @@ -0,0 +1,18 @@ +.o_tag { + @for $size from 1 through length($o-colors) { + &.o_tag_color_#{$size - 1} { + $-bg: mix(nth($o-colors, $size), $o-view-background-color, 25%); + $-color: scale-color( + nth($o-colors, $size), + $lightness: 70%, + $saturation: 100% + ); + + &, + &::after { + --background-color: #{$-bg}; + --color: #{$-color}; + } + } + } +} diff --git a/web_dark_mode/static/src/js/switch_item.esm.js b/web_dark_mode/static/src/js/switch_item.esm.js new file mode 100644 index 000000000000..79c273ba1789 --- /dev/null +++ b/web_dark_mode/static/src/js/switch_item.esm.js @@ -0,0 +1,60 @@ +/** @odoo-module **/ + +import {_t} from "@web/core/l10n/translation"; +import {browser} from "@web/core/browser/browser"; +import {cookie} from "@web/core/browser/cookie"; +import {registry} from "@web/core/registry"; +import {user} from "@web/core/user"; + +export function darkModeSwitchItem(env) { + return { + type: "switch", + id: "color_scheme.switch", + description: _t("Dark Mode"), + callback: () => { + env.services.color_scheme.switchColorScheme(); + }, + isChecked: cookie.get("color_scheme") === "dark", + sequence: 40, + }; +} + +export const colorSchemeService = { + dependencies: ["orm", "ui"], + + async start(env, {orm, ui}) { + // This is only for browsers like Firefox and Safari that do not support + // Sec-CH-Prefers-Color-Scheme. Browsers that do support it will have already + // set the correct cookie value on first request due to server side handling + // in ir.http. + if (user.settings.dark_mode_device_dependent === true) { + const device_preference = window.matchMedia("(prefers-color-scheme: dark)") + .matches + ? "dark" + : "light"; + if (cookie.get("color_scheme") !== device_preference) { + cookie.set("color_scheme", device_preference); + // This will cause a bit of flicker as odoo loads the wrong assets + // before it can determine the browser system color scheme. + browser.location.reload(); + } + } else { + registry.category("user_menuitems").add("darkmode", darkModeSwitchItem); + } + + return { + async switchColorScheme() { + const scheme = cookie.get("color_scheme") === "dark" ? "light" : "dark"; + cookie.set("color_scheme", scheme); + await orm.write("res.users", [user.userId], { + dark_mode: scheme === "dark", + }); + + ui.block(); + browser.location.reload(); + }, + }; + }, +}; + +registry.category("services").add("color_scheme", colorSchemeService); diff --git a/web_dark_mode/static/src/scss/bootstrap_overridden.dark.scss b/web_dark_mode/static/src/scss/bootstrap_overridden.dark.scss new file mode 100644 index 000000000000..09d82b856c16 --- /dev/null +++ b/web_dark_mode/static/src/scss/bootstrap_overridden.dark.scss @@ -0,0 +1,49 @@ +// This overrides the overrides in web/static/src/scss/bootstrap_overridden.scss +// and also some additional overrides to web/static/lib/bootstrap/scss/_variables.scss + +// web/static/lib/bootstrap/scss/_variables.scss sets these colors with tint-color() and shade-color() +// but we inversed those functions in web_dark_mode/static/src/scss/bs_functions_overrides.dark.scss +// so we have to adjust a bit. Most noticable in purchase dashboard (19.0) and banners in html editor +$info-text-emphasis: shade-color($o-info, 75%) !default; +$info-bg-subtle: tint-color($o-info, 65%) !default; +$success-text-emphasis: shade-color($o-success, 75%) !default; +$success-bg-subtle: tint-color($o-success, 65%) !default; +$warning-text-emphasis: shade-color($o-warning, 75%) !default; +$warning-bg-subtle: tint-color($o-warning, 65%) !default; +$danger-text-emphasis: shade-color($o-danger, 75%) !default; +$danger-bg-subtle: tint-color($o-danger, 65%) !default; + +// Shadows +$box-shadow: 0 0.5rem 1rem rgba($o-white, 0.4) !default; +$box-shadow-sm: 0 0.125rem 0.25rem rgba($o-white, 0.2) !default; +$box-shadow-lg: 0 1rem 3rem rgba($o-white, 0.4) !default; +$box-shadow-inset: inset 0 1px 2px rgba($o-white, 0.2) !default; + +// Dropdowns +$dropdown-bg: $o-white !default; + +// Navs +$nav-tabs-link-active-bg: transparent !default; +$nav-link-color: $o-main-text-color !default; + +// Tooltips +$tooltip-bg: $o-white !default; +$tooltip-color: $o-main-text-color !default; + +// Modals +$modal-backdrop-bg: $o-white !default; + +// User input typically entered via keyboard +$kbd-color: $o-gray-100 !default; +$kbd-bg: $o-gray-900 !default; +$kbd-box-shadow: + 0px 1px 1px rgba($o-gray-100, 0.2), + inset 0px -1px 1px 1px rgba($o-gray-700, 0.8), + inset 0px 2px 0px 0px rgba($o-black, 0.8) !default; + +// Input +$input-focus-box-shadow: 0 !default; +$input-focus-border-color: $o-enterprise-action-color !default; +$form-check-input-checked-color: $o-white !default; +$form-check-input-checked-border-color: $o-enterprise-action-color !default; +$form-check-input-checked-bg-color: $o-enterprise-action-color !default; diff --git a/web_dark_mode/static/src/scss/bs_functions_overrides.dark.scss b/web_dark_mode/static/src/scss/bs_functions_overrides.dark.scss new file mode 100644 index 000000000000..726cf9aecd20 --- /dev/null +++ b/web_dark_mode/static/src/scss/bs_functions_overrides.dark.scss @@ -0,0 +1,11 @@ +// Inverse the tint and shade functions found in web/static/lib/bootstrap/scss/_functions.scss +// It would make a lot more sense if we could use web/static/lib/bootstrap/scss/_variables-dark.scss +// but odoo has everything hardcoded to the light mode versions of the variables, so we are left +// with this rather hacky way of inverting shades and tints +@function tint-color($color, $weight) { + @return mix(#000000, $color, $weight); +} + +@function shade-color($color, $weight) { + @return mix(#ffffff, $color, $weight); +} diff --git a/web_dark_mode/static/src/scss/primary_variables.dark.scss b/web_dark_mode/static/src/scss/primary_variables.dark.scss new file mode 100644 index 000000000000..ecf7bd291f47 --- /dev/null +++ b/web_dark_mode/static/src/scss/primary_variables.dark.scss @@ -0,0 +1,131 @@ +// This file is just the things in web/static/src/scss/primary_variables.scss +// that need to be overridden for dark mode. Anything that does not need to be +// changed does not make it here. +// These variables will be loaded right before web/static/src/scss/primary_variables.scss +// so any variable defined here will override the default ones. +// The !default flag is included in case any other model needs to override these values again. + +// Color-scheme +$o-webclient-color-scheme: dark !default; + +// Colors +$o-white: #000000 !default; +$o-black: #ffffff !default; + +$o-gray-100: #181818 !default; // L: 9% +$o-gray-200: #1f1f1f !default; // L: 12% +$o-gray-300: #303030 !default; // L: 19% +$o-gray-400: #4a4a4a !default; // L: 29% +$o-gray-500: #696969 !default; // L: 41% +$o-gray-600: #8b8b8b !default; // L: 55% +$o-gray-700: #aeaeae !default; // L: 68% +$o-gray-800: #c0c0c0 !default; // L: 75% +$o-gray-900: #c8c8c8 !default; // L: 78% + +$o-community-color: $o-gray-200 !default; +$o-enterprise-color: #71639e !default; +$o-enterprise-action-color: #00c7c7 !default; + +$o-brand-odoo: $o-enterprise-color !default; +$o-brand-primary: $o-enterprise-color !default; + +// This only has 3 uses. The only one I was able to test is at +// web/static/src/views/form/form_controller.scss which changes form lables +// to this in mobile. Those are usually gray-900. +$o-brand-secondary: $o-gray-900 !default; + +$o-action: $o-enterprise-action-color !default; + +// Font colors +$o-main-link-color: $o-enterprise-action-color !default; + +// Component colors +$o-view-background-color: $o-gray-200 !default; +$o-shadow-color: $o-gray-100 !default; + +$o-form-lightsecondary: $o-gray-500 !default; + +// This is the background color. it is declared in web/static/src/scss/secondary_variables.scss +// but it really ought to be here +$o-webclient-background-color: $o-gray-100 !default; + +// List group +$o-list-group-active-bg: $o-gray-300 !default; + +// Buttons +$o-btns-bs-override: () !default; +$o-btns-bs-override: map-merge( + $o-btns-bs-override, + ( + "primary": ( + background: $o-brand-primary, + border: $o-brand-primary, + color: $o-black, + hover-background: lighten($o-brand-primary, 5%), + hover-border: lighten($o-brand-primary, 5%), + hover-color: $o-black, + + active-background: lighten($o-brand-primary, 10%), + active-border: lighten($o-brand-primary, 10%), + active-color: $o-black, + ), + "secondary": ( + background: $o-gray-300, + border: $o-gray-300, + color: $o-gray-900, + + hover-background: $o-gray-400, + hover-border: $o-gray-400, + hover-color: $o-gray-900, + + active-background: mix($o-action, $o-gray-100, 10%), + active-border: $o-action, + active-color: $o-black, + ), + "light": ( + background: transparent, + border: transparent, + color: $o-gray-800, + + hover-background: $o-gray-300, + hover-border: $o-gray-300, + hover-color: $o-gray-900, + + active-background: mix($o-action, $o-gray-100, 10%), + active-border: $o-action, + active-color: $o-black, + ), + ) +); + +$o-btns-bs-outline-override: () !default; +$o-btns-bs-outline-override: map-merge( + $o-btns-bs-outline-override, + ( + "primary": ( + background: transparent, + border: saturate(lighten($o-brand-primary, 20%), 25%), + color: saturate(lighten($o-brand-primary, 20%), 25%), + hover-background: lighten($o-brand-primary, 5%), + hover-border: lighten($o-brand-primary, 5%), + hover-color: $o-black, + + active-background: lighten($o-brand-primary, 10%), + active-border: lighten($o-brand-primary, 10%), + active-color: $o-black, + ), + "secondary": ( + background: transparent, + border: $o-gray-300, + color: $o-gray-900, + + hover-background: $o-gray-300, + hover-border: $o-gray-300, + hover-color: $o-gray-900, + + active-background: mix($o-action, $o-gray-100, 10%), + active-border: $o-action, + active-color: $o-black, + ), + ) +); diff --git a/web_dark_mode/static/src/scss/secondary_variables.dark.scss b/web_dark_mode/static/src/scss/secondary_variables.dark.scss new file mode 100644 index 000000000000..8af23ad7998e --- /dev/null +++ b/web_dark_mode/static/src/scss/secondary_variables.dark.scss @@ -0,0 +1,16 @@ +// Note that first color will be used as color_0 in various places, but most noticably +// for private tasks in calendar view. +$o-colors: + #899db1, #ee2d2d, #dc8534, #e8bb1d, #5794dd, #9f628f, #db8865, #41a9a2, #304be0, + #ee2f8a, #61c36e, #9872e6 !default; + +// An epically lazy solution to colors that do not do well on the dark background: just delete them. +// Unfortunately this does introduce a problem where, when there are more calendar users than colors, +// the event gets a $o-webclient-background-color background and the filter check gets +// $form-check-input-checked-bg-color. This problem exists in enterprise too, +// so hopefully they will fix it. +$o-colors-secondary: + #aa4b6b, #30c381, #f7cd1f, #4285f4, #d6145f, #aa3a38, #6be585, #e9d362, #b56969, + #bdc3c7, #ea00ff, #ff0026, #8bcc00, #00bfaf, #006aff, #af00bf, #bf6300, #8cff00, + #00f2ff, #ff00d0, #ffa600, #3acc00, #00b6bf, #0048ff, #bf7c00, #04ff00, #00d0ff, + #ff008c, #00bf49, #0092b3, #0004ff, #b20062 !default; diff --git a/web_dark_mode/static/src/search/search_panel/search_view.dark.scss b/web_dark_mode/static/src/search/search_panel/search_view.dark.scss new file mode 100644 index 000000000000..42581895f19e --- /dev/null +++ b/web_dark_mode/static/src/search/search_panel/search_view.dark.scss @@ -0,0 +1,13 @@ +.o_searchview { + --SearchBar-background-color: #{$o-gray-100}; + &:focus-within { + $-searchbar-border-color: rgba($input-focus-border-color, 0.5); + border-color: $-searchbar-border-color; + + .o_searchview_dropdown_toggler { + border-left-color: $-searchbar-border-color; + border-top-color: $-searchbar-border-color; + border-right-color: $-searchbar-border-color; + border-bottom-color: $-searchbar-border-color; + } + } +} diff --git a/web_dark_mode/static/src/views/calendar/calendar_renderer.dark.scss b/web_dark_mode/static/src/views/calendar/calendar_renderer.dark.scss new file mode 100644 index 000000000000..d3df07ba6203 --- /dev/null +++ b/web_dark_mode/static/src/views/calendar/calendar_renderer.dark.scss @@ -0,0 +1,63 @@ +// I really hate this whole loop and with I could just override +// $color and $color-subtle, but that doesn't seem to be possible. +@for $i from 1 through length($o-colors-complete) { + $color: nth($o-colors-complete, $i); + $color-subtle: scale-color( + mix($o-white, $color, 30%), + $lightness: -20%, + $saturation: -35% + ); + + .o_calendar_renderer { + .o_calendar_color_#{$i - 1} { + --fc-event-bg-color: #{$color-subtle}; + --o-event-bg: #{$color}; + --o-event-bg--subtle-rgb: #{to-rgb($color-subtle)}; + + &.fc-bg-event { + --fc-bg-event-color: #{$color-subtle}; + } + + &.o_event_hatched:not(.o_event_dot):not(.fc-daygrid-event):not( + .fc-timegrid-event + ), + &.o_event_hatched .fc-bg, + &.o_attendee_status_tentative:not(.o_event_dot) .fc-bg { + background: repeating-linear-gradient( + 45deg, + RGBA(to-rgb($color), 0.3), + RGBA(to-rgb($color), 0.3) 10px, + RGBA(to-rgb($color), 0.6) 10px, + RGBA(to-rgb($color), 0.6) 20px + ) !important; + } + + &.o_event_striked:not(.o_event_dot) { + background: linear-gradient( + transparent 0 45%, + $color 45% 55%, + transparent 55% 100% + ); + } + + &.fc-event:not(.o_event_dot):not(.fc-dragging) { + --fc-event-text-color: #{color-contrast($color-subtle)}; + --fc-event-border-color: #{tint-color($color, 50%)}; + } + } + } + + .o_cw_filter_color_#{$i - 1} { + &.form-check:hover .o_cw_filter_input_bg:not(.no_filter_color) { + border-color: shade-color($color, 20%); + } + + .o_cw_filter_input_bg { + border-color: $color; + + &:checked { + background-color: $color; + } + } + } +} diff --git a/web_dark_mode/static/src/views/fields/image/image_field.dark.scss b/web_dark_mode/static/src/views/fields/image/image_field.dark.scss new file mode 100644 index 000000000000..f6371764635f --- /dev/null +++ b/web_dark_mode/static/src/views/fields/image/image_field.dark.scss @@ -0,0 +1,7 @@ +// Unfortunately, images with trasparent backgrounds do +// not display well on a dark background. +// I use #ffffff instead of $o-black to ensure that they will +// always be on a white background no matter what. +.o_field_image { + --ImageField-background-color: #ffffff; +} diff --git a/web_dark_mode/static/src/views/fields/properties/properties_field.dark.scss b/web_dark_mode/static/src/views/fields/properties/properties_field.dark.scss new file mode 100644 index 000000000000..41098213b50b --- /dev/null +++ b/web_dark_mode/static/src/views/fields/properties/properties_field.dark.scss @@ -0,0 +1,27 @@ +.o_field_property_definition_type .o_field_property_dropdown img, +.o_field_property_definition_type_menu .dropdown-item img { + -webkit-filter: invert(100%); + filter: invert(100%); +} + +.o_property_field_value { + select { + option { + background-color: $dropdown-bg; + } + } +} + +// This is the < Create "tagname" > link that shows when you type a +// tag that doesn't exist. It was getting set to purple for some reason +.o_property_field_value + .ui-widget.ui-autocomplete + .ui-menu-item.o_field_property_dropdown_add + a { + color: $o-main-link-color !important; +} + +.o_field_properties div:not([columns="1"]) .o_property_drag_group { + background-color: #{mix($o-action, $o-view-background-color, 10%)}; + border: 1px solid #{rgba($o-action, 0.5)}; +} diff --git a/web_dark_mode/static/src/views/kanban/kanban_controller.dark.scss b/web_dark_mode/static/src/views/kanban/kanban_controller.dark.scss new file mode 100644 index 000000000000..74c896a9cc86 --- /dev/null +++ b/web_dark_mode/static/src/views/kanban/kanban_controller.dark.scss @@ -0,0 +1,14 @@ +.o_kanban_renderer { + --KanbanColumn__highlight-background: #{mix($o-action, $o-gray-100, 10%)}; + --KanbanColumn__highlight-border: #{rgba($o-action, 0.5)}; + // Mirror the color of selected row in list view using the same logic as applied there: + // https://github.com/odoo/odoo/blob/19.0/addons/web/static/lib/bootstrap/scss/_variables.scss#L775 + --KanbanColumn__highlight-selected: #{shift-color($info, $table-bg-scale)}; + + // For some reason attachment images do not get the o_field_image class + .o_kanban_record:not(.o_legacy_kanban_record) { + .o_attachment_image > img { + background-color: #ffffff; + } + } +} diff --git a/web_dark_mode/static/src/webclient/navbar/navbar.variables.dark.scss b/web_dark_mode/static/src/webclient/navbar/navbar.variables.dark.scss new file mode 100644 index 000000000000..537cc13a64f7 --- /dev/null +++ b/web_dark_mode/static/src/webclient/navbar/navbar.variables.dark.scss @@ -0,0 +1,14 @@ +// The navbar is usually purple, as set by web/static/src/webclient/navbar/navbar.variables.scss +// We override it here for dark mode. +$o-navbar-background: $o-view-background-color !default; +// We do not really need to disable the border, but it helps on web_responsive +// when we change the color of the navbar to match the app grid background. +// If we do not disable it, it changes color with a noticeable delay after the navbar. +$o-navbar-border-bottom: 0px solid $o-navbar-background !default; + +$o-navbar-entry-color: $o-gray-900 !default; +$o-navbar-entry-color--hover: $o-black !default; + +$o-navbar-badge-bg: $o-danger !default; +$o-navbar-badge-color: $o-black !default; +$o-navbar-badge-text-shadow: 0 !default; diff --git a/web_dark_mode/tests/__init__.py b/web_dark_mode/tests/__init__.py new file mode 100644 index 000000000000..fd9ea3035a34 --- /dev/null +++ b/web_dark_mode/tests/__init__.py @@ -0,0 +1,4 @@ +# © 2022 Florian Kantelberg - initOS GmbH +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import test_ir_http diff --git a/web_dark_mode/tests/test_ir_http.py b/web_dark_mode/tests/test_ir_http.py new file mode 100644 index 000000000000..dae2a63896fa --- /dev/null +++ b/web_dark_mode/tests/test_ir_http.py @@ -0,0 +1,155 @@ +# © 2022 Florian Kantelberg - initOS GmbH +# © 2026 Liam Noonan - Pyxiris +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.tests import HttpCase, new_test_user, tagged + +HOST = "127.0.0.1" + + +@tagged("post_install", "-at_install") +class TestColorScheme(HttpCase): + def setUp(self): + super().setUp() + self.test_portal_user = new_test_user( + self.env, "test_portal_user", groups="base.group_portal" + ) + self.test_internal_user = new_test_user( + self.env, "test_internal_user", groups="base.group_user" + ) + self.test_internal_user.write( + { + "dark_mode": False, + "dark_mode_device_dependent": False, + } + ) + + # Non internal user -> skip logic, do nothing + def test_01_non_internal_user_ignored(self): + self.authenticate(self.test_portal_user.login, self.test_portal_user.login) + response = self.url_open("/my") + cookie_header = response.headers.get("Set-Cookie", "") + self.assertNotIn( + "color_scheme", + cookie_header, + "Color scheme logic should not run for non-internal users", + ) + + # No user preference, no cookie -> set light + def test_02_no_user_settings_no_cookie(self): + self.opener.cookies.clear() + self.authenticate(self.test_internal_user.login, self.test_internal_user.login) + response = self.url_open("/odoo") + cookie_header = response.headers.get("Set-Cookie", "") + self.assertIn("color_scheme=light", cookie_header) + self.assertEqual(self.opener.cookies.get("color_scheme"), "light") + + # No user preference, light cookie -> do nothing + def test_03_no_user_settings_light_cookie(self): + self.authenticate(self.test_internal_user.login, self.test_internal_user.login) + self.opener.cookies.set("color_scheme", "light", domain=HOST, path="/") + response = self.url_open("/odoo") + cookie_header = response.headers.get("Set-Cookie", "") + self.assertNotIn( + "color_scheme", + cookie_header, + "The server should not set the cookie if already exists and is correct", + ) + self.assertEqual(self.opener.cookies.get("color_scheme"), "light") + + # User dark, cookie light -> set dark + def test_04_user_dark_cookie_light(self): + self.test_internal_user.write( + { + "dark_mode": True, + "dark_mode_device_dependent": False, + } + ) + self.authenticate(self.test_internal_user.login, self.test_internal_user.login) + self.opener.cookies.set("color_scheme", "light", domain=HOST, path="/") + response = self.url_open("/odoo") + cookie_header = response.headers.get("Set-Cookie", "") + self.assertIn("color_scheme=dark", cookie_header) + self.assertEqual(self.opener.cookies.get("color_scheme"), "dark") + + # User dark, cookie dark -> do nothing + def test_05_user_dark_cookie_dark(self): + self.test_internal_user.write( + { + "dark_mode": True, + "dark_mode_device_dependent": False, + } + ) + self.authenticate(self.test_internal_user.login, self.test_internal_user.login) + self.opener.cookies.set("color_scheme", "dark", domain=HOST, path="/") + response = self.url_open("/odoo") + cookie_header = response.headers.get("Set-Cookie", "") + self.assertNotIn( + "color_scheme", + cookie_header, + "The server should not set the cookie if already exists and is correct", + ) + self.assertEqual(self.opener.cookies.get("color_scheme"), "dark") + + # User dev dep + dark, browser none, cookie none -> do nothing + def test_06_user_dev_dep_browser_none_cookie_none(self): + self.test_internal_user.write( + { + "dark_mode": True, + "dark_mode_device_dependent": True, + } + ) + self.authenticate(self.test_internal_user.login, self.test_internal_user.login) + headers = {"Sec-CH-Prefers-Color-Scheme": None} + response = self.url_open("/odoo", headers=headers) + cookie_header = response.headers.get("Set-Cookie", "") + # This also makes sure that device dependent is overruling regular dark mode + self.assertNotIn( + "color_scheme", + cookie_header, + "The server should not set the cookie as it will be set by client side js", + ) + + # User dev dep, browser light, cookie light -> do nothing + def test_07_user_dev_dep_browser_light_cookie_light(self): + self.test_internal_user.write( + { + "dark_mode": True, + "dark_mode_device_dependent": True, + } + ) + self.authenticate(self.test_internal_user.login, self.test_internal_user.login) + self.opener.cookies.set("color_scheme", "light", domain=HOST, path="/") + headers = {"Sec-CH-Prefers-Color-Scheme": "light"} + response = self.url_open("/odoo", headers=headers) + cookie_header = response.headers.get("Set-Cookie", "") + self.assertNotIn( + "color_scheme", + cookie_header, + "The server should not set the cookie if already exists and is correct", + ) + self.assertEqual(self.opener.cookies.get("color_scheme"), "light") + + # User dev dep, browser dark, cookie light -> set dark + def test_08_user_dev_dep_browser_dark_cookie_light(self): + self.test_internal_user.write( + { + "dark_mode": False, + "dark_mode_device_dependent": True, + } + ) + self.authenticate(self.test_internal_user.login, self.test_internal_user.login) + self.opener.cookies.set("color_scheme", "light", domain=HOST, path="/") + headers = {"Sec-CH-Prefers-Color-Scheme": "dark"} + response = self.url_open("/odoo", headers=headers) + cookie_header = response.headers.get("Set-Cookie", "") + self.assertIn("color_scheme=dark", cookie_header) + self.assertEqual(self.opener.cookies.get("color_scheme"), "dark") + + def test_09_vary_headers(self): + self.authenticate(self.test_internal_user.login, self.test_internal_user.login) + response = self.url_open("/odoo") + self.assertIn("Sec-CH-Prefers-Color-Scheme", response.headers.get("Vary", "")) + self.assertIn( + "Sec-CH-Prefers-Color-Scheme", response.headers.get("Accept-CH", "") + ) diff --git a/web_dark_mode/views/res_users_views.xml b/web_dark_mode/views/res_users_views.xml new file mode 100644 index 000000000000..520923af2f93 --- /dev/null +++ b/web_dark_mode/views/res_users_views.xml @@ -0,0 +1,14 @@ + + + + res.users + + + + + + + + + + diff --git a/web_dialog_size/README.rst b/web_dialog_size/README.rst new file mode 100644 index 000000000000..d2a45b12b5c0 --- /dev/null +++ b/web_dialog_size/README.rst @@ -0,0 +1,122 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +=============== +Web Dialog Size +=============== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:82dac89574909c0b51e36915e82361c0f70787d7b1b237ff449addfb0e5093da + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/license-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/19.0/web_dialog_size + :alt: OCA/web +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/web-19-0/web-19-0-web_dialog_size + :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=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +A module that lets the user expand/restore the dialog box size through a +button in the upper right corner (imitating most windows managers). It +also adds draggable support to the dialogs. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +By default, the module respects the caller's ``dialog_size`` option. If +you want to set dialog boxes maximized by default, you need to: + +1. Go to *Settings -> Technical -> Parameters -> System Parameters* + +2. | Add a new record with the text *web_dialog_size.default_maximize* + in + | the *Key* field and the text *True* in the *Value* field + +Known issues / Roadmap +====================== + +- Allow setting default dialog size per user. + +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 +------- + +* ACSONE SA/NV +* Therp BV +* Siddharth Bhalgami +* Tecnativa +* Amaris + +Contributors +------------ + +- Anthony Muschang +- Stéphane Bidoul +- Holger Brunn +- Siddharth Bhalgami +- Wolfgang Pichler +- David Vidal +- Quentin Theuret +- `Tecnativa `__: + + - Pedro M. Baeza + - Jairo Llopis + - Ernesto Tejeda + - Carlos Roca + +- Sudhir Arya +- Pierre Pizzetta +- Mantas Šniukas +- `Heliconia Solutions Pvt. Ltd. `__ + + - Bhavesh Heliconia + +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_dialog_size/__init__.py b/web_dialog_size/__init__.py new file mode 100644 index 000000000000..0650744f6bc6 --- /dev/null +++ b/web_dialog_size/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/web_dialog_size/__manifest__.py b/web_dialog_size/__manifest__.py new file mode 100644 index 000000000000..19fb6f15ee94 --- /dev/null +++ b/web_dialog_size/__manifest__.py @@ -0,0 +1,39 @@ +# Copyright 2015 ACSONE SA/NV +# Copyright 2018 Amaris +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Web Dialog Size", + "summary": """ + A module that lets the user expand a + dialog box to the full screen width.""", + "author": "ACSONE SA/NV, " + "Therp BV, " + "Siddharth Bhalgami," + "Tecnativa, " + "Amaris, " + "Odoo Community Association (OCA)", + "website": "https://github.com/OCA/web", + "category": "web", + "version": "19.0.1.0.0", + "license": "AGPL-3", + "depends": ["web"], + "installable": True, + "assets": { + "web.assets_backend": [ + "/web_dialog_size/static/src/js/web_dialog_size.esm.js", + "/web_dialog_size/static/src/scss/web_dialog_size.scss", + "/web_dialog_size/static/src/xml/ExpandButton.xml", + ( + "after", + "/web/static/src/core/dialog/dialog.xml", + "/web_dialog_size/static/src/xml/web_dialog_header.xml", + ), + ( + "after", + "/web/static/src/views/view_dialogs/select_create_dialog.xml", + "/web_dialog_size/static/src/xml/select_create_dialog.xml", + ), + ], + }, +} diff --git a/web_dialog_size/i18n/de.po b/web_dialog_size/i18n/de.po new file mode 100644 index 000000000000..3a7e405c3227 --- /dev/null +++ b/web_dialog_size/i18n/de.po @@ -0,0 +1,31 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_dialog_size +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-10-13 20:46+0000\n" +"Last-Translator: Corneliuus \n" +"Language-Team: none\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: web_dialog_size +#: model:ir.model,name:web_dialog_size.model_ir_config_parameter +msgid "System Parameter" +msgstr "Systemparameter" + +#~ msgid "Display Name" +#~ msgstr "Anzeigename" + +#~ msgid "ID" +#~ msgstr "ID" + +#~ msgid "Last Modified on" +#~ msgstr "Zuletzt bearbeitet am" diff --git a/web_dialog_size/i18n/es.po b/web_dialog_size/i18n/es.po new file mode 100644 index 000000000000..a3647c364aad --- /dev/null +++ b/web_dialog_size/i18n/es.po @@ -0,0 +1,25 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_dialog_size +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-05-25 11:47+0000\n" +"Last-Translator: Valentin Vinagre \n" +"Language-Team: none\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: web_dialog_size +#: model:ir.model,name:web_dialog_size.model_ir_config_parameter +msgid "System Parameter" +msgstr "Parámetro del sistema" + +#~ msgid "ID" +#~ msgstr "ID" diff --git a/web_dialog_size/i18n/fr.po b/web_dialog_size/i18n/fr.po new file mode 100644 index 000000000000..d3a0bde37860 --- /dev/null +++ b/web_dialog_size/i18n/fr.po @@ -0,0 +1,25 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_dialog_size +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-05-14 20:47+0000\n" +"Last-Translator: Yves Le Doeuff \n" +"Language-Team: none\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: web_dialog_size +#: model:ir.model,name:web_dialog_size.model_ir_config_parameter +msgid "System Parameter" +msgstr "Paramètre système" + +#~ msgid "Display Name" +#~ msgstr "Nom affiché" diff --git a/web_dialog_size/i18n/it.po b/web_dialog_size/i18n/it.po new file mode 100644 index 000000000000..b54cc337a46b --- /dev/null +++ b/web_dialog_size/i18n/it.po @@ -0,0 +1,31 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_dialog_size +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-11-27 11:33+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: web_dialog_size +#: model:ir.model,name:web_dialog_size.model_ir_config_parameter +msgid "System Parameter" +msgstr "Parametro di sistema" + +#~ msgid "Display Name" +#~ msgstr "Nome Visualizzato" + +#~ msgid "ID" +#~ msgstr "ID" + +#~ msgid "Last Modified on" +#~ msgstr "Ultima Modifica il" diff --git a/web_dialog_size/i18n/nl.po b/web_dialog_size/i18n/nl.po new file mode 100644 index 000000000000..d90fc964ebbe --- /dev/null +++ b/web_dialog_size/i18n/nl.po @@ -0,0 +1,31 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_dialog_size +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-05-17 20:47+0000\n" +"Last-Translator: Bosd \n" +"Language-Team: none\n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: web_dialog_size +#: model:ir.model,name:web_dialog_size.model_ir_config_parameter +msgid "System Parameter" +msgstr "Systeem Parameter" + +#~ msgid "Display Name" +#~ msgstr "Weergavenaam" + +#~ msgid "ID" +#~ msgstr "ID" + +#~ msgid "Last Modified on" +#~ msgstr "Laatst Gewijzigd op" diff --git a/web_dialog_size/i18n/web_dialog_size.pot b/web_dialog_size/i18n/web_dialog_size.pot new file mode 100644 index 000000000000..fe8076fa1439 --- /dev/null +++ b/web_dialog_size/i18n/web_dialog_size.pot @@ -0,0 +1,29 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_dialog_size +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 19.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" + +#. module: web_dialog_size +#: model:ir.model.fields,field_description:web_dialog_size.field_ir_config_parameter__display_name +msgid "Display Name" +msgstr "" + +#. module: web_dialog_size +#: model:ir.model.fields,field_description:web_dialog_size.field_ir_config_parameter__id +msgid "ID" +msgstr "" + +#. module: web_dialog_size +#: model:ir.model,name:web_dialog_size.model_ir_config_parameter +msgid "System Parameter" +msgstr "" diff --git a/web_dialog_size/i18n/zh_CN.po b/web_dialog_size/i18n/zh_CN.po new file mode 100644 index 000000000000..8a3c4118d4b9 --- /dev/null +++ b/web_dialog_size/i18n/zh_CN.po @@ -0,0 +1,22 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_dialog_size +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2019-09-01 12:52+0000\n" +"Last-Translator: 黎伟杰 <674416404@qq.com>\n" +"Language-Team: none\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 3.8\n" + +#. module: web_dialog_size +#: model:ir.model,name:web_dialog_size.model_ir_config_parameter +msgid "System Parameter" +msgstr "系统参数" diff --git a/web_dialog_size/models/__init__.py b/web_dialog_size/models/__init__.py new file mode 100644 index 000000000000..bd3aa9f10636 --- /dev/null +++ b/web_dialog_size/models/__init__.py @@ -0,0 +1 @@ +from . import ir_config_parameter diff --git a/web_dialog_size/models/ir_config_parameter.py b/web_dialog_size/models/ir_config_parameter.py new file mode 100644 index 000000000000..d202a98abcdf --- /dev/null +++ b/web_dialog_size/models/ir_config_parameter.py @@ -0,0 +1,18 @@ +# Copyright 2018 Tecnativa - Jairo Llopis +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, models +from odoo.tools.safe_eval import const_eval + + +class IrConfigParameter(models.Model): + _inherit = "ir.config_parameter" + + @api.model + def get_web_dialog_size_config(self): + get_param = self.sudo().get_param + return { + "default_maximize": const_eval( + get_param("web_dialog_size.default_maximize", "False") + ) + } diff --git a/web_dialog_size/pyproject.toml b/web_dialog_size/pyproject.toml new file mode 100644 index 000000000000..4231d0cccb3d --- /dev/null +++ b/web_dialog_size/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/web_dialog_size/readme/CONFIGURE.md b/web_dialog_size/readme/CONFIGURE.md new file mode 100644 index 000000000000..7626410d58d7 --- /dev/null +++ b/web_dialog_size/readme/CONFIGURE.md @@ -0,0 +1,7 @@ +By default, the module respects the caller's `dialog_size` option. If +you want to set dialog boxes maximized by default, you need to: + +1. Go to *Settings -\> Technical -\> Parameters -\> System Parameters* + +2. Add a new record with the text *web_dialog_size.default_maximize* in + the *Key* field and the text *True* in the *Value* field diff --git a/web_dialog_size/readme/CONTRIBUTORS.md b/web_dialog_size/readme/CONTRIBUTORS.md new file mode 100644 index 000000000000..9001cbc59192 --- /dev/null +++ b/web_dialog_size/readme/CONTRIBUTORS.md @@ -0,0 +1,17 @@ +- Anthony Muschang \<\> +- Stéphane Bidoul \<\> +- Holger Brunn \<\> +- Siddharth Bhalgami \<\> +- Wolfgang Pichler \<\> +- David Vidal \<\> +- Quentin Theuret \<\> +- [Tecnativa](https://www.tecnativa.com): + - Pedro M. Baeza + - Jairo Llopis + - Ernesto Tejeda + - Carlos Roca +- Sudhir Arya \<\> +- Pierre Pizzetta \<\> +- Mantas Šniukas \<\> +- [Heliconia Solutions Pvt. Ltd.](https://www.heliconia.io) + - Bhavesh Heliconia diff --git a/web_dialog_size/readme/DESCRIPTION.md b/web_dialog_size/readme/DESCRIPTION.md new file mode 100644 index 000000000000..cd588ffddcd5 --- /dev/null +++ b/web_dialog_size/readme/DESCRIPTION.md @@ -0,0 +1,3 @@ +A module that lets the user expand/restore the dialog box size through a +button in the upper right corner (imitating most windows managers). It +also adds draggable support to the dialogs. diff --git a/web_dialog_size/readme/ROADMAP.md b/web_dialog_size/readme/ROADMAP.md new file mode 100644 index 000000000000..df8c2291b925 --- /dev/null +++ b/web_dialog_size/readme/ROADMAP.md @@ -0,0 +1 @@ +- Allow setting default dialog size per user. diff --git a/web_dialog_size/static/description/icon.png b/web_dialog_size/static/description/icon.png new file mode 100644 index 000000000000..3a0328b516c4 Binary files /dev/null and b/web_dialog_size/static/description/icon.png differ diff --git a/web_dialog_size/static/description/index.html b/web_dialog_size/static/description/index.html new file mode 100644 index 000000000000..a56289ab9d30 --- /dev/null +++ b/web_dialog_size/static/description/index.html @@ -0,0 +1,478 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Web Dialog Size

+ +

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

+

A module that lets the user expand/restore the dialog box size through a +button in the upper right corner (imitating most windows managers). It +also adds draggable support to the dialogs.

+

Table of contents

+ +
+

Configuration

+

By default, the module respects the caller’s dialog_size option. If +you want to set dialog boxes maximized by default, you need to:

+
    +
  1. Go to Settings -> Technical -> Parameters -> System Parameters

    +
  2. +
  3. +
    Add a new record with the text web_dialog_size.default_maximize +in
    +
    the Key field and the text True in the Value field
    +
    +
  4. +
+
+
+

Known issues / Roadmap

+
    +
  • Allow setting default dialog size per user.
  • +
+
+
+

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

+
    +
  • ACSONE SA/NV
  • +
  • Therp BV
  • +
  • Siddharth Bhalgami
  • +
  • Tecnativa
  • +
  • Amaris
  • +
+
+
+

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_dialog_size/static/src/js/web_dialog_size.esm.js b/web_dialog_size/static/src/js/web_dialog_size.esm.js new file mode 100644 index 000000000000..07f4802392da --- /dev/null +++ b/web_dialog_size/static/src/js/web_dialog_size.esm.js @@ -0,0 +1,157 @@ +import {Component, onWillRender} from "@odoo/owl"; +import {ActionDialog} from "@web/webclient/actions/action_dialog"; +import {Dialog} from "@web/core/dialog/dialog"; +import {SelectCreateDialog} from "@web/views/view_dialogs/select_create_dialog"; +import {patch} from "@web/core/utils/patch"; +import {useService} from "@web/core/utils/hooks"; +import {browser} from "@web/core/browser/browser"; + +export class ExpandButton extends Component { + setup() { + this.original_size = this.props.getoriginalsize + ? this.props.getoriginalsize() + : this.props.getsize() !== "dialog_full_screen" + ? this.props.getsize() + : "md"; + } + + dialog_button_extend() { + this.props.setsize("dialog_full_screen"); + browser.localStorage.setItem("odoo.web_dialog_size.value", "true"); + this.render(); + } + + dialog_button_restore() { + this.props.setsize(this.original_size); + browser.localStorage.setItem("odoo.web_dialog_size.value", "false"); + this.render(); + } +} + +ExpandButton.template = "web_dialog_size.ExpandButton"; + +patch(Dialog.prototype, { + setup() { + this.originalSize = this.props.size; + super.setup(); + this.setSize = this.setSize.bind(this); + this.getSize = this.getSize.bind(this); + this.getOriginalSize = this.getOriginalSize.bind(this); + + const storedValue = browser.localStorage.getItem("odoo.web_dialog_size.value"); + const lastServerValue = browser.localStorage.getItem( + "odoo.web_dialog_size.last_server_value" + ); + + if (storedValue === "true") { + this._forcedSize = "dialog_full_screen"; + this.props.size = "dialog_full_screen"; + } + + const orm = useService("orm"); + orm.call("ir.config_parameter", "get_web_dialog_size_config").then((r) => { + const serverValue = String(Boolean(r.default_maximize)); + if (serverValue !== lastServerValue) { + browser.localStorage.setItem( + "odoo.web_dialog_size.last_server_value", + serverValue + ); + + if (storedValue === null || storedValue === lastServerValue) { + browser.localStorage.setItem( + "odoo.web_dialog_size.value", + serverValue + ); + if (serverValue === "true") { + this.setSize("dialog_full_screen"); + } else if (this._forcedSize === "dialog_full_screen") { + this.setSize(this.originalSize || "md"); + } + } + } + }); + + onWillRender(() => { + if (this._forcedSize && this.props.size !== this._forcedSize) { + this.props.size = this._forcedSize; + } + }); + }, + + setSize(size) { + this._forcedSize = size; + this.props.size = size; + this.render(); + }, + + getSize() { + return this.props.size; + }, + + getOriginalSize() { + return this.originalSize || "md"; + }, +}); + +patch(SelectCreateDialog.prototype, { + setup() { + this.originalSize = this.props.size; + super.setup(); + this.setSize = this.setSize.bind(this); + this.getSize = this.getSize.bind(this); + this.getOriginalSize = this.getOriginalSize.bind(this); + + const storedValue = browser.localStorage.getItem("odoo.web_dialog_size.value"); + const lastServerValue = browser.localStorage.getItem( + "odoo.web_dialog_size.last_server_value" + ); + + if (storedValue === "true") { + this.props.size = "dialog_full_screen"; + } + + const orm = useService("orm"); + orm.call("ir.config_parameter", "get_web_dialog_size_config").then((r) => { + const serverValue = String(Boolean(r.default_maximize)); + if (serverValue !== lastServerValue) { + browser.localStorage.setItem( + "odoo.web_dialog_size.last_server_value", + serverValue + ); + if (storedValue === null || storedValue === lastServerValue) { + browser.localStorage.setItem( + "odoo.web_dialog_size.value", + serverValue + ); + if (serverValue === "true") { + this.setSize("dialog_full_screen"); + } else if (this.props.size === "dialog_full_screen") { + this.setSize(this.originalSize || "md"); + } + } + } + }); + }, + + setSize(size) { + this.props.size = size; + this.render(); + }, + + getSize() { + return this.props.size; + }, + + getOriginalSize() { + return this.originalSize || "md"; + }, +}); + +Object.assign(ActionDialog.components, {ExpandButton}); +SelectCreateDialog.components = Object.assign(SelectCreateDialog.components || {}, { + ExpandButton, +}); +Dialog.components = Object.assign(Dialog.components || {}, {ExpandButton}); +// Patch annoying validation method +Dialog.props.size.validate = (s) => + ["sm", "md", "lg", "xl", "dialog_full_screen"].includes(s); diff --git a/web_dialog_size/static/src/scss/web_dialog_size.scss b/web_dialog_size/static/src/scss/web_dialog_size.scss new file mode 100644 index 000000000000..44e2066f1aa2 --- /dev/null +++ b/web_dialog_size/static/src/scss/web_dialog_size.scss @@ -0,0 +1,16 @@ +.modal { + .modal-dialog_full_screen { + @include media-breakpoint-up(sm) { + max-width: 100%; + width: calc(100% - 50px); + } + } + + .dialog_button_restore, + .dialog_button_extend { + margin-left: auto; + + .btn-close { + margin: -8px -8px -8px 0px; + } + } +} diff --git a/web_dialog_size/static/src/xml/ExpandButton.xml b/web_dialog_size/static/src/xml/ExpandButton.xml new file mode 100644 index 000000000000..71ce28c91058 --- /dev/null +++ b/web_dialog_size/static/src/xml/ExpandButton.xml @@ -0,0 +1,21 @@ + + + + + + + diff --git a/web_dialog_size/static/src/xml/select_create_dialog.xml b/web_dialog_size/static/src/xml/select_create_dialog.xml new file mode 100644 index 000000000000..1ba58a6bfcc9 --- /dev/null +++ b/web_dialog_size/static/src/xml/select_create_dialog.xml @@ -0,0 +1,8 @@ + + + + + props.size + + + diff --git a/web_dialog_size/static/src/xml/web_dialog_header.xml b/web_dialog_size/static/src/xml/web_dialog_header.xml new file mode 100644 index 000000000000..f242685e3a87 --- /dev/null +++ b/web_dialog_size/static/src/xml/web_dialog_header.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/web_dialog_size/tests/__init__.py b/web_dialog_size/tests/__init__.py new file mode 100644 index 000000000000..79d02635e051 --- /dev/null +++ b/web_dialog_size/tests/__init__.py @@ -0,0 +1 @@ +from . import test_web_dialog_size diff --git a/web_dialog_size/tests/test_web_dialog_size.py b/web_dialog_size/tests/test_web_dialog_size.py new file mode 100644 index 000000000000..0eefbd984545 --- /dev/null +++ b/web_dialog_size/tests/test_web_dialog_size.py @@ -0,0 +1,20 @@ +# Copyright 2018 Tecnativa - Ernesto Tejeda +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0 + +from odoo.tests.common import TransactionCase + + +class TestWebDialogSize(TransactionCase): + def setUp(self): + super().setUp() + + def test_get_web_dialog_size_config(self): + obj = self.env["ir.config_parameter"] + + self.assertFalse(obj.get_web_dialog_size_config()["default_maximize"]) + + obj.set_param("web_dialog_size.default_maximize", "True") + self.assertTrue(obj.get_web_dialog_size_config()["default_maximize"]) + + obj.set_param("web_dialog_size.default_maximize", "False") + self.assertFalse(obj.get_web_dialog_size_config()["default_maximize"]) diff --git a/web_group_expand/README.rst b/web_group_expand/README.rst new file mode 100644 index 000000000000..27ce75c8a2aa --- /dev/null +++ b/web_group_expand/README.rst @@ -0,0 +1,99 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +==================== +Group Expand Buttons +==================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:0a01a6ecc98a9d303fb17ff3d62f6ce5276c6248b6d335d359d8ab06f6ebb0a6 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/license-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/19.0/web_group_expand + :alt: OCA/web +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/web-19-0/web-19-0-web_group_expand + :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=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +When grouping a list by a field, this module adds two buttons to expand +or collapse all the groups at once. + +The buttons appear in the top right, in place of the pagination. + +One level of groups is expanded or collapsed at a time. + +**Table of contents** + +.. contents:: + :local: + +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 +------- + +* OpenERP SA +* AvanzOSC +* Serv. Tecnol. Avanzados - Pedro M. Baeza +* Therp BV +* Xtendoo + +Contributors +------------ + +- Mantavya Gajjar +- Oihane Crucelaegui +- Pedro M. Baeza +- Jay Vora (SerpentCS) for their alternative implementation +- Jan Verbeek +- Manuel Calero +- Alvaro Estebanez (brain-tec AG) +- Mayank Patel +- `360ERP `__: + + - Andrea Stirpe + +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_group_expand/__init__.py b/web_group_expand/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web_group_expand/__manifest__.py b/web_group_expand/__manifest__.py new file mode 100644 index 000000000000..fbd9663a23bc --- /dev/null +++ b/web_group_expand/__manifest__.py @@ -0,0 +1,20 @@ +{ + "name": "Group Expand Buttons", + "category": "Web", + "version": "19.0.1.0.0", + "license": "AGPL-3", + "author": "OpenERP SA, " + "AvanzOSC, " + "Serv. Tecnol. Avanzados - Pedro M. Baeza, " + "Therp BV, " + "Xtendoo, " + "Odoo Community Association (OCA)", + "website": "https://github.com/OCA/web", + "depends": ["web"], + "assets": { + "web.assets_backend": [ + "/web_group_expand/static/src/xml/list_controller.xml", + "/web_group_expand/static/src/js/list_controller.esm.js", + ], + }, +} diff --git a/web_group_expand/i18n/ca.po b/web_group_expand/i18n/ca.po new file mode 100644 index 000000000000..5ceccdb4035c --- /dev/null +++ b/web_group_expand/i18n/ca.po @@ -0,0 +1,39 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_group_expand +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-02-17 10:45+0000\n" +"Last-Translator: claudiagn \n" +"Language-Team: none\n" +"Language: ca\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: web_group_expand +#. odoo-javascript +#: code:addons/web_group_expand/static/src/xml/list_controller.xml:0 +#, python-format +msgid "Compress" +msgstr "" + +#. module: web_group_expand +#. odoo-javascript +#: code:addons/web_group_expand/static/src/xml/list_controller.xml:0 +#, python-format +msgid "Expand" +msgstr "" + +#, python-format +#~ msgid "Collapse groups" +#~ msgstr "Col·lapsar grups" + +#, python-format +#~ msgid "Expand groups" +#~ msgstr "Expandir grups" diff --git a/web_group_expand/i18n/de.po b/web_group_expand/i18n/de.po new file mode 100644 index 000000000000..dee839c1c609 --- /dev/null +++ b/web_group_expand/i18n/de.po @@ -0,0 +1,39 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_group_expand +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-10-13 20:46+0000\n" +"Last-Translator: Corneliuus \n" +"Language-Team: none\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: web_group_expand +#. odoo-javascript +#: code:addons/web_group_expand/static/src/xml/list_controller.xml:0 +#, python-format +msgid "Compress" +msgstr "" + +#. module: web_group_expand +#. odoo-javascript +#: code:addons/web_group_expand/static/src/xml/list_controller.xml:0 +#, python-format +msgid "Expand" +msgstr "" + +#, python-format +#~ msgid "Collapse groups" +#~ msgstr "Gruppen einklappen" + +#, python-format +#~ msgid "Expand groups" +#~ msgstr "Gruppen ausklappen" diff --git a/web_group_expand/i18n/es.po b/web_group_expand/i18n/es.po new file mode 100644 index 000000000000..ee16cdbd95bf --- /dev/null +++ b/web_group_expand/i18n/es.po @@ -0,0 +1,39 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_group_expand +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-10-08 23:01+0000\n" +"Last-Translator: Ivorra78 \n" +"Language-Team: none\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: web_group_expand +#. odoo-javascript +#: code:addons/web_group_expand/static/src/xml/list_controller.xml:0 +#, python-format +msgid "Compress" +msgstr "Comprimir" + +#. module: web_group_expand +#. odoo-javascript +#: code:addons/web_group_expand/static/src/xml/list_controller.xml:0 +#, python-format +msgid "Expand" +msgstr "Ampliar" + +#, python-format +#~ msgid "Collapse groups" +#~ msgstr "Colapsar grupos" + +#, python-format +#~ msgid "Expand groups" +#~ msgstr "Expandir grupos" diff --git a/web_group_expand/i18n/fr.po b/web_group_expand/i18n/fr.po new file mode 100644 index 000000000000..f0791a5b5d4c --- /dev/null +++ b/web_group_expand/i18n/fr.po @@ -0,0 +1,29 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_group_expand +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-05-06 09:24+0000\n" +"Last-Translator: timbreckx \n" +"Language-Team: none\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 5.10.4\n" + +#. module: web_group_expand +#. odoo-javascript +#: code:addons/web_group_expand/static/src/xml/list_controller.xml:0 +msgid "Compress" +msgstr "Replier" + +#. module: web_group_expand +#. odoo-javascript +#: code:addons/web_group_expand/static/src/xml/list_controller.xml:0 +msgid "Expand" +msgstr "Déplier" diff --git a/web_group_expand/i18n/fr_BE.po b/web_group_expand/i18n/fr_BE.po new file mode 100644 index 000000000000..4f70d6a8f860 --- /dev/null +++ b/web_group_expand/i18n/fr_BE.po @@ -0,0 +1,29 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_group_expand +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-05-07 13:09+0000\n" +"Last-Translator: timbreckx \n" +"Language-Team: none\n" +"Language: fr_BE\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 5.10.4\n" + +#. module: web_group_expand +#. odoo-javascript +#: code:addons/web_group_expand/static/src/xml/list_controller.xml:0 +msgid "Compress" +msgstr "Replier" + +#. module: web_group_expand +#. odoo-javascript +#: code:addons/web_group_expand/static/src/xml/list_controller.xml:0 +msgid "Expand" +msgstr "Déplier" diff --git a/web_group_expand/i18n/fr_FR.po b/web_group_expand/i18n/fr_FR.po new file mode 100644 index 000000000000..e8e28e70483c --- /dev/null +++ b/web_group_expand/i18n/fr_FR.po @@ -0,0 +1,27 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_group_expand +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: fr_FR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" + +#. module: web_group_expand +#. odoo-javascript +#: code:addons/web_group_expand/static/src/xml/list_controller.xml:0 +msgid "Compress" +msgstr "" + +#. module: web_group_expand +#. odoo-javascript +#: code:addons/web_group_expand/static/src/xml/list_controller.xml:0 +msgid "Expand" +msgstr "" diff --git a/web_group_expand/i18n/it.po b/web_group_expand/i18n/it.po new file mode 100644 index 000000000000..fd6ed615c2d0 --- /dev/null +++ b/web_group_expand/i18n/it.po @@ -0,0 +1,31 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_group_expand +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-11-27 11:34+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: web_group_expand +#. odoo-javascript +#: code:addons/web_group_expand/static/src/xml/list_controller.xml:0 +#, python-format +msgid "Compress" +msgstr "Comprimi" + +#. module: web_group_expand +#. odoo-javascript +#: code:addons/web_group_expand/static/src/xml/list_controller.xml:0 +#, python-format +msgid "Expand" +msgstr "Espandi" diff --git a/web_group_expand/i18n/nl.po b/web_group_expand/i18n/nl.po new file mode 100644 index 000000000000..daa246336750 --- /dev/null +++ b/web_group_expand/i18n/nl.po @@ -0,0 +1,39 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_group_expand +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-04-20 10:58+0000\n" +"PO-Revision-Date: 2020-04-20 12:59+0200\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: web_group_expand +#. odoo-javascript +#: code:addons/web_group_expand/static/src/xml/list_controller.xml:0 +#, python-format +msgid "Compress" +msgstr "" + +#. module: web_group_expand +#. odoo-javascript +#: code:addons/web_group_expand/static/src/xml/list_controller.xml:0 +#, python-format +msgid "Expand" +msgstr "" + +#, python-format +#~ msgid "Collapse groups" +#~ msgstr "Groepen inklappen" + +#, python-format +#~ msgid "Expand groups" +#~ msgstr "Groepen uitvouwen" diff --git a/web_group_expand/i18n/pt_BR.po b/web_group_expand/i18n/pt_BR.po new file mode 100644 index 000000000000..89dbe48ed1cf --- /dev/null +++ b/web_group_expand/i18n/pt_BR.po @@ -0,0 +1,39 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_group_expand +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-10-28 16:10+0000\n" +"Last-Translator: Adriano Prado \n" +"Language-Team: none\n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: web_group_expand +#. odoo-javascript +#: code:addons/web_group_expand/static/src/xml/list_controller.xml:0 +#, python-format +msgid "Compress" +msgstr "Comprimir" + +#. module: web_group_expand +#. odoo-javascript +#: code:addons/web_group_expand/static/src/xml/list_controller.xml:0 +#, python-format +msgid "Expand" +msgstr "Expandir" + +#, python-format +#~ msgid "Collapse groups" +#~ msgstr "Recolher grupos" + +#, python-format +#~ msgid "Expand groups" +#~ msgstr "Expandir grupos" diff --git a/web_group_expand/i18n/web_group_expand.pot b/web_group_expand/i18n/web_group_expand.pot new file mode 100644 index 000000000000..03322d3ed84b --- /dev/null +++ b/web_group_expand/i18n/web_group_expand.pot @@ -0,0 +1,26 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_group_expand +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 19.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" + +#. module: web_group_expand +#. odoo-javascript +#: code:addons/web_group_expand/static/src/xml/list_controller.xml:0 +msgid "Compress" +msgstr "" + +#. module: web_group_expand +#. odoo-javascript +#: code:addons/web_group_expand/static/src/xml/list_controller.xml:0 +msgid "Expand" +msgstr "" diff --git a/web_group_expand/pyproject.toml b/web_group_expand/pyproject.toml new file mode 100644 index 000000000000..4231d0cccb3d --- /dev/null +++ b/web_group_expand/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/web_group_expand/readme/CONTRIBUTORS.md b/web_group_expand/readme/CONTRIBUTORS.md new file mode 100644 index 000000000000..46e5537110e4 --- /dev/null +++ b/web_group_expand/readme/CONTRIBUTORS.md @@ -0,0 +1,10 @@ +- Mantavya Gajjar \<\> +- Oihane Crucelaegui \<\> +- Pedro M. Baeza \<\> +- Jay Vora (SerpentCS) for their alternative implementation +- Jan Verbeek \<\> +- Manuel Calero \<\> +- Alvaro Estebanez (brain-tec AG) \<\> +- Mayank Patel \<\> +- [360ERP](https://www.360erp.com): + - Andrea Stirpe diff --git a/web_group_expand/readme/DESCRIPTION.md b/web_group_expand/readme/DESCRIPTION.md new file mode 100644 index 000000000000..7255e7128368 --- /dev/null +++ b/web_group_expand/readme/DESCRIPTION.md @@ -0,0 +1,6 @@ +When grouping a list by a field, this module adds two buttons to expand +or collapse all the groups at once. + +The buttons appear in the top right, in place of the pagination. + +One level of groups is expanded or collapsed at a time. diff --git a/web_group_expand/static/description/icon.png b/web_group_expand/static/description/icon.png new file mode 100644 index 000000000000..775a5935375d Binary files /dev/null and b/web_group_expand/static/description/icon.png differ diff --git a/web_group_expand/static/description/index.html b/web_group_expand/static/description/index.html new file mode 100644 index 000000000000..54a30f11b69b --- /dev/null +++ b/web_group_expand/static/description/index.html @@ -0,0 +1,447 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Group Expand Buttons

+ +

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

+

When grouping a list by a field, this module adds two buttons to expand +or collapse all the groups at once.

+

The buttons appear in the top right, in place of the pagination.

+

One level of groups is expanded or collapsed at a time.

+

Table of contents

+ +
+

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

+
    +
  • OpenERP SA
  • +
  • AvanzOSC
  • +
  • Serv. Tecnol. Avanzados - Pedro M. Baeza
  • +
  • Therp BV
  • +
  • Xtendoo
  • +
+
+
+

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_group_expand/static/src/js/list_controller.esm.js b/web_group_expand/static/src/js/list_controller.esm.js new file mode 100644 index 000000000000..aea3acfe7aa3 --- /dev/null +++ b/web_group_expand/static/src/js/list_controller.esm.js @@ -0,0 +1,77 @@ +import {ListController} from "@web/views/list/list_controller"; +import {patch} from "@web/core/utils/patch"; + +function flatten(arr) { + return arr.reduce((flat, toFlatten) => { + return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten); + }, []); +} + +patch(ListController.prototype, { + async expandAllGroups() { + // We expand layer by layer. So first we need to find the highest + // layer that's not already fully expanded. + let layer = this.model.root.groups; + let max_length = 0; + while (layer.length) { + max_length = Math.max(max_length, layer.length); + const closed = layer.filter(function (group) { + return group._config.isFolded; + }); + if (closed.length) { + // This layer is not completely expanded, expand it + await layer.forEach((group) => { + group._config.isFolded = false; + }); + break; + } + // This layer is completely expanded, move to the next + layer = flatten( + layer.map(function (group) { + return group.list.groups || []; + }) + ); + } + // Save the default value of MAX_NUMBER_OPENED_GROUPS to restore it later + const default_max_opened = this.model.constructor.MAX_NUMBER_OPENED_GROUPS; + // Set in MAX_NUMBER_OPENED_GROUPS the maximum number of groups that can be opened + this.model.constructor.MAX_NUMBER_OPENED_GROUPS = max_length; + await this.model.root.load(); + // Restore the default value of MAX_NUMBER_OPENED_GROUPS + this.model.constructor.MAX_NUMBER_OPENED_GROUPS = default_max_opened; + this.model.notify(); + }, + + async collapseAllGroups() { + // We collapse layer by layer. So first we need to find the deepest + // layer that's not already fully collapsed. + let layer = this.model.root.groups; + let max_length = 0; + while (layer.length) { + max_length = Math.max(max_length, layer.length); + const next = flatten( + layer.map(function (group) { + return group.list.groups || []; + }) + ).filter(function (group) { + return !group._config.isFolded; + }); + if (!next.length) { + // Next layer is fully collapsed, so collapse this one + await layer.forEach((group) => { + group._config.isFolded = true; + }); + break; + } + layer = next; + } + // Save the default value of MAX_NUMBER_OPENED_GROUPS to restore it later + const default_max_opened = this.model.constructor.MAX_NUMBER_OPENED_GROUPS; + // Set in MAX_NUMBER_OPENED_GROUPS the maximum number of groups that can be opened + this.model.constructor.MAX_NUMBER_OPENED_GROUPS = max_length; + await this.model.root.load(); + // Restore the default value of MAX_NUMBER_OPENED_GROUPS + this.model.constructor.MAX_NUMBER_OPENED_GROUPS = default_max_opened; + this.model.notify(); + }, +}); diff --git a/web_group_expand/static/src/xml/list_controller.xml b/web_group_expand/static/src/xml/list_controller.xml new file mode 100644 index 000000000000..24b4bf716f62 --- /dev/null +++ b/web_group_expand/static/src/xml/list_controller.xml @@ -0,0 +1,23 @@ + + + + + + @@ -47,6 +48,7 @@ class="btn btn-secondary o_form_button_cancel" data-hotkey="j" t-on-click.stop="discard" + t-if="model.root.isInEdition" > @@ -57,6 +59,7 @@ class="btn btn-secondary o_form_button_create" data-hotkey="c" t-on-click.stop="create" + t-if="!model.root.isInEdition and canCreate" > @@ -77,6 +80,7 @@ class="btn btn-outline-primary o_form_button_create" data-hotkey="c" t-on-click.stop="create" + t-if="canCreate" > @@ -90,6 +94,7 @@ class="btn btn-secondary o_form_button_create" data-hotkey="c" t-on-click.stop="create" + t-if="canCreate" > @@ -115,6 +120,7 @@ accesskey="c" t-on-click="() => this.createRecord()" data-bounce-button="" + t-if="canCreate and props.showButtons" > @@ -133,6 +139,7 @@ data-hotkey="c" t-on-click="onClickCreate" data-bounce-button="" + t-if="!editedRecord and activeActions.create and props.showButtons" > diff --git a/web_search_with_and/README.rst b/web_search_with_and/README.rst new file mode 100644 index 000000000000..7b2e12895ce5 --- /dev/null +++ b/web_search_with_and/README.rst @@ -0,0 +1,111 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +==================================== +Use AND conditions on omnibar search +==================================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:136dc96228bf20333e1981f7b3d17843d17ea5dde97c86349bae2d6bf2e48e8f + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/license-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/19.0/web_search_with_and + :alt: OCA/web +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/web-19-0/web-19-0-web_search_with_and + :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=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +When searching for records on same field Odoo joins multiple queries +with OR. For example: + +- Perform a search for customer "John" on field Name +- Odoo displays customers containing "John" +- Search for "Smith" on same field Name +- Odoo displays customers containing "John" OR "Smith" + +With this module installed you can press Shift key before searching for +"Smith" and Odoo finds customers containing "John" AND "Smith" + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +- Enter your value in omnibar search field +- Press and hold Shift key +- Select field with mouse or keyboard to perform search on + +|Try me on Runbot| + +.. |Try me on Runbot| image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :target: https://runbot.odoo-community.org/runbot/162/11.0 + +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 +------- + +* Sandip SCS +* Versada UAB +* ACSONE SA/NV +* Serincloud + +Contributors +------------ + +- Andrius Preimantas +- Adrien Didenot +- Francesco Apruzzese +- Numigi (tm) and all its contributors (https://bit.ly/numigiens) +- Souheil Bejaoui +- Pedro Guirao +- Nedas Žilinskas +- Sandip SerpentCS + +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_search_with_and/__init__.py b/web_search_with_and/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web_search_with_and/__manifest__.py b/web_search_with_and/__manifest__.py new file mode 100644 index 000000000000..7b89bf1cbb2d --- /dev/null +++ b/web_search_with_and/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright 2015 Andrius Preimantas +# Copyright 2020 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +{ + "name": "Use AND conditions on omnibar search", + "version": "19.0.1.0.0", + "author": """Sandip SCS, Versada UAB, ACSONE SA/NV, Serincloud, + Odoo Community Association (OCA)""", + "license": "AGPL-3", + "category": "web", + "website": "https://github.com/OCA/web", + "depends": ["web"], + "assets": { + "web.assets_backend": [ + "/web_search_with_and/static/src/js/search_model.esm.js", + "/web_search_with_and/static/src/js/search_bar.esm.js", + ], + }, +} diff --git a/web_search_with_and/i18n/es.po b/web_search_with_and/i18n/es.po new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web_search_with_and/i18n/it.po b/web_search_with_and/i18n/it.po new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web_search_with_and/i18n/pt.po b/web_search_with_and/i18n/pt.po new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web_search_with_and/i18n/tr.po b/web_search_with_and/i18n/tr.po new file mode 100644 index 000000000000..ebd417b4f9d9 --- /dev/null +++ b/web_search_with_and/i18n/tr.po @@ -0,0 +1,14 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: tr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" diff --git a/web_search_with_and/i18n/web_search_with_and.pot b/web_search_with_and/i18n/web_search_with_and.pot new file mode 100644 index 000000000000..73e76416e0ee --- /dev/null +++ b/web_search_with_and/i18n/web_search_with_and.pot @@ -0,0 +1 @@ +# No translations. diff --git a/web_search_with_and/pyproject.toml b/web_search_with_and/pyproject.toml new file mode 100644 index 000000000000..4231d0cccb3d --- /dev/null +++ b/web_search_with_and/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/web_search_with_and/readme/CONTRIBUTORS.md b/web_search_with_and/readme/CONTRIBUTORS.md new file mode 100644 index 000000000000..b85b32382635 --- /dev/null +++ b/web_search_with_and/readme/CONTRIBUTORS.md @@ -0,0 +1,8 @@ +- Andrius Preimantas \<\> +- Adrien Didenot \<\> +- Francesco Apruzzese \<\> +- Numigi (tm) and all its contributors () +- Souheil Bejaoui \<\> +- Pedro Guirao \<\> +- Nedas Žilinskas \<\> +- Sandip SerpentCS \<\> diff --git a/web_search_with_and/readme/DESCRIPTION.md b/web_search_with_and/readme/DESCRIPTION.md new file mode 100644 index 000000000000..34571a656060 --- /dev/null +++ b/web_search_with_and/readme/DESCRIPTION.md @@ -0,0 +1,10 @@ +When searching for records on same field Odoo joins multiple queries +with OR. For example: + +- Perform a search for customer "John" on field Name +- Odoo displays customers containing "John" +- Search for "Smith" on same field Name +- Odoo displays customers containing "John" OR "Smith" + +With this module installed you can press Shift key before searching for +"Smith" and Odoo finds customers containing "John" AND "Smith" diff --git a/web_search_with_and/readme/USAGE.md b/web_search_with_and/readme/USAGE.md new file mode 100644 index 000000000000..5116254948ce --- /dev/null +++ b/web_search_with_and/readme/USAGE.md @@ -0,0 +1,5 @@ +- Enter your value in omnibar search field +- Press and hold Shift key +- Select field with mouse or keyboard to perform search on + +[![Try me on Runbot](https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas)](https://runbot.odoo-community.org/runbot/162/11.0) diff --git a/web_search_with_and/static/description/icon.png b/web_search_with_and/static/description/icon.png new file mode 100644 index 000000000000..3a0328b516c4 Binary files /dev/null and b/web_search_with_and/static/description/icon.png differ diff --git a/web_search_with_and/static/description/index.html b/web_search_with_and/static/description/index.html new file mode 100644 index 000000000000..258518cd290d --- /dev/null +++ b/web_search_with_and/static/description/index.html @@ -0,0 +1,458 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + + +
+ + diff --git a/web_search_with_and/static/src/js/search_bar.esm.js b/web_search_with_and/static/src/js/search_bar.esm.js new file mode 100644 index 000000000000..2a32d3352c80 --- /dev/null +++ b/web_search_with_and/static/src/js/search_bar.esm.js @@ -0,0 +1,97 @@ +import {onMounted, onWillUnmount} from "@odoo/owl"; +import {SearchBar} from "@web/search/search_bar/search_bar"; +import {patch} from "@web/core/utils/patch"; + +const searchBarSetup = SearchBar.prototype.setup; +const searchBarGetDropdownNavigation = SearchBar.prototype.getDropdownNavigation; + +patch(SearchBar.prototype, { + setup(...args) { + searchBarSetup.call(this, ...args); + this._searchWithAndShiftPressed = false; + this._searchWithAndHandleKeydown = (ev) => { + this._searchWithAndShiftPressed = Boolean(ev.shiftKey); + }; + this._searchWithAndHandleKeyup = (ev) => { + this._searchWithAndShiftPressed = Boolean(ev.shiftKey); + }; + onMounted(() => { + document.addEventListener( + "keydown", + this._searchWithAndHandleKeydown, + true + ); + document.addEventListener("keyup", this._searchWithAndHandleKeyup, true); + }); + onWillUnmount(() => { + document.removeEventListener( + "keydown", + this._searchWithAndHandleKeydown, + true + ); + document.removeEventListener("keyup", this._searchWithAndHandleKeyup, true); + }); + }, + + getDropdownNavigation() { + const originalNav = searchBarGetDropdownNavigation.call(this); + originalNav.hotkeys["shift+enter"] = { + bypassEditableProtection: true, + isAvailable: ({navigator}) => Boolean(navigator.activeItem), + callback: (navigator) => { + const activeItemIndex = navigator.activeItemIndex; + const item = this.items[activeItemIndex]; + if (item) { + this._searchWithAndShiftPressed = true; + this.selectItem(item); + } + }, + }; + return originalNav; + }, + + selectItem(item) { + if (item.isAddCustomFilterButton) { + return this.env.searchModel.spawnCustomFilterDialog(); + } + + const searchItem = this.getSearchItem(item.searchItemId); + if ( + (searchItem.type === "field" && searchItem.fieldType === "properties") || + (searchItem.type === "field_property" && item.unselectable) + ) { + this.toggleItem(item, !item.isExpanded); + return; + } + + if (!item.unselectable) { + const {searchItemId, label, operator, value} = item; + const isShiftPressed = + (window.event && window.event.shiftKey) || + this._searchWithAndShiftPressed; + const autoCompletionValues = { + label, + operator, + value, + isShiftKey: isShiftPressed, + }; + if (value && value[0] === '"' && value[value.length - 1] === '"') { + autoCompletionValues.value = value.slice(1, -1); + autoCompletionValues.label = label.slice(1, -1); + autoCompletionValues.operator = "="; + autoCompletionValues.enforceEqual = true; + } + this.env.searchModel.addAutoCompletionValues( + searchItemId, + autoCompletionValues + ); + } + + if (item.loadMore) { + item.loadMore(); + } else { + this.inputDropdownState.close(); + this.resetState(); + } + }, +}); diff --git a/web_search_with_and/static/src/js/search_model.esm.js b/web_search_with_and/static/src/js/search_model.esm.js new file mode 100644 index 000000000000..de03e5a3fb7f --- /dev/null +++ b/web_search_with_and/static/src/js/search_model.esm.js @@ -0,0 +1,93 @@ +import {SearchModel} from "@web/search/search_model"; +import {patch} from "@web/core/utils/patch"; +import {rankInterval} from "@web/search/utils/dates"; + +function processActiveItem(activeItem, queryElem) { + if ("generatorId" in queryElem) { + activeItem.generatorIds.push(queryElem.generatorId); + } else if ("intervalId" in queryElem) { + activeItem.intervalIds.push(queryElem.intervalId); + } else if ("autocompleteValue" in queryElem) { + activeItem.autocompleteValues.push(queryElem.autocompleteValue); + } +} + +function createActiveItem(searchItemId, queryElem) { + if ("generatorId" in queryElem) { + return {searchItemId, generatorIds: [queryElem.generatorId]}; + } + if ("intervalId" in queryElem) { + return {searchItemId, intervalIds: [queryElem.intervalId]}; + } + if ("autocompleteValue" in queryElem) { + return {searchItemId, autocompleteValues: [queryElem.autocompleteValue]}; + } + return {searchItemId}; +} + +patch(SearchModel.prototype, { + _getGroups() { + const preGroups = []; + for (const queryElem of this.query) { + const {searchItemId} = queryElem; + let {groupId} = this.searchItems[searchItemId]; + if ("autocompleteValue" in queryElem) { + if (queryElem.autocompleteValue.isShiftKey) { + groupId = Math.random(); + } + } + let preGroup = preGroups.find((group) => group.id === groupId); + if (!preGroup) { + preGroup = {id: groupId, queryElements: []}; + preGroups.push(preGroup); + } + queryElem.groupId = groupId; + preGroup.queryElements.push(queryElem); + } + const groups = []; + for (const preGroup of preGroups) { + const {queryElements, id} = preGroup; + const activeItems = []; + for (const queryElem of queryElements) { + const {searchItemId} = queryElem; + let activeItem = activeItems.find( + ({searchItemId: existingId}) => existingId === searchItemId + ); + if (activeItem) { + processActiveItem(activeItem, queryElem); + } else { + activeItem = createActiveItem(searchItemId, queryElem); + activeItems.push(activeItem); + } + } + for (const activeItem of activeItems) { + if ("intervalIds" in activeItem) { + activeItem.intervalIds.sort( + (g1, g2) => rankInterval(g1) - rankInterval(g2) + ); + } + } + groups.push({id, activeItems}); + } + + return groups; + }, + deactivateGroup(groupId) { + this.query = this.query.filter((queryElem) => { + return queryElem.groupId !== groupId; + }); + + for (const partName in this.domainParts) { + const part = this.domainParts[partName]; + if (part.groupId === groupId) { + this.setDomainParts({[partName]: null}); + } + } + if (this._checkOrderByCountStatus) { + this._checkOrderByCountStatus(); + } else if (this._checkComparisonStatus) { + this._checkComparisonStatus(); + } + this._notify(); + }, +}); diff --git a/web_tree_many2one_clickable/README.rst b/web_tree_many2one_clickable/README.rst new file mode 100644 index 000000000000..c1ca8c08b512 --- /dev/null +++ b/web_tree_many2one_clickable/README.rst @@ -0,0 +1,127 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +======================================== +Clickable many2one fields for tree views +======================================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:fcc4f4fa242a6f8602f46237e6b39090c2307cd9d11b8ceb6516e6dd2b123099 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/license-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/19.0/web_tree_many2one_clickable + :alt: OCA/web +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/web-19-0/web-19-0-web_tree_many2one_clickable + :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=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This addon forces Odoo to use many2one widget on a many2one fields in +tree views. This allows users to open linked resources from trees +directly, using a button without accessing the form. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +After installation, all many2one and reference fields will be clickable +by default. + +Usage +===== + +Put the mouse pointer over a many2one cell and click the button. + +|image| + +.. |image| image:: https://raw.githubusercontent.com/OCA/web/19.0/web_tree_many2one_clickable/static/img/clickable.gif + +Known issues / Roadmap +====================== + +This widget is currently not working on the product field in the lines +tree of the sale order form, see https://github.com/OCA/web/pull/1438 +for further details. + +To add this functionality to lines of sales, purchases and invoices, as +they are special views, is required a glue module that add this feature. + +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 +------- + +* Therp BV +* Tecnativa +* Camptocamp +* Onestein + +Contributors +------------ + +- Therp BV + +- Sodexis + +- Artem Kostyuk + +- Anand Kansagra + +- Dennis Sluijk + +- Maciej Wichowski + +- `Tecnativa `__ + + - Pedro M. Baeza + - Antonio Espinosa + - Alexandre Díaz + - Carlos Roca + +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_tree_many2one_clickable/__init__.py b/web_tree_many2one_clickable/__init__.py new file mode 100644 index 000000000000..d9d1f13deb58 --- /dev/null +++ b/web_tree_many2one_clickable/__init__.py @@ -0,0 +1 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). diff --git a/web_tree_many2one_clickable/__manifest__.py b/web_tree_many2one_clickable/__manifest__.py new file mode 100644 index 000000000000..cd701a728dda --- /dev/null +++ b/web_tree_many2one_clickable/__manifest__.py @@ -0,0 +1,32 @@ +# Copyright 2013 Therp BV (). +# Copyright 2015 Pedro M. Baeza +# Copyright 2015 Antonio Espinosa +# Copyright 2017 Sodexis +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Clickable many2one fields for tree views", + "summary": "Open the linked resource when clicking on their name", + "version": "19.0.1.0.0", + "category": "Hidden", + "website": "https://github.com/OCA/web", + "author": "Therp BV, " + "Tecnativa, " + "Camptocamp, " + "Onestein, " + "Odoo Community Association (OCA)", + "license": "AGPL-3", + "installable": True, + "depends": ["web"], + "data": [], + "assets": { + "web.assets_backend": [ + "web_tree_many2one_clickable/static/src/components/" + "many2one_button/many2one_button.esm.js", + "web_tree_many2one_clickable/static/src/components/" + "many2one_button/many2one_button.scss", + "web_tree_many2one_clickable/static/src/components/" + "many2one_button/many2one_button.xml", + ] + }, +} diff --git a/web_tree_many2one_clickable/i18n/it.po b/web_tree_many2one_clickable/i18n/it.po new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web_tree_many2one_clickable/i18n/web_tree_many2one_clickable.pot b/web_tree_many2one_clickable/i18n/web_tree_many2one_clickable.pot new file mode 100644 index 000000000000..73e76416e0ee --- /dev/null +++ b/web_tree_many2one_clickable/i18n/web_tree_many2one_clickable.pot @@ -0,0 +1 @@ +# No translations. diff --git a/web_tree_many2one_clickable/i18n/zh_CN.po b/web_tree_many2one_clickable/i18n/zh_CN.po new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/web_tree_many2one_clickable/pyproject.toml b/web_tree_many2one_clickable/pyproject.toml new file mode 100644 index 000000000000..4231d0cccb3d --- /dev/null +++ b/web_tree_many2one_clickable/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/web_tree_many2one_clickable/readme/CONFIGURE.md b/web_tree_many2one_clickable/readme/CONFIGURE.md new file mode 100644 index 000000000000..fe557cf0f498 --- /dev/null +++ b/web_tree_many2one_clickable/readme/CONFIGURE.md @@ -0,0 +1 @@ +After installation, all many2one and reference fields will be clickable by default. diff --git a/web_tree_many2one_clickable/readme/CONTRIBUTORS.md b/web_tree_many2one_clickable/readme/CONTRIBUTORS.md new file mode 100644 index 000000000000..82274cf71b58 --- /dev/null +++ b/web_tree_many2one_clickable/readme/CONTRIBUTORS.md @@ -0,0 +1,12 @@ +- Therp BV +- Sodexis \<\> +- Artem Kostyuk \<\> +- Anand Kansagra \<\> +- Dennis Sluijk \<\> +- Maciej Wichowski \<\> + +- [Tecnativa](https://www.tecnativa.com) + - Pedro M. Baeza + - Antonio Espinosa + - Alexandre Díaz + - Carlos Roca diff --git a/web_tree_many2one_clickable/readme/DESCRIPTION.md b/web_tree_many2one_clickable/readme/DESCRIPTION.md new file mode 100644 index 000000000000..8e07ea67a567 --- /dev/null +++ b/web_tree_many2one_clickable/readme/DESCRIPTION.md @@ -0,0 +1,3 @@ +This addon forces Odoo to use many2one widget on a many2one fields in +tree views. This allows users to open linked resources from trees +directly, using a button without accessing the form. diff --git a/web_tree_many2one_clickable/readme/ROADMAP.md b/web_tree_many2one_clickable/readme/ROADMAP.md new file mode 100644 index 000000000000..e24c53c65faf --- /dev/null +++ b/web_tree_many2one_clickable/readme/ROADMAP.md @@ -0,0 +1,6 @@ +This widget is currently not working on the product field in the lines +tree of the sale order form, see +for further details. + +To add this functionality to lines of sales, purchases and invoices, as +they are special views, is required a glue module that add this feature. diff --git a/web_tree_many2one_clickable/readme/USAGE.md b/web_tree_many2one_clickable/readme/USAGE.md new file mode 100644 index 000000000000..0579fc795c1d --- /dev/null +++ b/web_tree_many2one_clickable/readme/USAGE.md @@ -0,0 +1,3 @@ +Put the mouse pointer over a many2one cell and click the button. + +![image](../static/img/clickable.gif) diff --git a/web_tree_many2one_clickable/static/description/icon.png b/web_tree_many2one_clickable/static/description/icon.png new file mode 100644 index 000000000000..f1006195e022 Binary files /dev/null and b/web_tree_many2one_clickable/static/description/icon.png differ diff --git a/web_tree_many2one_clickable/static/description/index.html b/web_tree_many2one_clickable/static/description/index.html new file mode 100644 index 000000000000..4fefd83ab241 --- /dev/null +++ b/web_tree_many2one_clickable/static/description/index.html @@ -0,0 +1,467 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Clickable many2one fields for tree views

+ +

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

+

This addon forces Odoo to use many2one widget on a many2one fields in +tree views. This allows users to open linked resources from trees +directly, using a button without accessing the form.

+

Table of contents

+ +
+

Configuration

+

After installation, all many2one and reference fields will be clickable +by default.

+
+
+

Usage

+

Put the mouse pointer over a many2one cell and click the button.

+

image

+
+
+

Known issues / Roadmap

+

This widget is currently not working on the product field in the lines +tree of the sale order form, see https://github.com/OCA/web/pull/1438 +for further details.

+

To add this functionality to lines of sales, purchases and invoices, as +they are special views, is required a glue module that add this feature.

+
+
+

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

+
    +
  • Therp BV
  • +
  • Tecnativa
  • +
  • Camptocamp
  • +
  • Onestein
  • +
+
+
+

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_tree_many2one_clickable/static/img/clickable.gif b/web_tree_many2one_clickable/static/img/clickable.gif new file mode 100644 index 000000000000..a6da74e6cdef Binary files /dev/null and b/web_tree_many2one_clickable/static/img/clickable.gif differ diff --git a/web_tree_many2one_clickable/static/src/components/many2one_button/many2one_button.esm.js b/web_tree_many2one_clickable/static/src/components/many2one_button/many2one_button.esm.js new file mode 100644 index 000000000000..4097fc278f07 --- /dev/null +++ b/web_tree_many2one_clickable/static/src/components/many2one_button/many2one_button.esm.js @@ -0,0 +1,32 @@ +/* Copyright 2013 Therp BV (). + * Copyright 2015 Pedro M. Baeza + * Copyright 2016 Antonio Espinosa + * Copyright 2017 Sodexis + * Copyright 2018 Camptocamp SA + * Copyright 2019 Alexandre Díaz + * Copyright 2024 Versada (https://versada.eu) + * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */ + +import {ListRenderer} from "@web/views/list/list_renderer"; +import {patch} from "@web/core/utils/patch"; +import {useService} from "@web/core/utils/hooks"; + +patch(ListRenderer.prototype, { + setup() { + this.actionService = useService("action"); + super.setup(...arguments); + }, + async onClickM2oButton(record, column, ev) { + ev.stopPropagation(); + const field = record.fields[column.name]; + const value = record.data[column.name]; + return this.actionService.doAction({ + type: "ir.actions.act_window", + res_model: field.relation, + res_id: value && value.id, + views: [[false, "form"]], + target: "current", + additionalContext: column.context || {}, + }); + }, +}); diff --git a/web_tree_many2one_clickable/static/src/components/many2one_button/many2one_button.scss b/web_tree_many2one_clickable/static/src/components/many2one_button/many2one_button.scss new file mode 100644 index 000000000000..b6811b0391c9 --- /dev/null +++ b/web_tree_many2one_clickable/static/src/components/many2one_button/many2one_button.scss @@ -0,0 +1,10 @@ +td.o_list_many2one { + button.web_tree_many2one_clickable { + margin-left: 0.5em; + visibility: hidden; + } + + &:hover button.web_tree_many2one_clickable { + visibility: visible; + } +} diff --git a/web_tree_many2one_clickable/static/src/components/many2one_button/many2one_button.xml b/web_tree_many2one_clickable/static/src/components/many2one_button/many2one_button.xml new file mode 100644 index 000000000000..1b42fd548ce8 --- /dev/null +++ b/web_tree_many2one_clickable/static/src/components/many2one_button/many2one_button.xml @@ -0,0 +1,12 @@ + + + + +