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 @@
-
+
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 @@
-
-
-
-
+
@@ -39,7 +36,7 @@
/>
-
+
- Add Custom Filter
+
@@ -70,10 +67,7 @@
-
-
-
-
+
@@ -87,7 +81,7 @@
/>
-
+