From 129bb263f0c2c9d57bf9eeaa2de468ae14f9505c Mon Sep 17 00:00:00 2001 From: Jorge Pinna Puissant Date: Mon, 29 Aug 2022 13:29:40 +0000 Subject: [PATCH] [FIX] web: SettingsFormView - avoid searching hidden settings When searching a text of a hidden field (for example, "gate"), the setting itself will not be shown, but the group title, and the app Search Header will be shown. This issue arise because, we use an if condition with all the label of all the fields (hidden or not) in the group (or app) to decide if the group title or the app header will be showed. Now, we modify this to hide (d-none) the group title or the app header if there is not a settings below them. Part-of: odoo/odoo#99205 --- .../settings_form_view/settings/setting.js | 48 +++++ .../settings_form_view/settings/setting.xml | 8 + .../settings/settings_app.js | 19 +- .../settings/settings_app.xml | 2 +- .../settings/settings_container.js | 57 ++++++ .../settings/settings_container.xml | 10 ++ .../settings_form_compiler.js | 165 ++++++------------ .../settings_form_controller.js | 7 +- .../settings_form_renderer.js | 17 +- .../widgets/res_config_dev_tool.js | 6 + .../widgets/res_config_dev_tool.xml | 9 +- .../settings_form_view_tests.js | 106 +++++++++-- .../views/res_config_settings_views.xml | 2 +- 13 files changed, 308 insertions(+), 148 deletions(-) create mode 100644 addons/web/static/src/webclient/settings_form_view/settings/setting.js create mode 100644 addons/web/static/src/webclient/settings_form_view/settings/setting.xml create mode 100644 addons/web/static/src/webclient/settings_form_view/settings/settings_container.js create mode 100644 addons/web/static/src/webclient/settings_form_view/settings/settings_container.xml diff --git a/addons/web/static/src/webclient/settings_form_view/settings/setting.js b/addons/web/static/src/webclient/settings_form_view/settings/setting.js new file mode 100644 index 00000000000..0d3642e7b4b --- /dev/null +++ b/addons/web/static/src/webclient/settings_form_view/settings/setting.js @@ -0,0 +1,48 @@ +/** @odoo-module **/ + +import { escapeRegExp } from "@web/core/utils/strings"; + +const { Component, useState, useChildSubEnv } = owl; + +export class Setting extends Component { + setup() { + this.state = useState({ + search: this.env.searchState, + showAllContainer: this.env.showAllContainer, + }); + // Don't search on a header setting + if (this.props.type === "header") { + useChildSubEnv({ searchState: { value: "" } }); + } + this.labels = this.props.labels || []; + } + visible() { + if (!this.state.search.value) { + return true; + } + // Always shown a header setting + if (this.props.type === "header") { + return true; + } + if (this.state.showAllContainer.showAllContainer) { + return true; + } + const regexp = new RegExp(escapeRegExp(this.state.search.value), "i"); + if (regexp.test(this.labels.join())) { + return true; + } + return false; + } + + get classNames() { + const { class: _class, type } = this.props; + const classNames = { + o_setting_box: true, + o_searchable_setting: this.labels.length && type !== "header", + [_class]: Boolean(_class), + }; + + return classNames; + } +} +Setting.template = "web.Setting"; diff --git a/addons/web/static/src/webclient/settings_form_view/settings/setting.xml b/addons/web/static/src/webclient/settings_form_view/settings/setting.xml new file mode 100644 index 00000000000..43f85cf0666 --- /dev/null +++ b/addons/web/static/src/webclient/settings_form_view/settings/setting.xml @@ -0,0 +1,8 @@ + + + +
+ +
+
+
diff --git a/addons/web/static/src/webclient/settings_form_view/settings/settings_app.js b/addons/web/static/src/webclient/settings_form_view/settings/settings_app.js index b5690da131d..c9c693a5993 100644 --- a/addons/web/static/src/webclient/settings_form_view/settings/settings_app.js +++ b/addons/web/static/src/webclient/settings_form_view/settings/settings_app.js @@ -1,12 +1,29 @@ /** @odoo-module **/ -const { Component, useState } = owl; +const { Component, useState, useEffect, useRef } = owl; export class SettingsApp extends Component { setup() { this.state = useState({ search: this.env.searchState, }); + this.settingsAppRef = useRef("settingsApp"); + useEffect( + () => { + if (this.settingsAppRef.el) { + const force = + this.state.search.value && + !this.settingsAppRef.el.querySelector( + ".o_settings_container:not(.d-none)" + ) && + !this.settingsAppRef.el.querySelector( + ".o_setting_box.o_searchable_setting" + ); + this.settingsAppRef.el.classList.toggle("d-none", force); + } + }, + () => [this.state.search.value] + ); } } SettingsApp.template = "web.SettingsApp"; diff --git a/addons/web/static/src/webclient/settings_form_view/settings/settings_app.xml b/addons/web/static/src/webclient/settings_form_view/settings/settings_app.xml index 24e43cb8ce0..5724316db6e 100644 --- a/addons/web/static/src/webclient/settings_form_view/settings/settings_app.xml +++ b/addons/web/static/src/webclient/settings_form_view/settings/settings_app.xml @@ -1,7 +1,7 @@ -
+
@@ -129,7 +153,7 @@ QUnit.module("SettingsFormView", (hooks) => { ["this is bar", "this is big bar", "this is foo"] ); assert.deepEqual( - [...target.querySelectorAll(".settings h2")].map((x) => x.textContent), + [...target.querySelectorAll(".settings h2:not(.d-none)")].map((x) => x.textContent), ["Title of group Bar", "Title of group Foo"] ); assert.doesNotHaveClass(target.querySelector(".o_form_editable"), "o_form_nosheet"); @@ -138,6 +162,10 @@ QUnit.module("SettingsFormView", (hooks) => { target.querySelector(".o_searchview input"), "searchview input should be focused" ); + assert.containsOnce( + target, + ".app_settings_block:not(.d-none) .app_settings_header .o_setting_box" + ); await editSearch(target, "Hello there"); await execTimeouts(); @@ -146,6 +174,10 @@ QUnit.module("SettingsFormView", (hooks) => { "Hello there", "input value should be updated" ); + assert.containsNone( + target, + ".app_settings_block:not(.d-none) .app_settings_header .o_setting_box" + ); await editSearch(target, "b"); await execTimeouts(); @@ -161,10 +193,14 @@ QUnit.module("SettingsFormView", (hooks) => { ); assert.deepEqual( - [...target.querySelectorAll(".settings h2")].map((x) => x.textContent), + [...target.querySelectorAll(".settings h2:not(.d-none)")].map((x) => x.textContent), ["Title of group Bar"], "The title of group Bar is also selected" ); + assert.containsOnce( + target, + ".app_settings_block:not(.d-none) .app_settings_header .o_setting_box" + ); await editSearch(target, "Big"); await execTimeouts(); @@ -174,10 +210,14 @@ QUnit.module("SettingsFormView", (hooks) => { "Only 'Big Bar' is shown" ); assert.deepEqual( - [...target.querySelectorAll(".settings h2")].map((x) => x.textContent), + [...target.querySelectorAll(".settings h2:not(.d-none)")].map((x) => x.textContent), ["Title of group Bar"], "The title of group Bar is also selected" ); + assert.containsOnce( + target, + ".app_settings_block:not(.d-none) .app_settings_header .o_setting_box" + ); await editSearch(target, "group Bar"); await execTimeouts(); @@ -186,6 +226,10 @@ QUnit.module("SettingsFormView", (hooks) => { ["Bar", "This is Big BAR"], "When searching a title, all group is shown" ); + assert.containsOnce( + target, + ".app_settings_block:not(.d-none) .app_settings_header .o_setting_box" + ); await editSearch(target, "bx"); await execTimeouts(); @@ -194,18 +238,44 @@ QUnit.module("SettingsFormView", (hooks) => { target.querySelector(".o_nocontent_help"), "record not found message shown" ); + assert.containsNone( + target, + ".app_settings_block:not(.d-none) .app_settings_header .o_setting_box" + ); + await editSearch(target, "Fo"); await execTimeouts(); assert.strictEqual( target.querySelector(".highlighter").textContent, "Fo", - "F word highlighted" + "Fo word highlighted" ); assert.deepEqual( [...target.querySelectorAll(".o_setting_box .o_form_label")].map((x) => x.textContent), ["Foo"], "only Foo is shown" ); + assert.containsOnce( + target, + ".app_settings_block:not(.d-none) .app_settings_header .o_setting_box" + ); + + await editSearch(target, "Hide"); + await execTimeouts(); + assert.deepEqual( + [...target.querySelectorAll(".settings h2:not(.d-none)")].map((x) => x.textContent), + [], + "Hide settings should not be shown" + ); + assert.deepEqual( + [...target.querySelectorAll(".o_setting_box .o_form_label")].map((x) => x.textContent), + [], + "Hide settings should not be shown" + ); + assert.containsNone( + target, + ".app_settings_block:not(.d-none) .app_settings_header .o_setting_box" + ); }); QUnit.test("unhighlight section not matching anymore", async function (assert) { @@ -303,16 +373,20 @@ QUnit.module("SettingsFormView", (hooks) => {
`, }); - assert.containsOnce(target, ".o_setting_tip", "Tip should not be hidden initially"); + assert.containsOnce( + target, + ".o_setting_tip:not(.d-none)", + "Tip should not be hidden initially" + ); await editSearch(target, "below"); await execTimeouts(); - assert.containsOnce(target, ".o_setting_tip", "Tip should not be hidden"); + assert.containsOnce(target, ".o_setting_tip:not(.d-none)", "Tip should not be hidden"); await editSearch(target, "Foo"); await execTimeouts(); - assert.containsNone(target, ".o_setting_tip", "Tip should not be displayed"); + assert.containsNone(target, ".o_setting_tip:not(.d-none)", "Tip should not be displayed"); await editSearch(target, ""); await execTimeouts(); - assert.containsOnce(target, ".o_setting_tip", "Tip should not be hidden"); + assert.containsOnce(target, ".o_setting_tip:not(.d-none)", "Tip should not be hidden"); }); QUnit.test( @@ -601,11 +675,11 @@ QUnit.module("SettingsFormView", (hooks) => { await doAction(webClient, 1); assert.containsOnce(target, ".o_form_label"); assert.equal(target.querySelector(".o_form_label").textContent, ""); - assert.containsNone(target, ".settingSearchHeader"); + assert.containsNone(target, ".app_settings_block:not(.d-none) .settingSearchHeader"); await editSearch(target, "Fo"); await execTimeouts(); assert.containsNone(target, ".o_form_label"); - assert.containsNone(target, ".settingSearchHeader"); + assert.containsNone(target, ".app_settings_block:not(.d-none) .settingSearchHeader"); }); QUnit.test( @@ -1018,7 +1092,15 @@ QUnit.module("SettingsFormView", (hooks) => {
-
+
+
`, @@ -1351,7 +1433,7 @@ QUnit.module("SettingsFormView", (hooks) => { const expectedCompiled = `
- + diff --git a/addons/website/views/res_config_settings_views.xml b/addons/website/views/res_config_settings_views.xml index 0943d126543..5368f5a9acd 100644 --- a/addons/website/views/res_config_settings_views.xml +++ b/addons/website/views/res_config_settings_views.xml @@ -20,7 +20,7 @@
-