From 0792200c9dab25c0e4d4d112485a98e2a944ba99 Mon Sep 17 00:00:00 2001 From: "Julien Carion (juca)" Date: Tue, 19 Sep 2023 10:48:23 +0200 Subject: [PATCH] [IMP] web: add include archived to domain selector This commit introduces a new feature to the domain selector that allows to toggle a new "include archived" option that alters the domain in a way such that archived records are included or not. This domain part is naive and may overlap with custom parts of the domain. The special domain part which includes archived records (['&', , '|', ('active' , '=', True), ('active', '=', False)]) is invisible inside the domain tree but remains visible in the domain code editor. Also rename the "Match records with xxx of the following rules" statement to "Match xxx of the following rules". task-3482381 closes odoo/odoo#135861 Related: odoo/enterprise#47599 Signed-off-by: Mathieu Duckerts-Antoine (dam) --- .../core/domain_selector/domain_selector.js | 52 ++++- .../core/domain_selector/domain_selector.xml | 42 ++-- addons/web/static/src/core/utils/objects.js | 9 + .../tests/core/domain_selector_tests.js | 197 ++++++++++++------ .../static/tests/search/search_bar_tests.js | 2 +- .../tests/views/fields/domain_field_tests.js | 20 +- 6 files changed, 229 insertions(+), 93 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 01fec1a50a2..f56d61e56a1 100644 --- a/addons/web/static/src/core/domain_selector/domain_selector.js +++ b/addons/web/static/src/core/domain_selector/domain_selector.js @@ -12,6 +12,7 @@ import { } from "@web/core/domain_selector/utils"; import { Component, onWillStart, onWillUpdateProps } from "@odoo/owl"; import { Domain } from "@web/core/domain"; +import { CheckBox } from "@web/core/checkbox/checkbox"; import { Dropdown } from "@web/core/dropdown/dropdown"; import { DropdownItem } from "@web/core/dropdown/dropdown_item"; import { getOperatorInfo, toOperator } from "@web/core/domain_selector/domain_selector_operators"; @@ -26,6 +27,8 @@ import { import { ModelFieldSelector } from "@web/core/model_field_selector/model_field_selector"; import { useLoadFieldInfo } from "@web/core/model_field_selector/utils"; import { formatValue } from "@web/core/domain_tree"; +import { deepEqual } from "@web/core/utils/objects"; +import { useService } from "@web/core/utils/hooks"; function collectDifferences(tree, otherTree) { // some differences shadow the other differences "below": @@ -92,6 +95,7 @@ export class DomainSelector extends Component { ModelFieldSelector, Editor, PathEditor, + CheckBox, }; static props = { domain: String, @@ -114,9 +118,18 @@ export class DomainSelector extends Component { setup() { this.getDefaultLeafDomain = useGetDefaultLeafDomain(); this.loadDisplayNames = useLoadDisplayNames(); - this.loadFieldInfo = useLoadFieldInfo(); + this.fieldService = useService("field"); + this.loadFieldInfo = useLoadFieldInfo(this.fieldService); this.tree = null; this.previousTree = null; + this.includeArchived = false; + this.archivedConnector = { + type: "condition", + value: [true, false], + negate: false, + path: "active", + operator: "in", + }; onWillStart(() => this.onPropsUpdated(this.props)); onWillUpdateProps((np) => this.onPropsUpdated(np)); } @@ -157,6 +170,7 @@ export class DomainSelector extends Component { const paths = new Set([ ...extractPathsFromDomain(domain), ...extractPathsFromDomain(defaultLeafDomain), + "active", ]); await this.loadFieldDefs(p.resModel, paths); @@ -177,6 +191,32 @@ export class DomainSelector extends Component { options ).children[0]; + this.showArchivedCheckbox = Boolean(this.fieldDefs.active); + this.includeArchived = false; + if (this.showArchivedCheckbox) { + if (this.tree.value === "&") { + this.tree.children = this.tree.children.filter((child) => { + if (deepEqual(child, this.archivedConnector)) { + this.includeArchived = true; + return false; + } + return true; + }); + if (this.tree.children.length === 1) { + if (this.tree.children[0].type !== "connector") { + this.tree.value = this.props.defaultConnector; + } else { + this.tree = this.tree.children[0]; + } + } + } else if ( + this.tree.children.length === 1 && + deepEqual(this.tree.children[0], this.archivedConnector) + ) { + this.includeArchived = true; + this.tree = buildDomainSelectorTree(new Domain(`[]`)); + } + } if (this.previousTree) { // find "first" difference restoreVirtualOperators(this.tree, this.previousTree); @@ -184,9 +224,17 @@ export class DomainSelector extends Component { } } + toggleIncludeArchived() { + this.includeArchived = !this.includeArchived; + this.notifyChanges(); + } + notifyChanges() { this.previousTree = cloneTree(this.tree); - const domain = this.tree ? buildDomain(this.tree) : `[]`; + const archiveDomain = this.includeArchived ? `[("active", "in", [True, False])]` : `[]`; + const domain = this.tree + ? Domain.and([buildDomain(this.tree), archiveDomain]).toString() + : archiveDomain; this.props.update(domain); } diff --git a/addons/web/static/src/core/domain_selector/domain_selector.xml b/addons/web/static/src/core/domain_selector/domain_selector.xml index f3a07370eec..6ba46c3b321 100644 --- a/addons/web/static/src/core/domain_selector/domain_selector.xml +++ b/addons/web/static/src/core/domain_selector/domain_selector.xml @@ -4,23 +4,31 @@
- - - Match all records - - - - - - Match records with - - of the following rules: - - - New Rule - + +
+
+ + Match all records + + + Match + + of the following rules: + +
+ + Include archived + +
+ + + New Rule diff --git a/addons/web/static/src/core/utils/objects.js b/addons/web/static/src/core/utils/objects.js index 20a5a0624c8..545e4c84c48 100644 --- a/addons/web/static/src/core/utils/objects.js +++ b/addons/web/static/src/core/utils/objects.js @@ -19,6 +19,15 @@ export function shallowEqual(obj1, obj2, comparisonFn = (a, b) => a === b) { ); } +/** + * Deeply compares two objects. + * + * @template {unknown} T + * @param {T} obj1 + * @param {T} obj2 + */ +export const deepEqual = (obj1, obj2) => shallowEqual(obj1, obj2, deepEqual); + /** * Deep copies an object. As it relies on JSON this function as some limitations * - no support for circular objects diff --git a/addons/web/static/tests/core/domain_selector_tests.js b/addons/web/static/tests/core/domain_selector_tests.js index 71e84cf02b3..2447f5486f7 100644 --- a/addons/web/static/tests/core/domain_selector_tests.js +++ b/addons/web/static/tests/core/domain_selector_tests.js @@ -172,17 +172,16 @@ QUnit.module("Components", (hooks) => { isDebugMode: true, }); - // As we gave an empty domain, there should be a visible button to add - // the first domain part + // When we have an empty domain, the "New Rule" button should be available assert.containsOnce( target, - ".o_domain_add_first_node_button", - "there should be a button to create first domain element" + "a[role=button]", + "there should be a button to create a domain element" ); // Clicking on the button should add a visible field selector in the // widget so that the user can change the field chain - await click(target, ".o_domain_add_first_node_button"); + await click(target, "a[role=button]"); assert.containsOnce(target, ".o_model_field_selector"); // Focusing the field selector input should open a field selector popover @@ -431,7 +430,7 @@ QUnit.module("Components", (hooks) => { }); // Clicking on the button should add a visible field selector in the // widget so that the user can change the field chain - await click(target, ".o_domain_add_first_node_button"); + await click(target, "a[role=button]"); }); QUnit.test("edit a domain with the debug textarea", async (assert) => { @@ -756,10 +755,10 @@ QUnit.module("Components", (hooks) => { await click(target, ".o_reset_domain_button"); assert.strictEqual( target.querySelector(".o_domain_selector").innerText.toLowerCase(), - "match all records add condition" + "match all records\nnew rule" ); assert.containsNone(target, ".o_reset_domain_button"); - assert.containsOnce(target, ".o_domain_add_first_node_button"); + assert.containsOnce(target, "a[role=button]"); assert.verifySteps(["[]"]); }); @@ -905,7 +904,7 @@ QUnit.module("Components", (hooks) => { }); assert.strictEqual( target.querySelector(".o_domain_selector").innerText, - `Match records with any of the following rules:\ncreate_date\nis between 2023-04-01 00:00:00 and 2023-04-30 23:59:59\n0\n= 1` + `Match any of the following rules:\ncreate_date\nis between 2023-04-01 00:00:00 and 2023-04-30 23:59:59\n0\n= 1` ); }); @@ -934,99 +933,99 @@ QUnit.module("Components", (hooks) => { const toTest = [ { domain: `["!", ("foo", "=", "abc")]`, - result: `Match records with all of the following rules:\nFoo\n!= abc`, + result: `Match all of the following rules:\nFoo\n!= abc`, }, { domain: `["!", "!", ("foo", "=", "abc")]`, - result: `Match records with all of the following rules:\nFoo\n= abc`, + result: `Match all of the following rules:\nFoo\n= abc`, }, { domain: `["!", "!", "!", ("foo", "=", "abc")]`, - result: `Match records with all of the following rules:\nFoo\n!= abc`, + result: `Match all of the following rules:\nFoo\n!= abc`, }, { domain: `["!", "&", ("foo", "=", "abc"), ("foo", "=", "def")]`, - result: `Match records with any of the following rules:\nFoo\n!= abc\nFoo\n!= def`, + result: `Match any of the following rules:\nFoo\n!= abc\nFoo\n!= def`, }, { domain: `["!", "|", ("foo", "=", "abc"), ("foo", "=", "def")]`, - result: `Match records with all of the following rules:\nFoo\n!= abc\nFoo\n!= def`, + result: `Match all of the following rules:\nFoo\n!= abc\nFoo\n!= def`, }, { domain: `["&", "!", ("foo", "=", "abc"), ("foo", "=", "def")]`, - result: `Match records with all of the following rules:\nFoo\n!= abc\nFoo\n= def`, + result: `Match all of the following rules:\nFoo\n!= abc\nFoo\n= def`, }, { domain: `["&", "!", "!", ("foo", "=", "abc"), ("foo", "=", "def")]`, - result: `Match records with all of the following rules:\nFoo\n= abc\nFoo\n= def`, + result: `Match all of the following rules:\nFoo\n= abc\nFoo\n= def`, }, { domain: `["&", ("foo", "=", "abc"), "!", ("foo", "=", "def")]`, - result: `Match records with all of the following rules:\nFoo\n= abc\nFoo\n!= def`, + result: `Match all of the following rules:\nFoo\n= abc\nFoo\n!= def`, }, { domain: `["&", ("foo", "=", "abc"), "!", "!", ("foo", "=", "def")]`, - result: `Match records with all of the following rules:\nFoo\n= abc\nFoo\n= def`, + result: `Match all of the following rules:\nFoo\n= abc\nFoo\n= def`, }, { domain: `["|", "!", ("foo", "=", "abc"), ("foo", "=", "def")]`, - result: `Match records with any of the following rules:\nFoo\n!= abc\nFoo\n= def`, + result: `Match any of the following rules:\nFoo\n!= abc\nFoo\n= def`, }, { domain: `["|", "!", "!", ("foo", "=", "abc"), ("foo", "=", "def")]`, - result: `Match records with any of the following rules:\nFoo\n= abc\nFoo\n= def`, + result: `Match any of the following rules:\nFoo\n= abc\nFoo\n= def`, }, { domain: `["|", ("foo", "=", "abc"), "!", ("foo", "=", "def")]`, - result: `Match records with any of the following rules:\nFoo\n= abc\nFoo\n!= def`, + result: `Match any of the following rules:\nFoo\n= abc\nFoo\n!= def`, }, { domain: `["|", ("foo", "=", "abc"), "!", "!", ("foo", "=", "def")]`, - result: `Match records with any of the following rules:\nFoo\n= abc\nFoo\n= def`, + result: `Match any of the following rules:\nFoo\n= abc\nFoo\n= def`, }, { domain: `["&", "!", "&", ("foo", "=", "abc"), ("foo", "=", "def"), ("foo", "=", "ghi")]`, - result: `Match records with all of the following rules:\nany\nof:\nFoo\n!= abc\nFoo\n!= def\nFoo\n= ghi`, + result: `Match all of the following rules:\nany\nof:\nFoo\n!= abc\nFoo\n!= def\nFoo\n= ghi`, }, { domain: `["&", "!", "|", ("foo", "=", "abc"), ("foo", "=", "def"), ("foo", "=", "ghi")]`, - result: `Match records with all of the following rules:\nFoo\n!= abc\nFoo\n!= def\nFoo\n= ghi`, + result: `Match all of the following rules:\nFoo\n!= abc\nFoo\n!= def\nFoo\n= ghi`, }, { domain: `["|", "!", "&", ("foo", "=", "abc"), ("foo", "=", "def"), ("foo", "=", "ghi")]`, - result: `Match records with any of the following rules:\nFoo\n!= abc\nFoo\n!= def\nFoo\n= ghi`, + result: `Match any of the following rules:\nFoo\n!= abc\nFoo\n!= def\nFoo\n= ghi`, }, { domain: `["|", "!", "|", ("foo", "=", "abc"), ("foo", "=", "def"), ("foo", "=", "ghi")]`, - result: `Match records with any of the following rules:\nall\nof:\nFoo\n!= abc\nFoo\n!= def\nFoo\n= ghi`, + result: `Match any of the following rules:\nall\nof:\nFoo\n!= abc\nFoo\n!= def\nFoo\n= ghi`, }, { domain: `["!", "&", "&", ("foo", "=", "abc"), ("foo", "=", "def"), ("foo", "=", "ghi")]`, - result: `Match records with any of the following rules:\nFoo\n!= abc\nFoo\n!= def\nFoo\n!= ghi`, + result: `Match any of the following rules:\nFoo\n!= abc\nFoo\n!= def\nFoo\n!= ghi`, }, { domain: `["!", "|", "|", ("foo", "=", "abc"), ("foo", "=", "def"), ("foo", "=", "ghi")]`, - result: `Match records with all of the following rules:\nFoo\n!= abc\nFoo\n!= def\nFoo\n!= ghi`, + result: `Match all of the following rules:\nFoo\n!= abc\nFoo\n!= def\nFoo\n!= ghi`, }, { domain: `["!", "&", "|", ("foo", "=", "abc"), "!", ("foo", "=", "def"), ("foo", "=", "ghi")]`, - result: `Match records with any of the following rules:\nall\nof:\nFoo\n!= abc\nFoo\n= def\nFoo\n!= ghi`, + result: `Match any of the following rules:\nall\nof:\nFoo\n!= abc\nFoo\n= def\nFoo\n!= ghi`, }, { domain: `["!", "|", "&", ("foo", "=", "abc"), ("foo", "=", "def"), ("foo", "=", "ghi")]`, - result: `Match records with all of the following rules:\nany\nof:\nFoo\n!= abc\nFoo\n!= def\nFoo\n!= ghi`, + result: `Match all of the following rules:\nany\nof:\nFoo\n!= abc\nFoo\n!= def\nFoo\n!= ghi`, }, { domain: `["!", "&", ("foo", "=", "abc"), "|", ("foo", "=", "def"), ("foo", "=", "ghi")]`, - result: `Match records with any of the following rules:\nFoo\n!= abc\nall\nof:\nFoo\n!= def\nFoo\n!= ghi`, + result: `Match any of the following rules:\nFoo\n!= abc\nall\nof:\nFoo\n!= def\nFoo\n!= ghi`, }, { domain: `["!", "|", ("foo", "=", "abc"), "&", ("foo", "=", "def"), ("foo", "!=", "ghi")]`, - result: `Match records with all of the following rules:\nFoo\n!= abc\nany\nof:\nFoo\n!= def\nFoo\n= ghi`, + result: `Match all of the following rules:\nFoo\n!= abc\nany\nof:\nFoo\n!= def\nFoo\n= ghi`, }, { domain: `["!", "|", ("foo", "=", "abc"), "&", ("foo", "!=", "def"), "!", ("foo", "=", "ghi")]`, - result: `Match records with all of the following rules:\nFoo\n!= abc\nany\nof:\nFoo\n= def\nFoo\n= ghi`, + result: `Match all of the following rules:\nFoo\n!= abc\nany\nof:\nFoo\n= def\nFoo\n= ghi`, }, ]; @@ -1051,99 +1050,99 @@ QUnit.module("Components", (hooks) => { const toTest = [ { domain: `["!", ("foo", "=", "abc")]`, - result: `Match records with all of the following rules:\nFoo\n!= abc`, + result: `Match all of the following rules:\nFoo\n!= abc`, }, { domain: `["!", "!", ("foo", "=", "abc")]`, - result: `Match records with all of the following rules:\nFoo\n= abc`, + result: `Match all of the following rules:\nFoo\n= abc`, }, { domain: `["!", "!", "!", ("foo", "=", "abc")]`, - result: `Match records with all of the following rules:\nFoo\n!= abc`, + result: `Match all of the following rules:\nFoo\n!= abc`, }, { domain: `["!", "&", ("foo", "=", "abc"), ("foo", "=", "def")]`, - result: `Match records with not all of the following rules:\nFoo\n= abc\nFoo\n= def`, + result: `Match not all of the following rules:\nFoo\n= abc\nFoo\n= def`, }, { domain: `["!", "|", ("foo", "=", "abc"), ("foo", "=", "def")]`, - result: `Match records with none of the following rules:\nFoo\n= abc\nFoo\n= def`, + result: `Match none of the following rules:\nFoo\n= abc\nFoo\n= def`, }, { domain: `["&", "!", ("foo", "=", "abc"), ("foo", "=", "def")]`, - result: `Match records with all of the following rules:\nFoo\n!= abc\nFoo\n= def`, + result: `Match all of the following rules:\nFoo\n!= abc\nFoo\n= def`, }, { domain: `["&", "!", "!", ("foo", "=", "abc"), ("foo", "=", "def")]`, - result: `Match records with all of the following rules:\nFoo\n= abc\nFoo\n= def`, + result: `Match all of the following rules:\nFoo\n= abc\nFoo\n= def`, }, { domain: `["&", ("foo", "=", "abc"), "!", ("foo", "=", "def")]`, - result: `Match records with all of the following rules:\nFoo\n= abc\nFoo\n!= def`, + result: `Match all of the following rules:\nFoo\n= abc\nFoo\n!= def`, }, { domain: `["&", ("foo", "=", "abc"), "!", "!", ("foo", "=", "def")]`, - result: `Match records with all of the following rules:\nFoo\n= abc\nFoo\n= def`, + result: `Match all of the following rules:\nFoo\n= abc\nFoo\n= def`, }, { domain: `["|", "!", ("foo", "=", "abc"), ("foo", "=", "def")]`, - result: `Match records with any of the following rules:\nFoo\n!= abc\nFoo\n= def`, + result: `Match any of the following rules:\nFoo\n!= abc\nFoo\n= def`, }, { domain: `["|", "!", "!", ("foo", "=", "abc"), ("foo", "=", "def")]`, - result: `Match records with any of the following rules:\nFoo\n= abc\nFoo\n= def`, + result: `Match any of the following rules:\nFoo\n= abc\nFoo\n= def`, }, { domain: `["|", ("foo", "=", "abc"), "!", ("foo", "=", "def")]`, - result: `Match records with any of the following rules:\nFoo\n= abc\nFoo\n!= def`, + result: `Match any of the following rules:\nFoo\n= abc\nFoo\n!= def`, }, { domain: `["|", ("foo", "=", "abc"), "!", "!", ("foo", "=", "def")]`, - result: `Match records with any of the following rules:\nFoo\n= abc\nFoo\n= def`, + result: `Match any of the following rules:\nFoo\n= abc\nFoo\n= def`, }, { domain: `["&", "!", "&", ("foo", "=", "abc"), ("foo", "=", "def"), ("foo", "=", "ghi")]`, - result: `Match records with all of the following rules:\nnot all\nof:\nFoo\n= abc\nFoo\n= def\nFoo\n= ghi`, + result: `Match all of the following rules:\nnot all\nof:\nFoo\n= abc\nFoo\n= def\nFoo\n= ghi`, }, { domain: `["&", "!", "|", ("foo", "=", "abc"), ("foo", "=", "def"), ("foo", "=", "ghi")]`, - result: `Match records with all of the following rules:\nnone\nof:\nFoo\n= abc\nFoo\n= def\nFoo\n= ghi`, + result: `Match all of the following rules:\nnone\nof:\nFoo\n= abc\nFoo\n= def\nFoo\n= ghi`, }, { domain: `["|", "!", "&", ("foo", "=", "abc"), ("foo", "=", "def"), ("foo", "=", "ghi")]`, - result: `Match records with any of the following rules:\nnot all\nof:\nFoo\n= abc\nFoo\n= def\nFoo\n= ghi`, + result: `Match any of the following rules:\nnot all\nof:\nFoo\n= abc\nFoo\n= def\nFoo\n= ghi`, }, { domain: `["|", "!", "|", ("foo", "=", "abc"), ("foo", "=", "def"), ("foo", "=", "ghi")]`, - result: `Match records with any of the following rules:\nnone\nof:\nFoo\n= abc\nFoo\n= def\nFoo\n= ghi`, + result: `Match any of the following rules:\nnone\nof:\nFoo\n= abc\nFoo\n= def\nFoo\n= ghi`, }, { domain: `["!", "&", "&", ("foo", "=", "abc"), ("foo", "=", "def"), ("foo", "=", "ghi")]`, - result: `Match records with not all of the following rules:\nFoo\n= abc\nFoo\n= def\nFoo\n= ghi`, + result: `Match not all of the following rules:\nFoo\n= abc\nFoo\n= def\nFoo\n= ghi`, }, { domain: `["!", "|", "|", ("foo", "=", "abc"), ("foo", "=", "def"), ("foo", "=", "ghi")]`, - result: `Match records with none of the following rules:\nFoo\n= abc\nFoo\n= def\nFoo\n= ghi`, + result: `Match none of the following rules:\nFoo\n= abc\nFoo\n= def\nFoo\n= ghi`, }, { domain: `["!", "&", "|", ("foo", "=", "abc"), "!", ("foo", "=", "def"), ("foo", "=", "ghi")]`, - result: `Match records with not all of the following rules:\nany\nof:\nFoo\n= abc\nFoo\n!= def\nFoo\n= ghi`, + result: `Match not all of the following rules:\nany\nof:\nFoo\n= abc\nFoo\n!= def\nFoo\n= ghi`, }, { domain: `["!", "|", "&", ("foo", "=", "abc"), ("foo", "=", "def"), ("foo", "=", "ghi")]`, - result: `Match records with none of the following rules:\nall\nof:\nFoo\n= abc\nFoo\n= def\nFoo\n= ghi`, + result: `Match none of the following rules:\nall\nof:\nFoo\n= abc\nFoo\n= def\nFoo\n= ghi`, }, { domain: `["!", "&", ("foo", "=", "abc"), "|", ("foo", "=", "def"), ("foo", "=", "ghi")]`, - result: `Match records with not all of the following rules:\nFoo\n= abc\nany\nof:\nFoo\n= def\nFoo\n= ghi`, + result: `Match not all of the following rules:\nFoo\n= abc\nany\nof:\nFoo\n= def\nFoo\n= ghi`, }, { domain: `["!", "|", ("foo", "=", "abc"), "&", ("foo", "=", "def"), ("foo", "=", "ghi")]`, - result: `Match records with none of the following rules:\nFoo\n= abc\nall\nof:\nFoo\n= def\nFoo\n= ghi`, + result: `Match none of the following rules:\nFoo\n= abc\nall\nof:\nFoo\n= def\nFoo\n= ghi`, }, { domain: `["!", "|", ("foo", "=", "abc"), "&", ("foo", "=", "def"), "!", ("foo", "=", "ghi")]`, - result: `Match records with none of the following rules:\nFoo\n= abc\nall\nof:\nFoo\n= def\nFoo\n!= ghi`, + result: `Match none of the following rules:\nFoo\n= abc\nall\nof:\nFoo\n= def\nFoo\n!= ghi`, }, ]; @@ -1268,17 +1267,14 @@ QUnit.module("Components", (hooks) => { QUnit.test("button 'New Rule' (edit mode)", async (assert) => { await makeDomainSelector(); assert.containsNone(target, ".o_domain_leaf"); - assert.containsOnce(target, ".o_domain_add_first_node_button"); - assert.containsNone(target, "a[role=button]"); + assert.containsOnce(target, "a[role=button]"); - await click(target, ".o_domain_add_first_node_button"); + await click(target, "a[role=button]"); assert.containsOnce(target, ".o_domain_leaf"); - assert.containsNone(target, ".o_domain_add_first_node_button"); assert.containsOnce(target, "a[role=button]"); await click(target, "a[role=button]"); assert.containsN(target, ".o_domain_leaf", 2); - assert.containsNone(target, ".o_domain_add_first_node_button"); assert.containsOnce(target, "a[role=button]"); }); @@ -2080,4 +2076,81 @@ QUnit.module("Components", (hooks) => { assert.containsNone(target, ".o_ds_value_cell"); assert.verifySteps([`[("product_ids", "!=", False)]`]); }); + + QUnit.test("Include archived button basic use", async (assert) => { + serverData.models.partner.fields.active = { + string: "Active", + type: "boolean", + searchable: true, + }; + await makeDomainSelector({ + isDebugMode: true, + domain: `["&", ("foo", "=", "test"), ("bar", "=", True)]`, + update(domain) { + assert.step(domain); + }, + }); + assert.containsN(target, ".o_domain_leaf", 2); + assert.containsOnce(target, '.form-switch label:contains("Include archived")'); + await click(target, ".form-switch"); + assert.containsN(target, ".o_domain_leaf", 2); + assert.verifySteps([ + '["&", "&", ("foo", "=", "test"), ("bar", "=", True), ("active", "in", [True, False])]', + ]); + await click(target, ".dropdown-toggle"); + await click(target, ".dropdown-menu span:nth-child(2)"); + assert.containsN(target, ".o_domain_leaf", 2); + assert.verifySteps([ + '["&", "|", ("foo", "=", "test"), ("bar", "=", True), ("active", "in", [True, False])]', + ]); + await click(target, ".form-switch"); + assert.containsN(target, ".o_domain_leaf", 2); + assert.verifySteps(['["|", ("foo", "=", "test"), ("bar", "=", True)]']); + }); + + QUnit.test("Include archived on empty tree", async (assert) => { + serverData.models.partner.fields.active = { + string: "Active", + type: "boolean", + searchable: true, + }; + await makeDomainSelector({ + isDebugMode: true, + domain: `[("foo", "=", "test")]`, + update(domain) { + assert.step(domain); + }, + }); + assert.containsOnce(target, ".o_domain_leaf"); + assert.containsOnce(target, '.form-switch label:contains("Include archived")'); + await click(target, ".form-switch"); + assert.containsOnce(target, ".o_domain_leaf"); + assert.verifySteps(['["&", ("foo", "=", "test"), ("active", "in", [True, False])]']); + await click(target, ".o_domain_delete_node_button"); + assert.containsNone(target, ".o_domain_leaf"); + assert.verifySteps(['[("active", "in", [True, False])]']); + await click(target, ".form-switch"); + assert.verifySteps(["[]"]); + await click(target, ".form-switch"); + assert.containsNone(target, ".o_domain_leaf"); + assert.verifySteps(['[("active", "in", [True, False])]']); + await click(target, "a[role=button]"); + assert.containsOnce(target, ".o_domain_leaf"); + assert.verifySteps(['["&", ("id", "=", 1), ("active", "in", [True, False])]']); + }); + + QUnit.test( + "Include archived not shown when model doesn't have the active field", + async (assert) => { + await makeDomainSelector({ + isDebugMode: true, + domain: `[("foo", "=", "test")]`, + update(domain) { + assert.step(domain); + }, + }); + assert.containsOnce(target, ".o_domain_leaf"); + assert.containsNone(target, '.form-switch label:contains("Include archived")'); + } + ); }); diff --git a/addons/web/static/tests/search/search_bar_tests.js b/addons/web/static/tests/search/search_bar_tests.js index b8e5142a820..f15d9f3a9fe 100644 --- a/addons/web/static/tests/search/search_bar_tests.js +++ b/addons/web/static/tests/search/search_bar_tests.js @@ -1476,7 +1476,7 @@ QUnit.module("Search", (hooks) => { assert.containsNone(target, ".o_domain_leaf"); assert.ok(target.querySelector(".modal footer button").disabled); - await click(target, ".modal .o_domain_add_first_node_button"); + await click(target, ".modal .o_domain_tree a[role=button]"); assert.containsOnce(target, ".o_domain_leaf"); assert.strictEqual(target.querySelector(".o_model_field_selector_value").innerText, "ID"); assert.strictEqual(target.querySelector(".o_domain_leaf_operator_select").value, "="); diff --git a/addons/web/static/tests/views/fields/domain_field_tests.js b/addons/web/static/tests/views/fields/domain_field_tests.js index 37605738101..fad92e86ae9 100644 --- a/addons/web/static/tests/views/fields/domain_field_tests.js +++ b/addons/web/static/tests/views/fields/domain_field_tests.js @@ -181,13 +181,12 @@ QUnit.module("Fields", (hooks) => { `, }); - // As the domain is empty, there should be a button to add the first - // domain part - assert.containsOnce(target, ".o_domain_add_first_node_button"); + // As the domain is empty, there should be a button to add a new rule + assert.containsOnce(target, ".o_domain_tree a[role=button]"); // Clicking on the button should add the [["id", "=", "1"]] domain, so // there should be a field selector in the DOM - await click(target, ".o_domain_add_first_node_button"); + await click(target, ".o_domain_tree a[role=button]"); assert.containsOnce(target, ".o_model_field_selector", "there should be a field selector"); // Focusing the field selector input should open the field selector @@ -242,7 +241,7 @@ QUnit.module("Fields", (hooks) => { `, }); - await click(target, ".o_domain_add_first_node_button"); + await click(target, ".o_domain_tree a[role=button]"); await click(target, ".o_model_field_selector"); await click( document.body.querySelector( @@ -930,7 +929,7 @@ QUnit.module("Fields", (hooks) => { assert.containsNone(target, ".modal"); await click(target, ".o_field_domain_dialog_button"); assert.containsOnce(target, ".modal"); - await click(target, ".modal .o_domain_add_first_node_button"); + await click(target, ".modal .o_domain_tree a[role=button]"); await click(target, ".modal-footer .btn-primary"); assert.containsOnce(target, ".o_domain_leaf"); assert.strictEqual(target.querySelector(".o_domain_leaf").textContent, "ID = 1"); @@ -957,7 +956,7 @@ QUnit.module("Fields", (hooks) => { await click(target, ".o_field_domain_dialog_button"); assert.containsOnce(target, ".modal"); - await click(target, ".modal .o_domain_add_first_node_button"); + await click(target, ".modal .o_domain_tree a[role=button]"); await editInput(target, ".o_domain_debug_input", "[(0, '=', expr)]"); await click(target, ".modal-footer .btn-primary"); assert.containsOnce(target, ".modal", "the domain is invalid: the dialog is not closed"); @@ -1027,13 +1026,12 @@ QUnit.module("Fields", (hooks) => { // Unfold the domain await click(target, ".o_field_domain > div > div"); - // As the domain is empty, there should be a button to add the first - // domain part - assert.containsOnce(target, ".o_domain_add_first_node_button"); + // As the domain is empty, there should be a button to add a new rule + assert.containsOnce(target, ".o_domain_tree a[role=button]"); // Clicking on the button should add the [["id", "=", "1"]] domain, so // there should be a field selector in the DOM - await click(target, ".o_domain_add_first_node_button"); + await click(target, ".o_domain_tree a[role=button]"); assert.containsOnce(target, ".o_model_field_selector"); // Focusing the field selector input should open the field selector