From 96e3782a146249fede5130c3e048cfdf5adadcdd Mon Sep 17 00:00:00 2001 From: Aaron Bohy Date: Fri, 1 Mar 2024 15:53:44 +0100 Subject: [PATCH] [FIX] web: ButtonBox: do not display More for one button Before this commit, it could happen that the More dropdown was displayed, but it only contained a single stat button. This isn't what we want, as that single button could simply be displayed instead of the More dropdown toggler. Task 3778382 closes odoo/odoo#156241 Related: odoo/enterprise#58565 Signed-off-by: Lucas Perais (lpe) --- .../src/views/form/button_box/button_box.js | 35 ++++++++++--------- .../src/views/form/button_box/button_box.xml | 5 +-- .../tests/mobile/views/form_view_tests.js | 35 +++++++++++++++++++ .../tests/views/form/form_view_tests.js | 6 ++-- 4 files changed, 58 insertions(+), 23 deletions(-) diff --git a/addons/web/static/src/views/form/button_box/button_box.js b/addons/web/static/src/views/form/button_box/button_box.js index 8e377be6b4c..ee3cb2dfb4c 100644 --- a/addons/web/static/src/views/form/button_box/button_box.js +++ b/addons/web/static/src/views/form/button_box/button_box.js @@ -4,27 +4,30 @@ import { useService } from "@web/core/utils/hooks"; import { Dropdown } from "@web/core/dropdown/dropdown"; import { DropdownItem } from "@web/core/dropdown/dropdown_item"; -import { Component } from "@odoo/owl"; +import { Component, onWillRender } from "@odoo/owl"; export class ButtonBox extends Component { setup() { const ui = useService("ui"); - this.getMaxButtons = () => [2, 3, 4, 6, 3, 4, 7][ui.size] || 7; + onWillRender(() => { + const maxVisibleButtons = [3, 4, 5, 7, 4, 5, 8][ui.size] || 8; + const allVisibleButtons = Object.entries(this.props.slots) + .filter(([_, slot]) => this.isSlotVisible(slot)) + .map(([slotName]) => slotName); + if (allVisibleButtons.length <= maxVisibleButtons) { + this.visibleButtons = allVisibleButtons; + this.additionalButtons = []; + this.isFull = allVisibleButtons.length === maxVisibleButtons; + } else { + // -1 for "More" dropdown + this.visibleButtons = allVisibleButtons.slice(0, maxVisibleButtons - 1); + this.additionalButtons = allVisibleButtons.slice(maxVisibleButtons - 1); + this.isFull = true; + } + }); } - getButtons() { - const maxVisibleButtons = this.getMaxButtons(); - const visible = []; - const additional = []; - for (const [slotName, slot] of Object.entries(this.props.slots)) { - if (!("isVisible" in slot) || slot.isVisible) { - if (visible.length >= maxVisibleButtons) { - additional.push(slotName); - } else { - visible.push(slotName); - } - } - } - return { visible, additional }; + isSlotVisible(slot) { + return !("isVisible" in slot) || slot.isVisible; } } ButtonBox.template = "web.Form.ButtonBox"; diff --git a/addons/web/static/src/views/form/button_box/button_box.xml b/addons/web/static/src/views/form/button_box/button_box.xml index 0bb15b230da..aa1dcb575a2 100644 --- a/addons/web/static/src/views/form/button_box/button_box.xml +++ b/addons/web/static/src/views/form/button_box/button_box.xml @@ -2,10 +2,7 @@ - - - -
+
diff --git a/addons/web/static/tests/mobile/views/form_view_tests.js b/addons/web/static/tests/mobile/views/form_view_tests.js index 29e16ca15b4..4dbc1949ee2 100644 --- a/addons/web/static/tests/mobile/views/form_view_tests.js +++ b/addons/web/static/tests/mobile/views/form_view_tests.js @@ -28,6 +28,7 @@ QUnit.module("Mobile Views", ({ beforeEach }) => { fields: { display_name: { type: "char", string: "Display Name" }, trululu: { type: "many2one", string: "Trululu", relation: "partner" }, + boolean: { type: "boolean", string: "Bool" }, }, records: [ { id: 1, display_name: "first record", trululu: 4 }, @@ -479,4 +480,38 @@ QUnit.module("Mobile Views", ({ beforeEach }) => { await nextTick(); assert.verifySteps(["post"]); }); + + QUnit.test("button box with 3/4 buttons (close to threshold)", async (assert) => { + await makeView({ + type: "form", + resModel: "partner", + serverData, + arch: ` +
+ +
+ + + + +
+ +
+
`, + resId: 2, + }); + + // 3 buttons to display -> no "More" dropdown + assert.containsNone(fixture, ".o_field_widget[name=boolean] input:checked"); + assert.containsN(fixture, ".o-form-buttonbox > .oe_stat_button", 3); + assert.containsNone(fixture, ".o-form-buttonbox .o_button_more"); + + // 4 buttons to display -> 2 buttons visible + 2 inside the "More" dropdown + await click(fixture.querySelector(".o_field_widget[name=boolean] input")); + assert.containsN(fixture, ".o-form-buttonbox > .oe_stat_button", 3); + assert.containsOnce(fixture, ".o-form-buttonbox .oe_stat_button .o_button_more"); + + await click(fixture.querySelector(".o_button_more")); + assert.containsN(fixture, ".o_dropdown_more .oe_stat_button", 2); + }); }); diff --git a/addons/web/static/tests/views/form/form_view_tests.js b/addons/web/static/tests/views/form/form_view_tests.js index 8461d02f87d..de8260f41cc 100644 --- a/addons/web/static/tests/views/form/form_view_tests.js +++ b/addons/web/static/tests/views/form/form_view_tests.js @@ -430,7 +430,7 @@ QUnit.module("Views", (hooks) => { }); return { bus: new EventBus(), - size: 9, + size: 6, isSmall: false, }; }, @@ -8391,7 +8391,7 @@ QUnit.module("Views", (hooks) => { }); QUnit.test("correct amount of buttons", async function (assert) { - let screenSize = 7; + let screenSize = 6; const uiService = { start(env) { Object.defineProperty(env, "isSmall", { @@ -8445,7 +8445,7 @@ QUnit.module("Views", (hooks) => { await assertFormContainsNButtonsWithSizeClass(0, 2); await assertFormContainsNButtonsWithSizeClass(1, 3); await assertFormContainsNButtonsWithSizeClass(2, 4); - await assertFormContainsNButtonsWithSizeClass(3, 6); + await assertFormContainsNButtonsWithSizeClass(3, 7); await assertFormContainsNButtonsWithSizeClass(4, 3); await assertFormContainsNButtonsWithSizeClass(5, 4); await assertFormContainsNButtonsWithSizeClass(6, 7);