[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:
committed by
Aaron Bohy
co-authored by
Xavier BOL
parent
0e6481f359
commit
7e86933d94
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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="{"invisible": true}" />
|
||||
<div class="visible3" modifiers="{"invisible": false}"/>
|
||||
<div modifiers="{"invisible": "[['display_name', '=', 'take']]"}"/>
|
||||
</form>`;
|
||||
|
||||
const expected = /*xml*/ `
|
||||
<div class="visible3" />
|
||||
<div t-if="!evalDomainFromRecord(props.record,"[['display_name','=','take']]")" />
|
||||
`;
|
||||
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="{"invisible": "[['display_name', '=', uid]]"}">
|
||||
<field name="charfield"/>
|
||||
</div>
|
||||
<field name="display_name" attrs="{'readonly': "[['display_name', '=', uid]]"}"/>
|
||||
</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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user