Skip to content

[ADD] awesome_owl, awesome_dashboard: basic client-side modules for todos and t-shirt sales dashboard#1307

Open
sidum-odoo wants to merge 1 commit into
odoo:19.0from
odoo-dev:19.0-web-framework-tutorial-sidum
Open

[ADD] awesome_owl, awesome_dashboard: basic client-side modules for todos and t-shirt sales dashboard#1307
sidum-odoo wants to merge 1 commit into
odoo:19.0from
odoo-dev:19.0-web-framework-tutorial-sidum

Conversation

@sidum-odoo
Copy link
Copy Markdown

@sidum-odoo sidum-odoo commented May 29, 2026

Problem:

  • No existing module for handling simple todo list.
  • No existing module for analysing t-shirt sales.

Solution:

  • New module (100% client-side) with basic components such as todo list and counter.
  • New module (100% client-side) implementing a dashboard for t-shirt sales analysis.

Task-6241079

@robodoo
Copy link
Copy Markdown

robodoo commented May 29, 2026

Pull request status dashboard

@sidum-odoo sidum-odoo force-pushed the 19.0-web-framework-tutorial-sidum branch from e8ae96f to 26d5ee0 Compare June 1, 2026 09:09
@sidum-odoo sidum-odoo changed the title [ADD] awesome_owl: front-end module with basic components such as todo list and counter button [ADD] awesome_owl, awesome_dashboard: basic front-end module (todos) and dashboard module (t-shirt sales) Jun 1, 2026
@sidum-odoo sidum-odoo force-pushed the 19.0-web-framework-tutorial-sidum branch from 26d5ee0 to 18dafec Compare June 1, 2026 09:19
@sidum-odoo sidum-odoo changed the title [ADD] awesome_owl, awesome_dashboard: basic front-end module (todos) and dashboard module (t-shirt sales) [ADD] awesome_owl, awesome_dashboard: basic client-side modules for todos and t-shirt sales dashboard Jun 1, 2026
@sidum-odoo sidum-odoo force-pushed the 19.0-web-framework-tutorial-sidum branch from 18dafec to 3558516 Compare June 1, 2026 09:28
@sidum-odoo sidum-odoo requested a review from Megaaaaaa June 1, 2026 09:30
@sidum-odoo
Copy link
Copy Markdown
Author

@Megaaaaaa ready for review

Copy link
Copy Markdown

@Megaaaaaa Megaaaaaa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello hello 👋

Nice pr already, here 's a review for you 👍 These are mostly conventions that I wanted to show you but there is also a lot of what we usually call "useless diff" in reviews like changing quotes to double quotes or the other way around or removing or adding an empty line where nothing else changes. There are also a few EOL that you're missing but I guess the ci/style already told you that 😄

Don't hesitate to tell me if anything is unclear or if you have any question 👍

@@ -0,0 +1,51 @@
import { Component, onWillStart, useState } from "@odoo/owl";
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imported but unused 😉

Suggested change
import { Component, onWillStart, useState } from "@odoo/owl";
import { Component, useState } from "@odoo/owl";

openLeads() {
this.action.doAction({
type: "ir.actions.act_window",
name: "Leads",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This action label is user-facing, so it should go through _t, the JS translation method (import { _t } from "@web/core/l10n/translation").

Suggested change
name: "Leads",
name: _t("Leads"),

t-model="state[item.id]"
t-att-id="'check_' + item.id"
/>
<label class="form-check-label" t-att-id="'check_' + item.id" t-out="item.description"/>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently you have duplicated ids. It looks like its works but it's not the way 😅 No big deal thoug, just assign the for attribute of the label and you'll be good to go 👍

Suggested change
<label class="form-check-label" t-att-id="'check_' + item.id" t-out="item.description"/>
<label class="form-check-label" t-att-for="'check_' + item.id" t-out="item.description"/>

import { Component, xml } from "@odoo/owl";

export class NumberCard extends Component {
static template = xml`
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We always make our props explicit. Or at least as much as possible. It helps everyone reading the component and debugging. It's probably the only piece of documentation we try to write on every single component 😄

Suggested change
static template = xml`
static props = {
title: String,
value: { optional: true },
};
static template = xml`

import { loadJS } from "@web/core/assets";

export class PieChart extends Component {
static template = "awesome_dashboard.PieChart";
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, let's make the props explicit 👍

return;
}
if (this.chart) {
this.chart.destroy();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The chart is destroyed before re-rendering, which is good, but it is never destroyed when the component is unmounted. Chart.js keeps an object attached to the canvas, so cleaning it up teaches the right lifecycle habit for external libraries. Leaving it as-is accepts a small memory/resource leak when the dashboard is left or reloaded. What I would do instead is import onWillUnmount and destroy the chart there to clean it up a bit. 👍

# awesome_dashboard/static/src/dashboard/pie_chart.js (setup): destroy the Chart.js instance when Owl removes the component.
        onWillUnmount(() => {
            this.chart?.destroy();
        });

import { PieChart } from "./pie_chart";

export class PieChartCard extends Component {
static components = { PieChart };
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

props 😄

<input type="checkbox" t-att-checked="props.todo.isCompleted" t-on-change="() => props.toggleState(props.todo.id)"/>
<t t-esc="props.todo.id"/>. <t t-esc="props.todo.description"/>
</div>
<span class="fa fa-remove" t-on-click="() => props.deleteTodo(props.todo.id)"/>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a clickable action, so it should be a button rather than a span. From seeing everyone do it, I understand this is the way the tutorial tells you to do but it's prefereable to use <button>. The current version works but it is less clear and weaker for keyboard users and assistive technologies. Just keep in mind: Callable action -> Button.

Suggested change
<span class="fa fa-remove" t-on-click="() => props.deleteTodo(props.todo.id)"/>
<button type="button" class="btn btn-link p-0" t-on-click="() => props.deleteTodo(props.todo.id)">
<i class="fa fa-remove"/>
</button>

Comment thread awesome_owl/static/src/todo/todolist.js Outdated
}

addTodo(ev) {
if (ev.keyCode == 13) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this too comes from the tutorial I would guess but we try to use the key names a lot more than the key codes to get a more self explanatory code. In opposition to ev.keyCode == 13, here, you understand instantaneously that this triggers on "Enter" input 👍

Suggested change
if (ev.keyCode == 13) {
if (ev.key === "Enter") {

…odos and t-shirt sales dashboard

Problem:
- No existing module for handling simple todo list.
- No existing module for analysing t-shirt sales.

Solution:
- New module (100% client-side) with basic components such as todo list and counter.
- New module (100% client-side) implementing a dashboard for t-shirt sales analysis.
@sidum-odoo sidum-odoo force-pushed the 19.0-web-framework-tutorial-sidum branch from 3558516 to 83f6601 Compare June 1, 2026 12:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants