From 4cfe0e4b2d6fb157d87ceeb7aaf1034249294442 Mon Sep 17 00:00:00 2001 From: FrancoisGe Date: Tue, 1 Mar 2022 09:53:51 +0000 Subject: [PATCH] [IMP] web: Command Palette Footer Clickable With this commit, it will be possible to click on the different namespace in the footer of the command palette to insert the namespace value directly into the searchValue. The purpose of this feature is to make it easier to discover how namespaces work. closes odoo/odoo#82773 Signed-off-by: Aaron Bohy (aab) --- .../src/core/commands/command_palette.js | 11 ++- .../src/core/commands/command_palette.scss | 6 ++ .../src/core/commands/command_palette.xml | 2 +- .../src/core/commands/command_service.js | 8 ++- .../core/commands/command_service_tests.js | 68 +++++++++++++++++++ 5 files changed, 92 insertions(+), 3 deletions(-) diff --git a/addons/web/static/src/core/commands/command_palette.js b/addons/web/static/src/core/commands/command_palette.js index 85ed664ca35..72218535caf 100644 --- a/addons/web/static/src/core/commands/command_palette.js +++ b/addons/web/static/src/core/commands/command_palette.js @@ -82,7 +82,7 @@ export class CommandPalette extends Component { this.DefaultCommandItem = DefaultCommandItem; this.activeElement = useService("ui").activeElement; this.defaultDebounceSearch = debounce.apply(this, [this.search, 0]); - useAutofocus(); + this.inputRef = useAutofocus(); useHotkey("Enter", () => this.executeSelectedCommand(), { bypassEditableProtection: true }); useHotkey("ArrowUp", () => this.selectCommandAndScrollTo("PREV"), { @@ -267,6 +267,9 @@ export class CommandPalette extends Component { searchValue, activeElement: this.activeElement, }); + if (this.inputRef.el) { + this.inputRef.el.focus(); + } } debounceSearch(value) { @@ -299,5 +302,11 @@ export class CommandPalette extends Component { } return { namespace, searchValue }; } + + switchNamespace(namespace) { + const searchValue = `${namespace}${this.clearSearchValue}`; + this.state.searchValue = searchValue; + this.debounceSearch(searchValue); + } } CommandPalette.template = "web.CommandPalette"; diff --git a/addons/web/static/src/core/commands/command_palette.scss b/addons/web/static/src/core/commands/command_palette.scss index 2d09af1b9ee..37676908fc3 100644 --- a/addons/web/static/src/core/commands/command_palette.scss +++ b/addons/web/static/src/core/commands/command_palette.scss @@ -122,6 +122,12 @@ padding: 0.6rem 1.3em; border-top: 1px solid rgba(0, 0, 0, 0.1); + .o_namespace:hover { + color: $o-brand-primary; + cursor: pointer; + text-decoration: underline dotted; + } + .o_promote { color: $o-brand-primary; font-weight: 900; diff --git a/addons/web/static/src/core/commands/command_palette.xml b/addons/web/static/src/core/commands/command_palette.xml index 278487c8c2a..be8979e3d0c 100644 --- a/addons/web/static/src/core/commands/command_palette.xml +++ b/addons/web/static/src/core/commands/command_palette.xml @@ -37,7 +37,7 @@ diff --git a/addons/web/static/src/core/commands/command_service.js b/addons/web/static/src/core/commands/command_service.js index c0f117cd3a2..4a380e9a747 100644 --- a/addons/web/static/src/core/commands/command_service.js +++ b/addons/web/static/src/core/commands/command_service.js @@ -43,6 +43,10 @@ class DefaultFooter extends Component { .map((el) => ({ namespace: el[0], name: el[1].name })) .filter((el) => el.name); } + + onClick(namespace) { + this.props.switchNamespace(namespace); + } } DefaultFooter.template = xml` @@ -50,7 +54,9 @@ DefaultFooter.template = xml` , and - + + + `; diff --git a/addons/web/static/tests/core/commands/command_service_tests.js b/addons/web/static/tests/core/commands/command_service_tests.js index 20d11960235..61fb53c601d 100644 --- a/addons/web/static/tests/core/commands/command_service_tests.js +++ b/addons/web/static/tests/core/commands/command_service_tests.js @@ -490,6 +490,74 @@ QUnit.test("footer displays the right tips", async (assert) => { ); }); +QUnit.test("namespaces display in the footer are still clickable", async (assert) => { + const action = () => {}; + clearRegistryWithCleanup(commandProviderRegistry); + commandProviderRegistry.add("@", { + namespace: "@", + provide: () => [ + { + name: "Command@", + action, + }, + ], + }); + commandProviderRegistry.add("#", { + namespace: "#", + provide: () => [ + { + name: "Command#", + action, + }, + ], + }); + + const commandSetupRegistry = registry.category("command_setup"); + clearRegistryWithCleanup(commandSetupRegistry); + commandSetupRegistry.add("default", {}); + commandSetupRegistry.add("@", { + name: "users", + }); + commandSetupRegistry.add("#", { + name: "channels", + }); + await mount(TestComponent, target, { env }); + + // Open palette + triggerHotkey("control+k"); + await nextTick(); + assert.strictEqual( + target.querySelector(".o_command_palette_footer").textContent, + "TIP — search for @users and #channels" + ); + assert.deepEqual( + [...target.querySelectorAll(".o_command")].map((el) => el.textContent), + [] + ); + + await click(target.querySelectorAll(".o_command_palette_footer .o_namespace")[0]); + assert.strictEqual(target.querySelector(".o_command_palette_search input").value, "@"); + assert.deepEqual( + [...target.querySelectorAll(".o_command")].map((el) => el.textContent), + ["Command@"] + ); + + await editSearchBar("Com"); + await click(target.querySelectorAll(".o_command_palette_footer .o_namespace")[1]); + assert.strictEqual(target.querySelector(".o_command_palette_search input").value, "#Com"); + assert.deepEqual( + [...target.querySelectorAll(".o_command")].map((el) => el.textContent), + ["Command#"] + ); + + await click(target.querySelectorAll(".o_command_palette_footer .o_namespace")[0]); + assert.strictEqual(target.querySelector(".o_command_palette_search input").value, "@Com"); + assert.deepEqual( + [...target.querySelectorAll(".o_command")].map((el) => el.textContent), + ["Command@"] + ); +}); + QUnit.test("defined multiple providers with the same namespace", async (assert) => { assert.expect(2);