From 976491e01272336bc34abcdcec2718f83e19c5fc Mon Sep 17 00:00:00 2001 From: Romeo Fragomeli Date: Fri, 19 May 2023 12:13:54 +0000 Subject: [PATCH] [IMP] web,*: add accordion menu component * = project,website On the small screen, the sub dropdown is a bit weird to positioning, so we use an accordion instead. We apply this change also on desktop to avoid split behavior between small screen and bigger screen and also to avoid duplicating code. Also, we have made some DOM/CSS change: * avoid reflow of the search bar menu by adding a min-width on the columns and a max-width on the input for custom groupbys and favorite filters * re-align caret vertically for accordion indicators * reword favorite edition items and add a tooltip * all menu items have the class `o_menu_item` closes odoo/odoo#122635 Note: DOM and some tests were adapted to reflect the change Task-id: 3276542 (Part of) Related: odoo/enterprise#41563 Signed-off-by: Pierre Paridans (app) --- .../tours/project_burndown_chart_tour.js | 6 - .../tests/tours/project_sharing_tour.js | 11 +- .../src/core/dropdown/accordion_item.js | 40 ++++++ .../src/core/dropdown/accordion_item.scss | 12 ++ .../src/core/dropdown/accordion_item.xml | 21 +++ .../core/dropdown/dropdown_navigation_hook.js | 28 +++- .../custom_favorite_item.js | 4 +- .../custom_favorite_item.xml | 13 +- .../custom_group_by_item.js | 4 +- .../custom_group_by_item.xml | 9 +- .../search/search_bar_menu/search_bar_menu.js | 2 + .../search_bar_menu/search_bar_menu.scss | 7 + .../search_bar_menu/search_bar_menu.xml | 16 +-- .../core/dropdown_accordion_item_tests.js | 123 ++++++++++++++++++ .../search/custom_favorite_item_tests.js | 14 +- .../search/custom_group_by_item_tests.js | 39 +++--- addons/web/static/tests/search/helpers.js | 14 +- .../tests/search/search_bar_menu_tests.js | 27 ++-- .../static/tests/views/graph_view_tests.js | 1 - .../tests/views/kanban/kanban_view_tests.js | 2 +- .../static/tests/views/pivot_view_tests.js | 122 ++++++++--------- .../webclient/actions/window_action_tests.js | 1 - .../static/tests/tours/page_manager.js | 7 +- 23 files changed, 370 insertions(+), 153 deletions(-) create mode 100644 addons/web/static/src/core/dropdown/accordion_item.js create mode 100644 addons/web/static/src/core/dropdown/accordion_item.scss create mode 100644 addons/web/static/src/core/dropdown/accordion_item.xml create mode 100644 addons/web/static/tests/core/dropdown_accordion_item_tests.js diff --git a/addons/project/static/tests/tours/project_burndown_chart_tour.js b/addons/project/static/tests/tours/project_burndown_chart_tour.js index ba38e91c718..65bfc208528 100644 --- a/addons/project/static/tests/tours/project_burndown_chart_tour.js +++ b/addons/project/static/tests/tours/project_burndown_chart_tour.js @@ -43,9 +43,6 @@ registry.category("web_tour.tours").add('burndown_chart_tour', { }, { content: 'Open the Date group by sub menu', trigger: '.o_group_by_menu button.o_menu_item:contains("Date")', - run: function () { - this.$anchor[0].dispatchEvent(new Event('mouseenter')); - }, }, { content: 'Click on the selected Date sub menu', trigger: '.o_group_by_menu button.o_menu_item:contains("Date") + * .dropdown-item.selected', @@ -61,9 +58,6 @@ registry.category("web_tour.tours").add('burndown_chart_tour', { }, { content: 'Open the Date filter sub menu', trigger: '.o_filter_menu button.o_menu_item:contains("Date")', - run: function () { - this.$anchor[0].dispatchEvent(new Event('mouseenter')); - }, }, { content: 'Click on the first Date filter sub menu', trigger: '.o_filter_menu .o_menu_item:contains("Date") + * .dropdown-item:first-child', diff --git a/addons/project/static/tests/tours/project_sharing_tour.js b/addons/project/static/tests/tours/project_sharing_tour.js index 7dbaaafa75b..f91acfaa846 100644 --- a/addons/project/static/tests/tours/project_sharing_tour.js +++ b/addons/project/static/tests/tours/project_sharing_tour.js @@ -71,8 +71,11 @@ const projectSharingSteps = [...stepUtils.goToAppSteps("project.menu_main_pm", ' trigger: 'iframe .o_group_by_menu .dropdown-item:first-child', content: 'click on the first item in the group by menu', }, { - trigger: 'iframe .o_favorite_menu .o_add_favorite > button', - content: 'click to "save current search" button in favorite menu', + trigger: 'iframe .o_favorite_menu .o_add_favorite', + content: 'open accordion "save current search" in favorite menu', +}, { + trigger: 'iframe .o_favorite_menu .o_accordion_values .o_save_favorite', + content: 'click to "save" button in favorite menu', }, { trigger: 'iframe .o_filter_menu .dropdown-item:first-child', content: 'click on the first item in the filter menu', @@ -80,8 +83,8 @@ const projectSharingSteps = [...stepUtils.goToAppSteps("project.menu_main_pm", ' trigger: 'iframe .o_group_by_menu .dropdown-item:first-child', content: 'click on the first item in the group by menu', }, { - trigger: 'iframe .o_favorite_menu .o_add_favorite > button', - content: 'click to "save current search" button in favorite menu', + trigger: 'iframe .o_favorite_menu .o_accordion_values .o_save_favorite', + content: 'click to "save" button in favorite menu', }, { trigger: 'iframe button.o_switch_view.o_list', content: 'Go to the list view', diff --git a/addons/web/static/src/core/dropdown/accordion_item.js b/addons/web/static/src/core/dropdown/accordion_item.js new file mode 100644 index 00000000000..7bb11cff806 --- /dev/null +++ b/addons/web/static/src/core/dropdown/accordion_item.js @@ -0,0 +1,40 @@ +/** @odoo-module **/ + +import { Component, onPatched, useState } from "@odoo/owl"; + +export const ACCORDION = Symbol("Accordion"); +export class AccordionItem extends Component { + static template = "web.AccordionItem"; + static components = {}; + static props = { + slots: { + type: Object, + shape: { + default: {}, + }, + }, + description: String, + selected: { + type: Boolean, + optional: true, + }, + class: { + type: String, + optional: true, + }, + }; + static defaultProps = { + class: "", + selected: false, + }; + + setup() { + this.state = useState({ + open: false, + }); + this.parentComponent = this.env[ACCORDION]; + onPatched(() => { + this.parentComponent?.accordionStateChanged?.(); + }); + } +} diff --git a/addons/web/static/src/core/dropdown/accordion_item.scss b/addons/web/static/src/core/dropdown/accordion_item.scss new file mode 100644 index 00000000000..7dc8ba479f5 --- /dev/null +++ b/addons/web/static/src/core/dropdown/accordion_item.scss @@ -0,0 +1,12 @@ +.o_accordion_toggle { + @include caret(); + + &.open { + @include caret('up'); + } + + &::after { + @include o-position-absolute($top: 0, $right: 0); + transform: translate(-0.6em, 0.8em) /*rtl:translate(0.6em, 0.8em) scaleX(-1)*/; + } +} diff --git a/addons/web/static/src/core/dropdown/accordion_item.xml b/addons/web/static/src/core/dropdown/accordion_item.xml new file mode 100644 index 00000000000..5f6418e6c51 --- /dev/null +++ b/addons/web/static/src/core/dropdown/accordion_item.xml @@ -0,0 +1,21 @@ + + + + +
+
+
+ +
diff --git a/addons/web/static/src/core/dropdown/dropdown_navigation_hook.js b/addons/web/static/src/core/dropdown/dropdown_navigation_hook.js index db4a3a8c26f..5f7e547aaba 100644 --- a/addons/web/static/src/core/dropdown/dropdown_navigation_hook.js +++ b/addons/web/static/src/core/dropdown/dropdown_navigation_hook.js @@ -5,7 +5,8 @@ import { browser } from "../browser/browser"; import { localization } from "@web/core/l10n/localization"; import { scrollTo } from "../utils/scrolling"; -import { useComponent, useEffect, useRef } from "@odoo/owl"; +import { useChildSubEnv, useComponent, useEffect, useRef } from "@odoo/owl"; +import { ACCORDION } from "@web/core/dropdown/accordion_item"; /** * @typedef {{ @@ -24,8 +25,12 @@ const ACTIVE_MENU_ELEMENT_CLASS = "focus"; const MENU_ELEMENTS_SELECTORS = [ ":scope > .dropdown-item", ":scope > .dropdown", + ":scope > .o_accordion > .dropdown-item", + ":scope > .o_accordion > .o_accordion_values > .dropdown-item", ":scope > .o_dropdown_container > .dropdown-item", ":scope > .o_dropdown_container > .dropdown", + ":scope > .o_dropdown_container > .o_accordion > .dropdown-item", + ":scope > .o_dropdown_container > .o_accordion > .o_accordion_values > .dropdown-item", ]; const NEXT_ACTIVE_INDEX_FNS = { FIRST: () => 0, @@ -70,7 +75,9 @@ export function useDropdownNavigation() { const menuRef = useRef("menuRef"); /** @type {MenuElement[]} */ let menuElements = []; - useEffect(() => { + + let cleanupMenuElements; + const refreshMenuElements = () => { if (!comp.state.open) { return; } @@ -157,7 +164,7 @@ export function useDropdownNavigation() { } addedListeners.push([navTarget, elementListeners]); } - return () => { + cleanupMenuElements = () => { menuElements = []; mouseSelectionActive = true; @@ -168,6 +175,21 @@ export function useDropdownNavigation() { } } }; + return () => cleanupMenuElements(); + }; + + useEffect(refreshMenuElements); + + // Set up nested accordion + // This is needed in order to keep the parent dropdown + // aware of the accordion menu elements when its state has changed. + useChildSubEnv({ + [ACCORDION]: { + accordionStateChanged: () => { + cleanupMenuElements?.(); + refreshMenuElements(); + }, + }, }); // Set up active menu element helpers -------------------------------------- diff --git a/addons/web/static/src/search/custom_favorite_item/custom_favorite_item.js b/addons/web/static/src/search/custom_favorite_item/custom_favorite_item.js index f8c0441e29a..a5ddeb1243b 100644 --- a/addons/web/static/src/search/custom_favorite_item/custom_favorite_item.js +++ b/addons/web/static/src/search/custom_favorite_item/custom_favorite_item.js @@ -1,6 +1,6 @@ /** @odoo-module **/ -import { Dropdown } from "@web/core/dropdown/dropdown"; +import { AccordionItem } from "@web/core/dropdown/accordion_item"; import { CheckBox } from "@web/core/checkbox/checkbox"; import { registry } from "@web/core/registry"; import { useService } from "@web/core/utils/hooks"; @@ -91,7 +91,7 @@ export class CustomFavoriteItem extends Component { } CustomFavoriteItem.template = "web.CustomFavoriteItem"; -CustomFavoriteItem.components = { CheckBox, Dropdown }; +CustomFavoriteItem.components = { CheckBox, AccordionItem }; CustomFavoriteItem.props = {}; favoriteMenuRegistry.add( "custom-favorite-item", diff --git a/addons/web/static/src/search/custom_favorite_item/custom_favorite_item.xml b/addons/web/static/src/search/custom_favorite_item/custom_favorite_item.xml index 04b53015f30..1471272e83f 100644 --- a/addons/web/static/src/search/custom_favorite_item/custom_favorite_item.xml +++ b/addons/web/static/src/search/custom_favorite_item/custom_favorite_item.xml @@ -2,10 +2,7 @@ - - - Save current search - +
- Use by default + Default filter - Share with all users + Shared
-
-
+
diff --git a/addons/web/static/src/search/custom_group_by_item/custom_group_by_item.js b/addons/web/static/src/search/custom_group_by_item/custom_group_by_item.js index 5f30af28902..0e328ba4927 100644 --- a/addons/web/static/src/search/custom_group_by_item/custom_group_by_item.js +++ b/addons/web/static/src/search/custom_group_by_item/custom_group_by_item.js @@ -1,6 +1,6 @@ /** @odoo-module **/ -import { Dropdown } from "@web/core/dropdown/dropdown"; +import { AccordionItem } from "@web/core/dropdown/accordion_item"; import { Component, useState } from "@odoo/owl"; @@ -14,7 +14,7 @@ export class CustomGroupByItem extends Component { } CustomGroupByItem.template = "web.CustomGroupByItem"; -CustomGroupByItem.components = { Dropdown }; +CustomGroupByItem.components = { AccordionItem }; CustomGroupByItem.props = { fields: Array, onAddCustomGroup: Function, diff --git a/addons/web/static/src/search/custom_group_by_item/custom_group_by_item.xml b/addons/web/static/src/search/custom_group_by_item/custom_group_by_item.xml index f2a202bf589..fb3b5770b61 100644 --- a/addons/web/static/src/search/custom_group_by_item/custom_group_by_item.xml +++ b/addons/web/static/src/search/custom_group_by_item/custom_group_by_item.xml @@ -1,12 +1,9 @@ - - - Add Custom Group - +
-
-
+
diff --git a/addons/web/static/src/search/search_bar_menu/search_bar_menu.js b/addons/web/static/src/search/search_bar_menu/search_bar_menu.js index b540f4092ec..79f2363e12b 100644 --- a/addons/web/static/src/search/search_bar_menu/search_bar_menu.js +++ b/addons/web/static/src/search/search_bar_menu/search_bar_menu.js @@ -8,6 +8,7 @@ import { DropdownItem } from "@web/core/dropdown/dropdown_item"; import { registry } from "@web/core/registry"; import { sortBy } from "@web/core/utils/arrays"; import { useBus, useService } from "@web/core/utils/hooks"; +import { AccordionItem } from "@web/core/dropdown/accordion_item"; import { CustomGroupByItem } from "@web/search/custom_group_by_item/custom_group_by_item"; import { SearchDropdownItem } from "@web/search/search_dropdown_item/search_dropdown_item"; import { FACET_ICONS, GROUPABLE_TYPES } from "@web/search/utils/misc"; @@ -23,6 +24,7 @@ export class SearchBarMenu extends Component { DropdownItem, SearchDropdownItem, CustomGroupByItem, + AccordionItem, }; static props = { slots: { diff --git a/addons/web/static/src/search/search_bar_menu/search_bar_menu.scss b/addons/web/static/src/search/search_bar_menu/search_bar_menu.scss index a5d076f9ca5..a3c9165cd10 100644 --- a/addons/web/static/src/search/search_bar_menu/search_bar_menu.scss +++ b/addons/web/static/src/search/search_bar_menu/search_bar_menu.scss @@ -3,5 +3,12 @@ .o_search_bar_menu { .o_dropdown_container { border-color: $dropdown-divider-bg !important; + min-width: 220px; + } + + .o_accordion_values .o_input { + max-width: 17ch; + text-overflow: ellipsis; + white-space: nowrap; } } \ No newline at end of file diff --git a/addons/web/static/src/search/search_bar_menu/search_bar_menu.xml b/addons/web/static/src/search/search_bar_menu/search_bar_menu.xml index 4e7c39791db..fff083ad939 100644 --- a/addons/web/static/src/search/search_bar_menu/search_bar_menu.xml +++ b/addons/web/static/src/search/search_bar_menu/search_bar_menu.xml @@ -22,10 +22,7 @@