From 33cc55c94c74bbdade6baecdc0480ff55cbbba97 Mon Sep 17 00:00:00 2001 From: "Robin (robal)" Date: Fri, 19 Dec 2025 10:36:19 +0100 Subject: [PATCH 01/18] [IMP] awesome_owl: added counter, card and todo list components Discover the web framework tutorial - Chapter 1, section 1 to 8 --- awesome_owl/static/src/card/card.js | 9 +++++++++ awesome_owl/static/src/card/card.xml | 15 +++++++++++++++ awesome_owl/static/src/counter/counter.js | 22 ++++++++++++++++++++++ awesome_owl/static/src/counter/counter.xml | 9 +++++++++ awesome_owl/static/src/playground.js | 19 ++++++++++++++++++- awesome_owl/static/src/playground.xml | 9 ++++++++- awesome_owl/static/src/todo/todo-item.js | 11 +++++++++++ awesome_owl/static/src/todo/todo-item.xml | 11 +++++++++++ awesome_owl/static/src/todo/todo-list.js | 15 +++++++++++++++ awesome_owl/static/src/todo/todo-list.xml | 10 ++++++++++ 10 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 awesome_owl/static/src/card/card.js create mode 100644 awesome_owl/static/src/card/card.xml create mode 100644 awesome_owl/static/src/counter/counter.js create mode 100644 awesome_owl/static/src/counter/counter.xml create mode 100644 awesome_owl/static/src/todo/todo-item.js create mode 100644 awesome_owl/static/src/todo/todo-item.xml create mode 100644 awesome_owl/static/src/todo/todo-list.js create mode 100644 awesome_owl/static/src/todo/todo-list.xml diff --git a/awesome_owl/static/src/card/card.js b/awesome_owl/static/src/card/card.js new file mode 100644 index 00000000000..f934fbf140f --- /dev/null +++ b/awesome_owl/static/src/card/card.js @@ -0,0 +1,9 @@ +import { Component } from "@odoo/owl"; + +export class Card extends Component { + static template = "awesome_owl.card"; + static props = { + title: String, + content: String, + }; +} diff --git a/awesome_owl/static/src/card/card.xml b/awesome_owl/static/src/card/card.xml new file mode 100644 index 00000000000..6df30f51cea --- /dev/null +++ b/awesome_owl/static/src/card/card.xml @@ -0,0 +1,15 @@ + + + + +
+
+
+

+ +

+
+
+
+ +
diff --git a/awesome_owl/static/src/counter/counter.js b/awesome_owl/static/src/counter/counter.js new file mode 100644 index 00000000000..d6d92784524 --- /dev/null +++ b/awesome_owl/static/src/counter/counter.js @@ -0,0 +1,22 @@ +import { useState, Component } from "@odoo/owl"; + +export class Counter extends Component { + static template = "awesome_owl.counter"; + static props = { + onChange: { + type: Function, + optional: true, + }, + }; + + setup() { + this.state = useState({ value: 1 }); + } + + increment() { + this.state.value++; + if (this.props.onChange) { + this.props.onChange(); + } + } +} diff --git a/awesome_owl/static/src/counter/counter.xml b/awesome_owl/static/src/counter/counter.xml new file mode 100644 index 00000000000..5e0ec2135c0 --- /dev/null +++ b/awesome_owl/static/src/counter/counter.xml @@ -0,0 +1,9 @@ + + + + +

Counter:

