diff --git a/awesome_dashboard/static/src/dashboard.js b/awesome_dashboard/static/src/dashboard.js
index c4fb245621b..88527030c13 100644
--- a/awesome_dashboard/static/src/dashboard.js
+++ b/awesome_dashboard/static/src/dashboard.js
@@ -1,8 +1,36 @@
-import { Component } from "@odoo/owl";
+import { Component, onWillStart, useState } from "@odoo/owl";
import { registry } from "@web/core/registry";
+import { useService } from "@web/core/utils/hooks";
+import { _t } from "@web/core/l10n/translation";
+
+import { DashboardItem } from "./dashboard_item/dashboard_item";
+import { Layout } from "@web/search/layout"
+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.state = useState({
+ stats: useService("awesome_dashboard.statistics"),
+ });
+ }
+
+ async openCustomersKanban() {
+ this.action.doAction('base.action_partner_form');
+ }
+
+ async openLeads() {
+ this.action.doAction({
+ type: 'ir.actions.act_window',
+ name: _t('Lots of 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.scss b/awesome_dashboard/static/src/dashboard.scss
new file mode 100644
index 00000000000..12d12f7d1f8
--- /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..07d9d85249d 100644
--- a/awesome_dashboard/static/src/dashboard.xml
+++ b/awesome_dashboard/static/src/dashboard.xml
@@ -2,7 +2,20 @@
- hello dashboard
+
+
+
+
+
+
+
+ Counter:
+
+
+
+
+
+
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..62fa57253ff
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard_item/dashboard_item.js
@@ -0,0 +1,19 @@
+import {Component} from "@odoo/owl"
+
+
+export class DashboardItem extends Component {
+ static template = "awesome_dashboard.dashboard_item"
+ static props = {
+ size: {
+ type: Number,
+ default: 1,
+ optional: true,
+ },
+ slots: {
+ type: Object,
+ shape: {
+ default: true
+ }
+ },
+ };
+}
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..b1bb5acc1a2
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard_item/dashboard_item.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
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..45265fd3581
--- /dev/null
+++ b/awesome_dashboard/static/src/pie_chart/pie_chart.js
@@ -0,0 +1,54 @@
+import { Component, onMounted, onPatched, onWillStart, onWillUnmount, useRef, useState } 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.pie_chart"
+ static props = {
+ data: Object,
+ optional: true
+ }
+
+ setup() {
+ onWillStart(async () => {
+ await loadJS("/web/static/lib/Chart/Chart.js")
+ })
+
+ this.canvasRef = useRef("canvas");
+
+ if (this.props.data) {
+ onMounted(() => {
+ this.renderChart()
+ })
+
+ onPatched(() => {
+ this.chart.destroy()
+ this.renderChart()
+ })
+
+ onWillUnmount(() => {
+ this.chart.destroy()
+ });
+ }
+ }
+
+ renderChart() {
+ const keys = Object.keys(this.props.data)
+ const values = Object.values(this.props.data)
+ const colors = keys.map((_, index) => getColor(index));
+
+ this.chart = new Chart(this.canvasRef.el, {
+ type: "pie",
+ data: {
+ labels: keys,
+ datasets: [
+ {
+ backgroundColor: colors,
+ data: values,
+ },
+ ]
+ }
+ });
+ }
+}
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..09b6f9835f7
--- /dev/null
+++ b/awesome_dashboard/static/src/pie_chart/pie_chart.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/awesome_dashboard/static/src/statistics_service.js b/awesome_dashboard/static/src/statistics_service.js
new file mode 100644
index 00000000000..48d5ea2fb31
--- /dev/null
+++ b/awesome_dashboard/static/src/statistics_service.js
@@ -0,0 +1,22 @@
+import { registry } from "@web/core/registry";
+import { rpc } from "@web/core/network/rpc";
+import { reactive } from "@odoo/owl";
+
+
+const statisticsService = {
+ start() {
+ let stats = reactive({})
+
+ async function getStats() {
+ let updates = await rpc("/awesome_dashboard/statistics");
+ Object.assign(stats, updates);
+ }
+
+ getStats()
+ setInterval(getStats, 10*1000)
+
+ return stats
+ }
+}
+
+registry.category("services").add("awesome_dashboard.statistics", statisticsService);
diff --git a/awesome_owl/static/src/card/card.js b/awesome_owl/static/src/card/card.js
new file mode 100644
index 00000000000..5260a66fb58
--- /dev/null
+++ b/awesome_owl/static/src/card/card.js
@@ -0,0 +1,25 @@
+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({
+ state: false,
+ })
+ }
+
+ toggleState() {
+ this.state.state = !this.state.state;
+ }
+}
diff --git a/awesome_owl/static/src/card/card.xml b/awesome_owl/static/src/card/card.xml
new file mode 100644
index 00000000000..85b728a00fe
--- /dev/null
+++ b/awesome_owl/static/src/card/card.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/awesome_owl/static/src/counter/counter.js b/awesome_owl/static/src/counter/counter.js
new file mode 100644
index 00000000000..3289fd964ef
--- /dev/null
+++ b/awesome_owl/static/src/counter/counter.js
@@ -0,0 +1,21 @@
+import { Component, useState } from "@odoo/owl";
+
+
+export class Counter extends Component {
+ static template = "awesome_owl.counter";
+ static prop = {
+ onChange: {
+ type: Function,
+ optional: true,
+ },
+ }
+
+ setup() {
+ this.state = useState({ value: 0 });
+ }
+
+ 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..c5d85afe20c
--- /dev/null
+++ b/awesome_owl/static/src/counter/counter.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/awesome_owl/static/src/main.js b/awesome_owl/static/src/main.js
index 1aaea902b55..6c108687e29 100644
--- a/awesome_owl/static/src/main.js
+++ b/awesome_owl/static/src/main.js
@@ -9,4 +9,3 @@ const config = {
// 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 4ac769b0aa5..53bc34c32d3 100644
--- a/awesome_owl/static/src/playground.js
+++ b/awesome_owl/static/src/playground.js
@@ -1,5 +1,17 @@
-import { Component } from "@odoo/owl";
+import {Component, useState} from "@odoo/owl";
+import { Card } from "./card/card";
+import { Counter } from "./counter/counter";
+import { TodoList } from "./todo/todo_list";
export class Playground extends Component {
static template = "awesome_owl.playground";
+ static components = { Counter, Card, TodoList };
+
+ setup() {
+ this.sum = useState({ value: 0 });
+ }
+
+ incrementSum() {
+ this.sum.value++
+ }
}
diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml
index 4fb905d59f9..0dc4b3d5e4d 100644
--- a/awesome_owl/static/src/playground.xml
+++ b/awesome_owl/static/src/playground.xml
@@ -4,6 +4,18 @@
hello world
+
+
+
The sum is:
+
+
+
+
+
+ some content
+
+
+
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..fd63fcba41c
--- /dev/null
+++ b/awesome_owl/static/src/todo/todo_item.js
@@ -0,0 +1,37 @@
+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,
+ }
+ },
+ toggleState: {
+ type: Function,
+ optional: true
+ },
+
+ deleteTodo: {
+ type: Function,
+ optional: true
+ }
+ };
+
+ onChange() {
+ if (this.props.toggleState) {
+ this.props.toggleState(this.props.todo.id);
+ }
+ }
+
+ onRemove() {
+ if (this.props.deleteTodo) {
+ this.props.deleteTodo(this.props.todo.id)
+ }
+ }
+}
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..19beb0d32ff
--- /dev/null
+++ b/awesome_owl/static/src/todo/todo_item.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
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..727a1f3d434
--- /dev/null
+++ b/awesome_owl/static/src/todo/todo_list.js
@@ -0,0 +1,41 @@
+import { Component, useState } from "@odoo/owl"
+import { TodoItem } from "./todo_item";
+import { Autofocus } from "../utils";
+
+
+export class TodoList extends Component {
+ static template = "awesome_owl.todo_list";
+ static components = { TodoItem };
+
+ setup() {
+ this.nextId = 0;
+ this.todos = useState([]);
+ Autofocus("input")
+ }
+
+ addTodo(event) {
+ if (event.key === 'Enter' && event.target.value !== '') {
+ this.todos.push({
+ id: this.nextId++,
+ description: event.target.value,
+ isCompleted: false
+ });
+
+ event.target.value = '';
+ }
+ }
+
+ listToggleComplete(itemId) {
+ const todoItem = this.todos.find(item => item.id === itemId);
+ if (todoItem) {
+ todoItem.isCompleted = !todoItem.isCompleted;
+ }
+ }
+
+ removeTodo(itemId) {
+ const todoIndex = this.todos.findIndex((todo) => todo.id === itemId);
+ if (todoIndex >= 0) {
+ this.todos.splice(todoIndex, 1);
+ }
+ }
+}
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..6366d399b6c
--- /dev/null
+++ b/awesome_owl/static/src/todo/todo_list.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
diff --git a/awesome_owl/static/src/utils.js b/awesome_owl/static/src/utils.js
new file mode 100644
index 00000000000..696db80c603
--- /dev/null
+++ b/awesome_owl/static/src/utils.js
@@ -0,0 +1,10 @@
+import { onMounted, useRef } from "@odoo/owl"
+
+
+export function Autofocus(refName) {
+ const ref = useRef(refName);
+
+ onMounted(() => {
+ ref.el.focus()
+ })
+}