[FIX] web: client report action mounted called twice
Before this commit, the 'mounted' method of the ControlPanel in
the client report action was called twice.
It happened because the client report action updated the ControlPanel
before being actually mounted, so mounted was called once when the
traceability report was mounted, and once when the update was applied.
Ideally, this should not be an issue (this isn't an issue with owl).
However, in Odoo, we mix layers of Owl Components and legacy
widgets. In these situations, the above scenario isn't properly
handled (and can't be).
As a consequence, in mobile (enterprise), it crashed because an
handler bound in mounted (thus twice) was only unbound once.
This commit avoids the issue as the update was actually useless.
Steps to reproduces (Mobile):
* Go to Inventory (Stock)
* Open the "burger menu"
* Select "Products" -> "Products"
* Select one product in the list
* Click on the "Forecasted" ("stat button")
* Select one "SO line" (sale order) to go to the form view
* Go back to the previous view using breadcrumb
* Optional: Go to another app if the screen can't scroll (e.g. go to Sales)
* Scroll the view => Bug
closes odoo/odoo#66497
X-original-commit: d3854dbf7a6e0c0f9ac00c11716908bc175808d7
Related: odoo/enterprise#16507
Signed-off-by: Adrien Dieudonné (adr) <adr@odoo.com>
This commit is contained in:
@@ -53,15 +53,6 @@ var ReportAction = AbstractAction.extend({
|
||||
});
|
||||
},
|
||||
|
||||
do_show: function () {
|
||||
this.updateControlPanel({
|
||||
cp_content: {
|
||||
$buttons: this.$buttons,
|
||||
},
|
||||
});
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
on_attach_callback: function () {
|
||||
// Register now the postMessage event handler. We only want to listen to ~trusted
|
||||
// messages and we can only filter them by their origin, so we chose to ignore the
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
odoo.define('web/static/tests/report/client_action_tests', function (require) {
|
||||
"use strict";
|
||||
|
||||
const ControlPanel = require('web.ControlPanel');
|
||||
const ReportClientAction = require('report.client_action');
|
||||
const testUtils = require("web.test_utils");
|
||||
|
||||
const { createActionManager, dom, mock } = testUtils;
|
||||
|
||||
QUnit.module('Client Action Report', {}, () => {
|
||||
QUnit.test("mounted is called once when returning on 'Client Action Report' from breadcrumb", async assert => {
|
||||
// This test can be removed as soon as we don't mix legacy and owl layers anymore.
|
||||
assert.expect(7);
|
||||
|
||||
let mountCount = 0;
|
||||
|
||||
// patch the report client action to override its iframe's url so that
|
||||
// it doesn't trigger an RPC when it is appended to the DOM (for this
|
||||
// usecase, using removeSRCAttribute doesn't work as the RPC is
|
||||
// triggered as soon as the iframe is in the DOM, even if its src
|
||||
// attribute is removed right after)
|
||||
mock.patch(ReportClientAction, {
|
||||
start: function () {
|
||||
var self = this;
|
||||
return this._super.apply(this, arguments).then(function () {
|
||||
self._rpc({route: self.iframe.getAttribute('src')});
|
||||
self.iframe.setAttribute('src', 'about:blank');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
ControlPanel.patch('test.ControlPanel', T => {
|
||||
class ControlPanelPatchTest extends T {
|
||||
mounted() {
|
||||
mountCount = mountCount + 1;
|
||||
this.__uniqueId = mountCount;
|
||||
assert.step(`mounted ${this.__uniqueId}`);
|
||||
super.mounted(...arguments);
|
||||
}
|
||||
willUnmount() {
|
||||
assert.step(`willUnmount ${this.__uniqueId}`);
|
||||
super.mounted(...arguments);
|
||||
}
|
||||
}
|
||||
return ControlPanelPatchTest;
|
||||
});
|
||||
const actionManager = await createActionManager({
|
||||
actions: [
|
||||
{
|
||||
id: 42,
|
||||
name: "Client Action Report",
|
||||
tag: 'report.client_action',
|
||||
type: 'ir.actions.report',
|
||||
report_type: 'qweb-html',
|
||||
},
|
||||
{
|
||||
id: 43,
|
||||
type: "ir.actions.act_window",
|
||||
res_id: 1,
|
||||
res_model: "partner",
|
||||
views: [
|
||||
[false, "form"],
|
||||
],
|
||||
}
|
||||
],
|
||||
archs: {
|
||||
'partner,false,form': '<form><field name="display_name"/></form>',
|
||||
'partner,false,search': '<search></search>',
|
||||
},
|
||||
data: {
|
||||
partner: {
|
||||
fields: {
|
||||
display_name: { string: "Displayed name", type: "char" },
|
||||
},
|
||||
records: [
|
||||
{id: 1, display_name: "Genda Swami"},
|
||||
],
|
||||
},
|
||||
},
|
||||
mockRPC: function (route) {
|
||||
if (route === '/report/html/undefined?context=%7B%7D') {
|
||||
return Promise.resolve('<a action="go_to_details">Go to detail view</a>');
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
intercepts: {
|
||||
do_action: ev => actionManager.doAction(ev.data.action, ev.data.options),
|
||||
},
|
||||
});
|
||||
|
||||
await actionManager.doAction(42);
|
||||
// simulate an action as we are not able to reproduce a real doAction using 'Client Action Report'
|
||||
await actionManager.doAction(43);
|
||||
await dom.click(actionManager.$('.breadcrumb-item:first'));
|
||||
actionManager.destroy();
|
||||
|
||||
assert.verifySteps([
|
||||
'mounted 1',
|
||||
'willUnmount 1',
|
||||
'mounted 2',
|
||||
'willUnmount 2',
|
||||
'mounted 3',
|
||||
'willUnmount 3',
|
||||
]);
|
||||
|
||||
ControlPanel.unpatch('test.ControlPanel');
|
||||
mock.unpatch(ReportClientAction);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -778,6 +778,8 @@
|
||||
<script type="text/javascript" src="/web/static/tests/widgets/model_field_selector_tests.js"/>
|
||||
<script type="text/javascript" src="/web/static/tests/widgets/rainbow_man_tests.js"/>
|
||||
|
||||
<script type="text/javascript" src="/web/static/tests/report/client_action_tests.js"/>
|
||||
|
||||
<script type="text/javascript" src="/web/static/tests/tools/debug_manager_tests.js"/>
|
||||
|
||||
<script type="text/javascript" src="/web/static/tests/helpers/test_utils_tests.js"></script>
|
||||
|
||||
Reference in New Issue
Block a user