[FIX] web: x2many with non inline form: don't share active fields

Before this commit, the StaticList and its Records shared the same
reference to the activeFields. When an x2many record was opened in
form view (and that form view wasn't inline), we altered the active
fields to add the information coming from the form, and we loaded
the corresponding data for the record we open. However, by doing
so, we also altered the active fields of all the other records,
for which we didn't load the corresponding data. From that point,
a rendering of those kanban records could lead to a crash, because
we iterate over active fields and make the assumption that there's
an entry for each of them in data, which isn't the case.

For instance, this happened in a dev branch in project, in mobile:
after opening a sub task in form view, if we switched to another
notebook tab and then switched back, there was a crash.

This commit fixes the issue by creating a copy of activeFields for
each Record, s.t. when a record is opened in a dialog, only its
activeFields (and those of the StaticList) are altered.

Note that activeFields of the StaticList must be altered in this
case to ensure that the onchange spec is properly generated, with
the fields of the form view.

closes odoo/odoo#148351

Signed-off-by: Francois Georis (fge) <fge@odoo.com>
This commit is contained in:
Aaron Bohy
2024-01-09 06:27:58 +00:00
parent 2005c38679
commit ac40c6eabb
2 changed files with 65 additions and 1 deletions
@@ -716,7 +716,7 @@ export class StaticList extends DataPoint {
const id = resId || params.virtualId;
const config = {
context: this.context,
activeFields: params.activeFields || this.activeFields,
activeFields: Object.assign({}, params.activeFields || this.activeFields),
resModel: this.resModel,
fields: params.fields || this.fields,
relationField: this.config.relationField,
@@ -14445,4 +14445,68 @@ QUnit.module("Fields", (hooks) => {
);
}
);
QUnit.test(
"x2many kanban with float field in form (non inline) but not in kanban",
async function (assert) {
// In this test, the form view contains an extra float field and isn't inline. When we open
// a record, we add the form fields to the list of activeFields, and we load the
// corresponding data (for that record only). Afterwards, we force a re-rendering of the
// x2many kanban to ensure that the other record can still be rendered. Before the fix coming
// with this test, it wasn't the case, because those records had extra activeFields, but no
// entry in data for those fields.
serverData.models.partner.records[0].turtles = [2, 3];
serverData.views = {
"turtle,false,form": `
<form>
<field name="display_name"/>
<field name="turtle_qux"/>
</form>`,
};
await makeView({
type: "form",
resModel: "partner",
serverData,
arch: `
<form>
<field name="bar"/>
<field name="turtles" invisible="not bar">
<kanban>
<field name="display_name"/>
<templates>
<t t-name="kanban-box">
<div class="oe_kanban_global_click">
<t t-esc="record.display_name.raw_value"/>
</div>
</t>
</templates>
</kanban>
</field>
</form>`,
resId: 1,
});
assert.containsOnce(target, ".o_field_widget[name=turtles]");
assert.containsN(target, ".o_kanban_record:not(.o_kanban_ghost)", 2);
// open the first record
await click(target.querySelector(".o_kanban_record"));
assert.containsOnce(target, ".o_dialog");
assert.containsOnce(target, ".o_dialog .o_field_widget[name=turtle_qux]");
// close the dialog
await click(target.querySelector(".o_dialog .o_form_button_save"));
assert.containsNone(target, ".o_dialog");
// toggle bar to make the x2many invisible
await click(target, ".o_field_widget[name=bar] input");
assert.containsNone(target, ".o_field_widget[name=turtles]");
// toggle bar again to make the x2many visible and force kanban cards to re-render
await click(target, ".o_field_widget[name=bar] input");
assert.containsOnce(target, ".o_field_widget[name=turtles]");
assert.containsN(target, ".o_kanban_record:not(.o_kanban_ghost)", 2);
}
);
});