From a3b00f2dca1e268bbd6d971ac3aa8d34228faf9c Mon Sep 17 00:00:00 2001 From: Mathieu Duckerts-Antoine Date: Mon, 3 Jul 2023 11:27:44 +0000 Subject: [PATCH] [FIX] web: domain selector: operators with same key Before that commit, we could get two operators with the same key to display at the same time. In that case, an error would be thrown by OWL: Got duplicate key in t-foreach... . We fix that problem. Part-of: odoo/odoo#121688 --- .../core/domain_selector/domain_selector.js | 6 ++-- .../domain_selector_operators.js | 30 +++++++++++++++++-- .../tests/core/domain_selector_tests.js | 8 +++++ 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/addons/web/static/src/core/domain_selector/domain_selector.js b/addons/web/static/src/core/domain_selector/domain_selector.js index 8b76fac6558..ae1175d9bca 100644 --- a/addons/web/static/src/core/domain_selector/domain_selector.js +++ b/addons/web/static/src/core/domain_selector/domain_selector.js @@ -11,7 +11,7 @@ import { Component, onWillStart, onWillUpdateProps } from "@odoo/owl"; import { Domain } from "@web/core/domain"; import { Dropdown } from "@web/core/dropdown/dropdown"; import { DropdownItem } from "@web/core/dropdown/dropdown_item"; -import { getOperatorInfo } from "@web/core/domain_selector/domain_selector_operators"; +import { getOperatorInfo, toOperator } from "@web/core/domain_selector/domain_selector_operators"; import { Editor, PathEditor, @@ -207,8 +207,10 @@ export class DomainSelector extends Component { this.notifyChanges(); } - updateLeafOperator(node, operator) { + updateLeafOperator(node, operatorKey) { + const [operator, negate] = toOperator(operatorKey); const previousOperatorInfo = getOperatorInfo(node.operator); + node.negate = negate; node.operator = operator; const operatorInfo = getOperatorInfo(operator); if (previousOperatorInfo.valueCount !== operatorInfo.valueCount) { diff --git a/addons/web/static/src/core/domain_selector/domain_selector_operators.js b/addons/web/static/src/core/domain_selector/domain_selector_operators.js index df20141938b..b5b9eaf241d 100644 --- a/addons/web/static/src/core/domain_selector/domain_selector_operators.js +++ b/addons/web/static/src/core/domain_selector/domain_selector_operators.js @@ -1,8 +1,9 @@ /** @odoo-module **/ import { _lt } from "@web/core/l10n/translation"; -import { formatValue } from "@web/core/domain_tree"; +import { formatValue, toValue } from "@web/core/domain_tree"; import { sprintf } from "@web/core/utils/strings"; +import { parseExpr } from "@web/core/py_js/py"; /** * @typedef {Object} OperatorInfo @@ -41,6 +42,22 @@ export const OPERATOR_DESCRIPTIONS = { between: { label: _lt("is between"), valueCount: 2 }, }; +function toKey(operator, negate = false) { + if (!negate && typeof operator === "string" && operator in OPERATOR_DESCRIPTIONS) { + // this case is the main one. We keep it simple + return operator; + } + return JSON.stringify([formatValue(operator), negate]); +} + +export function toOperator(key) { + if (!key.includes("[")) { + return [key, false]; + } + const [expr, negate] = JSON.parse(key); + return [toValue(parseExpr(expr)), negate]; +} + /** * @param {import("@web/core/domain_tree").Value} operator * @param {boolean} [negate=false] @@ -48,12 +65,19 @@ export const OPERATOR_DESCRIPTIONS = { */ export function getOperatorInfo(operator, negate = false) { let operatorInfo; + const key = toKey(operator, negate); if (typeof operator === "string" && operator in OPERATOR_DESCRIPTIONS) { const { label, valueCount } = OPERATOR_DESCRIPTIONS[operator]; - operatorInfo = { key: operator, label: label.toString(), operator, negate, valueCount }; + operatorInfo = { + key, + label: label.toString(), + operator, + negate, + valueCount, + }; } else { operatorInfo = { - key: "__unknown__", + key, label: formatValue(operator), operator, negate, diff --git a/addons/web/static/tests/core/domain_selector_tests.js b/addons/web/static/tests/core/domain_selector_tests.js index d1606d6f085..6c2b1e1d5ce 100644 --- a/addons/web/static/tests/core/domain_selector_tests.js +++ b/addons/web/static/tests/core/domain_selector_tests.js @@ -1405,4 +1405,12 @@ QUnit.module("Components", (hooks) => { }); assert.strictEqual(target.querySelector(".o_domain_leaf").textContent, `Foo = uid`); }); + + QUnit.test("display of an operator without negation defined (edit)", async (assert) => { + await makeDomainSelector({ + resModel: "partner", + domain: `["!", (expr, "parent_of", "a")]`, + }); + assert.strictEqual(getSelectedOperator(target), `not parent of`); + }); });