diff --git a/awesome_dashboard/__manifest__.py b/awesome_dashboard/__manifest__.py
index 31406e8addb..48b3aa1aff0 100644
--- a/awesome_dashboard/__manifest__.py
+++ b/awesome_dashboard/__manifest__.py
@@ -24,7 +24,11 @@
'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.js
deleted file mode 100644
index 637fa4bb972..00000000000
--- a/awesome_dashboard/static/src/dashboard.js
+++ /dev/null
@@ -1,10 +0,0 @@
-/** @odoo-module **/
-
-import { Component } from "@odoo/owl";
-import { registry } from "@web/core/registry";
-
-class AwesomeDashboard extends Component {
- static template = "awesome_dashboard.AwesomeDashboard";
-}
-
-registry.category("actions").add("awesome_dashboard.dashboard", AwesomeDashboard);
diff --git a/awesome_dashboard/static/src/dashboard.xml b/awesome_dashboard/static/src/dashboard.xml
deleted file mode 100644
index 1a2ac9a2fed..00000000000
--- a/awesome_dashboard/static/src/dashboard.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
- hello dashboard
-
-
-
diff --git a/awesome_dashboard/static/src/dashboard/dashboard.js b/awesome_dashboard/static/src/dashboard/dashboard.js
new file mode 100644
index 00000000000..31e2f659336
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/dashboard.js
@@ -0,0 +1,38 @@
+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";
+import { DashboardItem, items } 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, PieChart };
+
+ setup() {
+ this.action = useService("action");
+ this.statistics = useState(useService("awesome_dashboard.statistics"));
+ this.display = {
+ controlPanel: {},
+ };
+ this.items = items;
+ }
+
+ openCustomerView() {
+ this.action.doAction("base.action_partner_form");
+ }
+
+ openLeads() {
+ this.action.doAction({
+ type: "ir.actions.act_window",
+ name: "All leads",
+ res_model: "crm.lead",
+ views: [
+ [false, "list"],
+ [false, "form"],
+ ],
+ });
+ }
+}
+
+registry.category("lazy_components").add("AwesomeDashboard", AwesomeDashboard);
diff --git a/awesome_dashboard/static/src/dashboard/dashboard.scss b/awesome_dashboard/static/src/dashboard/dashboard.scss
new file mode 100644
index 00000000000..32862ec0d82
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/dashboard.scss
@@ -0,0 +1,3 @@
+.o_dashboard {
+ background-color: gray;
+}
diff --git a/awesome_dashboard/static/src/dashboard/dashboard.xml b/awesome_dashboard/static/src/dashboard/dashboard.xml
new file mode 100644
index 00000000000..5d510d3df0c
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/dashboard.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.js b/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.js
new file mode 100644
index 00000000000..36195555f4f
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.js
@@ -0,0 +1,79 @@
+import { NumberCard } from "../number_card/number_card";
+import { PieChartCard } from "../pie_chart_card/pie_chart_card";
+import { Component, onWillStart, useRef, onMounted, onWillUnmount } from "@odoo/owl";
+
+export const items = [
+ {
+ id: "average_quantity",
+ description: "Average amount of t-shirt",
+ 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",
+ Component: NumberCard,
+ props: (data) => ({
+ title: "Average time for an order to go from 'new' to 'sent' or 'cancelled'",
+ value: data.average_time,
+ })
+ },
+ {
+ id: "number_new_orders",
+ description: "New orders this month",
+ Component: NumberCard,
+ props: (data) => ({
+ title: "Number of new orders this month",
+ value: data.nb_new_orders,
+ })
+ },
+ {
+ id: "cancelled_orders",
+ description: "Cancelled orders this month",
+ Component: NumberCard,
+ props: (data) => ({
+ title: "Number of cancelled orders this month",
+ value: data.nb_cancelled_orders,
+ })
+ },
+ {
+ id: "amount_new_orders",
+ description: "amount orders this month",
+ Component: NumberCard,
+ props: (data) => ({
+ title: "Total amount of new orders this month",
+ value: data.total_amount,
+ })
+ },
+ {
+ id: "pie_chart",
+ description: "Shirt orders by size",
+ Component: PieChartCard,
+ size: 2,
+ props: (data) => ({
+ title: "Shirt orders by size",
+ values: data.orders_by_size,
+ })
+ }
+]
+
+
+export class DashboardItem extends Component {
+ static template = "awesome_dashboard.DashboardItem"
+ static props = {
+ slots: {
+ type: Object,
+ shape: {
+ default: Object
+ },
+ },
+ size: {
+ type: Number,
+ default: 1,
+ optional: true,
+ },
+ };
+}
diff --git a/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.xml b/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.xml
new file mode 100644
index 00000000000..33e1fd98752
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
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..ca8b584a334
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/number_card/number_card.js
@@ -0,0 +1,13 @@
+import { Component } from "@odoo/owl";
+
+export class NumberCard extends Component {
+ static template = "awesome_dashboard.NumberCard";
+ static props = {
+ title: {
+ type: String,
+ },
+ value: {
+ type: 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..3a0713623fa
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/number_card/number_card.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.js b/awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.js
new file mode 100644
index 00000000000..7c2c324e588
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.js
@@ -0,0 +1,41 @@
+import { loadJS } from "@web/core/assets";
+import { getColor } from "@web/core/colors/colors";
+import { Component, onWillStart, useRef, onMounted, onWillUnmount } from "@odoo/owl";
+
+export class PieChart extends Component {
+ static template = "awesome_dashboard.PieChart";
+ static props = {
+ label: String,
+ data: Object,
+ };
+
+ setup() {
+ this.canvasRef = useRef("canvas");
+ onWillStart(() => loadJS("/web/static/lib/Chart/Chart.js"));
+ onMounted(() => {
+ this.renderChart();
+ });
+ onWillUnmount(() => {
+ this.chart.destroy();
+ });
+ }
+
+ renderChart() {
+ const labels = Object.keys(this.props.data);
+ const data = Object.values(this.props.data);
+ const color = labels.map((_, index) => getColor(index));
+ this.chart = new Chart(this.canvasRef.el, {
+ type: "pie",
+ data: {
+ labels: labels,
+ datasets: [
+ {
+ label: this.props.label,
+ data: data,
+ backgroundColor: color,
+ },
+ ],
+ },
+ });
+ }
+}
diff --git a/awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.xml b/awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.xml
new file mode 100644
index 00000000000..1925523a47f
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
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..a28c2f48c6f
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/pie_chart_card/pie_chart_card.js
@@ -0,0 +1,17 @@
+/** @odoo-module */
+
+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: {
+ type: String,
+ },
+ values: {
+ type: 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..58a6811c83a
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/pie_chart_card/pie_chart_card.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
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..ce2e6f18559
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/statistics_service.js
@@ -0,0 +1,22 @@
+import { registry } from "@web/core/registry";
+import { reactive } from "@odoo/owl";
+import { rpc } from "@web/core/network/rpc";
+
+const statisticsService = {
+ start() {
+
+ const statistics = reactive({ isReady: false });
+
+ async function loadData() {
+ const updates = await rpc("/awesome_dashboard/statistics");
+ Object.assign(statistics, updates, { isReady: true });
+ }
+
+ setInterval(loadData, 10*60*1000);
+ loadData();
+
+ return statistics;
+ },
+};
+
+registry.category("services").add("awesome_dashboard.statistics", statisticsService);
diff --git a/awesome_dashboard/static/src/dashboard_loader.js b/awesome_dashboard/static/src/dashboard_loader.js
new file mode 100644
index 00000000000..35296129c1f
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard_loader.js
@@ -0,0 +1,15 @@
+/** @odoo-module */
+
+import { registry } from "@web/core/registry";
+import { LazyComponent } from "@web/core/assets";
+import { Component, xml } from "@odoo/owl";
+
+class AwesomeDashboardLoader extends Component {
+ static components = { LazyComponent };
+ static template = xml`
+
+ `;
+
+}
+
+registry.category("actions").add("awesome_dashboard.dashboard", AwesomeDashboardLoader);
diff --git a/awesome_owl/__manifest__.py b/awesome_owl/__manifest__.py
index 77abad510ef..fa64351c27f 100644
--- a/awesome_owl/__manifest__.py
+++ b/awesome_owl/__manifest__.py
@@ -26,6 +26,7 @@
'data': [
'views/templates.xml',
],
+
'assets': {
'awesome_owl.assets_playground': [
('include', 'web._assets_helpers'),
@@ -36,6 +37,12 @@
('include', 'web._assets_core'),
'web/static/src/libs/fontawesome/css/font-awesome.css',
'awesome_owl/static/src/**/*',
+ 'awesome_owl/static/src/playground.js',
+ 'awesome_owl/static/src/playground.xml',
+ 'awesome_owl/static/src/counter/counter.js',
+ 'awesome_owl/static/src/counter/counter.xml',
+ 'awesome_owl/static/src/card/utils.js',
+
],
},
'license': 'AGPL-3'
diff --git a/awesome_owl/static/src/card/card.js b/awesome_owl/static/src/card/card.js
new file mode 100644
index 00000000000..4c90e753072
--- /dev/null
+++ b/awesome_owl/static/src/card/card.js
@@ -0,0 +1,25 @@
+/** @odoo-module **/
+
+import { Component, useState } from "@odoo/owl";
+
+export class Card extends Component {
+ static template = "awesome_owl.Card";
+
+ static props = {
+ title: String,
+ slots: {
+ type: Object,
+ shape: {
+ default: true
+ },
+ }
+ };
+
+ setup() {
+ this.state = useState({ isOpen: true });
+ }
+
+ toggleContent() {
+ this.state.isOpen = !this.state.isOpen;
+ }
+}
diff --git a/awesome_owl/static/src/card/card.xml b/awesome_owl/static/src/card/card.xml
new file mode 100644
index 00000000000..cc6ad178805
--- /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..a3b1df314e0
--- /dev/null
+++ b/awesome_owl/static/src/counter/counter.js
@@ -0,0 +1,20 @@
+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({ value: 0 });
+ }
+
+ increment() {
+ this.state.value = this.state.value + 1;
+ 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..bf86fe83e1b
--- /dev/null
+++ b/awesome_owl/static/src/counter/counter.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/awesome_owl/static/src/main.js b/awesome_owl/static/src/main.js
index 1af6c827e0b..67b3bef7087 100644
--- a/awesome_owl/static/src/main.js
+++ b/awesome_owl/static/src/main.js
@@ -7,5 +7,4 @@ const config = {
name: "Owl Tutorial",
};
-// Mount the Playground component when the document.body is ready
whenReady(() => mountComponent(Playground, document.body, config));
diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js
index 657fb8b07bb..4b6a3073879 100644
--- a/awesome_owl/static/src/playground.js
+++ b/awesome_owl/static/src/playground.js
@@ -1,7 +1,26 @@
/** @odoo-module **/
-import { Component } from "@odoo/owl";
+import { Component, markup, useState } from "@odoo/owl";
+import { Counter } from "./counter/counter";
+import { Card } from "./card/card";
+import { TodoList } from "./todo_list/todo_list.js";
+
+
+
export class Playground extends Component {
static template = "awesome_owl.playground";
+
+ static components = { Counter, Card, TodoList };
+
+
+ setup() {
+ this.str1 = "
some content
";
+ this.str2 = markup("some content
");
+ this.sum = useState({ value: 2 });
+ }
+
+ incrementSum() {
+ this.sum.value++;
+ }
}
diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml
index 4fb905d59f9..df37898f39d 100644
--- a/awesome_owl/static/src/playground.xml
+++ b/awesome_owl/static/src/playground.xml
@@ -1,10 +1,21 @@
-
-
-
+
hello world
+
+
+
The sum is:
+
+
+ content of card 1
+
+
+
+
+
+
+
+
-
diff --git a/awesome_owl/static/src/todo_list/todo_item.js b/awesome_owl/static/src/todo_list/todo_item.js
new file mode 100644
index 00000000000..3f8d28c1e9a
--- /dev/null
+++ b/awesome_owl/static/src/todo_list/todo_item.js
@@ -0,0 +1,25 @@
+import { Component } from "@odoo/owl";
+
+export class TodoItem extends Component {
+ static template = "awesome_owl.TodoItem";
+ static props = {
+ todo: {
+ type: Object,
+ shape: { id: Number, description: String, isCompleted: Boolean }
+ },
+
+ toggleState: Function,
+ removeTodo: Function,
+
+
+ };
+
+ onChange() {
+ this.props.toggleState(this.props.todo.id);
+ }
+
+
+ onRemove() {
+ this.props.removeTodo(this.props.todo.id);
+ }
+}
diff --git a/awesome_owl/static/src/todo_list/todo_item.xml b/awesome_owl/static/src/todo_list/todo_item.xml
new file mode 100644
index 00000000000..4c43faa1d7c
--- /dev/null
+++ b/awesome_owl/static/src/todo_list/todo_item.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
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..6b4c3550dc2
--- /dev/null
+++ b/awesome_owl/static/src/todo_list/todo_list.js
@@ -0,0 +1,41 @@
+import { Component, useState } from "@odoo/owl";
+import { TodoItem } from "./todo_item";
+import { useAutofocus } from "../utils";
+
+
+export class TodoList extends Component {
+ static template = "awesome_owl.TodoList";
+ static components = { TodoItem };
+
+ setup() {
+ this.nextId = 0;
+ this.todos = useState([]);
+ useAutofocus("input")
+
+ }
+
+ addTodo(ev) {
+ if (ev.keyCode === 13 && ev.target.value !== "") { this.todos.push({
+ id: this.nextId++,
+ description: ev.target.value,
+ isCompleted: false,
+ });
+ ev.target.value = "";
+ }
+ }
+
+ toggleTodo(todoId) {
+ const todo = this.todos.find((todo) => todo.id === todoId);
+ if (todo) {
+ todo.isCompleted = !todo.isCompleted;
+ }
+ }
+
+
+ removeTodo(todoId) {
+ const todoIndex = this.todos.findIndex((todo) => todo.id === todoId);
+ if (todoIndex >= 0) {
+ this.todos.splice(todoIndex, 1);
+ }
+ }
+}
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..3248c389e9c
--- /dev/null
+++ b/awesome_owl/static/src/todo_list/todo_list.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/awesome_owl/static/src/utils.js b/awesome_owl/static/src/utils.js
new file mode 100644
index 00000000000..f452f103aa0
--- /dev/null
+++ b/awesome_owl/static/src/utils.js
@@ -0,0 +1,8 @@
+import { useRef, onMounted } from "@odoo/owl";
+
+export function useAutofocus(refName) {
+ const ref = useRef(refName);
+ onMounted(() => {
+ ref.el.focus();
+ });
+}