[ADD] awesome_owl, awesome_dashboard: basic client-side modules for todos and t-shirt sales dashboard#1307
Conversation
e8ae96f to
26d5ee0
Compare
26d5ee0 to
18dafec
Compare
18dafec to
3558516
Compare
|
@Megaaaaaa ready for review |
Megaaaaaa
left a comment
There was a problem hiding this comment.
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"; | |||
There was a problem hiding this comment.
Imported but unused 😉
| import { Component, onWillStart, useState } from "@odoo/owl"; | |
| import { Component, useState } from "@odoo/owl"; |
| openLeads() { | ||
| this.action.doAction({ | ||
| type: "ir.actions.act_window", | ||
| name: "Leads", |
There was a problem hiding this comment.
This action label is user-facing, so it should go through _t, the JS translation method (import { _t } from "@web/core/l10n/translation").
| 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"/> |
There was a problem hiding this comment.
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 👍
| <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` |
There was a problem hiding this comment.
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 😄
| 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"; |
There was a problem hiding this comment.
Same here, let's make the props explicit 👍
| return; | ||
| } | ||
| if (this.chart) { | ||
| this.chart.destroy(); |
There was a problem hiding this comment.
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 }; |
| <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)"/> |
There was a problem hiding this comment.
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.
| <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> |
| } | ||
|
|
||
| addTodo(ev) { | ||
| if (ev.keyCode == 13) { |
There was a problem hiding this comment.
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 👍
| 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.
3558516 to
83f6601
Compare

Problem:
Solution:
Task-6241079