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);