From 43953c2a4d45c2bbb63c4e04bca496eb09ae8284 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Wed, 24 Aug 2022 09:10:51 +0000 Subject: [PATCH] [IMP] web: allow to have nested buttons in form header Before this revision, it wasn't possible, in the form header, to organize buttons in nodes. If you attempted to do so, the buttons were not appearing. e.g. for the below form ```xml
``` Before this revision, the buttons 2 and 3 were not appearing. Adding this possibility can allow simpler inheritage, for instance by organizing buttons in sections and then the inherited view can add buttons directly within the right section, using a selector targetting the section. It also allows to restrict a button to users having 2 groups. e.g. ```xml ``` If you want to restrict the button `action_done` to users having both `sale.group_auto_done_setting` and `sales_team.group_sale_manager`, you cannot put both groups on the same node, because otherwise it's an OR connection, not an AND. `groups="sale.group_auto_done_setting,sales_team.group_sale_manager"` means "users has `sale.group_auto_done_setting` or `sales_team.group_sale_manager`", not AND. So, the only possibility to restrict a button to two groups with an AND connection is to restrict the button to a group and nest the button inside a block restricted to the second group. The above example is an actual example/need from the existing code. But, as this possibility wasn't there before this revision, they achieved the goal by using the `groups_id` feature: ```xml sale.order.form sale.order ``` So they had to use an inerited view for that purpose only to restrict the button to two groups. It's a work-around. It is much simpler to allow to have nested buttons in the header of the form. closes odoo/odoo#98551 Related: odoo/enterprise#30643 Related: odoo/upgrade#3812 Signed-off-by: Denis Ledoux (dle) --- .../src/legacy/js/views/form/form_renderer.js | 9 ++++-- .../static/tests/legacy/views/form_tests.js | 30 +++++++++++++++++++ .../tests/views/form/form_view_tests.js | 26 ++++++++++++++++ 3 files changed, 63 insertions(+), 2 deletions(-) diff --git a/addons/web/static/src/legacy/js/views/form/form_renderer.js b/addons/web/static/src/legacy/js/views/form/form_renderer.js index af5b4b3d69e..fcee6d0ee58 100644 --- a/addons/web/static/src/legacy/js/views/form/form_renderer.js +++ b/addons/web/static/src/legacy/js/views/form/form_renderer.js @@ -652,14 +652,19 @@ var FormRenderer = BasicRenderer.extend({ _renderHeaderButtons: function (node) { var self = this; var buttons = []; - _.each(node.children, function (child) { + var children = [...node.children]; + while(children.length) { + var child = children.shift(); if (child.tag === 'button') { buttons.push(self._renderHeaderButton(child)); } if (child.tag === 'widget') { buttons.push(self._renderTagWidget(child)); } - }); + if (child.children){ + children.push(...child.children); + } + } return this._renderStatusbarButtons(buttons); }, /** diff --git a/addons/web/static/tests/legacy/views/form_tests.js b/addons/web/static/tests/legacy/views/form_tests.js index d3504e29266..efb1a21f22c 100644 --- a/addons/web/static/tests/legacy/views/form_tests.js +++ b/addons/web/static/tests/legacy/views/form_tests.js @@ -2209,6 +2209,36 @@ QUnit.module('LegacyViews', { form.destroy(); }); + QUnit.test("nested buttons in form view header", async function (assert) { + assert.expect(4); + + var form = await createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: + '
' + + '
' + + '
' + + '
', + res_id: 2, + }); + + var buttons = form.$('.o_form_statusbar button'); + assert.hasAttrValue(buttons[0], 'name', '0'); + assert.hasAttrValue(buttons[1], 'name', '1'); + assert.hasAttrValue(buttons[2], 'name', '2'); + assert.hasAttrValue(buttons[3], 'name', '3'); + + form.destroy(); + }); + QUnit.test('button in form view and long willStart', async function (assert) { assert.expect(6); 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 fa47aba501b..1fe2e0c0878 100644 --- a/addons/web/static/tests/views/form/form_view_tests.js +++ b/addons/web/static/tests/views/form/form_view_tests.js @@ -2644,6 +2644,32 @@ QUnit.module("Views", (hooks) => { ); }); + QUnit.test("nested buttons in form view header", async function (assert) { + await makeView({ + type: "form", + resModel: "partner", + serverData, + arch: ` +
+
+
+
`, + resId: 2, + }); + + const buttons = target.querySelectorAll('.o_form_statusbar button'); + assert.strictEqual(buttons[0].attributes.name.textContent, "0"); + assert.strictEqual(buttons[1].attributes.name.textContent, "1"); + assert.strictEqual(buttons[2].attributes.name.textContent, "2"); + assert.strictEqual(buttons[3].attributes.name.textContent, "3"); + }); + QUnit.test("button in form view and long willStart", async function (assert) { const mockedActionService = { start() {