[FIX] web: FormView: add fieldDependencies to fields

Since [1], a call to getView no longer returns the all models the
list of all their fields, because a lot of them aren't necessary.

However, it caused an issue in the following situation:
 - have a form view with an x2many displayed as a list
 - in the list, have a field or widget with fieldDependencies
   (dependency on field A)
 - in the arch, the x2many form view isn't inline
 - in readonly mode, the user clicks on a row, which will open
   the x2many form view
 - since the form view isn't inline, a call to getView is done
 - in the returned form view, field A isn't present.

Since [1], it crashed at this point because A wasn't part of the
known fields in the form view (but it was in the activeFields,
since they are shared between the x2many list and form).

This commit fixes the issue by adding fieldDependencies not only
in activeFields, but also in fields if not already there.

[1] 4636620004

closes odoo/odoo#100495

Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
Aaron Bohy
2022-09-19 20:59:08 +02:00
parent 1df86678e2
commit fa1906223f
5 changed files with 61 additions and 6 deletions
@@ -29,14 +29,22 @@ export class FormArchParser extends XMLParser {
if (archParseBoolean(node.getAttribute("default_focus") || "")) {
autofocusFieldId = fieldId;
}
addFieldDependencies(activeFields, fieldInfo.FieldComponent.fieldDependencies);
addFieldDependencies(
activeFields,
models[modelName],
fieldInfo.FieldComponent.fieldDependencies
);
return false;
} else if (node.tagName === "div" && node.classList.contains("oe_chatter")) {
// remove this when chatter fields are declared as attributes on the root node
return false;
} else if (node.tagName === "widget") {
const { WidgetComponent } = Widget.parseWidgetNode(node);
addFieldDependencies(activeFields, WidgetComponent.fieldDependencies);
addFieldDependencies(
activeFields,
models[modelName],
WidgetComponent.fieldDependencies
);
}
});
// TODO: generate activeFields for the model based on fieldNodes (merge duplicated fields)
@@ -84,11 +84,19 @@ export class KanbanArchParser extends XMLParser {
if (fieldInfo.widget === "handle") {
handleField = name;
}
addFieldDependencies(activeFields, fieldInfo.FieldComponent.fieldDependencies);
addFieldDependencies(
activeFields,
models[modelName],
fieldInfo.FieldComponent.fieldDependencies
);
}
if (node.tagName === "widget") {
const { WidgetComponent } = Widget.parseWidgetNode(node);
addFieldDependencies(activeFields, WidgetComponent.fieldDependencies);
addFieldDependencies(
activeFields,
models[modelName],
WidgetComponent.fieldDependencies
);
}
// Keep track of last update so images can be reloaded when they may have changed.
@@ -86,7 +86,11 @@ export class ListArchParser extends XMLParser {
if (fieldInfo.widget === "handle") {
handleField = fieldInfo.name;
}
addFieldDependencies(activeFields, fieldInfo.FieldComponent.fieldDependencies);
addFieldDependencies(
activeFields,
models[modelName],
fieldInfo.FieldComponent.fieldDependencies
);
if (fieldInfo.modifiers.column_invisible !== true) {
const label = fieldInfo.FieldComponent.label;
columns.push({
+4 -1
View File
@@ -13,13 +13,16 @@ const NUMERIC_TYPES = ["integer", "float", "monetary"];
* @param {Object} activeFields
* @param {Object} [dependencies={}]
*/
export function addFieldDependencies(activeFields, dependencies = {}) {
export function addFieldDependencies(activeFields, fields, dependencies = {}) {
for (const [name, dependency] of Object.entries(dependencies)) {
if (!(name in activeFields)) {
activeFields[name] = Object.assign({ name, rawAttrs: {} }, dependency, {
modifiers: { invisible: true },
});
}
if (!(name in fields)) {
fields[name] = { ...dependency };
}
}
}
@@ -673,6 +673,38 @@ QUnit.module("Views", (hooks) => {
}
);
QUnit.test("form with o2m having a field with fieldDependencies", async function (assert) {
// In this scenario, the x2many form view isn't inline, so when we click on the record,
// it does an independant getView, which doesn't return all fields of the model. In the
// x2many list view, there's a field with fieldDependencies, and the dependency field
// (int_field) in our case, isn't in the form view. This test ensures that we can open
// the form view in this situation.
class MyField extends CharField {}
MyField.fieldDependencies = {
int_field: { type: "integer" },
};
fieldRegistry.add("my_widget", MyField);
serverData.models.partner.records[1].p = [1];
await makeView({
type: "form",
resModel: "partner",
serverData,
arch: `
<form>
<field name="p">
<tree>
<field name="foo" widget="my_widget"/>
</tree>
</field>
</form>`,
resId: 2,
});
assert.containsOnce(target, ".o_field_widget[name=p] .o_data_row");
await click(target.querySelector(".o_field_widget[name=p] .o_data_row .o_data_cell"));
assert.containsOnce(target, ".modal .o_form_view .o_field_widget[name=p]");
});
QUnit.test("decoration-bf works on fields", async function (assert) {
await makeView({
type: "form",