From 2176cadebdee10989e686d34f593a80126f32f9e Mon Sep 17 00:00:00 2001 From: Aaron Bohy Date: Mon, 18 Mar 2024 12:20:43 +0100 Subject: [PATCH] [FIX] web: multi level grouped list: correct pager inside groups Have a list view with multiple groupbys and a lot of records to have pagers displayed. Open a group (first level). The pager of the group uses the number of records instead of number of (inner) groups as total. This commit fixes the issue. The pager now correctly allows to navigate through inner groups. closes odoo/odoo#157995 Signed-off-by: Francois Georis (fge) --- .../static/src/views/list/list_renderer.js | 9 +- .../web/static/tests/views/list_view_tests.js | 91 ++++++++++++------- 2 files changed, 64 insertions(+), 36 deletions(-) diff --git a/addons/web/static/src/views/list/list_renderer.js b/addons/web/static/src/views/list/list_renderer.js index 12d8b047259..f306137eaa5 100644 --- a/addons/web/static/src/views/list/list_renderer.js +++ b/addons/web/static/src/views/list/list_renderer.js @@ -1029,7 +1029,7 @@ export class ListRenderer extends Component { if (this.props.onOpenFormView) { colspan++; } - return colspan + return colspan; } getGroupPagerProps(group) { @@ -1037,7 +1037,7 @@ export class ListRenderer extends Component { return { offset: list.offset, limit: list.limit, - total: group.count, + total: list.isGrouped ? list.count : group.count, onUpdate: async ({ offset, limit }) => { await list.load({ limit, offset }); this.render(true); @@ -1778,7 +1778,10 @@ export class ListRenderer extends Component { } showGroupPager(group) { - return !group.isFolded && group.list.limit < group.count; + return ( + !group.isFolded && + group.list.limit < (group.list.isGrouped ? group.list.count : group.count) + ); } /** diff --git a/addons/web/static/tests/views/list_view_tests.js b/addons/web/static/tests/views/list_view_tests.js index cdc111b166a..331e16c3e83 100644 --- a/addons/web/static/tests/views/list_view_tests.js +++ b/addons/web/static/tests/views/list_view_tests.js @@ -2159,11 +2159,12 @@ QUnit.module("Views", (hooks) => { }); assert.strictEqual( - target.querySelector(".o_group_header th").getAttribute("colspan"), "2" + target.querySelector(".o_group_header th").getAttribute("colspan"), + "2" ); assert.strictEqual( target.querySelector(".o_group_header th:last-child").getAttribute("colspan"), - "2", + "2" ); } ); @@ -2186,11 +2187,12 @@ QUnit.module("Views", (hooks) => { }); assert.strictEqual( - target.querySelector(".o_group_header th").getAttribute("colspan"), "2" + target.querySelector(".o_group_header th").getAttribute("colspan"), + "2" ); assert.strictEqual( target.querySelector(".o_group_header th:last-child").getAttribute("colspan"), - "1", + "1" ); } ); @@ -6808,6 +6810,23 @@ QUnit.module("Views", (hooks) => { ); }); + QUnit.test("multi-level grouped list, pager inside a group", async function (assert) { + serverData.models.foo.records.forEach((r) => (r.bar = true)); + await makeView({ + type: "list", + resModel: "foo", + serverData, + arch: '', + groupBy: ["bar", "foo"], + }); + + assert.containsOnce(target, ".o_group_header"); + + await click(target.querySelector(".o_group_header")); + assert.containsN(target, ".o_group_header", 4); + assert.containsNone(target, ".o_group_header:first-of-type .o_group_name .o_pager"); + }); + QUnit.test("count_limit attrs set in arch", async function (assert) { let expectedCountLimit = 4; await makeView({ @@ -11563,7 +11582,10 @@ QUnit.module("Views", (hooks) => { `, mockRPC(route, args) { if (args.method === "write") { - assert.deepEqual(args.args, [[1, 2], { date_start: "2021-04-01", date_end: "2017-01-26"}]); + assert.deepEqual(args.args, [ + [1, 2], + { date_start: "2021-04-01", date_end: "2017-01-26" }, + ]); } }, }); @@ -20025,36 +20047,39 @@ QUnit.module("Views", (hooks) => { } ); - QUnit.test("onchange should only be called once after pressing enter on a field", async function (assert) { - serverData.models.foo.onchanges = { - foo(record) { - if (record.foo) { - record.int_field = 1; - } - }, - }; - await makeView({ - type: "list", - resModel: "foo", - serverData, - arch: ` + QUnit.test( + "onchange should only be called once after pressing enter on a field", + async function (assert) { + serverData.models.foo.onchanges = { + foo(record) { + if (record.foo) { + record.int_field = 1; + } + }, + }; + await makeView({ + type: "list", + resModel: "foo", + serverData, + arch: ` `, - async mockRPC(_, { method }) { - if (method === "onchange") { - assert.step(method); - } - }, - }); - await click(target.querySelector(".o_data_cell")); - target.querySelector(".o_field_widget[name=foo] input").value = "1"; - await triggerEvents(target, ".o_field_widget[name=foo] input", [ - ["keydown", { key: "Enter" }], - ["change"], - ]); - await nextTick(); - assert.verifySteps(["onchange"], "There should only be one onchange call"); - }); + async mockRPC(_, { method }) { + if (method === "onchange") { + assert.step(method); + } + }, + }); + await click(target.querySelector(".o_data_cell")); + target.querySelector(".o_field_widget[name=foo] input").value = "1"; + await triggerEvents(target, ".o_field_widget[name=foo] input", [ + ["keydown", { key: "Enter" }], + ["change"], + ]); + await nextTick(); + assert.verifySteps(["onchange"], "There should only be one onchange call"); + } + ); });