+ +
+ +
diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js index 4ac769b0aa5..6b571e58aa5 100644 --- a/awesome_owl/static/src/playground.js +++ b/awesome_owl/static/src/playground.js @@ -1,5 +1,22 @@ -import { Component } from "@odoo/owl"; +import { markup, useState, Component } from "@odoo/owl"; +import { Counter } from "./counter/counter"; +import { Card } from "./card/card"; +import { TodoList } from "./todo/todo-list"; export class Playground extends Component { static template = "awesome_owl.playground"; + static components = { Counter, Card, TodoList }; + + setup() { + this.state = useState({ sum: 2 }); + } + + incrementSum() { + this.state.sum++; + } + + title1 = "Card 1"; + title2 = "Card 2"; + content1 = "
My content
"; + content2 = markup("
My content
"); } diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml index 4fb905d59f9..fb92e1c3ffb 100644 --- a/awesome_owl/static/src/playground.xml +++ b/awesome_owl/static/src/playground.xml @@ -5,6 +5,13 @@
hello world
- + + +

The sum is

+ + + + + diff --git a/awesome_owl/static/src/todo/todo-item.js b/awesome_owl/static/src/todo/todo-item.js new file mode 100644 index 00000000000..365c51083be --- /dev/null +++ b/awesome_owl/static/src/todo/todo-item.js @@ -0,0 +1,11 @@ +import { Component } from "@odoo/owl"; + +export class TodoItem extends Component { + static template = "awesome_owl.todo-item"; + static props = { + todo: { + type: Object, + shape: { id: Number, description: String, isCompleted: Boolean}, + }, + }; +} diff --git a/awesome_owl/static/src/todo/todo-item.xml b/awesome_owl/static/src/todo/todo-item.xml new file mode 100644 index 00000000000..0ae91f0bbf5 --- /dev/null +++ b/awesome_owl/static/src/todo/todo-item.xml @@ -0,0 +1,11 @@ + + + + +
+ + +
+
+ +
diff --git a/awesome_owl/static/src/todo/todo-list.js b/awesome_owl/static/src/todo/todo-list.js new file mode 100644 index 00000000000..7febc8037b0 --- /dev/null +++ b/awesome_owl/static/src/todo/todo-list.js @@ -0,0 +1,15 @@ +import { useState, Component } from "@odoo/owl"; +import { TodoItem } from "./todo-item"; + +export class TodoList extends Component { + static template = "awesome_owl.todo-list"; + static components = { TodoItem } + + setup() { + this.state = useState([ + { id: 1, description: "buy water", isCompleted: true }, + { id: 2, description: "buy bread", isCompleted: false }, + { id: 3, description: "buy milk", isCompleted: false }, + ]); + } +} diff --git a/awesome_owl/static/src/todo/todo-list.xml b/awesome_owl/static/src/todo/todo-list.xml new file mode 100644 index 00000000000..0f7bf19737c --- /dev/null +++ b/awesome_owl/static/src/todo/todo-list.xml @@ -0,0 +1,10 @@ + + + + + + + + + + From 3b27e955e8813ac0187b4b94c0bbec9a3e13b343 Mon Sep 17 00:00:00 2001 From: "Robin (robal)" Date: Fri, 19 Dec 2025 11:21:23 +0100 Subject: [PATCH 02/18] [IMP] awesome_owl: dynamically add todo items with an input field Discover the web framework tutorial - Chapter 1, section 9 --- awesome_owl/static/src/todo/todo-list.js | 17 ++++++++++++----- awesome_owl/static/src/todo/todo-list.xml | 3 ++- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/awesome_owl/static/src/todo/todo-list.js b/awesome_owl/static/src/todo/todo-list.js index 7febc8037b0..d3b4e280bf3 100644 --- a/awesome_owl/static/src/todo/todo-list.js +++ b/awesome_owl/static/src/todo/todo-list.js @@ -6,10 +6,17 @@ export class TodoList extends Component { static components = { TodoItem } setup() { - this.state = useState([ - { id: 1, description: "buy water", isCompleted: true }, - { id: 2, description: "buy bread", isCompleted: false }, - { id: 3, description: "buy milk", isCompleted: false }, - ]); + this.state = useState({todos: [], nextId: 1}); + } + + input_event_handler(event) { + // keyCode is deprecated, use key instead + if (event.key === "Enter") { + if (event.target.value) { + this.state.todos.push({id: this.state.nextId, description: event.target.value, isCompleted: false}); + this.state.nextId++; + event.target.value = ""; + } + } } } diff --git a/awesome_owl/static/src/todo/todo-list.xml b/awesome_owl/static/src/todo/todo-list.xml index 0f7bf19737c..e4bb2142a1e 100644 --- a/awesome_owl/static/src/todo/todo-list.xml +++ b/awesome_owl/static/src/todo/todo-list.xml @@ -2,7 +2,8 @@ - + + From 901c9c5f9c399a6a1a8dfe50751680145faab07e Mon Sep 17 00:00:00 2001 From: "Robin (robal)" Date: Fri, 19 Dec 2025 11:41:09 +0100 Subject: [PATCH 03/18] [IMP] awesome_owl: auto-focus the input for creating TODOs Chapter 1, section 10 --- awesome_owl/static/src/todo/todo-list.js | 4 +++- awesome_owl/static/src/todo/todo-list.xml | 2 +- awesome_owl/static/src/utils.js | 9 +++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 awesome_owl/static/src/utils.js diff --git a/awesome_owl/static/src/todo/todo-list.js b/awesome_owl/static/src/todo/todo-list.js index d3b4e280bf3..5bc68d78728 100644 --- a/awesome_owl/static/src/todo/todo-list.js +++ b/awesome_owl/static/src/todo/todo-list.js @@ -1,5 +1,6 @@ -import { useState, Component } from "@odoo/owl"; +import { onMounted, useRef, useState, Component } from "@odoo/owl"; import { TodoItem } from "./todo-item"; +import { useAutoFocus } from "../utils" export class TodoList extends Component { static template = "awesome_owl.todo-list"; @@ -7,6 +8,7 @@ export class TodoList extends Component { setup() { this.state = useState({todos: [], nextId: 1}); + useAutoFocus("new-todo-input"); } input_event_handler(event) { diff --git a/awesome_owl/static/src/todo/todo-list.xml b/awesome_owl/static/src/todo/todo-list.xml index e4bb2142a1e..41aa608c3ad 100644 --- a/awesome_owl/static/src/todo/todo-list.xml +++ b/awesome_owl/static/src/todo/todo-list.xml @@ -2,7 +2,7 @@ - + diff --git a/awesome_owl/static/src/utils.js b/awesome_owl/static/src/utils.js new file mode 100644 index 00000000000..4d9e30c9eff --- /dev/null +++ b/awesome_owl/static/src/utils.js @@ -0,0 +1,9 @@ +import { useEffect, useRef } from "@odoo/owl"; + +export function useAutoFocus(name) { + let ref = useRef(name); + useEffect( + (el) => el && el.focus(), + () => [ref.el] + ); +} From 92dc4955bea409b3efeb0e961a4ddadeb89aa535 Mon Sep 17 00:00:00 2001 From: "Robin (robal)" Date: Fri, 19 Dec 2025 15:42:54 +0100 Subject: [PATCH 04/18] [IMP] awesome_owl: toggling todos --- awesome_owl/static/src/todo/todo-item.js | 1 + awesome_owl/static/src/todo/todo-item.xml | 1 + awesome_owl/static/src/todo/todo-list.js | 5 +++++ awesome_owl/static/src/todo/todo-list.xml | 2 +- 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/awesome_owl/static/src/todo/todo-item.js b/awesome_owl/static/src/todo/todo-item.js index 365c51083be..c5c9d17a994 100644 --- a/awesome_owl/static/src/todo/todo-item.js +++ b/awesome_owl/static/src/todo/todo-item.js @@ -7,5 +7,6 @@ export class TodoItem extends Component { type: Object, shape: { id: Number, description: String, isCompleted: Boolean}, }, + toggleState: Function, }; } diff --git a/awesome_owl/static/src/todo/todo-item.xml b/awesome_owl/static/src/todo/todo-item.xml index 0ae91f0bbf5..29363bffe43 100644 --- a/awesome_owl/static/src/todo/todo-item.xml +++ b/awesome_owl/static/src/todo/todo-item.xml @@ -3,6 +3,7 @@
+
diff --git a/awesome_owl/static/src/todo/todo-list.js b/awesome_owl/static/src/todo/todo-list.js index 5bc68d78728..9ea1d3fe534 100644 --- a/awesome_owl/static/src/todo/todo-list.js +++ b/awesome_owl/static/src/todo/todo-list.js @@ -21,4 +21,9 @@ export class TodoList extends Component { } } } + + toggleState(todoId) { + const selectedTodo = this.state.todos.find(todo => todo.id == todoId) + selectedTodo.isCompleted = !selectedTodo.isCompleted + } } diff --git a/awesome_owl/static/src/todo/todo-list.xml b/awesome_owl/static/src/todo/todo-list.xml index 41aa608c3ad..fef97006df7 100644 --- a/awesome_owl/static/src/todo/todo-list.xml +++ b/awesome_owl/static/src/todo/todo-list.xml @@ -4,7 +4,7 @@ - + From 8e74efeee7a45e1ff458ec9f183abab421f5a2e0 Mon Sep 17 00:00:00 2001 From: "Robin (robal)" Date: Fri, 19 Dec 2025 15:49:47 +0100 Subject: [PATCH 05/18] [IMP] awesome_owl: add button to delete TODOs --- awesome_owl/static/src/todo/todo-item.js | 1 + awesome_owl/static/src/todo/todo-item.xml | 1 + awesome_owl/static/src/todo/todo-list.js | 13 +++++++++++-- awesome_owl/static/src/todo/todo-list.xml | 2 +- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/awesome_owl/static/src/todo/todo-item.js b/awesome_owl/static/src/todo/todo-item.js index c5c9d17a994..3f05f1ddc7d 100644 --- a/awesome_owl/static/src/todo/todo-item.js +++ b/awesome_owl/static/src/todo/todo-item.js @@ -8,5 +8,6 @@ export class TodoItem extends Component { shape: { id: Number, description: String, isCompleted: Boolean}, }, toggleState: Function, + removeTodo: Function, }; } diff --git a/awesome_owl/static/src/todo/todo-item.xml b/awesome_owl/static/src/todo/todo-item.xml index 29363bffe43..572f326dc9a 100644 --- a/awesome_owl/static/src/todo/todo-item.xml +++ b/awesome_owl/static/src/todo/todo-item.xml @@ -6,6 +6,7 @@ + diff --git a/awesome_owl/static/src/todo/todo-list.js b/awesome_owl/static/src/todo/todo-list.js index 9ea1d3fe534..d54a0813c34 100644 --- a/awesome_owl/static/src/todo/todo-list.js +++ b/awesome_owl/static/src/todo/todo-list.js @@ -23,7 +23,16 @@ export class TodoList extends Component { } toggleState(todoId) { - const selectedTodo = this.state.todos.find(todo => todo.id == todoId) - selectedTodo.isCompleted = !selectedTodo.isCompleted + const selectedTodo = this.state.todos.find((todo) => todo.id === todoId); + if (selectedTodo) { + selectedTodo.isCompleted = !selectedTodo.isCompleted; + } + } + + removeTodo(todoId) { + const index = this.state.todos.findIndex((todo) => todo.id === todoId); + if (index >= 0) { + this.state.todos.splice(index, 1); + } } } diff --git a/awesome_owl/static/src/todo/todo-list.xml b/awesome_owl/static/src/todo/todo-list.xml index fef97006df7..f38db5b98f1 100644 --- a/awesome_owl/static/src/todo/todo-list.xml +++ b/awesome_owl/static/src/todo/todo-list.xml @@ -4,7 +4,7 @@ - + From 71bde6ff4fefdb7eb15e99065f5fb7cfa821e615 Mon Sep 17 00:00:00 2001 From: "Robin (robal)" Date: Mon, 22 Dec 2025 08:37:04 +0100 Subject: [PATCH 06/18] [IMP] awesome_owl: generic cards with slots --- awesome_owl/static/src/card/card.js | 2 +- awesome_owl/static/src/card/card.xml | 4 +--- awesome_owl/static/src/counter/counter.xml | 2 +- awesome_owl/static/src/playground.js | 6 ++--- awesome_owl/static/src/playground.xml | 28 +++++++++++++--------- 5 files changed, 22 insertions(+), 20 deletions(-) diff --git a/awesome_owl/static/src/card/card.js b/awesome_owl/static/src/card/card.js index f934fbf140f..e3bf70bb6ff 100644 --- a/awesome_owl/static/src/card/card.js +++ b/awesome_owl/static/src/card/card.js @@ -4,6 +4,6 @@ export class Card extends Component { static template = "awesome_owl.card"; static props = { title: String, - content: String, + slots: {type: Object, optional: true}, }; } diff --git a/awesome_owl/static/src/card/card.xml b/awesome_owl/static/src/card/card.xml index 6df30f51cea..2ec51605223 100644 --- a/awesome_owl/static/src/card/card.xml +++ b/awesome_owl/static/src/card/card.xml @@ -5,9 +5,7 @@
-

