From 6f5a7ebfa38116afc639480f1e526558c692b541 Mon Sep 17 00:00:00 2001 From: Hashem Khaled Date: Mon, 27 Oct 2025 15:30:27 +0100 Subject: [PATCH 01/24] [IMP] awesome_owl: add Card and Counter components --- awesome_owl/static/src/card/card.js | 9 +++++++++ awesome_owl/static/src/card/card.xml | 13 +++++++++++++ awesome_owl/static/src/counter/counter.js | 13 +++++++++++++ awesome_owl/static/src/counter/counter.xml | 10 ++++++++++ awesome_owl/static/src/playground.js | 9 ++++++++- awesome_owl/static/src/playground.xml | 4 ++++ 6 files changed, 57 insertions(+), 1 deletion(-) 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 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..aaf3580b86f --- /dev/null +++ b/awesome_owl/static/src/card/card.xml @@ -0,0 +1,13 @@ + + + +
+
+
+

+ +

+
+
+
+
\ No newline at end of file diff --git a/awesome_owl/static/src/counter/counter.js b/awesome_owl/static/src/counter/counter.js new file mode 100644 index 00000000000..ca3102514c6 --- /dev/null +++ b/awesome_owl/static/src/counter/counter.js @@ -0,0 +1,13 @@ +import { Component, useState } from "@odoo/owl"; + +export class Counter extends Component { + static template = "awesome_owl.counter"; + + setup() { + this.state = useState({ count: 0 }); + } + + increment() { + this.state.count++; + } +} diff --git a/awesome_owl/static/src/counter/counter.xml b/awesome_owl/static/src/counter/counter.xml new file mode 100644 index 00000000000..4ff9c09597c --- /dev/null +++ b/awesome_owl/static/src/counter/counter.xml @@ -0,0 +1,10 @@ + + + + +
+

Counter:

