Étape 3 sur 4

Construire l'écran et son entrée

Nous dessinons maintenant le bouton « Well, hello Odoo », puis nous créons l'action et le menu racine qui feront apparaître l'application dans Odoo.

1. Dessinez l'écran

Le template XML décrit ce que le composant affiche. La directive t-on-click="sayHello" relie le clic à la méthode JavaScript écrite à l'étape précédente.

custom_addons/training_hello/static/src/hello_world/hello_world.xml
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
    <t t-name="training_hello.HelloWorld">
        <div class="o_action p-4">
            <h1>Hello Odoo</h1>
            <p>Votre premier module est bien ouvert.</p>
            <button type="button"
                    class="btn btn-primary"
                    t-on-click="sayHello">
                Well, hello Odoo
            </button>
        </div>
    </t>
</templates>

Le nom training_hello.HelloWorld doit être strictement identique à la valeur de static template dans le fichier JavaScript.

2. Rendez l'application accessible depuis l'accueil

Pour que Hello Odoo apparaisse parmi les applications, Odoo doit savoir quel nom afficher et quel écran ouvrir lorsqu'on clique dessus.

Dans le fichier suivant, le bloc record crée une client action qui ouvre notre écran. Le bloc menuitem ajoute Hello Odoo au menu des applications et relie le clic à cette action.

custom_addons/training_hello/views/hello_world_menus.xml
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
    <record id="training_hello_action" model="ir.actions.client">
        <field name="name">Hello Odoo</field>
        <field name="tag">training_hello.hello_world</field>
    </record>

    <menuitem id="training_hello_menu_root"
              name="Hello Odoo"
              action="training_hello_action"
              sequence="10"/>
</odoo>
Suivez le trajet du clic

Ne cherchez pas à mémoriser tous les attributs. Pour cet écran, retenez simplement ce qui se passe quand vous cliquez sur Hello Odoo :

  1. Le menu porte le libellé visible name="Hello Odoo". Son attribut action="training_hello_action" désigne l'action à lancer. L'id de l'action fournit donc le handle stable de ce binding : gardez-le tel quel pendant l'exercice.
  2. model="ir.actions.client" choisit le type client action : il affiche un composant dans le client web, au lieu d'ouvrir la liste ou le formulaire d'un modèle métier. C'est le bon choix pour notre écran Owl.
  3. Le tag training_hello.hello_world est le binding décisif : le client web recherche exactement cette clé dans registry.category("actions"), où le composant JavaScript a été enregistré. La casse et les deux côtés doivent correspondre.
  4. Le composant charge ensuite le template training_hello.HelloWorld, puis le bouton relie t-on-click="sayHello" à la méthode JavaScript sayHello().

Le type client action n'est qu'une famille parmi d'autres : ir.actions.act_window ouvre des vues sur un modèle, ir.actions.act_url ouvre une URL, ir.actions.server exécute une logique côté serveur et ir.actions.report produit un rapport. Consultez la liste officielle des actions Odoo 19 ; la référence « Client actions » décrit précisément le lien entre le menu, le tag et le registry JavaScript.

Le nom hello_world_menus.xml est-il imposé ?

Non. Odoo n'exige pas de nom précis pour ce fichier. Nous utilisons un nom en minuscules, avec des mots séparés par des underscores, qui décrit clairement son contenu. Vous pourriez par exemple le renommer menus.xml ou hello_menus.xml.

En revanche, le chemin déclaré dans __manifest__.py doit correspondre exactement au nouveau nom. Si le fichier devient views/menus.xml, remplacez aussi views/hello_world_menus.xml par views/menus.xml dans la propriété data, puis mettez le module à niveau.

Le nom du fichier sert surtout aux développeurs. Pour Odoo, ce sont les identifiants définis à l'intérieur — comme training_hello_action et training_hello_menu_root — qui donnent leur identité durable aux enregistrements.

3. Complétez le manifeste

Les trois nouveaux fichiers existent. Avant de copier le manifeste complet, vérifiez précisément ce qui change par rapport à __manifest__.py minimal de la section 1 :

  • summary : remplacez Un premier module minimal pour Odoo par Un premier écran interactif dans Odoo pour décrire le nouveau résultat.
  • depends : remplacez ["base"] par ["web"] ; le module utilise le client web, ses services et son registry, et web dépend déjà de base.
  • data : remplacez [] par ["views/hello_world_menus.xml"] pour demander à Odoo de charger l'action et le menu dans la base.
  • assets : ajoutez le bundle web.assets_backend avec training_hello/static/src/hello_world/hello_world.js et training_hello/static/src/hello_world/hello_world.xml ; ces deux fichiers pourront alors être chargés par le client web.
  • application et installable : conservez True pour les deux ; application=True classe le module dans Apps et le menuitem racine crée l'entrée de l'app switcher/accueil, tandis que installable=True autorise son installation.
  • Les autres champs : gardez name, version, category, author et license tels quels pour cet exercice.

Vous pouvez ensuite remplacer le contenu par cette version complète :

custom_addons/training_hello/__manifest__.py
{
    "name": "Hello Odoo",
    "summary": "Un premier écran interactif dans Odoo",
    "version": "19.0.1.0.0",
    "category": "Training",
    "author": "Formation Odoo",
    "license": "LGPL-3",
    "depends": ["web"],
    "data": [
        "views/hello_world_menus.xml",
    ],
    "assets": {
        "web.assets_backend": [
            "training_hello/static/src/hello_world/hello_world.js",
            "training_hello/static/src/hello_world/hello_world.xml",
        ],
    },
    "application": True,
    "installable": True,
}

web remplace base dans depends : le client web dépend déjà de base, et notre composant utilise directement ses services. web.assets_backend est le bundle chargé dans l'interface interne des utilisateurs connectés ; il ne signifie pas « réservé aux administrateurs ».

Deux conventions de chemin

Dans data, views/hello_world_menus.xml est relatif au dossier du module. Dans assets, chaque chemin commence par training_hello, car un bundle réunit des fichiers provenant de plusieurs modules.

4. Vérifiez que les noms correspondent

  1. Le manifeste charge les deux fichiers d'assets et views/hello_world_menus.xml.
  2. Dans l'action, training_hello.hello_world est exactement le nom sous lequel le composant est enregistré en JavaScript.
  3. Dans le composant, training_hello.HelloWorld est exactement le nom donné au template XML.
Le trajet est complet

L'entrée Hello Odoo lance l'action, l'action retrouve le composant, le composant affiche le template et le bouton appelle sayHello().