diff --git a/awesome_dashboard/__manifest__.py b/awesome_dashboard/__manifest__.py
index 31406e8addb..e783edeacf1 100644
--- a/awesome_dashboard/__manifest__.py
+++ b/awesome_dashboard/__manifest__.py
@@ -24,7 +24,12 @@
'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'
-}
+}
\ No newline at end of file
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..ff912400a7f
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/dashboard.js
@@ -0,0 +1,71 @@
+/** @odoo-module **/
+
+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 } from "./dashboard_item/dashboard_item";
+import { DashboardSettingsDialog } from "./dashboard_settings_dialog";
+
+class AwesomeDashboard extends Component {
+ static template = "awesome_dashboard.AwesomeDashboard";
+ static components = { Layout, DashboardItem };
+
+ setup() {
+ this.action = useService("action");
+ this.dialog = useService("dialog");
+ this.statistics = useState(useService("awesome_dashboard.statistics"));
+ this.dashboardRegistry = registry.category("awesome_dashboard.items");
+ this.display = {
+ controlPanel: {},
+ };
+ this.state = useState({
+ items: this.getVisibleItems()
+ });
+ }
+
+ getVisibleItems() {
+ const allItems = this.dashboardRegistry.getAll();
+ const hiddenItems = this.getHiddenItems();
+ return allItems.filter(item => !hiddenItems.includes(item.id))
+ }
+
+ getHiddenItems() {
+ const stored = localStorage.getItem('dashboard_hidden_items');
+ return stored ? JSON.parse(stored) : [];
+ }
+
+ saveHiddenItems(hiddenItemIds){
+ localStorage.setItem('dashboard_hidden_items', JSON.stringify(hiddenItemIds));
+ this.state.items = this.getVisibleItems();
+ }
+
+ openSettings() {
+ const allItems = this.dashboardRegistry.getAll();
+ this.dialog.add(DashboardSettingsDialog, {
+ items: allItems,
+ hiddenItems: this.getHiddenItems(),
+ onApply: (hiddenItemIds) => {
+ this.saveHiddenItems(hiddenItemIds);
+ }
+ })
+ }
+
+ 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);
\ No newline at end of file
diff --git a/awesome_dashboard/static/src/dashboard/dashboard.xml b/awesome_dashboard/static/src/dashboard/dashboard.xml
new file mode 100644
index 00000000000..ee485dc552c
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/dashboard.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
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..d4619303083
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.js
@@ -0,0 +1,21 @@
+/** @odoo-module */
+
+import { Component } from "@odoo/owl";
+
+
+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,
+ },
+ };
+}
\ 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
new file mode 100644
index 00000000000..d023340bb59
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/dashboard_item/dashboard_item.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
\ No newline at end of file
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..a6c2cd553c0
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/dashboard_items.js
@@ -0,0 +1,76 @@
+/** @odoo-module */
+
+import { NumberCard } from "./number_card/number_card";
+import { PieChartCard } from "./pie_chart_card/pie_chart_card";
+import { registry } from "@web/core/registry";
+
+const dashboardRegistry = registry.category("awesome_dashboard.items");
+
+
+
+dashboardRegistry.add("average_quantity",
+ {
+ 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,
+ })
+ });
+
+dashboardRegistry.add("average_time",
+ {
+ 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,
+ })
+ });
+
+dashboardRegistry.add("number_new_orders",
+ {
+ 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,
+ })
+ });
+
+dashboardRegistry.add("cancelled_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,
+ })
+ });
+
+dashboardRegistry.add("amount_new_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,
+ })
+ });
+
+dashboardRegistry.add("pie_chart",
+ {
+ id: "pie_chart",
+ description: "Shirt orders by size",
+ Component: PieChartCard,
+ size: 2,
+ props: (data) => ({
+ title: "Shirt orders by size",
+ values: data.orders_by_size,
+ })
+ });
\ No newline at end of file
diff --git a/awesome_dashboard/static/src/dashboard/dashboard_setting_dialog.xml b/awesome_dashboard/static/src/dashboard/dashboard_setting_dialog.xml
new file mode 100644
index 00000000000..bdcc981393a
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/dashboard_setting_dialog.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/awesome_dashboard/static/src/dashboard/dashboard_settings_dialog.js b/awesome_dashboard/static/src/dashboard/dashboard_settings_dialog.js
new file mode 100644
index 00000000000..382a2254ebc
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/dashboard_settings_dialog.js
@@ -0,0 +1,30 @@
+/** @odoo-module **/
+
+import { Component } from "@odoo/owl";
+import { Dialog } from "@web/core/dialog/dialog";
+
+export class DashboardSettingsDialog extends Component {
+ static template = "awesome_dashboard.DashboardSettingsDialog";
+ static components = { Dialog };
+
+ static props = {
+ items: Array,
+ hiddenItems: Array,
+ onApply: Function,
+ close: Function,
+ };
+
+ onApply() {
+ const hiddenItemIds = [];
+ this.props.items.forEach(item => {
+ const checkbox = document.getElementById(item.id);
+ if (!checkbox.checked) {
+ hiddenItemIds.push(item.id);
+ }
+ });
+
+ this.props.onApply(hiddenItemIds);
+
+ this.props.close();
+ }
+}
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..cc5e2d439d7
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/number_card/number_card.js
@@ -0,0 +1,15 @@
+/** @odoo-module */
+
+import { Component } from "@odoo/owl";
+
+export class NumberCard extends Component {
+ static template = "awesome_dashboard.NumberCard";
+ static props = {
+ title: {
+ type: String,
+ },
+ value: {
+ type: Number,
+ }
+ }
+}
\ 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
new file mode 100644
index 00000000000..73bc3cac926
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/number_card/number_card.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
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..29de2774d35
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.js
@@ -0,0 +1,43 @@
+/** @odoo-module */
+
+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,
+ },
+ ],
+ },
+ });
+ }
+}
\ 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
new file mode 100644
index 00000000000..18416e9a223
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/pie_chart/pie_chart.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..6a962d2c99b
--- /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,
+ },
+ }
+}
\ 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
new file mode 100644
index 00000000000..b8c94bebb64
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/pie_chart_card/pie_chart_card.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
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..e435d676105
--- /dev/null
+++ b/awesome_dashboard/static/src/dashboard/statistics_service.js
@@ -0,0 +1,23 @@
+/** @odoo-module */
+
+import { registry } from "@web/core/registry";
+import { reactive } from "@odoo/owl";
+import { rpc } from "@web/core/network/rpc"
+
+const statisticsService = {
+ start(env) {
+ 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);
\ No newline at end of file
diff --git a/awesome_dashboard/static/src/dashboard_loader.js b/awesome_dashboard/static/src/dashboard_loader.js
new file mode 100644
index 00000000000..06ae51de339
--- /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);
\ No newline at end of file
diff --git a/awesome_owl/static/src/card/card.js b/awesome_owl/static/src/card/card.js
new file mode 100644
index 00000000000..42a40f2256b
--- /dev/null
+++ b/awesome_owl/static/src/card/card.js
@@ -0,0 +1,18 @@
+/** @odoo-module **/
+
+import { Component, useState } from '@odoo/owl'
+
+
+export class Card extends Component{
+ static template = "awesome_owl.card"
+ static props = ['slots']
+
+ setup(){
+ this.state = useState({isToggled: true});
+ }
+
+ toggle() {
+ console.log(this.state.isToggled)
+ this.state.isToggled = !this.state.isToggled;
+ }
+}
diff --git a/awesome_owl/static/src/card/card.xml b/awesome_owl/static/src/card/card.xml
new file mode 100644
index 00000000000..4bc3a2ccda7
--- /dev/null
+++ b/awesome_owl/static/src/card/card.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
Card 1
+
+
+
+
+
+
+
+
+
+
\ 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..fa3f7c400b1
--- /dev/null
+++ b/awesome_owl/static/src/counter/counter.js
@@ -0,0 +1,20 @@
+/** @odoo-module **/
+
+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.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..5a685ed4d5d
--- /dev/null
+++ b/awesome_owl/static/src/counter/counter.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/awesome_owl/static/src/playground.js b/awesome_owl/static/src/playground.js
index 657fb8b07bb..ab5b5ea3d8e 100644
--- a/awesome_owl/static/src/playground.js
+++ b/awesome_owl/static/src/playground.js
@@ -1,7 +1,21 @@
/** @odoo-module **/
-import { Component } from "@odoo/owl";
+import { Component, useState, markup } from "@odoo/owl";
+import { Counter } from "./counter/counter";
+import { Card } from "./card/card";
+import { ToDoList } from "./to_do/to_do_list";
export class Playground extends Component {
- static template = "awesome_owl.playground";
+ static template = "awesome_owl.playground"
+
+ setup(){
+ this.state = useState({ sum: 0})
+ this.incrementSum = this.incrementSum.bind(this);
+ }
+
+ incrementSum(){
+ this.state.sum++
+ }
+
+ static components = { Counter, Card, ToDoList };
}
diff --git a/awesome_owl/static/src/playground.xml b/awesome_owl/static/src/playground.xml
index 4fb905d59f9..ed8ba6435af 100644
--- a/awesome_owl/static/src/playground.xml
+++ b/awesome_owl/static/src/playground.xml
@@ -1,10 +1,11 @@
-
-
- hello world
-
+
+
+
+
+ Sum:
+
-
diff --git a/awesome_owl/static/src/to_do/to_do_item.js b/awesome_owl/static/src/to_do/to_do_item.js
new file mode 100644
index 00000000000..327aa4d7729
--- /dev/null
+++ b/awesome_owl/static/src/to_do/to_do_item.js
@@ -0,0 +1,32 @@
+/** @odoo-module **/
+
+import { Component } from "@odoo/owl"
+
+export class ToDoItem extends Component{
+ static template = "awesome_owl.to_do_item"
+ static props = {
+ todo : {
+ type: Object,
+ shape : {id: Number, description: String, isComplete: Boolean}
+ },
+ deleteToDo: {
+ type: Function,
+ optional: true,
+ }
+ }
+
+ setup(){
+ this.toggleState = this.toggleState.bind(this);
+ }
+
+ toggleState() {
+ this.props.todo.isComplete = !this.props.todo.isComplete
+ }
+
+ removeToDo() {
+ if(this.props.todo){
+ this.props.deleteToDo(this.props.todo.id)
+ }
+ }
+
+}
diff --git a/awesome_owl/static/src/to_do/to_do_item.xml b/awesome_owl/static/src/to_do/to_do_item.xml
new file mode 100644
index 00000000000..5e49ffb6c35
--- /dev/null
+++ b/awesome_owl/static/src/to_do/to_do_item.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/awesome_owl/static/src/to_do/to_do_list.js b/awesome_owl/static/src/to_do/to_do_list.js
new file mode 100644
index 00000000000..b4639587e69
--- /dev/null
+++ b/awesome_owl/static/src/to_do/to_do_list.js
@@ -0,0 +1,38 @@
+/** @odoo-module **/
+
+import { Component, useState, onMounted } from '@odoo/owl'
+import { ToDoItem } from './to_do_item'
+import { useAutoFocus } from '../utils'
+
+export class ToDoList extends Component {
+ static template = "awesome_owl.to_do_list"
+ static props = {
+ removeTodo: {
+ type: Function,
+ optional: true
+ }
+ }
+ setup(){
+ this.state = useState({value: 1});
+ this.todos = useState([]);
+ useAutoFocus('task');
+ this.deleteToDo = this.deleteToDo.bind(this);
+ }
+
+ addToDo(event) {
+ if(event.keyCode===13 && event.target.value){
+ this.todos.push({id: this.state.value, description: event.target.value, isComplete: false});
+ this.state.value++;
+ event.target.value = ""
+ }
+ }
+
+ deleteToDo(id){
+ const index = this.todos.findIndex((elem) => elem.id === id)
+ if(index >= 0){
+ this.todos.splice(index,1)
+ }
+ }
+
+ static components = { ToDoItem };
+}
diff --git a/awesome_owl/static/src/to_do/to_do_list.xml b/awesome_owl/static/src/to_do/to_do_list.xml
new file mode 100644
index 00000000000..87975315643
--- /dev/null
+++ b/awesome_owl/static/src/to_do/to_do_list.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
To Do List
+
+
+
+
+
+
\ No newline at end of file
diff --git a/awesome_owl/static/src/utils.js b/awesome_owl/static/src/utils.js
new file mode 100644
index 00000000000..55ff0fa7ffa
--- /dev/null
+++ b/awesome_owl/static/src/utils.js
@@ -0,0 +1,10 @@
+/** @odoo-module **/
+
+import { useRef, onMounted } from '@odoo/owl'
+
+export function useAutoFocus(name) {
+ const inputRef = useRef(name);
+ onMounted(() => {
+ inputRef.el.focus();
+ })
+}