+ +
+
+
diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js index 657fb8b07bb..cb985159f1b 100644 --- a/awesome_owl/static/src/playground.js +++ b/awesome_owl/static/src/playground.js @@ -1,7 +1,14 @@ /** @odoo-module **/ -import { Component } from "@odoo/owl"; +import { Component, markup } from "@odoo/owl"; +import { Counter } from "./counter/counter"; +import { Card } from "./card/card"; export class Playground extends Component { static template = "awesome_owl.playground"; + + static components = { Counter, Card }; + + card1_content = "
some content
"; + card2_content = markup("
some content
"); } diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml index 4fb905d59f9..40af4885ffa 100644 --- a/awesome_owl/static/src/playground.xml +++ b/awesome_owl/static/src/playground.xml @@ -4,6 +4,10 @@
hello world + + + +
From 5927c8681abbac2a3204f93df4a26d06cd04f7a2 Mon Sep 17 00:00:00 2001 From: Hashem Khaled Date: Mon, 27 Oct 2025 15:48:18 +0100 Subject: [PATCH 02/24] [IMP] awesome_owl: add card props validation --- awesome_owl/static/src/card/card.js | 4 ++-- awesome_owl/static/src/card/card.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/awesome_owl/static/src/card/card.js b/awesome_owl/static/src/card/card.js index f934fbf140f..45e2a650e6b 100644 --- a/awesome_owl/static/src/card/card.js +++ b/awesome_owl/static/src/card/card.js @@ -3,7 +3,7 @@ import { Component } from "@odoo/owl"; export class Card extends Component { static template = "awesome_owl.card"; static props = { - title: String, - content: String, + title: {type: String}, + content: {type: String}, }; } diff --git a/awesome_owl/static/src/card/card.xml b/awesome_owl/static/src/card/card.xml index aaf3580b86f..f6f9e7e54b5 100644 --- a/awesome_owl/static/src/card/card.xml +++ b/awesome_owl/static/src/card/card.xml @@ -10,4 +10,4 @@ - \ No newline at end of file + From 55f402828e50f27e448bea182d302685477e632a Mon Sep 17 00:00:00 2001 From: Hashem Khaled Date: Mon, 27 Oct 2025 16:24:50 +0100 Subject: [PATCH 03/24] [IMP] awesome_owl: display the sum of two counters --- awesome_owl/static/src/counter/counter.js | 5 +++++ awesome_owl/static/src/playground.js | 12 +++++++++++- awesome_owl/static/src/playground.xml | 5 +++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/awesome_owl/static/src/counter/counter.js b/awesome_owl/static/src/counter/counter.js index ca3102514c6..4402260dbe8 100644 --- a/awesome_owl/static/src/counter/counter.js +++ b/awesome_owl/static/src/counter/counter.js @@ -3,11 +3,16 @@ import { Component, useState } from "@odoo/owl"; export class Counter extends Component { static template = "awesome_owl.counter"; + static props = { + onChange: { type: Function, optional: true }, + }; + setup() { this.state = useState({ count: 0 }); } increment() { this.state.count++; + this.props.onChange?.(); } } diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js index cb985159f1b..ecf8352b864 100644 --- a/awesome_owl/static/src/playground.js +++ b/awesome_owl/static/src/playground.js @@ -1,6 +1,6 @@ /** @odoo-module **/ -import { Component, markup } from "@odoo/owl"; +import { Component, markup, useState } from "@odoo/owl"; import { Counter } from "./counter/counter"; import { Card } from "./card/card"; @@ -11,4 +11,14 @@ export class Playground extends Component { card1_content = "
some content
"; card2_content = markup("
some content
"); + + setup() { + this.state = useState({ + sum: 0, + }); + } + + incrementSum = () => { + this.state.sum += 1; + }; } diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml index 40af4885ffa..f717127c31a 100644 --- a/awesome_owl/static/src/playground.xml +++ b/awesome_owl/static/src/playground.xml @@ -4,10 +4,11 @@
hello world - - + + +

The sum is:

From 20d5c857af68e1f76d6b4d4d9ff89be8163d8681 Mon Sep 17 00:00:00 2001 From: Hashem Khaled Date: Mon, 27 Oct 2025 17:03:52 +0100 Subject: [PATCH 04/24] [IMP] awesome_owl: add a todo list --- awesome_owl/__manifest__.py | 2 +- awesome_owl/static/src/playground.js | 10 ++++++---- awesome_owl/static/src/playground.xml | 1 + .../static/src/todo_list/todo_item/todo_item.js | 16 ++++++++++++++++ .../src/todo_list/todo_item/todo_item.xml | 10 ++++++++++ awesome_owl/static/src/todo_list/todo_list.js | 17 +++++++++++++++++ awesome_owl/static/src/todo_list/todo_list.xml | 11 +++++++++++ 7 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 awesome_owl/static/src/todo_list/todo_item/todo_item.js create mode 100644 awesome_owl/static/src/todo_list/todo_item/todo_item.xml create mode 100644 awesome_owl/static/src/todo_list/todo_list.js create mode 100644 awesome_owl/static/src/todo_list/todo_list.xml diff --git a/awesome_owl/__manifest__.py b/awesome_owl/__manifest__.py index 77abad510ef..f3acf2d167c 100644 --- a/awesome_owl/__manifest__.py +++ b/awesome_owl/__manifest__.py @@ -35,7 +35,7 @@ ('include', 'web._assets_bootstrap'), ('include', 'web._assets_core'), 'web/static/src/libs/fontawesome/css/font-awesome.css', - 'awesome_owl/static/src/**/*', + 'awesome_owl/static/src/**/**', ], }, 'license': 'AGPL-3' diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js index ecf8352b864..8a540594619 100644 --- a/awesome_owl/static/src/playground.js +++ b/awesome_owl/static/src/playground.js @@ -3,16 +3,18 @@ import { Component, markup, useState } from "@odoo/owl"; import { Counter } from "./counter/counter"; import { Card } from "./card/card"; +import { TodoList } from "./todo_list/todo_list"; export class Playground extends Component { static template = "awesome_owl.playground"; - static components = { Counter, Card }; - - card1_content = "
some content
"; - card2_content = markup("
some content
"); + static components = { Counter, Card, TodoList }; setup() { + this.card1_content = "
some content
"; + this.card2_content = markup( + "
some content
" + ); this.state = useState({ sum: 0, }); diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml index f717127c31a..d0223d9fb39 100644 --- a/awesome_owl/static/src/playground.xml +++ b/awesome_owl/static/src/playground.xml @@ -9,6 +9,7 @@

The sum is:

+ diff --git a/awesome_owl/static/src/todo_list/todo_item/todo_item.js b/awesome_owl/static/src/todo_list/todo_item/todo_item.js new file mode 100644 index 00000000000..df6b0173575 --- /dev/null +++ b/awesome_owl/static/src/todo_list/todo_item/todo_item.js @@ -0,0 +1,16 @@ +import { Component } from "@odoo/owl"; + +export class TodoItem extends Component { + static template = "awesome_owl.todo_item"; + + static props = { + todo: { + type: Object, + shape: { + id: { type: Number }, + description: { type: String }, + isCompleted: { type: Boolean }, + }, + }, + }; +} diff --git a/awesome_owl/static/src/todo_list/todo_item/todo_item.xml b/awesome_owl/static/src/todo_list/todo_item/todo_item.xml new file mode 100644 index 00000000000..3b008c7c729 --- /dev/null +++ b/awesome_owl/static/src/todo_list/todo_item/todo_item.xml @@ -0,0 +1,10 @@ + + + + +
+

Todo Item #

+

+
+
+
diff --git a/awesome_owl/static/src/todo_list/todo_list.js b/awesome_owl/static/src/todo_list/todo_list.js new file mode 100644 index 00000000000..df70d404ed9 --- /dev/null +++ b/awesome_owl/static/src/todo_list/todo_list.js @@ -0,0 +1,17 @@ +import { Component, useState } from "@odoo/owl"; +import { TodoItem } from "./todo_item/todo_item"; + +export class TodoList extends Component { + static template = "awesome_owl.todo_list"; + + static components = { TodoItem }; + + setup() { + this.state = useState({ + todos: [ + { id: 2, description: "write tutorial", isCompleted: false }, + { id: 3, description: "buy milk", isCompleted: false }, + ], + }); + } +} diff --git a/awesome_owl/static/src/todo_list/todo_list.xml b/awesome_owl/static/src/todo_list/todo_list.xml new file mode 100644 index 00000000000..74172e39387 --- /dev/null +++ b/awesome_owl/static/src/todo_list/todo_list.xml @@ -0,0 +1,11 @@ + + + + +
+ + + +
+
+
From a2c679a0037814750adad13e4a4204270b99595c Mon Sep 17 00:00:00 2001 From: Hashem Khaled Date: Mon, 27 Oct 2025 20:10:50 +0100 Subject: [PATCH 05/24] [FIX] awesome_owl: use dynamic attributes --- awesome_owl/static/src/todo_list/todo_item/todo_item.xml | 5 ++--- awesome_owl/static/src/todo_list/todo_list.js | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/awesome_owl/static/src/todo_list/todo_item/todo_item.xml b/awesome_owl/static/src/todo_list/todo_item/todo_item.xml index 3b008c7c729..5f286ff9478 100644 --- a/awesome_owl/static/src/todo_list/todo_item/todo_item.xml +++ b/awesome_owl/static/src/todo_list/todo_item/todo_item.xml @@ -2,9 +2,8 @@ -
-

Todo Item #

-

+
+

.

diff --git a/awesome_owl/static/src/todo_list/todo_list.js b/awesome_owl/static/src/todo_list/todo_list.js index df70d404ed9..f75091e6c37 100644 --- a/awesome_owl/static/src/todo_list/todo_list.js +++ b/awesome_owl/static/src/todo_list/todo_list.js @@ -9,7 +9,7 @@ export class TodoList extends Component { setup() { this.state = useState({ todos: [ - { id: 2, description: "write tutorial", isCompleted: false }, + { id: 2, description: "write tutorial", isCompleted: true }, { id: 3, description: "buy milk", isCompleted: false }, ], }); From dd51372f72f055ab7101ce2e4c994df9401d246e Mon Sep 17 00:00:00 2001 From: Hashem Khaled Date: Tue, 28 Oct 2025 09:15:20 +0100 Subject: [PATCH 06/24] [IMP] awesome_owl: add a todo from the UI --- awesome_owl/static/src/todo_list/todo_list.js | 21 +++++++++++++++---- .../static/src/todo_list/todo_list.xml | 1 + 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/awesome_owl/static/src/todo_list/todo_list.js b/awesome_owl/static/src/todo_list/todo_list.js index f75091e6c37..d0f378ce16f 100644 --- a/awesome_owl/static/src/todo_list/todo_list.js +++ b/awesome_owl/static/src/todo_list/todo_list.js @@ -8,10 +8,23 @@ export class TodoList extends Component { setup() { this.state = useState({ - todos: [ - { id: 2, description: "write tutorial", isCompleted: true }, - { id: 3, description: "buy milk", isCompleted: false }, - ], + todos: [], }); + this.addTodo = this.addTodo.bind(this); + } + + addTodo(ev) { + if (ev.keyCode === 13 && ev.target.value.trim() !== "") { + const newId = + this.state.todos.length > 0 + ? Math.max(...this.state.todos.map((todo) => todo.id)) + 1 + : 1; + this.state.todos.push({ + id: newId, + description: ev.target.value, + isCompleted: false, + }); + ev.target.value = ""; + } } } diff --git a/awesome_owl/static/src/todo_list/todo_list.xml b/awesome_owl/static/src/todo_list/todo_list.xml index 74172e39387..31cebfb9e10 100644 --- a/awesome_owl/static/src/todo_list/todo_list.xml +++ b/awesome_owl/static/src/todo_list/todo_list.xml @@ -2,6 +2,7 @@ +
From 0d14be0a428ac5afa7938d167155b4948c720c36 Mon Sep 17 00:00:00 2001 From: Hashem Khaled Date: Tue, 28 Oct 2025 12:41:52 +0100 Subject: [PATCH 07/24] [IMP] awesome_owl: implement useAutofocus hook --- awesome_owl/static/src/todo_list/todo_list.js | 2 ++ awesome_owl/static/src/todo_list/todo_list.xml | 2 +- awesome_owl/static/src/utils.js | 9 +++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 awesome_owl/static/src/utils.js diff --git a/awesome_owl/static/src/todo_list/todo_list.js b/awesome_owl/static/src/todo_list/todo_list.js index d0f378ce16f..90e907d0684 100644 --- a/awesome_owl/static/src/todo_list/todo_list.js +++ b/awesome_owl/static/src/todo_list/todo_list.js @@ -1,5 +1,6 @@ import { Component, useState } from "@odoo/owl"; import { TodoItem } from "./todo_item/todo_item"; +import { useAutofocus } from "../utils"; export class TodoList extends Component { static template = "awesome_owl.todo_list"; @@ -11,6 +12,7 @@ export class TodoList extends Component { todos: [], }); this.addTodo = this.addTodo.bind(this); + useAutofocus("input"); } addTodo(ev) { diff --git a/awesome_owl/static/src/todo_list/todo_list.xml b/awesome_owl/static/src/todo_list/todo_list.xml index 31cebfb9e10..b2493340ac0 100644 --- a/awesome_owl/static/src/todo_list/todo_list.xml +++ b/awesome_owl/static/src/todo_list/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..27ec0aab507 --- /dev/null +++ b/awesome_owl/static/src/utils.js @@ -0,0 +1,9 @@ +import { useRef, onMounted } from "@odoo/owl"; + +export function useAutofocus(refName) { + const ref = useRef(refName); + onMounted(() => { + ref.el.focus(); + }); + return { ref }; +} From b1e3577add0c797af488c4816fd1d4e9e0fe8520 Mon Sep 17 00:00:00 2001 From: Hashem Khaled Date: Tue, 28 Oct 2025 13:26:55 +0100 Subject: [PATCH 08/24] [IMP] awesome_owl: implement toggle functionality for todo items --- awesome_owl/static/src/todo_list/todo_item/todo_item.js | 5 +++++ awesome_owl/static/src/todo_list/todo_item/todo_item.xml | 2 +- awesome_owl/static/src/todo_list/todo_list.js | 9 +++++++++ awesome_owl/static/src/todo_list/todo_list.xml | 2 +- 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/awesome_owl/static/src/todo_list/todo_item/todo_item.js b/awesome_owl/static/src/todo_list/todo_item/todo_item.js index df6b0173575..1c856829696 100644 --- a/awesome_owl/static/src/todo_list/todo_item/todo_item.js +++ b/awesome_owl/static/src/todo_list/todo_item/todo_item.js @@ -12,5 +12,10 @@ export class TodoItem extends Component { isCompleted: { type: Boolean }, }, }, + toggleState: Function, }; + + onChange() { + this.props.toggleState(this.props.todo.id); + } } diff --git a/awesome_owl/static/src/todo_list/todo_item/todo_item.xml b/awesome_owl/static/src/todo_list/todo_item/todo_item.xml index 5f286ff9478..4ea37ac5e1c 100644 --- a/awesome_owl/static/src/todo_list/todo_item/todo_item.xml +++ b/awesome_owl/static/src/todo_list/todo_item/todo_item.xml @@ -3,7 +3,7 @@
-

