diff --git a/addons/web/static/src/views/relational_model.js b/addons/web/static/src/views/relational_model.js index 977db751896..0d3918a18e2 100644 --- a/addons/web/static/src/views/relational_model.js +++ b/addons/web/static/src/views/relational_model.js @@ -1921,7 +1921,15 @@ export class DynamicRecordList extends DynamicList { for (const record of records) { this.removeRecord(record); } - await this._adjustOffset(); + const hasReloaded = await this._adjustOffset(); + if (resIds.length > 0 && !hasReloaded) { + // If the list hasn't been reloaded, force a reload if there are + // deleted records. + // NOTE that we don't rely on the reload logic of the _adjustOffset + // because we don't want the offset to be adjusted. Offset adjustment + // should only be done when at the last page. + await this.load(); + } return resIds; } @@ -2015,13 +2023,15 @@ export class DynamicRecordList extends DynamicList { /** * Reload the model if more records should appear on the current page. * - * @returns {Promise} + * @returns {Promise} Resolves to true if the model reloaded. */ async _adjustOffset() { if (this.offset && !this.records.length) { this.offset = Math.max(this.offset - this.limit, 0); await this.load(); + return true; } + return false; } /** diff --git a/addons/web/static/tests/views/list_view_tests.js b/addons/web/static/tests/views/list_view_tests.js index 935c88e521a..6cf46d1da7f 100644 --- a/addons/web/static/tests/views/list_view_tests.js +++ b/addons/web/static/tests/views/list_view_tests.js @@ -11553,7 +11553,7 @@ QUnit.module("Views", (hooks) => { QUnit.test( "grouped list view move to previous page of group when all records from last page deleted", async function (assert) { - assert.expect(9); + assert.expect(10); let checkSearchRead = false; await makeView({ @@ -11610,6 +11610,63 @@ QUnit.module("Views", (hooks) => { "", "should be on first page now" ); + assert.containsN(target, ".o_data_row", 2); + } + ); + + QUnit.test( + "grouped list view move to next page when all records from the current page deleted", + async function (assert) { + serverData.models.foo.records = [1, 2, 3, 4, 5, 6] + .map((i) => ({ + id: i, + foo: `yop${i}`, + m2o: 1, + })) + .concat([{ id: 7, foo: "blip", m2o: 2 }]); + + await makeView({ + type: "list", + resModel: "foo", + serverData, + arch: '', + actionMenus: {}, + groupBy: ["m2o"], + }); + + assert.strictEqual( + target.querySelector("tr.o_group_header:first-child th").textContent.trim(), + "Value 1 (6)" + ); + assert.strictEqual( + target.querySelector("tr.o_group_header:nth-child(2) th").textContent.trim(), + "Value 2 (1)" + ); + const firstGroup = target.querySelector("tr.o_group_header:first-child"); + await click(firstGroup); + assert.deepEqual(getPagerValue(firstGroup), [1, 2]); + assert.strictEqual(getPagerLimit(firstGroup), 6); + + // delete all records from current page + await click(target.querySelector("thead .o_list_record_selector input")); + await click(target, ".o_cp_action_menus .dropdown-toggle"); + await click( + [...target.querySelectorAll(".dropdown-item")].filter( + (el) => el.innerText === "Delete" + )[0] + ); + await click(target, ".modal .btn-primary"); + + const groupLabel = "Value 1 (4)"; + const pagerText = "1-2 / 4"; + assert.strictEqual( + target.querySelector(".o_group_header:nth-child(1) .o_group_name").textContent, + `${groupLabel} ${pagerText}` + ); + assert.deepEqual( + [...target.querySelectorAll(".o_data_row")].map((row) => row.textContent), + ["yop3", "yop4"] + ); } );