diff --git a/web_responsive/README.rst b/web_responsive/README.rst new file mode 100644 index 000000000..8ef85d0b9 --- /dev/null +++ b/web_responsive/README.rst @@ -0,0 +1,202 @@ +============== +Web Responsive +============== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:9b3ae1467041b443396d6062ed0af40d96c2fa5e97cbce6b17e7daa93a3ee53f + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/licence-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/17.0/web_responsive + :alt: OCA/web +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/web-17-0/web-17-0-web_responsive + :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=17.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module adds responsiveness to web backend. + +**Features for all devices**: + +- New navigation with the fullscreen app menu + + |image| + +- Quick menu search inside the app menu + + |image1| + +- Sticky header & footer in list view + + |image2| + +- Sticky statusbar in form view + + |image3| + +- Bigger checkboxes in list view + + |image4| + +**Features for mobile**: \* View type picker dropdown displays +comfortably + +- Control panel buttons use icons to save space. + + |image5| + +- Followers and send button is displayed on mobile. Avatar is hidden. + + |image6| + +- Big inputs on form in edit mode + +**Features for desktop computers**: + +- Keyboard shortcuts for easier navigation, **using \`Alt + Shift + + [NUM]\`** combination instead of just Alt + [NUM] to avoid conflict + with Firefox Tab switching. Standard Odoo keyboard hotkeys changed to + be more intuitive or accessible by fingers of one hand. F.x. Alt + S + for Save + + |image7| + +- Autofocus on search menu box when opening the app menu + + |image8| + +- When the chatter is on the side part, the document viewer fills that + part for side-by-side reading instead of full screen. You can still + put it on full width preview clicking on the new maximize button. + + |image9| + +- When the user chooses to send a public message the color of the + composer is different from the one when the message is an internal + log. + + |image10| + +.. |image| image:: https://raw.githubusercontent.com/OCA/web/17.0/web_responsive/static/img/appmenu.gif +.. |image1| image:: https://raw.githubusercontent.com/OCA/web/17.0/web_responsive/static/img/appsearch.gif +.. |image2| image:: https://raw.githubusercontent.com/OCA/web/17.0/web_responsive/static/img/listview.gif +.. |image3| image:: https://raw.githubusercontent.com/OCA/web/17.0/web_responsive/static/img/formview.gif +.. |image4| image:: https://raw.githubusercontent.com/OCA/web/17.0/web_responsive/static/img/listview.gif +.. |image5| image:: https://raw.githubusercontent.com/OCA/web/17.0/web_responsive/static/img/form_buttons.gif +.. |image6| image:: https://raw.githubusercontent.com/OCA/web/17.0/web_responsive/static/img/chatter.png +.. |image7| image:: https://raw.githubusercontent.com/OCA/web/17.0/web_responsive/static/img/shortcuts.gif +.. |image8| image:: https://raw.githubusercontent.com/OCA/web/17.0/web_responsive/static/img/appsearch.gif +.. |image9| image:: https://raw.githubusercontent.com/OCA/web/17.0/web_responsive/static/img/document_viewer.gif +.. |image10| image:: https://raw.githubusercontent.com/OCA/web/17.0/web_responsive/static/img/chatter-colors.png + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +The following keyboard shortcuts are implemented: + +- Navigate app search results - Arrow keys +- Choose app result - ``Enter`` +- ``Esc`` to close app drawer + +Known issues / Roadmap +====================== + +- App navigation with keyboard. +- Handle long titles on forms in a better way + +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 +------- + +* LasLabs +* Tecnativa +* ITerra +* Onestein + +Contributors +------------ + +- Dave Lasley + +- Jairo Llopis + +- `Onestein `__: + + - Dennis Sluijk + - Anjeel Haria + +- Sergio Teruel + +- Alexandre Díaz + +- Mathias Markl + +- Iván Todorovich + +- Sergey Shebanin + +- David Vidal + +- Taras Shabaranskyi + +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 +.. |maintainer-Tardo| image:: https://github.com/Tardo.png?size=40px + :target: https://github.com/Tardo + :alt: Tardo +.. |maintainer-SplashS| image:: https://github.com/SplashS.png?size=40px + :target: https://github.com/SplashS + :alt: SplashS + +Current `maintainers `__: + +|maintainer-Yajo| |maintainer-Tardo| |maintainer-SplashS| + +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_responsive/__init__.py b/web_responsive/__init__.py new file mode 100644 index 000000000..f115f756a --- /dev/null +++ b/web_responsive/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2023 Taras Shabaranskyi +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +from . import models diff --git a/web_responsive/__manifest__.py b/web_responsive/__manifest__.py new file mode 100644 index 000000000..1fbbdad44 --- /dev/null +++ b/web_responsive/__manifest__.py @@ -0,0 +1,64 @@ +# Copyright 2016-2017 LasLabs Inc. +# Copyright 2017-2018 Tecnativa - Jairo Llopis +# Copyright 2018-2019 Tecnativa - Alexandre Díaz +# Copyright 2021 ITerra - Sergey Shebanin +# Copyright 2023 Onestein - Anjeel Haria +# Copyright 2023 Taras Shabaranskyi +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +{ + "name": "Web Responsive", + "summary": "Responsive web client, community-supported", + "version": "17.0.1.0.0", + "category": "Website", + "website": "https://github.com/OCA/web", + "author": "LasLabs, Tecnativa, ITerra, Onestein, " + "Odoo Community Association (OCA)", + "license": "LGPL-3", + "installable": True, + "depends": ["web", "mail"], + "development_status": "Production/Stable", + "maintainers": ["Yajo", "Tardo", "SplashS"], + "excludes": ["web_enterprise"], + "data": [ + "views/res_users_views.xml", + ], + "assets": { + "web._assets_primary_variables": { + "/web_responsive/static/src/legacy/scss/form_variable.scss", + "/web_responsive/static/src/legacy/scss/primary_variable.scss", + }, + "web.assets_backend": [ + "web_responsive/static/src/lib/fuse/fuse.basic.min.js", + "/web_responsive/static/src/legacy/scss/web_responsive.scss", + "/web_responsive/static/src/legacy/scss/big_boxes.scss", + "/web_responsive/static/src/legacy/scss/list_sticky_header.scss", + "/web_responsive/static/src/legacy/js/web_responsive.esm.js", + "/web_responsive/static/src/legacy/xml/form_buttons.xml", + "/web_responsive/static/src/legacy/xml/custom_favorite_item.xml", + "/web_responsive/static/src/components/apps_menu_tools.esm.js", + "/web_responsive/static/src/components/apps_menu/*", + "/web_responsive/static/src/components/apps_menu_item/*", + "/web_responsive/static/src/components/menu_canonical_searchbar/*", + "/web_responsive/static/src/components/menu_odoo_searchbar/*", + "/web_responsive/static/src/components/menu_fuse_searchbar/*", + "/web_responsive/static/src/components/menu_searchbar/*", + "/web_responsive/static/src/components/hotkey/*", + "/web_responsive/static/src/components/file_viewer/*", + "/web_responsive/static/src/components/chatter/*", + "/web_responsive/static/src/components/control_panel/*", + "/web_responsive/static/src/components/command_palette/*", + "/web_responsive/static/src/views/form/form_controller.scss", + "/web_responsive/static/src/views/form/status_bar_buttons.xml", + "/web_responsive/static/src/views/form/form_statusbar.scss", + ], + "web.assets_tests": [ + "/web_responsive/static/tests/test_patch.js", + ], + "web.qunit_suite_tests": [ + "/web_responsive/static/tests/apps_menu_tests.esm.js", + "/web_responsive/static/tests/apps_menu_search_tests.esm.js", + ], + }, + "sequence": 1, +} diff --git a/web_responsive/i18n/ar.po b/web_responsive/i18n/ar.po new file mode 100644 index 000000000..bb9ca2a90 --- /dev/null +++ b/web_responsive/i18n/ar.po @@ -0,0 +1,191 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-11-07 15:08+0000\n" +"Last-Translator: Waleed Mohsen \n" +"Language-Team: none\n" +"Language: ar\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " +"&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n" +"X-Generator: Weblate 3.10\n" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Activities" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "All" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachment counter loading..." +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachments" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "CLEAR" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Discard" +msgstr "تجاهل" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "FILTER" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Home Menu" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Log note" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "تكبير" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "تصغير" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "New" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "SEE RESULT" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Save" +msgstr "حفظ" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Search menus..." +msgstr "بحث في القوائم..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "Search..." +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Send message" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "View switcher" +msgstr "" + +#, python-format +#~ msgid "Create" +#~ msgstr "إنشاء" + +#~ msgid "Chatter Position" +#~ msgstr "موقع الدردشة" + +#, python-format +#~ msgid "Edit" +#~ msgstr "تعديل" + +#~ msgid "Normal" +#~ msgstr "عادي" + +#, python-format +#~ msgid "Quick actions" +#~ msgstr "اجراءات سريعة" + +#~ msgid "Sided" +#~ msgstr "جانبي" + +#~ msgid "Users" +#~ msgstr "المستخدمون" + +#~ msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}" +#~ msgstr "#menu_id=#{app.menuID}&action_id=#{app.actionID}" + +#~ msgid "Close" +#~ msgstr "إغلاق" + +#~ msgid "" +#~ "btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-" +#~ "none" +#~ msgstr "" +#~ "btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-" +#~ "none" + +#~ msgid "false" +#~ msgstr "false" + +#~ msgid "" +#~ "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer" +#~ msgstr "" +#~ "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer" diff --git a/web_responsive/i18n/ca.po b/web_responsive/i18n/ca.po new file mode 100644 index 000000000..cb8b5697f --- /dev/null +++ b/web_responsive/i18n/ca.po @@ -0,0 +1,175 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-02-02 22:13+0000\n" +"Last-Translator: eduardgm \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 3.10\n" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Activities" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "All" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachment counter loading..." +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachments" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "CLEAR" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Discard" +msgstr "Descartar" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "FILTER" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Home Menu" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Log note" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "Maximitzar" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "Minimitzar" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "New" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "SEE RESULT" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Save" +msgstr "Guardar" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Search menus..." +msgstr "Cercar menús..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "Search..." +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Send message" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "View switcher" +msgstr "" + +#, python-format +#~ msgid "Create" +#~ msgstr "Crear" + +#~ msgid "Chatter Position" +#~ msgstr "Posició del chatter" + +#, python-format +#~ msgid "Edit" +#~ msgstr "Editar" + +#~ msgid "Normal" +#~ msgstr "Normal" + +#, python-format +#~ msgid "Quick actions" +#~ msgstr "Accions ràpides" + +#~ msgid "Sided" +#~ msgstr "Lateral" + +#~ msgid "Users" +#~ msgstr "Usuaris" + +#~ msgid "Close" +#~ msgstr "Tancar" + +#~ msgid "false" +#~ msgstr "fals" diff --git a/web_responsive/i18n/da.po b/web_responsive/i18n/da.po new file mode 100644 index 000000000..5598eccb3 --- /dev/null +++ b/web_responsive/i18n/da.po @@ -0,0 +1,172 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 11.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2018-09-02 05:11+0000\n" +"Last-Translator: Hans Henrik Gabelgaard \n" +"Language-Team: none\n" +"Language: da\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 3.1.1\n" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Activities" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "All" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachment counter loading..." +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachments" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "CLEAR" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Discard" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "FILTER" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Home Menu" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Log note" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "New" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "SEE RESULT" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Save" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Search menus..." +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "Search..." +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Send message" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "View switcher" +msgstr "" + +#~ msgid "Chatter Position" +#~ msgstr "Log position" + +#~ msgid "Sided" +#~ msgstr "Side" + +#~ msgid "Users" +#~ msgstr "Brugere" + +#~ msgid "Toggle App Drawer" +#~ msgstr "Skift App skuffe" + +#~ msgid "Toggle Navigation" +#~ msgstr "Skift navigation" + +#~ msgid "Apps" +#~ msgstr "Applikationer" + +#~ msgid "More" +#~ msgstr "Mere" + +#~ msgid "More " +#~ msgstr "Mere " + +#~ msgid "Task" +#~ msgstr "Opgave" diff --git a/web_responsive/i18n/de.po b/web_responsive/i18n/de.po new file mode 100644 index 000000000..15c390910 --- /dev/null +++ b/web_responsive/i18n/de.po @@ -0,0 +1,187 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +# Translators: +# Niki Waibel , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-02-03 01:37+0000\n" +"PO-Revision-Date: 2023-06-20 11:09+0000\n" +"Last-Translator: Nils Coenen \n" +"Language-Team: German (https://www.transifex.com/oca/teams/23907/de/)\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.17\n" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Activities" +msgstr "Aktivitäten" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "All" +msgstr "Alles" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachment counter loading..." +msgstr "Anhangszähler wird geladen..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachments" +msgstr "Anhänge" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "CLEAR" +msgstr "LÖSCHEN" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Discard" +msgstr "Verwerfen" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "FILTER" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Home Menu" +msgstr "Home-Menü" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Log note" +msgstr "Protokollnotiz" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "maximieren" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "minimieren" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "New" +msgstr "Neu" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "SEE RESULT" +msgstr "SIEHE ERGEBNIS" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Save" +msgstr "Speichern" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Search menus..." +msgstr "Such-Menüs..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "Search..." +msgstr "Suche..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Send message" +msgstr "Nachricht senden" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "View switcher" +msgstr "Ansichtsumschalter" + +#, python-format +#~ msgid "Create" +#~ msgstr "Erstellen" + +#~ msgid "Chatter Position" +#~ msgstr "Chatter-Position" + +#, python-format +#~ msgid "Edit" +#~ msgstr "Ändern" + +#~ msgid "Normal" +#~ msgstr "normal" + +#, python-format +#~ msgid "Quick actions" +#~ msgstr "Schnell-Aktion" + +#~ msgid "Sided" +#~ msgstr "Seitlich" + +#~ msgid "Users" +#~ msgstr "Benutzer" + +#~ msgid "Close" +#~ msgstr "Schließen" + +#~ msgid "Toggle App Drawer" +#~ msgstr "App Ordner umschalten" + +#~ msgid "Toggle Navigation" +#~ msgstr "Navigation umschalten" + +#~ msgid "Apps" +#~ msgstr "Apps" + +#~ msgid "More " +#~ msgstr "Mehr " diff --git a/web_responsive/i18n/es.po b/web_responsive/i18n/es.po new file mode 100644 index 000000000..d81b20e2e --- /dev/null +++ b/web_responsive/i18n/es.po @@ -0,0 +1,196 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +# Translators: +# Pedro M. Baeza , 2016 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-01-10 10:49+0000\n" +"PO-Revision-Date: 2023-09-20 17:50+0000\n" +"Last-Translator: kikopeiro \n" +"Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/es/)\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Activities" +msgstr "Actividades" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "All" +msgstr "Todos" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachment counter loading..." +msgstr "Carga del contador de archivos adjuntos..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachments" +msgstr "Archivos adjuntos" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "CLEAR" +msgstr "LIMPIAR" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Discard" +msgstr "Descartar" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "FILTER" +msgstr "FILTRAR" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Home Menu" +msgstr "Menú de Inicio" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Log note" +msgstr "Nota de registro" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "Maximizar" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "Minimizar" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "New" +msgstr "Nuevo" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "SEE RESULT" +msgstr "VER RESULTADO" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Save" +msgstr "Guardar" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Search menus..." +msgstr "Buscar menús..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "Search..." +msgstr "Búsqueda..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Send message" +msgstr "Enviar mensaje" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "View switcher" +msgstr "Vista del conmutador" + +#, python-format +#~ msgid "Create" +#~ msgstr "Crear" + +#~ msgid "Chatter Position" +#~ msgstr "Posición del chatter" + +#, python-format +#~ msgid "Edit" +#~ msgstr "Editar" + +#~ msgid "Normal" +#~ msgstr "Normal" + +#, python-format +#~ msgid "Quick actions" +#~ msgstr "Acciones rápidas" + +#~ msgid "Sided" +#~ msgstr "Lateral" + +#~ msgid "Users" +#~ msgstr "Usuarios" + +#~ msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}" +#~ msgstr "#menu_id=#{app.menuID}&action_id=#{app.actionID}" + +#~ msgid "Close" +#~ msgstr "Cerrar" + +#~ msgid "Shift" +#~ msgstr "Turno" + +#~ msgid "" +#~ "btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-" +#~ "none" +#~ msgstr "" +#~ "btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-" +#~ "none" + +#~ msgid "false" +#~ msgstr "falso" + +#~ msgid "" +#~ "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer" +#~ msgstr "" +#~ "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer" diff --git a/web_responsive/i18n/fr.po b/web_responsive/i18n/fr.po new file mode 100644 index 000000000..5d2d145cf --- /dev/null +++ b/web_responsive/i18n/fr.po @@ -0,0 +1,195 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-03-13 14:23+0000\n" +"Last-Translator: Rémi \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.14.1\n" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Activities" +msgstr "Activités" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "All" +msgstr "Tout" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachment counter loading..." +msgstr "Chargement du compteur de pièces jointes..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachments" +msgstr "Pièces Jointes" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "CLEAR" +msgstr "NETTOYER" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Discard" +msgstr "Annuler" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "FILTER" +msgstr "FILTRER" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Home Menu" +msgstr "Menu d’accueil" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Log note" +msgstr "Enregistrer une note" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "Maximiser" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "Minimiser" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "New" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "SEE RESULT" +msgstr "VOIR RÉSULTAT" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Save" +msgstr "Enregistrer" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Search menus..." +msgstr "Rechercher dans les menus..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "Search..." +msgstr "Rechercher…" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Send message" +msgstr "Envoyer un message" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "View switcher" +msgstr "Bascule de vue" + +#, python-format +#~ msgid "Create" +#~ msgstr "Créer" + +#~ msgid "Chatter Position" +#~ msgstr "Position de la messagerie" + +#, python-format +#~ msgid "Clear" +#~ msgstr "Nettoyer" + +#, python-format +#~ msgid "Edit" +#~ msgstr "Editer" + +#~ msgid "Normal" +#~ msgstr "Normal" + +#, python-format +#~ msgid "Quick actions" +#~ msgstr "Actions rapides" + +#~ msgid "Sided" +#~ msgstr "À coté" + +#, python-format +#~ msgid "Today" +#~ msgstr "Aujourd’hui" + +#, python-format +#~ msgid "Undefined" +#~ msgstr "Non défini" + +#~ msgid "Users" +#~ msgstr "Utilisateurs" + +#, python-format +#~ msgid "props.withAccessKey ? 'x' : false" +#~ msgstr "props.withAccessKey ? 'x' : false" + +#, python-format +#~ msgid "props.withAccessKey ? 'z' : false" +#~ msgstr "props.withAccessKey ? 'z' : false" + +#~ msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}" +#~ msgstr "#menu_id=#{app.menuID}&action_id=#{app.actionID}" + +#~ msgid "Close" +#~ msgstr "Fermer" diff --git a/web_responsive/i18n/fr_FR.po b/web_responsive/i18n/fr_FR.po new file mode 100644 index 000000000..9d209573c --- /dev/null +++ b/web_responsive/i18n/fr_FR.po @@ -0,0 +1,169 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-04-11 18:46+0000\n" +"Last-Translator: Yves Le Doeuff \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" +"X-Generator: Weblate 4.3.2\n" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Activities" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "All" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachment counter loading..." +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachments" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "CLEAR" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Discard" +msgstr "Annuler" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "FILTER" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Home Menu" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Log note" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "Maximiser" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "Minimiser" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "New" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "SEE RESULT" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Save" +msgstr "Sauvegarder" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Search menus..." +msgstr "Rechercher dans les menus..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "Search..." +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Send message" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "View switcher" +msgstr "" + +#, python-format +#~ msgid "Create" +#~ msgstr "Créer" + +#~ msgid "Chatter Position" +#~ msgstr "Position du Chatter" + +#, python-format +#~ msgid "Edit" +#~ msgstr "Editer" + +#~ msgid "Normal" +#~ msgstr "Normal" + +#, python-format +#~ msgid "Quick actions" +#~ msgstr "Actions rapides" + +#~ msgid "Sided" +#~ msgstr "À coté" + +#~ msgid "Users" +#~ msgstr "Utilisateurs" diff --git a/web_responsive/i18n/hr.po b/web_responsive/i18n/hr.po new file mode 100644 index 000000000..8c440ee61 --- /dev/null +++ b/web_responsive/i18n/hr.po @@ -0,0 +1,161 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +# Translators: +# Bole , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-04-28 18:03+0000\n" +"PO-Revision-Date: 2023-04-03 13:22+0000\n" +"Last-Translator: Bole \n" +"Language-Team: Croatian (https://www.transifex.com/oca/teams/23907/hr/)\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_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Activities" +msgstr "Aktivnosti" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "All" +msgstr "Sve" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachment counter loading..." +msgstr "Učitavam brojač priloga..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachments" +msgstr "Prilozi" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "CLEAR" +msgstr "OČISTI" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Discard" +msgstr "Odustani" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "FILTER" +msgstr "TRAŽI" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Home Menu" +msgstr "Glavni izbornik" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Log note" +msgstr "Zabilježi napomenu" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "Maksimiziraj" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "Minimiziraj" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "New" +msgstr "Novi" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "SEE RESULT" +msgstr "VIDI REZULTAT" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Save" +msgstr "Spremi" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Search menus..." +msgstr "Pretraži izbornike..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "Search..." +msgstr "Pretraži..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Send message" +msgstr "Pošalji poruku" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "View switcher" +msgstr "Izmjena pogleda" + +#~ msgid "Toggle App Drawer" +#~ msgstr "Izmjeni izbornik aplikacije" + +#~ msgid "Toggle Navigation" +#~ msgstr "Izmjeni navigaciju" + +#~ msgid "Apps" +#~ msgstr "Apikacije" + +#~ msgid "More " +#~ msgstr "Više " diff --git a/web_responsive/i18n/nl.po b/web_responsive/i18n/nl.po new file mode 100644 index 000000000..a70e92e8c --- /dev/null +++ b/web_responsive/i18n/nl.po @@ -0,0 +1,183 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.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_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Activities" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "All" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachment counter loading..." +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachments" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "CLEAR" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Discard" +msgstr "Negeren" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "FILTER" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Home Menu" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Log note" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "Maximaliseren" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "Minimaliseren" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "New" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "SEE RESULT" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Save" +msgstr "Opslaan" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Search menus..." +msgstr "Zoek menu's..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "Search..." +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Send message" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "View switcher" +msgstr "" + +#, python-format +#~ msgid "Create" +#~ msgstr "Aanmaken" + +#~ msgid "Chatter Position" +#~ msgstr "Chatter Positie" + +#, python-format +#~ msgid "Edit" +#~ msgstr "Bewerken" + +#~ msgid "Normal" +#~ msgstr "Normaal" + +#, python-format +#~ msgid "Quick actions" +#~ msgstr "Snelle Acties" + +#~ msgid "Sided" +#~ msgstr "Aan de zijkant" + +#~ msgid "Users" +#~ msgstr "Gebruikers" + +#~ msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}" +#~ msgstr "#menu_id=#{app.menuID}&action_id=#{app.actionID}" + +#~ msgid "Close" +#~ msgstr "Sluit" + +#, fuzzy +#~ msgid "Shift" +#~ msgstr "Shift" + +#, fuzzy +#~ msgid "false" +#~ msgstr "false" diff --git a/web_responsive/i18n/pl.po b/web_responsive/i18n/pl.po new file mode 100644 index 000000000..f0f5aec57 --- /dev/null +++ b/web_responsive/i18n/pl.po @@ -0,0 +1,185 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 15.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2022-08-08 23:07+0000\n" +"Last-Translator: Jacek Michalski \n" +"Language-Team: none\n" +"Language: pl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Activities" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "All" +msgstr "Wszystkie" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachment counter loading..." +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachments" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "CLEAR" +msgstr "WYCZYŚĆ" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Discard" +msgstr "Odrzuć" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "FILTER" +msgstr "FILTRUJ" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Home Menu" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Log note" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "Zmaksymalizuj" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "Zminimalizuj" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "New" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "SEE RESULT" +msgstr "ZOBACZ WYNIK" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Save" +msgstr "Zapisz" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Search menus..." +msgstr "Przeszukaj menu..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "Search..." +msgstr "Szukaj..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Send message" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "View switcher" +msgstr "Przełącznik widoku" + +#, python-format +#~ msgid "Create" +#~ msgstr "Utwórz" + +#~ msgid "Chatter Position" +#~ msgstr "Pozycja Czatu" + +#, python-format +#~ msgid "Clear" +#~ msgstr "Wyczyść" + +#, python-format +#~ msgid "Edit" +#~ msgstr "Edytuj" + +#~ msgid "Normal" +#~ msgstr "Normalna" + +#, python-format +#~ msgid "Quick actions" +#~ msgstr "Szybkie akcje" + +#~ msgid "Sided" +#~ msgstr "Z boku" + +#, python-format +#~ msgid "Today" +#~ msgstr "Dzisiaj" + +#, python-format +#~ msgid "Undefined" +#~ msgstr "Niezdefiniowane" + +#~ msgid "Users" +#~ msgstr "Użytkownicy" + +#~ msgid "fade" +#~ msgstr "wygasanie" diff --git a/web_responsive/i18n/pt.po b/web_responsive/i18n/pt.po new file mode 100644 index 000000000..51ce4964d --- /dev/null +++ b/web_responsive/i18n/pt.po @@ -0,0 +1,169 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2019-08-12 11:44+0000\n" +"Last-Translator: Pedro Castro Silva \n" +"Language-Team: none\n" +"Language: pt\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 3.7.1\n" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Activities" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "All" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachment counter loading..." +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachments" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "CLEAR" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Discard" +msgstr "Descartar" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "FILTER" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Home Menu" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Log note" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "New" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "SEE RESULT" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Save" +msgstr "Gravar" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Search menus..." +msgstr "Procurar menus..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "Search..." +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Send message" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "View switcher" +msgstr "" + +#, python-format +#~ msgid "Create" +#~ msgstr "Criar" + +#~ msgid "Chatter Position" +#~ msgstr "Posição do Chatter" + +#, python-format +#~ msgid "Edit" +#~ msgstr "Editar" + +#~ msgid "Normal" +#~ msgstr "Normal" + +#, python-format +#~ msgid "Quick actions" +#~ msgstr "Ações rápidas" + +#~ msgid "Sided" +#~ msgstr "Lateralizado" + +#~ msgid "Users" +#~ msgstr "Utilizadores" diff --git a/web_responsive/i18n/pt_BR.po b/web_responsive/i18n/pt_BR.po new file mode 100644 index 000000000..03a8954ef --- /dev/null +++ b/web_responsive/i18n/pt_BR.po @@ -0,0 +1,202 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +# Translators: +# Rodrigo de Almeida Sottomaior Macedo , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-06-22 08:27+0000\n" +"PO-Revision-Date: 2023-10-28 16:10+0000\n" +"Last-Translator: Adriano Prado \n" +"Language-Team: Portuguese (Brazil) (https://www.transifex.com/oca/teams/" +"23907/pt_BR/)\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_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Activities" +msgstr "Atividades" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "All" +msgstr "Tudo" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachment counter loading..." +msgstr "Carregando do contador de anexos..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachments" +msgstr "Anexos" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "CLEAR" +msgstr "LIMPAR" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Discard" +msgstr "Descartar" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "FILTER" +msgstr "FILTRAR" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Home Menu" +msgstr "Menu Inicial" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Log note" +msgstr "Nota de Registro" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "Maximizar" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "Minimizar" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "New" +msgstr "Novo" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "SEE RESULT" +msgstr "VER RESULTADO" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Save" +msgstr "Salvar" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Search menus..." +msgstr "Pesquisar menus..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "Search..." +msgstr "Procurar..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Send message" +msgstr "Enviar menssagem" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "View switcher" +msgstr "Ver alternador" + +#, python-format +#~ msgid "Create" +#~ msgstr "Criar" + +#~ msgid "Chatter Position" +#~ msgstr "Posição do Chatter" + +#, python-format +#~ msgid "Edit" +#~ msgstr "Editar" + +#~ msgid "Normal" +#~ msgstr "Normal" + +#, python-format +#~ msgid "Quick actions" +#~ msgstr "Ações rápidas" + +#~ msgid "Sided" +#~ msgstr "Frente e verso" + +#~ msgid "Users" +#~ msgstr "Usuários" + +#~ msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}" +#~ msgstr "#menu_id=#{app.menuID}&action_id=#{app.actionID}" + +#~ msgid "Close" +#~ msgstr "Fechar" + +#~ msgid "false" +#~ msgstr "falso" + +#~ msgid "" +#~ "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer" +#~ msgstr "" +#~ "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer" + +#~ msgid "Toggle App Drawer" +#~ msgstr "Aplicativo Desenhador Alternativo" + +#~ msgid "Toggle Navigation" +#~ msgstr "Navegação Alternativa" + +#~ msgid "Apps" +#~ msgstr "Aplicativos" + +#~ msgid "HTTP routing" +#~ msgstr "roteamento HTTP" + +#~ msgid "More " +#~ msgstr "Mais " diff --git a/web_responsive/i18n/ru.po b/web_responsive/i18n/ru.po new file mode 100644 index 000000000..be579c03b --- /dev/null +++ b/web_responsive/i18n/ru.po @@ -0,0 +1,181 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-03-31 16:36+0000\n" +"Last-Translator: SplashS \n" +"Language-Team: none\n" +"Language: ru\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.3.2\n" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Activities" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "All" +msgstr "Все" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachment counter loading..." +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachments" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "CLEAR" +msgstr "Очистить" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Discard" +msgstr "Отменить" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "FILTER" +msgstr "Фильтр" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Home Menu" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Log note" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "Увеличить" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "Уменьшить" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "New" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "SEE RESULT" +msgstr "Применить" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Save" +msgstr "Сохранить" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Search menus..." +msgstr "Поиск по меню..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "Search..." +msgstr "Поиск..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Send message" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "View switcher" +msgstr "Сменить вид" + +#, python-format +#~ msgid "Create" +#~ msgstr "Создать" + +#~ msgid "Chatter Position" +#~ msgstr "Расположение Чата" + +#, python-format +#~ msgid "Edit" +#~ msgstr "Править" + +#~ msgid "Normal" +#~ msgstr "Снизу" + +#, python-format +#~ msgid "Quick actions" +#~ msgstr "Действия" + +#~ msgid "Sided" +#~ msgstr "Справа" + +#, python-format +#~ msgid "Today" +#~ msgstr "Сегодня" + +#, python-format +#~ msgid "Undefined" +#~ msgstr "Не определено" + +#~ msgid "Users" +#~ msgstr "Пользователи" + +#~ msgid "Display Name" +#~ msgstr "Видимое имя" diff --git a/web_responsive/i18n/tr.po b/web_responsive/i18n/tr.po new file mode 100644 index 000000000..e23b0cbad --- /dev/null +++ b/web_responsive/i18n/tr.po @@ -0,0 +1,149 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 15.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-03-07 08:01+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_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Activities" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "All" +msgstr "Hepsi" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachment counter loading..." +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachments" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "CLEAR" +msgstr "TEMİZLEME" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Discard" +msgstr "Vazgeç" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "FILTER" +msgstr "FİLTRE" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Home Menu" +msgstr "Ana Menü" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Log note" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "Büyütme" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "Küçültme" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "New" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "SEE RESULT" +msgstr "SONUCU GÖR" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Save" +msgstr "Kaydet" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Search menus..." +msgstr "Arama menüleri..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "Search..." +msgstr "Arama..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Send message" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "View switcher" +msgstr "Görüntü Değiştiriciyi" + +#, python-format +#~ msgid "Create" +#~ msgstr "Oluşturma" diff --git a/web_responsive/i18n/uk_UA.po b/web_responsive/i18n/uk_UA.po new file mode 100644 index 000000000..20b265b55 --- /dev/null +++ b/web_responsive/i18n/uk_UA.po @@ -0,0 +1,105 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0-20231123\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-11-25 15:27+0000\n" +"PO-Revision-Date: 2023-11-25 15:27+0000\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_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/views/form/status_bar_buttons.xml:0 +#, python-format +msgid "Action" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu_searchbar/apps_menu_searchbar.xml:0 +#, python-format +msgid "App Icon" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Discard" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Home Menu" +msgstr "Головне меню" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter/chatter.xml:0 +#, python-format +msgid "Log note" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/file_viewer/file_viewer.xml:0 +#: code:addons/web_responsive/static/src/components/file_viewer/file_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "Збільшити" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/file_viewer/file_viewer.xml:0 +#: code:addons/web_responsive/static/src/components/file_viewer/file_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "Згорнути" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "New" +msgstr "Новий" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu_searchbar/apps_menu_searchbar.xml:0 +#, python-format +msgid "Nothing to show" +msgstr "Нема чого показати" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Save" +msgstr "Зберегти" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu_searchbar/apps_menu_searchbar.xml:0 +#, python-format +msgid "Search menus..." +msgstr "Пошук..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter/chatter.xml:0 +#, python-format +msgid "Send message" +msgstr "Надіслати повідомлення" diff --git a/web_responsive/i18n/web_responsive.pot b/web_responsive/i18n/web_responsive.pot new file mode 100644 index 000000000..4f7477b79 --- /dev/null +++ b/web_responsive/i18n/web_responsive.pot @@ -0,0 +1,157 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.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_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Activities" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "All" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachment counter loading..." +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachments" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "CLEAR" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Discard" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "FILTER" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Home Menu" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Log note" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "New" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "SEE RESULT" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Save" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Search menus..." +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "Search..." +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Send message" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "View switcher" +msgstr "" diff --git a/web_responsive/i18n/zh_CN.po b/web_responsive/i18n/zh_CN.po new file mode 100644 index 000000000..7003f41ac --- /dev/null +++ b/web_responsive/i18n/zh_CN.po @@ -0,0 +1,190 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * web_responsive +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-07-08 05:19+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.10\n" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Activities" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "All" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachment counter loading..." +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Attachments" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "CLEAR" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Discard" +msgstr "丢弃" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "FILTER" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Home Menu" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Log note" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Maximize" +msgstr "最大化" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/attachment_viewer/attachment_viewer.xml:0 +#, python-format +msgid "Minimize" +msgstr "最小化" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "New" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#: code:addons/web_responsive/static/src/components/search_panel/search_panel.xml:0 +#, python-format +msgid "SEE RESULT" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/legacy/xml/form_buttons.xml:0 +#, python-format +msgid "Save" +msgstr "保存" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/apps_menu/apps_menu.xml:0 +#, python-format +msgid "Search menus..." +msgstr "搜索菜单..." + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "Search..." +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/chatter_topbar/chatter_topbar.xml:0 +#, python-format +msgid "Send message" +msgstr "" + +#. module: web_responsive +#. odoo-javascript +#: code:addons/web_responsive/static/src/components/control_panel/control_panel.xml:0 +#, python-format +msgid "View switcher" +msgstr "" + +#, python-format +#~ msgid "Create" +#~ msgstr "创建" + +#~ msgid "Chatter Position" +#~ msgstr "聊天位置" + +#, python-format +#~ msgid "Edit" +#~ msgstr "编辑" + +#~ msgid "Normal" +#~ msgstr "正常" + +#, python-format +#~ msgid "Quick actions" +#~ msgstr "快捷方式" + +#~ msgid "Sided" +#~ msgstr "侧面" + +#~ msgid "Users" +#~ msgstr "用户" + +#~ msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}" +#~ msgstr "#menu_id=#{app.menuID}&action_id=#{app.actionID}" + +#~ msgid "Close" +#~ msgstr "关闭" + +#~ msgid "" +#~ "btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-" +#~ "none" +#~ msgstr "" +#~ "btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-" +#~ "none" + +#~ msgid "false" +#~ msgstr "false" + +#~ msgid "" +#~ "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer" +#~ msgstr "" +#~ "modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer" diff --git a/web_responsive/models/__init__.py b/web_responsive/models/__init__.py new file mode 100644 index 000000000..c6b5178dd --- /dev/null +++ b/web_responsive/models/__init__.py @@ -0,0 +1,5 @@ +# Copyright 2023 Taras Shabaranskyi +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +from . import res_users +from . import ir_http diff --git a/web_responsive/models/ir_http.py b/web_responsive/models/ir_http.py new file mode 100644 index 000000000..98fff28ac --- /dev/null +++ b/web_responsive/models/ir_http.py @@ -0,0 +1,19 @@ +# Copyright 2023 Taras Shabaranskyi +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +from odoo import models + + +class IrHttp(models.AbstractModel): + _inherit = "ir.http" + + def session_info(self): + session = super().session_info() + user = self.env.user + return { + **session, + "apps_menu": { + "search_type": user.apps_menu_search_type, + "theme": user.apps_menu_theme, + }, + } diff --git a/web_responsive/models/res_users.py b/web_responsive/models/res_users.py new file mode 100644 index 000000000..7b67ccaaa --- /dev/null +++ b/web_responsive/models/res_users.py @@ -0,0 +1,26 @@ +# Copyright 2023 Taras Shabaranskyi +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +from odoo import fields, models + + +class ResUsers(models.Model): + _inherit = "res.users" + + apps_menu_search_type = fields.Selection( + [ + ("canonical", "Canonical"), + ("fuse", "Fuse"), + ("command_palette", "Command Palette"), + ], + default="canonical", + required=True, + ) + apps_menu_theme = fields.Selection( + [ + ("milk", "Milk"), + ("community", "Community"), + ], + default="milk", + required=True, + ) diff --git a/web_responsive/pyproject.toml b/web_responsive/pyproject.toml new file mode 100644 index 000000000..4231d0ccc --- /dev/null +++ b/web_responsive/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/web_responsive/readme/CONTRIBUTORS.md b/web_responsive/readme/CONTRIBUTORS.md new file mode 100644 index 000000000..dc659b2fa --- /dev/null +++ b/web_responsive/readme/CONTRIBUTORS.md @@ -0,0 +1,21 @@ +- Dave Lasley \<\> + +- Jairo Llopis \<\> + +- [Onestein](https://www.onestein.nl): + - Dennis Sluijk \<\> + - Anjeel Haria + +- Sergio Teruel \<\> + +- Alexandre Díaz \<\> + +- Mathias Markl \<\> + +- Iván Todorovich \<\> + +- Sergey Shebanin \<\> + +- David Vidal \<\> + +- Taras Shabaranskyi \<\> diff --git a/web_responsive/readme/DESCRIPTION.md b/web_responsive/readme/DESCRIPTION.md new file mode 100644 index 000000000..d7e22a902 --- /dev/null +++ b/web_responsive/readme/DESCRIPTION.md @@ -0,0 +1,62 @@ +This module adds responsiveness to web backend. + +**Features for all devices**: + +- New navigation with the fullscreen app menu + + ![image](../static/img/appmenu.gif) + +- Quick menu search inside the app menu + + ![image](../static/img/appsearch.gif) + +- Sticky header & footer in list view + + ![image](../static/img/listview.gif) + +- Sticky statusbar in form view + + ![image](../static/img/formview.gif) + +- Bigger checkboxes in list view + + ![image](../static/img/listview.gif) + +**Features for mobile**: \* View type picker dropdown displays +comfortably + +- Control panel buttons use icons to save space. + + ![image](../static/img/form_buttons.gif) + +- Followers and send button is displayed on mobile. Avatar is hidden. + + ![image](../static/img/chatter.png) + +- Big inputs on form in edit mode + +**Features for desktop computers**: + +- Keyboard shortcuts for easier navigation, **using \`Alt + Shift + + \[NUM\]\`** combination instead of just Alt + \[NUM\] to avoid + conflict with Firefox Tab switching. Standard Odoo keyboard hotkeys + changed to be more intuitive or accessible by fingers of one hand. + F.x. Alt + S for Save + + ![image](../static/img/shortcuts.gif) + +- Autofocus on search menu box when opening the app menu + + ![image](../static/img/appsearch.gif) + +- When the chatter is on the side part, the document viewer fills that + part for side-by-side reading instead of full screen. You can still + put it on full width preview clicking on the new maximize button. + + ![image](../static/img/document_viewer.gif) + +- When the user chooses to send a public message the color of the + composer is different from the one when the message is an internal + log. + + ![image](../static/img/chatter-colors.png) diff --git a/web_responsive/readme/ROADMAP.md b/web_responsive/readme/ROADMAP.md new file mode 100644 index 000000000..5772fcad3 --- /dev/null +++ b/web_responsive/readme/ROADMAP.md @@ -0,0 +1,2 @@ +- App navigation with keyboard. +- Handle long titles on forms in a better way diff --git a/web_responsive/readme/USAGE.md b/web_responsive/readme/USAGE.md new file mode 100644 index 000000000..4b2b6b3cc --- /dev/null +++ b/web_responsive/readme/USAGE.md @@ -0,0 +1,5 @@ +The following keyboard shortcuts are implemented: + +- Navigate app search results - Arrow keys +- Choose app result - `Enter` +- `Esc` to close app drawer diff --git a/web_responsive/static/description/icon.png b/web_responsive/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/web_responsive/static/description/icon.png differ diff --git a/web_responsive/static/description/index.html b/web_responsive/static/description/index.html new file mode 100644 index 000000000..94d762b35 --- /dev/null +++ b/web_responsive/static/description/index.html @@ -0,0 +1,510 @@ + + + + + + +Web Responsive + + + +
+

Web Responsive

+ + +

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

+

This module adds responsiveness to web backend.

+

Features for all devices:

+
    +
  • New navigation with the fullscreen app menu

    +

    image

    +
  • +
  • Quick menu search inside the app menu

    +

    image1

    +
  • +
  • Sticky header & footer in list view

    +

    image2

    +
  • +
  • Sticky statusbar in form view

    +

    image3

    +
  • +
  • Bigger checkboxes in list view

    +

    image4

    +
  • +
+

Features for mobile: * View type picker dropdown displays +comfortably

+
    +
  • Control panel buttons use icons to save space.

    +

    image5

    +
  • +
  • Followers and send button is displayed on mobile. Avatar is hidden.

    +

    image6

    +
  • +
  • Big inputs on form in edit mode

    +
  • +
+

Features for desktop computers:

+
    +
  • Keyboard shortcuts for easier navigation, using `Alt + Shift + +[NUM]` combination instead of just Alt + [NUM] to avoid conflict +with Firefox Tab switching. Standard Odoo keyboard hotkeys changed to +be more intuitive or accessible by fingers of one hand. F.x. Alt + S +for Save

    +

    image7

    +
  • +
  • Autofocus on search menu box when opening the app menu

    +

    image8

    +
  • +
  • When the chatter is on the side part, the document viewer fills that +part for side-by-side reading instead of full screen. You can still +put it on full width preview clicking on the new maximize button.

    +

    image9

    +
  • +
  • When the user chooses to send a public message the color of the +composer is different from the one when the message is an internal +log.

    +

    image10

    +
  • +
+

Table of contents

+ +
+

Usage

+

The following keyboard shortcuts are implemented:

+
    +
  • Navigate app search results - Arrow keys
  • +
  • Choose app result - Enter
  • +
  • Esc to close app drawer
  • +
+
+
+

Known issues / Roadmap

+
    +
  • App navigation with keyboard.
  • +
  • Handle long titles on forms in a better way
  • +
+
+
+

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

+
    +
  • LasLabs
  • +
  • Tecnativa
  • +
  • ITerra
  • +
  • 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.

+

Current maintainers:

+

Yajo Tardo SplashS

+

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_responsive/static/img/appmenu.gif b/web_responsive/static/img/appmenu.gif new file mode 100644 index 000000000..9cb67bf1e Binary files /dev/null and b/web_responsive/static/img/appmenu.gif differ diff --git a/web_responsive/static/img/appsearch.gif b/web_responsive/static/img/appsearch.gif new file mode 100644 index 000000000..412fc8944 Binary files /dev/null and b/web_responsive/static/img/appsearch.gif differ diff --git a/web_responsive/static/img/breadcrumbs.gif b/web_responsive/static/img/breadcrumbs.gif new file mode 100644 index 000000000..6a6be4da4 Binary files /dev/null and b/web_responsive/static/img/breadcrumbs.gif differ diff --git a/web_responsive/static/img/calendar.gif b/web_responsive/static/img/calendar.gif new file mode 100644 index 000000000..6168e1919 Binary files /dev/null and b/web_responsive/static/img/calendar.gif differ diff --git a/web_responsive/static/img/chatter-colors.png b/web_responsive/static/img/chatter-colors.png new file mode 100644 index 000000000..e07af30d2 Binary files /dev/null and b/web_responsive/static/img/chatter-colors.png differ diff --git a/web_responsive/static/img/chatter.png b/web_responsive/static/img/chatter.png new file mode 100644 index 000000000..23182827f Binary files /dev/null and b/web_responsive/static/img/chatter.png differ diff --git a/web_responsive/static/img/chatter_sided.gif b/web_responsive/static/img/chatter_sided.gif new file mode 100644 index 000000000..0a99a1fa0 Binary files /dev/null and b/web_responsive/static/img/chatter_sided.gif differ diff --git a/web_responsive/static/img/chatter_topbar.gif b/web_responsive/static/img/chatter_topbar.gif new file mode 100644 index 000000000..09ded196f Binary files /dev/null and b/web_responsive/static/img/chatter_topbar.gif differ diff --git a/web_responsive/static/img/default_icon_app.png b/web_responsive/static/img/default_icon_app.png new file mode 100644 index 000000000..8fc87e959 Binary files /dev/null and b/web_responsive/static/img/default_icon_app.png differ diff --git a/web_responsive/static/img/device_rotation.gif b/web_responsive/static/img/device_rotation.gif new file mode 100644 index 000000000..f501cc789 Binary files /dev/null and b/web_responsive/static/img/device_rotation.gif differ diff --git a/web_responsive/static/img/document_viewer.gif b/web_responsive/static/img/document_viewer.gif new file mode 100644 index 000000000..fe90d31b1 Binary files /dev/null and b/web_responsive/static/img/document_viewer.gif differ diff --git a/web_responsive/static/img/dropdown_scroll.gif b/web_responsive/static/img/dropdown_scroll.gif new file mode 100644 index 000000000..5a5ac7bb7 Binary files /dev/null and b/web_responsive/static/img/dropdown_scroll.gif differ diff --git a/web_responsive/static/img/form_buttons.gif b/web_responsive/static/img/form_buttons.gif new file mode 100644 index 000000000..93f989722 Binary files /dev/null and b/web_responsive/static/img/form_buttons.gif differ diff --git a/web_responsive/static/img/formview.gif b/web_responsive/static/img/formview.gif new file mode 100644 index 000000000..cd6117426 Binary files /dev/null and b/web_responsive/static/img/formview.gif differ diff --git a/web_responsive/static/img/hamburger.gif b/web_responsive/static/img/hamburger.gif new file mode 100644 index 000000000..c94fed08c Binary files /dev/null and b/web_responsive/static/img/hamburger.gif differ diff --git a/web_responsive/static/img/kanban.gif b/web_responsive/static/img/kanban.gif new file mode 100644 index 000000000..217ac0d15 Binary files /dev/null and b/web_responsive/static/img/kanban.gif differ diff --git a/web_responsive/static/img/label_size_large.png b/web_responsive/static/img/label_size_large.png new file mode 100644 index 000000000..e91b01801 Binary files /dev/null and b/web_responsive/static/img/label_size_large.png differ diff --git a/web_responsive/static/img/label_size_small.png b/web_responsive/static/img/label_size_small.png new file mode 100644 index 000000000..1337a6499 Binary files /dev/null and b/web_responsive/static/img/label_size_small.png differ diff --git a/web_responsive/static/img/listview.gif b/web_responsive/static/img/listview.gif new file mode 100644 index 000000000..96ed91cf3 Binary files /dev/null and b/web_responsive/static/img/listview.gif differ diff --git a/web_responsive/static/img/mobile_search.gif b/web_responsive/static/img/mobile_search.gif new file mode 100644 index 000000000..6ab7c342b Binary files /dev/null and b/web_responsive/static/img/mobile_search.gif differ diff --git a/web_responsive/static/img/navbar.gif b/web_responsive/static/img/navbar.gif new file mode 100644 index 000000000..52b09e4d6 Binary files /dev/null and b/web_responsive/static/img/navbar.gif differ diff --git a/web_responsive/static/img/search_panel.gif b/web_responsive/static/img/search_panel.gif new file mode 100644 index 000000000..13d3e7a3f Binary files /dev/null and b/web_responsive/static/img/search_panel.gif differ diff --git a/web_responsive/static/img/shortcuts.gif b/web_responsive/static/img/shortcuts.gif new file mode 100644 index 000000000..97bd0df8b Binary files /dev/null and b/web_responsive/static/img/shortcuts.gif differ diff --git a/web_responsive/static/img/usermenu.gif b/web_responsive/static/img/usermenu.gif new file mode 100644 index 000000000..d43a72177 Binary files /dev/null and b/web_responsive/static/img/usermenu.gif differ diff --git a/web_responsive/static/src/components/apps_menu/apps_menu.esm.js b/web_responsive/static/src/components/apps_menu/apps_menu.esm.js new file mode 100644 index 000000000..b9c9e3e0b --- /dev/null +++ b/web_responsive/static/src/components/apps_menu/apps_menu.esm.js @@ -0,0 +1,123 @@ +/** @odoo-module **/ +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Onestein - Anjeel Haria + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +import {Component, useState} from "@odoo/owl"; +import {session} from "@web/session"; +import {useBus, useService} from "@web/core/utils/hooks"; +import {AppMenuItem} from "@web_responsive/components/apps_menu_item/apps_menu_item.esm"; +import {AppsMenuSearchBar} from "@web_responsive/components/menu_searchbar/searchbar.esm"; +import {NavBar} from "@web/webclient/navbar/navbar"; +import {WebClient} from "@web/webclient/webclient"; +import {patch} from "@web/core/utils/patch"; +import {useHotkey} from "@web/core/hotkeys/hotkey_hook"; + +// Patch WebClient to show AppsMenu instead of default app +patch(WebClient.prototype, { + setup() { + super.setup(); + useBus(this.env.bus, "APPS_MENU:STATE_CHANGED", ({detail: state}) => { + document.body.classList.toggle("o_apps_menu_opened", state); + }); + }, +}); + +export class AppsMenu extends Component { + setup() { + super.setup(); + this.state = useState({open: false}); + this.theme = session.apps_menu.theme || "milk"; + this.menuService = useService("menu"); + useBus(this.env.bus, "ACTION_MANAGER:UI-UPDATED", () => { + this.setOpenState(false); + }); + this._setupKeyNavigation(); + } + + setOpenState(open_state) { + this.state.open = open_state; + this.env.bus.trigger("APPS_MENU:STATE_CHANGED", open_state); + } + + /** + * Setup navigation among app menus + */ + _setupKeyNavigation() { + const repeatable = { + allowRepeat: true, + }; + useHotkey( + "ArrowRight", + () => { + this._onWindowKeydown("next"); + }, + repeatable + ); + useHotkey( + "ArrowLeft", + () => { + this._onWindowKeydown("prev"); + }, + repeatable + ); + useHotkey( + "ArrowDown", + () => { + this._onWindowKeydown("next"); + }, + repeatable + ); + useHotkey( + "ArrowUp", + () => { + this._onWindowKeydown("prev"); + }, + repeatable + ); + useHotkey("Escape", () => { + this.env.bus.trigger("ACTION_MANAGER:UI-UPDATED"); + }); + } + + _onWindowKeydown(direction) { + const focusableInputElements = document.querySelectorAll(".o-app-menu-item"); + if (focusableInputElements.length) { + const focusable = [...focusableInputElements]; + const index = focusable.indexOf(document.activeElement); + let nextIndex = 0; + if (direction === "prev" && index >= 0) { + if (index > 0) { + nextIndex = index - 1; + } else { + nextIndex = focusable.length - 1; + } + } else if (direction === "next") { + if (index + 1 < focusable.length) { + nextIndex = index + 1; + } else { + nextIndex = 0; + } + } + focusableInputElements[nextIndex].focus(); + } + } + + onMenuClick() { + this.setOpenState(!this.state.open); + } +} + +Object.assign(AppsMenu, { + template: "web_responsive.AppsMenu", + props: { + slots: { + type: Object, + optional: true, + }, + }, +}); + +Object.assign(NavBar.components, {AppsMenu, AppMenuItem, AppsMenuSearchBar}); diff --git a/web_responsive/static/src/components/apps_menu/apps_menu.scss b/web_responsive/static/src/components/apps_menu/apps_menu.scss new file mode 100644 index 000000000..6ddfe5790 --- /dev/null +++ b/web_responsive/static/src/components/apps_menu/apps_menu.scss @@ -0,0 +1,109 @@ +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +:root { + .o_grid_apps_menu[data-theme="milk"] { + --app-menu-background: url("../../img/home-menu-bg-overlay.svg"), + linear-gradient( + to bottom, + #{$app-menu-background-color}, + #{desaturate(lighten($app-menu-background-color, 20%), 15)} + ); + } + + .o_grid_apps_menu[data-theme="community"] { + --app-menu-background: url("../../img/home-menu-bg-overlay.svg"), + linear-gradient( + to bottom, + #{$o-brand-primary}, + #{desaturate(lighten($o-brand-primary, 20%), 15)} + ); + } +} + +@mixin full-screen-dropdown { + border: none; + box-shadow: none; + height: 100%; + max-height: calc(var(--vh100, 100vh) - #{$o-navbar-height}); + max-height: calc(100dvh - #{$o-navbar-height}); + position: fixed; + margin: 0; + width: 100vw; + z-index: 1000; + left: 0 !important; +} + +.o_apps_menu_opened .o_main_navbar { + .o_menu_brand, + .o_menu_sections { + display: none !important; + } +} + +// hide and save odoo default QUnit tests +.o_navbar_apps_menu.hide .dropdown-toggle { + position: absolute !important; + z-index: -100 !important; +} + +// Iconized full screen apps menu +.o_grid_apps_menu { + &__button { + background: unset; + border: unset; + outline: unset; + margin-right: 0.25rem; + min-height: $o-navbar-height; + height: $o-navbar-height; + width: $o-navbar-height; + color: $o-navbar-brand-color; + + &:hover, + &:focus { + background: $o-navbar-entry-bg--hover; + } + } + + .o-app-menu-list { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); + width: 100%; + gap: 0.25rem; + + @include media-breakpoint-up(sm) { + grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); + } + } +} + +.app-menu-container { + @include full-screen-dropdown(); + overflow: auto; + background-clip: border-box; + padding: 1rem 0.5rem; + gap: 1rem; + background: var(--app-menu-background); + background-size: cover; + border-radius: 0; + // Display apps in a grid + align-content: flex-start; + display: flex !important; + flex-direction: row; + flex-wrap: wrap; + justify-content: flex-start; + + // Hide app icons when searching + .has-results ~ .o-app-menu-list { + display: none; + } + + @include media-breakpoint-up(lg) { + padding: { + left: calc((100vw - 850px) / 2); + right: calc((100vw - 850px) / 2); + } + } +} diff --git a/web_responsive/static/src/components/apps_menu/apps_menu.xml b/web_responsive/static/src/components/apps_menu/apps_menu.xml new file mode 100644 index 000000000..7e0a877f5 --- /dev/null +++ b/web_responsive/static/src/components/apps_menu/apps_menu.xml @@ -0,0 +1,51 @@ + + + + + + 'o_navbar_apps_menu hide' + true + + + + + + + + + + + + + + +
+ +
+ +
+ +
+
+
+
+
diff --git a/web_responsive/static/src/components/apps_menu/apps_menu_preferences.esm.js b/web_responsive/static/src/components/apps_menu/apps_menu_preferences.esm.js new file mode 100644 index 000000000..9f6678ff4 --- /dev/null +++ b/web_responsive/static/src/components/apps_menu/apps_menu_preferences.esm.js @@ -0,0 +1,39 @@ +/** @odoo-module **/ +/* Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +import {Component, xml} from "@odoo/owl"; +import {registry} from "@web/core/registry"; +import {useService} from "@web/core/utils/hooks"; + +class AppsMenuPreferences extends Component { + setup() { + this.action = useService("action"); + this.user = useService("user"); + } + + async _onClick() { + const onClose = () => this.action.doAction("reload_context"); + const action = await this.action.loadAction( + "web_responsive.res_users_view_form_apps_menu_preferences_action" + ); + this.action.doAction({...action, res_id: this.user.userId}, {onClose}).then(); + } +} + +AppsMenuPreferences.template = xml` + +`; + +registry + .category("systray") + .add("AppMenuTheme", {Component: AppsMenuPreferences}, {sequence: 100}); diff --git a/web_responsive/static/src/components/apps_menu_item/apps_menu_item.esm.js b/web_responsive/static/src/components/apps_menu_item/apps_menu_item.esm.js new file mode 100644 index 000000000..70b271240 --- /dev/null +++ b/web_responsive/static/src/components/apps_menu_item/apps_menu_item.esm.js @@ -0,0 +1,53 @@ +/** @odoo-module **/ +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Onestein - Anjeel Haria + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +import {Component, onWillUpdateProps} from "@odoo/owl"; +import {getWebIconData} from "@web_responsive/components/apps_menu_tools.esm"; + +export class AppMenuItem extends Component { + setup() { + super.setup(); + this.webIconData = getWebIconData(this.props.app); + onWillUpdateProps(this.onUpdateProps); + } + + get isActive() { + const {currentApp} = this.props; + return currentApp && currentApp.id === this.props.app.id; + } + + get className() { + const classItems = ["o-app-menu-item"]; + if (this.isActive) { + classItems.push("active"); + } + return classItems.join(" "); + } + + onUpdateProps(nextProps) { + this.webIconData = getWebIconData(nextProps.app); + } + + onClick() { + if (typeof this.props.onClick === "function") { + this.props.onClick(this.props.app); + } + } +} + +Object.assign(AppMenuItem, { + template: "web_responsive.AppMenuItem", + props: { + app: Object, + href: String, + currentApp: { + type: Object, + optional: true, + }, + onClick: Function, + }, +}); diff --git a/web_responsive/static/src/components/apps_menu_item/apps_menu_item.scss b/web_responsive/static/src/components/apps_menu_item/apps_menu_item.scss new file mode 100644 index 000000000..029a0df29 --- /dev/null +++ b/web_responsive/static/src/components/apps_menu_item/apps_menu_item.scss @@ -0,0 +1,73 @@ +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +:root { + .o_grid_apps_menu[data-theme="milk"] { + --app-menu-text-color: #{$app-menu-text-color}; + --app-menu-text-shadow: 1px 1px 1px #{rgba($white, 0.4)}; + --app-menu-hover-background: #{rgba(white, 0.4)}; + } + + .o_grid_apps_menu[data-theme="community"] { + --app-menu-text-color: white; + --app-menu-text-shadow: 1px 1px 1px #{rgba(black, 0.4)}; + --app-menu-hover-background: #{rgba(white, 0.2)}; + } +} + +.o-app-menu-item { + display: flex; + flex-direction: column; + border-radius: 4px; + gap: 0.25rem; + transition: ease box-shadow, transform, 0.3s; + background: unset; + outline: unset; + border: unset; + padding: 0.75rem 0.5rem; + justify-content: flex-start; + align-items: center; + white-space: normal; + user-select: none; + height: -moz-available; + height: max-content; + + &__name { + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; + font-size: 1em; + text-shadow: var(--app-menu-text-shadow); + color: var(--app-menu-text-color); + text-align: center; + } + + &__icon { + height: auto; + max-width: 64px; + width: 64px; + aspect-ratio: 1; + padding: 10px; + background-color: white; + box-shadow: $app-menu-box-shadow; + } + + &__active { + position: absolute; + bottom: 2px; + right: 2px; + text-shadow: 0 0 2px rgba(250, 250, 250, 0.6); + color: $app-menu-text-color; + } + + &:focus, + &:hover { + transform: translateY(-4px); + box-shadow: 0 6px 12px -8px transparentize($app-menu-text-color, 0.6); + background-color: var(--app-menu-hover-background) !important; + backdrop-filter: blur(2px); + } +} diff --git a/web_responsive/static/src/components/apps_menu_item/apps_menu_item.xml b/web_responsive/static/src/components/apps_menu_item/apps_menu_item.xml new file mode 100644 index 000000000..a25834bc7 --- /dev/null +++ b/web_responsive/static/src/components/apps_menu_item/apps_menu_item.xml @@ -0,0 +1,33 @@ + + + + + +
+ + +
+ + + +
+
+
diff --git a/web_responsive/static/src/components/apps_menu_tools.esm.js b/web_responsive/static/src/components/apps_menu_tools.esm.js new file mode 100644 index 000000000..6749dd71a --- /dev/null +++ b/web_responsive/static/src/components/apps_menu_tools.esm.js @@ -0,0 +1,77 @@ +/** @odoo-module **/ + +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Onestein - Anjeel Haria + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +export function getWebIconData(menu) { + const result = "/web_responsive/static/img/default_icon_app.png"; + const iconData = menu.webIconData; + if (!iconData) { + return result; + } + const prefix = iconData.startsWith("P") + ? "data:image/svg+xml;base64," + : "data:image/png;base64,"; + if (iconData.startsWith("data:image")) { + return iconData; + } + return prefix + iconData.replace(/\s/g, ""); +} + +/** + * @param {Object} menu + */ +export function updateMenuWebIconData(menu) { + menu.webIconData = menu.webIconData ? getWebIconData(menu) : ""; +} + +export function updateMenuDisplayName(menu) { + menu.displayName = menu.name.trim(); +} + +/** + * @param {Object} menu + * @returns {Boolean} + */ +export function isRootMenu(menu) { + return menu.actionID && menu.appID === menu.id; +} + +/** + * @param {Object[]} memo + * @param {Object|null} parentMenu + * @param {Object} menu + * @returns {Object[]} + */ +export function collectSubMenuItems(memo, parentMenu, menu) { + const menuCopy = Object.assign({}, menu); + updateMenuDisplayName(menuCopy); + if (parentMenu) { + menuCopy.displayName = `${parentMenu.displayName} / ${menuCopy.displayName}`; + } + if (menuCopy.actionID && !isRootMenu(menuCopy)) { + memo.push(menuCopy); + } + for (const child of menuCopy.childrenTree || []) { + collectSubMenuItems(memo, menuCopy, child); + } + return memo; +} + +/** + * @param {Object[]} memo + * @param {Object} menu + * @returns {Object} + */ +export function collectRootMenuItems(memo, menu) { + if (isRootMenu(menu)) { + const menuCopy = Object.assign({}, menu); + updateMenuWebIconData(menuCopy); + updateMenuDisplayName(menuCopy); + memo.push(menuCopy); + } + return memo; +} diff --git a/web_responsive/static/src/components/chatter/chatter.esm.js b/web_responsive/static/src/components/chatter/chatter.esm.js new file mode 100644 index 000000000..b12fc7ae0 --- /dev/null +++ b/web_responsive/static/src/components/chatter/chatter.esm.js @@ -0,0 +1,28 @@ +/** @odoo-module **/ +/* Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Onestein - Anjeel Haria + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +import {Chatter} from "@mail/core/web/chatter"; +import {patch} from "@web/core/utils/patch"; +import {useEffect} from "@odoo/owl"; + +patch(Chatter.prototype, { + setup() { + super.setup(); + useEffect(this._resetScrollToAttachmentsEffect.bind(this), () => [ + this.state.isAttachmentBoxOpened, + ]); + }, + /** + * Prevent scrollIntoView error + * @param {Boolean} isAttachmentBoxOpened + * @private + */ + _resetScrollToAttachmentsEffect(isAttachmentBoxOpened) { + if (!isAttachmentBoxOpened) { + this.state.scrollToAttachments = 0; + } + }, +}); diff --git a/web_responsive/static/src/components/chatter/chatter.scss b/web_responsive/static/src/components/chatter/chatter.scss new file mode 100644 index 000000000..6ea395863 --- /dev/null +++ b/web_responsive/static/src/components/chatter/chatter.scss @@ -0,0 +1,42 @@ +/* Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +.o-mail-Composer { + grid-template-areas: + "sidebar-header core-header" + "core-main core-main" + "sidebar-footer core-footer"; + + .o-mail-Composer-sidebarMain { + display: none; + } + + @include media-breakpoint-up(sm) { + grid-template-areas: + "sidebar-header core-header" + "sidebar-main core-main" + "sidebar-footer core-footer"; + + .o-mail-Composer-sidebarMain { + display: block; + } + + .o-mail-SuggestedRecipient { + margin-left: 42px; + } + } +} + +.o-mail-Form-chatter { + .o-mail-SuggestedRecipient, + .o-mail-Chatter-recipientList { + margin-left: 0; + } + + @include media-breakpoint-up(sm) { + .o-mail-SuggestedRecipient, + .o-mail-Chatter-recipientList { + margin-left: 42px; + } + } +} diff --git a/web_responsive/static/src/components/chatter/chatter.xml b/web_responsive/static/src/components/chatter/chatter.xml new file mode 100644 index 000000000..689004572 --- /dev/null +++ b/web_responsive/static/src/components/chatter/chatter.xml @@ -0,0 +1,69 @@ + + + + + + '' + + + + + + + + + + + + + + + + + + + diff --git a/web_responsive/static/src/components/command_palette/main.esm.js b/web_responsive/static/src/components/command_palette/main.esm.js new file mode 100644 index 000000000..a23fe795e --- /dev/null +++ b/web_responsive/static/src/components/command_palette/main.esm.js @@ -0,0 +1,21 @@ +/** @odoo-module **/ + +import {useState} from "@odoo/owl"; +import {useService} from "@web/core/utils/hooks"; +import {CommandPalette} from "@web/core/commands/command_palette"; +import {patch} from "@web/core/utils/patch"; + +export const unpatchCommandPalette = patch(CommandPalette.prototype, { + setup() { + super.setup(); + this.ui = useState(useService("ui")); + }, + + get small() { + return this.ui.size < 2; + }, + + get contentClass() { + return `o_command_palette ${this.small ? "" : "mt-5"}`; + }, +}); diff --git a/web_responsive/static/src/components/command_palette/main.scss b/web_responsive/static/src/components/command_palette/main.scss new file mode 100644 index 000000000..834b8b8db --- /dev/null +++ b/web_responsive/static/src/components/command_palette/main.scss @@ -0,0 +1,28 @@ +.o_command_palette { + .o_command_palette_exit { + display: none; + } + + @include media-breakpoint-down(sm) { + .o_command_palette_root { + display: flex; + max-height: 100vh; + max-height: 100dvh; + flex-direction: column; + height: 100%; + justify-content: space-between; + } + .o_command_palette_exit { + display: block; + } + .o_command_palette_search { + flex-shrink: 0; + } + .o_command_palette_listbox { + max-height: unset; + } + .o_command_palette_footer { + flex-shrink: 0; + } + } +} diff --git a/web_responsive/static/src/components/command_palette/main.xml b/web_responsive/static/src/components/command_palette/main.xml new file mode 100644 index 000000000..a49723e7e --- /dev/null +++ b/web_responsive/static/src/components/command_palette/main.xml @@ -0,0 +1,24 @@ + + + + + contentClass + + + o_command_palette_root + + +
+ +
+
+
+
diff --git a/web_responsive/static/src/components/control_panel/control_panel.esm.js b/web_responsive/static/src/components/control_panel/control_panel.esm.js new file mode 100644 index 000000000..b1bfb4dca --- /dev/null +++ b/web_responsive/static/src/components/control_panel/control_panel.esm.js @@ -0,0 +1,73 @@ +/** @odoo-module **/ +/* Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +import {ControlPanel} from "@web/search/control_panel/control_panel"; +import {patch} from "@web/core/utils/patch"; +import {browser} from "@web/core/browser/browser"; + +export const STICKY_CLASS = "o_mobile_sticky"; + +/** + * @param {Number} delay + * @returns {{collect: function(Number, (function(Number, Number): void)): void}} + */ +export function minMaxCollector(delay = 100) { + const state = { + id: null, + items: [], + }; + + function min() { + return Math.min.apply(null, state.items); + } + + function max() { + return Math.max.apply(null, state.items); + } + + return { + collect(value, callback) { + clearTimeout(state.id); + state.items.push(value); + state.id = setTimeout(() => { + callback(min(), max()); + state.items = []; + state.id = null; + }, delay); + }, + }; +} + +export const unpatchControlPanel = patch(ControlPanel.prototype, { + scrollValueCollector: undefined, + /** @type {Number}*/ + scrollHeaderGap: undefined, + setup() { + super.setup(); + this.scrollValueCollector = minMaxCollector(100); + this.scrollHeaderGap = 2; + }, + onScrollThrottled() { + if (this.isScrolling) { + return; + } + this.isScrolling = true; + browser.requestAnimationFrame(() => (this.isScrolling = false)); + + /** @type {HTMLElement}*/ + const rootEl = this.root.el; + const scrollTop = this.getScrollingElement().scrollTop; + const activeAnimation = scrollTop > this.initialScrollTop; + + rootEl.classList.toggle(STICKY_CLASS, activeAnimation); + this.scrollValueCollector.collect(scrollTop - this.oldScrollTop, (min, max) => { + const delta = min + max; + if (delta < -this.scrollHeaderGap || delta > this.scrollHeaderGap) { + rootEl.style.top = `${delta < 0 ? -rootEl.clientHeight : 0}px`; + } + }); + + this.oldScrollTop = scrollTop; + }, +}); diff --git a/web_responsive/static/src/components/file_viewer/file_viewer.esm.js b/web_responsive/static/src/components/file_viewer/file_viewer.esm.js new file mode 100644 index 000000000..145a84445 --- /dev/null +++ b/web_responsive/static/src/components/file_viewer/file_viewer.esm.js @@ -0,0 +1,77 @@ +/** @odoo-module **/ +/* Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Onestein - Anjeel Haria + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +import {onMounted, onWillStart, useExternalListener, useRef} from "@odoo/owl"; +import {FileViewer} from "@web/core/file_viewer/file_viewer"; +import {patch} from "@web/core/utils/patch"; + +const formChatterClassName = ".o-mail-Form-chatter"; +const formViewSheetClassName = ".o_form_view_container .o_form_sheet_bg"; + +export function useFileViewerContainerSize(ref) { + function updateActualFormChatterSize() { + /** @type {HTMLDivElement}*/ + const chatterElement = document.querySelector(formChatterClassName); + /** @type {HTMLDivElement}*/ + const formSheetElement = document.querySelector(formViewSheetClassName); + if (chatterElement && formSheetElement && ref.el) { + /** @type {CSSStyleDeclaration}*/ + const elStyle = ref.el.style; + const width = `${chatterElement.clientWidth}px`; + const height = `${chatterElement.clientHeight}px`; + const left = `${formSheetElement.clientWidth}px`; + elStyle.setProperty("--o-FileViewerContainer-width", width); + elStyle.setProperty("--o-FileViewerContainer-height", height); + elStyle.setProperty("--o-FileViewerContainer-left", left); + } + } + + useExternalListener(window, "resize", () => { + requestAnimationFrame(updateActualFormChatterSize); + }); + onMounted(() => { + requestAnimationFrame(updateActualFormChatterSize); + }); +} + +/** + * Patch attachment viewer to add min/max buttons capability + * @property {Function} resizeUpdateActualFormChatterWidth + */ +patch(FileViewer.prototype, { + setup() { + super.setup(); + this.root = useRef("root"); + Object.assign(this.state, { + allowMinimize: false, + maximized: true, + }); + useFileViewerContainerSize(this.root); + onWillStart(this.setDefaultMaximizeState); + }, + + get rootClass() { + return { + modal: this.props.modal, + "o-FileViewerContainer__maximized": this.state.maximized, + "o-FileViewerContainer__minimized": !this.state.maximized, + }; + }, + + setDefaultMaximizeState() { + this.state.allowMinimize = Boolean( + document.querySelector(`${formChatterClassName}.o-aside`) + ); + this.state.maximized = !this.state.allowMinimize; + }, + + /** + * @param {Boolean} value + */ + setMaximized(value) { + this.state.maximized = value; + }, +}); diff --git a/web_responsive/static/src/components/file_viewer/file_viewer.scss b/web_responsive/static/src/components/file_viewer/file_viewer.scss new file mode 100644 index 000000000..f528e8333 --- /dev/null +++ b/web_responsive/static/src/components/file_viewer/file_viewer.scss @@ -0,0 +1,56 @@ +/* Copyright 2019 Tecnativa - Alexandre Díaz + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +.o-FileViewerContainer { + --o-FileViewerContainer-width: #{$o-mail-Chatter-minWidth}; + --o-FileViewerContainer-height: var(--100vh, calc(100vh - #{$o-navbar-height})); + --o-FileViewerContainer-left: unset; + --o-FileViewerContainer-right: 0; + + position: fixed; + right: 0; + z-index: $zindex-fixed; + + &__maximized { + top: 0; + left: 0; + right: 0; + } + + &__minimized { + width: 100%; + max-width: var(--o-FileViewerContainer-width, #{$o-mail-Chatter-minWidth}); + height: var(--o-FileViewerContainer-height); + top: unset; + right: var(--o-FileViewerContainer-right, 0); + left: var(--o-FileViewerContainer-left, unset); + bottom: 0; + + .o-FileViewer-main { + padding: $o-navbar-height 0 0 0; + } + + .o-FileViewer-viewPdf { + width: 100% !important; + } + } + + .o-FileViewer-navigation { + background-color: rgba(255, 255, 255, 0.2); + text-shadow: 0 0 rgba(30, 30, 30, 0.8); + box-shadow: 0 0 1px 0 rgba(30, 30, 30, 0.4); + transition: background-color 0.2s, box-shadow 0.2s; + + &:hover { + background-color: rgba(255, 255, 255, 0.8); + text-shadow: 0 0 black; + box-shadow: 0 0 2px 0 rgba(30, 30, 30, 0.8); + } + } +} + +.o_apps_menu_opened .o-FileViewerContainer { + display: none !important; +} diff --git a/web_responsive/static/src/components/file_viewer/file_viewer.xml b/web_responsive/static/src/components/file_viewer/file_viewer.xml new file mode 100644 index 000000000..ace2e1d10 --- /dev/null +++ b/web_responsive/static/src/components/file_viewer/file_viewer.xml @@ -0,0 +1,47 @@ + + + diff --git a/web_responsive/static/src/components/hotkey/hotkey.scss b/web_responsive/static/src/components/hotkey/hotkey.scss new file mode 100644 index 000000000..392c01238 --- /dev/null +++ b/web_responsive/static/src/components/hotkey/hotkey.scss @@ -0,0 +1,12 @@ +/* Copyright 2021 ITerra - Sergey Shebanin + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +// Shortcut table ui improvement +.o_shortcut_table { + width: 100%; + white-space: nowrap; + max-width: 400px; + td { + padding: 0 20px; + } +} diff --git a/web_responsive/static/src/components/hotkey/hotkey.xml b/web_responsive/static/src/components/hotkey/hotkey.xml new file mode 100644 index 000000000..d9b615c92 --- /dev/null +++ b/web_responsive/static/src/components/hotkey/hotkey.xml @@ -0,0 +1,26 @@ + + + + + + 'shift+' + ((section_index + 1) % 10).toString() + + + 'shift+' + (sectionsVisibleCount + 1 % 10).toString() + + + diff --git a/web_responsive/static/src/components/menu_canonical_searchbar/searchbar.esm.js b/web_responsive/static/src/components/menu_canonical_searchbar/searchbar.esm.js new file mode 100644 index 000000000..265778e43 --- /dev/null +++ b/web_responsive/static/src/components/menu_canonical_searchbar/searchbar.esm.js @@ -0,0 +1,207 @@ +/** @odoo-module **/ +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Onestein - Anjeel Haria + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +import {Component, onPatched, onWillPatch, useRef, useState} from "@odoo/owl"; +import { + collectRootMenuItems, + collectSubMenuItems, +} from "@web_responsive/components/apps_menu_tools.esm"; +import {useAutofocus, useService} from "@web/core/utils/hooks"; +import {debounce} from "@web/core/utils/timing"; +import {escapeRegExp} from "@web/core/utils/strings"; +import {fuzzyLookup} from "@web/core/utils/search"; +import {scrollTo} from "@web/core/utils/scrolling"; + +/** + * @extends Component + */ +export class AppsMenuCanonicalSearchBar extends Component { + setup() { + super.setup(); + this.state = useState({ + rootItems: [], + subItems: [], + offset: 0, + hasResults: false, + }); + this.searchBarInput = useAutofocus({refName: "SearchBarInput"}); + this._searchMenus = debounce(this._searchMenus, 200); + this.menuService = useService("menu"); + this.searchItemsRef = useRef("searchItems"); + this.rootMenuItems = this.getRootMenuItems(); + this.subMenuItems = this.getSubMenuItems(); + onWillPatch(this._computeResultOffset); + onPatched(this._scrollToHighlight); + } + + /** + * @returns {String} + */ + get inputValue() { + const {el} = this.searchBarInput; + return el ? el.value : ""; + } + + /** + * @returns {Boolean} + */ + get hasItemsToDisplay() { + return this.totalItemsCount > 0; + } + + /** + * @returns {Number} + */ + get totalItemsCount() { + const {rootItems, subItems} = this.state; + return rootItems.length + subItems.length; + } + + /** + * @param {Number} index + * @param {Boolean} isSubMenu + * @returns {String} + */ + highlighted(index, isSubMenu = false) { + const {state} = this; + let _index = index; + if (isSubMenu) { + _index = state.rootItems.length + index; + } + return _index === state.offset ? "highlight" : ""; + } + + /** + * @returns {Object[]} + */ + getRootMenuItems() { + return this.menuService.getApps().reduce(collectRootMenuItems, []); + } + + /** + * @returns {Object[]} + */ + getSubMenuItems() { + const response = []; + for (const menu of this.menuService.getApps()) { + const menuTree = this.menuService.getMenuAsTree(menu.id); + collectSubMenuItems(response, null, menuTree); + } + return response; + } + + /** + * Search among available menu items, and render that search. + */ + _searchMenus() { + const {state} = this; + const query = this.inputValue; + state.hasResults = query !== ""; + if (!state.hasResults) { + state.rootItems = []; + state.subItems = []; + return; + } + const searchField = (item) => item.displayName; + state.rootItems = fuzzyLookup(query, this.rootMenuItems, searchField); + state.subItems = fuzzyLookup(query, this.subMenuItems, searchField); + } + + _onKeyDown(ev) { + const code = ev.code; + if (code === "Escape") { + ev.stopPropagation(); + ev.preventDefault(); + if (this.inputValue) { + this.searchBarInput.el.value = ""; + Object.assign(this.state, {rootItems: [], subItems: []}); + this.state.hasResults = false; + } else { + this.env.bus.trigger("ACTION_MANAGER:UI-UPDATED"); + } + } else if (code === "Tab") { + if (this.searchItemsRef.el) { + ev.preventDefault(); + if (ev.shiftKey) { + this.state.offset--; + } else { + this.state.offset++; + } + } + } else if (code === "ArrowUp") { + if (this.searchItemsRef.el) { + ev.preventDefault(); + this.state.offset--; + } + } else if (code === "ArrowDown") { + if (this.searchItemsRef.el) { + ev.preventDefault(); + this.state.offset++; + } + } else if (code === "Enter") { + const element = this.searchItemsRef.el; + if (this.hasItemsToDisplay && element) { + ev.preventDefault(); + this._selectHighlightedSearchItem(element); + } + } else if (code === "Home") { + this.state.offset = 0; + } else if (code === "End") { + this.state.offset = this.totalItemsCount - 1; + } + } + + /** + * @param {HTMLElement} element + * @private + */ + _selectHighlightedSearchItem(element) { + const highlightedElement = element.querySelector( + ".highlight > .search-item__link" + ); + if (highlightedElement) { + highlightedElement.click(); + } else { + console.warn("Highlighted search item is not found"); + } + } + + _splitName(name) { + if (!name) { + return []; + } + const value = this.inputValue; + const splitName = name.split(new RegExp(`(${escapeRegExp(value)})`, "ig")); + return value.length && splitName.length > 1 ? splitName : [name]; + } + + _scrollToHighlight() { + // Scroll to selected element on keyboard navigation + const element = this.searchItemsRef.el; + if (!(this.totalItemsCount && element)) { + return; + } + const activeElement = element.querySelector(".highlight"); + if (activeElement) { + scrollTo(activeElement, element); + } + } + + _computeResultOffset() { + // Allow looping on results + const {state} = this; + const total = this.totalItemsCount; + if (state.offset < 0) { + state.offset = total + state.offset; + } else if (state.offset >= total) { + state.offset -= total; + } + } +} + +AppsMenuCanonicalSearchBar.props = {}; +AppsMenuCanonicalSearchBar.template = "web_responsive.AppsMenuCanonicalSearchBar"; diff --git a/web_responsive/static/src/components/menu_canonical_searchbar/searchbar.scss b/web_responsive/static/src/components/menu_canonical_searchbar/searchbar.scss new file mode 100644 index 000000000..e8d9be180 --- /dev/null +++ b/web_responsive/static/src/components/menu_canonical_searchbar/searchbar.scss @@ -0,0 +1,112 @@ +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +:root { + .o_grid_apps_menu[data-theme="milk"] { + --apps-menu-scrollbar-background: #{$o-brand-odoo}; + --apps-menu-empty-search-color: $app-menu-text-color; + } + + .o_grid_apps_menu[data-theme="community"] { + --apps-menu-scrollbar-background: white; + --apps-menu-empty-search-color: white; + } +} + +.o_grid_apps_menu .search-container { + // Allow to scroll only on results, keeping static search box above + .search-list { + display: flex; + flex-direction: column; + gap: calc(0.25rem + 1px); + overflow: auto; + padding: 0.25rem 0; + margin: 0.25rem 0; + max-height: calc(100vh - #{$o-navbar-height} - 5.25rem); + max-height: calc(100dvh - #{$o-navbar-height} - 5.25rem); + max-width: calc(100vw - 1rem); + position: relative; + width: 100%; + height: 100%; + + &::-webkit-scrollbar { + width: 10px; + } + + &::-webkit-scrollbar-thumb { + background: var(--apps-menu-scrollbar-background); + border-radius: 6px; + } + + @include media-breakpoint-down(md) { + &::-webkit-scrollbar { + width: 4px; + } + } + } + + .search-item-divider { + margin: 0 4px; + + hr { + margin: 0.5rem 0; + background-color: $o-brand-odoo; + } + } + + .search-item { + display: block; + align-items: center; + background-position: left; + background-repeat: no-repeat; + background-size: contain; + white-space: normal; + font-weight: 100; + background-color: white; + box-shadow: $app-menu-box-shadow; + margin: 0 4px; + border-radius: 4px; + + &__link { + display: flex; + gap: 0.5rem; + padding: 0.25rem 0.5rem; + align-items: center; + cursor: pointer; + } + + &__name { + color: $app-menu-text-color; + text-shadow: 0 0 $app-menu-text-color; + } + + &__image { + max-height: 40px; + max-width: 40px; + width: 40px; + object-fit: contain; + padding: 4px; + } + + &.highlight, + &:hover { + background-color: $app-menu-item-highlight; + box-shadow: $app-menu-box-shadow-highlight; + font-weight: 300; + } + + b { + font-weight: 700; + } + } + + .empty-search-item { + display: inline-block; + width: 100%; + text-align: center; + padding: 0.25rem 0.5rem; + color: var(--apps-menu-empty-search-color); + } +} diff --git a/web_responsive/static/src/components/menu_canonical_searchbar/searchbar.xml b/web_responsive/static/src/components/menu_canonical_searchbar/searchbar.xml new file mode 100644 index 000000000..023864a0f --- /dev/null +++ b/web_responsive/static/src/components/menu_canonical_searchbar/searchbar.xml @@ -0,0 +1,99 @@ + + + + + +
+
+ + +
+ +
    +
  • + Nothing to show +
  • +
+
+
+
diff --git a/web_responsive/static/src/components/menu_fuse_searchbar/searchbar.esm.js b/web_responsive/static/src/components/menu_fuse_searchbar/searchbar.esm.js new file mode 100644 index 000000000..3aa7da63e --- /dev/null +++ b/web_responsive/static/src/components/menu_fuse_searchbar/searchbar.esm.js @@ -0,0 +1,32 @@ +/** @odoo-module **/ +/* global Fuse */ +/* Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +import {AppsMenuCanonicalSearchBar} from "@web_responsive/components/menu_canonical_searchbar/searchbar.esm"; + +/** + * @extends AppsMenuCanonicalSearchBar + */ +export class AppsMenuFuseSearchBar extends AppsMenuCanonicalSearchBar { + setup() { + super.setup(); + this.fuseOptions = { + keys: ["displayName"], + threshold: 0.43, + }; + this.rootMenuItems = new Fuse(this.getRootMenuItems(), this.fuseOptions); + this.subMenuItems = new Fuse(this.getSubMenuItems(), this.fuseOptions); + } + + _searchMenus() { + const {state} = this; + const query = this.inputValue; + state.hasResults = query !== ""; + state.rootItems = this.rootMenuItems.search(query); + state.subItems = this.subMenuItems.search(query); + } +} + +AppsMenuFuseSearchBar.props = {}; +AppsMenuFuseSearchBar.template = "web_responsive.AppsMenuFuseSearchBar"; diff --git a/web_responsive/static/src/components/menu_fuse_searchbar/searchbar.xml b/web_responsive/static/src/components/menu_fuse_searchbar/searchbar.xml new file mode 100644 index 000000000..50945226c --- /dev/null +++ b/web_responsive/static/src/components/menu_fuse_searchbar/searchbar.xml @@ -0,0 +1,36 @@ + + + + + + + result + result.item.xmlid + + + + + + search-item {{highlighted(result_index)}} + + + result + result.item.xmlid + + + + + + search-item {{highlighted(result_index, true)}} + + + diff --git a/web_responsive/static/src/components/menu_odoo_searchbar/searchbar.esm.js b/web_responsive/static/src/components/menu_odoo_searchbar/searchbar.esm.js new file mode 100644 index 000000000..c0b5e7b9b --- /dev/null +++ b/web_responsive/static/src/components/menu_odoo_searchbar/searchbar.esm.js @@ -0,0 +1,65 @@ +/** @odoo-module **/ +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Onestein - Anjeel Haria + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +import {Component, useState} from "@odoo/owl"; +import {useAutofocus, useService} from "@web/core/utils/hooks"; + +/** + * @extends Component + * @property {{el: HTMLInputElement}} searchBarInput + */ +export class AppsMenuOdooSearchBar extends Component { + setup() { + super.setup(); + this.state = useState({ + rootItems: [], + subItems: [], + offset: 0, + hasResults: false, + }); + this.searchBarInput = useAutofocus({refName: "SearchBarInput"}); + this.command = useService("command"); + } + + /** + * @returns {String} + */ + get inputValue() { + const {el} = this.searchBarInput; + return el ? el.value : ""; + } + + set inputValue(value) { + const {el} = this.searchBarInput; + if (el) { + el.value = value; + } + } + + _onSearchInput() { + if (this.inputValue) { + this._openSearchMenu(this.inputValue); + this.inputValue = ""; + } + } + + _onSearchClick() { + this._openSearchMenu(); + } + + /** + * @param {String} [value] + * @private + */ + _openSearchMenu(value) { + const searchValue = value ? `/${value}` : "/"; + this.command.openMainPalette({searchValue}, null); + } +} + +AppsMenuOdooSearchBar.props = {}; +AppsMenuOdooSearchBar.template = "web_responsive.AppsMenuOdooSearchBar"; diff --git a/web_responsive/static/src/components/menu_odoo_searchbar/searchbar.scss b/web_responsive/static/src/components/menu_odoo_searchbar/searchbar.scss new file mode 100644 index 000000000..b503e575b --- /dev/null +++ b/web_responsive/static/src/components/menu_odoo_searchbar/searchbar.scss @@ -0,0 +1,4 @@ +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ diff --git a/web_responsive/static/src/components/menu_odoo_searchbar/searchbar.xml b/web_responsive/static/src/components/menu_odoo_searchbar/searchbar.xml new file mode 100644 index 000000000..4b2ccf552 --- /dev/null +++ b/web_responsive/static/src/components/menu_odoo_searchbar/searchbar.xml @@ -0,0 +1,25 @@ + + + + + +
+
+ + +
+
+
+
diff --git a/web_responsive/static/src/components/menu_searchbar/searchbar.esm.js b/web_responsive/static/src/components/menu_searchbar/searchbar.esm.js new file mode 100644 index 000000000..a976b4125 --- /dev/null +++ b/web_responsive/static/src/components/menu_searchbar/searchbar.esm.js @@ -0,0 +1,26 @@ +/** @odoo-module **/ +/* Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +import {AppsMenuCanonicalSearchBar} from "@web_responsive/components/menu_canonical_searchbar/searchbar.esm"; +import {AppsMenuOdooSearchBar} from "@web_responsive/components/menu_odoo_searchbar/searchbar.esm"; +import {AppsMenuFuseSearchBar} from "@web_responsive/components/menu_fuse_searchbar/searchbar.esm"; +import {Component} from "@odoo/owl"; +import {session} from "@web/session"; + +export class AppsMenuSearchBar extends Component { + setup() { + super.setup(); + this.searchType = session.apps_menu.search_type || "canonical"; + } +} + +Object.assign(AppsMenuSearchBar, { + props: {}, + template: "web_responsive.AppsMenuSearchBar", + components: { + AppsMenuOdooSearchBar, + AppsMenuCanonicalSearchBar, + AppsMenuFuseSearchBar, + }, +}); diff --git a/web_responsive/static/src/components/menu_searchbar/searchbar.scss b/web_responsive/static/src/components/menu_searchbar/searchbar.scss new file mode 100644 index 000000000..0b4c25e1a --- /dev/null +++ b/web_responsive/static/src/components/menu_searchbar/searchbar.scss @@ -0,0 +1,45 @@ +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +.o_grid_apps_menu .search-container { + width: 100%; + + .search-input { + display: flex; + justify-items: center; + gap: 0.75rem; + box-shadow: $app-menu-box-shadow; + border-radius: 4px; + padding: 0.5rem 0.75rem; + background-color: white; + + .search-icon { + color: $app-menu-text-color; + font-size: 1.5rem; + padding-top: 1px; + } + + .form-control { + height: 1.75rem; + background: none; + border: none; + color: $app-menu-text-color; + display: block; + padding: 0; + box-shadow: none; + + &::placeholder { + color: $app-menu-text-color; + opacity: 0.5; + } + } + } +} + +.o_command_palette_search .form-control { + &:focus { + box-shadow: unset; + } +} diff --git a/web_responsive/static/src/components/menu_searchbar/searchbar.xml b/web_responsive/static/src/components/menu_searchbar/searchbar.xml new file mode 100644 index 000000000..76214f221 --- /dev/null +++ b/web_responsive/static/src/components/menu_searchbar/searchbar.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/web_responsive/static/src/img/home-menu-bg-overlay.svg b/web_responsive/static/src/img/home-menu-bg-overlay.svg new file mode 100644 index 000000000..b9fe251bc --- /dev/null +++ b/web_responsive/static/src/img/home-menu-bg-overlay.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/web_responsive/static/src/legacy/js/web_responsive.esm.js b/web_responsive/static/src/legacy/js/web_responsive.esm.js new file mode 100644 index 000000000..3c5c8520c --- /dev/null +++ b/web_responsive/static/src/legacy/js/web_responsive.esm.js @@ -0,0 +1,27 @@ +/** @odoo-module **/ + +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Onestein - Anjeel Haria + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +import {debounce} from "@web/core/utils/timing"; + +// Fix for iOS Safari to set correct viewport height +// https://github.com/Faisal-Manzer/postcss-viewport-height-correction +export function setViewportProperty(doc) { + function handleResize() { + requestAnimationFrame(function () { + doc.style.setProperty("--vh100", doc.clientHeight + "px"); + }); + } + + handleResize(); + return handleResize; +} + +window.addEventListener( + "resize", + debounce(setViewportProperty(document.documentElement), 25) +); diff --git a/web_responsive/static/src/legacy/scss/big_boxes.scss b/web_responsive/static/src/legacy/scss/big_boxes.scss new file mode 100644 index 000000000..180a3bdfe --- /dev/null +++ b/web_responsive/static/src/legacy/scss/big_boxes.scss @@ -0,0 +1,95 @@ +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Onestein - Anjeel Haria + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +$big-checkbox-size: 1.5em; + +// Big checkboxes +.o_list_view, +.o_setting_container .o_setting_box { + .o_setting_right_pane { + margin-left: 34px; + } + + .o-checkbox:not(.o_boolean_toggle) { + margin-right: 10px; + margin-top: -6px; + + &.d-inline-block { + display: block !important; + } + + .form-check-input { + height: $big-checkbox-size; + width: $big-checkbox-size; + } + } + + .o_optional_columns_dropdown { + .o-dropdown--menu { + display: flex !important; + flex-direction: column; + margin: 0; + } + + .o-checkbox { + display: inline-flex; + align-items: center; + gap: 0.5rem; + margin: 0; + } + + .form-check-input { + margin-bottom: 2px; + } + } +} + +.o_add_favorite + .o_accordion_values { + .o_add_favorite_props { + display: flex; + flex-direction: column; + margin: 0; + } + + .o_add_favorite_name { + margin-bottom: 0.5rem; + max-width: 100%; + } + + .form-check-input { + height: $big-checkbox-size; + width: $big-checkbox-size; + } + + .form-check-label { + line-height: normal; + } + + .o-checkbox { + display: inline-flex; + align-items: center; + gap: 0.5rem; + margin: 0; + } +} + +.o_setting_container .o_setting_box { + .o-checkbox:not(.o_boolean_toggle) { + .form-check-label { + &::after { + width: 24px; + height: 24px; + } + + &::before { + outline: none !important; + border: 1px solid #4c4c4c; + width: 24px; + height: 24px; + } + } + } +} diff --git a/web_responsive/static/src/legacy/scss/form_variable.scss b/web_responsive/static/src/legacy/scss/form_variable.scss new file mode 100644 index 000000000..442e98a87 --- /dev/null +++ b/web_responsive/static/src/legacy/scss/form_variable.scss @@ -0,0 +1,5 @@ +/* Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +$o-form-renderer-max-width: 3840px; +$o-form-view-sheet-max-width: 2560px; diff --git a/web_responsive/static/src/legacy/scss/list_sticky_header.scss b/web_responsive/static/src/legacy/scss/list_sticky_header.scss new file mode 100644 index 000000000..63cd160f9 --- /dev/null +++ b/web_responsive/static/src/legacy/scss/list_sticky_header.scss @@ -0,0 +1,26 @@ +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Onestein - Anjeel Haria + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +.o_mobile_sticky { + transition: top 0.5s; +} + +// Sticky Header & Footer in List View +.o_list_view { + .o_list_table { + thead { + box-shadow: 0 1px 0 0 var(--ListRenderer-thead-border-end-color); + } + + .o_list_footer { + position: sticky; + bottom: 0; + z-index: 2; + background-color: var(--ListRenderer-thead-bg-color); + box-shadow: 0 -1px 0 -1px var(--ListRenderer-thead-border-end-color); + } + } +} diff --git a/web_responsive/static/src/legacy/scss/primary_variable.scss b/web_responsive/static/src/legacy/scss/primary_variable.scss new file mode 100644 index 000000000..bb1f12852 --- /dev/null +++ b/web_responsive/static/src/legacy/scss/primary_variable.scss @@ -0,0 +1,12 @@ +/* Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +$app-menu-text-color: #374151 !default; +$app-menu-background-color: rgb(233, 230, 249) !default; +$app-menu-item-highlight: rgb(243, 240, 259) !default; +$app-menu-box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.16), + 0 2px 2px rgba(0, 0, 0, 0.016), 0 4px 4px rgba(0, 0, 0, 0.016), + 0 8px 8px rgba(0, 0, 0, 0.016), 0 16px 16px rgba(0, 0, 0, 0.016) !default; +$app-menu-box-shadow-highlight: inset 0 0 0 1px rgba(0, 0, 0, 0.26), + 0 2px 2px rgba(0, 0, 0, 0.026), 0 4px 4px rgba(0, 0, 0, 0.026), + 0 8px 8px rgba(0, 0, 0, 0.026), 0 16px 16px rgba(0, 0, 0, 0.026) !default; diff --git a/web_responsive/static/src/legacy/scss/web_responsive.scss b/web_responsive/static/src/legacy/scss/web_responsive.scss new file mode 100644 index 000000000..092faba20 --- /dev/null +++ b/web_responsive/static/src/legacy/scss/web_responsive.scss @@ -0,0 +1,215 @@ +/* Copyright 2018 Tecnativa - Jairo Llopis + * Copyright 2021 ITerra - Sergey Shebanin + * Copyright 2023 Onestein - Anjeel Haria + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +$chatter_zone_width: 35% !important; + +// Allow sticky header +.o_action_manager { + .o_form_view { + overflow: unset; + + .o_form_view_container { + overflow: auto; + } + } +} + +@include media-breakpoint-down(sm) { + .ui-menu-item-wrapper { + display: inline-flex !important; + align-items: center; + height: 35px; + } + .o_calendar_widget { + .fc-dayGridMonth-view { + .fc-week-number { + display: none; + } + } + + .fc-timeGridDay-view { + .fc-day-header { + vertical-align: middle; + } + } + } + .o_kanban_view .o_cp_pager .btn-group { + top: -1px; + } + .o_kanban_renderer { + width: 100%; + } +} + +// Normal views +.o_content, +.modal-content { + max-width: 100%; + + // Form views + .o_form_editable { + .o_cell .o_form_label:not(.o_status):not(.o_calendar_invitation) { + min-height: 23px; + @include media-breakpoint-up(md) { + margin-bottom: 10px; + } + } + + .o_horizontal_separator { + font-size: 14px; + } + + // Some UX improvements for form in edit mode + @include media-breakpoint-down(sm) { + &.o_form_editable .o_field_widget { + &:not(.o_stat_info):not(.o_readonly_modifier):not(.oe_form_field_html):not(.o_field_image) { + min-height: 35px; + } + + .o_x2m_control_panel { + margin-bottom: 10px !important; + } + + &.o_field_float_percentage, + &.o_field_monetary, + &.o_field_many2many_selection, + .o_field_many2one_selection { + align-items: center; + } + + .o_field_many2one_selection .o_input_dropdown, + &.o_datepicker, + &.o_partner_autocomplete_info { + input { + min-height: 35px; + } + } + + .o_external_button { + margin-left: 5px; + } + + .o_dropdown_button, + .o_datepicker_button { + top: 50%; + right: 6px; + bottom: auto; + transform: translateY(-50%); + } + } + } + + @include media-breakpoint-down(sm) { + min-width: auto; + + // Avoid overflow on modals + .o_form_sheet { + min-width: auto; + } + + // Render website inputs properly in phones + .o_group .o_field_widget.o_text_overflow { + // Overrides another !important + width: auto !important; + } + } + } + + //No content message improvements on mobile + @include media-breakpoint-down(md) { + .o_view_nocontent { + top: 53px; + } + .o_nocontent_help { + box-shadow: none; + } + .o_sample_data_disabled { + display: none; + } + } +} + +.o-mail-Form-chatter { + &.o-isInFormSheetBg:not(.o-aside) { + background-color: $white; + + &:not(.o-aside) { + width: auto; + border-top: 1px solid $border-color; + } + } + + &.o-aside { + flex: 0 0 $chatter_zone_width; + max-width: initial; + min-width: initial; + overflow: auto; + } +} + +body:not(.o_statusbar_buttons) { + .oe-toolbar { + z-index: 0 !important; + } +} + +.o_inner_group > .mb-sm-0 { + margin-bottom: 0 !important; +} + +.o_searchview_autocomplete { + z-index: 999; +} + +// Color clue to tell the difference between a note and a public message +// HACK: has() pseudo class is broadly supported in desktop, even FF will deploy +// full support soon (now it's available behind a config flag) +// https://caniuse.com/css-has +.o-mail-Chatter-top:has(.o-mail-Chatter-sendMessage.active) { + .o-mail-Composer { + background-color: lighten($o-brand-primary, 35%); + padding-top: 0.25rem !important; + } + + @include media-breakpoint-up(sm) { + .o-mail-Composer { + padding-top: 0.5rem !important; + } + } +} + +@include media-breakpoint-up(md) { + .app_settings_block > h2, + .app_settings_block > div > h2 { + @include o-position-sticky(0); + z-index: 10; + } +} + +.o_list_table { + .o_handle_cell, + .o_list_record_remove { + vertical-align: middle; + } +} + +.o_action_manager { + .dropdown-menu { + max-height: 70vh; + max-height: 70dvh; + } + + .o_searchview_input { + padding-top: 0; + padding-bottom: 0; + } + + .o_control_panel_main { + .btn { + white-space: nowrap; + } + } +} diff --git a/web_responsive/static/src/legacy/xml/custom_favorite_item.xml b/web_responsive/static/src/legacy/xml/custom_favorite_item.xml new file mode 100644 index 000000000..be79500c6 --- /dev/null +++ b/web_responsive/static/src/legacy/xml/custom_favorite_item.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + diff --git a/web_responsive/static/src/legacy/xml/form_buttons.xml b/web_responsive/static/src/legacy/xml/form_buttons.xml new file mode 100644 index 000000000..c8ca382ff --- /dev/null +++ b/web_responsive/static/src/legacy/xml/form_buttons.xml @@ -0,0 +1,206 @@ + + + + + + + New + + + + Save + + + + Discard + + + + + d + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + d + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web_responsive/static/src/lib/fuse/LICENSE b/web_responsive/static/src/lib/fuse/LICENSE new file mode 100644 index 000000000..453d70be2 --- /dev/null +++ b/web_responsive/static/src/lib/fuse/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 Kirollos Risk + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/web_responsive/static/src/lib/fuse/fuse.basic.js b/web_responsive/static/src/lib/fuse/fuse.basic.js new file mode 100644 index 000000000..0e7292e04 --- /dev/null +++ b/web_responsive/static/src/lib/fuse/fuse.basic.js @@ -0,0 +1,1335 @@ +/** + * Fuse.js v7.0.0 - Lightweight fuzzy-search (http://fusejs.io) + * + * Copyright (c) 2023 Kiro Risk (http://kiro.me) + * All Rights Reserved. Apache Software License 2.0 + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Fuse = factory()); +})(this, (function () { 'use strict'; + + function ownKeys(object, enumerableOnly) { + var keys = Object.keys(object); + if (Object.getOwnPropertySymbols) { + var symbols = Object.getOwnPropertySymbols(object); + enumerableOnly && (symbols = symbols.filter(function (sym) { + return Object.getOwnPropertyDescriptor(object, sym).enumerable; + })), keys.push.apply(keys, symbols); + } + return keys; + } + function _objectSpread2(target) { + for (var i = 1; i < arguments.length; i++) { + var source = null != arguments[i] ? arguments[i] : {}; + i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { + _defineProperty(target, key, source[key]); + }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { + Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); + }); + } + return target; + } + function _typeof(obj) { + "@babel/helpers - typeof"; + + return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }, _typeof(obj); + } + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); + } + } + function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + Object.defineProperty(Constructor, "prototype", { + writable: false + }); + return Constructor; + } + function _defineProperty(obj, key, value) { + key = _toPropertyKey(key); + if (key in obj) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } else { + obj[key] = value; + } + return obj; + } + function _toConsumableArray(arr) { + return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); + } + function _arrayWithoutHoles(arr) { + if (Array.isArray(arr)) return _arrayLikeToArray(arr); + } + function _iterableToArray(iter) { + if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); + } + function _unsupportedIterableToArray(o, minLen) { + if (!o) return; + if (typeof o === "string") return _arrayLikeToArray(o, minLen); + var n = Object.prototype.toString.call(o).slice(8, -1); + if (n === "Object" && o.constructor) n = o.constructor.name; + if (n === "Map" || n === "Set") return Array.from(o); + if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); + } + function _arrayLikeToArray(arr, len) { + if (len == null || len > arr.length) len = arr.length; + for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; + return arr2; + } + function _nonIterableSpread() { + throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); + } + function _toPrimitive(input, hint) { + if (typeof input !== "object" || input === null) return input; + var prim = input[Symbol.toPrimitive]; + if (prim !== undefined) { + var res = prim.call(input, hint || "default"); + if (typeof res !== "object") return res; + throw new TypeError("@@toPrimitive must return a primitive value."); + } + return (hint === "string" ? String : Number)(input); + } + function _toPropertyKey(arg) { + var key = _toPrimitive(arg, "string"); + return typeof key === "symbol" ? key : String(key); + } + + function isArray(value) { + return !Array.isArray ? getTag(value) === '[object Array]' : Array.isArray(value); + } + + // Adapted from: https://github.com/lodash/lodash/blob/master/.internal/baseToString.js + var INFINITY = 1 / 0; + function baseToString(value) { + // Exit early for strings to avoid a performance hit in some environments. + if (typeof value == 'string') { + return value; + } + var result = value + ''; + return result == '0' && 1 / value == -INFINITY ? '-0' : result; + } + function toString(value) { + return value == null ? '' : baseToString(value); + } + function isString(value) { + return typeof value === 'string'; + } + function isNumber(value) { + return typeof value === 'number'; + } + + // Adapted from: https://github.com/lodash/lodash/blob/master/isBoolean.js + function isBoolean(value) { + return value === true || value === false || isObjectLike(value) && getTag(value) == '[object Boolean]'; + } + function isObject(value) { + return _typeof(value) === 'object'; + } + + // Checks if `value` is object-like. + function isObjectLike(value) { + return isObject(value) && value !== null; + } + function isDefined(value) { + return value !== undefined && value !== null; + } + function isBlank(value) { + return !value.trim().length; + } + + // Gets the `toStringTag` of `value`. + // Adapted from: https://github.com/lodash/lodash/blob/master/.internal/getTag.js + function getTag(value) { + return value == null ? value === undefined ? '[object Undefined]' : '[object Null]' : Object.prototype.toString.call(value); + } + + var EXTENDED_SEARCH_UNAVAILABLE = 'Extended search is not available'; + var LOGICAL_SEARCH_UNAVAILABLE = 'Logical search is not available'; + var INCORRECT_INDEX_TYPE = "Incorrect 'index' type"; + var LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY = function LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY(key) { + return "Invalid value for key ".concat(key); + }; + var PATTERN_LENGTH_TOO_LARGE = function PATTERN_LENGTH_TOO_LARGE(max) { + return "Pattern length exceeds max of ".concat(max, "."); + }; + var MISSING_KEY_PROPERTY = function MISSING_KEY_PROPERTY(name) { + return "Missing ".concat(name, " property in key"); + }; + var INVALID_KEY_WEIGHT_VALUE = function INVALID_KEY_WEIGHT_VALUE(key) { + return "Property 'weight' in key '".concat(key, "' must be a positive integer"); + }; + + var hasOwn = Object.prototype.hasOwnProperty; + var KeyStore = /*#__PURE__*/function () { + function KeyStore(keys) { + var _this = this; + _classCallCheck(this, KeyStore); + this._keys = []; + this._keyMap = {}; + var totalWeight = 0; + keys.forEach(function (key) { + var obj = createKey(key); + _this._keys.push(obj); + _this._keyMap[obj.id] = obj; + totalWeight += obj.weight; + }); + + // Normalize weights so that their sum is equal to 1 + this._keys.forEach(function (key) { + key.weight /= totalWeight; + }); + } + _createClass(KeyStore, [{ + key: "get", + value: function get(keyId) { + return this._keyMap[keyId]; + } + }, { + key: "keys", + value: function keys() { + return this._keys; + } + }, { + key: "toJSON", + value: function toJSON() { + return JSON.stringify(this._keys); + } + }]); + return KeyStore; + }(); + function createKey(key) { + var path = null; + var id = null; + var src = null; + var weight = 1; + var getFn = null; + if (isString(key) || isArray(key)) { + src = key; + path = createKeyPath(key); + id = createKeyId(key); + } else { + if (!hasOwn.call(key, 'name')) { + throw new Error(MISSING_KEY_PROPERTY('name')); + } + var name = key.name; + src = name; + if (hasOwn.call(key, 'weight')) { + weight = key.weight; + if (weight <= 0) { + throw new Error(INVALID_KEY_WEIGHT_VALUE(name)); + } + } + path = createKeyPath(name); + id = createKeyId(name); + getFn = key.getFn; + } + return { + path: path, + id: id, + weight: weight, + src: src, + getFn: getFn + }; + } + function createKeyPath(key) { + return isArray(key) ? key : key.split('.'); + } + function createKeyId(key) { + return isArray(key) ? key.join('.') : key; + } + + function get(obj, path) { + var list = []; + var arr = false; + var deepGet = function deepGet(obj, path, index) { + if (!isDefined(obj)) { + return; + } + if (!path[index]) { + // If there's no path left, we've arrived at the object we care about. + list.push(obj); + } else { + var key = path[index]; + var value = obj[key]; + if (!isDefined(value)) { + return; + } + + // If we're at the last value in the path, and if it's a string/number/bool, + // add it to the list + if (index === path.length - 1 && (isString(value) || isNumber(value) || isBoolean(value))) { + list.push(toString(value)); + } else if (isArray(value)) { + arr = true; + // Search each item in the array. + for (var i = 0, len = value.length; i < len; i += 1) { + deepGet(value[i], path, index + 1); + } + } else if (path.length) { + // An object. Recurse further. + deepGet(value, path, index + 1); + } + } + }; + + // Backwards compatibility (since path used to be a string) + deepGet(obj, isString(path) ? path.split('.') : path, 0); + return arr ? list : list[0]; + } + + var MatchOptions = { + // Whether the matches should be included in the result set. When `true`, each record in the result + // set will include the indices of the matched characters. + // These can consequently be used for highlighting purposes. + includeMatches: false, + // When `true`, the matching function will continue to the end of a search pattern even if + // a perfect match has already been located in the string. + findAllMatches: false, + // Minimum number of characters that must be matched before a result is considered a match + minMatchCharLength: 1 + }; + var BasicOptions = { + // When `true`, the algorithm continues searching to the end of the input even if a perfect + // match is found before the end of the same input. + isCaseSensitive: false, + // When true, the matching function will continue to the end of a search pattern even if + includeScore: false, + // List of properties that will be searched. This also supports nested properties. + keys: [], + // Whether to sort the result list, by score + shouldSort: true, + // Default sort function: sort by ascending score, ascending index + sortFn: function sortFn(a, b) { + return a.score === b.score ? a.idx < b.idx ? -1 : 1 : a.score < b.score ? -1 : 1; + } + }; + var FuzzyOptions = { + // Approximately where in the text is the pattern expected to be found? + location: 0, + // At what point does the match algorithm give up. A threshold of '0.0' requires a perfect match + // (of both letters and location), a threshold of '1.0' would match anything. + threshold: 0.6, + // Determines how close the match must be to the fuzzy location (specified above). + // An exact letter match which is 'distance' characters away from the fuzzy location + // would score as a complete mismatch. A distance of '0' requires the match be at + // the exact location specified, a threshold of '1000' would require a perfect match + // to be within 800 characters of the fuzzy location to be found using a 0.8 threshold. + distance: 100 + }; + var AdvancedOptions = { + // When `true`, it enables the use of unix-like search commands + useExtendedSearch: false, + // The get function to use when fetching an object's properties. + // The default will search nested paths *ie foo.bar.baz* + getFn: get, + // When `true`, search will ignore `location` and `distance`, so it won't matter + // where in the string the pattern appears. + // More info: https://fusejs.io/concepts/scoring-theory.html#fuzziness-score + ignoreLocation: false, + // When `true`, the calculation for the relevance score (used for sorting) will + // ignore the field-length norm. + // More info: https://fusejs.io/concepts/scoring-theory.html#field-length-norm + ignoreFieldNorm: false, + // The weight to determine how much field length norm effects scoring. + fieldNormWeight: 1 + }; + var Config = _objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, BasicOptions), MatchOptions), FuzzyOptions), AdvancedOptions); + + var SPACE = /[^ ]+/g; + + // Field-length norm: the shorter the field, the higher the weight. + // Set to 3 decimals to reduce index size. + function norm() { + var weight = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1; + var mantissa = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 3; + var cache = new Map(); + var m = Math.pow(10, mantissa); + return { + get: function get(value) { + var numTokens = value.match(SPACE).length; + if (cache.has(numTokens)) { + return cache.get(numTokens); + } + + // Default function is 1/sqrt(x), weight makes that variable + var norm = 1 / Math.pow(numTokens, 0.5 * weight); + + // In place of `toFixed(mantissa)`, for faster computation + var n = parseFloat(Math.round(norm * m) / m); + cache.set(numTokens, n); + return n; + }, + clear: function clear() { + cache.clear(); + } + }; + } + + var FuseIndex = /*#__PURE__*/function () { + function FuseIndex() { + var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, + _ref$getFn = _ref.getFn, + getFn = _ref$getFn === void 0 ? Config.getFn : _ref$getFn, + _ref$fieldNormWeight = _ref.fieldNormWeight, + fieldNormWeight = _ref$fieldNormWeight === void 0 ? Config.fieldNormWeight : _ref$fieldNormWeight; + _classCallCheck(this, FuseIndex); + this.norm = norm(fieldNormWeight, 3); + this.getFn = getFn; + this.isCreated = false; + this.setIndexRecords(); + } + _createClass(FuseIndex, [{ + key: "setSources", + value: function setSources() { + var docs = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + this.docs = docs; + } + }, { + key: "setIndexRecords", + value: function setIndexRecords() { + var records = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + this.records = records; + } + }, { + key: "setKeys", + value: function setKeys() { + var _this = this; + var keys = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + this.keys = keys; + this._keysMap = {}; + keys.forEach(function (key, idx) { + _this._keysMap[key.id] = idx; + }); + } + }, { + key: "create", + value: function create() { + var _this2 = this; + if (this.isCreated || !this.docs.length) { + return; + } + this.isCreated = true; + + // List is Array + if (isString(this.docs[0])) { + this.docs.forEach(function (doc, docIndex) { + _this2._addString(doc, docIndex); + }); + } else { + // List is Array + this.docs.forEach(function (doc, docIndex) { + _this2._addObject(doc, docIndex); + }); + } + this.norm.clear(); + } + // Adds a doc to the end of the index + }, { + key: "add", + value: function add(doc) { + var idx = this.size(); + if (isString(doc)) { + this._addString(doc, idx); + } else { + this._addObject(doc, idx); + } + } + // Removes the doc at the specified index of the index + }, { + key: "removeAt", + value: function removeAt(idx) { + this.records.splice(idx, 1); + + // Change ref index of every subsquent doc + for (var i = idx, len = this.size(); i < len; i += 1) { + this.records[i].i -= 1; + } + } + }, { + key: "getValueForItemAtKeyId", + value: function getValueForItemAtKeyId(item, keyId) { + return item[this._keysMap[keyId]]; + } + }, { + key: "size", + value: function size() { + return this.records.length; + } + }, { + key: "_addString", + value: function _addString(doc, docIndex) { + if (!isDefined(doc) || isBlank(doc)) { + return; + } + var record = { + v: doc, + i: docIndex, + n: this.norm.get(doc) + }; + this.records.push(record); + } + }, { + key: "_addObject", + value: function _addObject(doc, docIndex) { + var _this3 = this; + var record = { + i: docIndex, + $: {} + }; + + // Iterate over every key (i.e, path), and fetch the value at that key + this.keys.forEach(function (key, keyIndex) { + var value = key.getFn ? key.getFn(doc) : _this3.getFn(doc, key.path); + if (!isDefined(value)) { + return; + } + if (isArray(value)) { + var subRecords = []; + var stack = [{ + nestedArrIndex: -1, + value: value + }]; + while (stack.length) { + var _stack$pop = stack.pop(), + nestedArrIndex = _stack$pop.nestedArrIndex, + _value = _stack$pop.value; + if (!isDefined(_value)) { + continue; + } + if (isString(_value) && !isBlank(_value)) { + var subRecord = { + v: _value, + i: nestedArrIndex, + n: _this3.norm.get(_value) + }; + subRecords.push(subRecord); + } else if (isArray(_value)) { + _value.forEach(function (item, k) { + stack.push({ + nestedArrIndex: k, + value: item + }); + }); + } else ; + } + record.$[keyIndex] = subRecords; + } else if (isString(value) && !isBlank(value)) { + var _subRecord = { + v: value, + n: _this3.norm.get(value) + }; + record.$[keyIndex] = _subRecord; + } + }); + this.records.push(record); + } + }, { + key: "toJSON", + value: function toJSON() { + return { + keys: this.keys, + records: this.records + }; + } + }]); + return FuseIndex; + }(); + function createIndex(keys, docs) { + var _ref2 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, + _ref2$getFn = _ref2.getFn, + getFn = _ref2$getFn === void 0 ? Config.getFn : _ref2$getFn, + _ref2$fieldNormWeight = _ref2.fieldNormWeight, + fieldNormWeight = _ref2$fieldNormWeight === void 0 ? Config.fieldNormWeight : _ref2$fieldNormWeight; + var myIndex = new FuseIndex({ + getFn: getFn, + fieldNormWeight: fieldNormWeight + }); + myIndex.setKeys(keys.map(createKey)); + myIndex.setSources(docs); + myIndex.create(); + return myIndex; + } + function parseIndex(data) { + var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, + _ref3$getFn = _ref3.getFn, + getFn = _ref3$getFn === void 0 ? Config.getFn : _ref3$getFn, + _ref3$fieldNormWeight = _ref3.fieldNormWeight, + fieldNormWeight = _ref3$fieldNormWeight === void 0 ? Config.fieldNormWeight : _ref3$fieldNormWeight; + var keys = data.keys, + records = data.records; + var myIndex = new FuseIndex({ + getFn: getFn, + fieldNormWeight: fieldNormWeight + }); + myIndex.setKeys(keys); + myIndex.setIndexRecords(records); + return myIndex; + } + + function computeScore$1(pattern) { + var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, + _ref$errors = _ref.errors, + errors = _ref$errors === void 0 ? 0 : _ref$errors, + _ref$currentLocation = _ref.currentLocation, + currentLocation = _ref$currentLocation === void 0 ? 0 : _ref$currentLocation, + _ref$expectedLocation = _ref.expectedLocation, + expectedLocation = _ref$expectedLocation === void 0 ? 0 : _ref$expectedLocation, + _ref$distance = _ref.distance, + distance = _ref$distance === void 0 ? Config.distance : _ref$distance, + _ref$ignoreLocation = _ref.ignoreLocation, + ignoreLocation = _ref$ignoreLocation === void 0 ? Config.ignoreLocation : _ref$ignoreLocation; + var accuracy = errors / pattern.length; + if (ignoreLocation) { + return accuracy; + } + var proximity = Math.abs(expectedLocation - currentLocation); + if (!distance) { + // Dodge divide by zero error. + return proximity ? 1.0 : accuracy; + } + return accuracy + proximity / distance; + } + + function convertMaskToIndices() { + var matchmask = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + var minMatchCharLength = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Config.minMatchCharLength; + var indices = []; + var start = -1; + var end = -1; + var i = 0; + for (var len = matchmask.length; i < len; i += 1) { + var match = matchmask[i]; + if (match && start === -1) { + start = i; + } else if (!match && start !== -1) { + end = i - 1; + if (end - start + 1 >= minMatchCharLength) { + indices.push([start, end]); + } + start = -1; + } + } + + // (i-1 - start) + 1 => i - start + if (matchmask[i - 1] && i - start >= minMatchCharLength) { + indices.push([start, i - 1]); + } + return indices; + } + + // Machine word size + var MAX_BITS = 32; + + function search(text, pattern, patternAlphabet) { + var _ref = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}, + _ref$location = _ref.location, + location = _ref$location === void 0 ? Config.location : _ref$location, + _ref$distance = _ref.distance, + distance = _ref$distance === void 0 ? Config.distance : _ref$distance, + _ref$threshold = _ref.threshold, + threshold = _ref$threshold === void 0 ? Config.threshold : _ref$threshold, + _ref$findAllMatches = _ref.findAllMatches, + findAllMatches = _ref$findAllMatches === void 0 ? Config.findAllMatches : _ref$findAllMatches, + _ref$minMatchCharLeng = _ref.minMatchCharLength, + minMatchCharLength = _ref$minMatchCharLeng === void 0 ? Config.minMatchCharLength : _ref$minMatchCharLeng, + _ref$includeMatches = _ref.includeMatches, + includeMatches = _ref$includeMatches === void 0 ? Config.includeMatches : _ref$includeMatches, + _ref$ignoreLocation = _ref.ignoreLocation, + ignoreLocation = _ref$ignoreLocation === void 0 ? Config.ignoreLocation : _ref$ignoreLocation; + if (pattern.length > MAX_BITS) { + throw new Error(PATTERN_LENGTH_TOO_LARGE(MAX_BITS)); + } + var patternLen = pattern.length; + // Set starting location at beginning text and initialize the alphabet. + var textLen = text.length; + // Handle the case when location > text.length + var expectedLocation = Math.max(0, Math.min(location, textLen)); + // Highest score beyond which we give up. + var currentThreshold = threshold; + // Is there a nearby exact match? (speedup) + var bestLocation = expectedLocation; + + // Performance: only computer matches when the minMatchCharLength > 1 + // OR if `includeMatches` is true. + var computeMatches = minMatchCharLength > 1 || includeMatches; + // A mask of the matches, used for building the indices + var matchMask = computeMatches ? Array(textLen) : []; + var index; + + // Get all exact matches, here for speed up + while ((index = text.indexOf(pattern, bestLocation)) > -1) { + var score = computeScore$1(pattern, { + currentLocation: index, + expectedLocation: expectedLocation, + distance: distance, + ignoreLocation: ignoreLocation + }); + currentThreshold = Math.min(score, currentThreshold); + bestLocation = index + patternLen; + if (computeMatches) { + var i = 0; + while (i < patternLen) { + matchMask[index + i] = 1; + i += 1; + } + } + } + + // Reset the best location + bestLocation = -1; + var lastBitArr = []; + var finalScore = 1; + var binMax = patternLen + textLen; + var mask = 1 << patternLen - 1; + for (var _i = 0; _i < patternLen; _i += 1) { + // Scan for the best match; each iteration allows for one more error. + // Run a binary search to determine how far from the match location we can stray + // at this error level. + var binMin = 0; + var binMid = binMax; + while (binMin < binMid) { + var _score = computeScore$1(pattern, { + errors: _i, + currentLocation: expectedLocation + binMid, + expectedLocation: expectedLocation, + distance: distance, + ignoreLocation: ignoreLocation + }); + if (_score <= currentThreshold) { + binMin = binMid; + } else { + binMax = binMid; + } + binMid = Math.floor((binMax - binMin) / 2 + binMin); + } + + // Use the result from this iteration as the maximum for the next. + binMax = binMid; + var start = Math.max(1, expectedLocation - binMid + 1); + var finish = findAllMatches ? textLen : Math.min(expectedLocation + binMid, textLen) + patternLen; + + // Initialize the bit array + var bitArr = Array(finish + 2); + bitArr[finish + 1] = (1 << _i) - 1; + for (var j = finish; j >= start; j -= 1) { + var currentLocation = j - 1; + var charMatch = patternAlphabet[text.charAt(currentLocation)]; + if (computeMatches) { + // Speed up: quick bool to int conversion (i.e, `charMatch ? 1 : 0`) + matchMask[currentLocation] = +!!charMatch; + } + + // First pass: exact match + bitArr[j] = (bitArr[j + 1] << 1 | 1) & charMatch; + + // Subsequent passes: fuzzy match + if (_i) { + bitArr[j] |= (lastBitArr[j + 1] | lastBitArr[j]) << 1 | 1 | lastBitArr[j + 1]; + } + if (bitArr[j] & mask) { + finalScore = computeScore$1(pattern, { + errors: _i, + currentLocation: currentLocation, + expectedLocation: expectedLocation, + distance: distance, + ignoreLocation: ignoreLocation + }); + + // This match will almost certainly be better than any existing match. + // But check anyway. + if (finalScore <= currentThreshold) { + // Indeed it is + currentThreshold = finalScore; + bestLocation = currentLocation; + + // Already passed `loc`, downhill from here on in. + if (bestLocation <= expectedLocation) { + break; + } + + // When passing `bestLocation`, don't exceed our current distance from `expectedLocation`. + start = Math.max(1, 2 * expectedLocation - bestLocation); + } + } + } + + // No hope for a (better) match at greater error levels. + var _score2 = computeScore$1(pattern, { + errors: _i + 1, + currentLocation: expectedLocation, + expectedLocation: expectedLocation, + distance: distance, + ignoreLocation: ignoreLocation + }); + if (_score2 > currentThreshold) { + break; + } + lastBitArr = bitArr; + } + var result = { + isMatch: bestLocation >= 0, + // Count exact matches (those with a score of 0) to be "almost" exact + score: Math.max(0.001, finalScore) + }; + if (computeMatches) { + var indices = convertMaskToIndices(matchMask, minMatchCharLength); + if (!indices.length) { + result.isMatch = false; + } else if (includeMatches) { + result.indices = indices; + } + } + return result; + } + + function createPatternAlphabet(pattern) { + var mask = {}; + for (var i = 0, len = pattern.length; i < len; i += 1) { + var _char = pattern.charAt(i); + mask[_char] = (mask[_char] || 0) | 1 << len - i - 1; + } + return mask; + } + + var BitapSearch = /*#__PURE__*/function () { + function BitapSearch(pattern) { + var _this = this; + var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, + _ref$location = _ref.location, + location = _ref$location === void 0 ? Config.location : _ref$location, + _ref$threshold = _ref.threshold, + threshold = _ref$threshold === void 0 ? Config.threshold : _ref$threshold, + _ref$distance = _ref.distance, + distance = _ref$distance === void 0 ? Config.distance : _ref$distance, + _ref$includeMatches = _ref.includeMatches, + includeMatches = _ref$includeMatches === void 0 ? Config.includeMatches : _ref$includeMatches, + _ref$findAllMatches = _ref.findAllMatches, + findAllMatches = _ref$findAllMatches === void 0 ? Config.findAllMatches : _ref$findAllMatches, + _ref$minMatchCharLeng = _ref.minMatchCharLength, + minMatchCharLength = _ref$minMatchCharLeng === void 0 ? Config.minMatchCharLength : _ref$minMatchCharLeng, + _ref$isCaseSensitive = _ref.isCaseSensitive, + isCaseSensitive = _ref$isCaseSensitive === void 0 ? Config.isCaseSensitive : _ref$isCaseSensitive, + _ref$ignoreLocation = _ref.ignoreLocation, + ignoreLocation = _ref$ignoreLocation === void 0 ? Config.ignoreLocation : _ref$ignoreLocation; + _classCallCheck(this, BitapSearch); + this.options = { + location: location, + threshold: threshold, + distance: distance, + includeMatches: includeMatches, + findAllMatches: findAllMatches, + minMatchCharLength: minMatchCharLength, + isCaseSensitive: isCaseSensitive, + ignoreLocation: ignoreLocation + }; + this.pattern = isCaseSensitive ? pattern : pattern.toLowerCase(); + this.chunks = []; + if (!this.pattern.length) { + return; + } + var addChunk = function addChunk(pattern, startIndex) { + _this.chunks.push({ + pattern: pattern, + alphabet: createPatternAlphabet(pattern), + startIndex: startIndex + }); + }; + var len = this.pattern.length; + if (len > MAX_BITS) { + var i = 0; + var remainder = len % MAX_BITS; + var end = len - remainder; + while (i < end) { + addChunk(this.pattern.substr(i, MAX_BITS), i); + i += MAX_BITS; + } + if (remainder) { + var startIndex = len - MAX_BITS; + addChunk(this.pattern.substr(startIndex), startIndex); + } + } else { + addChunk(this.pattern, 0); + } + } + _createClass(BitapSearch, [{ + key: "searchIn", + value: function searchIn(text) { + var _this$options = this.options, + isCaseSensitive = _this$options.isCaseSensitive, + includeMatches = _this$options.includeMatches; + if (!isCaseSensitive) { + text = text.toLowerCase(); + } + + // Exact match + if (this.pattern === text) { + var _result = { + isMatch: true, + score: 0 + }; + if (includeMatches) { + _result.indices = [[0, text.length - 1]]; + } + return _result; + } + + // Otherwise, use Bitap algorithm + var _this$options2 = this.options, + location = _this$options2.location, + distance = _this$options2.distance, + threshold = _this$options2.threshold, + findAllMatches = _this$options2.findAllMatches, + minMatchCharLength = _this$options2.minMatchCharLength, + ignoreLocation = _this$options2.ignoreLocation; + var allIndices = []; + var totalScore = 0; + var hasMatches = false; + this.chunks.forEach(function (_ref2) { + var pattern = _ref2.pattern, + alphabet = _ref2.alphabet, + startIndex = _ref2.startIndex; + var _search = search(text, pattern, alphabet, { + location: location + startIndex, + distance: distance, + threshold: threshold, + findAllMatches: findAllMatches, + minMatchCharLength: minMatchCharLength, + includeMatches: includeMatches, + ignoreLocation: ignoreLocation + }), + isMatch = _search.isMatch, + score = _search.score, + indices = _search.indices; + if (isMatch) { + hasMatches = true; + } + totalScore += score; + if (isMatch && indices) { + allIndices = [].concat(_toConsumableArray(allIndices), _toConsumableArray(indices)); + } + }); + var result = { + isMatch: hasMatches, + score: hasMatches ? totalScore / this.chunks.length : 1 + }; + if (hasMatches && includeMatches) { + result.indices = allIndices; + } + return result; + } + }]); + return BitapSearch; + }(); + + var registeredSearchers = []; + function createSearcher(pattern, options) { + for (var i = 0, len = registeredSearchers.length; i < len; i += 1) { + var searcherClass = registeredSearchers[i]; + if (searcherClass.condition(pattern, options)) { + return new searcherClass(pattern, options); + } + } + return new BitapSearch(pattern, options); + } + + var LogicalOperator = { + AND: '$and', + OR: '$or' + }; + var KeyType = { + PATH: '$path', + PATTERN: '$val' + }; + var isExpression = function isExpression(query) { + return !!(query[LogicalOperator.AND] || query[LogicalOperator.OR]); + }; + var isPath = function isPath(query) { + return !!query[KeyType.PATH]; + }; + var isLeaf = function isLeaf(query) { + return !isArray(query) && isObject(query) && !isExpression(query); + }; + var convertToExplicit = function convertToExplicit(query) { + return _defineProperty({}, LogicalOperator.AND, Object.keys(query).map(function (key) { + return _defineProperty({}, key, query[key]); + })); + }; + + // When `auto` is `true`, the parse function will infer and initialize and add + // the appropriate `Searcher` instance + function parse(query, options) { + var _ref3 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, + _ref3$auto = _ref3.auto, + auto = _ref3$auto === void 0 ? true : _ref3$auto; + var next = function next(query) { + var keys = Object.keys(query); + var isQueryPath = isPath(query); + if (!isQueryPath && keys.length > 1 && !isExpression(query)) { + return next(convertToExplicit(query)); + } + if (isLeaf(query)) { + var key = isQueryPath ? query[KeyType.PATH] : keys[0]; + var pattern = isQueryPath ? query[KeyType.PATTERN] : query[key]; + if (!isString(pattern)) { + throw new Error(LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY(key)); + } + var obj = { + keyId: createKeyId(key), + pattern: pattern + }; + if (auto) { + obj.searcher = createSearcher(pattern, options); + } + return obj; + } + var node = { + children: [], + operator: keys[0] + }; + keys.forEach(function (key) { + var value = query[key]; + if (isArray(value)) { + value.forEach(function (item) { + node.children.push(next(item)); + }); + } + }); + return node; + }; + if (!isExpression(query)) { + query = convertToExplicit(query); + } + return next(query); + } + + // Practical scoring function + function computeScore(results, _ref) { + var _ref$ignoreFieldNorm = _ref.ignoreFieldNorm, + ignoreFieldNorm = _ref$ignoreFieldNorm === void 0 ? Config.ignoreFieldNorm : _ref$ignoreFieldNorm; + results.forEach(function (result) { + var totalScore = 1; + result.matches.forEach(function (_ref2) { + var key = _ref2.key, + norm = _ref2.norm, + score = _ref2.score; + var weight = key ? key.weight : null; + totalScore *= Math.pow(score === 0 && weight ? Number.EPSILON : score, (weight || 1) * (ignoreFieldNorm ? 1 : norm)); + }); + result.score = totalScore; + }); + } + + function transformMatches(result, data) { + var matches = result.matches; + data.matches = []; + if (!isDefined(matches)) { + return; + } + matches.forEach(function (match) { + if (!isDefined(match.indices) || !match.indices.length) { + return; + } + var indices = match.indices, + value = match.value; + var obj = { + indices: indices, + value: value + }; + if (match.key) { + obj.key = match.key.src; + } + if (match.idx > -1) { + obj.refIndex = match.idx; + } + data.matches.push(obj); + }); + } + + function transformScore(result, data) { + data.score = result.score; + } + + function format(results, docs) { + var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, + _ref$includeMatches = _ref.includeMatches, + includeMatches = _ref$includeMatches === void 0 ? Config.includeMatches : _ref$includeMatches, + _ref$includeScore = _ref.includeScore, + includeScore = _ref$includeScore === void 0 ? Config.includeScore : _ref$includeScore; + var transformers = []; + if (includeMatches) transformers.push(transformMatches); + if (includeScore) transformers.push(transformScore); + return results.map(function (result) { + var idx = result.idx; + var data = { + item: docs[idx], + refIndex: idx + }; + if (transformers.length) { + transformers.forEach(function (transformer) { + transformer(result, data); + }); + } + return data; + }); + } + + var Fuse$1 = /*#__PURE__*/function () { + function Fuse(docs) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var index = arguments.length > 2 ? arguments[2] : undefined; + _classCallCheck(this, Fuse); + this.options = _objectSpread2(_objectSpread2({}, Config), options); + if (this.options.useExtendedSearch && !false) { + throw new Error(EXTENDED_SEARCH_UNAVAILABLE); + } + this._keyStore = new KeyStore(this.options.keys); + this.setCollection(docs, index); + } + _createClass(Fuse, [{ + key: "setCollection", + value: function setCollection(docs, index) { + this._docs = docs; + if (index && !(index instanceof FuseIndex)) { + throw new Error(INCORRECT_INDEX_TYPE); + } + this._myIndex = index || createIndex(this.options.keys, this._docs, { + getFn: this.options.getFn, + fieldNormWeight: this.options.fieldNormWeight + }); + } + }, { + key: "add", + value: function add(doc) { + if (!isDefined(doc)) { + return; + } + this._docs.push(doc); + this._myIndex.add(doc); + } + }, { + key: "remove", + value: function remove() { + var predicate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function /* doc, idx */ () { + return false; + }; + var results = []; + for (var i = 0, len = this._docs.length; i < len; i += 1) { + var doc = this._docs[i]; + if (predicate(doc, i)) { + this.removeAt(i); + i -= 1; + len -= 1; + results.push(doc); + } + } + return results; + } + }, { + key: "removeAt", + value: function removeAt(idx) { + this._docs.splice(idx, 1); + this._myIndex.removeAt(idx); + } + }, { + key: "getIndex", + value: function getIndex() { + return this._myIndex; + } + }, { + key: "search", + value: function search(query) { + var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, + _ref$limit = _ref.limit, + limit = _ref$limit === void 0 ? -1 : _ref$limit; + var _this$options = this.options, + includeMatches = _this$options.includeMatches, + includeScore = _this$options.includeScore, + shouldSort = _this$options.shouldSort, + sortFn = _this$options.sortFn, + ignoreFieldNorm = _this$options.ignoreFieldNorm; + var results = isString(query) ? isString(this._docs[0]) ? this._searchStringList(query) : this._searchObjectList(query) : this._searchLogical(query); + computeScore(results, { + ignoreFieldNorm: ignoreFieldNorm + }); + if (shouldSort) { + results.sort(sortFn); + } + if (isNumber(limit) && limit > -1) { + results = results.slice(0, limit); + } + return format(results, this._docs, { + includeMatches: includeMatches, + includeScore: includeScore + }); + } + }, { + key: "_searchStringList", + value: function _searchStringList(query) { + var searcher = createSearcher(query, this.options); + var records = this._myIndex.records; + var results = []; + + // Iterate over every string in the index + records.forEach(function (_ref2) { + var text = _ref2.v, + idx = _ref2.i, + norm = _ref2.n; + if (!isDefined(text)) { + return; + } + var _searcher$searchIn = searcher.searchIn(text), + isMatch = _searcher$searchIn.isMatch, + score = _searcher$searchIn.score, + indices = _searcher$searchIn.indices; + if (isMatch) { + results.push({ + item: text, + idx: idx, + matches: [{ + score: score, + value: text, + norm: norm, + indices: indices + }] + }); + } + }); + return results; + } + }, { + key: "_searchLogical", + value: function _searchLogical(query) { + { + throw new Error(LOGICAL_SEARCH_UNAVAILABLE); + } + } + }, { + key: "_searchObjectList", + value: function _searchObjectList(query) { + var _this2 = this; + var searcher = createSearcher(query, this.options); + var _this$_myIndex = this._myIndex, + keys = _this$_myIndex.keys, + records = _this$_myIndex.records; + var results = []; + + // List is Array + records.forEach(function (_ref5) { + var item = _ref5.$, + idx = _ref5.i; + if (!isDefined(item)) { + return; + } + var matches = []; + + // Iterate over every key (i.e, path), and fetch the value at that key + keys.forEach(function (key, keyIndex) { + matches.push.apply(matches, _toConsumableArray(_this2._findMatches({ + key: key, + value: item[keyIndex], + searcher: searcher + }))); + }); + if (matches.length) { + results.push({ + idx: idx, + item: item, + matches: matches + }); + } + }); + return results; + } + }, { + key: "_findMatches", + value: function _findMatches(_ref6) { + var key = _ref6.key, + value = _ref6.value, + searcher = _ref6.searcher; + if (!isDefined(value)) { + return []; + } + var matches = []; + if (isArray(value)) { + value.forEach(function (_ref7) { + var text = _ref7.v, + idx = _ref7.i, + norm = _ref7.n; + if (!isDefined(text)) { + return; + } + var _searcher$searchIn2 = searcher.searchIn(text), + isMatch = _searcher$searchIn2.isMatch, + score = _searcher$searchIn2.score, + indices = _searcher$searchIn2.indices; + if (isMatch) { + matches.push({ + score: score, + key: key, + value: text, + idx: idx, + norm: norm, + indices: indices + }); + } + }); + } else { + var text = value.v, + norm = value.n; + var _searcher$searchIn3 = searcher.searchIn(text), + isMatch = _searcher$searchIn3.isMatch, + score = _searcher$searchIn3.score, + indices = _searcher$searchIn3.indices; + if (isMatch) { + matches.push({ + score: score, + key: key, + value: text, + norm: norm, + indices: indices + }); + } + } + return matches; + } + }]); + return Fuse; + }(); + + Fuse$1.version = '7.0.0'; + Fuse$1.createIndex = createIndex; + Fuse$1.parseIndex = parseIndex; + Fuse$1.config = Config; + { + Fuse$1.parseQuery = parse; + } + var Fuse = Fuse$1; + + return Fuse; + +})); diff --git a/web_responsive/static/src/lib/fuse/fuse.basic.min.js b/web_responsive/static/src/lib/fuse/fuse.basic.min.js new file mode 100644 index 000000000..745772143 --- /dev/null +++ b/web_responsive/static/src/lib/fuse/fuse.basic.min.js @@ -0,0 +1,9 @@ +/** + * Fuse.js v7.0.0 - Lightweight fuzzy-search (http://fusejs.io) + * + * Copyright (c) 2023 Kiro Risk (http://kiro.me) + * All Rights Reserved. Apache Software License 2.0 + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +var e,t;e=this,t=function(){"use strict";function e(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function t(t){for(var n=1;ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n0&&void 0!==arguments[0]?arguments[0]:{},n=t.getFn,i=void 0===n?O.getFn:n,o=t.fieldNormWeight,a=void 0===o?O.fieldNormWeight:o;r(this,e),this.norm=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:3,n=new Map,r=Math.pow(10,t);return{get:function(t){var i=t.match(j).length;if(n.has(i))return n.get(i);var o=1/Math.pow(i,.5*e),a=parseFloat(Math.round(o*r)/r);return n.set(i,a),a},clear:function(){n.clear()}}}(a,3),this.getFn=i,this.isCreated=!1,this.setIndexRecords()}return o(e,[{key:"setSources",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.docs=e}},{key:"setIndexRecords",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.records=e}},{key:"setKeys",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.keys=t,this._keysMap={},t.forEach((function(t,n){e._keysMap[t.id]=n}))}},{key:"create",value:function(){var e=this;!this.isCreated&&this.docs.length&&(this.isCreated=!0,f(this.docs[0])?this.docs.forEach((function(t,n){e._addString(t,n)})):this.docs.forEach((function(t,n){e._addObject(t,n)})),this.norm.clear())}},{key:"add",value:function(e){var t=this.size();f(e)?this._addString(e,t):this._addObject(e,t)}},{key:"removeAt",value:function(e){this.records.splice(e,1);for(var t=e,n=this.size();t2&&void 0!==arguments[2]?arguments[2]:{},r=n.getFn,i=void 0===r?O.getFn:r,o=n.fieldNormWeight,a=void 0===o?O.fieldNormWeight:o,c=new A({getFn:i,fieldNormWeight:a});return c.setKeys(e.map(x)),c.setSources(t),c.create(),c}function I(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.errors,r=void 0===n?0:n,i=t.currentLocation,o=void 0===i?0:i,a=t.expectedLocation,c=void 0===a?0:a,s=t.distance,h=void 0===s?O.distance:s,u=t.ignoreLocation,l=void 0===u?O.ignoreLocation:u,d=r/e.length;if(l)return d;var f=Math.abs(c-o);return h?d+f/h:f?1:d}var F=32;function C(e,t,n){var r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},i=r.location,o=void 0===i?O.location:i,a=r.distance,c=void 0===a?O.distance:a,s=r.threshold,h=void 0===s?O.threshold:s,u=r.findAllMatches,l=void 0===u?O.findAllMatches:u,d=r.minMatchCharLength,f=void 0===d?O.minMatchCharLength:d,v=r.includeMatches,g=void 0===v?O.includeMatches:v,y=r.ignoreLocation,p=void 0===y?O.ignoreLocation:y;if(t.length>F)throw new Error("Pattern length exceeds max of ".concat(F,"."));for(var m,b=t.length,k=e.length,M=Math.max(0,Math.min(o,k)),w=h,x=M,L=f>1||g,S=L?Array(k):[];(m=e.indexOf(t,x))>-1;){var _=I(t,{currentLocation:m,expectedLocation:M,distance:c,ignoreLocation:p});if(w=Math.min(_,w),x=m+b,L)for(var j=0;j=$;z-=1){var J=z-1,R=n[e.charAt(J)];if(L&&(S[J]=+!!R),K[z]=(K[z+1]<<1|1)&R,P&&(K[z]|=(A[z+1]|A[z])<<1|1|A[z+1]),K[z]&N&&(E=I(t,{errors:P,currentLocation:J,expectedLocation:M,distance:c,ignoreLocation:p}))<=w){if(w=E,(x=J)<=M)break;$=Math.max(1,2*M-x)}}if(I(t,{errors:P+1,currentLocation:M,expectedLocation:M,distance:c,ignoreLocation:p})>w)break;A=K}var U={isMatch:x>=0,score:Math.max(.001,E)};if(L){var B=function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:O.minMatchCharLength,n=[],r=-1,i=-1,o=0,a=e.length;o=t&&n.push([r,i]),r=-1)}return e[o-1]&&o-r>=t&&n.push([r,o-1]),n}(S,f);B.length?g&&(U.indices=B):U.isMatch=!1}return U}function N(e){for(var t={},n=0,r=e.length;n1&&void 0!==arguments[1]?arguments[1]:{},o=i.location,a=void 0===o?O.location:o,c=i.threshold,s=void 0===c?O.threshold:c,h=i.distance,u=void 0===h?O.distance:h,l=i.includeMatches,d=void 0===l?O.includeMatches:l,f=i.findAllMatches,v=void 0===f?O.findAllMatches:f,g=i.minMatchCharLength,y=void 0===g?O.minMatchCharLength:g,p=i.isCaseSensitive,m=void 0===p?O.isCaseSensitive:p,b=i.ignoreLocation,k=void 0===b?O.ignoreLocation:b;if(r(this,e),this.options={location:a,threshold:s,distance:u,includeMatches:d,findAllMatches:v,minMatchCharLength:y,isCaseSensitive:m,ignoreLocation:k},this.pattern=m?t:t.toLowerCase(),this.chunks=[],this.pattern.length){var M=function(e,t){n.chunks.push({pattern:e,alphabet:N(e),startIndex:t})},w=this.pattern.length;if(w>F){for(var x=0,L=w%F,S=w-L;x-1&&(n.refIndex=e.idx),t.matches.push(n)}}))}function D(e,t){t.score=e.score}var K=function(){function e(n){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},o=arguments.length>2?arguments[2]:void 0;if(r(this,e),this.options=t(t({},O),i),this.options.useExtendedSearch)throw new Error("Extended search is not available");this._keyStore=new w(this.options.keys),this.setCollection(n,o)}return o(e,[{key:"setCollection",value:function(e,t){if(this._docs=e,t&&!(t instanceof A))throw new Error("Incorrect 'index' type");this._myIndex=t||E(this.options.keys,this._docs,{getFn:this.options.getFn,fieldNormWeight:this.options.fieldNormWeight})}},{key:"add",value:function(e){y(e)&&(this._docs.push(e),this._myIndex.add(e))}},{key:"remove",value:function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:function(){return!1},t=[],n=0,r=this._docs.length;n1&&void 0!==arguments[1]?arguments[1]:{}).limit,n=void 0===t?-1:t,r=this.options,i=r.includeMatches,o=r.includeScore,a=r.shouldSort,c=r.sortFn,s=r.ignoreFieldNorm,h=f(e)?f(this._docs[0])?this._searchStringList(e):this._searchObjectList(e):this._searchLogical(e);return function(e,t){var n=t.ignoreFieldNorm,r=void 0===n?O.ignoreFieldNorm:n;e.forEach((function(e){var t=1;e.matches.forEach((function(e){var n=e.key,i=e.norm,o=e.score,a=n?n.weight:null;t*=Math.pow(0===o&&a?Number.EPSILON:o,(a||1)*(r?1:i))})),e.score=t}))}(h,{ignoreFieldNorm:s}),a&&h.sort(c),v(n)&&n>-1&&(h=h.slice(0,n)),function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=n.includeMatches,i=void 0===r?O.includeMatches:r,o=n.includeScore,a=void 0===o?O.includeScore:o,c=[];return i&&c.push($),a&&c.push(D),e.map((function(e){var n=e.idx,r={item:t[n],refIndex:n};return c.length&&c.forEach((function(t){t(e,r)})),r}))}(h,this._docs,{includeMatches:i,includeScore:o})}},{key:"_searchStringList",value:function(e){var t=T(e,this.options),n=this._myIndex.records,r=[];return n.forEach((function(e){var n=e.v,i=e.i,o=e.n;if(y(n)){var a=t.searchIn(n),c=a.isMatch,s=a.score,h=a.indices;c&&r.push({item:n,idx:i,matches:[{score:s,value:n,norm:o,indices:h}]})}})),r}},{key:"_searchLogical",value:function(e){throw new Error("Logical search is not available")}},{key:"_searchObjectList",value:function(e){var t=this,n=T(e,this.options),r=this._myIndex,i=r.keys,o=r.records,a=[];return o.forEach((function(e){var r=e.$,o=e.i;if(y(r)){var s=[];i.forEach((function(e,i){s.push.apply(s,c(t._findMatches({key:e,value:r[i],searcher:n})))})),s.length&&a.push({idx:o,item:r,matches:s})}})),a}},{key:"_findMatches",value:function(e){var t=e.key,n=e.value,r=e.searcher;if(!y(n))return[];var i=[];if(u(n))n.forEach((function(e){var n=e.v,o=e.i,a=e.n;if(y(n)){var c=r.searchIn(n),s=c.isMatch,h=c.score,u=c.indices;s&&i.push({score:h,key:t,value:n,idx:o,norm:a,indices:u})}}));else{var o=n.v,a=n.n,c=r.searchIn(o),s=c.isMatch,h=c.score,l=c.indices;s&&i.push({score:h,key:t,value:o,norm:a,indices:l})}return i}}]),e}();return K.version="7.0.0",K.createIndex=E,K.parseIndex=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.getFn,r=void 0===n?O.getFn:n,i=t.fieldNormWeight,o=void 0===i?O.fieldNormWeight:i,a=e.keys,c=e.records,s=new A({getFn:r,fieldNormWeight:o});return s.setKeys(a),s.setIndexRecords(c),s},K.config=O,K},"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Fuse=t(); \ No newline at end of file diff --git a/web_responsive/static/src/views/form/form_controller.scss b/web_responsive/static/src/views/form/form_controller.scss new file mode 100644 index 000000000..75310c3ae --- /dev/null +++ b/web_responsive/static/src/views/form/form_controller.scss @@ -0,0 +1,10 @@ +/* Copyright 2023 Tecnativa - Carlos Roca + * Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +// Many2one li items with wrap +.o_field_many2one_selection { + .o-autocomplete--dropdown-menu .ui-menu-item-wrapper { + white-space: initial; + } +} diff --git a/web_responsive/static/src/views/form/form_statusbar.scss b/web_responsive/static/src/views/form/form_statusbar.scss new file mode 100644 index 000000000..7f7084661 --- /dev/null +++ b/web_responsive/static/src/views/form/form_statusbar.scss @@ -0,0 +1,21 @@ +/* Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +.o_xxl_form_view { + .o_form_sheet_bg { + overflow: unset; + + .o_form_sheet { + overflow: auto; + + &::-webkit-scrollbar { + width: 10px; + } + + &::-webkit-scrollbar-thumb { + background: $o-brand-odoo; + border-radius: 6px; + } + } + } +} diff --git a/web_responsive/static/src/views/form/status_bar_buttons.xml b/web_responsive/static/src/views/form/status_bar_buttons.xml new file mode 100644 index 000000000..9d8cb8ff1 --- /dev/null +++ b/web_responsive/static/src/views/form/status_bar_buttons.xml @@ -0,0 +1,24 @@ + + + + + + + 'shift+a' + + + + + Action + + + + + diff --git a/web_responsive/static/tests/apps_menu_search_tests.esm.js b/web_responsive/static/tests/apps_menu_search_tests.esm.js new file mode 100644 index 000000000..4832c4f5d --- /dev/null +++ b/web_responsive/static/tests/apps_menu_search_tests.esm.js @@ -0,0 +1,54 @@ +/** @odoo-module **/ +/* global QUnit */ +/* eslint init-declarations: "warn" */ +/* Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +import {click, getFixture, mount, patchWithCleanup} from "@web/../tests/helpers/utils"; +import {Component, xml} from "@odoo/owl"; +import {makeTestEnv} from "@web/../tests/helpers/mock_env"; +import {actionService} from "@web/webclient/actions/action_service"; +import {browser} from "@web/core/browser/browser"; +import {menuService} from "@web/webclient/menus/menu_service"; +import {notificationService} from "@web/core/notifications/notification_service"; +import {NavBar} from "@web/webclient/navbar/navbar"; +import {registry} from "@web/core/registry"; +import {hotkeyService} from "@web/core/hotkeys/hotkey_service"; +import {uiService} from "@web/core/ui/ui_service"; + +const serviceRegistry = registry.category("services"); + +class MySystrayItem extends Component {} + +MySystrayItem.template = xml`
  • my item
  • `; +let baseConfig; +let target; + +QUnit.module("AppsMenu Search", { + async beforeEach() { + target = getFixture(); + serviceRegistry.add("menu", menuService); + serviceRegistry.add("action", actionService); + serviceRegistry.add("notification", notificationService); + serviceRegistry.add("hotkey", hotkeyService); + serviceRegistry.add("ui", uiService); + patchWithCleanup(browser, { + setTimeout: (handler, delay, ...args) => handler(...args), + clearTimeout: () => undefined, + }); + const menus = { + root: {id: "root", children: [1, 2], name: "root", appID: "root"}, + 1: {id: 1, children: [], name: "App0", appID: 1, xmlid: "menu_1"}, + 2: {id: 2, children: [], name: "App1", appID: 2, xmlid: "menu_2"}, + }; + const serverData = {menus}; + baseConfig = {serverData}; + }, +}); + +QUnit.test("can be rendered", async (assert) => { + const env = await makeTestEnv(baseConfig); + await mount(NavBar, target, {env}); + await click(target, "button.o_grid_apps_menu__button"); + assert.containsOnce(target, ".app-menu-container .search-input"); +}); diff --git a/web_responsive/static/tests/apps_menu_tests.esm.js b/web_responsive/static/tests/apps_menu_tests.esm.js new file mode 100644 index 000000000..6af7a5e00 --- /dev/null +++ b/web_responsive/static/tests/apps_menu_tests.esm.js @@ -0,0 +1,87 @@ +/** @odoo-module **/ +/* global QUnit */ +/* eslint init-declarations: "warn" */ +/* Copyright 2023 Taras Shabaranskyi + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ + +import { + click, + getFixture, + mount, + nextTick, + patchWithCleanup, +} from "@web/../tests/helpers/utils"; +import {Component, xml} from "@odoo/owl"; +import {makeTestEnv} from "@web/../tests/helpers/mock_env"; +import {actionService} from "@web/webclient/actions/action_service"; +import {browser} from "@web/core/browser/browser"; +import {menuService} from "@web/webclient/menus/menu_service"; +import {notificationService} from "@web/core/notifications/notification_service"; +import {NavBar} from "@web/webclient/navbar/navbar"; +import {registry} from "@web/core/registry"; +import {hotkeyService} from "@web/core/hotkeys/hotkey_service"; +import {uiService} from "@web/core/ui/ui_service"; + +const serviceRegistry = registry.category("services"); + +class MySystrayItem extends Component {} + +MySystrayItem.template = xml`
  • my item
  • `; +let baseConfig; +let target; + +QUnit.module("AppsMenu", { + async beforeEach() { + target = getFixture(); + serviceRegistry.add("menu", menuService); + serviceRegistry.add("action", actionService); + serviceRegistry.add("notification", notificationService); + serviceRegistry.add("hotkey", hotkeyService); + serviceRegistry.add("ui", uiService); + patchWithCleanup(browser, { + setTimeout: (handler, delay, ...args) => handler(...args), + clearTimeout: () => undefined, + }); + const menus = { + root: {id: "root", children: [1, 2], name: "root", appID: "root"}, + 1: {id: 1, children: [], name: "App0", appID: 1, xmlid: "menu_1"}, + 2: {id: 2, children: [], name: "App1", appID: 2, xmlid: "menu_2"}, + }; + const serverData = {menus}; + baseConfig = {serverData}; + }, +}); + +QUnit.test("can be rendered", async (assert) => { + const env = await makeTestEnv(baseConfig); + await mount(NavBar, target, {env}); + assert.containsOnce( + target, + ".o_grid_apps_menu button.o_grid_apps_menu__button", + "1 apps menu button present" + ); +}); + +QUnit.test("can be opened and closed", async (assert) => { + const env = await makeTestEnv(baseConfig); + await mount(NavBar, target, {env}); + await click(target, "button.o_grid_apps_menu__button"); + await nextTick(); + assert.containsOnce(target, ".o-app-menu-list"); + await click(target, "button.o_grid_apps_menu__button"); + await nextTick(); + assert.containsNone(target, ".o-app-menu-list"); +}); + +QUnit.test("can be active", async (assert) => { + const env = await makeTestEnv(baseConfig); + await mount(NavBar, target, {env}); + await click(target, "button.o_grid_apps_menu__button"); + await nextTick(); + env.services.menu.setCurrentMenu(1); + await nextTick(); + assert.containsOnce(target, '.o-app-menu-item.active[data-menu-xmlid="menu_1"]'); + env.services.menu.setCurrentMenu(2); + await nextTick(); + assert.containsOnce(target, '.o-app-menu-item.active[data-menu-xmlid="menu_2"]'); +}); diff --git a/web_responsive/static/tests/test_patch.js b/web_responsive/static/tests/test_patch.js new file mode 100644 index 000000000..46319cf7d --- /dev/null +++ b/web_responsive/static/tests/test_patch.js @@ -0,0 +1,19 @@ +/* Copyright 2021 ITerra - Sergey Shebanin + * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */ +odoo.define("web_responsive.test_patch", function (require) { + "use strict"; + + const utils = require("web_tour.TourStepUtils"); + + /* Make base odoo JS tests working */ + utils.include({ + showAppsMenuItem() { + return { + edition: "community", + trigger: ".o_navbar_apps_menu", + auto: true, + position: "bottom", + }; + }, + }); +}); diff --git a/web_responsive/tests/__init__.py b/web_responsive/tests/__init__.py new file mode 100644 index 000000000..1961bf280 --- /dev/null +++ b/web_responsive/tests/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2023 Taras Shabaranskyi +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +from . import test_ir_http diff --git a/web_responsive/tests/test_ir_http.py b/web_responsive/tests/test_ir_http.py new file mode 100644 index 000000000..e2100762c --- /dev/null +++ b/web_responsive/tests/test_ir_http.py @@ -0,0 +1,35 @@ +# Copyright 2023 Taras Shabaranskyi +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +import json +import re + +from odoo.tests import HttpCase, tagged + + +@tagged("-at_install", "post_install") +class TestIrHttp(HttpCase): + def _test_session_info(self, session_info): + apps_menu = session_info.get("apps_menu") + self.assertIsNotNone(apps_menu) + self.assertTrue("search_type" in apps_menu) + self.assertTrue("theme" in apps_menu) + + def _find_session_info(self, line_items): + key = "odoo.__session_info__ = " + line = next(filter(lambda item: key in item, line_items), None) + self.assertIsNotNone(line) + match = re.match(rf".*{key}(.*);", line) + self.assertIsNotNone(match) + return match.group(1) + + def test_session_info(self): + self.authenticate("admin", "admin") + r = self.url_open("/web") + self.assertEqual(r.status_code, 200) + self.assertIsInstance(r.text, str) + line_items = r.text.splitlines() + self.assertTrue(bool(line_items)) + session_info_str = self._find_session_info(line_items) + self.assertIsInstance(session_info_str, str) + self._test_session_info(json.loads(session_info_str)) diff --git a/web_responsive/views/res_users_views.xml b/web_responsive/views/res_users_views.xml new file mode 100644 index 000000000..8972a65f3 --- /dev/null +++ b/web_responsive/views/res_users_views.xml @@ -0,0 +1,64 @@ + + + + + res.users.apps.menu.preferences.form + res.users + +
    + + + + + + + + +
    +

    Search Type Help

    + + + + + + + + + + + + + +
    Canonicaluses a standard algorithm
    Fusea new search algorithm is used
    Command Palettethe standard odoo search tool
    +
    +
    +
    +
    + + + Apps Menu Preferences + ir.actions.act_window + res.users + form + new + + +