diff --git a/addons/mail/static/src/webclient/commands/command_category.js b/addons/mail/static/src/webclient/commands/command_category.js index 82b81dd4cc9..517b854168b 100644 --- a/addons/mail/static/src/webclient/commands/command_category.js +++ b/addons/mail/static/src/webclient/commands/command_category.js @@ -1,7 +1,6 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; -import { _lt } from "@web/core/l10n/translation"; const commandCategoryRegistry = registry.category("command_categories"); commandCategoryRegistry.add("mail", {}, { sequence: 20 }); diff --git a/addons/mail/static/src/webclient/commands/mail_providers.js b/addons/mail/static/src/webclient/commands/mail_providers.js index 0208048cee7..3a5443ed0cc 100644 --- a/addons/mail/static/src/webclient/commands/mail_providers.js +++ b/addons/mail/static/src/webclient/commands/mail_providers.js @@ -14,9 +14,15 @@ DialogCommand.template = xml` `; -const commandEmptyMessageRegistry = registry.category("command_empty_list"); -commandEmptyMessageRegistry.add("@", _lt("No user found")); -commandEmptyMessageRegistry.add("#", _lt("No channel found")); +const commandSetupRegistry = registry.category("command_setup"); +commandSetupRegistry.add("@", { + emptyMessage: _lt("No user found"), + name: _lt("users"), +}); +commandSetupRegistry.add("#", { + emptyMessage: _lt("No channel found"), + name: _lt("channels"), +}); const commandProviderRegistry = registry.category("command_provider"); commandProviderRegistry.add("partner", { diff --git a/addons/web/static/src/core/commands/command_palette.js b/addons/web/static/src/core/commands/command_palette.js index 22b5e8ea4e0..605cfab33b6 100644 --- a/addons/web/static/src/core/commands/command_palette.js +++ b/addons/web/static/src/core/commands/command_palette.js @@ -12,7 +12,7 @@ const { Component, hooks } = owl; const { onWillStart, useState } = hooks; const DEFAULT_PLACEHOLDER = _lt("Search..."); -const DEFAULT_EMPTY_MESSAGE = _lt("No results found"); +const DEFAULT_EMPTY_MESSAGE = _lt("No result found"); const FUZZY_NAMESPACES = ["default"]; /** @@ -37,7 +37,7 @@ const FUZZY_NAMESPACES = ["default"]; * @typedef {{ * categoriesByNamespace?: {[namespace]: string[]}; * emptyMessageByNamespace?: {[namespace]: string}; - * footerTemplate?: string; + * footerComponent?: Component; * placeholder?: string; * providers: Provider[]; * searchValue?: string; @@ -84,7 +84,7 @@ export class CommandPalette extends Component { /** * @type {{ commands: CommandItem[], * emptyMessage: string, - * footerTemplate: string, + * footerComponent: Component, * placeholder: string, * searchValue: string, * selectedCommand: CommandItem }} @@ -130,7 +130,7 @@ export class CommandPalette extends Component { this.emptyMessageByNamespace = config.emptyMessageByNamespace || {}; this.providersByNamespace = result; - this.state.footerTemplate = config.footerTemplate; + this.state.footerComponent = config.footerComponent; this.state.placeholder = config.placeholder || DEFAULT_PLACEHOLDER.toString(); diff --git a/addons/web/static/src/core/commands/command_palette.xml b/addons/web/static/src/core/commands/command_palette.xml index 7abfb172ff2..39c4f8877c0 100644 --- a/addons/web/static/src/core/commands/command_palette.xml +++ b/addons/web/static/src/core/commands/command_palette.xml @@ -28,8 +28,8 @@ - diff --git a/addons/web/static/src/core/commands/command_service.js b/addons/web/static/src/core/commands/command_service.js index e3289c648d6..308073a7452 100644 --- a/addons/web/static/src/core/commands/command_service.js +++ b/addons/web/static/src/core/commands/command_service.js @@ -2,6 +2,7 @@ import { registry } from "@web/core/registry"; import { CommandPaletteDialog } from "./command_palette_dialog"; +const { Component } = owl; const { xml } = owl.tags; @@ -33,12 +34,25 @@ const { xml } = owl.tags; */ const commandCategoryRegistry = registry.category("command_categories"); -const commandEmptyMessageRegistry = registry.category("command_empty_list"); const commandProviderRegistry = registry.category("command_provider"); +const commandSetupRegistry = registry.category("command_setup"); -const footerTemplate = xml` +class DefaultFooter extends Component { + setup() { + this.elements = commandSetupRegistry + .getEntries() + .map((el) => ({ namespace: el[0], name: el[1].name })) + .filter((el) => el.name); + } +} +DefaultFooter.template = xml` - TIP — search for @users, #channels, and /menus + TIP — search for + + , + and + + `; @@ -70,14 +84,16 @@ export const commandService = { }); const emptyMessageByNamespace = {}; - commandEmptyMessageRegistry.getEntries().forEach(([key, message]) => { - emptyMessageByNamespace[key] = message.toString(); + commandSetupRegistry.getEntries().forEach(([key, { emptyMessage }]) => { + if (emptyMessage) { + emptyMessageByNamespace[key] = emptyMessage.toString(); + } }); config = Object.assign( { categoriesByNamespace, emptyMessageByNamespace, - footerTemplate, + footerComponent: DefaultFooter, placeholder: env._t("Search for a command..."), providers: commandProviderRegistry.getAll(), }, diff --git a/addons/web/static/src/core/commands/default_providers.js b/addons/web/static/src/core/commands/default_providers.js index 6f90f228b46..7c7398ab4a3 100644 --- a/addons/web/static/src/core/commands/default_providers.js +++ b/addons/web/static/src/core/commands/default_providers.js @@ -10,6 +10,11 @@ import { DefaultCommandItem } from "./command_palette"; const { Component } = owl; +const commandSetupRegistry = registry.category("command_setup"); +commandSetupRegistry.add("default", { + emptyMessage: _lt("No command found"), +}); + export class HotkeyCommandItem extends Component { setup() { useHotkey(this.props.hotkey, () => { @@ -29,11 +34,8 @@ export class HotkeyCommandItem extends Component { } } HotkeyCommandItem.template = "web.HotkeyCommandItem"; -const commandEmptyMessageRegistry = registry.category("command_empty_list"); -commandEmptyMessageRegistry.add("default", _lt("No commands found")); const commandCategoryRegistry = registry.category("command_categories"); - const commandProviderRegistry = registry.category("command_provider"); commandProviderRegistry.add("command", { provide: (env, options = {}) => { diff --git a/addons/web/static/src/core/debug/debug_menu.js b/addons/web/static/src/core/debug/debug_menu.js index 12ad50e6e6f..78f526336c0 100644 --- a/addons/web/static/src/core/debug/debug_menu.js +++ b/addons/web/static/src/core/debug/debug_menu.js @@ -41,7 +41,7 @@ export class DebugMenu extends DebugMenuBasic { categoriesByNamespace: { default: defaultCategories, }, - emptyMessageByNamespace: { default: this.env._t("No commands found") }, + emptyMessageByNamespace: { default: this.env._t("No command found") }, placeholder: this.env._t("Choose a debug command..."), providers: [provider], }; diff --git a/addons/web/static/src/webclient/menus/menu_providers.js b/addons/web/static/src/webclient/menus/menu_providers.js index 3a4e3789f1e..3c0bcd62815 100644 --- a/addons/web/static/src/webclient/menus/menu_providers.js +++ b/addons/web/static/src/webclient/menus/menu_providers.js @@ -14,8 +14,11 @@ const commandCategoryRegistry = registry.category("command_categories"); commandCategoryRegistry.add("apps", { namespace: "/" }, { sequence: 10 }); commandCategoryRegistry.add("menu_items", { namespace: "/" }, { sequence: 20 }); -const commandEmptyMessageRegistry = registry.category("command_empty_list"); -commandEmptyMessageRegistry.add("/", _lt("No menu found")); +const commandSetupRegistry = registry.category("command_setup"); +commandSetupRegistry.add("/", { + emptyMessage: _lt("No menu found"), + name: _lt("menus"), +}); const commandProviderRegistry = registry.category("command_provider"); commandProviderRegistry.add("menu", { diff --git a/addons/web/static/tests/core/commands/command_palette_tests.js b/addons/web/static/tests/core/commands/command_palette_tests.js index b4fdaf5e6d4..3ebfaa608f3 100644 --- a/addons/web/static/tests/core/commands/command_palette_tests.js +++ b/addons/web/static/tests/core/commands/command_palette_tests.js @@ -26,7 +26,8 @@ let target; let testComponent; const serviceRegistry = registry.category("services"); -const footerTemplate = xml`My footer`; +class footerComponent extends Component {} +footerComponent.template = xml`My footer`; class TestComponent extends Component { get DialogContainer() { @@ -78,7 +79,7 @@ QUnit.test("empty providers", async (assert) => { assert.containsOnce(target, ".o_command_palette_listbox_empty"); assert.strictEqual( target.querySelector(".o_command_palette_listbox_empty").textContent, - "No results found" + "No result found" ); assert.strictEqual( target.querySelector(".o_command_palette_search input").placeholder, @@ -153,7 +154,7 @@ QUnit.test("add a footer", async (assert) => { testComponent = await mount(TestComponent, { env, target }); const config = { providers: [], - footerTemplate, + footerComponent, }; env.services.dialog.add(CommandPaletteDialog, { config, @@ -962,7 +963,7 @@ QUnit.test("multi level command", async (assert) => { ]; const config = { emptyMessageByNamespace, - footerTemplate, + footerComponent, placeholder: "placeholder test", providers, }; @@ -1003,7 +1004,7 @@ QUnit.test("multi level command", async (assert) => { await editSearchBar("empty"); assert.strictEqual( target.querySelector(".o_command_palette_listbox_empty").textContent, - "No results found" + "No result found" ); assert.strictEqual( target.querySelector(".o_command_palette_search input").placeholder, 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 690462c49eb..6981a25b0b0 100644 --- a/addons/web/static/tests/core/commands/command_service_tests.js +++ b/addons/web/static/tests/core/commands/command_service_tests.js @@ -394,10 +394,14 @@ QUnit.test("configure the empty message based on the namespace", async (assert) provide: () => [], }); - const commandEmptyMessageRegistry = registry.category("command_empty_list"); - clearRegistryWithCleanup(commandEmptyMessageRegistry); - commandEmptyMessageRegistry.add("default", "Empty Default"); - commandEmptyMessageRegistry.add("@", "Empty @"); + const commandSetupRegistry = registry.category("command_setup"); + clearRegistryWithCleanup(commandSetupRegistry); + commandSetupRegistry.add("default", { + emptyMessage: "Empty Default", + }); + commandSetupRegistry.add("@", { + emptyMessage: "Empty @", + }); testComponent = await mount(TestComponent, { env, target }); @@ -417,6 +421,74 @@ QUnit.test("configure the empty message based on the namespace", async (assert) ); }); +QUnit.test("footer displays the right tips", async (assert) => { + assert.expect(3); + + clearRegistryWithCleanup(commandProviderRegistry); + + commandProviderRegistry.add("default", { + namespace: "default", + provide: () => [], + }); + + commandProviderRegistry.add("@", { + namespace: "@", + provide: () => [], + }); + + commandProviderRegistry.add("!", { + namespace: "!", + provide: () => [], + }); + + commandProviderRegistry.add("#", { + namespace: "#", + provide: () => [], + }); + + const commandSetupRegistry = registry.category("command_setup"); + clearRegistryWithCleanup(commandSetupRegistry); + commandSetupRegistry.add("default", {}); + commandSetupRegistry.add("@", { + name: "FirstName", + }); + + testComponent = await mount(TestComponent, { env, target }); + + // Open palette + triggerHotkey("control+k"); + await nextTick(); + assert.strictEqual( + target.querySelector(".o_command_palette_footer").textContent, + "TIP — search for @FirstName" + ); + + // Close palette + triggerHotkey("escape"); + commandSetupRegistry.add("!", { + name: "SecondName", + }); + // Open palette + triggerHotkey("control+k"); + await nextTick(); + assert.strictEqual( + target.querySelector(".o_command_palette_footer").textContent, + "TIP — search for @FirstName and !SecondName" + ); + // Close palette + triggerHotkey("escape"); + commandSetupRegistry.add("#", { + name: "ThirdName", + }); + // Open palette + triggerHotkey("control+k"); + await nextTick(); + assert.strictEqual( + target.querySelector(".o_command_palette_footer").textContent, + "TIP — search for @FirstName, !SecondName and #ThirdName" + ); +}); + QUnit.test("defined multiple providers with the same namespace", async (assert) => { assert.expect(2);