From 0ff71ab65f5da30bc113c8feabe6ec0f9b76f8fc Mon Sep 17 00:00:00 2001 From: Romain Estievenart Date: Tue, 23 May 2023 10:37:21 +0000 Subject: [PATCH] [FIX] web: crash in grouped kanban's progressbar with folded column Steps to reproduce: - Open Odoo on small screen - Go to "Project" app - Select project > Traceback The Kanban progress bar's refactoring [1] didn't completely took into account the fact that, on smaller screen, the "folded" columns aren't actually folded (like on dekstop-like screen sizes) but instead their records aren't loaded by default. As a result, in one case the progress bar is shown (small screen) and in the other hidden. As the progressbar's information is memoized in `getGroupInfo`, this getter should have been called wherever those information are read. This commit fixes the issue by properly calling the `getGroupInfo` getter instead of using the "private" `_groupsInfo` object (which may not yet have been populated, due to the memoization). task-3336233 [1] https://github.com/odoo/odoo/commit/58ca40b03215ef4c6c575267494dc8bccc30a033 closes odoo/odoo#122214 X-original-commit: c2efa7f059c92298ae5fb22b83e812453e2eb8ea Signed-off-by: Pierre Paridans (app) --- .../src/views/kanban/progress_bar_hook.js | 10 +- .../tests/mobile/views/kanban_view_tests.js | 107 ++++++++++++++++++ 2 files changed, 112 insertions(+), 5 deletions(-) create mode 100644 addons/web/static/tests/mobile/views/kanban_view_tests.js diff --git a/addons/web/static/src/views/kanban/progress_bar_hook.js b/addons/web/static/src/views/kanban/progress_bar_hook.js index 62c0892542b..edf53359891 100644 --- a/addons/web/static/src/views/kanban/progress_bar_hook.js +++ b/addons/web/static/src/views/kanban/progress_bar_hook.js @@ -137,7 +137,7 @@ class ProgressBarState { async selectBar(groupId, bar) { const group = this.model.root.groups.find((group) => group.id === groupId); - const progressBar = this._groupsInfo[groupId]; + const progressBar = this.getGroupInfo(group); const nextActiveBar = {}; if (bar.value && this.activeBars[group.value]?.value !== bar.value) { nextActiveBar.value = bar.value; @@ -157,7 +157,7 @@ class ProgressBarState { const proms = []; proms.push( group.applyFilter(filterDomain).then((res) => { - const groupInfo = this._groupsInfo[group.id]; + const groupInfo = this.getGroupInfo(group); nextActiveBar.count = groupInfo.bars.find( (x) => x.value === nextActiveBar.value ).count; @@ -171,7 +171,7 @@ class ProgressBarState { } _updateAggregateGroup(group, activeBar) { - const groupInfo = this._groupsInfo[group.id]; + const groupInfo = this.getGroupInfo(group); const filterDomain = _createFilterDomain( this.progressAttributes.fieldName, groupInfo.bars, @@ -253,7 +253,7 @@ class ProgressBarState { } for (const group of this.model.root.groups) { if (!group.isFolded) { - const groupInfo = this._groupsInfo[group.id]; + const groupInfo = this.getGroupInfo(group); let groupValue = group.displayName || group.value; if (groupValue === true) { groupValue = "True"; @@ -299,7 +299,7 @@ class ProgressBarState { } getGroupCount(group) { - const progressBarInfo = this._groupsInfo[group.id]; + const progressBarInfo = this.getGroupInfo(group); if (progressBarInfo.activeBar) { const progressBar = progressBarInfo.bars.find( (b) => b.value === progressBarInfo.activeBar diff --git a/addons/web/static/tests/mobile/views/kanban_view_tests.js b/addons/web/static/tests/mobile/views/kanban_view_tests.js new file mode 100644 index 00000000000..0cbfb2fd540 --- /dev/null +++ b/addons/web/static/tests/mobile/views/kanban_view_tests.js @@ -0,0 +1,107 @@ +/** @odoo-module **/ + +import { makeView, setupViewRegistries } from "@web/../tests/views/helpers"; +import { click, getFixture, patchWithCleanup} from "@web/../tests/helpers/utils"; +import { AnimatedNumber } from "@web/views/view_components/animated_number"; + +let serverData; +let target; + +QUnit.module("Views", (hooks) => { + hooks.beforeEach(() => { + patchWithCleanup(AnimatedNumber, { enableAnimations: false }); + serverData = { + models: { + partner: { + fields: { + foo: { string: "Foo", type: "char" }, + product_id: { + string: "something_id", + type: "many2one", + relation: "product", + }, + }, + records: [ + { + id: 1, + foo: "yop", + product_id: 3, + }, + { + id: 2, + foo: "blip", + product_id: 5, + }, + { + id: 3, + foo: "gnap", + product_id: 3, + }, + { + id: 4, + foo: "blip", + product_id: 5, + }, + ], + }, + product: { + fields: { + id: { string: "ID", type: "integer" }, + name: { string: "Display Name", type: "char" }, + }, + records: [ + { id: 3, name: "hello" }, + { id: 5, name: "xmo" }, + ], + }, + }, + views: {}, + }; + target = getFixture(); + + setupViewRegistries(); + }); + + QUnit.module("KanbanView"); + + QUnit.test("Should load grouped kanban with folded column", async (assert) => { + await makeView({ + type: "kanban", + resModel: "partner", + serverData, + arch: ` + + + + + +
+
+
+
`, + groupBy: ["product_id"], + async mockRPC(route, args, performRPC) { + if (args.method === "web_read_group") { + const result = await performRPC(route, args); + result.groups[1].__fold = true; + return result; + } + }, + }); + assert.containsN(target, ".o_column_progress", 2, "Should have 2 progress bar"); + assert.containsN(target, ".o_kanban_group", 2, "Should have 2 grouped column"); + assert.containsN(target, ".o_kanban_record", 2, "Should have 2 loaded record"); + assert.containsOnce( + target, + ".o_kanban_load_more", + "Should have a folded column with a load more button" + ); + await click(target, ".o_kanban_load_more button"); + assert.containsNone( + target, + ".o_kanban_load_more", + "Shouldn't have a load more button" + ); + assert.containsN(target, ".o_kanban_record", 4, "Should have 4 loaded record"); + }); +});