Introduction: Transforming Your Odoo Kanban Experience
Welcome back to our Odoo development series! In today’s deep dive, we’re tackling a powerful enhancement that can significantly improve your team’s efficiency and visibility: Odoo Kanban Color Counters. Imagine a Kanban board where critical information doesn’t require a single click. Overdue tasks flash red, urgent items glow orange, completed tasks turn green, and unread messages are immediately visible. This isn’t just a dream; it’s a practical, real-time solution we’ll build using Odoo 18 and the modern OWL 2 framework.
This guide will walk you through the process of developing a custom Odoo 18 module to add dynamic color coding, live counters, and informative tooltips directly to your Kanban cards. Whether you’re managing CRM leads, project tasks, or any other workflow, these visual indicators will provide instant insights, reduce clicks, and make your Odoo experience more intuitive and user-friendly.
The concepts and code presented here are based on a detailed video tutorial. For a visual walkthrough, you can reference the source video here: Odoo OWL 2 Development Add Live Colors & Counters to Kanban Cards.
Why Dynamic Odoo Kanban Color Counters Are Essential
Kanban boards are a cornerstone of modern project management and workflow visualization in Odoo. They offer a clear overview of tasks and opportunities moving through different stages. However, a standard Kanban view can sometimes lack immediate visual cues about a card’s status. Is a task overdue? Does an opportunity have unread messages? How many activities are pending? Without opening each record, these questions often remain unanswered, leading to:
- Increased Clicks and Time Waste: Users have to open individual records to check critical details, slowing down their workflow.
- Delayed Action: Important tasks or urgent communications might be overlooked until it’s too late.
- Reduced Visibility: The overall “health” of a project or sales pipeline isn’t immediately apparent.
By implementing dynamic Odoo Kanban Color Counters, you transform your static board into a live, reactive dashboard. This means:
- Instant Insights: Visually identify overdue items, upcoming deadlines, or records needing attention at a glance.
- Improved Efficiency: Prioritize tasks quickly without needing to drill down into each record.
- Enhanced User Experience: A more engaging and informative interface makes Odoo more pleasant and productive to use.
- Proactive Management: Managers and team members can spot potential bottlenecks or critical issues before they escalate.
This level of visual feedback is crucial for dynamic environments like CRM and Project Management, where quick decision-making is key.
Understanding the Architecture: OWL 2 and Beyond
Before we dive into the code, let’s briefly touch upon the technologies involved. Odoo 18 leverages OWL 2 (Odoo Web Library 2) as its modern JavaScript framework for frontend development. OWL 2 is a powerful, modular, and reactive system, similar to popular frameworks like React or Vue, but fully integrated within the Odoo ecosystem. It allows us to build dynamic UI components that seamlessly interact with Odoo’s backend.
Our custom module will consist of three main layers:
- Python Backend (Models): A lightweight abstract model to compute metrics (like deadline days, activity counts, unread messages, subtasks) for each record. This logic is accessible via Remote Procedure Calls (RPC).
- JavaScript Frontend (OWL 2): This is where the magic happens. An OWL 2 service will scan the Kanban view, fetch metrics from the backend via RPC, and then dynamically apply colors, counters, and tooltips to each card. It will also listen for DOM changes to ensure real-time updates.
- CSS Styling (SCSS): Custom styles to define the appearance of the colored stripes and counter footers, ensuring a polished look.
With this architecture, we ensure that our Odoo Kanban Color Counters are both dynamic and efficient.
Tutorial: Building Your Custom Odoo Kanban Color Counters Module
Let’s begin the hands-on development.
Prerequisites:
- Odoo 18 (Enterprise or Community Edition).
- Developer Mode Activated in Odoo.
- Basic familiarity with Odoo module structure, Python, JavaScript, and CSS.
- A code editor like Visual Studio Code.
Step 1: Module Setup
First, create a new custom module in your Odoo custom addons directory.
- Create Module Folder: In your custom modules directory, create a new folder named
owl_kanban_color_counters
. - Create Essential Files and Folders: Inside
owl_kanban_color_counters
, create the following structure:
owl_kanban_color_counters/
├── __init__.py
├── __manifest__.py
├── models/
│ └── __init__.py
├── static/
│ ├── description/
│ └── src/
│ ├── js/
│ └── scss/
Step 2: __init__.py
Files
These files tell Python how to import modules.
owl_kanban_color_counters/__init__.py
:from . import models
owl_kanban_color_counters/models/__init__.py
:from . import kanban_metric_mixin
This line will import our custom Python file later.
Step 3: __manifest__.py
The manifest file defines your module’s metadata, dependencies, and assets.
owl_kanban_color_counters/__manifest__.py
:{ 'name': 'OWL Kanban Color & Counters', 'version': '18.0.1.0.0', # Odoo version.major.minor.patch.build 'summary': 'Dynamic Kanban color coding and live counters using OWL 2', 'category': 'Web', 'author': 'Odoistic', # Replace with your name or company 'depends': ['web', 'crm', 'mail'], # 'project' can be added if needed 'data': [ # No data files directly loaded as these are static assets ], 'assets': { 'web.assets_backend': [ 'owl_kanban_color_counters/static/src/js/okc_boot.js', 'owl_kanban_color_counters/static/src/js/kanban_color_counters.js', 'owl_kanban_color_counters/static/src/scss/kanban_color_counters.scss', ], }, 'installable': True, 'license': 'LGPL-3', 'images': ['static/description/icon.png'], # Optional: Add a module icon }
Explanation:
name
: The display name for your module in the Apps menu.version
: Follows the Odoo versioning convention.summary
: A brief description of what the module does.category
: Helps categorize your module. ‘Web’ is appropriate for UI enhancements.author
: Your name or company.depends
:web
: Essential for all Odoo web client functionality and OWL 2.crm
: Needed if you plan to use these Odoo Kanban Color Counters for CRM leads.mail
: Crucial for tracking unread messages, a key metric for our counters.project
: (Optional) Include if you want to extend this functionality to project tasks.
assets
: This is the modern way to load static files (JS, CSS) in Odoo 18.web.assets_backend
ensures these files are loaded in the Odoo backend.installable
: Must beTrue
for the module to appear in the Apps list.license
: LGPL-3 is a common license for community modules.images
: (Optional) Path to an icon for your module.
Step 4: models/kanban_metric_mixin.py
(Python Backend)
This file defines an abstract model that computes the metrics we’ll display.
owl_kanban_color_counters/models/kanban_metric_mixin.py
:from odoo import models, fields, api class KanbanMetricMixin(models.AbstractModel): _name = 'kanban.metric.mixin' _description = 'Abstract model for computing Kanban metrics' _abstract = True # Abstract models do not create database tables @api.model def get_kanban_metrics(self, model_name, ids): """ Fetch pre-record metrics used for coloring and counters in Kanban cards. This method is called from the frontend JavaScript via RPC. """ if not ids or model_name not in ('crm.lead', 'project.task'): return {} try: ids = [int(i) for i in ids] except ValueError: return {} # Use self.env.sudo() to bypass access rights and ensure data is always visible # with_context(prefetch_fields=False) can improve performance for large datasets records = self.env[model_name].sudo().with_context(prefetch_fields=False).browse(ids) today = fields.Date.context_today(self) result = {} for record in records: metrics = {} # 1. Deadline Calculation if hasattr(record, 'date_deadline') and record.date_deadline: deadline = record.date_deadline days_until_deadline = (deadline - today).days metrics['deadline_days_left'] = days_until_deadline # 2. Activities Count # Filters activities for upcoming deadlines, not all activities if hasattr(record, 'activity_ids'): metrics['activities_count'] = len(record.activity_ids.filtered(lambda a: a.date_deadline >= today)) # 3. Unread Messages Count # Excludes internal messages and already read messages if hasattr(record, 'message_ids') and hasattr(record, 'message_unread') and record.message_unread: # Note: message_unread field is a boolean, indicating if there are ANY unread messages # To get a count, we iterate through messages metrics['unread_count'] = len(record.message_ids.filtered(lambda m: not m.is_internal and not m.message_read)) # 4. Subtasks Count (specific to project.task) if model_name == 'project.task' and hasattr(record, 'child_ids'): metrics['subtask_count'] = len(record.child_ids) # A task is "done" if all its child tasks are closed metrics['is_done'] = all(child.stage_id and child.stage_id.is_closed for child in record.child_ids) # 5. "Is Done" Status for CRM Lead if model_name == 'crm.lead': metrics['is_done'] = record.probability >= 100 or (hasattr(record.stage_id, 'is_won') and record.stage_id.is_won) result[record.id] = metrics return result
Explanation:
- Abstract Model:
_abstract = True
means this model doesn’t create a database table. It’s a reusable piece of logic. get_kanban_metrics
Method: This is the core method.- Input Validation: Ensures
ids
are provided and themodel_name
iscrm.lead
orproject.task
. self.env[model_name].sudo().browse(ids)
: Retrieves the records.sudo()
is used to bypass potential access right issues, ensuring all users see the same metrics.with_context(prefetch_fields=False)
is a performance optimization.- Metrics Computation:
deadline_days_left
: Calculates the remaining days until the deadline (negative if overdue).activities_count
: Counts scheduled activities that are not yet past due.unread_count
: Counts unread chatter messages. This is particularly useful for Odoo Kanban Color Counters to highlight communication.subtask_count
: Forproject.task
records, it counts child tasks and determines if the main task is “done” based on its children.is_done
: Determines if a CRM lead is won (probability >= 100% or stage is ‘Won’).
- Result Structure: Returns a dictionary where keys are record IDs and values are their respective metric dictionaries.
- Input Validation: Ensures
Step 5:
static/src/js/kanban_color_counters.js
(OWL 2 Frontend Logic)This is the main JavaScript file responsible for rendering the Odoo Kanban Color Counters.
owl_kanban_color_counters/static/src/js/kanban_color_counters.js
:/** @odoo-module */ // Declares this as an Odoo ES module import { registry } from '@web/core/registry'; // For registering services import { useService } from '@web/core/utils/hooks'; // For using Odoo services like RPC // Register a new service in the 'services' category registry.category("services").add('kanban_color_counters_service', { // Renamed to avoid potential conflict start(env) { // The 'start' method runs when the service is initialized // Use the RPC service to make calls to the Odoo backend const RPC = useService('rpc'); // Configuration for color thresholds const config = { thresholdDueSoon: 2, // Days: Deadline within 2 days is considered 'due soon' }; // Helper functions for determining colors, formatting tooltips, etc. const colorHelpers = { /** * Determines CSS class and hex color based on record metrics. * Priority: Done > Overdue > Due Soon > Unread * @param {Object} m - The metrics object for a single record. * @returns {Object} - An object with 'class' (CSS class) and 'color' (hex code). */ colorFromMatrix: (m) => { if (m.is_done) return { class: 'okc-card-green', color: '#4CAF50' }; // Green for completed/won if (m.deadline_days_left !== undefined && m.deadline_days_left < 0) return { class: 'okc-card-red', color: '#F44336' }; // Red for overdue if (m.deadline_days_left !== undefined && m.deadline_days_left <= config.thresholdDueSoon) return { class: 'okc-card-orange', color: '#FF9800' }; // Orange for due soon if (m.unread_count > 0) return { class: 'okc-card-blue', color: '#2196F3' }; // Blue for unread messages return {}; // No special class/color }, /** * Determines a fallback color based on the Kanban column title (stage name). * Used when server metrics are not available immediately or for default styling. * @param {string} title - The title of the Kanban column. * @returns {Object} - An object with 'class' (CSS class) and 'color' (hex code). */ colorFromColumn: (title) => { title = title.toLowerCase(); if (title.includes('won') || title.includes('done') || title.includes('closed')) return { class: 'okc-card-green', color: '#4CAF50' }; if (title.includes('proposition') || title.includes('proposal')) return { class: 'okc-card-orange', color: '#FF9800' }; if (title.includes('qualified') || title.includes('progress')) return { class: 'okc-card-blue', color: '#2196F3' }; if (title.includes('new') || title.includes('draft')) return { class: 'okc-card-red', color: '#F44336' }; return { class: 'okc-card-blue', color: '#2196F3' }; // Default color if no keyword matches }, /** * Formats the metrics into a human-readable tooltip string. * @param {Object} m - The metrics object for a single record. * @returns {string} - The formatted tooltip text. */ formatTooltip: (m) => { let tooltip = 'Kanban Card Details:\n'; if (m.deadline_days_left !== undefined) { tooltip += `Deadline: `; if (m.deadline_days_left < 0) tooltip += `${Math.abs(m.deadline_days_left)} days overdue\n`; else if (m.deadline_days_left === 0) tooltip += `due today\n`; else tooltip += `${m.deadline_days_left} days left\n`; } if (m.activities_count !== undefined && m.activities_count > 0) tooltip += `Activities: ${m.activities_count} pending\n`; if (m.unread_count !== undefined && m.unread_count > 0) tooltip += `Unread Messages: ${m.unread_count}\n`; if (m.subtask_count !== undefined && m.subtask_count > 0) tooltip += `Subtasks: ${m.subtask_count}\n`; if (m.is_done) tooltip += `Status: Completed/Won\n`; return tooltip.trim(); // Remove trailing newline } }; /** * Extracts the Odoo record ID from a Kanban card element. * Tries multiple common locations where Odoo stores the ID. * @param {HTMLElement} card - The Kanban card DOM element. * @returns {string|null} The record ID or null if not found. */ const getResId = (card) => { // Try data-id or data-res-id attributes on the card itself let resId = card.dataset.id || card.dataset.resId; // If not found, look for a link inside the card with #id= in its URL hash if (!resId) { const aTag = card.querySelector('a[href*="#id="]'); if (aTag) { const href = aTag.getAttribute('href'); try { // Parse the hash part of the URL const url = new URL(href, window.location.origin); // Use window.location.origin for base const params = new URLSearchParams(url.hash.substring(1)); // Remove the leading '#' resId = params.get('id'); } catch (e) { console.warn("Invalid URL found in Kanban card link:", href, e); } } } // If still not found, look for data-res-id on an inner clickable element if (!resId) { const innerClickable = card.querySelector('[data-res-id]'); if (innerClickable) { resId = innerClickable.dataset.resId; } } return resId; }; /** * Inserts or updates a colored stripe on the left side of a Kanban card. * @param {HTMLElement} card - The Kanban card DOM element. * @param {Object} color - An object containing 'class' and 'color' (hex code). */ const ensureStripe = (card, color) => { let stripe = card.querySelector('.okc-stripe'); if (!stripe) { stripe = document.createElement('div'); stripe.classList.add('okc-stripe'); card.prepend(stripe); // Add as the first child } // Apply the new color stripe.style.backgroundColor = color.color || 'transparent'; // Add a subtle box-shadow for depth and visibility stripe.style.boxShadow = `inset 4px 0 0 0 ${color.color || 'transparent'}`; // Optional: add outline for contrast against very dark backgrounds stripe.style.outline = `1px solid ${color.color || 'transparent'}`; }; /** * The main worker function: repaints a single Kanban container. * @param {HTMLElement} container - The Kanban view container element. */ const repaintContainer = async (container) => { // Determine the model currently being displayed. // For now, it's hardcoded to 'crm.lead' for immediate CRM functionality. // This could be made dynamic by parsing the view's data. const model = 'crm.lead'; // Example: 'project.task' if targeting project module const cards = container.querySelectorAll('.o_kanban_record'); const idsToFetch = []; cards.forEach(card => { const resId = getResId(card); if (resId) { idsToFetch.push(parseInt(resId, 10)); // Ensure IDs are integers } }); // First pass: apply immediate column-based colors cards.forEach(card => { const columnTitleElement = card.closest('.o_kanban_group')?.querySelector('.o_kanban_header .o_column_title'); const columnTitle = columnTitleElement ? columnTitleElement.innerText : ''; const color = colorHelpers.colorFromColumn(columnTitle); ensureStripe(card, color); }); // If we found any IDs, fetch server metrics if (idsToFetch.length > 0) { try { // Call the Python mixin method via RPC const metrics = await RPC('/web/dataset/call_kw/' + model, { // Correct RPC path for abstract models model: 'kanban.metric.mixin', method: 'get_kanban_metrics', args: [model, idsToFetch], kwargs: {}, }); cards.forEach(card => { const resId = getResId(card); if (!resId || !metrics[resId]) { // If no metrics are available, column-based color remains return; } const metric = metrics[resId]; // Remove any previously applied color classes to avoid conflicts card.classList.remove('okc-card-green', 'okc-card-red', 'okc-card-orange', 'okc-card-blue'); // Try to apply matrix-based color const color = colorHelpers.colorFromMatrix(metric); if (color.class) { card.classList.add(color.class); // Apply the new color class } ensureStripe(card, color); // Update the stripe color // Inject counters footer and tooltip if not already present let footer = card.querySelector('.okc-counters'); if (metric && !footer) { footer = document.createElement('div'); footer.classList.add('okc-counters'); card.appendChild(footer); } if (footer) { let tooltipText = colorHelpers.formatTooltip(metric); card.setAttribute('title', tooltipText); // Set the tooltip for the card // You could add more complex counter displays here within the footer // For simplicity, we just use the tooltip for the full summary. // Example: footer.innerHTML = `<span>${metric.activities_count || 0} A | ${metric.unread_count || 0} U</span>`; } }); } catch (e) { console.error("Error fetching Kanban metrics:", e); } } }; /** * Applies the repaint logic to all Kanban views currently on the page. */ const applyToAllKanban = () => { const kanbanContainers = document.querySelectorAll('.o_kanban_view'); kanbanContainers.forEach(repaintContainer); }; // --- Initialization and Real-time Updates --- // 1. Initial paint: Apply colors and counters as soon as the service starts applyToAllKanban(); // 2. Repaint after short delays: Catch elements rendered lazily by Odoo setTimeout(applyToAllKanban, 500); setTimeout(applyToAllKanban, 1500); // 3. Mutation Observer: Recolor whenever the DOM of the Odoo backend changes // This catches changes like scrolling, filtering, moving cards, opening/closing forms, etc. const observer = new MutationObserver(applyToAllKanban); const observerConfig = { childList: true, subtree: true, attributes: false }; const targetNode = document.querySelector('body'); // Observe the entire body for broad coverage if (targetNode) { observer.observe(targetNode, observerConfig); } else { console.warn("Could not find body element to attach MutationObserver."); } // Cleanup when the service stops (e.g., when navigating away from Odoo client) return () => { observer.disconnect(); }; }, });
Explanation:
@odoo-module
& Service Registration: Declares an ES module and registers a servicekanban_color_counters_service
. Services are automatically started and stopped by the Odoo web client, making them ideal for background tasks.useService('rpc')
: Hooks into Odoo’s RPC service to make calls to the Python backend.colorFromMatrix
: This function is central to our Odoo Kanban Color Counters. It applies colors based on the numerical metrics: green for “done,” red for “overdue,” orange for “due soon,” and blue for “unread messages.” The order of conditions defines priority.colorFromColumn
: Provides a fallback color based on the Kanban column (stage) name. This ensures cards always have some visual indicator, even if backend metrics aren’t immediately available or applicable.formatTooltip
: Generates a detailed tooltip that summarizes all the computed metrics.getResId
: A robust function to reliably extract the Odoo record ID from various places within a Kanban card’s DOM structure.ensureStripe
: Dynamically adds or updates a vertical colored stripe on the left side of each Kanban card, using the color determined by our helper functions.repaintContainer
: The heart of the frontend logic.- It identifies all Kanban cards within a specific container.
- First, it applies column-based fallback colors.
- Then, it collects all record IDs and makes an RPC call to
get_kanban_metrics
on our Python mixin. - Upon receiving metrics, it iterates through cards again, removes old colors, applies the more precise matrix-based colors, and injects/updates tooltips.
applyToAllKanban
: Orchestrates the process by finding all Kanban views on the page and callingrepaintContainer
for each.- Real-time Updates:
- Initial
applyToAllKanban()
calls: Ensure cards are colored immediately and catch any elements that might load slightly later. MutationObserver
: This powerful Web API is key for real-time responsiveness. It monitors the DOM for changes (e.g., new cards appearing after a search, filtering, or moving cards) and triggersapplyToAllKanban()
to refresh the colors and counters, making our Odoo Kanban Color Counters truly dynamic.
- Initial
Step 6:
static/src/js/okc_boot.js
(Boot Service)This simple file creates a boot service, primarily used to ensure our module’s assets are loaded correctly.
owl_kanban_color_counters/static/src/js/okc_boot.js
:/** @odoo-module */ import { registry } from '@web/core/registry'; registry.category("services").add('okc_boot', { start(env) { // This service is primarily to ensure that the module's assets (JS and CSS) // are properly injected and loaded in the Odoo web client. // No specific logic is needed here for this module, as the main logic is // in kanban_color_counters.js, which is also loaded as an asset. }, });
Explanation: A minimalistic service that simply registers itself. Its presence in
web.assets_backend
within__manifest__.py
helps ensure the proper loading order and injection of our assets into the Odoo web client.
Step 7:
static/src/scss/kanban_color_counters.scss
(CSS Styling)This file defines the visual styles for our Kanban cards and the new elements.
owl_kanban_color_counters/static/src/scss/kanban_color_counters.scss
:// Styles for the custom Odoo Kanban Color Counters .o_kanban_view { // Target individual Kanban records (cards) .o_kanban_record { position: relative; // Needed for absolute positioning of the stripe border-left: 0px solid transparent; // Initial state, stripe will be managed by JS box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.1); // Subtle shadow for depth transition: border-color 0.3s ease, box-shadow 0.3s ease; // Smooth transitions for visual changes overflow: hidden; // Ensures stripe doesn't bleed out if borders are rounded } // Style for the dynamically inserted color stripe .okc-stripe { position: absolute; top: 0; left: 0; bottom: 0; width: 5px; // Width of the color stripe z-index: 1; // Ensure stripe is above other card content if needed } /* Color definitions for the stripes and card borders */ .okc-card-green { border-left-color: #4CAF50 !important; // Green for 'Done' or 'Won' } .okc-card-orange { border-left-color: #FF9800 !important; // Orange for 'Due Soon' or 'Proposition' } .okc-card-red { border-left-color: #F44336 !important; // Red for 'Overdue' or 'New' } .okc-card-blue { border-left-color: #2196F3 !important; // Blue for 'Unread' or 'Qualified' } /* Styling for the counters footer */ .okc-counters { position: absolute; bottom: 0; left: 0; width: 100%; padding: 4px 8px; // Padding inside the footer background-color: rgba(255, 255, 255, 0.9); // Slightly transparent white background border-top: 1px solid rgba(0, 0, 0, 0.05); // Subtle border font-size: 0.75em; // Smaller font size color: #555; // Darker text color text-align: right; // Align text to the right z-index: 2; // Ensure footer is above the stripe box-sizing: border-box; // Include padding and border in the element's total width and height } }
Explanation:
.o_kanban_record
: Sets up the base styling for Kanban cards, includingposition: relative
which is crucial for positioning our absoluteokc-stripe
.transition
creates a smooth visual effect when colors change..okc-stripe
: Defines the appearance and absolute positioning of the vertical colored bar..okc-card-green
,.okc-card-orange
, etc.: These classes, applied by JavaScript, set theborder-left-color
for the cards, giving them their distinctive visual cues.!important
is often used to ensure these custom styles override Odoo’s default styles..okc-counters
: Styles the dynamic footer that will potentially display counters and acts as the anchor for our rich tooltips.
Step 8: Install the Module
Once all files are created and saved:
- Restart Odoo Service: Go to your terminal and restart your Odoo server (e.g.,
sudo service odoo-server restart
orpython3 odoo-bin --addons-path=...
). - Update Apps List: In your Odoo instance, navigate to Settings -> Developer Tools (top right, bug icon) -> Update Apps List.
- Install Module: Go to the Apps menu, search for “OWL Kanban Color & Counters”, and click Activate.
Step 9: Test Your Odoo Kanban Color Counters
After installation, navigate to a Kanban view, for example:
- CRM -> Pipeline -> Kanban view
- (If you added
project
dependency and configured for it) Project -> Projects -> Kanban view
You should immediately see:
- Colored Stripes: Kanban cards will have colored stripes on their left side. Initially, these might be based on the column’s stage name.
- Dynamic Updates: As the page loads, or if you filter, move cards, or interact with the view, you’ll observe cards changing colors based on their underlying metrics.
- Tooltips: Hover over a card, and you’ll see a detailed tooltip summarizing its deadline, activities, unread messages, and done status, thanks to our robust Odoo Kanban Color Counters.
Customization and Further Enhancements
The beauty of this module lies in its flexibility. You can easily adapt it to your specific business needs:
- Adjust Due Soon Threshold: Modify
config.thresholdDueSoon
inkanban_color_counters.js
to change when a task is considered “due soon.” - Customize Stage Colors: Edit the
colorFromColumn
function inkanban_color_counters.js
to match your specific Kanban stage names and desired colors. - Extend to More Models: Change the
model
variable inrepaintContainer
to'project.task'
or make it dynamic by reading the_name
from the Kanban view’s definition. Remember to add the corresponding Odoo module to yourdepends
in__manifest__.py
. - Add More Metrics: Extend the
get_kanban_metrics
Python method to calculate any other relevant metrics (e.g., priority, assigned user status) and then updatecolorFromMatrix
andformatTooltip
accordingly. - Visual Counters in Footer: Currently, we’re using the tooltip for detailed metrics. You could extend the
repaintContainer
logic to dynamically insert smaller counter badges (e.g.,<span>A: ${metric.activities_count}</span>
) directly into the.okc-counters
footer element. - Advanced ID Extraction: In some highly customized Kanban views,
getResId
might not find the ID. You might need to extend it or even create a tiny Odoo QWeb patch to ensuredata-res-id
is explicitly stamped on your Kanban cards.
Conclusion
Congratulations! You’ve successfully built a powerful custom Odoo 18 module that injects dynamic Odoo Kanban Color Counters and live metrics directly into your Kanban views. By leveraging OWL 2, RPC calls to a Python backend, and a reactive JavaScript frontend, you’ve transformed a standard Kanban board into an insightful, real-time dashboard. This enhancement significantly boosts productivity, reduces information overload, and provides a more engaging user experience for your Odoo users.
The principles learned here, from service registration to
MutationObserver
usage, are invaluable for any Odoo 18 frontend development. Continue experimenting, and let these dynamic visuals streamline your workflows!If you have any questions, need further customization, or require Odoo implementation support for your business, feel free to reach out to me via contact@odoistic.co.uk. Your support for this channel, via a small PayPal donation (link typically in video description), also helps me continue creating free Odoo content.
Thanks for watching, and I’ll see you in the next video! Take care.
- Abstract Model:
Discover more from teguhteja.id
Subscribe to get the latest posts sent to your email.