[FIX] web: allow any levels in navbar menus
In 14.0 the menu items in the navbar sections menu could have any level.
Since the webclient refactoring landed in 15.0 0573aca this feature has
been unintentionnally limited to two levels.
More sub menus would simply not be displayed.
**Before this commit**
- Have a menu item with the following path:
`App/Menu/Group/Sub-group/Item`
- The `Sub-group` is displayed as an item. It is clickable but nothing happens.
- The `Item` is not displayed.
**After this commit**
Works properly as it should. See screenshots on the PR description.
closes odoo/odoo#121422
X-original-commit: 708d17ba3a9d12e153069ecb7ae6c8e3d6187dd0
Signed-off-by: Mathieu Duckerts-Antoine <dam@odoo.com>
Signed-off-by: Bruno Boi (boi) <boi@odoo.com>
Co-authored-by: Mathieu Duckerts-Antoine <dam@odoo.com>
This commit is contained in:
co-authored by
Mathieu Duckerts-Antoine
parent
3f17aa2fe2
commit
5de4c6dca1
@@ -7,11 +7,25 @@ import { registry } from "@web/core/registry";
|
||||
import { debounce } from "@web/core/utils/timing";
|
||||
import { ErrorHandler } from "@web/core/utils/components";
|
||||
|
||||
import { Component, onWillDestroy, onWillUnmount, useExternalListener, useEffect, useRef } from "@odoo/owl";
|
||||
import {
|
||||
Component,
|
||||
onWillDestroy,
|
||||
onWillUnmount,
|
||||
useExternalListener,
|
||||
useEffect,
|
||||
useRef,
|
||||
} from "@odoo/owl";
|
||||
const systrayRegistry = registry.category("systray");
|
||||
|
||||
const getBoundingClientRect = Element.prototype.getBoundingClientRect;
|
||||
|
||||
class NavBarDropdownItem extends DropdownItem {}
|
||||
NavBarDropdownItem.template = "web.NavBar.DropdownItem";
|
||||
NavBarDropdownItem.props = {
|
||||
...DropdownItem.props,
|
||||
style: { type: String, optional: true },
|
||||
};
|
||||
|
||||
export class MenuDropdown extends Dropdown {
|
||||
setup() {
|
||||
super.setup();
|
||||
@@ -201,5 +215,5 @@ export class NavBar extends Component {
|
||||
}
|
||||
}
|
||||
NavBar.template = "web.NavBar";
|
||||
NavBar.components = { Dropdown, DropdownItem, MenuDropdown, ErrorHandler };
|
||||
NavBar.components = { Dropdown, DropdownItem: NavBarDropdownItem, MenuDropdown, ErrorHandler };
|
||||
NavBar.props = {};
|
||||
|
||||
@@ -58,6 +58,14 @@
|
||||
border-radius: $o-navbar-dropdown-menu-border-radius;
|
||||
}
|
||||
|
||||
.dropdown-header.dropdown-menu_group {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.dropdown-item + .dropdown-header:not(.o_more_dropdown_section_group) {
|
||||
margin-top: .3em;
|
||||
}
|
||||
|
||||
.o_dropdown_menu_group_entry.dropdown-item {
|
||||
padding-left: $o-dropdown-hpadding * 1.5;
|
||||
|
||||
|
||||
@@ -95,6 +95,7 @@
|
||||
</t>
|
||||
<t t-call="web.NavBar.SectionsMenu.Dropdown.MenuSlot">
|
||||
<t t-set="items" t-value="section.childrenTree" />
|
||||
<t t-set="decalage" t-value="20" />
|
||||
</t>
|
||||
</MenuDropdown>
|
||||
</t>
|
||||
@@ -110,29 +111,34 @@
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="web.NavBar.DropdownItem" t-inherit="web.DropdownItem" t-inherit-mode="primary" owl="1">
|
||||
<xpath expr="//t[@t-tag]" position="attributes">
|
||||
<attribute name="t-att-style">props.style</attribute>
|
||||
</xpath>
|
||||
</t>
|
||||
|
||||
<t t-name="web.NavBar.SectionsMenu.Dropdown.MenuSlot" owl="1">
|
||||
<t t-set="style" t-value="`padding-left: ${decalage}px;`" />
|
||||
<t t-foreach="items" t-as="item" t-key="item.id">
|
||||
<DropdownItem
|
||||
t-if="!item.childrenTree.length"
|
||||
href="getMenuItemHref(item)"
|
||||
class="'dropdown-item'"
|
||||
class="{
|
||||
'dropdown-item': true,
|
||||
o_dropdown_menu_group_entry: decalage gt 20
|
||||
}"
|
||||
style="style"
|
||||
t-esc="item.name"
|
||||
dataset="{ menuXmlid: item.xmlid, section: item.id }"
|
||||
onSelected="() => this.onNavBarDropdownItemSelection(item)"
|
||||
/>
|
||||
|
||||
<t t-else="">
|
||||
<div class="dropdown-menu_group dropdown-header" t-esc="item.name" />
|
||||
<DropdownItem
|
||||
t-foreach="item.childrenTree"
|
||||
t-as="subItem"
|
||||
t-key="subItem.id"
|
||||
class="'o_dropdown_menu_group_entry dropdown-item'"
|
||||
href="getMenuItemHref(subItem)"
|
||||
t-esc="subItem.name"
|
||||
dataset="{ menuXmlid: subItem.xmlid, section: subItem.id }"
|
||||
onSelected="() => this.onNavBarDropdownItemSelection(subItem)"
|
||||
/>
|
||||
<div class="dropdown-menu_group dropdown-header" t-att-style="style" t-esc="item.name" />
|
||||
<t t-call="web.NavBar.SectionsMenu.Dropdown.MenuSlot">
|
||||
<t t-set="items" t-value="item.childrenTree" />
|
||||
<t t-set="decalage" t-value="decalage + 12" />
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
@@ -160,6 +166,7 @@
|
||||
/>
|
||||
<t t-call="web.NavBar.SectionsMenu.Dropdown.MenuSlot">
|
||||
<t t-set="items" t-value="section.childrenTree" />
|
||||
<t t-set="decalage" t-value="20" />
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
@@ -86,6 +86,43 @@ QUnit.test("href attribute on apps menu items", async (assert) => {
|
||||
assert.strictEqual(dropdownItem.getAttribute("href"), "#menu_id=1&action=339");
|
||||
});
|
||||
|
||||
QUnit.test("many sublevels in app menu items", async (assert) => {
|
||||
baseConfig.serverData.menus = {
|
||||
root: { id: "root", children: [1], name: "root", appID: "root" },
|
||||
1: { id: 1, children: [2], name: "My app", appID: 1 },
|
||||
2: { id: 2, children: [3], name: "My menu", appID: 1 },
|
||||
3: { id: 3, children: [4], name: "My submenu 1", appID: 1 },
|
||||
4: { id: 4, children: [5], name: "My submenu 2", appID: 1 },
|
||||
5: { id: 5, children: [6], name: "My submenu 3", appID: 1 },
|
||||
6: { id: 6, children: [7], name: "My submenu 4", appID: 1 },
|
||||
7: { id: 7, children: [8], name: "My submenu 5", appID: 1 },
|
||||
8: { id: 8, children: [9], name: "My submenu 6", appID: 1 },
|
||||
9: { id: 9, children: [], name: "My submenu 7", appID: 1 },
|
||||
};
|
||||
const env = await makeTestEnv(baseConfig);
|
||||
env.services.menu.setCurrentMenu(1);
|
||||
await mount(NavBar, target, { env });
|
||||
const firstSectionMenu = target.querySelector(".o_menu_sections .dropdown");
|
||||
await click(firstSectionMenu, "button.dropdown-toggle");
|
||||
const menuChildren = [...firstSectionMenu.querySelectorAll(".dropdown-menu > *")];
|
||||
assert.deepEqual(
|
||||
menuChildren.map((el) => ({
|
||||
text: el.textContent,
|
||||
paddingLeft: el.style.paddingLeft,
|
||||
tagName: el.tagName,
|
||||
})),
|
||||
[
|
||||
{ text: "My submenu 1", paddingLeft: "20px", tagName: "DIV" },
|
||||
{ text: "My submenu 2", paddingLeft: "32px", tagName: "DIV" },
|
||||
{ text: "My submenu 3", paddingLeft: "44px", tagName: "DIV" },
|
||||
{ text: "My submenu 4", paddingLeft: "56px", tagName: "DIV" },
|
||||
{ text: "My submenu 5", paddingLeft: "68px", tagName: "DIV" },
|
||||
{ text: "My submenu 6", paddingLeft: "80px", tagName: "DIV" },
|
||||
{ text: "My submenu 7", paddingLeft: "92px", tagName: "A" },
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("data-menu-xmlid attribute on AppsMenu items", async (assert) => {
|
||||
baseConfig.serverData.menus = {
|
||||
root: { id: "root", children: [1, 2], name: "root", appID: "root" },
|
||||
|
||||
Reference in New Issue
Block a user