[FIX] web: evaluate string domain in modifiers

Before this commit, in `getModifier` method when a modifier contains a
domain in a string, the domain is not evaluated and just converted into
a boolean value that is if the string is not empty then the method will
return `true` and `false` otherwise.
Also, the `applyInvisible` method does not take into account an invisible
domain in a string. That is if the `invisible` variable contains a domain
in an `Array` then  the domain is evaluated otherwise the domain is
considered as a boolean value.

This commit checks if the modifier contains a boolean value as value to
evaluate it as a boolean and return it otherwise the modifier value is
returned in the `getModifier` method.
In the `applyInvisible`, this commit allows to evaluate the domain if
the domain is containing in a string.

Part-of: odoo/odoo#92475
Co-authored-by: Xavier BOL (xbo) <xbo@odoo.com>
This commit is contained in:
Jorge Pinna Puissant
2022-06-30 09:29:48 +02:00
committed by Aaron Bohy
co-authored by Xavier BOL
parent 0e6481f359
commit 7e86933d94
5 changed files with 51 additions and 21 deletions
@@ -5,9 +5,10 @@ import { Field } from "@web/views/fields/field";
import { ButtonBox } from "@web/views/form/button_box/button_box";
import { InnerGroup, OuterGroup } from "@web/views/form/form_group/form_group";
import { ViewButton } from "@web/views/view_button/view_button";
import { evalDomainFromRecord, useViewCompiler } from "@web/views/view_compiler";
import { useViewCompiler } from "@web/views/view_compiler";
import { useBounceButton } from "@web/views/view_hook";
import { Widget } from "@web/views/widgets/widget";
import { evalDomain } from "../utils";
import { FormCompiler } from "./form_compiler";
import { FormLabel } from "./form_label";
import { StatusBarButtons } from "./status_bar_buttons/status_bar_buttons";
@@ -25,8 +26,8 @@ export class FormRenderer extends Component {
});
}
evalDomainFromRecord() {
return evalDomainFromRecord(...arguments);
evalDomainFromRecord(record, expr) {
return evalDomain(expr, record.evalContext);
}
}
@@ -11,9 +11,10 @@ import { url } from "@web/core/utils/urls";
import { Field } from "@web/views/fields/field";
import { fileTypeMagicWordMap } from "@web/views/fields/image/image_field";
import { ViewButton } from "@web/views/view_button/view_button";
import { evalDomainFromRecord, useViewCompiler } from "@web/views/view_compiler";
import { useViewCompiler } from "@web/views/view_compiler";
import { Widget } from "@web/views/widgets/widget";
import { useTooltip } from "@web/core/tooltip/tooltip_hook";
import { evalDomain } from "../utils";
import { KANBAN_BOX_ATTRIBUTE, KANBAN_TOOLTIP_ATTRIBUTE } from "./kanban_arch_parser";
import { KanbanCompiler } from "./kanban_compiler";
import { KanbanCoverImageDialog } from "./kanban_cover_image_dialog";
@@ -228,8 +229,8 @@ export class KanbanRecord extends Component {
};
}
evalDomainFromRecord() {
return evalDomainFromRecord(...arguments);
evalDomainFromRecord(record, expr) {
return evalDomain(expr, record.evalContext);
}
getRecordClasses() {
+1 -1
View File
@@ -89,7 +89,7 @@ export const computeReportMeasures = (
* @returns {boolean}
*/
export function evalDomain(modifier, evalContext) {
if (Array.isArray(modifier)) {
if (modifier && typeof modifier !== "boolean") {
modifier = new Domain(modifier).contains(evalContext);
}
return Boolean(modifier);
+2 -13
View File
@@ -1,6 +1,5 @@
/** @odoo-module **/
import { Domain } from "@web/core/domain";
import {
append,
combineAttributes,
@@ -142,10 +141,6 @@ export function encodeObjectForTemplate(obj) {
return `"${encodeURI(JSON.stringify(obj))}"`;
}
export function evalDomainFromRecord(record, expr) {
return new Domain(expr).contains(record.evalContext);
}
/**
* @param {Element} el
* @param {string} modifierName
@@ -156,7 +151,7 @@ export function getModifier(el, modifierName) {
// modifiers' string are evaluated to their boolean or array form
const modifiers = JSON.parse(el.getAttribute("modifiers") || "{}");
const mod = modifierName in modifiers ? modifiers[modifierName] : false;
return Array.isArray(mod) ? mod : !!mod;
return typeof mod !== "boolean" ? mod : !!mod;
}
/**
@@ -251,13 +246,7 @@ export class ViewCompiler {
" and "
);
} else {
let expr;
if (Array.isArray(invisible)) {
expr = `evalDomainFromRecord(props.record,${JSON.stringify(invisible)})`;
} else {
expr = invisible;
}
appendAttr(compiled, "class", `o_invisible_modifier:${expr}`);
appendAttr(compiled, "class", `o_invisible_modifier:${invisible}`);
}
return compiled;
}
@@ -3,6 +3,7 @@ import { makeView } from "../helpers";
import { setupViewRegistries } from "@web/../tests/views/helpers";
import { FormCompiler } from "@web/views/form/form_compiler";
import { registry } from "@web/core/registry";
import { click, getFixture } from "../../helpers/utils";
function compileTemplate(arch) {
const parser = new DOMParser();
@@ -141,12 +142,28 @@ QUnit.module("Form Compiler", () => {
assert.areContentEquivalent(compileTemplate(arch), expected);
});
QUnit.test("compile invisible containing string as domain", async (assert) => {
const arch = /*xml*/ `
<form>
<field name="display_name" modifiers="{&quot;invisible&quot;: true}" />
<div class="visible3" modifiers="{&quot;invisible&quot;: false}"/>
<div modifiers="{&quot;invisible&quot;: &quot;[['display_name', '=', 'take']]&quot;}"/>
</form>`;
const expected = /*xml*/ `
<div class="visible3" />
<div t-if="!evalDomainFromRecord(props.record,&quot;[['display_name','=','take']]&quot;)" />
`;
assert.areContentEquivalent(compileTemplate(arch), expected);
});
});
QUnit.module("Form Renderer", (hooks) => {
let serverData;
let target, serverData;
hooks.beforeEach(() => {
target = getFixture();
setupViewRegistries();
serverData = {
models: {
@@ -163,6 +180,28 @@ QUnit.module("Form Renderer", (hooks) => {
};
});
QUnit.test("compile form with modifiers and attrs - string as domain", async (assert) => {
serverData.views = {
"partner,1,form": /*xml*/ `
<form>
<div modifiers="{&quot;invisible&quot;: &quot;[['display_name', '=', uid]]&quot;}">
<field name="charfield"/>
</div>
<field name="display_name" attrs="{'readonly': &quot;[['display_name', '=', uid]]&quot;}"/>
</form>`,
};
await makeView({
serverData,
resModel: "partner",
type: "form",
resId: 1,
});
await click(target.querySelector(".o_form_button_edit"));
assert.containsN(target, ".o_form_editable input", 2);
});
QUnit.test("compile notebook with modifiers", async (assert) => {
assert.expect(0);