- -

+
diff --git a/awesome_owl/static/src/counter/counter.xml b/awesome_owl/static/src/counter/counter.xml index 5e0ec2135c0..08590167539 100644 --- a/awesome_owl/static/src/counter/counter.xml +++ b/awesome_owl/static/src/counter/counter.xml @@ -3,7 +3,7 @@

Counter:

- +
diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js index 6b571e58aa5..560db73de0a 100644 --- a/awesome_owl/static/src/playground.js +++ b/awesome_owl/static/src/playground.js @@ -15,8 +15,6 @@ export class Playground extends Component { this.state.sum++; } - title1 = "Card 1"; - title2 = "Card 2"; - content1 = "
My content
"; - content2 = markup("
My content
"); + someHtmlEscaped = "
My content
"; + someHtml = markup("
My content
"); } diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml index fb92e1c3ffb..5699ac0c128 100644 --- a/awesome_owl/static/src/playground.xml +++ b/awesome_owl/static/src/playground.xml @@ -2,16 +2,22 @@ -
- hello world -
- - -

The sum is

- - - - - + +

+

+
+ + + + + + + +

The sum is

+
+ + +
+
From f9086da598ebb5fa139430e51daec73be018fb9f Mon Sep 17 00:00:00 2001 From: "Robin (robal)" Date: Mon, 22 Dec 2025 09:08:00 +0100 Subject: [PATCH 07/18] [IMP] awesome_owl: add toggle to hide/minimize card contents --- awesome_owl/static/src/card/card.js | 10 +++++++++- awesome_owl/static/src/card/card.xml | 7 +++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/awesome_owl/static/src/card/card.js b/awesome_owl/static/src/card/card.js index e3bf70bb6ff..940e461f25c 100644 --- a/awesome_owl/static/src/card/card.js +++ b/awesome_owl/static/src/card/card.js @@ -1,4 +1,4 @@ -import { Component } from "@odoo/owl"; +import { useState, Component } from "@odoo/owl"; export class Card extends Component { static template = "awesome_owl.card"; @@ -6,4 +6,12 @@ export class Card extends Component { title: String, slots: {type: Object, optional: true}, }; + + setup() { + this.state = useState({ visible: true }); + } + + toggleVisible() { + this.state.visible = !this.state.visible; + } } diff --git a/awesome_owl/static/src/card/card.xml b/awesome_owl/static/src/card/card.xml index 2ec51605223..57ff80c37b6 100644 --- a/awesome_owl/static/src/card/card.xml +++ b/awesome_owl/static/src/card/card.xml @@ -4,8 +4,11 @@
-
- +
+ + +
+
From 9482d39f0f4a68b7e44017bd6d18e03e470c633b Mon Sep 17 00:00:00 2001 From: "Robin (robal)" Date: Mon, 22 Dec 2025 09:35:08 +0100 Subject: [PATCH 08/18] [IMP] awesome_dashboard: add a layout with background color - Discover the web framework, chapter 2 --- awesome_dashboard/static/src/dashboard.js | 2 ++ awesome_dashboard/static/src/dashboard.scss | 3 +++ awesome_dashboard/static/src/dashboard.xml | 4 +++- 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 awesome_dashboard/static/src/dashboard.scss diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index c4fb245621b..e1297aadeb4 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -1,8 +1,10 @@ import { Component } from "@odoo/owl"; import { registry } from "@web/core/registry"; +import { Layout } from "@web/search/layout"; class AwesomeDashboard extends Component { static template = "awesome_dashboard.AwesomeDashboard"; + static components = { Layout }; } registry.category("actions").add("awesome_dashboard.dashboard", AwesomeDashboard); diff --git a/awesome_dashboard/static/src/dashboard.scss b/awesome_dashboard/static/src/dashboard.scss new file mode 100644 index 00000000000..32862ec0d82 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard.scss @@ -0,0 +1,3 @@ +.o_dashboard { + background-color: gray; +} diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index 1a2ac9a2fed..1c06610c3c7 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -2,7 +2,9 @@ - hello dashboard + + Some contents for my awesome dashboard! + From 746f5e4f80109bdc10c7acc4f598f2f6e4518e4a Mon Sep 17 00:00:00 2001 From: "Robin (robal)" Date: Mon, 22 Dec 2025 10:34:48 +0100 Subject: [PATCH 09/18] [IMP] awesome_dashboard: add action buttons - Add an action button that redirects to a kanban view of customers - Add an action button that redirects to the lead model --- awesome_dashboard/static/src/dashboard.js | 20 +++++++++++++++++++- awesome_dashboard/static/src/dashboard.xml | 6 +++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index e1297aadeb4..00589cd37d1 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -1,10 +1,28 @@ -import { Component } from "@odoo/owl"; import { registry } from "@web/core/registry"; +import { useService } from "@web/core/utils/hooks"; import { Layout } from "@web/search/layout"; +import { Component } from "@odoo/owl"; class AwesomeDashboard extends Component { static template = "awesome_dashboard.AwesomeDashboard"; static components = { Layout }; + + setup() { + this.action = useService("action"); + } + + actionCustomers() { + this.action.doAction("base.action_partner_form", { viewType: "kanban"}); + } + + actionLeads() { + this.action.doAction({ + type: "ir.actions.act_window", + name: "All leads", + res_model: "crm.lead", + views: [[false, "list"], [false, "form"]], + }); + } } registry.category("actions").add("awesome_dashboard.dashboard", AwesomeDashboard); diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index 1c06610c3c7..fa514d968ef 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -3,7 +3,11 @@ - Some contents for my awesome dashboard! + + + + + Some contents for my awesome dashboard! From 1921d332e3adf73c3bdad312beb0774534351e0b Mon Sep 17 00:00:00 2001 From: "Robin (robal)" Date: Mon, 22 Dec 2025 11:00:37 +0100 Subject: [PATCH 10/18] [IMP] awesome_dashboard: add dashboard item component --- .../static/src/dashboard-item/dashboard-item.js | 12 ++++++++++++ .../static/src/dashboard-item/dashboard-item.xml | 12 ++++++++++++ awesome_dashboard/static/src/dashboard.js | 3 ++- awesome_dashboard/static/src/dashboard.xml | 6 +++++- 4 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 awesome_dashboard/static/src/dashboard-item/dashboard-item.js create mode 100644 awesome_dashboard/static/src/dashboard-item/dashboard-item.xml diff --git a/awesome_dashboard/static/src/dashboard-item/dashboard-item.js b/awesome_dashboard/static/src/dashboard-item/dashboard-item.js new file mode 100644 index 00000000000..27ec1ccdb48 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard-item/dashboard-item.js @@ -0,0 +1,12 @@ +import { Component } from "@odoo/owl"; + +export class DashboardItem extends Component { + static template = "awesome_dashboard.dashboard-item"; + static props = { + size: { type: Number, optional: true }, + slots: { type: Object, optional: true }, + }; + static defaultProps = { + size: 1, + }; +} diff --git a/awesome_dashboard/static/src/dashboard-item/dashboard-item.xml b/awesome_dashboard/static/src/dashboard-item/dashboard-item.xml new file mode 100644 index 00000000000..c035fb0ff8e --- /dev/null +++ b/awesome_dashboard/static/src/dashboard-item/dashboard-item.xml @@ -0,0 +1,12 @@ + + + + +
+
+ +
+
+
+ +
diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index 00589cd37d1..4480e45f6d4 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -2,10 +2,11 @@ import { registry } from "@web/core/registry"; import { useService } from "@web/core/utils/hooks"; import { Layout } from "@web/search/layout"; import { Component } from "@odoo/owl"; +import { DashboardItem } from "./dashboard-item/dashboard-item" class AwesomeDashboard extends Component { static template = "awesome_dashboard.AwesomeDashboard"; - static components = { Layout }; + static components = { Layout, DashboardItem }; setup() { this.action = useService("action"); diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index fa514d968ef..7aeedbb2524 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -7,7 +7,11 @@
- Some contents for my awesome dashboard! + + Small content + Long content + Small content 2 + From d28bdb91c4da53a8f9191bd0decb4dfca1277d63 Mon Sep 17 00:00:00 2001 From: "Robin (robal)" Date: Mon, 22 Dec 2025 11:31:01 +0100 Subject: [PATCH 11/18] [IMP] awesome_dashboard: add dashboard items with statistics from RPC call --- awesome_dashboard/static/src/dashboard.js | 8 +++++++- awesome_dashboard/static/src/dashboard.xml | 8 +++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index 4480e45f6d4..0c3bc8ff020 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -1,7 +1,8 @@ import { registry } from "@web/core/registry"; +import { rpc } from "@web/core/network/rpc"; import { useService } from "@web/core/utils/hooks"; import { Layout } from "@web/search/layout"; -import { Component } from "@odoo/owl"; +import { Component, onWillStart, useState } from "@odoo/owl"; import { DashboardItem } from "./dashboard-item/dashboard-item" class AwesomeDashboard extends Component { @@ -10,6 +11,11 @@ class AwesomeDashboard extends Component { setup() { this.action = useService("action"); + this.state = useState({ statistics: {} }); + onWillStart( async () => { + const result = await rpc("/awesome_dashboard/statistics"); + this.state.statistics = result; + }); } actionCustomers() { diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index 7aeedbb2524..c0d915a16aa 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -8,9 +8,11 @@ - Small content - Long content - Small content 2 + Number of new orders this month

+ Total amount of new orders this month

+ Average amount of t-shirt by order this month

+ Number of cancelled orders this month

+ Average time for an order to go from 'new' to 'sent' or 'cancelled'

From c59f6e071f9407b4884e51a42b0a516b1980ea2c Mon Sep 17 00:00:00 2001 From: "Robin (robal)" Date: Mon, 22 Dec 2025 13:09:47 +0100 Subject: [PATCH 12/18] [IMP] awesome_dashboard: create a service to cache rpc call --- awesome_dashboard/static/src/dashboard.js | 6 +++--- awesome_dashboard/static/src/statistics-service.js | 12 ++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 awesome_dashboard/static/src/statistics-service.js diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index 0c3bc8ff020..d38d63872f0 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -1,5 +1,4 @@ import { registry } from "@web/core/registry"; -import { rpc } from "@web/core/network/rpc"; import { useService } from "@web/core/utils/hooks"; import { Layout } from "@web/search/layout"; import { Component, onWillStart, useState } from "@odoo/owl"; @@ -11,15 +10,16 @@ class AwesomeDashboard extends Component { setup() { this.action = useService("action"); + this.statistics = useService("awesome_dashboard.statistics") this.state = useState({ statistics: {} }); onWillStart( async () => { - const result = await rpc("/awesome_dashboard/statistics"); + const result = await this.statistics.loadStatistics(); this.state.statistics = result; }); } actionCustomers() { - this.action.doAction("base.action_partner_form", { viewType: "kanban"}); + this.action.doAction("base.action_partner_form", { viewType: "kanban" }); } actionLeads() { diff --git a/awesome_dashboard/static/src/statistics-service.js b/awesome_dashboard/static/src/statistics-service.js new file mode 100644 index 00000000000..75e981ebed7 --- /dev/null +++ b/awesome_dashboard/static/src/statistics-service.js @@ -0,0 +1,12 @@ +import { registry } from "@web/core/registry"; +import { rpc } from "@web/core/network/rpc"; +import { memoize } from "@web/core/utils/functions"; + +export const statisticsService = { + async: ["loadStatistics"], + start() { + return { loadStatistics: memoize(() => rpc("/awesome_dashboard/statistics")) } + } +}; + +registry.category("services").add("awesome_dashboard.statistics", statisticsService); From 1064d05bb841e5d0ad00ca245c2fd26006af47b3 Mon Sep 17 00:00:00 2001 From: "Robin (robal)" Date: Mon, 22 Dec 2025 14:36:46 +0100 Subject: [PATCH 13/18] [IMP] awesome_dashboard: pie chart --- awesome_dashboard/static/src/dashboard.js | 5 ++- awesome_dashboard/static/src/dashboard.xml | 1 + .../static/src/pie-chart/pie-chart.js | 40 +++++++++++++++++++ .../static/src/pie-chart/pie-chart.xml | 8 ++++ 4 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 awesome_dashboard/static/src/pie-chart/pie-chart.js create mode 100644 awesome_dashboard/static/src/pie-chart/pie-chart.xml diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index d38d63872f0..4b9969fd2ba 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -3,14 +3,15 @@ import { useService } from "@web/core/utils/hooks"; import { Layout } from "@web/search/layout"; import { Component, onWillStart, useState } from "@odoo/owl"; import { DashboardItem } from "./dashboard-item/dashboard-item" +import { PieChart } from "./pie-chart/pie-chart"; class AwesomeDashboard extends Component { static template = "awesome_dashboard.AwesomeDashboard"; - static components = { Layout, DashboardItem }; + static components = { Layout, DashboardItem, PieChart }; setup() { this.action = useService("action"); - this.statistics = useService("awesome_dashboard.statistics") + this.statistics = useService("awesome_dashboard.statistics"); this.state = useState({ statistics: {} }); onWillStart( async () => { const result = await this.statistics.loadStatistics(); diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index c0d915a16aa..398f73f78fc 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -13,6 +13,7 @@ Average amount of t-shirt by order this month

Number of cancelled orders this month

Average time for an order to go from 'new' to 'sent' or 'cancelled'

+ diff --git a/awesome_dashboard/static/src/pie-chart/pie-chart.js b/awesome_dashboard/static/src/pie-chart/pie-chart.js new file mode 100644 index 00000000000..d99a02b711b --- /dev/null +++ b/awesome_dashboard/static/src/pie-chart/pie-chart.js @@ -0,0 +1,40 @@ +import { Component, onWillStart, onWillUnmount, onMounted, useRef } from "@odoo/owl"; +import { loadJS } from "@web/core/assets"; +import { DashboardItem } from "../dashboard-item/dashboard-item"; + +export class PieChart extends Component { + static template = "awesome_dashboard.pie-chart"; + static components = { DashboardItem }; + static props = { + data: { type: Array, element: { type: Number }}, + labels: { type: Array, element: { type: String }}, + } + + setup() { + this.canvasRef = useRef("canvas"); + this.chart = null; + + onWillStart(() => loadJS("/web/static/lib/Chart/Chart.js")); + onMounted(this.renderChart); + onWillUnmount(this.destroyChart); + } + + renderChart() { + this.destroyChart(); + + this.chart = new Chart(this.canvasRef.el, { + type: "doughnut", + data: { + labels: this.props.labels, + datasets: [{ data: this.props.data }], + }, + }); + } + + destroyChart() { + if (this.chart) { + this.chart.destroy(); + this.chart = null; + } + } +} diff --git a/awesome_dashboard/static/src/pie-chart/pie-chart.xml b/awesome_dashboard/static/src/pie-chart/pie-chart.xml new file mode 100644 index 00000000000..724ea3d6b5a --- /dev/null +++ b/awesome_dashboard/static/src/pie-chart/pie-chart.xml @@ -0,0 +1,8 @@ + + + + + + + + From 4d2988e48a56174d6974555ee733577df0ca9d0d Mon Sep 17 00:00:00 2001 From: "Robin (robal)" Date: Mon, 22 Dec 2025 14:56:10 +0100 Subject: [PATCH 14/18] [REF] awesome_dashboard: refactor components (part 1) --- .../src/dashboard-item/dashboard-item.js | 1 + .../src/dashboard-item/dashboard-item.xml | 2 ++ awesome_dashboard/static/src/dashboard.scss | 6 +++++ awesome_dashboard/static/src/dashboard.xml | 24 ++++++++++++++----- .../static/src/pie-chart/pie-chart.xml | 2 +- 5 files changed, 28 insertions(+), 7 deletions(-) diff --git a/awesome_dashboard/static/src/dashboard-item/dashboard-item.js b/awesome_dashboard/static/src/dashboard-item/dashboard-item.js index 27ec1ccdb48..d0e775f716c 100644 --- a/awesome_dashboard/static/src/dashboard-item/dashboard-item.js +++ b/awesome_dashboard/static/src/dashboard-item/dashboard-item.js @@ -4,6 +4,7 @@ export class DashboardItem extends Component { static template = "awesome_dashboard.dashboard-item"; static props = { size: { type: Number, optional: true }, + title: String, slots: { type: Object, optional: true }, }; static defaultProps = { diff --git a/awesome_dashboard/static/src/dashboard-item/dashboard-item.xml b/awesome_dashboard/static/src/dashboard-item/dashboard-item.xml index c035fb0ff8e..c104f88eb3c 100644 --- a/awesome_dashboard/static/src/dashboard-item/dashboard-item.xml +++ b/awesome_dashboard/static/src/dashboard-item/dashboard-item.xml @@ -4,6 +4,8 @@
+
+
diff --git a/awesome_dashboard/static/src/dashboard.scss b/awesome_dashboard/static/src/dashboard.scss index 32862ec0d82..78dd7418f7e 100644 --- a/awesome_dashboard/static/src/dashboard.scss +++ b/awesome_dashboard/static/src/dashboard.scss @@ -1,3 +1,9 @@ .o_dashboard { background-color: gray; } + +.stat_number { + color: green; + font-weight: bold; + text-align: center; +} diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index 398f73f78fc..85f11a146bc 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -8,12 +8,24 @@
- Number of new orders this month

- Total amount of new orders this month

- Average amount of t-shirt by order this month

- Number of cancelled orders this month

- Average time for an order to go from 'new' to 'sent' or 'cancelled'

- + +

+ + +

+ + +

+ + +

+ + +

+ + + + diff --git a/awesome_dashboard/static/src/pie-chart/pie-chart.xml b/awesome_dashboard/static/src/pie-chart/pie-chart.xml index 724ea3d6b5a..a01e05e71d6 100644 --- a/awesome_dashboard/static/src/pie-chart/pie-chart.xml +++ b/awesome_dashboard/static/src/pie-chart/pie-chart.xml @@ -2,7 +2,7 @@ - + From ff83420b9461d91d144031155923736f500e2b0a Mon Sep 17 00:00:00 2001 From: "Robin (robal)" Date: Mon, 22 Dec 2025 15:01:58 +0100 Subject: [PATCH 15/18] [REF] awesome_dashboard: refactor/simplify props of PieChart component --- awesome_dashboard/static/src/dashboard.xml | 2 +- awesome_dashboard/static/src/pie-chart/pie-chart.js | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index 85f11a146bc..94546bc2ed4 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -24,7 +24,7 @@

- + diff --git a/awesome_dashboard/static/src/pie-chart/pie-chart.js b/awesome_dashboard/static/src/pie-chart/pie-chart.js index d99a02b711b..5b64c21a021 100644 --- a/awesome_dashboard/static/src/pie-chart/pie-chart.js +++ b/awesome_dashboard/static/src/pie-chart/pie-chart.js @@ -6,8 +6,7 @@ export class PieChart extends Component { static template = "awesome_dashboard.pie-chart"; static components = { DashboardItem }; static props = { - data: { type: Array, element: { type: Number }}, - labels: { type: Array, element: { type: String }}, + data: { type: Object, values: Number }, } setup() { @@ -22,11 +21,13 @@ export class PieChart extends Component { renderChart() { this.destroyChart(); + const labels = Object.keys(this.props.data); + const datapoints = Object.values(this.props.data); this.chart = new Chart(this.canvasRef.el, { type: "doughnut", data: { - labels: this.props.labels, - datasets: [{ data: this.props.data }], + labels: labels, + datasets: [{ data: datapoints }], }, }); } From c9eb39f4c98a52c0323ac8c004188708b25495ea Mon Sep 17 00:00:00 2001 From: "Robin (robal)" Date: Mon, 22 Dec 2025 16:08:13 +0100 Subject: [PATCH 16/18] [IMP] awesome_dashboard: added reactivity --- awesome_dashboard/static/src/dashboard.js | 9 +---- awesome_dashboard/static/src/dashboard.xml | 38 ++++++++++--------- .../static/src/statistics-service.js | 19 ++++++++-- 3 files changed, 37 insertions(+), 29 deletions(-) diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index 4b9969fd2ba..6461e72b607 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -1,7 +1,7 @@ import { registry } from "@web/core/registry"; import { useService } from "@web/core/utils/hooks"; import { Layout } from "@web/search/layout"; -import { Component, onWillStart, useState } from "@odoo/owl"; +import { Component, useState } from "@odoo/owl"; import { DashboardItem } from "./dashboard-item/dashboard-item" import { PieChart } from "./pie-chart/pie-chart"; @@ -11,12 +11,7 @@ class AwesomeDashboard extends Component { setup() { this.action = useService("action"); - this.statistics = useService("awesome_dashboard.statistics"); - this.state = useState({ statistics: {} }); - onWillStart( async () => { - const result = await this.statistics.loadStatistics(); - this.state.statistics = result; - }); + this.statistics = useState(useService("awesome_dashboard.statistics")); } actionCustomers() { diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index 94546bc2ed4..355d79481d0 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -8,24 +8,26 @@ - -

- - -

- - -

- - -

- - -

- - - - +
+ +

+ + +

+ + +

+ + +

+ + +

+ + + + +

diff --git a/awesome_dashboard/static/src/statistics-service.js b/awesome_dashboard/static/src/statistics-service.js index 75e981ebed7..0c97dc57973 100644 --- a/awesome_dashboard/static/src/statistics-service.js +++ b/awesome_dashboard/static/src/statistics-service.js @@ -1,12 +1,23 @@ import { registry } from "@web/core/registry"; import { rpc } from "@web/core/network/rpc"; -import { memoize } from "@web/core/utils/functions"; +import { reactive } from "@odoo/owl"; export const statisticsService = { - async: ["loadStatistics"], start() { - return { loadStatistics: memoize(() => rpc("/awesome_dashboard/statistics")) } - } + let statistics = reactive({ isReady: false }); + async function loadStatistics() { + Object.assign(statistics, await rpc("/awesome_dashboard/statistics"), { isReady: true }); + } + + // Refresh every 10 seconds for testing + //const interval = 10000; + // Refresh every 10 minutes for real + const interval = 600000; + + setInterval(loadStatistics, interval); + loadStatistics(); + return statistics; + }, }; registry.category("services").add("awesome_dashboard.statistics", statisticsService); From ba25f900540846fe9f63b11452cadcbd0f2167c0 Mon Sep 17 00:00:00 2001 From: "Robin (robal)" Date: Mon, 22 Dec 2025 16:48:38 +0100 Subject: [PATCH 17/18] [IMP] awesome_dashboard: attempt to redraw the pie chart reactively --- awesome_dashboard/static/src/pie-chart/pie-chart.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/awesome_dashboard/static/src/pie-chart/pie-chart.js b/awesome_dashboard/static/src/pie-chart/pie-chart.js index 5b64c21a021..46bc6ba3dfd 100644 --- a/awesome_dashboard/static/src/pie-chart/pie-chart.js +++ b/awesome_dashboard/static/src/pie-chart/pie-chart.js @@ -1,4 +1,4 @@ -import { Component, onWillStart, onWillUnmount, onMounted, useRef } from "@odoo/owl"; +import { Component, onWillStart, onWillUnmount, onMounted, useRef, onWillUpdateProps } from "@odoo/owl"; import { loadJS } from "@web/core/assets"; import { DashboardItem } from "../dashboard-item/dashboard-item"; @@ -15,6 +15,7 @@ export class PieChart extends Component { onWillStart(() => loadJS("/web/static/lib/Chart/Chart.js")); onMounted(this.renderChart); + onWillUpdateProps(this.updateChart); onWillUnmount(this.destroyChart); } @@ -31,6 +32,14 @@ export class PieChart extends Component { }, }); } + + updateChart(newProps) { + if (this.chart) { + const datapoints = Object.values(newProps.data); + Object.assign(this.chart.data.datasets[0], { data: datapoints }); + this.chart.update(); + } + } destroyChart() { if (this.chart) { From b0be018adb64a943a3e3391c2255c4df69298ae3 Mon Sep 17 00:00:00 2001 From: "Robin (robal)" Date: Mon, 22 Dec 2025 17:27:44 +0100 Subject: [PATCH 18/18] [IMP] awesome_dashboard: make dashboard generic --- .../src/dashboard-item/dashboard-item.js | 6 +- .../src/dashboard-item/dashboard-item.xml | 6 +- awesome_dashboard/static/src/dashboard.js | 64 ++++++++++++++++++- awesome_dashboard/static/src/dashboard.scss | 6 -- awesome_dashboard/static/src/dashboard.xml | 24 ++----- .../static/src/number-card/number-card.js | 9 +++ .../static/src/number-card/number-card.scss | 5 ++ .../static/src/number-card/number-card.xml | 12 ++++ .../static/src/pie-chart/pie-chart-card.js | 11 ++++ .../static/src/pie-chart/pie-chart-card.xml | 12 ++++ 10 files changed, 119 insertions(+), 36 deletions(-) create mode 100644 awesome_dashboard/static/src/number-card/number-card.js create mode 100644 awesome_dashboard/static/src/number-card/number-card.scss create mode 100644 awesome_dashboard/static/src/number-card/number-card.xml create mode 100644 awesome_dashboard/static/src/pie-chart/pie-chart-card.js create mode 100644 awesome_dashboard/static/src/pie-chart/pie-chart-card.xml diff --git a/awesome_dashboard/static/src/dashboard-item/dashboard-item.js b/awesome_dashboard/static/src/dashboard-item/dashboard-item.js index d0e775f716c..ab480f80323 100644 --- a/awesome_dashboard/static/src/dashboard-item/dashboard-item.js +++ b/awesome_dashboard/static/src/dashboard-item/dashboard-item.js @@ -3,11 +3,7 @@ import { Component } from "@odoo/owl"; export class DashboardItem extends Component { static template = "awesome_dashboard.dashboard-item"; static props = { - size: { type: Number, optional: true }, - title: String, + size: Number, slots: { type: Object, optional: true }, }; - static defaultProps = { - size: 1, - }; } diff --git a/awesome_dashboard/static/src/dashboard-item/dashboard-item.xml b/awesome_dashboard/static/src/dashboard-item/dashboard-item.xml index c104f88eb3c..f0c6d50d65c 100644 --- a/awesome_dashboard/static/src/dashboard-item/dashboard-item.xml +++ b/awesome_dashboard/static/src/dashboard-item/dashboard-item.xml @@ -3,11 +3,7 @@
-
-
-
- -
+
diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index 6461e72b607..91a99d78eb8 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -3,15 +3,75 @@ import { useService } from "@web/core/utils/hooks"; import { Layout } from "@web/search/layout"; import { Component, useState } from "@odoo/owl"; import { DashboardItem } from "./dashboard-item/dashboard-item" -import { PieChart } from "./pie-chart/pie-chart"; +import { NumberCard } from "./number-card/number-card" +import { PieChartCard } from "./pie-chart/pie-chart-card" class AwesomeDashboard extends Component { static template = "awesome_dashboard.AwesomeDashboard"; - static components = { Layout, DashboardItem, PieChart }; + static components = { Layout, DashboardItem, NumberCard, PieChartCard }; setup() { this.action = useService("action"); this.statistics = useState(useService("awesome_dashboard.statistics")); + + // Dashboard items + this.items = [ + { + id: "nb_new_orders", + description: "Number of new orders this month", + component: NumberCard, + props: (data) => ({ + title: "Number of new orders this month", + value: data.nb_new_orders, + }), + }, + { + id: "total_amount", + description: "Total amount of new orders this month", + component: NumberCard, + props: (data) => ({ + title: "Total amount of new orders this month", + value: data.total_amount, + }), + }, + { + id: "average_quantity", + description: "Average amount of t-shirt by order this month", + component: NumberCard, + props: (data) => ({ + title: "Average amount of t-shirt by order this month", + value: data.average_quantity, + }), + }, + { + id: "nb_cancelled_orders", + description: "Number of cancelled orders this month", + component: NumberCard, + props: (data) => ({ + title: "Number of cancelled orders this month", + value: data.nb_cancelled_orders, + }), + }, + { + id: "average_time", + description: "Average time for an order to go from 'new' to 'sent' or 'cancelled'", + component: NumberCard, + props: (data) => ({ + title: "Average time for an order to go from 'new' to 'sent' or 'cancelled'", + value: data.average_time, + }), + }, + { + id: "orders_by_size", + description: "Ordered T-shirts by size", + component: PieChartCard, + size: 2, + props: (data) => ({ + title: "Ordered T-shirts by size", + value: data.orders_by_size, + }), + }, + ]; } actionCustomers() { diff --git a/awesome_dashboard/static/src/dashboard.scss b/awesome_dashboard/static/src/dashboard.scss index 78dd7418f7e..32862ec0d82 100644 --- a/awesome_dashboard/static/src/dashboard.scss +++ b/awesome_dashboard/static/src/dashboard.scss @@ -1,9 +1,3 @@ .o_dashboard { background-color: gray; } - -.stat_number { - color: green; - font-weight: bold; - text-align: center; -} diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index 355d79481d0..8f60c06385a 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -9,24 +9,12 @@
- -

- - -

- - -

- - -

- - -

- - - - + + + + + +

diff --git a/awesome_dashboard/static/src/number-card/number-card.js b/awesome_dashboard/static/src/number-card/number-card.js new file mode 100644 index 00000000000..173497ff13f --- /dev/null +++ b/awesome_dashboard/static/src/number-card/number-card.js @@ -0,0 +1,9 @@ +import { Component } from "@odoo/owl"; + +export class NumberCard extends Component { + static template = "awesome_dashboard.number-card"; + static props = { + title: String, + value: Number, + }; +} diff --git a/awesome_dashboard/static/src/number-card/number-card.scss b/awesome_dashboard/static/src/number-card/number-card.scss new file mode 100644 index 00000000000..5321e9b2a13 --- /dev/null +++ b/awesome_dashboard/static/src/number-card/number-card.scss @@ -0,0 +1,5 @@ +.number-card-value { + color: green; + font-weight: bold; + text-align: center; +} diff --git a/awesome_dashboard/static/src/number-card/number-card.xml b/awesome_dashboard/static/src/number-card/number-card.xml new file mode 100644 index 00000000000..b349bb6da35 --- /dev/null +++ b/awesome_dashboard/static/src/number-card/number-card.xml @@ -0,0 +1,12 @@ + + + + +
+
+
+

+

+
+ +
diff --git a/awesome_dashboard/static/src/pie-chart/pie-chart-card.js b/awesome_dashboard/static/src/pie-chart/pie-chart-card.js new file mode 100644 index 00000000000..4e2e767c05d --- /dev/null +++ b/awesome_dashboard/static/src/pie-chart/pie-chart-card.js @@ -0,0 +1,11 @@ +import { Component } from "@odoo/owl"; +import { PieChart } from "./pie-chart"; + +export class PieChartCard extends Component { + static template = "awesome_dashboard.pie-chart-card"; + static props = { + title: String, + value: { type: Object, values: Number }, + }; + static components = { PieChart }; +} diff --git a/awesome_dashboard/static/src/pie-chart/pie-chart-card.xml b/awesome_dashboard/static/src/pie-chart/pie-chart-card.xml new file mode 100644 index 00000000000..eff186e06bd --- /dev/null +++ b/awesome_dashboard/static/src/pie-chart/pie-chart-card.xml @@ -0,0 +1,12 @@ + + + + +
+
+
+ +
+
+ +