[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:
@@ -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({
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user