.

+

.

diff --git a/awesome_owl/static/src/todo_list/todo_list.js b/awesome_owl/static/src/todo_list/todo_list.js index 90e907d0684..86f75c012d6 100644 --- a/awesome_owl/static/src/todo_list/todo_list.js +++ b/awesome_owl/static/src/todo_list/todo_list.js @@ -12,6 +12,7 @@ export class TodoList extends Component { todos: [], }); this.addTodo = this.addTodo.bind(this); + this.toggleTodo = this.toggleTodo.bind(this); useAutofocus("input"); } @@ -29,4 +30,12 @@ export class TodoList extends Component { ev.target.value = ""; } } + + toggleTodo(todoId) { + console.log("Toggling todo with ID:", todoId); + const todo = this.state.todos.find((todo) => todo.id === todoId); + if (todo) { + todo.isCompleted = !todo.isCompleted; + } + } } diff --git a/awesome_owl/static/src/todo_list/todo_list.xml b/awesome_owl/static/src/todo_list/todo_list.xml index b2493340ac0..b8e1062ad92 100644 --- a/awesome_owl/static/src/todo_list/todo_list.xml +++ b/awesome_owl/static/src/todo_list/todo_list.xml @@ -5,7 +5,7 @@
- +
From 32e8847988f4cf95354e3b519db3e4e2ca4ae63e Mon Sep 17 00:00:00 2001 From: Hashem Khaled Date: Tue, 28 Oct 2025 13:44:30 +0100 Subject: [PATCH 09/24] [IMP] awesome_owl: delete todos --- awesome_owl/static/src/todo_list/todo_item/todo_item.js | 5 +++++ awesome_owl/static/src/todo_list/todo_item/todo_item.xml | 6 +++++- awesome_owl/static/src/todo_list/todo_list.js | 9 ++++++++- awesome_owl/static/src/todo_list/todo_list.xml | 2 +- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/awesome_owl/static/src/todo_list/todo_item/todo_item.js b/awesome_owl/static/src/todo_list/todo_item/todo_item.js index 1c856829696..38e8f3589d0 100644 --- a/awesome_owl/static/src/todo_list/todo_item/todo_item.js +++ b/awesome_owl/static/src/todo_list/todo_item/todo_item.js @@ -13,9 +13,14 @@ export class TodoItem extends Component { }, }, toggleState: Function, + removeTodo: Function, }; onChange() { this.props.toggleState(this.props.todo.id); } + + onDelete() { + this.props.removeTodo(this.props.todo.id); + } } diff --git a/awesome_owl/static/src/todo_list/todo_item/todo_item.xml b/awesome_owl/static/src/todo_list/todo_item/todo_item.xml index 4ea37ac5e1c..55edbde6ee0 100644 --- a/awesome_owl/static/src/todo_list/todo_item/todo_item.xml +++ b/awesome_owl/static/src/todo_list/todo_item/todo_item.xml @@ -3,7 +3,11 @@
-

.

+

+ . + + +

