From 5036a68a019f4d73e87e24b25b81d953b78a7531 Mon Sep 17 00:00:00 2001
From: Sergey Shebanin
Date: Thu, 11 Feb 2021 15:07:56 +0300
Subject: [PATCH] [MIG] web_responsive: Migration to 14.0
---
.../web_responsive/odoo/addons/web_responsive | 1 +
setup/web_responsive/setup.py | 6 +
web_responsive/README.rst | 18 +-
web_responsive/__manifest__.py | 9 +-
web_responsive/i18n/web_responsive.pot | 85 +--
web_responsive/models/res_users.py | 4 +-
web_responsive/readme/CONTRIBUTORS.rst | 1 +
web_responsive/static/description/index.html | 7 +-
.../static/src/css/kanban_view_mobile.scss | 97 ++++
.../static/src/css/search_view_mobile.scss | 109 ++++
.../static/src/css/web_responsive.scss | 386 +++++++++-----
web_responsive/static/src/js/discuss.js | 300 -----------
.../static/src/js/kanban_renderer_mobile.js | 494 ++++++++++++++++++
.../static/src/js/web_responsive.js | 228 +++++---
web_responsive/static/src/xml/apps.xml | 3 +-
.../static/src/xml/attachment_viewer.xml | 47 ++
.../static/src/xml/control_panel.xml | 146 ++++++
web_responsive/static/src/xml/discuss.xml | 7 +-
.../static/src/xml/document_viewer.xml | 46 --
.../xml/{form_view.xml => form_buttons.xml} | 39 +-
web_responsive/static/src/xml/navbar.xml | 4 +-
.../static/src/xml/search_panel.xml | 53 ++
web_responsive/views/assets.xml | 14 +-
web_responsive/views/web.xml | 12 +
24 files changed, 1463 insertions(+), 653 deletions(-)
create mode 120000 setup/web_responsive/odoo/addons/web_responsive
create mode 100644 setup/web_responsive/setup.py
create mode 100644 web_responsive/static/src/css/kanban_view_mobile.scss
create mode 100644 web_responsive/static/src/css/search_view_mobile.scss
delete mode 100644 web_responsive/static/src/js/discuss.js
create mode 100644 web_responsive/static/src/js/kanban_renderer_mobile.js
create mode 100644 web_responsive/static/src/xml/attachment_viewer.xml
create mode 100644 web_responsive/static/src/xml/control_panel.xml
delete mode 100644 web_responsive/static/src/xml/document_viewer.xml
rename web_responsive/static/src/xml/{form_view.xml => form_buttons.xml} (76%)
create mode 100644 web_responsive/static/src/xml/search_panel.xml
diff --git a/setup/web_responsive/odoo/addons/web_responsive b/setup/web_responsive/odoo/addons/web_responsive
new file mode 120000
index 000000000000..a084a42d2216
--- /dev/null
+++ b/setup/web_responsive/odoo/addons/web_responsive
@@ -0,0 +1 @@
+../../../../web_responsive
\ No newline at end of file
diff --git a/setup/web_responsive/setup.py b/setup/web_responsive/setup.py
new file mode 100644
index 000000000000..28c57bb64031
--- /dev/null
+++ b/setup/web_responsive/setup.py
@@ -0,0 +1,6 @@
+import setuptools
+
+setuptools.setup(
+ setup_requires=['setuptools-odoo'],
+ odoo_addon=True,
+)
diff --git a/web_responsive/README.rst b/web_responsive/README.rst
index f0196628e84c..c7015f43e404 100644
--- a/web_responsive/README.rst
+++ b/web_responsive/README.rst
@@ -14,16 +14,16 @@ Web Responsive
: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/13.0/web_responsive
+ :target: https://github.com/OCA/web/tree/14.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-13-0/web-13-0-web_responsive
+ :target: https://translation.odoo-community.org/projects/web-14-0/web-14-0-web_responsive
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
- :target: https://runbot.odoo-community.org/runbot/162/13.0
+ :target: https://runbot.odoo-community.org/runbot/162/14.0
:alt: Try me on Runbot
-|badge1| |badge2| |badge3| |badge4| |badge5|
+|badge1| |badge2| |badge3| |badge4| |badge5|
This module adds responsiveness to web backend.
@@ -142,9 +142,10 @@ Known issues / Roadmap
device screen size. This means that, if you change the size of your browser,
you should reload the web client to get the full experience for that
new size. This is Odoo's own limitation.
+* Kanban mobile/desktop mode switch on screen resize. F.x. when rotating a device
+ to landscape orientation.
* App navigation with keyboard.
* Handle long titles on forms in a better way
-* Standard sticky headers seems to not work properly on iOS Safari/Chrome (see #1626).
Bug Tracker
===========
@@ -152,7 +153,7 @@ 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 smashing it by providing a detailed and welcomed
-`feedback `_.
+`feedback `_.
Do not contact contributors directly about support or help with technical issues.
@@ -175,6 +176,7 @@ Contributors
* Alexandre Díaz
* Mathias Markl
* Iván Todorovich
+* Sergey Shebanin
Maintainers
~~~~~~~~~~~
@@ -198,8 +200,8 @@ promote its widespread use.
Current `maintainers `__:
-|maintainer-Yajo| |maintainer-Tardo|
+|maintainer-Yajo| |maintainer-Tardo|
-This module is part of the `OCA/web `_ project on GitHub.
+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/__manifest__.py b/web_responsive/__manifest__.py
index d6f416e1024d..10919c1985f8 100644
--- a/web_responsive/__manifest__.py
+++ b/web_responsive/__manifest__.py
@@ -6,7 +6,7 @@
{
"name": "Web Responsive",
"summary": "Responsive web client, community-supported",
- "version": "13.0.2.6.4",
+ "version": "14.0.1.0.0",
"category": "Website",
"website": "https://github.com/OCA/web",
"author": "LasLabs, Tecnativa, " "Odoo Community Association (OCA)",
@@ -18,10 +18,13 @@
"data": ["views/assets.xml", "views/res_users.xml", "views/web.xml"],
"qweb": [
"static/src/xml/apps.xml",
- "static/src/xml/form_view.xml",
+ "static/src/xml/form_buttons.xml",
"static/src/xml/menu.xml",
"static/src/xml/navbar.xml",
- "static/src/xml/document_viewer.xml",
+ "static/src/xml/attachment_viewer.xml",
"static/src/xml/discuss.xml",
+ "static/src/xml/control_panel.xml",
+ "static/src/xml/search_panel.xml",
],
+ "sequence": 1,
}
diff --git a/web_responsive/i18n/web_responsive.pot b/web_responsive/i18n/web_responsive.pot
index 016f496f0952..84a29138e0b4 100644
--- a/web_responsive/i18n/web_responsive.pot
+++ b/web_responsive/i18n/web_responsive.pot
@@ -4,7 +4,7 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: Odoo Server 13.0\n"
+"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: \n"
"Language-Team: \n"
@@ -15,9 +15,16 @@ msgstr ""
#. module: web_responsive
#. openerp-web
-#: code:addons/web_responsive/static/src/xml/apps.xml:0
+#: code:addons/web_responsive/static/src/xml/search_panel.xml:0
#, python-format
-msgid "#menu_id=#{app.menuID}&action_id=#{app.actionID}"
+msgid "All"
+msgstr ""
+
+#. module: web_responsive
+#. openerp-web
+#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
+#, python-format
+msgid "CLEAR"
msgstr ""
#. module: web_responsive
@@ -27,44 +34,47 @@ msgstr ""
#. module: web_responsive
#. openerp-web
-#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
+#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
+#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
-msgid "Close"
+msgid "Create"
msgstr ""
#. module: web_responsive
#. openerp-web
-#: code:addons/web_responsive/static/src/xml/form_view.xml:0
-#: code:addons/web_responsive/static/src/xml/form_view.xml:0
+#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
+#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
-msgid "Create"
+msgid "Discard"
msgstr ""
#. module: web_responsive
#. openerp-web
-#: code:addons/web_responsive/static/src/xml/form_view.xml:0
-#: code:addons/web_responsive/static/src/xml/form_view.xml:0
+#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
-msgid "Discard"
+msgid "Edit"
msgstr ""
#. module: web_responsive
#. openerp-web
-#: code:addons/web_responsive/static/src/xml/form_view.xml:0
+#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
+#: code:addons/web_responsive/static/src/xml/search_panel.xml:0
#, python-format
-msgid "Edit"
+msgid "FILTER"
msgstr ""
#. module: web_responsive
#. openerp-web
-#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
+#: code:addons/web_responsive/static/src/xml/attachment_viewer.xml:0
+#: code:addons/web_responsive/static/src/xml/attachment_viewer.xml:0
#, python-format
msgid "Maximize"
msgstr ""
#. module: web_responsive
#. openerp-web
-#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
+#: code:addons/web_responsive/static/src/xml/attachment_viewer.xml:0
+#: code:addons/web_responsive/static/src/xml/attachment_viewer.xml:0
#, python-format
msgid "Minimize"
msgstr ""
@@ -76,15 +86,23 @@ msgstr ""
#. module: web_responsive
#. openerp-web
-#: code:addons/web_responsive/static/src/xml/form_view.xml:0
+#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Quick actions"
msgstr ""
#. module: web_responsive
#. openerp-web
-#: code:addons/web_responsive/static/src/xml/form_view.xml:0
-#: code:addons/web_responsive/static/src/xml/form_view.xml:0
+#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
+#: code:addons/web_responsive/static/src/xml/search_panel.xml:0
+#, python-format
+msgid "SEE RESULT"
+msgstr ""
+
+#. module: web_responsive
+#. openerp-web
+#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
+#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
#, python-format
msgid "Save"
msgstr ""
@@ -96,6 +114,14 @@ msgstr ""
msgid "Search menus..."
msgstr ""
+#. module: web_responsive
+#. openerp-web
+#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
+#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
+#, python-format
+msgid "Search..."
+msgstr ""
+
#. module: web_responsive
#. openerp-web
#: code:addons/web_responsive/static/src/xml/menu.xml:0
@@ -109,30 +135,27 @@ msgid "Sided"
msgstr ""
#. module: web_responsive
-#: model:ir.model,name:web_responsive.model_res_users
-msgid "Users"
+#. openerp-web
+#: code:addons/web_responsive/static/src/xml/form_buttons.xml:0
+#, python-format
+msgid "Today"
msgstr ""
#. module: web_responsive
#. openerp-web
-#: code:addons/web_responsive/static/src/xml/discuss.xml:0
+#: code:addons/web_responsive/static/src/js/kanban_renderer_mobile.js:0
#, python-format
-msgid ""
-"btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none"
+msgid "Undefined"
msgstr ""
#. module: web_responsive
-#. openerp-web
-#: code:addons/web_responsive/static/src/xml/apps.xml:0
-#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
-#, python-format
-msgid "false"
+#: model:ir.model,name:web_responsive.model_res_users
+msgid "Users"
msgstr ""
#. module: web_responsive
#. openerp-web
-#: code:addons/web_responsive/static/src/xml/document_viewer.xml:0
+#: code:addons/web_responsive/static/src/xml/control_panel.xml:0
#, python-format
-msgid ""
-"modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer"
+msgid "View switcher"
msgstr ""
diff --git a/web_responsive/models/res_users.py b/web_responsive/models/res_users.py
index 035b5be8af58..5247df678087 100644
--- a/web_responsive/models/res_users.py
+++ b/web_responsive/models/res_users.py
@@ -14,11 +14,11 @@ class ResUsers(models.Model):
)
def __init__(self, pool, cr):
- """ Override of __init__ to add access rights.
+ """Override of __init__ to add access rights.
Access rights are disabled by default, but allowed on some specific
fields defined in self.SELF_{READ/WRITE}ABLE_FIELDS.
"""
- super(ResUsers, self).__init__(pool, cr)
+ super().__init__(pool, cr)
# duplicate list to avoid modifying the original reference
type(self).SELF_WRITEABLE_FIELDS = list(self.SELF_WRITEABLE_FIELDS)
type(self).SELF_WRITEABLE_FIELDS.extend(["chatter_position"])
diff --git a/web_responsive/readme/CONTRIBUTORS.rst b/web_responsive/readme/CONTRIBUTORS.rst
index 55c1e934b715..ca52594ac483 100644
--- a/web_responsive/readme/CONTRIBUTORS.rst
+++ b/web_responsive/readme/CONTRIBUTORS.rst
@@ -5,3 +5,4 @@
* Alexandre Díaz
* Mathias Markl
* Iván Todorovich
+* Sergey Shebanin
diff --git a/web_responsive/static/description/index.html b/web_responsive/static/description/index.html
index 7d6ba5fe7065..0efefb318381 100644
--- a/web_responsive/static/description/index.html
+++ b/web_responsive/static/description/index.html
@@ -367,7 +367,7 @@ Web Responsive
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
-
+
This module adds responsiveness to web backend.
Features for all devices:
@@ -485,7 +485,7 @@
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 smashing it by providing a detailed and welcomed
-feedback .
+feedback .
Do not contact contributors directly about support or help with technical issues.
@@ -518,7 +519,7 @@
promote its widespread use.
Current maintainers :
-
This module is part of the OCA/web project on GitHub.
+
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/src/css/kanban_view_mobile.scss b/web_responsive/static/src/css/kanban_view_mobile.scss
new file mode 100644
index 000000000000..76d86d09d00b
--- /dev/null
+++ b/web_responsive/static/src/css/kanban_view_mobile.scss
@@ -0,0 +1,97 @@
+@include media-breakpoint-down(sm) {
+ .o_kanban_view.o_kanban_grouped {
+ display: block;
+ position: relative;
+ overflow-x: hidden;
+ &.o_renderer_with_searchpanel {
+ width: 100%;
+ }
+
+ .o_kanban_mobile_tabs_container {
+ position: sticky;
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+ top: 0;
+ z-index: 1;
+ background-color: #5e5e5e;
+
+ .o_kanban_mobile_add_column {
+ height: $o-kanban-mobile-tabs-height;
+ padding: 10px;
+ border-left: grey 1px solid;
+ color: white;
+ font-size: 14px;
+ }
+
+ .o_kanban_mobile_tabs {
+ position: relative;
+ display: flex;
+ width: 100%;
+ height: $o-kanban-mobile-tabs-height;
+ overflow-x: auto;
+
+ .o_kanban_mobile_tab {
+ height: $o-kanban-mobile-tabs-height;
+ padding: 10px 20px;
+ font-size: 14px;
+ color: white;
+
+ &.o_current {
+ font-weight: bold;
+ border-bottom: 3px solid $o-brand-primary;
+ }
+
+ .o_column_title {
+ white-space: nowrap;
+ text-transform: uppercase;
+ }
+ }
+ }
+ }
+ .o_kanban_columns_content {
+ position: relative;
+ }
+ // [class] to get same specificity as elsewhere (kanban_view.less)
+ &[class] .o_kanban_group:not(.o_column_folded) {
+ @include o-position-absolute(
+ $top: $o-kanban-mobile-tabs-height,
+ $left: 0,
+ $bottom: 0
+ );
+ width: 100%;
+ padding: 0;
+ margin-left: 0; // override the margin-left: -1px of the desktop mode
+ border: none;
+
+ &.o_current {
+ position: inherit;
+ top: 0;
+
+ &.o_kanban_no_records {
+ // set a default height for clarity when embedded in another view
+ min-height: $o-kanban-mobile-empty-height;
+ }
+ }
+
+ .o_kanban_header {
+ display: none;
+ }
+ .o_kanban_record,
+ .o_kanban_quick_create {
+ border: none;
+ border-bottom: 1px solid lightgray;
+ padding: 10px 16px;
+ margin: 0;
+ }
+ }
+ }
+ .o_kanban_view .o_column_quick_create {
+ .o_quick_create_folded {
+ display: none !important;
+ }
+ .o_quick_create_unfolded {
+ width: 100%;
+ }
+ }
+}
diff --git a/web_responsive/static/src/css/search_view_mobile.scss b/web_responsive/static/src/css/search_view_mobile.scss
new file mode 100644
index 000000000000..06762e4b0c9e
--- /dev/null
+++ b/web_responsive/static/src/css/search_view_mobile.scss
@@ -0,0 +1,109 @@
+.o_web_client {
+ .o_mobile_search {
+ position: fixed;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ padding: 0;
+ width: 100%;
+ background-color: white;
+ z-index: $zindex-modal;
+ overflow: auto;
+ .o_mobile_search_header {
+ height: 46px;
+ margin-bottom: 10px;
+ width: 100%;
+ background-color: $o-brand-odoo;
+ color: white;
+ span:active {
+ background-color: darken($o-brand-primary, 10%);
+ }
+ span {
+ cursor: pointer;
+ }
+ }
+ .o_searchview_input_container {
+ display: flex;
+ padding: 15px 20px 0 20px;
+ position: relative;
+ .o_searchview_input {
+ width: 100%;
+ margin-bottom: 15px;
+ border-bottom: 1px solid $o-brand-secondary;
+ }
+ .o_searchview_facet {
+ border-radius: 10px;
+ display: inline-flex;
+ order: 1;
+ .o_searchview_facet_label {
+ border-radius: 2em 0em 0em 2em;
+ }
+ }
+ .o_searchview_autocomplete {
+ top: 100%;
+ > li {
+ margin: 5px 0px;
+ }
+ }
+ }
+ .o_mobile_search_filter {
+ padding-bottom: 15%;
+ .o_dropdown {
+ width: 100%;
+ margin: 15px 5px 0px 5px;
+ border: solid 1px darken(gray("200"), 20%);
+ }
+ .o_dropdown_toggler_btn {
+ width: 100%;
+ text-align: left;
+
+ &:after {
+ display: none;
+ }
+ }
+
+ // We disable the backdrop in this case because it prevents any
+ // interaction outside of a dropdown while it is open.
+ .dropdown-backdrop {
+ z-index: -1;
+ }
+ .dropdown-menu {
+ // Here we use !important because of popper js adding custom style
+ // to element so to override it use !important
+ position: relative !important;
+ width: 100% !important;
+ transform: translate3d(0, 0, 0) !important;
+ box-shadow: none;
+ border: none;
+ color: gray("600");
+ .divider {
+ margin: 0px;
+ }
+ > li > a {
+ padding: 10px 26px;
+ }
+ }
+ }
+ .o_mobile_search_show_result {
+ padding: 10px;
+ font-size: 15px;
+ }
+ }
+}
+// Search panel
+@include media-breakpoint-down(sm) {
+ .o_controller_with_searchpanel {
+ display: block;
+ .o_search_panel {
+ height: auto;
+ padding: 8px;
+ border-left: 1px solid $gray-300;
+ section {
+ padding: 0px 16px;
+ }
+ }
+ .o_search_panel_summary {
+ cursor: pointer;
+ }
+ }
+}
diff --git a/web_responsive/static/src/css/web_responsive.scss b/web_responsive/static/src/css/web_responsive.scss
index 683eb8700558..a1a7d332ab5e 100644
--- a/web_responsive/static/src/css/web_responsive.scss
+++ b/web_responsive/static/src/css/web_responsive.scss
@@ -328,38 +328,114 @@ html .o_web_client .o_action_manager .o_action {
max-width: 100%;
}
-// Control panel (breadcrumbs, search box, buttons...)
+// Make enough space for search panel filters buttons
+.o_control_panel {
+ // There is no media breakpoint for XL upper bound
+ @include media-breakpoint-up(lg) {
+ @media (max-width: 1360px) {
+ .o_cp_top_left,
+ .o_cp_bottom_left {
+ width: 40%;
+ }
+ .o_cp_top_right,
+ .o_cp_bottom_right {
+ width: 60%;
+ }
+ }
+ }
+ // For FULL HD devices
+ @media (min-width: 1900px) {
+ .o_cp_top_left,
+ .o_cp_bottom_left {
+ width: 60%;
+ }
+ .o_cp_top_right,
+ .o_cp_bottom_right {
+ width: 40%;
+ }
+ }
+ @include media-breakpoint-only(md) {
+ .o_search_options_hide_labels .o_dropdown_title {
+ display: none;
+ }
+ }
+ .o_cp_bottom_right {
+ height: 30px;
+ }
+}
+
+// Mobile Control panel (breadcrumbs, search box, buttons...)
@include media-breakpoint-down(sm) {
.o_control_panel {
+ // Avoid horizontal scrolling of control panel.
+ // It doesn't work on iOS Safari, but it looks similar as
+ // without this patch. With this patch it looks better for
+ // other browsers.
+ position: sticky;
+ left: 0;
+ z-index: 3;
+
// Arrange buttons to use space better
- .breadcrumb,
- .o_cp_buttons,
- .o_cp_left,
- .o_cp_right,
- .o_cp_searchview {
+ .o_cp_top_left,
+ .o_cp_top_right {
flex: 1 1 100%;
- @include media-breakpoint-up(md) {
- flex-basis: 50%;
- }
}
- .breadcrumb {
+ .o_cp_top_left {
flex-basis: 80%;
}
- .o_cp_searchview,
- .o_cp_right {
- flex-basis: 10%;
+ .o_cp_top_right {
+ flex-basis: 20%;
}
- .o_cp_left {
- flex-basis: 50%;
- white-space: nowrap;
+ .o_cp_bottom {
+ position: relative; // Necessary for dropdown menu positioning
+ display: block;
+ margin: 0;
+ }
+
+ .o_cp_bottom_left {
+ float: left;
+ margin: 5px 0;
+ }
+
+ .o_cp_bottom_right {
+ float: right;
+ height: 30px;
+ padding-left: 10px;
+ margin: 5px 0;
}
+ .o_cp_bottom_right,
.o_cp_pager {
white-space: nowrap;
}
+ .o_cp_pager {
+ margin-bottom: 0;
+ }
+
+ .o_cp_bottom_left > .o_cp_action_menus {
+ padding-right: 0;
+ .o_dropdown_title,
+ .fa-chevron-right,
+ .fa-chevron-down {
+ display: none;
+ }
+ .o_dropdown_toggler_btn {
+ margin: 0px 2px;
+ }
+ @include media-breakpoint-down(xs) {
+ .o_dropdown {
+ position: static;
+ }
+ .dropdown-menu {
+ right: 0;
+ left: 0;
+ top: 35px;
+ }
+ }
+ }
// Hide all but 2 last breadcrumbs, and render 2nd-to-last as arrow
.breadcrumb-item {
@@ -379,7 +455,7 @@ html .o_web_client .o_action_manager .o_action {
&:nth-last-of-type(2) {
&::before {
color: var(--primary);
- content: "\f048"; // .fa-step-backward
+ content: "\f060"; // .fa-arrow-left
cursor: pointer;
font-family: FontAwesome;
}
@@ -396,36 +472,67 @@ html .o_web_client .o_action_manager .o_action {
text-overflow: ellipsis;
}
- // Empty sidebar should not break layout
- .o_cp_sidebar:blank {
- display: none;
- }
-
// In case you install `mail`, there is a mess on BS vs inline styles
// we need to fix
.o_cp_buttons .btn.d-block:not(.d-none) {
display: inline-block !important;
}
- // Dropdown with buttons to switch the view type
- .o_cp_switch_buttons.show {
- .dropdown-menu {
- align-content: center;
+ .o_searchview {
+ padding: 1px 0px 3px 0px;
+ &.o_searchview_mobile {
+ cursor: pointer;
+ }
+ &.o_searchview_quick {
display: flex;
- flex-direction: row;
- justify-content: space-around;
- padding: 0;
-
- .btn {
- border: {
- bottom: 0;
- radius: 0;
- top: 0;
- }
+ flex: 1 1 auto;
+ align-items: center;
+ .o_searchview_input_container {
+ flex: 1 1 auto;
}
}
}
}
+ .o_calendar_view .o_calendar_widget {
+ .fc-timeGridDay-view .fc-axis,
+ .fc-timeGridWeek-view .fc-axis {
+ padding-left: 0px;
+ }
+ .fc-dayGridMonth-view {
+ padding-left: 0px;
+ .fc-week-number {
+ display: none;
+ }
+ }
+ .fc-dayGridYear-view {
+ padding-left: 0px;
+ > .fc-month-container > .fc-month {
+ width: 100%;
+ }
+ }
+ .fc-timeGridDay-view .fc-widget-header {
+ margin: 0 4px;
+ }
+ .fc-timeGridWeek-view .fc-widget-header {
+ word-spacing: 4em;
+ white-space: normal;
+ text-align: center;
+ }
+ }
+ .o_base_settings .o_setting_container {
+ display: block;
+ .settings_tab {
+ flex-flow: row nowrap;
+ padding-top: 0px;
+ .tab {
+ padding-right: 16px;
+ }
+ .selected {
+ background-color: #212529;
+ box-shadow: inset 0 -5px #7c7bad;
+ }
+ }
+ }
}
// Normal views
@@ -440,13 +547,31 @@ html .o_web_client .o_action_manager .o_action {
overflow-x: auto;
}
- .oe_chatter {
+ .o_FormRenderer_chatterContainer {
padding-top: 0;
+ .o_Activity_info {
+ flex-wrap: wrap;
+ }
+ .o_ActivityBox_title {
+ margin-bottom: 0;
+ }
+ .o_MessageList_separatorDate {
+ padding-bottom: 0;
+ }
}
-
- .o_chatter_topbar {
- height: auto;
- flex-wrap: wrap-reverse;
+ // Sided chatter scrolling behavior
+ .o_Chatter {
+ height: fit-content;
+ .o_Chatter_fixedPanel {
+ position: sticky;
+ top: 0;
+ z-index: 1;
+ background-color: white;
+ padding-bottom: 10px;
+ }
+ .o_Chatter_scrollPanel {
+ overflow: initial;
+ }
}
// Sticky statusbar
@@ -458,17 +583,14 @@ html .o_web_client .o_action_manager .o_action {
// Support for long title (with ellipsis)
.oe_title {
- span.o_field_widget {
- &:not(.oe_inline) {
- max-width: 100%;
- text-overflow: ellipsis;
- white-space: nowrap;
- overflow: hidden;
- width: initial;
-
- &:active {
- white-space: normal;
- }
+ span.o_field_widget:not(.oe_inline) {
+ max-width: 100%;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ width: initial;
+ &:active {
+ white-space: normal;
}
}
}
@@ -520,7 +642,7 @@ html .o_web_client .o_action_manager .o_action {
}
height: 100%;
}
- .o_statusbar_buttons > .btn {
+ .o_statusbar_buttons.dropdown-menu > .btn {
border-radius: 0;
border: 0;
width: 100%;
@@ -541,7 +663,7 @@ html .o_web_client .o_action_manager .o_action {
// Full width in form sheets
.o_form_sheet,
- .oe_chatter {
+ .o_FormRenderer_chatterContainer {
min-width: auto;
max-width: 98%;
}
@@ -553,7 +675,7 @@ html .o_web_client .o_action_manager .o_action {
}
}
- .o_chatter {
+ .o_FormRenderer_chatterContainer {
padding-top: initial;
// Display send button on small screens
@@ -605,7 +727,7 @@ html .o_web_client .o_action_manager .o_action {
}
}
- .o_chatter {
+ .o_FormRenderer_chatterContainer {
border-left: 1px solid gray("400");
flex: 0 0 $chatter_zone_width;
max-width: initial;
@@ -645,7 +767,6 @@ html .o_web_client .o_action_manager .o_action {
.table-responsive {
.o_list_table {
// th & td are here for compatibility with chrome
- thead,
thead tr:nth-child(1) th {
position: sticky;
top: 0;
@@ -693,114 +814,105 @@ html .o_web_client .o_action_manager .o_action {
cursor: progress;
}
-// Document Viewer
-.o_web_client.o_chatter_position_sided {
- .o_modal_fullscreen.o_document_viewer {
- // On-top of navbar
- z-index: 10;
-
- &.o_responsive_document_viewer {
- /* Show sided viewer on large screens */
- @include media-breakpoint-up(lg) {
- width: $chatter_zone_width;
- margin-left: auto;
- right: 0;
-
- /* Show/Hide control buttons (next, prev, etc..) */
- &:hover .arrow,
- &:hover .o_viewer_toolbar {
- display: flex;
- }
- .arrow,
- .o_viewer_toolbar {
- display: none;
- }
+// Attachment Viewer
+.o_web_client.o_chatter_position_sided .o_Dialog_AttachmentViewer {
+ /* Show sided viewer on large screens */
+ @include media-breakpoint-up(lg) {
+ position: static;
+ .o_AttachmentViewer_main {
+ padding-bottom: 20px;
+ }
+ .o_AttachmentViewer {
+ // On-top of navbar
+ z-index: 10;
+ position: absolute;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ margin-left: auto;
+ background-color: rgba(0, 0, 0, 0.7);
- .o_viewer_img_wrapper {
- position: relative;
+ .o_AttachmentViewer_name {
+ display: contents;
+ }
- .o_viewer_pdf {
- width: 95%;
- }
- }
+ width: $chatter_zone_width;
+ &.o_AttachmentViewer_maximized {
+ width: 100%;
}
- .o_minimize_btn {
- display: none;
+ /* Show/Hide control buttons (next, prev, etc..) */
+ &:hover .o_AttachmentViewer_buttonNavigation,
+ &:hover .o_AttachmentViewer_toolbar {
+ display: flex;
}
- }
- &:not(.o_responsive_document_viewer) {
- .o_maximize_btn {
+ .o_AttachmentViewer_buttonNavigation,
+ .o_AttachmentViewer_toolbar {
display: none;
}
- }
- @include media-breakpoint-down(lg) {
- .o_minimize_btn,
- .o_maximize_btn {
- display: none;
+ .o_AttachmentViewer_viewIframe {
+ width: 95%;
}
}
}
-}
-/* Max/Min buttons only are usefull in sided mode */
-.o_web_client:not(.o_chatter_position_sided) {
- .o_minimize_btn,
- .o_maximize_btn {
- display: none;
- }
-}
-// Apply improvements for Document Viewer on all modes
-.o_modal_fullscreen .o_viewer_content {
- .o_viewer-header {
- .o_image_caption {
- display: contents;
- }
-
- // Now uses a container to have more buttons
- .o_buttons {
- min-width: 35px;
- text-align: right;
-
- // Now close button ('X') it's a fa-icon
- > .o_close_btn {
- top: unset;
- left: unset;
- bottom: unset;
- right: unset;
- font-size: unset;
- font-weight: unset;
- }
+ @include media-breakpoint-down(md) {
+ .o_AttachmentViewer_headerItemButtonMinimize,
+ .o_AttachmentViewer_headerItemButtonMaximize {
+ display: none;
}
}
}
-
-// Search Panel
-@include media-breakpoint-down(sm) {
- // Hide search panel
- .o_controller_with_searchpanel {
- .o_search_panel {
- display: none;
- }
+/* Attachment Viewer Max/Min buttons only are useful in sided mode */
+.o_web_client:not(.o_chatter_position_sided) {
+ .o_AttachmentViewer_headerItemButtonMinimize,
+ .o_AttachmentViewer_headerItemButtonMaximize {
+ display: none;
}
}
.o_control_panel {
- // Filter Menu item
- .o_filters_menu {
+ // Filter Menu
+ // Cut long filters names in the filters menu
+ .o_filter_menu {
.o_menu_item {
- @include o-search-options-dropdown-custom-item;
-
+ width: auto;
+ @include media-breakpoint-up(md) {
+ max-width: 250px;
+ }
a {
overflow: hidden;
text-overflow: ellipsis;
}
}
}
-
// Enable scroll on dropdowns
.o_cp_buttons .dropdown-menu {
max-height: 70vh;
overflow-y: auto;
overflow-x: hidden;
}
+ // Dropdown with buttons to switch the view type
+ .o_cp_switch_buttons.show {
+ .dropdown-menu {
+ align-content: center;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-around;
+ padding: 0;
+
+ .btn {
+ border: {
+ bottom: 0;
+ radius: 0;
+ top: 0;
+ }
+ font-size: 1.3em;
+ }
+ }
+ }
+}
+
+// Shortcut table ui improvement
+.o_shortcut_table {
+ width: 100%;
}
diff --git a/web_responsive/static/src/js/discuss.js b/web_responsive/static/src/js/discuss.js
deleted file mode 100644
index bf516dfeb774..000000000000
--- a/web_responsive/static/src/js/discuss.js
+++ /dev/null
@@ -1,300 +0,0 @@
-/* Copyright Odoo S.A.
- * Ported to 13.0 by Copyright 2020 Tecnativa - Alexandre Díaz
- * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */
-
-odoo.define("web_responsive.Discuss", function(require) {
- "use strict";
-
- const config = require("web.config");
- if (!config.device.isMobile) {
- return;
- }
-
- const core = require("web.core");
- const Discuss = require("mail.Discuss");
-
- const QWeb = core.qweb;
-
- Discuss.include({
- contentTemplate: "mail.discuss_mobile",
- events: Object.assign({}, Discuss.prototype.events, {
- "click .o_mail_mobile_tab": "_onClickMobileTab",
- "click .o_mailbox_inbox_item": "_onClickMobileMailboxItem",
- "click .o_mail_preview": "_onClickMobileMailPreview",
- }),
-
- /**
- * @override
- */
- init: function() {
- this._super.apply(this, arguments);
- this._currentState = this._defaultThreadID;
- },
-
- /**
- * @override
- */
- start: function() {
- this._$mainContent = this.$(".o_mail_discuss_content");
- return this._super
- .apply(this, arguments)
- .then(this._updateControlPanel.bind(this));
- },
-
- /**
- * @override
- */
- on_attach_callback: function() {
- if (this._thread && this._isInInboxTab()) {
- this._threadWidget.scrollToPosition(
- this._threadsScrolltop[this._thread.getID()]
- );
- }
- },
- /**
- * @override
- */
- on_detach_callback: function() {
- if (this._isInInboxTab()) {
- this._threadsScrolltop[
- this._thread.getID()
- ] = this._threadWidget.getScrolltop();
- }
- },
-
- // --------------------------------------------------------------------------
- // Private
- // --------------------------------------------------------------------------
-
- /**
- * @private
- * @returns {Boolean} true iff we currently are in the Inbox tab
- */
- _isInInboxTab: function() {
- return _.contains(["mailbox_inbox", "mailbox_starred"], this._currentState);
- },
- /**
- * @override
- * @private
- */
- _renderButtons: function() {
- this._super.apply(this, arguments);
- _.each(["dm_chat", "multi_user_channel"], type => {
- const selector = ".o_mail_discuss_button_" + type;
- this.$buttons.on("click", selector, this._onAddThread.bind(this));
- });
- },
- /**
- * Overrides to only store the thread state if we are in the Inbox tab, as
- * this is the only tab in which we actually have a displayed thread
- *
- * @override
- * @private
- */
- _restoreThreadState: function() {
- if (this._isInInboxTab()) {
- this._super.apply(this, arguments);
- }
- },
- /**
- * Overrides to toggle the visibility of the tabs when a message is selected
- *
- * @override
- * @private
- */
- _selectMessage: function() {
- this._super.apply(this, arguments);
- this.$(".o_mail_mobile_tabs").addClass("o_hidden");
- },
- /**
- * @override
- * @private
- */
- _setThread: function(threadID) {
- const thread = this.call("mail_service", "getThread", threadID);
- this._thread = thread;
- if (thread.getType() !== "mailbox") {
- this.call("mail_service", "openThreadWindow", threadID);
- return Promise.resolve();
- }
- return this._super.apply(this, arguments);
- },
- /**
- * Overrides to only store the thread state if we are in the Inbox tab, as
- * this is the only tab in which we actually have a displayed thread
- *
- * @override
- * @private
- */
- _storeThreadState: function() {
- if (this._thread && this._isInInboxTab()) {
- this._super.apply(this, arguments);
- }
- },
- /**
- * Overrides to toggle the visibility of the tabs when a message is
- * unselected
- *
- * @override
- * @private
- */
- _unselectMessage: function() {
- this._super.apply(this, arguments);
- this.$(".o_mail_mobile_tabs").removeClass("o_hidden");
- },
- /**
- * @override
- * @private
- */
- _updateThreads: function() {
- return this._updateContent(this._currentState);
- },
- /**
- * Redraws the content of the client action according to its current state.
- *
- * @private
- * @param {String} type the thread's type to display (e.g. 'mailbox_inbox',
- * 'mailbox_starred', 'dm_chat'...).
- * @returns {Promise}
- */
- _updateContent: function(type) {
- const inMailbox = type === "mailbox_inbox" || type === "mailbox_starred";
- if (!inMailbox && this._isInInboxTab()) {
- // We're leaving the inbox, so store the thread scrolltop
- this._storeThreadState();
- }
- const previouslyInInbox = this._isInInboxTab();
- this._currentState = type;
-
- // Fetch content to display
- let def = false;
- if (inMailbox) {
- def = this._fetchAndRenderThread();
- } else {
- const allChannels = this.call("mail_service", "getChannels");
- const channels = _.filter(allChannels, function(channel) {
- return channel.getType() === type;
- });
- def = this.call("mail_service", "getChannelPreviews", channels);
- }
- return def.then(previews => {
- // Update content
- if (inMailbox) {
- if (!previouslyInInbox) {
- this.$(".o_mail_discuss_tab_pane").remove();
- this._$mainContent.append(this._threadWidget.$el);
- this._$mainContent.append(this._extendedComposer.$el);
- }
- this._restoreThreadState();
- } else {
- this._threadWidget.$el.detach();
- this._extendedComposer.$el.detach();
- const $content = $(
- QWeb.render("mail.discuss.MobileTabPane", {
- previews: previews,
- type: type,
- })
- );
- this._prepareAddThreadInput(
- $content.find(".o_mail_add_thread input"),
- type
- );
- this._$mainContent.html($content);
- }
-
- // Update control panel
- this.$buttons
- .find("button")
- .removeClass("d-block")
- .addClass("d-none");
- this.$buttons
- .find(".o_mail_discuss_button_" + type)
- .removeClass("d-none")
- .addClass("d-block");
- this.$buttons
- .find(".o_mail_discuss_button_mark_all_read")
- .toggleClass("d-none", type !== "mailbox_inbox")
- .toggleClass("d-block", type === "mailbox_inbox");
- this.$buttons
- .find(".o_mail_discuss_button_unstar_all")
- .toggleClass("d-none", type !== "mailbox_starred")
- .toggleClass("d-block", type === "mailbox_starred");
-
- // Update Mailbox page buttons
- if (inMailbox) {
- this.$(".o_mail_discuss_mobile_mailboxes_buttons").removeClass(
- "o_hidden"
- );
- this.$(".o_mailbox_inbox_item")
- .removeClass("btn-primary")
- .addClass("btn-secondary");
- this.$(".o_mailbox_inbox_item[data-type=" + type + "]")
- .removeClass("btn-secondary")
- .addClass("btn-primary");
- } else {
- this.$(".o_mail_discuss_mobile_mailboxes_buttons").addClass(
- "o_hidden"
- );
- }
-
- // Update bottom buttons
- this.$(".o_mail_mobile_tab").removeClass("active");
- // Mailbox_inbox and mailbox_starred share the same tab
- const type_n = type === "mailbox_starred" ? "mailbox_inbox" : type;
- this.$(".o_mail_mobile_tab[data-type=" + type_n + "]").addClass(
- "active"
- );
- });
- },
-
- // --------------------------------------------------------------------------
- // Handlers
- // --------------------------------------------------------------------------
-
- /**
- * @override
- * @private
- */
- _onAddThread: function() {
- this.$(".o_mail_add_thread")
- .show()
- .find("input")
- .focus();
- },
- /**
- * Switches to the clicked thread in the Inbox page (Inbox or Starred).
- *
- * @private
- * @param {MouseEvent} ev
- */
- _onClickMobileMailboxItem: function(ev) {
- const mailboxID = $(ev.currentTarget).data("type");
- this._setThread(mailboxID);
- this._updateContent(this._thread.getID());
- },
- /**
- * Switches to another tab.
- *
- * @private
- * @param {MouseEvent} ev
- */
- _onClickMobileTab: function(ev) {
- const type = $(ev.currentTarget).data("type");
- if (type === "mailbox") {
- const inbox = this.call("mail_service", "getMailbox", "inbox");
- this._setThread(inbox);
- }
- this._updateContent(type);
- },
- /**
- * Opens a thread in a chat window (full screen in mobile).
- *
- * @private
- * @param {MouseEvent} ev
- */
- _onClickMobileMailPreview: function(ev) {
- const threadID = $(ev.currentTarget).data("preview-id");
- this.call("mail_service", "openThreadWindow", threadID);
- },
- });
-});
diff --git a/web_responsive/static/src/js/kanban_renderer_mobile.js b/web_responsive/static/src/js/kanban_renderer_mobile.js
new file mode 100644
index 000000000000..5c62db757220
--- /dev/null
+++ b/web_responsive/static/src/js/kanban_renderer_mobile.js
@@ -0,0 +1,494 @@
+odoo.define("web_responsive.KanbanRendererMobile", function (require) {
+ "use strict";
+
+ /**
+ * The purpose of this file is to improve the UX of grouped kanban views in
+ * mobile. It includes the KanbanRenderer (in mobile only) to only display one
+ * column full width, and enables the swipe to browse to the other columns.
+ * Moreover, records in columns are lazy-loaded.
+ */
+
+ var config = require("web.config");
+ var core = require("web.core");
+ var KanbanRenderer = require("web.KanbanRenderer");
+ var KanbanView = require("web.KanbanView");
+ var KanbanQuickCreate = require("web.kanban_column_quick_create");
+
+ var _t = core._t;
+ var qweb = core.qweb;
+
+ if (!config.device.isMobile) {
+ return;
+ }
+
+ KanbanQuickCreate.include({
+ init() {
+ this._super.apply(this, arguments);
+ this.isMobile = true;
+ },
+ });
+
+ KanbanView.include({
+ init() {
+ this._super.apply(this, arguments);
+ this.jsLibs.push("/web/static/lib/jquery.touchSwipe/jquery.touchSwipe.js");
+ },
+ });
+
+ KanbanRenderer.include({
+ custom_events: _.extend({}, KanbanRenderer.prototype.custom_events || {}, {
+ quick_create_column_created: "_onColumnAdded",
+ }),
+ events: _.extend({}, KanbanRenderer.prototype.events, {
+ "click .o_kanban_mobile_tab": "_onMobileTabClicked",
+ "click .o_kanban_mobile_add_column": "_onMobileQuickCreateClicked",
+ }),
+ ANIMATE: true, // Allows to disable animations for the tests
+ /**
+ * @override
+ */
+ init: function () {
+ this._super.apply(this, arguments);
+ this.activeColumnIndex = 0; // Index of the currently displayed column
+ this._scrollPosition = null;
+ },
+ /**
+ * As this renderer defines its own scrolling area (the column in grouped
+ * mode), we override this hook to restore the scroll position like it was
+ * when the renderer has been last detached.
+ *
+ * @override
+ */
+ on_attach_callback: function () {
+ if (
+ this._scrollPosition &&
+ this.state.groupedBy.length &&
+ this.widgets.length
+ ) {
+ var $column = this.widgets[this.activeColumnIndex].$el;
+ $column.scrollLeft(this._scrollPosition.left);
+ $column.scrollTop(this._scrollPosition.top);
+ }
+ this._computeTabPosition();
+ this._super.apply(this, arguments);
+ },
+ /**
+ * As this renderer defines its own scrolling area (the column in grouped
+ * mode), we override this hook to store the scroll position, so that we can
+ * restore it if the renderer is re-attached to the DOM later.
+ *
+ * @override
+ */
+ on_detach_callback: function () {
+ if (this.state.groupedBy.length && this.widgets.length) {
+ var $column = this.widgets[this.activeColumnIndex].$el;
+ this._scrollPosition = {
+ left: $column.scrollLeft(),
+ top: $column.scrollTop(),
+ };
+ } else {
+ this._scrollPosition = null;
+ }
+ this._super.apply(this, arguments);
+ },
+
+ // --------------------------------------------------------------------------
+ // Public
+ // --------------------------------------------------------------------------
+
+ /**
+ * Displays the quick create record in the active column
+ * override to open quick create record in current active column
+ *
+ * @override
+ * @returns {Promise}
+ */
+ addQuickCreate: function () {
+ if (this._canCreateColumn() && !this.quickCreate.folded) {
+ this._onMobileQuickCreateClicked();
+ }
+ return this.widgets[this.activeColumnIndex].addQuickCreate();
+ },
+
+ /**
+ * Overrides to restore the left property and the scrollTop on the updated
+ * column, and to enable the swipe handlers
+ *
+ * @override
+ */
+ updateColumn: function (localID) {
+ var index = _.findIndex(this.widgets, {db_id: localID});
+ var $column = this.widgets[index].$el;
+ var scrollTop = $column.scrollTop();
+ return (
+ this._super
+ .apply(this, arguments)
+ .then(() => this._layoutUpdate(false))
+ // Required when clicking on 'Load More'
+ .then(() => $column.scrollTop(scrollTop))
+ .then(() => this._enableSwipe())
+ );
+ },
+
+ // --------------------------------------------------------------------------
+ // Private
+ // --------------------------------------------------------------------------
+
+ /**
+ * Check if we use the quick create on mobile
+ * @returns {Boolean}
+ * @private
+ */
+ _canCreateColumn: function () {
+ return this.quickCreateEnabled && this.quickCreate && this.widgets.length;
+ },
+
+ /**
+ * Update the columns positions
+ *
+ * @private
+ * @param {Boolean} [animate=false] set to true to animate
+ */
+ _computeColumnPosition: function (animate) {
+ if (this.widgets.length) {
+ // Check rtl to compute correct css value
+ const rtl = _t.database.parameters.direction === "rtl";
+
+ // Display all o_kanban_group
+ this.$(".o_kanban_group").show();
+
+ const $columnAfter = this._toNode(
+ this.widgets.filter(
+ (widget, index) => index > this.activeColumnIndex
+ )
+ );
+ const promiseAfter = this._updateColumnCss(
+ $columnAfter,
+ rtl ? {right: "100%"} : {left: "100%"},
+ animate
+ );
+
+ const $columnBefore = this._toNode(
+ this.widgets.filter(
+ (widget, index) => index < this.activeColumnIndex
+ )
+ );
+ const promiseBefore = this._updateColumnCss(
+ $columnBefore,
+ rtl ? {right: "-100%"} : {left: "-100%"},
+ animate
+ );
+
+ const $columnCurrent = this._toNode(
+ this.widgets.filter(
+ (widget, index) => index === this.activeColumnIndex
+ )
+ );
+ const promiseCurrent = this._updateColumnCss(
+ $columnCurrent,
+ rtl ? {right: "0%"} : {left: "0%"},
+ animate
+ );
+
+ promiseAfter
+ .then(promiseBefore)
+ .then(promiseCurrent)
+ .then(() => {
+ $columnAfter.hide();
+ $columnBefore.hide();
+ });
+ }
+ },
+
+ /**
+ * Define the o_current class to the current selected kanban (column & tab)
+ *
+ * @private
+ */
+ _computeCurrentColumn: function () {
+ if (this.widgets.length) {
+ var column = this.widgets[this.activeColumnIndex];
+ if (!column) {
+ return;
+ }
+ var columnID = column.id || column.db_id;
+ this.$(
+ ".o_kanban_mobile_tab.o_current, .o_kanban_group.o_current"
+ ).removeClass("o_current");
+ this.$(
+ '.o_kanban_group[data-id="' +
+ columnID +
+ '"], ' +
+ '.o_kanban_mobile_tab[data-id="' +
+ columnID +
+ '"]'
+ ).addClass("o_current");
+ }
+ },
+
+ /**
+ * Update the tabs positions
+ *
+ * @private
+ */
+ _computeTabPosition: function () {
+ this._computeTabJustification();
+ this._computeTabScrollPosition();
+ },
+
+ /**
+ * Update the tabs positions
+ *
+ * @private
+ */
+ _computeTabScrollPosition: function () {
+ if (this.widgets.length) {
+ var lastItemIndex = this.widgets.length - 1;
+ var moveToIndex = this.activeColumnIndex;
+ var scrollToLeft = 0;
+ for (var i = 0; i < moveToIndex; i++) {
+ var columnWidth = this._getTabWidth(this.widgets[i]);
+ // Apply
+ if (moveToIndex !== lastItemIndex && i === moveToIndex - 1) {
+ var partialWidth = 0.75;
+ scrollToLeft += columnWidth * partialWidth;
+ } else {
+ scrollToLeft += columnWidth;
+ }
+ }
+ // Apply the scroll x on the tabs
+ // XXX in case of RTL, should we use scrollRight?
+ this.$(".o_kanban_mobile_tabs").scrollLeft(scrollToLeft);
+ }
+ },
+
+ /**
+ * Compute the justify content of the kanban tab headers
+ *
+ * @private
+ */
+ _computeTabJustification: function () {
+ if (this.widgets.length) {
+ var self = this;
+ // Use to compute the sum of the width of all tab
+ var widthChilds = this.widgets.reduce(function (total, column) {
+ return total + self._getTabWidth(column);
+ }, 0);
+ // Apply a space around between child if the parent length is higher then the sum of the child width
+ var $tabs = this.$(".o_kanban_mobile_tabs");
+ $tabs.toggleClass(
+ "justify-content-between",
+ $tabs.outerWidth() >= widthChilds
+ );
+ }
+ },
+
+ /**
+ * Enables swipe event on the current column
+ *
+ * @private
+ */
+ _enableSwipe: function () {
+ var self = this;
+ var step = _t.database.parameters.direction === "rtl" ? -1 : 1;
+ this.$el.swipe({
+ excludedElements: ".o_kanban_mobile_tabs",
+ swipeLeft: function () {
+ var moveToIndex = self.activeColumnIndex + step;
+ if (moveToIndex < self.widgets.length) {
+ self._moveToGroup(moveToIndex, self.ANIMATE);
+ }
+ },
+ swipeRight: function () {
+ var moveToIndex = self.activeColumnIndex - step;
+ if (moveToIndex > -1) {
+ self._moveToGroup(moveToIndex, self.ANIMATE);
+ }
+ },
+ });
+ },
+
+ /**
+ * Retrieve the outerWidth of a given widget column
+ *
+ * @param {KanbanColumn} column
+ * @returns {integer} outerWidth of the found column
+ * @private
+ */
+ _getTabWidth: function (column) {
+ var columnID = column.id || column.db_id;
+ return this.$(
+ '.o_kanban_mobile_tab[data-id="' + columnID + '"]'
+ ).outerWidth();
+ },
+
+ /**
+ * Update the kanban layout
+ *
+ * @private
+ * @param {Boolean} [animate=false] set to true to animate
+ */
+ _layoutUpdate: function (animate) {
+ this._computeCurrentColumn();
+ this._computeTabPosition();
+ this._computeColumnPosition(animate);
+ this._enableSwipe();
+ },
+
+ /**
+ * Moves to the given kanban column
+ *
+ * @private
+ * @param {integer} moveToIndex index of the column to move to
+ * @param {Boolean} [animate=false] set to true to animate
+ * @returns {Promise} resolved when the new current group has been loaded
+ * and displayed
+ */
+ _moveToGroup: function (moveToIndex, animate) {
+ var self = this;
+ if (moveToIndex >= 0 && moveToIndex < this.widgets.length) {
+ this.activeColumnIndex = moveToIndex;
+ }
+ var column = this.widgets[this.activeColumnIndex];
+ this._enableSwipe();
+ if (!column.data.isOpen) {
+ this.trigger_up("column_toggle_fold", {
+ db_id: column.db_id,
+ onSuccess: () => self._layoutUpdate(animate),
+ });
+ } else {
+ this._layoutUpdate(animate);
+ }
+ return Promise.resolve();
+ },
+ /**
+ * @override
+ * @private
+ */
+ _renderExampleBackground: function () {
+ // Override to avoid display of example background
+ },
+ /**
+ * @override
+ * @private
+ */
+ _renderGrouped: function (fragment) {
+ var self = this;
+ var newFragment = document.createDocumentFragment();
+ this._super.apply(this, [newFragment]);
+ this.defs.push(
+ Promise.all(this.defs).then(function () {
+ var data = [];
+ _.each(self.state.data, function (group) {
+ if (!group.value) {
+ group = _.extend({}, group, {value: _t("Undefined")});
+ data.unshift(group);
+ } else {
+ data.push(group);
+ }
+ });
+
+ var kanbanColumnContainer = document.createElement("div");
+ kanbanColumnContainer.classList.add("o_kanban_columns_content");
+ kanbanColumnContainer.appendChild(newFragment);
+ fragment.appendChild(kanbanColumnContainer);
+ $(
+ qweb.render("KanbanView.MobileTabs", {
+ data: data,
+ quickCreateEnabled: self._canCreateColumn(),
+ })
+ ).prependTo(fragment);
+ })
+ );
+ },
+
+ /**
+ * @override
+ * @private
+ */
+ _renderView: function () {
+ var self = this;
+ return this._super.apply(this, arguments).then(function () {
+ if (self.state.groupedBy.length) {
+ // Force first column for kanban view, because the groupedBy can be changed
+ return self._moveToGroup(0);
+ }
+ if (self._canCreateColumn()) {
+ self._onMobileQuickCreateClicked();
+ }
+ return Promise.resolve();
+ });
+ },
+
+ /**
+ * Retrieve the Jquery node (.o_kanban_group) for a list of a given widgets
+ *
+ * @private
+ * @param widgets
+ * @returns {jQuery} the matching .o_kanban_group widgets
+ */
+ _toNode: function (widgets) {
+ const selectorCss = widgets
+ .map(
+ (widget) =>
+ '.o_kanban_group[data-id="' + (widget.id || widget.db_id) + '"]'
+ )
+ .join(", ");
+ return this.$(selectorCss);
+ },
+
+ /**
+ * Update the given column to the updated positions
+ *
+ * @private
+ * @param $column The jquery column
+ * @param cssProperties Use to update column
+ * @param {Boolean} [animate=false] set to true to animate
+ * @returns {Promise}
+ */
+ _updateColumnCss: function ($column, cssProperties, animate) {
+ if (animate) {
+ return new Promise((resolve) =>
+ $column.animate(cssProperties, "fast", resolve)
+ );
+ }
+ $column.css(cssProperties);
+ return Promise.resolve();
+ },
+
+ // --------------------------------------------------------------------------
+ // Handlers
+ // --------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ _onColumnAdded: function () {
+ this._computeTabPosition();
+ if (this._canCreateColumn() && !this.quickCreate.folded) {
+ this.quickCreate.toggleFold();
+ }
+ },
+
+ /**
+ * @private
+ */
+ _onMobileQuickCreateClicked: function (event) {
+ if (event) {
+ event.stopPropagation();
+ }
+ this.$(".o_kanban_group").toggle();
+ this.quickCreate.toggleFold();
+ },
+ /**
+ * @private
+ * @param {MouseEvent} event
+ */
+ _onMobileTabClicked: function (event) {
+ if (this._canCreateColumn() && !this.quickCreate.folded) {
+ this.quickCreate.toggleFold();
+ }
+ this._moveToGroup($(event.currentTarget).index(), true);
+ },
+ });
+});
diff --git a/web_responsive/static/src/js/web_responsive.js b/web_responsive/static/src/js/web_responsive.js
index 244c867a6f38..5151a30396fe 100644
--- a/web_responsive/static/src/js/web_responsive.js
+++ b/web_responsive/static/src/js/web_responsive.js
@@ -1,7 +1,8 @@
/* Copyright 2018 Tecnativa - Jairo Llopis
+ * Copyright 2018 Tecnativa - Sergey Shebanin
* License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). */
-odoo.define("web_responsive", function(require) {
+odoo.define("web_responsive", function (require) {
"use strict";
const ActionManager = require("web.ActionManager");
@@ -13,16 +14,23 @@ odoo.define("web_responsive", function(require) {
const FormRenderer = require("web.FormRenderer");
const Menu = require("web.Menu");
const RelationalFields = require("web.relational_fields");
- const Chatter = require("mail.Chatter");
const ListRenderer = require("web.ListRenderer");
- const DocumentViewer = require("mail.DocumentViewer");
+ const CalendarRenderer = require("web.CalendarRenderer");
+ const patchMixin = require("web.patchMixin");
+ const AttachmentViewer = require("mail/static/src/components/attachment_viewer/attachment_viewer.js");
+ const PatchableAttachmentViewer = patchMixin(AttachmentViewer);
+ const ControlPanel = require("web.ControlPanel");
+ const SearchPanel = require("web/static/src/js/views/search_panel.js");
+ /* global owl */
+ const {QWeb, Context} = owl;
+ const {useState, useContext} = owl.hooks;
/* Hide AppDrawer in desktop and mobile modes.
* To avoid delays in pages with a lot of DOM nodes we make
* sub-groups' with 'querySelector' to improve the performance.
*/
function closeAppDrawer() {
- _.defer(function() {
+ _.defer(function () {
// Need close AppDrawer?
var menu_apps_dropdown = document.querySelector(".o_menu_apps .dropdown");
$(menu_apps_dropdown)
@@ -115,7 +123,7 @@ odoo.define("web_responsive", function(require) {
*
* @override
*/
- init: function(parent, menuData) {
+ init: function (parent, menuData) {
this._super.apply(this, arguments);
// Keep base64 icon for main menus
for (const n in this._apps) {
@@ -130,7 +138,7 @@ odoo.define("web_responsive", function(require) {
/**
* @override
*/
- start: function() {
+ start: function () {
this.$search_container = this.$(".search-container");
this.$search_input = this.$(".search-input input");
this.$search_results = this.$(".search-results");
@@ -142,7 +150,7 @@ odoo.define("web_responsive", function(require) {
*
* @override
*/
- _onAppsMenuItemClicked: function(ev) {
+ _onAppsMenuItemClicked: function (ev) {
this._super.apply(this, arguments);
ev.preventDefault();
ev.stopPropagation();
@@ -157,7 +165,7 @@ odoo.define("web_responsive", function(require) {
* @returns {Object}
* Menu definition, plus extra needed keys.
*/
- _menuInfo: function(key) {
+ _menuInfo: function (key) {
const original = this._searchableMenus[key];
return _.extend(
{
@@ -170,7 +178,7 @@ odoo.define("web_responsive", function(require) {
/**
* Autofocus on search field on big screens.
*/
- _searchFocus: function() {
+ _searchFocus: function () {
if (!config.device.isMobile) {
// This timeout is necessary since the menu has a 100ms fading animation
setTimeout(() => this.$search_input.focus(), 100);
@@ -180,7 +188,7 @@ odoo.define("web_responsive", function(require) {
/**
* Reset search input and results
*/
- _searchReset: function() {
+ _searchReset: function () {
this.$search_container.removeClass("has-results");
this.$search_results.empty();
this.$search_input.val("");
@@ -189,8 +197,8 @@ odoo.define("web_responsive", function(require) {
/**
* Schedule a search on current menu items.
*/
- _searchMenusSchedule: function() {
- this._search_def = new Promise(resolve => {
+ _searchMenusSchedule: function () {
+ this._search_def = new Promise((resolve) => {
setTimeout(resolve, 50);
});
this._search_def.then(this._searchMenus.bind(this));
@@ -199,7 +207,7 @@ odoo.define("web_responsive", function(require) {
/**
* Search among available menu items, and render that search.
*/
- _searchMenus: function() {
+ _searchMenus: function () {
const query = this.$search_input.val();
if (query === "") {
this.$search_container.removeClass("has-results");
@@ -224,7 +232,7 @@ odoo.define("web_responsive", function(require) {
*
* @param {jQuery.Event} event
*/
- _searchResultChosen: function(event) {
+ _searchResultChosen: function (event) {
event.preventDefault();
event.stopPropagation();
const $result = $(event.currentTarget),
@@ -238,7 +246,7 @@ odoo.define("web_responsive", function(require) {
previous_menu_id: data.parentId,
});
// Find app that owns the chosen menu
- const app = _.find(this._apps, function(_app) {
+ const app = _.find(this._apps, function (_app) {
return text.indexOf(_app.name + suffix) === 0;
});
// Update navbar menus
@@ -250,7 +258,7 @@ odoo.define("web_responsive", function(require) {
*
* @param {jQuery.Event} event
*/
- _searchResultsNavigate: function(event) {
+ _searchResultsNavigate: function (event) {
// Find current results and active element (1st by default)
const all = this.$search_results.find(".o-menu-search-result"),
pre_focused = all.filter(".active") || $(all[0]);
@@ -301,7 +309,7 @@ odoo.define("web_responsive", function(require) {
/*
* Control if AppDrawer can be closed
*/
- _hideAppsMenu: function() {
+ _hideAppsMenu: function () {
return !this.$("input").is(":focus");
},
});
@@ -313,7 +321,7 @@ odoo.define("web_responsive", function(require) {
*
* @override
*/
- canBeDiscarded: function(recordID) {
+ canBeDiscarded: function (recordID) {
if (this.model.isDirty(recordID || this.handle)) {
closeAppDrawer();
}
@@ -332,7 +340,7 @@ odoo.define("web_responsive", function(require) {
Menu.prototype.events
),
- start: function() {
+ start: function () {
this.$menu_toggle = this.$(".o-menu-toggle");
return this._super.apply(this, arguments);
},
@@ -340,7 +348,7 @@ odoo.define("web_responsive", function(require) {
/**
* Hide menus for current app if you're in mobile
*/
- _hideMobileSubmenus: function() {
+ _hideMobileSubmenus: function () {
if (
config.device.isMobile &&
this.$menu_toggle.is(":visible") &&
@@ -355,7 +363,7 @@ odoo.define("web_responsive", function(require) {
*
* @param {ClickEvent} ev
*/
- _onClickMenuItem: function(ev) {
+ _onClickMenuItem: function (ev) {
ev.stopPropagation();
},
@@ -364,7 +372,7 @@ odoo.define("web_responsive", function(require) {
*
* @override
*/
- _updateMenuBrand: function() {
+ _updateMenuBrand: function () {
if (!config.device.isMobile) {
return this._super.apply(this, arguments);
}
@@ -377,10 +385,10 @@ odoo.define("web_responsive", function(require) {
*
* @override
*/
- _setState: function() {
+ _setState: function () {
this._super.apply(this, arguments);
if (config.device.isMobile) {
- _.map(this.status_information, value => {
+ _.map(this.status_information, (value) => {
value.fold = true;
});
}
@@ -389,7 +397,7 @@ odoo.define("web_responsive", function(require) {
// Sticky Column Selector
ListRenderer.include({
- _renderView: function() {
+ _renderView: function () {
const self = this;
return this._super.apply(this, arguments).then(() => {
const $col_selector = self.$el.find(
@@ -402,7 +410,7 @@ odoo.define("web_responsive", function(require) {
});
},
- _onToggleOptionalColumnDropdown: function(ev) {
+ _onToggleOptionalColumnDropdown: function (ev) {
// FIXME: For some strange reason the 'stopPropagation' call
// in the main method don't work. Invoking here the same method
// does the expected behavior... O_O!
@@ -420,17 +428,16 @@ odoo.define("web_responsive", function(require) {
*
* @override
*/
- _renderHeaderButtons: function() {
+ _renderHeaderButtons: function () {
const $buttons = this._super.apply(this, arguments);
if (
!config.device.isMobile ||
- !$buttons.is(":has(>:not(.o_invisible_modifier))")
+ $buttons.children("button:not(.o_invisible_modifier)").length <= 2
) {
return $buttons;
}
// $buttons must be appended by JS because all events are bound
- $buttons.addClass("dropdown-menu");
const $dropdown = $(
core.qweb.render("web_responsive.MenuStatusbarButtons")
);
@@ -439,18 +446,13 @@ odoo.define("web_responsive", function(require) {
},
});
- // Chatter Hide Composer
- Chatter.include({
- _openComposer: function(options) {
- if (
- this._composer &&
- options.isLog === this._composer.options.isLog &&
- this._composer.$el.is(":visible")
- ) {
- this._closeComposer(false);
- } else {
- this._super.apply(this, arguments);
+ CalendarRenderer.include({
+ _getFullCalendarOptions: function () {
+ var options = this._super.apply(this, arguments);
+ if (config.device.isMobile) {
+ options.views.dayGridMonth.columnHeaderFormat = "ddd";
}
+ return options;
},
});
@@ -459,7 +461,7 @@ odoo.define("web_responsive", function(require) {
/**
* @override
*/
- _appendController: function() {
+ _appendController: function () {
this._super.apply(this, arguments);
closeAppDrawer();
},
@@ -495,7 +497,7 @@ odoo.define("web_responsive", function(require) {
* @returns {keyEvent}
* Altered event object
*/
- _shiftPressed: function(keyEvent) {
+ _shiftPressed: function (keyEvent) {
const alt = keyEvent.altKey || keyEvent.key === "Alt",
newEvent = _.extend({}, keyEvent),
shift = keyEvent.shiftKey || keyEvent.key === "Shift";
@@ -509,11 +511,11 @@ odoo.define("web_responsive", function(require) {
return newEvent;
},
- _onKeyDown: function(keyDownEvent) {
+ _onKeyDown: function (keyDownEvent) {
return this._super(this._shiftPressed(keyDownEvent));
},
- _onKeyUp: function(keyUpEvent) {
+ _onKeyUp: function (keyUpEvent) {
return this._super(this._shiftPressed(keyUpEvent));
},
};
@@ -522,44 +524,106 @@ odoo.define("web_responsive", function(require) {
// `KeyboardNavigationMixin` is used upstream
AbstractWebClient.include(KeyboardNavigationShiftAltMixin);
- // DocumentViewer: Add support to maximize/minimize
- DocumentViewer.include({
- // Widget 'keydown' and 'keyup' events are only dispatched when
- // this.$el is active, but now the modal have buttons that can obtain
- // the focus. For this reason we now listen core events, that are
- // dispatched every time.
- events: _.extend(
- _.omit(DocumentViewer.prototype.events, ["keydown", "keyup"]),
- {
- "click .o_maximize_btn": "_onClickMaximize",
- "click .o_minimize_btn": "_onClickMinimize",
- "shown.bs.modal": "_onShownModal",
+ // TODO: use default odoo device context when it will be realized
+ const deviceContext = new Context({
+ isMobile: config.device.isMobile,
+ size_class: config.device.size_class,
+ SIZES: config.device.SIZES,
+ });
+ window.addEventListener(
+ "resize",
+ owl.utils.debounce(() => {
+ const state = deviceContext.state;
+ if (state.isMobile !== config.device.isMobile) {
+ state.isMobile = !state.isMobile;
}
- ),
-
- start: function() {
- core.bus.on("keydown", this, this._onKeydown);
- core.bus.on("keyup", this, this._onKeyUp);
- return this._super.apply(this, arguments);
- },
-
- destroy: function() {
- core.bus.off("keydown", this, this._onKeydown);
- core.bus.off("keyup", this, this._onKeyUp);
- this._super.apply(this, arguments);
- },
-
- _onShownModal: function() {
- // Disable auto-focus to allow to use controls in edit mode.
- // This only affects the active modal.
- // More info: https://stackoverflow.com/a/14795256
- $(document).off("focusin.modal");
- },
- _onClickMaximize: function() {
- this.$el.removeClass("o_responsive_document_viewer");
- },
- _onClickMinimize: function() {
- this.$el.addClass("o_responsive_document_viewer");
- },
+ if (state.size_class !== config.device.size_class) {
+ state.size_class = config.device.size_class;
+ }
+ }, 15)
+ );
+ // Patch attachment viewer to add min/max buttons capability
+ PatchableAttachmentViewer.patch("web_responsive.AttachmentViewer", (T) => {
+ class AttachmentViewerPatchResponsive extends T {
+ constructor() {
+ super(...arguments);
+ this.state = useState({
+ maximized: false,
+ });
+ }
+ // Disable auto-close to allow to use form in edit mode.
+ isCloseable() {
+ return false;
+ }
+ }
+ return AttachmentViewerPatchResponsive;
+ });
+ QWeb.components.AttachmentViewer = PatchableAttachmentViewer;
+
+ // Patch control panel to add states for mobile quick search
+ ControlPanel.patch("web_responsive.ControlPanelMobile", (T) => {
+ class ControlPanelPatchResponsive extends T {
+ constructor() {
+ super(...arguments);
+ this.state = useState({
+ mobileSearchMode: "",
+ });
+ this.device = useContext(deviceContext);
+ }
+ }
+ return ControlPanelPatchResponsive;
+ });
+ // Patch search panel to add functionality for mobile view
+ SearchPanel.patch("web_responsive.SearchPanelMobile", (T) => {
+ class SearchPanelPatchResponsive extends T {
+ constructor() {
+ super(...arguments);
+ this.state.mobileSearch = false;
+ this.device = useContext(deviceContext);
+ }
+ getActiveSummary() {
+ const selection = [];
+ for (const filter of this.model.get("sections")) {
+ let filterValues = [];
+ if (filter.type === "category") {
+ if (filter.activeValueId) {
+ const parentIds = this._getAncestorValueIds(
+ filter,
+ filter.activeValueId
+ );
+ filterValues = [...parentIds, filter.activeValueId].map(
+ (valueId) => filter.values.get(valueId).display_name
+ );
+ }
+ } else {
+ let values = [];
+ if (filter.groups) {
+ values = [
+ ...filter.groups.values().map((g) => g.values),
+ ].flat();
+ }
+ if (filter.values) {
+ values = [...filter.values.values()];
+ }
+ filterValues = values
+ .filter((v) => v.checked)
+ .map((v) => v.display_name);
+ }
+ if (filterValues.length) {
+ selection.push({
+ values: filterValues,
+ icon: filter.icon,
+ color: filter.color,
+ type: filter.type,
+ });
+ }
+ }
+ return selection;
+ }
+ }
+ return SearchPanelPatchResponsive;
});
+ return {
+ deviceContext: deviceContext,
+ };
});
diff --git a/web_responsive/static/src/xml/apps.xml b/web_responsive/static/src/xml/apps.xml
index cd3d0de20d97..d9e409853515 100644
--- a/web_responsive/static/src/xml/apps.xml
+++ b/web_responsive/static/src/xml/apps.xml
@@ -7,8 +7,9 @@
#menu_id=#{app.menuID}&action_id=#{app.actionID}
- false
+ false
diff --git a/web_responsive/static/src/xml/attachment_viewer.xml b/web_responsive/static/src/xml/attachment_viewer.xml
new file mode 100644
index 000000000000..928a1e4bf11c
--- /dev/null
+++ b/web_responsive/static/src/xml/attachment_viewer.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+ o_Dialog_{{dialog.record['constructor'].name}}
+
+
+
+
+ state.maximized ? 'o_AttachmentViewer_maximized' : ''
+
+
+
+
+
+
+
diff --git a/web_responsive/static/src/xml/control_panel.xml b/web_responsive/static/src/xml/control_panel.xml
new file mode 100644
index 000000000000..d7d0f9c34c6e
--- /dev/null
+++ b/web_responsive/static/src/xml/control_panel.xml
@@ -0,0 +1,146 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ device.isMobile and state.mobileSearchMode == 'quick' ? 'o_hidden' : ''
+
+
+ !device.isMobile
+ device.size_class == device.SIZES.MD ? 'o_search_options_hide_labels' : ''
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SEE RESULT
+
+
+
+
diff --git a/web_responsive/static/src/xml/discuss.xml b/web_responsive/static/src/xml/discuss.xml
index 2bf74b5a3031..0789dee01a2e 100644
--- a/web_responsive/static/src/xml/discuss.xml
+++ b/web_responsive/static/src/xml/discuss.xml
@@ -7,9 +7,10 @@
t-jquery=".o_mail_discuss_button_multi_user_channel"
t-operation="attributes"
>
- btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block d-none
+
+ btn btn-secondary o_mail_discuss_button_multi_user_channel d-md-block
+ d-none
+
diff --git a/web_responsive/static/src/xml/document_viewer.xml b/web_responsive/static/src/xml/document_viewer.xml
deleted file mode 100644
index ce135250146a..000000000000
--- a/web_responsive/static/src/xml/document_viewer.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-
-
-
- modal o_modal_fullscreen o_document_viewer o_responsive_document_viewer
- false
-
-
-
-
-
-
-
-
diff --git a/web_responsive/static/src/xml/form_view.xml b/web_responsive/static/src/xml/form_buttons.xml
similarity index 76%
rename from web_responsive/static/src/xml/form_view.xml
rename to web_responsive/static/src/xml/form_buttons.xml
index 91faab7e1874..2e860965bc12 100644
--- a/web_responsive/static/src/xml/form_view.xml
+++ b/web_responsive/static/src/xml/form_buttons.xml
@@ -98,40 +98,13 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+ Today
-
-
-
-
-
diff --git a/web_responsive/static/src/xml/navbar.xml b/web_responsive/static/src/xml/navbar.xml
index 6dd27cd9da9d..1d9654ab37fb 100644
--- a/web_responsive/static/src/xml/navbar.xml
+++ b/web_responsive/static/src/xml/navbar.xml
@@ -1,7 +1,7 @@
-
+
@@ -14,4 +14,4 @@
-
+
diff --git a/web_responsive/static/src/xml/search_panel.xml b/web_responsive/static/src/xml/search_panel.xml
new file mode 100644
index 000000000000..a1cc9db9bb6a
--- /dev/null
+++ b/web_responsive/static/src/xml/search_panel.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ SEE RESULT
+
+
+
+
diff --git a/web_responsive/views/assets.xml b/web_responsive/views/assets.xml
index d2d3c23b9757..291ef6705f5f 100644
--- a/web_responsive/views/assets.xml
+++ b/web_responsive/views/assets.xml
@@ -10,18 +10,28 @@
name="Open Mobile Assets"
inherit_id="web.assets_backend"
>
-
+
+
+
+
+
diff --git a/web_responsive/views/web.xml b/web_responsive/views/web.xml
index c8a742caefd8..487efedddd09 100644
--- a/web_responsive/views/web.xml
+++ b/web_responsive/views/web.xml
@@ -17,4 +17,16 @@
/>
+
+
+
+
+