[FIX] web: pager: count_limit: fetch count on previous

For performance reasons, we added a feature that allows to limit
the search_count done when fetching records in list and kanban
views, to display on the right side of the pager [1][2]. However,
the page previous case wasn't correctly handled when we had a
limited count. When doing page, we need to know the total number of
records to compute the offset. Before this commit, we went to the
last page, which wasn't really the last page (because we sent a
wrong offset), which can be misleading for users. With the commit,
we force a search_count when doing page previous on the first page.

[1] 6acfad2651
[2] 699215ec9a71b8c9b6a53fe96e924a400d216729

Task 3162026

closes odoo/odoo#113134

X-original-commit: cefff0dcd5b3b1120b215e6af28d678c7ec34d52
Signed-off-by: Pierre Paridans (app) <app@odoo.com>
This commit is contained in:
Aaron Bohy
2023-02-20 14:50:47 +01:00
parent 07aa7b0af0
commit 00e76a7da0
4 changed files with 102 additions and 0 deletions
@@ -64,6 +64,10 @@ export class Pager extends Component {
async navigate(direction) {
let minimum = this.props.offset + this.props.limit * direction;
let total = this.props.total;
if (this.props.updateTotal && minimum < 0) {
// we must know the real total to be able to loop by doing "previous"
total = await this.props.updateTotal();
}
if (minimum >= total) {
if (!this.props.updateTotal) {
// only loop forward if we know the real total, otherwise let the minimum
@@ -382,4 +382,30 @@ QUnit.module("Components", ({ beforeEach }) => {
assert.strictEqual(target.querySelector(".o_pager_limit").innerText, "10+");
assert.hasClass(target.querySelector(".o_pager_limit"), "o_pager_limit_fetch");
});
QUnit.test("updateTotal props: click previous", async function (assert) {
const pager = await makePager({
offset: 0,
limit: 5,
total: 10,
onUpdate(data) {
pager.updateProps(data);
},
async updateTotal() {
const total = 23;
pager.updateProps({ total, updateTotal: undefined });
return total;
},
});
assert.strictEqual(target.querySelector(".o_pager_value").innerText, "1-5");
assert.strictEqual(target.querySelector(".o_pager_limit").innerText, "10+");
assert.hasClass(target.querySelector(".o_pager_limit"), "o_pager_limit_fetch");
await click(target, ".o_pager_previous");
assert.strictEqual(target.querySelector(".o_pager_value").innerText, "21-23");
assert.strictEqual(target.querySelector(".o_pager_limit").innerText, "23");
assert.doesNotHaveClass(target.querySelector(".o_pager_limit"), "o_pager_limit_fetch");
});
});
@@ -1342,6 +1342,47 @@ QUnit.module("Views", (hooks) => {
assert.verifySteps(["search_count"]);
});
QUnit.test(
"pager, ungrouped, deleting all records from last page should move to previous page",
async (assert) => {
patchDialog((_cls, props) => {
assert.step("open-dialog");
props.confirm();
});
await makeView({
type: "kanban",
resModel: "partner",
serverData,
arch: `<kanban limit="3">
<templates>
<t t-name="kanban-box">
<div>
<div><a role="menuitem" type="delete" class="dropdown-item">Delete</a></div>
<field name="foo"/>
</div>
</t>
</templates>
</kanban>`,
});
assert.deepEqual(getPagerValue(target), [1, 3]);
assert.strictEqual(getPagerLimit(target), 4);
// move to next page
await pagerNext(target);
assert.deepEqual(getPagerValue(target), [4, 4]);
// delete a record
await click(target, ".o_kanban_record a");
assert.verifySteps(["open-dialog"]);
assert.deepEqual(getPagerValue(target), [1, 3]);
assert.strictEqual(getPagerLimit(target), 3);
}
);
QUnit.test("pager, update calls onUpdatedPager before the render", async (assert) => {
assert.expect(8);
@@ -5752,6 +5752,37 @@ QUnit.module("Views", (hooks) => {
assert.verifySteps(["web_search_read"]);
});
QUnit.test("pager, ungrouped, with count limit reached, click previous", async (assert) => {
patchWithCleanup(DynamicRecordList, { WEB_SEARCH_READ_COUNT_LIMIT: 3 });
serverData.models.foo.records.push({ id: 5, bar: true, foo: "xxx" });
let expectedCountLimit = 4;
await makeView({
type: "list",
resModel: "foo",
serverData,
arch: '<tree limit="2"><field name="foo"/><field name="bar"/></tree>',
mockRPC(route, args) {
assert.step(args.method);
if (args.method === "web_search_read") {
assert.strictEqual(args.kwargs.count_limit, expectedCountLimit);
}
},
});
assert.containsN(target, ".o_data_row", 2);
assert.strictEqual(target.querySelector(".o_pager_value").innerText, "1-2");
assert.strictEqual(target.querySelector(".o_pager_limit").innerText, "3+");
assert.verifySteps(["get_views", "web_search_read"]);
expectedCountLimit = undefined;
await click(target.querySelector(".o_pager_previous"));
assert.containsOnce(target, ".o_data_row");
assert.strictEqual(target.querySelector(".o_pager_value").innerText, "5-5");
assert.strictEqual(target.querySelector(".o_pager_limit").innerText, "5");
assert.verifySteps(["search_count", "web_search_read"]);
});
QUnit.test("pager, ungrouped, with count limit reached, edit pager", async (assert) => {
patchWithCleanup(DynamicRecordList, { WEB_SEARCH_READ_COUNT_LIMIT: 3 });
serverData.models.foo.records.push({ id: 5, bar: true, foo: "xxx" });