diff --git a/awesome_owl/static/src/todo_list/todo_list.js b/awesome_owl/static/src/todo_list/todo_list.js index 86f75c012d6..b34fc3a93d9 100644 --- a/awesome_owl/static/src/todo_list/todo_list.js +++ b/awesome_owl/static/src/todo_list/todo_list.js @@ -13,6 +13,7 @@ export class TodoList extends Component { }); this.addTodo = this.addTodo.bind(this); this.toggleTodo = this.toggleTodo.bind(this); + this.removeTodo = this.removeTodo.bind(this); useAutofocus("input"); } @@ -32,10 +33,16 @@ export class TodoList extends Component { } toggleTodo(todoId) { - console.log("Toggling todo with ID:", todoId); const todo = this.state.todos.find((todo) => todo.id === todoId); if (todo) { todo.isCompleted = !todo.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_list/todo_list.xml b/awesome_owl/static/src/todo_list/todo_list.xml index b8e1062ad92..5be3fea5d45 100644 --- a/awesome_owl/static/src/todo_list/todo_list.xml +++ b/awesome_owl/static/src/todo_list/todo_list.xml @@ -5,7 +5,7 @@
- +
From 07ae39164643f625e60642e37abde954ab0bfd34 Mon Sep 17 00:00:00 2001 From: Hashem Khaled Date: Tue, 28 Oct 2025 14:11:36 +0100 Subject: [PATCH 10/24] [IMP] awesome_owl: refactor Card component to use slots --- awesome_owl/static/src/card/card.js | 9 +++++++-- awesome_owl/static/src/card/card.xml | 2 +- awesome_owl/static/src/counter/counter.xml | 2 +- awesome_owl/static/src/playground.js | 8 ++++---- awesome_owl/static/src/playground.xml | 19 +++++++++++-------- 5 files changed, 24 insertions(+), 16 deletions(-) diff --git a/awesome_owl/static/src/card/card.js b/awesome_owl/static/src/card/card.js index 45e2a650e6b..1fa5ff02910 100644 --- a/awesome_owl/static/src/card/card.js +++ b/awesome_owl/static/src/card/card.js @@ -3,7 +3,12 @@ import { Component } from "@odoo/owl"; export class Card extends Component { static template = "awesome_owl.card"; static props = { - title: {type: String}, - content: {type: String}, + title: { type: String }, + slots: { + type: Object, + shape: { + default: true, + }, + }, }; } diff --git a/awesome_owl/static/src/card/card.xml b/awesome_owl/static/src/card/card.xml index f6f9e7e54b5..4962241d4fa 100644 --- a/awesome_owl/static/src/card/card.xml +++ b/awesome_owl/static/src/card/card.xml @@ -5,7 +5,7 @@

- +

diff --git a/awesome_owl/static/src/counter/counter.xml b/awesome_owl/static/src/counter/counter.xml index 4ff9c09597c..82a197bc766 100644 --- a/awesome_owl/static/src/counter/counter.xml +++ b/awesome_owl/static/src/counter/counter.xml @@ -2,7 +2,7 @@ -
+

Counter:

diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js index 8a540594619..597219d6ad6 100644 --- a/awesome_owl/static/src/playground.js +++ b/awesome_owl/static/src/playground.js @@ -11,10 +11,10 @@ export class Playground extends Component { static components = { Counter, Card, TodoList }; setup() { - this.card1_content = "
some content
"; - this.card2_content = markup( - "
some content
" - ); + // this.card1_content = "
some content
"; + // this.card2_content = markup( + // "
some content
" + // ); this.state = useState({ sum: 0, }); diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml index d0223d9fb39..b10bb86f21c 100644 --- a/awesome_owl/static/src/playground.xml +++ b/awesome_owl/static/src/playground.xml @@ -2,15 +2,18 @@ -
- hello world - - - - -

The sum is:

- +
+ + + + + + +
+ The sum is: +
+ From 8ac0d11defee4306b980694cc58a95a27ab68fc1 Mon Sep 17 00:00:00 2001 From: Hashem Khaled Date: Tue, 28 Oct 2025 14:25:29 +0100 Subject: [PATCH 11/24] [IMP] awesome_owl: toggle card content --- awesome_owl/static/src/card/card.js | 12 +++++++++++- awesome_owl/static/src/card/card.xml | 8 ++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/awesome_owl/static/src/card/card.js b/awesome_owl/static/src/card/card.js index 1fa5ff02910..6df2061ceca 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 { Component, useState } from "@odoo/owl"; export class Card extends Component { static template = "awesome_owl.card"; @@ -11,4 +11,14 @@ export class Card extends Component { }, }, }; + + setup() { + this.state = useState({ + isOpen: true, + }); + } + + onToggle() { + this.state.isOpen = !this.state.isOpen; + } } diff --git a/awesome_owl/static/src/card/card.xml b/awesome_owl/static/src/card/card.xml index 4962241d4fa..9bea5a05ad5 100644 --- a/awesome_owl/static/src/card/card.xml +++ b/awesome_owl/static/src/card/card.xml @@ -3,8 +3,12 @@
-
-

+

+ +
+

From e286ff6c56e55e6fb37cc7b7cc3fd751b03b56cf Mon Sep 17 00:00:00 2001 From: Hashem Khaled Date: Tue, 28 Oct 2025 15:53:16 +0100 Subject: [PATCH 12/24] [IMP] awesome_dashboard: add layout with some buttons for quick navigation --- awesome_dashboard/static/src/dashboard.js | 28 ++++++++++++++++++++- awesome_dashboard/static/src/dashboard.scss | 14 +++++++++++ awesome_dashboard/static/src/dashboard.xml | 11 +++++++- 3 files changed, 51 insertions(+), 2 deletions(-) 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 637fa4bb972..57843943c49 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -2,9 +2,35 @@ import { Component } from "@odoo/owl"; import { registry } from "@web/core/registry"; +import { Layout } from "@web/search/layout"; +import { useService } from "@web/core/utils/hooks"; class AwesomeDashboard extends Component { + static components = { Layout }; static template = "awesome_dashboard.AwesomeDashboard"; + + setup() { + this.display = { controlPanel: {} }; + this.action = useService("action"); + } + + openCustomers() { + this.action.doAction("base.action_partner_form"); + } + + openLeads() { + this.action.doAction({ + type: "ir.actions.act_window", + res_model: "crm.lead", + name: "Leads", + views: [ + [false, "list"], + [false, "form"], + ], + }); + } } -registry.category("actions").add("awesome_dashboard.dashboard", AwesomeDashboard); +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..8ab27423893 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard.scss @@ -0,0 +1,14 @@ +.o_dashboard { + background-color: gray; +} + +.btn-primary { + background-color: purple; + border-color: purple; +} + +.divider{ + width:5px; + height:auto; + display:inline-block; +} diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index 1a2ac9a2fed..4ca2c0d9b2f 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -2,7 +2,16 @@ - hello dashboard + + +
+ +
hello dashboard
+ From 94c0020e8a7863737880264a055238da67975fa6 Mon Sep 17 00:00:00 2001 From: Hashem Khaled Date: Tue, 28 Oct 2025 16:27:22 +0100 Subject: [PATCH 13/24] [IMP] awesome_dashboard: add a dashboard item --- awesome_dashboard/static/src/dashboard.js | 3 ++- awesome_dashboard/static/src/dashboard.xml | 5 ++++- .../src/dashboard_item/dashboard_item.js | 20 +++++++++++++++++++ .../src/dashboard_item/dashboard_item.xml | 11 ++++++++++ awesome_owl/static/src/playground.js | 4 ---- 5 files changed, 37 insertions(+), 6 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.js b/awesome_dashboard/static/src/dashboard.js index 57843943c49..5d117341608 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -4,9 +4,10 @@ import { Component } from "@odoo/owl"; import { registry } from "@web/core/registry"; import { Layout } from "@web/search/layout"; import { useService } from "@web/core/utils/hooks"; +import { DashboardItem } from "./dashboard_item/dashboard_item"; class AwesomeDashboard extends Component { - static components = { Layout }; + static components = { Layout, DashboardItem }; static template = "awesome_dashboard.AwesomeDashboard"; setup() { diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index 4ca2c0d9b2f..4e8fae644b0 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -10,7 +10,10 @@ -
hello dashboard
+
+ some content + I love milk +
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..30ca91ea7ec --- /dev/null +++ b/awesome_dashboard/static/src/dashboard_item/dashboard_item.js @@ -0,0 +1,20 @@ +import { Component } from "@odoo/owl"; + +export class DashboardItem extends Component { + static template = "awesome_dashboard.DashboardItem"; + static props = { + size: { + type: Number, + default: 1, + optional: true, + }, + slots: { + type: Object, + optional: true, + }, + }; + + setup() { + console.log(this.props.size); + } +} 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..21998becea2 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard_item/dashboard_item.xml @@ -0,0 +1,11 @@ + + + + +
+
+ +
+
+
+
diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js index 597219d6ad6..0b99b82e284 100644 --- a/awesome_owl/static/src/playground.js +++ b/awesome_owl/static/src/playground.js @@ -11,10 +11,6 @@ export class Playground extends Component { static components = { Counter, Card, TodoList }; setup() { - // this.card1_content = "
some content
"; - // this.card2_content = markup( - // "
some content
" - // ); this.state = useState({ sum: 0, }); From 22dbdb4e108b1b70e728458b1cad81a6153aef27 Mon Sep 17 00:00:00 2001 From: Hashem Khaled Date: Wed, 29 Oct 2025 10:16:46 +0100 Subject: [PATCH 14/24] [IMP] awesome_dashboard: call the server for adding some statistics --- awesome_dashboard/static/src/dashboard.js | 7 ++++- awesome_dashboard/static/src/dashboard.xml | 34 ++++++++++++++++++++-- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js index 5d117341608..e1e17de3e5d 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -1,10 +1,11 @@ /** @odoo-module **/ -import { Component } from "@odoo/owl"; +import { Component, onWillStart } from "@odoo/owl"; import { registry } from "@web/core/registry"; import { Layout } from "@web/search/layout"; import { useService } from "@web/core/utils/hooks"; import { DashboardItem } from "./dashboard_item/dashboard_item"; +import { rpc } from "@web/core/network/rpc"; class AwesomeDashboard extends Component { static components = { Layout, DashboardItem }; @@ -13,6 +14,10 @@ class AwesomeDashboard extends Component { setup() { this.display = { controlPanel: {} }; this.action = useService("action"); + + onWillStart(async () => { + this.stats = await rpc("/awesome_dashboard/statistics"); + }); } openCustomers() { diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index 4e8fae644b0..117456a1f43 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -10,9 +10,37 @@ -
- some content - I love milk +
+ + Average amount of t-shirt by order this month +
+ +
+
+ + Average time for an order to go from 'new' to 'sent' or 'cancelled' +
+ +
+
+ + Number of new orders this month +
+ +
+
+ + Number of cancelled orders this month +
+ +
+
+ + Total amount of new orders this month +
+ +
+
From 4282ec3091c29dcbda2bedec3cf84f743cb0b859 Mon Sep 17 00:00:00 2001 From: Hashem Khaled Date: Wed, 29 Oct 2025 11:25:04 +0100 Subject: [PATCH 15/24] [IMP] awesome_dashboard: implement statistics service --- awesome_dashboard/static/src/dashboard.js | 4 ++-- awesome_dashboard/static/src/dashboard.xml | 4 ++-- .../static/src/dashboard_item/dashboard_item.xml | 2 +- .../static/src/statistics_service.js | 16 ++++++++++++++++ 4 files changed, 21 insertions(+), 5 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 e1e17de3e5d..9fd3ac79fc8 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -5,7 +5,6 @@ import { registry } from "@web/core/registry"; import { Layout } from "@web/search/layout"; import { useService } from "@web/core/utils/hooks"; import { DashboardItem } from "./dashboard_item/dashboard_item"; -import { rpc } from "@web/core/network/rpc"; class AwesomeDashboard extends Component { static components = { Layout, DashboardItem }; @@ -14,9 +13,10 @@ class AwesomeDashboard extends Component { setup() { this.display = { controlPanel: {} }; this.action = useService("action"); + this.statsService = useService("awesome_dashboard.statistics"); onWillStart(async () => { - this.stats = await rpc("/awesome_dashboard/statistics"); + this.stats = await this.statsService.loadStatistics(); }); } diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index 117456a1f43..6f8b72089c0 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -1,4 +1,4 @@ - + @@ -45,4 +45,4 @@ - + \ No newline at end of file diff --git a/awesome_dashboard/static/src/dashboard_item/dashboard_item.xml b/awesome_dashboard/static/src/dashboard_item/dashboard_item.xml index 21998becea2..a25fa8dd491 100644 --- a/awesome_dashboard/static/src/dashboard_item/dashboard_item.xml +++ b/awesome_dashboard/static/src/dashboard_item/dashboard_item.xml @@ -8,4 +8,4 @@
-
+ \ No newline at end of file diff --git a/awesome_dashboard/static/src/statistics_service.js b/awesome_dashboard/static/src/statistics_service.js new file mode 100644 index 00000000000..1a30f316212 --- /dev/null +++ b/awesome_dashboard/static/src/statistics_service.js @@ -0,0 +1,16 @@ +import { registry } from "@web/core/registry"; +import { memoize } from "@web/core/utils/functions"; +import { rpc } from "@web/core/network/rpc"; + +const statisticsService = { + async: ["loadStatistics"], + start() { + return { + loadStatistics: memoize(() => rpc("/awesome_dashboard/statistics")), + }; + }, +}; + +registry + .category("services") + .add("awesome_dashboard.statistics", statisticsService); From 2dfd044cf2834e6bf45afa239742e8dee6e98315 Mon Sep 17 00:00:00 2001 From: Hashem Khaled Date: Wed, 29 Oct 2025 13:38:18 +0100 Subject: [PATCH 16/24] [IMP] awesome_dashboard: display a pie chart --- awesome_dashboard/static/src/dashboard.js | 3 +- awesome_dashboard/static/src/dashboard.xml | 4 ++ .../src/dashboard_item/dashboard_item.js | 4 -- .../static/src/pie_chart/pie_chart.js | 52 +++++++++++++++++++ .../static/src/pie_chart/pie_chart.xml | 6 +++ 5 files changed, 64 insertions(+), 5 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 9fd3ac79fc8..6e8c3ef03cf 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard.js @@ -5,9 +5,10 @@ import { registry } from "@web/core/registry"; import { Layout } from "@web/search/layout"; import { useService } from "@web/core/utils/hooks"; import { DashboardItem } from "./dashboard_item/dashboard_item"; +import { PieChart } from "./pie_chart/pie_chart"; class AwesomeDashboard extends Component { - static components = { Layout, DashboardItem }; + static components = { Layout, DashboardItem, PieChart }; static template = "awesome_dashboard.AwesomeDashboard"; setup() { diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml index 6f8b72089c0..9a6bc8fa134 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard.xml @@ -41,6 +41,10 @@
+ + Shirt orders by size + +
diff --git a/awesome_dashboard/static/src/dashboard_item/dashboard_item.js b/awesome_dashboard/static/src/dashboard_item/dashboard_item.js index 30ca91ea7ec..ca876872353 100644 --- a/awesome_dashboard/static/src/dashboard_item/dashboard_item.js +++ b/awesome_dashboard/static/src/dashboard_item/dashboard_item.js @@ -13,8 +13,4 @@ export class DashboardItem extends Component { optional: true, }, }; - - setup() { - console.log(this.props.size); - } } 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..9c8b9a7cb90 --- /dev/null +++ b/awesome_dashboard/static/src/pie_chart/pie_chart.js @@ -0,0 +1,52 @@ +import { + Component, + useEffect, + useRef, + onWillUnmount, + onWillStart, +} from "@odoo/owl"; +import { loadJS } from "@web/core/assets"; +import { getColor } from "@web/core/colors/colors"; + +export class PieChart extends Component { + static template = "awesome_dashboard.PieChart"; + static props = { + label: { type: String, optional: true }, + data: { type: Object }, + }; + + setup() { + this.canvasRef = useRef("canvas"); + this.chart = null; + + onWillStart(() => loadJS(["/web/static/lib/Chart/Chart.js"])); + useEffect(() => this.renderChart()); + onWillUnmount(() => { + if (this.chart) { + this.chart.destroy(); + } + }); + } + + renderChart() { + const labels = Object.keys(this.props.data); + const values = Object.values(this.props.data); + const color = labels.map((_, idx) => getColor(idx * 2)); + if (this.chart) { + this.chart.destroy(); + } + this.chart = new Chart(this.canvasRef.el, { + type: "pie", + data: { + labels: labels, + datasets: [ + { + label: this.props.label || "", + data: values, + backgroundColor: color, + }, + ], + }, + }); + } +} 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..872a02c0c80 --- /dev/null +++ b/awesome_dashboard/static/src/pie_chart/pie_chart.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file From 1a863c671035698a7b54ce065e9a9d7d78341b32 Mon Sep 17 00:00:00 2001 From: Hashem Khaled Date: Wed, 29 Oct 2025 14:56:01 +0100 Subject: [PATCH 17/24] [IMP] awesome_dashboard: lazy loading the dashboard --- awesome_dashboard/__manifest__.py | 4 +++ .../static/src/{ => dashboard}/dashboard.js | 12 +++------ .../static/src/{ => dashboard}/dashboard.scss | 0 .../static/src/{ => dashboard}/dashboard.xml | 2 +- .../dashboard_item/dashboard_item.js | 0 .../dashboard_item/dashboard_item.xml | 0 .../{ => dashboard}/pie_chart/pie_chart.js | 0 .../{ => dashboard}/pie_chart/pie_chart.xml | 0 .../src/dashboard/statistics_service.js | 25 +++++++++++++++++++ .../static/src/dashboard_action.js | 12 +++++++++ .../static/src/statistics_service.js | 16 ------------ 11 files changed, 45 insertions(+), 26 deletions(-) rename awesome_dashboard/static/src/{ => dashboard}/dashboard.js (73%) rename awesome_dashboard/static/src/{ => dashboard}/dashboard.scss (100%) rename awesome_dashboard/static/src/{ => dashboard}/dashboard.xml (97%) rename awesome_dashboard/static/src/{ => dashboard}/dashboard_item/dashboard_item.js (100%) rename awesome_dashboard/static/src/{ => dashboard}/dashboard_item/dashboard_item.xml (100%) rename awesome_dashboard/static/src/{ => dashboard}/pie_chart/pie_chart.js (100%) rename awesome_dashboard/static/src/{ => dashboard}/pie_chart/pie_chart.xml (100%) create mode 100644 awesome_dashboard/static/src/dashboard/statistics_service.js create mode 100644 awesome_dashboard/static/src/dashboard_action.js delete mode 100644 awesome_dashboard/static/src/statistics_service.js diff --git a/awesome_dashboard/__manifest__.py b/awesome_dashboard/__manifest__.py index 31406e8addb..f57ecd32a40 100644 --- a/awesome_dashboard/__manifest__.py +++ b/awesome_dashboard/__manifest__.py @@ -24,6 +24,10 @@ 'assets': { 'web.assets_backend': [ 'awesome_dashboard/static/src/**/*', + ('remove', 'awesome_dashboard/static/src/dashboard/**/*'), + ], + 'awesome_dashboard.dashboard': [ + 'awesome_dashboard/static/src/dashboard/**/*', ], }, 'license': 'AGPL-3' diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard/dashboard.js similarity index 73% rename from awesome_dashboard/static/src/dashboard.js rename to awesome_dashboard/static/src/dashboard/dashboard.js index 6e8c3ef03cf..e0e6db9a2d3 100644 --- a/awesome_dashboard/static/src/dashboard.js +++ b/awesome_dashboard/static/src/dashboard/dashboard.js @@ -1,6 +1,6 @@ /** @odoo-module **/ -import { Component, onWillStart } from "@odoo/owl"; +import { Component, useState } from "@odoo/owl"; import { registry } from "@web/core/registry"; import { Layout } from "@web/search/layout"; import { useService } from "@web/core/utils/hooks"; @@ -14,11 +14,7 @@ class AwesomeDashboard extends Component { setup() { this.display = { controlPanel: {} }; this.action = useService("action"); - this.statsService = useService("awesome_dashboard.statistics"); - - onWillStart(async () => { - this.stats = await this.statsService.loadStatistics(); - }); + this.stats = useState(useService("awesome_dashboard.statistics")); } openCustomers() { @@ -38,6 +34,4 @@ class AwesomeDashboard extends Component { } } -registry - .category("actions") - .add("awesome_dashboard.dashboard", AwesomeDashboard); +registry.category("lazy_components").add("AwesomeDashboard", AwesomeDashboard); diff --git a/awesome_dashboard/static/src/dashboard.scss b/awesome_dashboard/static/src/dashboard/dashboard.scss similarity index 100% rename from awesome_dashboard/static/src/dashboard.scss rename to awesome_dashboard/static/src/dashboard/dashboard.scss diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard/dashboard.xml similarity index 97% rename from awesome_dashboard/static/src/dashboard.xml rename to awesome_dashboard/static/src/dashboard/dashboard.xml index 9a6bc8fa134..3d72bcbbb66 100644 --- a/awesome_dashboard/static/src/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard/dashboard.xml @@ -10,7 +10,7 @@ -
+
Average amount of t-shirt by order this month
diff --git a/awesome_dashboard/static/src/dashboard_item/dashboard_item.js b/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.js similarity index 100% rename from awesome_dashboard/static/src/dashboard_item/dashboard_item.js rename to awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.js diff --git a/awesome_dashboard/static/src/dashboard_item/dashboard_item.xml b/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.xml similarity index 100% rename from awesome_dashboard/static/src/dashboard_item/dashboard_item.xml rename to awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.xml diff --git a/awesome_dashboard/static/src/pie_chart/pie_chart.js b/awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.js similarity index 100% rename from awesome_dashboard/static/src/pie_chart/pie_chart.js rename to awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.js diff --git a/awesome_dashboard/static/src/pie_chart/pie_chart.xml b/awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.xml similarity index 100% rename from awesome_dashboard/static/src/pie_chart/pie_chart.xml rename to awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.xml diff --git a/awesome_dashboard/static/src/dashboard/statistics_service.js b/awesome_dashboard/static/src/dashboard/statistics_service.js new file mode 100644 index 00000000000..78efc202e43 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard/statistics_service.js @@ -0,0 +1,25 @@ +import { registry } from "@web/core/registry"; +import { rpc } from "@web/core/network/rpc"; +import { reactive } from "@odoo/owl"; + +const statisticsService = { + async: ["loadStatistics"], + start() { + const statistics = reactive({ isLoaded: false }); + + async function loadStatistics() { + const result = await rpc("/awesome_dashboard/statistics"); + statistics.isLoaded = true; + Object.assign(statistics, result); + } + + setInterval(loadStatistics, 10 * 60 * 1000); + loadStatistics(); + + return statistics; + }, +}; + +registry + .category("services") + .add("awesome_dashboard.statistics", statisticsService); diff --git a/awesome_dashboard/static/src/dashboard_action.js b/awesome_dashboard/static/src/dashboard_action.js new file mode 100644 index 00000000000..989c9fb9130 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard_action.js @@ -0,0 +1,12 @@ +import { Component, xml } from "@odoo/owl"; +import { registry } from "@web/core/registry"; +import { LazyComponent } from "@web/core/assets"; + +export class DashboardAction extends Component { + static components = { LazyComponent }; + static template = xml``; +} + +registry + .category("actions") + .add("awesome_dashboard.dashboard", DashboardAction); diff --git a/awesome_dashboard/static/src/statistics_service.js b/awesome_dashboard/static/src/statistics_service.js deleted file mode 100644 index 1a30f316212..00000000000 --- a/awesome_dashboard/static/src/statistics_service.js +++ /dev/null @@ -1,16 +0,0 @@ -import { registry } from "@web/core/registry"; -import { memoize } from "@web/core/utils/functions"; -import { rpc } from "@web/core/network/rpc"; - -const statisticsService = { - async: ["loadStatistics"], - start() { - return { - loadStatistics: memoize(() => rpc("/awesome_dashboard/statistics")), - }; - }, -}; - -registry - .category("services") - .add("awesome_dashboard.statistics", statisticsService); From 639c920044038fa8dd5d69a20e31d5ca406b541c Mon Sep 17 00:00:00 2001 From: Hashem Khaled Date: Wed, 29 Oct 2025 15:44:32 +0100 Subject: [PATCH 18/24] [IMP] awesome_dashboard: make the dashboard generic --- .../static/src/dashboard/dashboard.js | 2 + .../static/src/dashboard/dashboard.xml | 40 ++---------- .../static/src/dashboard/dashboard_items.js | 61 +++++++++++++++++++ .../src/dashboard/number_card/number_card.js | 10 +++ .../src/dashboard/number_card/number_card.xml | 10 +++ .../pie_chart_card/pie_chart_card.js | 12 ++++ .../pie_chart_card/pie_chart_card.xml | 8 +++ 7 files changed, 109 insertions(+), 34 deletions(-) create mode 100644 awesome_dashboard/static/src/dashboard/dashboard_items.js create mode 100644 awesome_dashboard/static/src/dashboard/number_card/number_card.js create mode 100644 awesome_dashboard/static/src/dashboard/number_card/number_card.xml create mode 100644 awesome_dashboard/static/src/dashboard/pie_chart_card/pie_chart_card.js create mode 100644 awesome_dashboard/static/src/dashboard/pie_chart_card/pie_chart_card.xml diff --git a/awesome_dashboard/static/src/dashboard/dashboard.js b/awesome_dashboard/static/src/dashboard/dashboard.js index e0e6db9a2d3..a9ddf5753b0 100644 --- a/awesome_dashboard/static/src/dashboard/dashboard.js +++ b/awesome_dashboard/static/src/dashboard/dashboard.js @@ -6,6 +6,7 @@ import { Layout } from "@web/search/layout"; import { useService } from "@web/core/utils/hooks"; import { DashboardItem } from "./dashboard_item/dashboard_item"; import { PieChart } from "./pie_chart/pie_chart"; +import { dashboardItems } from "./dashboard_items"; class AwesomeDashboard extends Component { static components = { Layout, DashboardItem, PieChart }; @@ -15,6 +16,7 @@ class AwesomeDashboard extends Component { this.display = { controlPanel: {} }; this.action = useService("action"); this.stats = useState(useService("awesome_dashboard.statistics")); + this.items = dashboardItems; } openCustomers() { diff --git a/awesome_dashboard/static/src/dashboard/dashboard.xml b/awesome_dashboard/static/src/dashboard/dashboard.xml index 3d72bcbbb66..29a7981a47e 100644 --- a/awesome_dashboard/static/src/dashboard/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard/dashboard.xml @@ -11,40 +11,12 @@ Leads
- - Average amount of t-shirt by order this month -
- -
-
- - Average time for an order to go from 'new' to 'sent' or 'cancelled' -
- -
-
- - Number of new orders this month -
- -
-
- - Number of cancelled orders this month -
- -
-
- - Total amount of new orders this month -
- -
-
- - Shirt orders by size - - + + + + + +
diff --git a/awesome_dashboard/static/src/dashboard/dashboard_items.js b/awesome_dashboard/static/src/dashboard/dashboard_items.js new file mode 100644 index 00000000000..46abd55f5e4 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard/dashboard_items.js @@ -0,0 +1,61 @@ +import { NumberCard } from "./number_card/number_card"; +import { PieChartCard } from "./pie_chart_card/pie_chart_card"; + +export const dashboardItems = [ + { + 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: "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: "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: "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: "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: "orders_by_size", + description: "Shirt orders by size", + component: PieChartCard, + size: 1.5, + props: (data) => ({ + title: "Shirt orders by size", + values: data.orders_by_size, + }), + }, +]; diff --git a/awesome_dashboard/static/src/dashboard/number_card/number_card.js b/awesome_dashboard/static/src/dashboard/number_card/number_card.js new file mode 100644 index 00000000000..3028b0c429e --- /dev/null +++ b/awesome_dashboard/static/src/dashboard/number_card/number_card.js @@ -0,0 +1,10 @@ +import { Component } from "@odoo/owl"; + +export class NumberCard extends Component { + static template = "awesome_dashboard.NumberCard"; + + static props = { + title: String, + value: Number, + }; +} diff --git a/awesome_dashboard/static/src/dashboard/number_card/number_card.xml b/awesome_dashboard/static/src/dashboard/number_card/number_card.xml new file mode 100644 index 00000000000..790de2025d5 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard/number_card/number_card.xml @@ -0,0 +1,10 @@ + + + + + +
+ +
+
+
\ No newline at end of file diff --git a/awesome_dashboard/static/src/dashboard/pie_chart_card/pie_chart_card.js b/awesome_dashboard/static/src/dashboard/pie_chart_card/pie_chart_card.js new file mode 100644 index 00000000000..86bc0d81550 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard/pie_chart_card/pie_chart_card.js @@ -0,0 +1,12 @@ +import { Component } from "@odoo/owl"; +import { PieChart } from "../pie_chart/pie_chart"; + +export class PieChartCard extends Component { + static template = "awesome_dashboard.PieChartCard"; + static components = { PieChart }; + + static props = { + title: String, + values: Object, + }; +} diff --git a/awesome_dashboard/static/src/dashboard/pie_chart_card/pie_chart_card.xml b/awesome_dashboard/static/src/dashboard/pie_chart_card/pie_chart_card.xml new file mode 100644 index 00000000000..6f19277d8b9 --- /dev/null +++ b/awesome_dashboard/static/src/dashboard/pie_chart_card/pie_chart_card.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file From 939fb620ec04be63e666b89631fb7cc6c2ed35c2 Mon Sep 17 00:00:00 2001 From: Hashem Khaled Date: Wed, 29 Oct 2025 15:51:19 +0100 Subject: [PATCH 19/24] [IMP] awesome_dashboard: make the dashboard extensible --- awesome_dashboard/static/src/dashboard/dashboard.js | 3 +-- awesome_dashboard/static/src/dashboard/dashboard_items.js | 7 ++++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/awesome_dashboard/static/src/dashboard/dashboard.js b/awesome_dashboard/static/src/dashboard/dashboard.js index a9ddf5753b0..6e1234ac802 100644 --- a/awesome_dashboard/static/src/dashboard/dashboard.js +++ b/awesome_dashboard/static/src/dashboard/dashboard.js @@ -6,7 +6,6 @@ import { Layout } from "@web/search/layout"; import { useService } from "@web/core/utils/hooks"; import { DashboardItem } from "./dashboard_item/dashboard_item"; import { PieChart } from "./pie_chart/pie_chart"; -import { dashboardItems } from "./dashboard_items"; class AwesomeDashboard extends Component { static components = { Layout, DashboardItem, PieChart }; @@ -16,7 +15,7 @@ class AwesomeDashboard extends Component { this.display = { controlPanel: {} }; this.action = useService("action"); this.stats = useState(useService("awesome_dashboard.statistics")); - this.items = dashboardItems; + this.items = registry.category("awesome_dashboard").getAll(); } openCustomers() { diff --git a/awesome_dashboard/static/src/dashboard/dashboard_items.js b/awesome_dashboard/static/src/dashboard/dashboard_items.js index 46abd55f5e4..ac6b48c33b3 100644 --- a/awesome_dashboard/static/src/dashboard/dashboard_items.js +++ b/awesome_dashboard/static/src/dashboard/dashboard_items.js @@ -1,7 +1,8 @@ import { NumberCard } from "./number_card/number_card"; import { PieChartCard } from "./pie_chart_card/pie_chart_card"; +import { registry } from "@web/core/registry"; -export const dashboardItems = [ +const dashboardItems = [ { id: "average_quantity", description: "Average amount of t-shirt by order this month", @@ -59,3 +60,7 @@ export const dashboardItems = [ }), }, ]; + +dashboardItems.forEach((item) => { + registry.category("awesome_dashboard").add(item.id, item); +}); From b2991032befbd6eceb299cd31bcf82aa29d9224a Mon Sep 17 00:00:00 2001 From: Hashem Khaled Date: Thu, 30 Oct 2025 09:56:49 +0100 Subject: [PATCH 20/24] [IMP] awesome_dashboard: add settings dialog for managing dashboard item visibility --- .../static/src/dashboard/dashboard.js | 68 +++++++++++++++++++ .../static/src/dashboard/dashboard.xml | 23 ++++++- 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/awesome_dashboard/static/src/dashboard/dashboard.js b/awesome_dashboard/static/src/dashboard/dashboard.js index 6e1234ac802..2679a8840db 100644 --- a/awesome_dashboard/static/src/dashboard/dashboard.js +++ b/awesome_dashboard/static/src/dashboard/dashboard.js @@ -6,6 +6,9 @@ import { Layout } from "@web/search/layout"; import { useService } from "@web/core/utils/hooks"; import { DashboardItem } from "./dashboard_item/dashboard_item"; import { PieChart } from "./pie_chart/pie_chart"; +import { Dialog } from "@web/core/dialog/dialog"; +import { CheckBox } from "@web/core/checkbox/checkbox"; +import { browser } from "@web/core/browser/browser"; class AwesomeDashboard extends Component { static components = { Layout, DashboardItem, PieChart }; @@ -16,6 +19,14 @@ class AwesomeDashboard extends Component { this.action = useService("action"); this.stats = useState(useService("awesome_dashboard.statistics")); this.items = registry.category("awesome_dashboard").getAll(); + this.dialog = useService("dialog"); + this.state = useState({ + disabledItems: + browser.localStorage + .getItem("disabledDashboardItems") + ?.split(",") || [], + }); + this.openSettings = this.openSettings.bind(this); } openCustomers() { @@ -33,6 +44,63 @@ class AwesomeDashboard extends Component { ], }); } + + openSettings() { + this.dialog.add(SettingsDialog, { + items: this.items, + disabledItems: this.state.disabledItems, + onUpdateSettings: this.updateSettings.bind(this), + close: this.closeSettings.bind(this), + }); + } + + updateSettings(newDisabledItems) { + this.state.disabledItems = newDisabledItems; + } + + closeSettings() { + this.dialog.close(); + } +} + +class SettingsDialog extends Component { + static template = "awesome_dashboard.SettingsDialog"; + static components = { Dialog, CheckBox }; + static props = { + items: Array, + disabledItems: Array, + onUpdateSettings: Function, + close: Function, + }; + + setup() { + this.items = useState( + this.props.items.map((item) => { + return { + ...item, + enabled: !this.props.disabledItems.includes(item.id), + }; + }) + ); + } + + closeDialog() { + this.props.close(); + } + + onChange(chekced, changedItem) { + changedItem.enabled = chekced; + const newDisabledItems = Object.values(this.items) + .filter((item) => !item.enabled) + .map((item) => item.id); + + browser.localStorage.setItem( + "disabledDashboardItems", + newDisabledItems + ); + + this.props.onUpdateSettings(newDisabledItems); + } } registry.category("lazy_components").add("AwesomeDashboard", AwesomeDashboard); diff --git a/awesome_dashboard/static/src/dashboard/dashboard.xml b/awesome_dashboard/static/src/dashboard/dashboard.xml index 29a7981a47e..c8c55752fb0 100644 --- a/awesome_dashboard/static/src/dashboard/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard/dashboard.xml @@ -10,9 +10,14 @@ + + +
- + @@ -21,4 +26,20 @@ + + + Which cards do you wish to see ? + + + + + + + + + + + \ No newline at end of file From d4fa2a0cf575f2d4a395638dcef5d155e8efbd99 Mon Sep 17 00:00:00 2001 From: Hashem Khaled Date: Thu, 30 Oct 2025 13:31:56 +0100 Subject: [PATCH 21/24] [FIX] awesome_dashboard: add missing newline at end of XML files --- awesome_dashboard/static/src/dashboard/dashboard.xml | 2 +- .../static/src/dashboard/dashboard_item/dashboard_item.xml | 2 +- .../static/src/dashboard/number_card/number_card.xml | 2 +- awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.xml | 2 +- .../static/src/dashboard/pie_chart_card/pie_chart_card.xml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/awesome_dashboard/static/src/dashboard/dashboard.xml b/awesome_dashboard/static/src/dashboard/dashboard.xml index c8c55752fb0..5e2896f67bb 100644 --- a/awesome_dashboard/static/src/dashboard/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard/dashboard.xml @@ -42,4 +42,4 @@ - \ No newline at end of file + diff --git a/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.xml b/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.xml index a25fa8dd491..21998becea2 100644 --- a/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.xml +++ b/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.xml @@ -8,4 +8,4 @@
- \ No newline at end of file + diff --git a/awesome_dashboard/static/src/dashboard/number_card/number_card.xml b/awesome_dashboard/static/src/dashboard/number_card/number_card.xml index 790de2025d5..7314095a8eb 100644 --- a/awesome_dashboard/static/src/dashboard/number_card/number_card.xml +++ b/awesome_dashboard/static/src/dashboard/number_card/number_card.xml @@ -7,4 +7,4 @@
- \ No newline at end of file + diff --git a/awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.xml b/awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.xml index 872a02c0c80..08b266452c9 100644 --- a/awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.xml +++ b/awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.xml @@ -3,4 +3,4 @@ - \ No newline at end of file + diff --git a/awesome_dashboard/static/src/dashboard/pie_chart_card/pie_chart_card.xml b/awesome_dashboard/static/src/dashboard/pie_chart_card/pie_chart_card.xml index 6f19277d8b9..d80daa2885a 100644 --- a/awesome_dashboard/static/src/dashboard/pie_chart_card/pie_chart_card.xml +++ b/awesome_dashboard/static/src/dashboard/pie_chart_card/pie_chart_card.xml @@ -5,4 +5,4 @@ - \ No newline at end of file + From d1884f2ae77058489a1e9d6d8c189c7aea7000fa Mon Sep 17 00:00:00 2001 From: Hashem Khaled Date: Thu, 30 Oct 2025 13:33:55 +0100 Subject: [PATCH 22/24] [FIX] awesome_dashboard: fix default size handling in DashboardItem component --- awesome_dashboard/static/src/dashboard/dashboard.xml | 2 +- .../static/src/dashboard/dashboard_item/dashboard_item.js | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/awesome_dashboard/static/src/dashboard/dashboard.xml b/awesome_dashboard/static/src/dashboard/dashboard.xml index 5e2896f67bb..8fa112b49f6 100644 --- a/awesome_dashboard/static/src/dashboard/dashboard.xml +++ b/awesome_dashboard/static/src/dashboard/dashboard.xml @@ -17,7 +17,7 @@
- + diff --git a/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.js b/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.js index ca876872353..34f7125f685 100644 --- a/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.js +++ b/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.js @@ -5,7 +5,6 @@ export class DashboardItem extends Component { static props = { size: { type: Number, - default: 1, optional: true, }, slots: { @@ -13,4 +12,11 @@ export class DashboardItem extends Component { optional: true, }, }; + static defaultProps = { + size: 1, + }; + + setup() { + console.log("size: ", this.props.size); + } } From 0f622fb73742ebd1e08971168a0061d7e653c355 Mon Sep 17 00:00:00 2001 From: Hashem Khaled Date: Thu, 30 Oct 2025 13:34:38 +0100 Subject: [PATCH 23/24] [FIX] awesome_owl: correct glob pattern for static assets inclusion --- awesome_owl/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awesome_owl/__manifest__.py b/awesome_owl/__manifest__.py index f3acf2d167c..77abad510ef 100644 --- a/awesome_owl/__manifest__.py +++ b/awesome_owl/__manifest__.py @@ -35,7 +35,7 @@ ('include', 'web._assets_bootstrap'), ('include', 'web._assets_core'), 'web/static/src/libs/fontawesome/css/font-awesome.css', - 'awesome_owl/static/src/**/**', + 'awesome_owl/static/src/**/*', ], }, 'license': 'AGPL-3' From 281a073a2f95bcb4261d9d66c7f4c207aab38ec6 Mon Sep 17 00:00:00 2001 From: Hashem Khaled Date: Thu, 30 Oct 2025 13:36:57 +0100 Subject: [PATCH 24/24] [FIX] awesome_dashboard: remove redundant chart destruction in PieChart component --- .../static/src/dashboard/dashboard_item/dashboard_item.js | 4 ---- awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.js | 3 --- 2 files changed, 7 deletions(-) diff --git a/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.js b/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.js index 34f7125f685..970dd3817de 100644 --- a/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.js +++ b/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.js @@ -15,8 +15,4 @@ export class DashboardItem extends Component { static defaultProps = { size: 1, }; - - setup() { - console.log("size: ", this.props.size); - } } diff --git a/awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.js b/awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.js index 9c8b9a7cb90..f51de6838e1 100644 --- a/awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.js +++ b/awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.js @@ -32,9 +32,6 @@ export class PieChart extends Component { const labels = Object.keys(this.props.data); const values = Object.values(this.props.data); const color = labels.map((_, idx) => getColor(idx * 2)); - if (this.chart) { - this.chart.destroy(); - } this.chart = new Chart(this.canvasRef.el, { type: "pie", data: {