Ở bài registry ta đã nhét một mẩu chữ vào thanh trên cùng để minh hoạ cơ chế đăng ký. Giờ làm cho ra dáng: một icon cà phê có badge đếm, bấm vào bung ra dropdown hiện số liệu và một mục mở màn hình danh sách. Đây là kiểu mục systray bạn gặp khắp Odoo — biểu tượng chat, hoạt động, chuyển công ty đều là systray.

Systray là gì và nằm ở đâu

Systray là dải các mục nhỏ ở góc phải thanh điều hướng (system tray). Mỗi mục là một component OWL đăng ký vào category "systray" của registry. Web client duyệt category này, sắp xếp theo sequence, rồi vẽ ra. Điểm cần nhớ ngay: sequence càng nhỏ thì càng nằm về bên phải (gần avatar) — ngược với trực giác "nhỏ trước, bên trái".

Một mục systray "bài bản" thường không chỉ là chữ, mà là icon + dropdown. Odoo cho sẵn hai component để dựng dropdown: Dropdown và DropdownItem.

Ảnh chụp hai đoạn mã nền tối. Đoạn trên là file systray_menu js import Dropdown từ web core dropdown dropdown và DropdownItem từ dropdown_item, lớp QuanSystray kế thừa Component khai static components gồm Dropdown và DropdownItem, setup lấy service orm và action, chú thích onWillStart nạp số liệu thẻ, method moDanhSach gọi action doAction mở action_the_thanh_vien, và đăng ký vào registry category systray với key quan_ca_phe systray value object Component QuanSystray cùng options sequence 30 kèm chú thích sequence nhỏ nằm bên phải gần avatar còn lớn nằm bên trái. Đoạn dưới là systray_menu xml khai Dropdown position bottom-end chứa một button với icon fa fa-coffee và badge state tong, một slot content chứa số liệu và một DropdownItem onSelected bind moDanhSach ghi Mở danh sách thẻ

Hình 1: Component (trên) và template (dưới). static components = { Dropdown, DropdownItem } khai để dùng chúng trong template. Dropdown bọc một <button> (phần luôn hiện trên thanh) và một slot content (phần bung ra khi bấm). DropdownItem với onSelected.bind là một dòng bấm được — ở đây gọi action.doAction mở view. Đăng ký với sequence: 30.

Kết quả thật trên thanh

Khai hai file vào bundle web.assets_backend, nâng cấp. Icon cà phê xuất hiện ngay trên thanh, cạnh các mục có sẵn của Odoo:

Ảnh chụp thật thanh điều hướng trên cùng của Odoo 19 nền tím, bên trái là tên Quán Cà Phê và các menu, bên phải lần lượt là icon cốc cà phê kèm huy hiệu số 4 màu vàng cam vừa thêm vào, rồi icon tin nhắn có số 3, icon hoạt động có số 2, tên công ty TNHH Cà Phê Việt và avatar chữ A

Hình 2: Icon cà phê (badge "4" = tổng số thẻ) nằm cạnh các mục systray sẵn có (chat "3", hoạt động "2"). Vị trí của nó so với hai mục kia do sequence quyết định — cùng một cơ chế, cùng một dải.

Bấm vào icon, dropdown bung ra với số liệu thật và một mục mở màn hình:

Ảnh chụp thật dropdown của mục systray vừa mở, tiêu đề có biểu tượng cốc cà phê và chữ Thẻ thành viên, ba dòng số liệu Tổng số thẻ bằng 4, Tổng điểm bằng 385, Thẻ Vàng bằng 1, và dưới cùng một mục bấm được có icon danh sách ghi Mở danh sách thẻ

Hình 3: Dropdown mở ra. Ba số liệu (4 thẻ, 385 điểm, 1 Vàng) do orm.searchRead nạp trong onWillStart. Dòng "Mở danh sách thẻ" là một DropdownItem — bấm vào chạy action.doAction("quan_ca_phe.action_the_thanh_vien"), đưa người dùng thẳng tới kanban thẻ. Một mục systray gọn gàng: liếc là thấy số liệu, một cú bấm là tới nơi.

Vài điều cần biết để nó đúng

  • sequence quyết định vị trí, và nhỏ = phải. Nếu icon của bạn nằm sai chỗ so với mong muốn, chỉnh sequence (số nhỏ đẩy về gần avatar). Các mục lõi của Odoo dùng sequence riêng, bạn chèn xen vào giữa được.
  • onWillStart để nạp dữ liệu, đừng nạp trong render. Số liệu trong dropdown gọi server, nên tải một lần lúc khởi tạo. Component systray sống suốt phiên nên dữ liệu là ảnh chụp lúc mở trang — cần tươi realtime thì phải nạp lại khi mở dropdown.
  • Value đăng ký là { Component }, không phải class trần. Systray category chờ đúng hình dạng đó (khác "actions" nhận thẳng class). Sai hình dạng thì mục không hiện mà chẳng có lỗi.
  • Đây vẫn là component OWL bình thường — dùng được useService, useState, mọi hook. Systray chỉ là nơi nó được gắn, không phải một loại component đặc biệt.

Ba ý mang về

  1. Systray là dải mục ở góc phải thanh điều hướng; mỗi mục là component OWL đăng ký vào registry.category("systray").add(key, { Component }, { sequence }). Giá trị phải là { Component }, không phải class trần.
  2. sequence quyết định vị trí, và số NHỎ nằm về bên PHẢI (gần avatar). Chèn xen giữa các mục lõi bằng cách chọn sequence phù hợp.
  3. Dựng dropdown bằng Dropdown + DropdownItem: <button> là phần luôn hiện, slot content là phần bung ra, DropdownItem với onSelected là dòng bấm được (gọi action.doAction, orm, v.v.). Nạp dữ liệu trong onWillStart.

Ta đã gắn thêm mảnh nhỏ khắp nơi — field, view, systray. Phần sau làm thứ lớn hơn: một client action OWL — cả một màn hình riêng do bạn toàn quyền vẽ, mở từ menu như một app thực thụ.