From df52c0297f3eea7767b81fe2a6f5704cc843cd76 Mon Sep 17 00:00:00 2001 From: Bruno Boi Date: Thu, 18 Aug 2022 12:47:59 +0000 Subject: [PATCH] [FIX] web: click on ViewButton will close parent Dropdown # Issue A Dropdown is not closed when a child ViewButton is clicked. # Solution Make the ViewButton close the Dropdown. # Note Usually, a dropdown is closed by a DropdownItem component. This is not the case here, because the clicks on view buttons are stopped (see the view button template). Letting them bubble would close their eventual parent dropdown, but it brings other issues (e.g. for a view button in a list renderer's group row, or view buttons that could get interpreted as action links under some conditions ). Instead of looking in the env to close the parent dropdown if any, an alternative solution would be to extend the ViewButton component, wrap it in a DropdownItem component, and reroute its `onClick` handler to the DropdownItem's `onSelected` prop. But this requires some preparation at the form compiler level (when compiling the status bar buttons), which we thought was overengineering at the time of writing. closes odoo/odoo#98399 Signed-off-by: Samuel Degueldre --- .../src/views/view_button/view_button.js | 6 +++ .../tests/views/view_button_hook_tests.js | 51 ++++++++++++++++++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/addons/web/static/src/views/view_button/view_button.js b/addons/web/static/src/views/view_button/view_button.js index 2c31d2354a4..b88eb15fd03 100644 --- a/addons/web/static/src/views/view_button/view_button.js +++ b/addons/web/static/src/views/view_button/view_button.js @@ -1,5 +1,6 @@ /** @odoo-module */ +import { DROPDOWN } from "@web/core/dropdown/dropdown"; import { debounce as debounceFn } from "@web/core/utils/timing"; const { Component } = owl; @@ -84,6 +85,11 @@ export class ViewButton extends Component { this.env.onClickViewButton({ clickParams: this.clickParams, record: this.props.record, + beforeExecute: () => { + if (this.env[DROPDOWN]) { + this.env[DROPDOWN].close(); + } + }, }); } diff --git a/addons/web/static/tests/views/view_button_hook_tests.js b/addons/web/static/tests/views/view_button_hook_tests.js index efd7d38926c..82a8167601e 100644 --- a/addons/web/static/tests/views/view_button_hook_tests.js +++ b/addons/web/static/tests/views/view_button_hook_tests.js @@ -1,11 +1,14 @@ /** @odoo-module */ +import { ViewButton } from "@web/views/view_button/view_button"; import { useViewButtons } from "@web/views/view_button/view_button_hook"; import { setupViewRegistries } from "./helpers"; -import { click, getFixture } from "../helpers/utils"; +import { click, getFixture, mount } from "../helpers/utils"; import { makeTestEnv } from "../helpers/mock_env"; import { registry } from "@web/core/registry"; +import { Dropdown } from "@web/core/dropdown/dropdown"; +import { DropdownItem } from "@web/core/dropdown/dropdown_item"; -const { useRef, mount, Component, xml } = owl; +const { useRef, Component, xml } = owl; QUnit.module("UseViewButton tests", (hooks) => { let target; @@ -76,4 +79,48 @@ QUnit.module("UseViewButton tests", (hooks) => { await click(target, ".myComponent"); assert.verifySteps(["beforeExecuteAction on handler"]); }); + + QUnit.test("ViewButton clicked in Dropdown close the Dropdown", async (assert) => { + registry.category("services").add( + "action", + { + start() { + return { + doActionButton() { + assert.step("doActionButton"); + }, + }; + }, + }, + { force: true } + ); + + class MyComponent extends Component { + setup() { + const rootRef = useRef("root"); + useViewButtons({}, rootRef); + } + } + MyComponent.components = { Dropdown, DropdownItem, ViewButton }; + MyComponent.template = xml` +
+ + dropdown + + + + +
+ `; + + const env = await makeTestEnv(); + await mount(MyComponent, target, { env }); + + await click(target, ".dropdown-toggle"); + assert.containsOnce(target, ".dropdown-menu"); + + await click(target, "a[type=action]"); + assert.verifySteps(["doActionButton"]); + assert.containsNone(target, ".dropdown-menu"); + }); });