Enable Dark Mode!
how-to-customize-odoo-command-palette-in-odoo-19.jpg
By: Abhijith CK

How to Customize Odoo Command Palette in Odoo 19

Technical Odoo 19 Odoo Community Odoo Enterprises

One of the best UX features available for users, admins, and developers is Odoo's Command Palette (triggered by using Ctrl+K). In the Odoo 19 framework, there is an API provided to users for customizing the command palette via registries.

In this blog post, let us understand the internal workings of the Odoo 19 Command Palette service. We will learn how to register global actions, namespace searching with @ or # triggers, making dynamic RPC calls based on user inputs, and rendering custom results using OWL.

1. Architectural Blueprint: How the Command Service Works

The Odoo command palette relies on the package @web/core/registry. Two different types of categories are used for categorizing the registry handlers in the command palette:

  • command_setup: This is used for setting up the command namespaces. The namespace becomes active depending upon the key prefix in the keyboard (? or /).
  • command_provider: This is used for declaring the provider which contains the function provide(env, options). Odoo calls this function when the user enters anything in the palette.

2. Step 1: Registering a Global Quick-Action

We will start by creating an action globally without having to use any namespace prefix. In this case, an action named “System: Reset Local Cache” which would reset the browser’s cache and reload the page.

Create a new file at the below-mentioned location for your custom module:

/** @odoo-module **/
import { registry } from "@web/core/registry";
import { _t } from "@web/core/l10n/translation";
registry.category("command_provider").add("clear_cache_provider", {
    async provide(env, options) {
        return [
            {
                name: _t("System: Reset Local Cache"),
                category: "tools",
                action: () => {
                    localStorage.clear();
                    sessionStorage.clear();
                    window.location.reload();
                },
            },
        ];
    },
});

Each time the user uses the command palette, the suggestion shall be shown in the “Tools” menu, or the user can find it by searching “cache”.

3. Step 2: Creating a Custom Namespace (e.g., # to Search Open Tasks)

Sometimes, there is a requirement to filter items with a prefix dynamically. This can be done by creating a custom namespace “#” through which developers can search project tasks by name.

1. Register the Namespace Setup

We will be using the command_setup registry for setting up the prefix, placeholder, and the debounce timeout in order to not flood our database with RPCs.

// static/src/js/task_command_provider.js
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { _t } from "@web/core/l10n/translation";
// 1. Setup the '#' namespace
registry.category("command_setup").add("#", {
    name: _t("Search Tasks"),
    placeholder: _t("Search tasks by name..."),
    debounceDelay: 300, // wait 300ms after typing before triggering search
});

2. Implementation of Command Provider Using RPC Search

The next step is to create a provider in command_provider with the ‘#’ namespace. The searching will be done using the ORM service of Odoo.

//  Register the provider associated with '#'
registry.category("command_provider").add("task_provider", {
    namespace: "#",
    async provide(env, options) {
        // Whatever the user entered in after the '#' trigger is in the 'options.searchValue'
        const searchVal = options.searchValue || "";
        const orm = env.services.orm;
        const actionService = env.services.action;
        try {
             // Retrieve up to 5 tasks that match the search criteria
            const tasks = await orm.searchRead(
                "project.task",
                [["name", "ilike", searchVal]],
                ["id", "name", "project_id"]
            );
            // Convert records from the Database to commands for the command palette
            return tasks.map(task => ({
                name: `[${task.project_id[1]}] ${task.name}`,
                category: "tasks",
                action: () => {
                    // Opens the form view of task
                    actionService.doAction({
                        type: "ir.actions.act_window",
                        res_model: "project.task",
                        res_id: task.id,
                        views: [[false, "form"]],
                        target: "current",
                    });
                },
            }));
        } catch (error) {
            console.error("Failed to fetch tasks for command palette:", error);
            return [];
        }
    },
});

4. Step 3: Creation of a Custom Rendering Component

Default Odoo provides commands in text form. However, if we want to display components such as icons for priority, colored, user images, and statuses, this could be done via a custom OWL Component.

1. The OWL Template (static/src/xml/task_command.xml):

<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
    <t t-name="my_module.TaskCommandItem" xml:space="preserve">
        <div class="d-flex align-items-center justify-content-between w-100 px-3 py-2">
            <div class="d-flex flex-column">
                <span class="fw-bold text-dark"><t t-esc="props.name"/></span>
                <span class="text-muted small"><t t-esc="props.project_name"/></span>
            </div>
            <span class="badge bg-primary text-white rounded-pill"><t t-esc="props.stage"/></span>
        </div>
    </t>
</templates>

2. The OWL Component Definition & Registration:

import { Component } from "@odoo/owl";
export class TaskCommandItem extends Component {
    static template = "my_module.TaskCommandItem";
}
// Modify the 'provide' mapping from Step 2 to return the component and props:
return tasks.map(task => ({
    Component: TaskCommandItem, // Our custom rendering component
    props: {
        name: task.name,
        project_name: task.project_id[1],
        stage: task.stage_id[1] || "New",
    },
    action: () => {
        // navigation logic can be entered here...
    },
}));

3. Adding Assets to __manifest__.py

For your custom commands to function properly, their scripts must be added into the assets bundle on the backend side:

{
    'name': 'Custom Command Palette',
    'version': '19.0.1.0.0',
    'depends': ['web', 'project'],
    'assets': {
        'web.assets_backend': [
            'my_module/static/src/js/global_command_provider.js',
            'my_module/static/src/js/task_command_provider.js',
            'my_module/static/src/xml/task_command.xml',
        ],
    },
}

Command Provider Best Practices

  • RPC Debouncing: It is recommended to include a debounce Delay in your namespace declaration to protect yourself against multiple hits on the database for every keystroke.
  • Return Smaller Array of Results: Do not return a large array of results. Try to limit your number of results to a maximum of 5-10 results.
  • Use Try/Catch in Error Handling: Since you are going to be working with the database, make sure all errors are caught using try/catch in order to avoid a typing lock in the command palette.

However, the Command Palette in Odoo 19 is not just another search dialog. It represents an interface that allows navigating through records, performing different actions, and optimizing day-to-day processes within the platform. Using command_setup and command_provider, it is possible to add custom commands, perform namespace searches, and fetch dynamic results from the database. Moreover, with the help of OWL components, the command palette allows displaying rich, interactive search results, which may be needed by a user before he opens a particular record.

Whatever you want to add from administrative functions to document searches to commonly performed tasks, the command palette is a convenient, yet highly extensible feature that does not require any changes in Odoo's core modules. Debouncing of RPC calls, a limited number of search results, and exception handling will ensure high performance and scalability of custom command providers. Therefore, the command palette becomes not only an additional function but also a productivity feature of Odoo.

To read more about Overview of OWL Component Structure In Odoo 19, refer to our blog Overview of OWL Component Structure In Odoo 19.


Frequently Asked Questions

What is the Command Palette in Odoo 19?

The Command Palette is a key-based interface that helps in searching for records, switching between views, and issuing commands. The palette can be accessed by using the keyboard shortcut Ctrl + K.

Which registries are used to customize the Command Palette?

Odoo 19 provides two primary registries for customization, one is command_setup, which defines command namespaces, placeholders, and debounce behavior. Another one is command_provider, which supplies the command results that appear in the palette.

What is a command namespace?

A namespace is a keyboard prefix that will narrow down the commands to a particular scope. For instance, one may define a namespace like ‘#’ which will help narrow down the search to project tasks, while another namespace may narrow down the search to customers, products, or invoices.

If you need any assistance in odoo, we are online, please chat with us.



0
Comments



Leave a comment



WhatsApp